AND OR  

このページでは主に Nginx のモジュールや設定関連のメモを書いています。
Modules

構築

  • CentOS 6.4 (x86_64)
  • Nginx 1.4.1
  • gcc 4.4.7
     
    各アーキテクチャ毎にプリビルド済みパッケージが提供されていますが、ここでは任意のモジュールを組み込むためにソースからコンパイルしてインストールします。Nginxのコンパイルには PCRE や ZLIB ライブラリが必要なので(SSLも有効にしたい場合はOpenSSLも必要)、もし入っていなければ予めインストールしておきます。 ここでは静的ファイル圧縮転送機能、サーバステータス取得機能、SSLを利用するために3つのモジュールをコンパイル時に別途組み込んでいます。また、prefix オプションを付けない場合は /usr/local/nginx 以下にインストールされます。ログや設定ファイルも /usr/local 以下に入ってしまうのが気に入らない場合はシンボリックリンクを貼っておきましょう。ここでは一般的なCentOSのファイル構成に倣って、設定ファイルは /etc 以下、ログファイルは /var/log 以下に置くことにします。
     
    Nginx 1.4からはSPDYに対応しているので --with-http_spdy_module 付けてコンパイルすれば有効になります。

設定

ここではNginxの設定に関することを載せます。

基本

Nginxの設定ファイルはApacheのものと比べると簡潔で読みやすくなっています。ここでは基本設定項目をいくつかピックアップして紹介します。

  • URI毎の処理 (location)
    Syntax: location [ = | ~ | ~* | ^~ ] uri { ... }
            location @name { ... }
    Context: server, location
    リクエストURI毎の処理を記述するディレクティブになっています。 uri には正規表現を適用できますが、付与するプレフィックスによって適用順序に違いがあります。
    プレフィックス説明
    なし前方一致
    =完全一致 見つかったら検索終了
    ^~前方一致 見つかったら検索終了
    ~正規表現 (大文字・小文字を区別する)
    ~*正規表現 (大文字・小文字を区別しない)
    また、uri の代わりに @{任意の名前} で設定することもできます。この記法は後述の try_files ディレクティブと併せて内部リダイレクトを行うときによく使われます。
     
  • URIの書き換え (try_files)
    Syntax: try_files file ... uri 
            try_files file ... = code
    Context: server, location
    file が存在しなかったときに uri にリダイレクトします。uri はいくつも指定できます。
    ## 例
    location /path/to {
      try_files $uri $uri/ @foo;
    }
    location @foo {
      ...
    }
     
  • ログファイルの設定 (access_log, log_format)
    ログフォーマットに利用できる主な変数を以下に挙げます。これ以外の変数については公式サイトなどを参照してください。
    変数概要
    $remote_addrクライアントのIPアドレス
    $time_localアクセス日時
    $requestリクエストURL
    $request_lengthリクエストボディの長さ
    $statusHTTPステータスコード
    $body_bytes_sent送信バイト数(レスポンスヘッダのバイト数を引いた値)
    $http_refererリファラーURL(遷移元URL)
    $http_user_agentユーザエージェント(ブラウザ名・バージョン等)
    ## ログフォーマットの指定例 (mainという名前で設定)
    log_format  main  '$remote_addr [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent"';
    
    ## ログファイルのパス
    access_log /var/log/nginx/access.log main;
    上記の設定例だと以下のようなログが出力されます。
    203.216.243.240 [02/May/2013:00:14:57 +0900] "GET /archives/1826/ HTTP/1.1" 200 8080 "http://rest-term.com/archives/1777/" "Mozilla/5.0 (Windows NT 6.1; rv:20.0) Gecko/20100101 Firefox/20.0"
     
  • Keep Alive時間の設定 (keepalive_timeout)
    接続を維持する時間を設定します。同時接続数の多いサイトでは問題が起こるので適切に設定する必要があります。この設定はNginxに限らず他のHTTPサーバでも同様です。
    keepalive_timeout  65;  ## 65秒コネクションを維持
    keepalive_timeout  0;  ## 0 にするとKeep Alive無効
     
  • Expiresヘッダの付与 (expires, log_not_found)
    画像ファイルやJavaScript/CSSファイルなどに Expires ヘッダを付与してブラウザにコンテンツをキャッシュさせることでHTTPリクエスト数を削減します。また、これらのファイルへのアクセスログは基本的に不要なので出力しないようにします。
    location ~* \.(gif|jpg|png|ico|js|css|woff)$ {
      expires 30d;  ## Expiresヘッダの有効期限を30日に指定
      access_log off;
      log_not_found off;
    }
     
  • リクエストサイズ制限 (client_max_body_size)
    HTTPリクエストのエンティティサイズ制限を設定します。ここで設定したサイズを超えたリクエストを受けると、"413 Request Entity Too Large" エラーをクライアントに返します。大きなサイズのファイルをアップロードしたいときはこの項目を設定します。デフォルトは1MBです。
    client_max_body_size 10M;  ## 10MBに制限
    ただし多くの場合、PHPなどのサーバサイド処理系毎の設定も必要となります。PHPの場合は、upload_max_filesize などの設定も併せて行ってサイズ制限を設定します。
     
  • その他雑多設定
    以下の設定は特に行わなくてもHTTP配信機能的には問題ありません。
    • バージョン表示を隠す (server_tokens)
      セキュリティ等の観点でServerヘッダにNginxのバージョンを付けたくない場合は以下のディレクティブを指定します。
      server_tokens off;
       
    • pidファイルの場所を変える (pid)
      デフォルトだと logs/nginx.pid になっていて気持ち悪いので /var/run 以下に作成するように変更します。
      pid /var/run/nginx.pid;

