Ubuntu 20.04上でRuby on Railsをnginxで動かす

はじめに_

Ubuntu 20.04 on WSL2上でRuby on Railsをnginxで動かす。実現したい状況は以下のとおり。

  • http://locahost:30080 にWindows上のWebブラウザからアクセスするとRailsアプリにアクセスできる
  • Webサーバnginxは30080ポートにアクセスがあったら、unicornを通して、Railsアプリを呼び出す
  • nginxとunicornはUnixソケットを通じて連携する

参考_

nginxのインストールと設定_

% sudo apt install -y nginx

デフォルトの設定のままだと以下のようなメッセージがエラーログに表示される。

2021/10/05 15:25:49 [alert] 1532#1532: *2630 768 worker_connections are not enough while connecting to upstream, client: 127.0.0.1, server: , request: "GET / HTTP/1.0", upstream: "http://127.0.0.1:30080/", host: "localhost:30080"

worker_connectionsとworker_rlimit_nofileの値は何がいいのか?に従い、worker_connectionsとworker_rlimit_nofileの値の設定を変える。

Ubuntu 20.04(Debian GNU/Linuxも)は /etc/nginx/nginx.conf で設定されている。まず、設定ファイルのコピーをする。

% cd /etc/nginx
% sudo cp -p nginx.conf nginx.conf.org

お好きなエディタで編集する(編集の際はroot権限が必要)。nginx.confのworker_connectionsとworker_rlimit_nofileの値を編集する。

user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

## 以下を追記する
worker_rlimit_nofile 83000;

events {
        ### 以下の値を変更する
	#worker_connections 768;
	worker_connections 4096;

	# multi_accept on;
}
~以下略~

設定が正しいかどうか確かめる。

% sudo nginx -t 
[sudo] gotoh のパスワード: 
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

nginxを再起動する。

% sudo service nginx restart

unicornのインストールと設定_

RailsアプリとWebサーバをつなぐミドルウェアとしてunicornを用いる。unicornの役割については以下のページが丁寧に説明してくれている。

動作確認用のRailsアプリの準備_

動作確認用のRailsアプリを作成する。(参考:rbenvを用いたRuby on Rails環境の構築 on Ubuntu 20.04

% cd
% mkdir -p ~/Sandboox/RailsTest
% cd ~/Sandboox/RailsTest

(Windows Subsystem for Linux上のUbuntuの場合)
% rails new demo --skip-bundle -skip-spring --skip-listen

% cd demo
% bundle install
% rails webpacker:install

% rails generate scaffold person name:string age:integer
% rails db:migrate

Railsアプリの動作確認をする。

% rails server
=> Booting Puma
=> Rails 6.1.4.1 application starting in development 
=> Run `bin/rails server --help` for more startup options
Puma starting in single mode...
* Puma version: 5.4.0 (ruby 3.0.2-p107) ("Super Flight")
*  Min threads: 5
*  Max threads: 5
*  Environment: development
*          PID: 20564
* Listening on http://127.0.0.1:3000
* Listening on http://[::1]:3000
Use Ctrl-C to stop

Webブラウザで、http://localhost:3000/people にアクセスし、アプリが動いていることを確認する。確認したらアプリを Ctrl-cで停止する。

unicornのインストールと設定_

Gemfileに以下を追記する。

gem 'unicorn'

インストールする。

% bundle install

Webサーバー「Unicorn」の基本情報と実装方法に従い config/unicorn.rb を記述する。また、各種ファイルを設置するディレクトリを作成する。

% touch config/unicorn.rb
% mkdir -p tmp/pids
% mkdir -p tmp/sockets

config/unicorn.rb の中身は以下のようにする。

# Refer to https://www.autovice.jp/articles/146

# Railsアプリのルート
rails_root = File.expand_path('../../', __FILE__)

# Gemfileの場所
ENV['BUNDLE_GEMFILE'] = rails_root + "/Gemfile"

# Unicornの設定
worker_processes  2
timeout           15
working_directory rails_root
pid               File.expand_path 'tmp/pids/unicorn.pid', rails_root
listen            File.expand_path 'tmp/sockets/.unicorn.sock', rails_root
stdout_path       File.expand_path 'log/unicorn.log', rails_root
stderr_path       File.expand_path 'log/unicorn.log', rails_root
preload_app       true

# フォークが行われる前の処理
before_fork do |server, worker|
  defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!
  old_pid = "#{server.config[:pid]}.oldbin"
  if old_pid != server.pid
    begin
      Process.kill "QUIT", File.read(old_pid).to_i
    rescue Errno::ENOENT, Errno::ESRCH
    end
  end
end

# フォークが行われた後の処理
after_fork do |server, worker|
  defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
end

# フォークが行われる前の処理
before_fork do |server, worker|
  defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!
end

# フォークが行われた後の処理
after_fork do |server, worker|
  defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
end

# フォークが行われる前の処理
before_fork do |server, worker|
  old_pid = "#{server.config[:pid]}.oldbin"
  if old_pid != server.pid
    begin
      Process.kill "QUIT", File.read(old_pid).to_i
    rescue Errno::ENOENT, Errno::ESRCH
    end
  end
end

続いて、unicornをNginx環境下で動かす時の設定方法に基づいて、unicornを起動するタスクファイルを設定する。

% rails g task unicorn
}}

