[Rails] Nginx × Pumaを連携させる方法
Nginxを仕事で使う際、ネット上には既に参考になる設定が存在するのですが、
何故その設定が必要になるのか、その詳細などが分からなかったので調べてみました。
環境
- Amazon Linux2
- Nginx version 1.18.0
- ACMとALBを使っている
Nginxの設定ファイル
実際に作ったnginxの設定ファイルがこちらになります。(一部変更)
上から順に解説して行きます。
upstream app {
server unix:///var/www/rails/tmp/sockets/puma.sock fail_timeout=0;
}
server {
listen 80 default_server;
server_name _;
location = / {
proxy_pass http://app;
}
}
server {
listen 80;
server_name example.com;
error_log /var/www/rails/log/error.log;
access_log /var/www/rails/log/access.log;
root /var/www/rails/public;
try_files $uri/index.html $uri.html $uri @app;
location @app {
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Forward_For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
proxy_pass http://app;
}
}
UNIXドメインソケットによる接続
まず、NginxとPumaを接続するための設定を書いていきます。
upstreamコンテキストで、バックエンドのアプリケーションサーバ、
pumaを使う前提なので、puma.sock
を指定すればOKです。
upstream app {
server unix:///var/www/rails/tmp/sockets/puma.sock fail_timeout=0;
}
このupstreamに付けた app
という名前は後述する proxy_pass
ディレクティブでまた使います。
UNIXドメインソケットはこちらの記事が参考になりました。
serverコンテキストに外部からのアクセス方法を記述する
listenディレクティブ
受け付けるポート番号を指定します。
特定のIPアドレスでのみリクエストを受付けたい場合には、 IPアドレス:ポート番号
の様に
書けるみたいですが、まだ試したことはありません。
server_nameディレクティブ
ここでホスト名を指定します。
例)
192.168.0.1
hogepiyo.com
ホスト名がどのserver_nameにもマッチしなかった場合の設定を記述する場合は、
listenディレクティブに、default_server
を追加することでこの様に書けます。
server {
listen 80 default_server;
server_name _;
location = / {
proxy_pass http://app;
}
}
ALBのヘルチェックのために記述しました。locationのパスはヘルスチェック用のパスがあるならそちらを使用します。
error_log,access_logディレクティブでログを残す
このティレクティブでは、ログファイルの出力先のファイル名を記述します。
rootディレクティブ
静的コンテンツのパスをドキュメントルートに設定します。
railsでは public
フォルダです。
root /var/www/rails/public
try_filesディレクティブ
引数の順番でファイルが存在するか調べてなければ、最後の引数の処理をします。
ここでは、ファイルが見つからなければwebアプリケーションへ転送するように設定しています。
try_files $uri/index.html $uri.html $uri @app;
locationディレクティブ
locationディレクティブではURLのパス名ごとの設定を記述できるのですが、
ここでは、@プレフィックスを使ってパス名には無関係にpumaへ転送するように設定しています。
# ファイルがなければ、pumaへ
try_files $uri/index.html $uri.html $uri @app;
location @app {
# 省略
# proxy_passディレクティブで転送先のサーバを指定
proxy_pass http://app;
}
proxy_redirectディレクティブ
リダイレクトに使われるLocationヘッダをどの様に書き換えるかを指定します。
今回は応答を書き換えない off
を指定しました。
off
の他にも, default
、また第一引数に書き換え対象の文字列、第二引数に書き換え先の文字列を指定出来ますが、off
以外指定したことないのでよく分からんです。
ヘッダの設定を追加する
何も設定しないと、webアプリケーションからはnginx(プロキシ)からのアクセスに見えてしまう
のと、基本的にクライアントからのリクエストのヘッダ情報はそのままバックエンドに送られます
が、 一部書き換えられてしまうヘッダ情報もあるので、注意が必要になります。
proxy_set_header
ディレクティブを使ってヘッダの情報を付与していきます。
今回追加したのはコチラ。
追加したヘッダ情報 | 役割 |
---|---|
Host | サーバーのホスト名。upstream名に書き換えられるので、今回はnginxで使用できる変数 $host を指定しました。 |
X-Forwarded_For | ロードバランサやプロキシを経由する時に送信元を判別するために利用する。複数の可能性がある。 $proxy_add_x_forwarded_for を指定しました。 |
X-Real_IP | ロードバランサやプロキシを経由する時に送信元を判別するために利用する。X-Forwarded_Forと違い1つだけ。$remote_addr を指定しました。 |
X-Forwarded-Proto | ALBをSSLの終端としているので、webアプリケーションにはセキュアなリクエスト(https)であることが伝わらないので、クライアントのプロトコルがhttpsであることを伝えるために $http_x_forwarded_proto を指定しました。 |
使ったnginxの変数
変数名 | 意味 |
---|---|
$uri | パラメータなしのリクエストURI |
$remote_addr | クライアントのIPアドレス |
$host | 次の優先順位で決まる。リクエストライン -> Hostヘッダフィールド -> リクエストに一致するサーバー名 |
$proxy_add_x_forwarded_for | ALBはEC2に X-Forwarded-For: xxx.xxx.xxx.xxx を送ってくれるので、これを参照する。 |
$http_x_forwarded_proto | ALBはEC2に X-Forwarded-Proto: https を送ってくれるので、これを参照する。 |
参考にしたページ
Discussion