モジュール機能

コンテンツの圧縮転送

  • HttpGzipModule (core module)
    gzipによるファイル圧縮転送を行うことができます(Apacheの場合は mod_deflate の機能)。設定ファイルには以下のように記述します。ディレクティブ数が多めなので別ファイルにして nginx.conf 内で include しても良いかもしれません。
    gzip              on;  ## gzip圧縮を有効化
    gzip_http_version 1.0;  ## 圧縮転送を行うHTTPのバージョン, 1.0にしておけば1.1でも有効化される
    gzip_types        text/plain  ## 圧縮対象ファイルのMIME Type
                      text/xml 
                      text/css 
                      application/xml 
                      application/xhtml+xml 
                      application/rss+xml 
                      application/atom_xml 
                      application/javascript 
                      application/x-javascript 
                      application/x-httpd-php;
    gzip_disable      "MSIE [1-6]\.";  ##  圧縮転送を無効にするUser-Agent (IE)
    gzip_disable      "Mozilla/4";  ## (Firefox)
    gzip_comp_level   1;  ## gzip圧縮レベル(0-9), 0だと圧縮なし, 1以上にしても圧縮率の変化は少ない
    gzip_proxied      any;  ## プロキシ経由でも圧縮転送
    gzip_vary         on;  ## Vary ヘッダを付与
    gzip_buffers      4 8k;  ## gzip圧縮処理で利用するバッファサイズ, 4*8kb=32kb
    gzip_min_length   1024;  ## gzip対象とするファイルの最小サイズ, 1024bytes以下のファイルは圧縮対象外
    gzip_static       on;  ## 静的圧縮ファイルの転送を有効化
  • HttpGzipStaticModule
    cssやjsファイル等が予めgzip圧縮されて置いてある場合にその圧縮ファイル(.gz)を代わりに転送してくれます。この機能により、リクエスト毎のgzip圧縮処理が省略されるためCPUリソースを節約することができます。HttpGzipStaticModule はコアモジュールではないのでコンパイル時に別途組み込む必要があります。
    $ ./configure --with-http_gzip_static_module

