トップ 差分 一覧 ソース 検索 ヘルプ PDF RSS ログイン

nginx

nginxでエンジンエックスと読むそうな。
webサーバーといえばApacheが有名だけど、nginxのほうが効率が良いらしい。
Yahooやfacebookなどの大手サイトではnginxを採用している。

raspbianならjessieのnginx-1.6以降を使ったほうが良いと感じた。
wheezyのnginx-1.2でドキュメントのとおりに行かずに嵌る、苦労するというのが実感。

インストール

とりあえず本家サイト。

nginx
http://nginx.org/

つづいてdebianでのインストール。

# apt-get install nginx-light

パッケージに種類があるようだけど、まずは軽い系で行って、足りなきゃ後で考える。

パッケージの違いについてはDebian Wikiが詳しい。

Nginx - Debian Wiki
https://wiki.debian.org/Nginx

ドキュメント、モジュール リファレンスとか。

nginx documentation
http://nginx.org/en/docs/

レスポンスでバージョン非公開

レスポンスのヘッダーにnginxのバージョンが出るのが嫌なら。

/etc/nginx/nginx.conf

http {
       server_tokens off;
       :
}

virtual hostの設定

/etc/nginx/sites-availableで使用するサイトの設定(例えばdefaultとか)に。

server {
       listen 80;
       server_name foo.sample.com;
       :
}
server {
       listen 80;
       server_name bar.sample.com sample.com;
       :
}
server {
       listen 80 default_server;
       server_name baz.com;
       :
}

設定が無い場合は、最初に記述されたserverがdefault_serverになる。

locationの優先順位

http://localhost/にアクセスした場合

location / { foo }
location = / { bar }

最初に書かれているfooかなと思いきやbarが有効、それ以外ならfooが有効になるそうな。

nginx連載5回目:nginxの設定その3
http://heartbeats.jp/hbblog/2012/04/nginx05.html

正規表現でマッチするほうが優先されるとのこと。
apacheのdirectoryみたいな下位にも有効な設定はlocationの入れ子になる模様。

fastcgi(php-fpm)が動かなくて嵌ったら

fastcgi_pass unix:/var/run/php5-fpm.sock;
include fastcgi_params;

のあたりは問題ないと思うが、

fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

がそのlocationにおいて、呼び出されるphpのディスク上のパスになる。

$document_rootは

root /path/to;
または
alias /path/to;

から設定され、$fastcgi_script_nameはURLからnginxにより設定されるが、これが嵌る素。

こちらが思ってるような$fastcgi_script_nameじゃなければ、not foundやpermission deniedに見舞われる(汗)。

とりあえずphpを動かし、phpinfo()をかまして変数を確認したいところなので

fastcgi_param SCRIPT_FILENAME /path/to/phpinfo.php;

のようにphpinfo()を記述したphpファイルまでのパスを直に設定し、そもそも動いてるのか、変数の中身はどうなってるのかをチェックするのが手っ取り早い。

変数の確認

location / {
:
add_header debug_docroot $document_root;
add_header debug_url $uri;
}

有効なロケーション内でadd_headerすると、レスポンスのヘッダーに追加してくれる。

もしくはそれがphp-fpmの設定であれば

fastcgi_param FOO_VALUE_NAME $document_root;

みたいな感じで、phpinfo()の出力で

_SERVER["FOO_VALUE_NAME"]

として一覧から確認できる。

rewriteの設定

proxyの設定

Zend Framework2の設定

nginxとphp5-fpmでZend Framework2を動かす。

# apt-get install nginx-light php5-fpm

/var/wwwにスケルトンとライブラリを解凍し、/var/www/zf2/publicと/var/www/ZendFramework-2.*.*/libraryという感じに配置。

とりあえず/etc/nginx/saites-available/defaultをいじる。

server {
        listen 80;

        root /var/www/zf2/public;
        server_name _;
        index index.php

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

        location ~ \.php$ {
                fastcgi_pass unix:/var/run/php5-fpm.sock;
                fastcgi_param ZF2_PATH /var/www/ZendFramework-2.*.*/library;
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                include fastcgi_params;
        }

        location ~ /\.ht {
                deny all;
        }
}

これはnginx-1.2.1で動作した設定。バージョンによってindexを書く場所やtry_filesの挙動(locationに@名前を使用した場合)が変わるようで、ぶっちゃけよくわからない(汗)。

外部のAPサーバーを使う

たとえばサーバーが2台あって

  • サーバー1がインターネットと繋がっていてnginxで静的ファイル(.htmlやcssやjsや画像)
  • サーバー2がサーバー1とLANで繋がっていてphp5-fpmで動的ファイル(.php)

