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

去年の暮れにPHP7がリリースされ、少しずつではありますがその速さに驚く声がちらほら聞こえます。
身内用にownCloudを運用してみようと思った時に、せっかくなのでいろいろ新しいことを試してみようと思ったのですが、まだこの構成でやったというリソースがあまり見当たらなかったので次回困らないよう手順にまとめてみました。
今回はメモ程度にサーバへのownCloudの導入と、HTTP2有効化 + Let's EncryptでSSL証明書の発行までを一括の流れでつらつらと書いていこうと思います。
初心者でも運用が開始できるように少し冗長に書いた部分もありますが、何かご指摘、改善点等あればご教授ください。

※こっそりアドベントカレンダーに掲載させていただきました。

#ownCloudとは
いわゆるDropboxやGoogle Driveのようなオンラインストレージです。特徴としては・・・
- オープンソース・自分でサーバーを建てて運用できる(完全にプライベート)
- 閉じたネットワークセグメントでも運用が可能(今回は外部公開用サーバの構築です)
- Windows/Mac/Linux/iOS/Android/ブラウザ上で使える
- LDAPやActive Directoryとの連携も可

などがあります。


# 本構築において既に準備できていることが前提の環境
- [x] CentOS 7にsudo権限のあるユーザが発行されていること
- [x] Selinuxやfirewalld(iptables)等の設定は既に済んでいること
- [x] 自分のドメインを取得していること

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


```lang:/etc/yum.repos.d/nginx.repo
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=0
enabled=1
```

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

#2. PHP7インストール
次に、PHP7の導入

```
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-php70 php-fpm php-gd php-json php-mysql php-curl php-mbstring php-intl php-mcrypt php-imagick php-xml php-zip php-apcu
```

このとき、`sudo chmod 777 /var/lib/php/session/`としておくといいかもしれません

