読者です 読者をやめる 読者になる 読者になる

nginx上でサブディレクトリのCakePHPアプリを動作させる

nginx CakePHP

もう本当に大変で、1週間潰れました。
同じように貴重な土日を潰してしまう人が一人でも減ることを願って。

環境

目標

サブディレクトリにあるCakePHPアプリを動作させたい。

いいかえるとhttp://example.com/subdir/ にアクセスして、サーバー上の/usr/shared/nginx/example.com/subdirにあるCakePHPアプリにアクセスしたい。

stackoverflowなどに同様の質問は沢山挙がっているのですが、どのベストアンサーも私の環境では正常に動作しませんでした。

CakePHP公式サイトのnginx設定例じゃダメなの?

ダメなんです。。。

server {
    listen   80;
    server_name www.example.com;
    rewrite ^(.*) http://example.com$1 permanent;
}

server {
    listen   80;
    server_name example.com;

    # root directive should be global
    root   /var/www/example.com/public/app/webroot/;
    index  index.php;

    access_log /var/www/example.com/log/access.log;
    error_log /var/www/example.com/log/error.log;

    location / {
        try_files $uri $uri/ /index.php?$uri&$args;
    }

    location ~ \.php$ {
        try_files $uri =404;
        include /etc/nginx/fastcgi_params;
        fastcgi_pass    127.0.0.1:9000;
        fastcgi_index   index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

残念ながら、これはサーバのルートディレクトリにCakePHPを設置した場合の設定例なのです。
サブディレクトリにCakePHPを配置した場合の設定を一から考える必要があります。

CakePHP公式サイトのnginx設定例は何をやっているのか

公式サイトの設定例はそのまま利用できないものの、nginxでどう設定すればよいのかヒントになるので、詳しく見ていきます。

まず、最初のserverコンテキストで設定されているものです。

server {
    listen   80;
    server_name www.example.com;
    rewrite ^(.*) http://example.com$1 permanent;
}

これはwww.有りでアクセスがあった際に、www.なしのhttp://example.com/にリダイレクトする設定です。これはCakePHPと関係がないので、以後無視します。

後半のserverコンテキストを見ます。

server {
    listen   80;
    server_name example.com;

    # root directive should be global
    root   /var/www/example.com/public/app/webroot/;
    index  index.php;

    access_log /var/www/example.com/log/access.log;
    error_log /var/www/example.com/log/error.log;

    location / {
        try_files $uri $uri/ /index.php?$uri&$args;
    }

    location ~ \.php$ {
        try_files $uri =404;
        include /etc/nginx/fastcgi_params;
        fastcgi_pass    127.0.0.1:9000;
        fastcgi_index   index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

server_name example.com;
Hostがexample.comであるアクセスは、このコンテキストの設定で処理されることを宣言しています。

root /var/www/example.com/public/app/webroot/;
URL上のルートパスに対応するサーバ上のフルパスが設定されます。apacheにおけるDocumentRootと同じ。

locationコンテキストその1

    location / {
        try_files $uri $uri/ /index.php?$uri&$args;
    }

(先ほどのrootディレクティブの設定は{}の内側全域で有効であることに注意)
ここのlocationコンテキストの動作はやや複雑。

  1. /var/www/example.com/public/app/webroot/$uriという静的ファイルを探す
  2. (無ければ)/var/www/example.com/public/app/webroot/$uri/というディレクトリを探す
  3. (それも無ければ)/var/www/example.com/public/app/webroot/index.php?$uri&$argsに内部リダイレクトする

  4. $uriにはクライアントから要求のあったURLから、server_nameを取り除いた文字列が入る

    • 例: http://www.example.com/xxx/yyyにアクセスがあった場合、$uri = xxx/yyy
  5. $argsはURLパラメータを保持したまま内部リダイレクトするための変数

locationコンテキストその2

    location ~ \.php$ {
        try_files $uri =404;
        include /etc/nginx/fastcgi_params;
        fastcgi_pass    127.0.0.1:9000;
        fastcgi_index   index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

locationコンテキストに~をつけると、設定を適用したいアクセスを正規表現で指定できます。
この場合、末尾が.phpで終わるファイルへのアクセスは、このlocationコンテキストの設定が適用されます。

nginx設定例

以上を踏まえて、こうなりました。

server {
    listen       80;
    server_name  example.com;

    root   /usr/share/nginx/example.com;

    location / {
        index  index.php index.html;
    }

    location ~ ^/subdir/(img|css|js|files)/(.+)$ {
        root /usr/share/nginx/example.com/subdir/app/webroot;
        try_files /$1/$2 =404;
    }

    location ~ ^/subdir/(.+\.php) {
        fastcgi_pass    127.0.0.1:9000;
        fastcgi_index   index.php;
        fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include         fastcgi_params;
    }

    location ~ ^/subdir/(.*)$ {
        index  index.php index.html;
        try_files /subdir/$1 /subdir/$1/ /subdir/index.php?$1&$args;
    }

    location ~ \.php$ {
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include        fastcgi_params;
    }
}

参考資料

Nginx Community
http://wiki.nginx.org/

Nginx はどのようにリクエストを処理するか
http://nginx.org/ja/docs/http/request_processing.html

Nginx で location の判定方法と優先順位を調べる
http://server-setting.info/centos/nginx-location-check.html

nginx連載5回目: nginxの設定、その3 - locationディレクティブ
http://heartbeats.jp/hbblog/2012/04/nginx05.html