lib/tasks/unicorn.rakeを以下のように編集する。なお、上述の config/unicorn.rb のPIDファイルの設置場所に合わせて、一部変更している。
{{{
# Refer to https://y-hilite.com/2857/
# Modified above setting according to current config/unicorn.rb
namespace :unicorn do
     # Tasks
   desc "Start unicorn"
   task(:start) {
     config = Rails.root.join('config', 'unicorn.rb')
     sh "unicorn -c #{config} -E development -D"
   }
 
   desc "Stop unicorn"
   task(:stop) {
     unicorn_signal :QUIT
   }
 
   desc "Restart unicorn with USR2"
   task(:restart) {
     unicorn_signal :USR2
   }
 
   desc "Increment number of worker processes"
   task(:increment) {
     unicorn_signal :TTIN
   }
 
   desc "Decrement number of worker processes"
   task(:decrement) {
     unicorn_signal :TTOU
   }
 
   desc "Unicorn pstree (depends on pstree command)"
   task(:pstree) do
     sh "pstree '#{unicorn_pid}'"
   end
 
   # Helpers
   def unicorn_signal signal
     Process.kill signal, unicorn_pid
   end
 
   def unicorn_pid
     begin
       unicorn_pid = Rails.root.join('tmp', 'pids', 'unicorn.pid')
       File.read(unicorn_pid ).to_i
     rescue Errno::ENOENT
       raise "Unicorn does not seem to be running"
     end
   end
end

起動確認をする。unicornのプロセスが動いていれば設定OK.

% rails unicorn:start
unicorn -c /home/gotoh/Sandbox/RailsTest/demo/config/unicorn.rb -E development -D

% ps -ef | grep unicorn | grep -v grep
gotoh     2403    12  0 16:02 ?        00:00:00 unicorn master -c /home/gotoh/Sandbox/RailsTest/demo/config/unicorn.rb -E development -D
gotoh     2405  2403  0 16:02 ?        00:00:00 unicorn worker[0] -c /home/gotoh/Sandbox/RailsTest/demo/config/unicorn.rb -E development -D
gotoh     2406  2403  0 16:02 ?        00:00:00 unicorn worker[1] -c /home/gotoh/Sandbox/RailsTest/demo/config/unicorn.rb -E development -D
gotoh     2407  2403  0 16:02 ?        00:00:00 unicorn worker[2] -c /home/gotoh/Sandbox/RailsTest/demo/config/unicorn.rb -E development -D
gotoh     2408  2403  0 16:02 ?        00:00:00 unicorn worker[3] -c /home/gotoh/Sandbox/RailsTest/demo/config/unicorn.rb -E development -D
gotoh     2409  2403  0 16:02 ?        00:00:00 unicorn worker[4] -c /home/gotoh/Sandbox/RailsTest/demo/config/unicorn.rb -E development -D
gotoh     2410  2403  0 16:02 ?        00:00:00 unicorn worker[5] -c /home/gotoh/Sandbox/RailsTest/demo/config/unicorn.rb -E development -D

停止する。停止したらプロセスも停止していることを確認する。psの実行結果で何も表示されなければ停止している。

% rails unicorn:stop
% ps -ef | grep unicorn | grep -v grep

ログは logs/unicorn.log にある。

バーチャルホストの設定_

今回は

Ubuntu 20.04のnginxは /etc/nginx/sites-avaiable 以下にバーチャルホストの設定を置いておくことになっている。今回のRailsアプリのディレクトリ名がdemoなのでバーチャルホストの設定ファイルもdemoとする。

% sudo touch /etc/nginx/sites-avaiable/demo

root権限で/etc/nginx/sites-avaiable/demoの中身を以下のように編集する。

upstream rails_app {
         # 注意.unicorn.sockの設置場所のフルパスを記載すること
	 server  unix:/home/gotoh/Sandbox/RailsTest/demo/tmp/sockets/.unicorn.sock fail_timeout=0;
}


server {
        # ポート番号は任意。
	listen 30080;
	server_name _;

        # Railsアプリの下にあるpublicディレクトリをrootとする。 
	root /home/gotoh/Sandbox/RailsTest/demo/public;

        # このバーチャルホスト用のログを指定する。ファイル名は任意
    	access_log  /var/log/nginx/demo_access.log;
    	error_log   /var/log/nginx/demo_error.log;
    
       client_max_body_size 100m;
       error_page  404              /404.html;
       error_page  500 502 503 504  /500.html;
       try_files   $uri/index.html $uri @unicorn;

	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;

               # upstreamの部分に記載しているもの(今回はrails_app)を書く
               proxy_pass http://rails_app;
	}
}

設定ファイルを有効化するためには sites-enabled にシンボリックリンクを作成する。

% sudo ln -s /etc/nginx/sites-available/demo /etc/nginx/sites-enabled/demo

設定ファイルが正しいかどうかを設定する。

% sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

nginxを再起動する。

% sudo service nginx restart
 * Restarting nginx nginx                                                [ OK ] 

Railsアプリの起動手順_

以下の手順でWindows上のWebブラウザからRailsアプリにアクセスできる

  1. nginxを起動する(以下のようになっていたら起動している)
    % ps -ef | grep nginx | grep -v grep
    root      3356    12  0 16:54 ?        00:00:00 nginx: master process /usr/sbin/nginx
    www-data  3357  3356  0 16:54 ?        00:00:00 nginx: worker process
    www-data  3358  3356  0 16:54 ?        00:00:00 nginx: worker process
    www-data  3359  3356  0 16:54 ?        00:00:00 nginx: worker process
    www-data  3360  3356  0 16:54 ?        00:00:00 nginx: worker process
    www-data  3362  3356  0 16:54 ?        00:00:00 nginx: worker process
    www-data  3363  3356  0 16:54 ?        00:00:00 nginx: worker process
    www-data  3364  3356  0 16:54 ?        00:00:00 nginx: worker process
    www-data  3365  3356  0 16:54 ?        00:00:00 nginx: worker process
    
    (起動していなければ以下のコマンドを実行する)
    % sudo service nginx start
    
  2. Unicornを起動する。
    (今回の例の場合は以下のように起動する)
    % cd ~/Sandbox/RailsTest/demo
    % rails unicorn:start
    
    (確認する)
    % ps -ef | grep unicorn | grep -v grep
    gotoh     3416    12  1 16:59 ?        00:00:00 unicorn master -c /home/gotoh/Sandbox/RailsTest/demo2/config/unicorn.rb -E development -D
    gotoh     3418  3416  0 16:59 ?        00:00:00 unicorn worker[0] -c /home/gotoh/Sandbox/RailsTest/demo2/config/unicorn.rb -E development -D
    gotoh     3419  3416  0 16:59 ?        00:00:00 unicorn worker[1] -c /home/gotoh/Sandbox/RailsTest/demo2/config/unicorn.rb -E development -D
    
  3. Windows上のWebブラウザから http://localhost:30080/people にアクセスする。

トラブルシューティング_

ログ置き場_

nginxのログは以下にある。500 Internal Server Errorや400 Bad Requestなどが出た場合はnginxのログをみる

  • /var/log/nginx/demo_access.log, demo_error.log (バーチャルホストのログ)

unicornのログは以下にある。以下のパスは今回の例のもの。

  • ~/Sandbox/RailsTest/demo/log/unicorn.log

Railsアプリのログは以下にある。以下のパスは今回の例のもの。

  • ~/Sandbox/RailsTest/demo/log/development.log

戻る_