#3. FastCGIとownCloudに向けた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
```

ここでnginxに対してもphpの設定を入れるのですが、上記の内容を除き、今回は基本的にはownCloudの公式ページで推奨されている設定を利用します。
今回はまだHTTPSの設定を行っていないので、今はそこだけいじってあとで変えることにします。ちなみにこの設定でWordpressもそのまま運用できます。
※server_nameにはDNSで自分が取得したアドレスを持ってくることに注意

コンフィグの場所: https://github.com/owncloud/documentation/wiki/ownCloud-9.x-nginx-config

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

```lang:/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;
  server_name cloud.example.com;

  # Path to the root of your installation
  root /usr/share/nginx/html/owncloud;
  # set max upload size
  client_max_body_size 10G;
  fastcgi_buffers 64 4K;

  # Disable gzip to avoid the removal of the ETag header
  gzip off;

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

  rewrite ^/caldav(.*)$ /remote.php/caldav$1 redirect;
  rewrite ^/carddav(.*)$ /remote.php/carddav$1 redirect;
  rewrite ^/webdav(.*)$ /remote.php/webdav$1 redirect;

  index index.php;
  error_page 403 /core/templates/403.php;
  error_page 404 /core/templates/404.php;

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

  location ~ ^/(?:\.htaccess|data|config|db_structure\.xml|README){
    deny all;
  }

  location / {
    # The following 2 rules are only needed with webfinger
    rewrite ^/.well-known/host-meta /public.php?service=host-meta last;
    rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json last;

    rewrite ^/.well-known/carddav /remote.php/carddav/ redirect;
    rewrite ^/.well-known/caldav /remote.php/caldav/ redirect;

    rewrite ^(/core/doc/[^\/]+/)$ $1/index.html;

    try_files $uri $uri/ /index.php;
  }

  location ~ \.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;
    fastcgi_pass php-handler;
  }

  # Optional: set long EXPIRES header on static assets
  location ~* \.(?:jpg|jpeg|gif|bmp|ico|png|css|js|swf)$ {
    expires 30d;
    # Optional: Don't log access to assets
    access_log off;
  }
}
```

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

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

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

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

```
curl -O 'https://download.owncloud.org/community/owncloud-9.0.1.zip'
unzip owncloud-9.0.1.zip
rm -f owncloud-9.0.1.zip
sudo mv owncloud/ /usr/share/nginx/html/
sudo chown -R nginx /usr/share/nginx/html/owncloud
```

これで、自分のサーバーのアドレスにアクセスした時にownCloudのサービスが表示されるはずです。
ここまできたらあとはSSL証明書を発行してちょこっと設定を変更すれば終了。

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

導入前に、gitが入ってるかを確認
`sudo yum list installed git`
無ければ`sudo yum -y install git`してあげればOK
続けて、

```
git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt/
./letsencrypt-auto --help
```

これで鍵作成の準備はOKです。
必要に応じてsudo用のパスワードを要求されるので入れてあげましょう。

```
./letsencrypt-auto certonly --standalone \
-d cloud.example.com -d cloud1.example.com \ #複数ドメインは必要に応じて
-m 自分のメールアドレス \ #この行は省略可能
--agree-tos
```
と入力すれば自動で鍵作成のセットアップが始まります。
URLは自分が取得したドメインに合わせて変更してくださいね。
セットアップ終了後、`  /etc/letsencrypt/live/cloud.example.com/fullchain.pem`のような形でファイルが作成されます。

#6. HTTP/2への対応
SSL証明書までは準備ができました。あとはWebサーバの設定ファイルに暗号化通信の設定を加えてあげればよいのですが、
せっかくSSL通信を導入するなら少しでも古い形式の通信は断ち切るべきです(脆弱性的な意味で)

```lang:/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;
  server_name cloud.example.com;
  # enforce https
  return 301 https://$server_name$request_uri;
}

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

  ssl_certificate /etc/letsencrypt/live/cloud.example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/cloud.example.com/privkey.pem;
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  ssl_prefer_server_ciphers on;
  ssl_ciphers 'kEECDH+ECDSA+AES128 kEECDH+ECDSA+AES256 kEECDH+AES128 kEECDH+AES256 kEDH+AES128 kEDH+AES256 DES-CBC3-SHA +SHA !DH !aNULL !eNULL !LOW !kECDH !DSS !MD5 !EXP !PSK !SRP !CAMELLIA !SEED';
  ssl_session_cache    shared:SSL:10m;
  ssl_session_timeout  10m;

  # Path to the root of your installation
  root /usr/share/nginx/html/owncloud;
  # set max upload size
  client_max_body_size 10G;
  fastcgi_buffers 64 4K;

  # Disable gzip to avoid the removal of the ETag header
  gzip off;

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

  rewrite ^/caldav(.*)$ /remote.php/caldav$1 redirect;
  rewrite ^/carddav(.*)$ /remote.php/carddav$1 redirect;
  rewrite ^/webdav(.*)$ /remote.php/webdav$1 redirect;

  index index.php;
  error_page 403 /core/templates/403.php;
  error_page 404 /core/templates/404.php;

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

  location ~ ^/(?:\.htaccess|data|config|db_structure\.xml|README){
    deny all;
  }

  location / {
    # The following 2 rules are only needed with webfinger
    rewrite ^/.well-known/host-meta /public.php?service=host-meta last;
    rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json last;

    rewrite ^/.well-known/carddav /remote.php/carddav/ redirect;
    rewrite ^/.well-known/caldav /remote.php/caldav/ redirect;

    rewrite ^(/core/doc/[^\/]+/)$ $1/index.html;

    try_files $uri $uri/ /index.php;
  }

  location ~ \.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;
    fastcgi_pass php-handler;
  }

  # Optional: set long EXPIRES header on static assets
  location ~* \.(?:jpg|jpeg|gif|bmp|ico|png|css|js|swf)$ {
    expires 30d;
    # Optional: Don't log access to assets
    access_log off;
  }
}
```

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

ブラウザのアドレスバー横に緑色で証明書が信頼されていますという表示になっていて、かつページが正常に表示されていればOK
ついでに、SSL通信の安全性について診断してくれるサイトを使ってみると、Aの評価が出ていると思います。もちろん完璧な暗号化通信なんてこの世にはありませんが、とりあえずこれだけやっていれば意図的にクラッキングを試みられない限りは大丈夫でしょう。

というわけでWebサーバを使って既存のアプリを動かす流れを解説してみました。
よいクラウドライフを！