Unicorn用のNginxの設定をする
nginx.confを昨日いい加減に書いたので、
設定を見直す。
昨日の書いたのは以下。
nginx.conf
user nginx; worker_processes 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; upstream unicorn_app { server unix:/tmp/unicorn.sock; } server { listen 80; server_name _; location / { proxy_pass http://unicorn_app; } } }
以下を参考にした。
- nginx documentation
- nginx wiki
- nginx連載4回目: nginxの設定、その2 - バーチャルサーバの設定 - インフラエンジニアway - Powered by HEARTBEATS
- nginx設定メモ - おおにしあきらの日記
serverブロックを別ファイルにする
まず、初期状態のnginx.confのhttpブロックはこうなってる。
http { ... include /etc/nginx/conf.d/*.conf; }
各サーバの設定はconf.d以下にサーバごとにファイルを分けて格納するのがより良い方法なのだろう。
ということで、新たにconf.d/rails_app.confを作って、upstreamブロックとserverブロックをそっちに移動する。
rails_app.conf
upstream unicorn_app { server unix:/tmp/unicorn.sock; } server { listen 80; server_name _; location / { proxy_pass http://unicorn_app; } }
nginx.confは初期状態の、conf.d以下をincludeする形に戻す。
ここまでで一旦動作確認する。本質的には設定内容は変わってないはずなので、問題なく動くはず。
$ unicorn_rails -c config/unicorn.rb
conf.d以下に最初からあるファイル(default.conf、example_ssl.conf)はファイル名末尾に.bkとかを付けてincludeしないようにしておいた。
設定内容の意味を知る
だいたい見た目から予想はつくものの、昨日の時点ではちゃんと調べずに書いてたので、ちょっと調べた。
upstream
Wikiにはこう書いてある。
Defines a group of servers. Servers can listen on different ports.
Module ngx_http_upstream_module
サーバグループを定義するやつみたい。
今回のように一つだけ書く場合には、ただ単に後ろで参照するための名前を付けているのと同じだと思う。
試しにupstreamの内容を後方のproxy_passに直接書いてみる。
rails_app.conf
#upstream unicorn_app { # server unix:/tmp/unicorn.sock; #} server { listen 80; server_name _; location / { #proxy_pass http://unicorn_app; proxy_pass http://unix:/tmp/unicorn.sock; } }
リロード。
$ sudo nginx -s reload $ unicorn_rails -c config/unicorn.rb
問題なく表示された。元に戻しておく。
listen
これは見た目通りリッスンするポート番号だろう。
Sets the address and port for IP, or the path for a UNIX-domain socket on which the server will accept requests.
サーバが受け入れるリクエストのアドレスとポート、またはUNIXドメインソケットのパス。
それはまあそうなんだけど、気になるのはデフォルト。
If the directive is not present then either :80 is used if nginx runs with the superuser privileges, or :8000 otherwise.
とのことなので、superuser権限で実行してたらデフォルトで*:80が使われる。
ということはlisten 80;
の行は要らないから消しちゃおう。
リロード。問題なし。
server_name
これも見た目通り。
Server names are defined using the server_name directive and determine which server block is used for a given request.
nginxはこのリクエストを受け取ると、このホスト名がserver_nameディレクティブに設定したサーバ名に一致するserverディレクティブのバーチャルサーバを選び、そのserverディレクティブ内の設定が適応されます。
nginx連載4回目: nginxの設定、その2 - バーチャルサーバの設定 - インフラエンジニアway - Powered by HEARTBEATS
指定してあるアンダースコア(_
)は全部に一致するやつ。
In catch-all server examples the strange name “_” can be seen:
最初はこれもアンダースコアがデフォルトかと思ったけど、デフォルトは""
だった。
Default: server_name "";
It allows this server to process requests without the “Host” header field
空を意味する""を設定すると、Host:ヘッダ フィールドがない場合に一致します。
nginx連載4回目: nginxの設定、その2 - バーチャルサーバの設定 - インフラエンジニアway - Powered by HEARTBEATS
""
の場合にはHostヘッダフィールドがない場合に一致となっているので、server_name _;
の行を削除すると動かないかと思ったけど、動いた。server_name hoge;
とかにしてみても動いた。
なんでだろうと思ったけど、
複数のバーチャルサーバがあるときには、リクエストのHost:ヘッダ フィールドのホスト名がserver_nameディレクティブのサーバ名に一致するserverディレクティブのバーチャルサーバが適応されます。しかし、一致しない場合にはデフォルトサーバとして選ばれたバーチャルサーバが適応されます。
デフォルトサーバはIPアドレスとポート番号の条件が一致したlistenディレクティブを持つserverディレクティブの中で次のものが選ばれます。
- 一致したlistenディレクティブの中でdefault_serverオプションを持つ
- 設定ファイル内で最初に一致したlistenディレクティブを持つ
listenディレクティブにdefault_serverパラメータを付けると、そのserverディレクティブがデフォルトサーバになります。
nginx連載4回目: nginxの設定、その2 - バーチャルサーバの設定 - インフラエンジニアway - Powered by HEARTBEATS
これの二個目に合致して、デフォルトサーバになってるっぽい。
結果的に動くけど、意図した動作じゃないので、やっぱりアンダースコアは指定した状態にしておく。
location
これも直感的。 指定したパスに一致したリクエストを受けたときの動作をブロック内で設定する。
proxy_pass
プロキシ先のURIやパスを指定する。
Sets the protocol and address of a proxied server and an optional URI to which a location should be mapped.
できあがり
以上を踏まえると以下のような感じになった。
nginx.conf(初期設定のまま)
user nginx; worker_processes 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 65; #gzip on; include /etc/nginx/conf.d/*.conf; }
conf.d/rails_app.conf
upstream unicorn_app { server unix:/tmp/unicorn.sock; } server { server_name _; location / { proxy_pass http://unicorn_app; } }
まとめ
超シンプルな設定でNginxのパワーを全然活かしてないんだろうけど、今のところこれで全然問題なさそう。
2015/5/28 追記
上記の設定だと、アプリでリダイレクトしたとき(scaffoldでできるcreateとかupdateとか)のときに、ポート番号が引き継がれなくてページが読み込めなかった。
なので、プロキシ時にヘッダ情報を引き継ぐ処理を追加する。
参考:Rails 4.2 + Unicorn + Nginx でアプリケーションサーバの構築 - Qiita
upstream unicorn_app { server unix:/tmp/unicorn.sock; } server { server_name _; location / { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_pass http://unicorn_app; } }
proxy_set_header Host $http_host;
だけで一応上記の問題は解消したんだけど、参考にしたページに従って他の二行も追加しておいた。