サーバステータスの取得

  • HttpStubStatusModule
    サーバステータスの取得を行いたい場合は HttpStubStatusModule の機能を利用します(Apacheの場合は mod_status の機能)。Muninなどでリソースモニタリングする際に必要となります。
    location = /nginx_status {  ## /nginx_status がエンドポイント
      stub_status on;  ## ステータス取得機能を有効化
      access_log off;  ## アクセスログを出力しない
      allow 127.0.0.1;  ## 127.0.0.1 ホストのみアクセス可能
      deny all;  ## それ以外のホストはアクセス拒否
    }
    • 動作確認
      $ curl -v http://127.0.0.1/nginx_status
      * About to connect() to 127.0.0.1 port 80 (#0)
      *   Trying 127.0.0.1... connected
      * Connected to 127.0.0.1 (127.0.0.1) port 80 (#0)
      > GET /nginx_status HTTP/1.1
      > User-Agent: curl/7.21.7 (x86_64-unknown-linux-gnu) libcurl/7.21.7 OpenSSL/0.9.8b  zlib/1.2.3 libidn/0.6.5 libssh2/1.2.8
      > Host: 127.0.0.1
      > Accept: */*
      >
      < HTTP/1.1 200 OK
      < Server: nginx
      < Date: Wed, 13 Jun 2012 13:51:12 GMT
      < Content-Type: text/plain
      < Content-Length: 109
      < Connection: close
      <
      Active connections: 1
      server accepts handled requests
       10991 10991 10985
      Reading: 0 Writing: 1 Waiting: 0
      * Closing connection #0

HttpStubStatusModule もコアモジュールではないのでコンパイル時に別途組み込む必要がます。

$ ./configure --with-http_stub_status_module

キャッシュコンテンツの配信 (memcached連携)

  • HttpMemcachedModule (core module)
    memcachedにキャッシュされたコンテンツを配信したい場合は HttpMemcachedModule の機能を利用します。キャッシュミスした場合はバックエンドサーバにプロキシする構成を採ることが多いので、併せて HttpUpstreamModule の機能も利用します。
    upstream backend {
      ip_hash;  ## IPハッシュによる分散
      server foo.co.jp;
      server bar.co.jp; 
    }
    server {
      location / {
        ## その他設定項目は省略
        
        ## POSTリクエストはバックエンドへ
        if($request_method = POST) {
          proxy_pass http://backend;
          break;
        }
        set $memcached_key $request_uri;  ## キャッシュキーはリクエストURI
        memcached_pass 127.0.0.1:11211;  ## memcachedのhost:portを指定
        default_type text/html;
        error_page 404 502 = @fallback;  ## キーが見つからないあるいはmemcachedに接続できなければバックエンドへ
      }
     
      location @fallback {
       ## バックエンドサーバ(アプリケーションサーバ)にプロキシ
        proxy_pass http://backend;
      }
    }
    また、Nginx 1.1.4からはupstreamで設定したバックエンドサーバにもKeep-Alive接続可能になっています。

MP4ファイルのHTTP Pseudo-Streaming配信

  • HttpMp4Module
    MP4(H.264/AAC)ファイルのHTTP Pseudo-Streaming(HTTPによる疑似ストリーミング)機能をサポートしています。
    ブログの方でもまとめているので参考までに(NginxのHTTP Pseudo-Streamingを試す)。
    ## /video 以下にアクセスされたらMP4ファイルのPseudo-Streaming配信機能を有効にする
    location /video {
      mp4;
      mp4_buffer_size 1m;  ## バッファサイズ(デフォルト512KB)
      mp4_max_buffer_size 5m;  ## 最大バッファサイズ(デフォルト10MB)
    }
    拡張子でマッチさせる設定を入れなくても .mp4/.m4v/.m4a は判別してくれるようです。atomデータ処理する時にバッファが足りなくなった場合はHTTP 500エラーが返るので適宜調整してください。
    • アクセス
      HTTPでMP4ファイルのあるパスにアクセスするだけです。その際にクエリパラメータ(start)として再生開始位置(秒)を指定します。動画の尺を超える値を入れるとHTTP 500エラーが返ります。
      http://example.com/video/sample.mp4?start=123

HttpMp4Module はコアモジュールではないのでコンパイル時に別途組み込む必要があります。

$ ./configure --with-http_mp4_module

アプリケーションコンテナ

NginxではApacheにおける mod_php や mod_wsgi などのようにHTTPサーバに言語処理系自体を組み込むのではなく、アプリケーションコンテナを単独のプロセスとして稼働させ、リクエストを適宜対応するコンテナにプロキシする構成を採ることが多いです。

PHP-FPM

PHP-FPM (FastCGI Process Manager) is an alternative PHP FastCGI implementation with some additional features useful for sites of any size, especially busier sites.

公式サイト: PHP-FPM
PHPアプリケーションコンテナの実装の一つ。このWikiも Nginx + PHP-FPM 上で動作している。

導入

RedHad系なら yum でインストールできます。

$ sudo yum install php-fpm.x86_64

設定

パラメータチューニング関連の設定項目を整理します。

pm子プロセスをどのように生成するか。(static/ondemand/dynamic)
pm.max_children子プロセスの最大数。Apacheでいうところの MaxClients に該当。
pm.max_requests子プロセスが再起動するまでに受け付けるリクエスト数。Apacheでいうところの MaxRequestsPerChild に該当。
pm.start_servers起動時に作成される子プロセスの数。(pm が dynamic の時のみ)
pm.max_spare_serversアイドル状態のサーバープロセスの最大値。(pm が dynamic の時のみ)
pm.min_spare_serversアイドル状態のサーバープロセスの最大値。(pm が dynamic の時のみ)
slowlog処理に時間のかかったリクエストを記録するログファイル。(デフォルト $INSTALL_PREFIX/log/php-fpm.log.slow)

次に nginx.conf を編集します。Nginxと同じホストで稼働させる場合はUNIXドメインソケットで通信すると効率的です。

# pass the PHP scripts to FastCGI server listening on unix domain socket
location ~ \.php$ {
  include        fastcgi.conf;
  fastcgi_pass   unix:/var/run/php-fpm/www.sock;
  fastcgi_index  index.php;
  fastcgi_param  PATH_INFO  $fastcgi_path_info;
  fastcgi_param  PATH_TRANSLATED  $document_root$fastcgi_script_name;
  fastcgi_intercept_errors on;
}
  • fastcgi.conf
    fastcgi.confファイルは以下のようになっています。
    fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
    fastcgi_param  QUERY_STRING       $query_string;
    fastcgi_param  REQUEST_METHOD     $request_method;
    fastcgi_param  CONTENT_TYPE       $content_type;
    fastcgi_param  CONTENT_LENGTH     $content_length;
    fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
    fastcgi_param  REQUEST_URI        $request_uri;
    fastcgi_param  DOCUMENT_URI       $document_uri;
    fastcgi_param  DOCUMENT_ROOT      $document_root;
    fastcgi_param  SERVER_PROTOCOL    $server_protocol;
    fastcgi_param  HTTPS              $https if_not_empty;
    fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
    fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;
    fastcgi_param  REMOTE_ADDR        $remote_addr;
    fastcgi_param  REMOTE_PORT        $remote_port;
    fastcgi_param  SERVER_ADDR        $server_addr;
    fastcgi_param  SERVER_PORT        $server_port;
    fastcgi_param  SERVER_NAME        $server_name;
    # PHP only, required if PHP was built with --enable-force-cgi-redirect
    fastcgi_param  REDIRECT_STATUS    200;

uWSGI

uWSGI is a fast, self-healing and developer/sysadmin-friendly application container server coded in pure C. 

公式サイト: uWSGI (WSGI: Web Server Gateway Interface)
WSGIアプリケーションコンテナの実装の一つ。

  • 対応プラットフォーム
    Portability (tested on Linux 2.6/3.x, Solaris/OpenSolaris/OpenIndiana, OpenBSD, NetBSD, DragonflyBSD, FreeBSD >= 8.0, MacOSX, Nexenta, and Haiku) 
    FreeBSDでは8.0以降が対象らしい。2012年現在、7.x系を現役で使っている人はまだそこそこいるような気はします。
  • 対応言語
    もともとuWSGIはPythonアプリケーションを対象としていましたが、現在ではPerl, Ruby, PHP, Luaなど多くの言語に対応しています。ここではPythonアプリケーションの動作確認までを行います。

導入

  • pipを利用する場合
    現在ではpipで簡単にインストールできます。Linuxへのpipの導入は割愛。FreeBSD8.0以降の場合は {PORTS_DIR}/devel/py-pip へ異動後、make install すればpipが利用可能になります。
    $ sudo pip install uwsgi
  • ソースからインストールする場合
    $ wget http://projects.unbit.it/downloads/uwsgi-latest.tar.gz  ## 最新版を取得
    $ tar zxf uwsgi-latest.tar.gz
    $ make
    後は出来上がったuwsgiバイナリをPATHの通った任意の場所に置きます。

設定

nginx.conf を編集します。ここではuWSGIサーバを 127.0.0.1:8000 で稼働させている場合(TCPソケット)の設定になっています。

## pass the Python scripts to uWSGI server listening on 127.0.0.1:8000
location ~ ¥.py$ {
  uwsgi_pass 127.0.0.1:8000;
  include uwsgi_params;
}
  • uwsgi_param
    uwsgi_paramファイルは以下のような内容になっています。
    uwsgi_param  QUERY_STRING       $query_string;
    uwsgi_param  REQUEST_METHOD     $request_method;
    uwsgi_param  CONTENT_TYPE       $content_type;
    uwsgi_param  CONTENT_LENGTH     $content_length;
    
    uwsgi_param  REQUEST_URI        $request_uri;
    uwsgi_param  PATH_INFO          $document_uri;
    uwsgi_param  DOCUMENT_ROOT      $document_root;
    uwsgi_param  SERVER_PROTOCOL    $server_protocol;
    uwsgi_param  HTTPS              $https if_not_empty;
    
    uwsgi_param  REMOTE_ADDR        $remote_addr;
    uwsgi_param  REMOTE_PORT        $remote_port;
    uwsgi_param  SERVER_PORT        $server_port;
    uwsgi_param  SERVER_NAME        $server_name

アプリケーション

動作確認用のWSGIアプリケーションを準備します。

  • hello.py

起動

アプリケーション毎にuWSGIサーバを立ち上げます。

$ uwsgi --socket 127.0.0.1:8000  --file hello.py  ## シングルプロセスモードで起動
  • YAMLファイルによる設定
    uwsgiアプリケーションの各種設定はYAMLファイルで設定可能です。
    hello:
      master: 1
      processes: 1
      socket: 127.0.0.1:8000
      wsgi-file: /var/www/html/labs/hello.py
      callable: app
      max-request: 1000
      daemonize: /var/log/uwsgi/hello.log
      pidfile: /var/run/hello.pid
    以下のように --yaml オプションの後に YAMLファイル名:アプリケーション名 と指定して起動します。
    $ uwsgi --yaml uwsgi.yaml:hello
    [uWSGI] getting YAML configuration from uwsgi.yaml

動作確認

ブラウザから /hello.py にアクセス(拡張子が.pyならなんでもいい)して hello, world と表示されたらOK。

モジュール開発

Nginxモジュールの開発手順についてメモしていきます。
atodekaku