みたいな感じのとき。

とりあえずサーバー2にphp5-fpmをインストール。

/etc/php5/fpm/pool/www.confで

#listen = /var/run/php5-fpm.sock
listen = xxx.xxx.xxx.xxx:9000

として起動。

# netstat -autn
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 xxx.xxx.xxx.xxx:9000       0.0.0.0:*               LISTEN

みたいに出ればポート9000で待ち受けしてる。
※ファイアーウォール(iptables)の設定があるなら解放しておくこと。

サーバー1からnetcatを使って

# nc -zv xxx.xxx.xxx.xxx 9000
xxx.xxx.xxx.xxx: inverse host lookup failed: Unknown host
(UNKNOWN) [xxx.xxx.xxx.xxx] 9000 (?) open

openとか出れば接続できてる。
エラーっぽい感じなのは逆引きができてないからで、ここでは問題なし。

サーバー1のnginx側は

root /path/to
:
location ~ \.php$ {
    fastcgi_pass xxx.xxx.xxx:9000;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
}

fastcgi_passがip:port指定になる。
rootやSCRIPT_FILENAMEはサーバー2内のプログラムファイルまでのパスになるので注意。
ここを間違えるとfile not foundとなる。

これでブラウザから

http://サーバー1/foo.php

にアクセスすると、サーバー1のnginxからxxx.xxx.xxx:9000にSCRIPT_FILENAMEのリクエストが行って、サーバー2の

/path/to/foo.php

が実行され、結果がnginxに返され、さらにnginxからブラウザに返される。

ブラウザでサーバー2にあるfoo.phpの実行結果が表示されれば成功。

aliasで勘違い

特定のlocationでdocument_root以下とは別の場所にアクセスさせたいと思い、aliasかなとテスト。

location /foo/ {
    alias /var/hoge/;
}

でどうかなと思ったけどダメだった。

このあたりはnginxのサイトのドキュメントをみると、

Module ngx_http_core_module - alias
http://nginx.org/en/docs/http/ngx_http_core_module.html#alias
/foo/bar.txt → /var/hoge/bar.txt

となるかのような記述だが、少なくてもraspbianのwheezyのnginx-1.2では/var/hoge/でindexファイルを探す挙動だった。バージョンが古いからだろうか(汗)。

拡張子が.txtだったらってケースを試してみたが

location ~ ^/foo/.*\.txt$ {
    alias /var/hoge/;

ファイル名.txtが何であっても/var/hoge/index.html(indexの設定による)になってしまう。

location ~ ^/foo/(.*\.txt)$ {
    alias /var/hoge/$1;

括弧を使うと値を利用できるらしい。
しかしあまりごちゃごちゃするようならバーチャルホストを分けてしまったほうがいいかも(汗)。

ob_flush()やflush()が効かない

for($i = 0; $i < 5; $i++) {
    echo $i . "<br>\n";
    ob_flush();
    flush();
}

ob_flush()でPHPのバッファを出力し、flush()でwebサーバのがバッファを出力することで逐次表示が実現される、と単純に思っていたが、基本はApacheに対するものらしい。

で、PHPのoutput_bufferはob_flush()で吐き出せるのだが、nginxではどうなってるのか調べた。

  • keep-aliveが有効であること
  • gzipが無効であること
  • プロキシ系のバッファが無効であること

あたりがとりあず必要らしく対象のlocationとかに

fastcgi_keep_conn on;
gzip off;
proxy_buffering off;

とするのだが、nginxはapacheのmod_phpみたいな一体型でないため、一般にはphp-fpmの出力を一旦バッファし、それをクライアントに返すようになっている。

fastcgi_buffering off;

とするか、phpプログラムの中で

<?php
header('X-Accel-Buffering: no');

とすることでphp-fpmの出力をそのままクライアントに返す模様。

ところがこの設定

This directive appeared in version 1.5.6.

なのね(汗)。

raspbianのwheezyはapt-getでインストールできるパッケージがnginx-1.2と古いので、fastcgiのバッファを無効にできずにflush()も効かない。

そこでネット上を徘徊してたらこんなん見つけた。

for($i = 0; $i < 5; $i++) {
    echo str_repeat(" ", 1024 * 1);
    echo $i . "<br>\n";
    ob_flush();
    flush();
}

nginxのfastcgi_buffer_sizeが1k(1024)だった場合の例だが、空白でも送りつけりゃバッファが溢れるんじゃね? っていう戦法らしい。
flush()はいらないのかと思ったら、これはこれで必要らしい。
とりあえず動いたが、これは酷いなぁと思ったのであった。