背景
ポートフォリオをEC2で公開するときにrails serverだとhttpで3000番ポートで通信をしなければならず、アクセスログの取得が不可で、かつアクセス負荷に対応ができません。
そういった場合、Nginxを利用してpumaをunixドメインソケットでリバースプロキシをする場合、接続方法でハマってしまったので、備忘録を兼ねてまとめます。
環境
EC2(AmazonLinux2)
Nginx 1.20
puma 5.2.2
ruby 2.7.2
Rails 6.1
MySQL 5.7
puma
WEBサーバーの一つ。Railsではアプリケーションサーバーとしてよく使われていると思います。
速度やメモリ効率に強みを持つらしい。同様のサーバーではunicornなどがある。
pumaとunicornの比較はこの以下のサイトがわかりやすかったです。
puma設定ファイル
max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count }
threads min_threads_count, max_threads_count
worker_timeout 3600 if ENV.fetch("RAILS_ENV", "production") == "production"
bind "unix:///var/www/アプリ名/shared/sockets/puma.sock"
environment ENV.fetch("RAILS_ENV") { "production" }
pidfile ENV.fetch("PIDFILE") { "shared/pids/server.pid" }
plugin :tmp_restart
ディレクティブ | 説明 |
---|---|
max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } | 変数max_threads_countを定義 |
min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } | 変数min_threads_countを定義 |
threads min_threads_count, max_threads_count | スレッドの最小数, 最大数を定義 |
worker_timeout 3600 if ENV.fetch("RAILS_ENV", "production") == "production" | pumaのworkerのタイムアウト時間を定義 |
bind "unix:///var/www/アプリ名/shared/sockets/puma.sock" | bindでどのように接続するかをURIで指定。今回はunixソケット経由で接続 |
environment ENV.fetch("RAILS_ENV") { "production" } | pumaをどの環境で動作させるか指定。今回はproduction |
pidfile ENV.fetch("PIDFILE") { "shared/pids/server.pid" } | PIDファイルの設置場所 |
plugin :tmp_restart | pumaに機能追加するときに使う。デフォルトでtmp_restart。pumaを再起動することでできる |
Nginx
NginxとはWEBサーバーの一つです。
ApacheというWEBサーバーの弱点であるC10k(Connect 10 × 1000 = 10,000の通信)問題を回避したWEBサーバーです。
Apacheは1アクセスに対して1対応する仕様なので、つ通信が10,000くると、負荷が大きくなってしまう弱点がありました。これに対して、Nginxは複数の通信に対して1対応なのでアクセス数の増加に比例して急激な負荷の増加を抑えられるそうです。
Nginx設定ファイル
$ sudo amazon-linux-extras install nginx1
ちなみにamazon-linux-extras
とは、AmazonLinux2に存在するExtras Libraryというパッケージ群を操作するコマンドです。
もしAmazonLinux1を使っている場合には、amazon-linux-extrasコマンドはないのでyumというコマンドを使いましょう。
$ nginx -v
->nginx version: nginx/1.20.0
インストールされていれば、バージョンが表示されます。
次に自分のアプリ専用にNginx設定ファイルを作りましょう。
インストールすると、/etc
配下にnginx/nginx.conf
やnginx/conf.d
というディレクトリが生成されているはずです。
Nginxにはnginx.conf
には、Nginx自体の設定(起動, アクセス負荷チューニング等)を書きます。このファイルにもバーチャルホストを書くことはできますが、わかりやすくするためバーチャルホスト*の設定はnginx/conf.d
配下にアプリ名.conf
を作りそこに書きましょう。
*バーチャルホストとは
デフォルトのバーチャルホストとは、複数のサイトが運用されているウェブサーバーに、IPアドレス(ドメイン名ではなく)でHTTPリクエストした場合に応答するホストのことです。
引用:nginxでデフォルトのバーチャルホストを設定する方法
アプリ名.conf
の書き方は以下のとおりです。
$ sudo vi /etc/nginx/conf.d/アプリ名.conf
viコマンドでファイルの編集+新規作成ができます。
viについてはコマンドモードと入力モードを抑えておけばとりあえず大丈夫だと思います。コマンドモード中にiを押すと入力モードへ、入力モード中にescを押すとコマンドモードになります。
- iを押して入力モードへ
- 内容を編集
- escでコマンドモードへ
- :wqで保存して終了
コマンド | 説明 |
---|---|
i | insert(入力)モード |
esc | コマンドモード |
:wq | 保存して終了 |
:q! | 保存せずに終了 |
*もちろんまだまだ重要なコマンドはあるので気になる方は調べてみましょう!
upstream puma {
server unix:/var/www/アプリ名/shared/sockets/puma.sock fail_timeout=0;
}
server {
listen 80;
server_name [ドメイン(ない場合はElastic IP];
root /var/www/アプリ名/public;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
client_max_body_size 2G;
keepalive_timeout 5;
# page cache loading
try_files $uri/index.html $uri.html $uri @app;
location / {
# HTTP headers
proxy_set_header X-Real-IP $remote_addr;
index index.html index.htm;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://puma;
}
}
設定ファイルの雛形はインストール後に自動生成されるnginx/nginx.conf
を見ると良いと思います。
設定ファイルの説明は以下のとおりです。
ディレクティブ | 説明 |
---|---|
upstream {} | |
server unix:/var/www/アプリ名/shared/sockets/puma.sock fail_timeout=0; | UNIXドメインのpumaソケットファイルを指定 |
server {} | バーチャルホストを定義 |
listen 80; | バーチャルホストが使用するポートを指定 |
server_name [ドメイン(ない場合はElastic IP]; | バーチャルサーバー内で使うホスト名としてドメイン名を指定 |
root /var/www/アプリ名/public; | 公開するディレクトリを指定 |
error_log /var/log/nginx/error.log; | エラーログの出力先を設定 (/var/log配下だとわかりやすい) |
access_log /var/log/nginx/access.log; | アクセスログの出力先を設定 (/var/log配下だとわかりやすい) |
client_max_body_size 2G; | Nginxが受信可能なリクエストボディの量を指定 |
keepalive_timeout 5; | HTTP通信をタイムアウトを待つ秒数を指定 |
try_files $uri/index.html $uri.html $uri @app; | 指定したファイルパスがある場合はリダイレクト、ない場合はその次のファイルパスへと繰り返し、最後までない場合は最後に指定されたURIへとリダイレクト |
location URI {} | リクエストされたURIにマッチししたときに使われる設定。設定は{}内に書く。 |
proxy_set_header XXXX | リクエストをプロキシする際にヘッダを付与する |
X-Real-IP $remote_addr; |
X-Real-IP で送信元を判別、$remote_addr で送信元IPを取得 |
index | インデックスページとして表示するファイルを指定 |
X-Forwarded-Proto $scheme; | ユーザーリクエストが使ったHTTPスキームを指定 |
X-Forwarded-For $proxy_add_x_forwarded_for; | リクエストが経由したアドレス全てを指定 |
Host $http_host; | ユーザーリクエストに含まれるホスト名を指定 |
proxy_redirect | レスポンスヘッダをどのように書き換えるかを指定(今回はoff) |
proxy_pass 転送先URI | リクエストを転送先URIにプロキシ**する。今回はupstreamでpuma として定義したpuma.sockに転送。 |
エラーが起きたとき
cat /var/log/nginx/error.log
を見てデバッグしましょう。(権限なければ sudoを頭につけてください。)
アクセスログ確認方法
cat /var/log/nginx/access.log
用語解説
$
: 変数を展開している。Nginxではもともと定義されている予約語的な変数がある。今回はほとんど予約語を使っている。
フォワードプロキシ
: 一般に「プロキシ」と呼ばれる。クライアントとサーバーの間に設置し、 内部ネットワークからインターネットへの通信を中継する。主にセキュリティ目的
リバースプロキシ
: WEBサーバーの前に設置し、WEBサイトへのリクエストを代理受付する。主にセキュリティ目的
Unixドメインソケット
:
ソケットは「受け口、接合部」の意味。「UNIXドメインソケット」とは、LinuxなどのUNIX系OS(オペレーティングシステム)で実行されるプロセス間のデータ通信の終点に使われるインターフェースのことをいう。
LinuxなどのUNIX系OSは、各種デバイスの入出力にデバイスファイルというインターフェースを利用するため、一般のファイルを読み書きするのと同じ手順で周辺機器を操作できる。ところが、プロセス同士がネットワーク経由で通信するときには、ファイル・インターフェースを拡張した「ソケット」というインターフェースが必要になる。通常インターネットで利用しているソケット通信(INETドメインソケット通信)とは異なり、ネットワーク経由ではないローカルマシン上のプロセスが利用するソケットが、UNIXドメインソケットである。
引用:UNIXドメインソケット
まとめ
- プロキシとはクライアントとサーバー間に設置することで内部から外部への通信を中継してくれる。
- リバースプロキシはWEBサーバーの前に設置することでWEBサイトへのリクエストを代理受付してくれる。例えば会社であれば誰がどのサイトにアクセスしたか等を見ることができセキュリティ強化に繋がる。
- Nginxとpumaをリバースプロキシさせることで、アクセス負荷対策やrails serverでは取得できないアクセスログを取得できる
未経験の立場からすると、サーバーサイドエンジニア志望となるとサーバーサイド言語の勉強に偏りがちですが、Nginxやpuma等のサーバーそのものの勉強は必須だと感じました。
言語と並行してWEB周りの知識も付けていきたいと思います。
参考
puma
Nginx