nginx
centos7
http2
letsencrypt
nextcloud

Let's Encryptを使ってCentOS7.4 + nginx(http/2) + PHP7.1な環境でセキュアなnextCloudを構築してみた

2015年の暮れに PHP7 がリリースされ、その速さに驚く声がちらほら聞こえます。
身内用にownCloudを運用してみようと思った時に、せっかくなのでいろいろ新しいことを試してみようと思ったのですが、2015年時点においてまだこの構成でやったというリソースがあまり見当たらなかったので次回困らないよう手順にまとめたQiitaの記事を、こちらに転載し、一部修正しています。
本稿においては、サーバへのnextCloudの導入、nginxを使ったHTTP/2の有効化を行った上で、Let's EncryptでSSL証明書の発行までを一括の流れでつらつらと書いていこうと思います。
初心者でも運用が開始できるように少し冗長に書いた部分もありますので、何卒ご了承ください。

nextCloudとは

いわゆるDropboxやGoogle Driveのようなオンラインストレージです。特徴としては・・・

  • オープンソース・自分でサーバーを建てて運用できる(完全にプライベート)
  • 閉じたネットワークセグメントでも運用が可能(今回は外部公開用サーバの構築です)
  • Windows/Mac/Linux/iOS/Android/ブラウザ上で使える
  • LDAPやActive Directoryとの連携も可

などがあります。

まずやっておいてほしいこと

  • CentOS 7.4にsudo権限のあるユーザが発行されていること
  • Selinuxやfirewalld(iptables)等の設定は既に済んでいること
  • 自分のドメインを取得していること

1. nginxを入れよう

まず、sudo vi /etc/yum.repos.d/nginx.repoとしてnginxのリポジトリ情報に以下の内容を記入します。
HTTP2は1.9.5以上のバージョンで実装されています。
※nginxの最新安定版のバージョンは1.13.8(2016/4/26時点)です。

/etc/yum.repos.d/nginx.repo
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/mainline/centos/7/x86_64/
gpgcheck=0
enabled=1

repoファイルを保存したら
sudo yum install nginx
これでnginxのインストールは終わりです。設定は後ほど。

2. PHP7.1インストール

次に、PHP7.1の導入

sudo yum install epel-release.noarch
sudo rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
sudo yum install --enablerepo=remi --enablerepo=remi-php71 php-fpm php-gd php-json php-mysql php-curl php-mbstring php-intl php-mcrypt php-imagick php-xml php-zip php-apcu

3. Let's Encryptでラクラク証明書発行

Let's Encryptはmozilla、Akamai、Cisco、Google、Facebookなどををはじめとした大手IT企業の支援を受けて2014年に創設されたプロジェクトで、個人でも信頼されたサーバ証明書を無料で発行することができます。

以前はletsenrypt-autoコマンドを使用していましたが、現在はyumリポジトリに入っているcertbotコマンドを使うのが良いと思います。

yum -y install certbot
certbot certonly --standalone \
-d cloud.example.com -d cloud1.example.com \ #複数ドメインは必要に応じて
-m 自分のメールアドレス \ #この行は省略可能

と入力すれば自動で鍵作成のセットアップが始まります。
URLは自分が取得したドメインに合わせて変更してくださいね。
セットアップ終了後、/etc/letsencrypt/live/cloud.example.com/fullchain.pemのような形でファイルが作成されます。

4. FastCGIとnextCloudに向けたnginxの設定

PHP-FPM(FastCGI)を導入したので設定しておきます。また、この後行うnginxの設定にもphp-fpmのためのソケットの場所を指定しておくことも忘れないでください。

/etc/php-fpm.d/www.confを以下のように変更

sed -i -e 's/listen = 127.0.0.1:9000/listen = \/var\/run\/php-fpm\/php-fpm.sock/' /etc/php-fpm.d/www.conf
sed -i -e 's/;listen.owner = nobody/listen.owner = nginx/' /etc/php-fpm.d/www.conf
sed -i -e 's/;listen.group = nobody/listen.group = nginx/' /etc/php-fpm.d/www.conf
sed -i -e 's/user = apache/user = nginx/' /etc/php-fpm.d/www.conf
sed -i -e 's/group = apache/group = nginx/' /etc/php-fpm.d/www.conf

ここでnginxに対してもphpの設定を入れるのですが、上記の内容を除き、今回は基本的にはnextCloudの公式ページで推奨されている設定を利用します。
※server_nameにはDNSで自分が取得したアドレスを持ってくることに注意

コンフィグの参考元

vi /etc/nginx/conf.d/cloud.conf

/etc/nginx/conf.d/cloud.conf
upstream php-handler {
  #server 127.0.0.1:9000;
  server unix:/var/run/php-fpm/php-fpm.sock;
}

