Apacheからnginxへ移行する際に気になったことメモ

最近VPSサービスのリプレースを行いまして、ついでにWebサーバをApacheからnginxに変更したのですが、移行時に気になったところがいくつかあったのでメモっておきます。

# 移行環境情報

### 移行前

OS： FreeBSD8.4
Apache2.2+mod_php

### 移行後

OS： FreeBSD10.1
nginx1.8+php-fpm (php5.6)

nginxはpkgでインストール
php-fpmはportsからインストール

## 稼働状況

* Wordpress (php,rewrite)
* ownCloud (php,rewrite)
* CakePHPで作成したWebアプリ (php,rewrite)
* VirtualHost3つほど
* HTTPSあり

見事にphpのアプリばかりですね！

# .htaccessが使えない

たぶんこれが一番インパクト大きいんじゃないかと。
.htaccessの中身はすべてnginxの設定ファイルに変換して設定する必要があります。

静的ファイルがメインのWebサイトならさほど問題ないでしょうが、WordpressをはじめとしたCMS、CakePHP等のフレームワークでは必ずと言っていいほど使われています。
ほかにもApacheでは.htaccessでサクッとできたディレクトリ毎のBASIC認証もnginxでは設定ファイルに書いてあげないといけなくなります。

# mod_rewriteが使えない

mod_rewriteはApache用のモジュールなので当然使えません。
上記に挙げたいくつかのWebアプリは1ファイルで処理するためにmod_rewriteで制御を行っています。
そのため単純にWebサーバをnginxに差し替えただけでは当然動きません。

nginxにもrewrite機能はありますので、mod_rewriteのルールをnginx用に書き換えてあげる必要があります。

公式ドキュメントに書かれているのでそこまで手間にはならなさそうですね。

Wordpress： https://codex.wordpress.org/Nginx
CakePHP： http://book.cakephp.org/3.0/ja/installation.html#nginx
ownCloud： https://doc.owncloud.org/server/8.0/admin_manual/installation/nginx_configuration.html

※実例を出したかったのですが、ウチのサイトはサブディレクトリで運用しているのであまり参考にならなさそうなので省略

# mod_phpが使えない

mod_phpはApache用のモジュールなので(以下略
nginxからphpを実行するためにはCGI経由で実行する必要があります。(CGI経由のphp実行自体はApacheでもできますけどネ)

## 意外と面倒なphpの設定

nginxでphpを使うためにphp-fpmを使用します。
単純にphpを実行するだけならlocationディレクティブにphpをCGIで実行する設定をすればOKです。

```nginx:nginx.conf
http {
  ...
  server {
    listen 80 default_server;
    server_name example.com;
    index index.php index.html;
    ...
    location ~ \.php$ {
      fastcgi_pass 127.0.0.1:9000;
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      fastcgi_param PATH_INFO $fastcgi_script_name;
      include fastcgi_params;
    }
  }
  server {
    listen 80;
    server_name www.example.com;
    index index.php index.html;
    ...
    location ~ \.php$ {
      fastcgi_pass 127.0.0.1:9000;
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      fastcgi_param PATH_INFO $fastcgi_script_name;
      include fastcgi_params;
    }
  }
}
```

問題はこれ、VirtualHost毎に設定をしないといけないのです！
ApacheならLoadModuleを1行書くだけですべてのホストで実行できていたのにこれは面倒くさい…

ちなみにlocationディレクティブはserverディレクティブ配下にしか書けないようです。
http://nginx.org/en/docs/http/ngx_http_core_module.html#location

## 代替案として

phpのCGI設定だけ別ファイルに切り出しておいてIncludeで管理した方が楽そう。

```nginx:nginx-php.conf
location ~ \.php$ {
  fastcgi_pass 127.0.0.1:9000;
  fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
  fastcgi_param PATH_INFO $fastcgi_script_name;
  include fastcgi_params;
}
```

```nginx:nginx.conf
http {
  ...
  server {
    listen 80 default_server;
    server_name example.com;
    index index.php index.html;
    ...
    include nginx-php.conf
  }
  server {
    listen 80;
    server_name www.example.com;
    index index.php index.html;
    ...
    include nginx-php.conf
  }
}
```
スッキリ。

## 実行ユーザに注意

Apache+mod_phpの場合、phpはApacheのプロセスで動作しているのでphpの実行ユーザ＝Apacheの実行ユーザとなっています。
それが、nginx+php-fpmではnginxはnginxの実行ユーザ、php-fpmはphp-fpmの実行ユーザと別々に設定されています。
そのため、Apache+mod_phpで書き出したファイル等をnginx+php-fpmで読み書きしようとするとファイル権限によりエラーとなる可能性はあります。

セキュリティ上問題ないのでしたら、手っ取り早いのはphp-fpmの実行ユーザをApacheの実行ユーザに設定してしまうことです。
※さらにいうとnginxの実行ユーザもApacheの実行ユーザにしてしまうと幸せになれるかも。

それがダメならファイルのユーザなりパーミッションを書き換えていくしかなさそうです。

## 起動方法にも注意

Apache+mod_php環境ではphpの設定を反映したい場合にはApacheのプロセスを再起動すればOKでしたが、nginxとphp-fpmはあくまで別プロセスなのでphpの設定を変更したらnginxではなくphp-fpmの再起動をしなくてはなりません。

# SSL証明書は連結してあげればOK

Apacheではサーバ証明書(SSLCertificateFile)と中間証明書(SSLCertificateChainFile)と2ファイル設定するが、nginxではサーバ証明書、中間証明書の順に1ファイルに連結してあげてssl_certificateに設定する。

| ＼ | apache | nginx |
|:-:|:-:|:-:|
|サーバ証明書|SSLCertificateFile|ssl_certificate|
|中間証明書|SSLCertificateChainFile|-|
|秘密鍵|SSLCertificateKeyFile|ssl_certificate_key|

```apache:httpd.conf
<VirtualHost _default_:443>
  SSLCertificateFile      hogehoge.crt
  SSLCertificateKeyFile   hogehoge.key
  SSLCertificateChainFile hogehoge.ca
</VirtualHost>
```

```shell-session:nginx用に証明書を生成
# hogehoge.crt > hogehoge.pem
# hogehoge.ca >> hogehoge.pem
```

```nginx:nginx.conf
http {
  server {
    listen 443 ssl;
    ssl_certificate     hogehoge.pem
    ssl_certificate_key hogehoge.key
  }
}
```

# SSLv3は無効化しておこう

nginxではデフォルトでSSL3.0が有効になっている。
POODLE脆弱性対策として、SSLv3を無効化しておこう。

```nginx:nginx.conf
http {
  server {
    listen       443 ssl;
    ...
    ssl_protocols  TLSv1 TLSv1.1 TLSv1.2; ## 使えるプロトコルをTLS1, 1.1, 1.2のみとする
```

https://www.nginx.com/blog/nginx-poodle-ssl/

# POSTできる容量に注意

ApacheではデフォルトでPOSTできるBODYのサイズ(LimitRequestBody)が2GBなので気にならないですが、nginxではデフォルトは1MBに設定されています。
WordpressやownCloudで大きめなファイルをアップロードしたい場合は変更必須です。

http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size

```nginx:nginx.conf
http {
  client_max_body_size 100m;
}
```