server {
    listen 80;
    listen [::]:80;
    server_name cloud.example.com;
    # enforce https
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name cloud.example.com;

    ssl_certificate /etc/ssl/nginx/cloud.example.com.crt;
    ssl_certificate_key /etc/ssl/nginx/cloud.example.com.key;

    # Add headers to serve security related headers
    # Before enabling Strict-Transport-Security headers please read into this
    # topic first.
    # add_header Strict-Transport-Security "max-age=15768000;
    # includeSubDomains; preload;";
    #
    # WARNING: Only add the preload option once you read about
    # the consequences in https://hstspreload.org/. This option
    # will add the domain to a hardcoded list that is shipped
    # in all major browsers and getting removed from this list
    # could take several months.
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Robots-Tag none;
    add_header X-Download-Options noopen;
    add_header X-Permitted-Cross-Domain-Policies none;

    # Path to the root of your installation
    root /var/www/nextcloud/;

    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
    }

    # The following 2 rules are only needed for the user_webfinger app.
    # Uncomment it if you're planning to use this app.
    #rewrite ^/.well-known/host-meta /public.php?service=host-meta last;
    #rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json
    # last;

    location = /.well-known/carddav {
      return 301 $scheme://$host/remote.php/dav;
    }
    location = /.well-known/caldav {
      return 301 $scheme://$host/remote.php/dav;
    }

    # set max upload size
    client_max_body_size 512M;
    fastcgi_buffers 64 4K;

    # Enable gzip but do not remove ETag headers
    gzip on;
    gzip_vary on;
    gzip_comp_level 4;
    gzip_min_length 256;
    gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
    gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;

    # Uncomment if your server is build with the ngx_pagespeed module
    # This module is currently not supported.
    #pagespeed off;

    location / {
        rewrite ^ /index.php$uri;
    }

    location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/ {
        deny all;
    }
    location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) {
        deny all;
    }

    location ~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+)\.php(?:$|/) {
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_param HTTPS on;
        #Avoid sending the security headers twice
        fastcgi_param modHeadersAvailable true;
        fastcgi_param front_controller_active true;
        fastcgi_pass php-handler;
        fastcgi_intercept_errors on;
        fastcgi_request_buffering off;
    }

    location ~ ^/(?:updater|ocs-provider)(?:$|/) {
        try_files $uri/ =404;
        index index.php;
    }

    # Adding the cache control header for js and css files
    # Make sure it is BELOW the PHP block
    location ~ \.(?:css|js|woff|svg|gif)$ {
        try_files $uri /index.php$uri$is_args$args;
        add_header Cache-Control "public, max-age=15778463";
        # Add headers to serve security related headers (It is intended to
        # have those duplicated to the ones above)
        # Before enabling Strict-Transport-Security headers please read into
        # this topic first.
        # add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;";
        #
        # WARNING: Only add the preload option once you read about
        # the consequences in https://hstspreload.org/. This option
        # will add the domain to a hardcoded list that is shipped
        # in all major browsers and getting removed from this list
        # could take several months.
        add_header X-Content-Type-Options nosniff;
        add_header X-XSS-Protection "1; mode=block";
        add_header X-Robots-Tag none;
        add_header X-Download-Options noopen;
        add_header X-Permitted-Cross-Domain-Policies none;
        # Optional: Don't log access to assets
        access_log off;
    }

    location ~ \.(?:png|html|ttf|ico|jpg|jpeg)$ {
        try_files $uri /index.php$uri$is_args$args;
        # Optional: Don't log access to other assets
        access_log off;
    }
}

その後、以下のコマンドで両方のサービスを起動し、スタートアップで起動するように設定します。

sudo systemctl start php-fpm
sudo systemctl start nginx
sudo systemctl enable php-fpm
sudo systemctl enable nginx

ところで、nextCloudを導入するためにはデータベースが必要です。幸い、nextcloudではSQLiteが使えるので個人的なサービスの運用であればMySQLの導入は必須ではありません。
よって今回に関しては最低限の構成ということで省略します、そのへんは自分の運用のスケールに合わせてください。

5. nextCloudをインストール

さて、nextCloud導入に必要な環境のインストールができましたので、nextCloudをいよいよサーバーへ落とし込みます。最新バージョンなどは各自調べてください

ここでは2017/05現在の最新を入れています。

curl -O 'https://download.nextcloud.com/server/releases/nextcloud-12.0.5.zip'
unzip nextcloud-12.0.5.zip
rm -f nextcloud-12.0.5.zip
sudo mv nextcloud/ /var/www/
sudo chown -R nginx /var/www/nextcloud

6. HTTP/2への対応

/etc/nginx/conf.d/cloud.conf

listen 443 ssl;listen 443 ssl http2;にするだけ

最後に、sudo nginx -t && sudo nginx -s reloadとしてnginxを再読み込みしてあげれば、無事にHTTP/2+SSLの設定は終わりです。

ブラウザのアドレスバー横に緑色で証明書が信頼されていますという表示になっていて、かつページが正常に表示されていればOK!

https://www.ssllabs.comhttps://observatory.mozilla.org
でセキュリティの確認を行ってみましょう :)