ubuntu14.04でRailsをnginx + unicorn環境で動作させるための作業手順
はじめに
RailsをnginxとunicornによるWebサーバ環境で動作させるまでに思ったより苦労したのでその手順をメモしておきます。なお、以下の手順や使用する設定ファイルのほとんどは、以下のサイトを参考にしています。メールでお願いして使わせて頂いてます。大変参考になりました。
Setting Up Your Production Server With Nginx and Unicorn | Tealeaf Academy Blogまた、そもそも
unicorn
とはなにかについては、以下のサイトが参考になると思います。(英語です)
Unicorn! | GitHub今回構築する環境は、nginxをリバースプロキシとして使用し、unicornをアプリケーションサーバとして使う構成になります。
環境と前提
- ubuntu 14.04
- nginx 1.4.6
- unicorn 4.8.3
- rbenv 0.4.0
- Ruby 2.2.0
- Railsのルートディレクトリは
/var/www/railsapp
- Ruby, Railsのインストールは完了している環境 (参考:ubuntu14.04にRuby on Rails環境を構築する手順)
- RailsではデータベースとしてMySQLを使用。RailsでMySQLを使用するための設定も完了済の環境(参考:Ruby on RailsでMySQLを使用する際に必要な作業手順)
作業概要
主な作業としては以下のようになります。
- nginxのインストールと設定
- unicornのインストールと設定
- 動作確認
nginxのインストールと設定
nginxのインストール
apt-get
でupdateしてその後インストールでOKです。
$ sudo apt-get update
$ sudo apt-get install nginx
nginxのインストール時のエラーと解決策
私の環境だと、上記のsudo apt-get install nginx
を実行した時に以下のようなエラーが出ました。
Reading package lists... Done
Building dependency tree
Reading state information... Done
Package nginx is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source
E: Package 'nginx' has no installation candidate
このエラーの解決策としては、まず以下のコマンドでnginxをインストールするためのリポジトリを追加します。
$ sudo add-apt-repository ppa:nginx/stable
続いて以下コマンドでアップデートし、その後でインストールを実行すれば無事に完了しました。
$ sudo apt-get update
$ sudo apt-get install nginx
参考サイト様
VagrantでUbuntu+nginx+MySQL+PHP-FPMの最新環境を構築する | Qiita
nginx.confの修正
nginxのインストールが完了したら、次に/etc/nginx
配下にあるnginx.conf
を以下のように修正します。
user www-data;
worker_processes 4;
pid /run/nginx.pid;
events {
worker_connections 768;
}
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# Logging Settings
##
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on;
gzip_disable "msie6";
gzip_proxied any;
gzip_http_version 1.1;
gzip_min_length 500;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
##
# nginx-naxsi config
##
# Uncomment it if you installed nginx-naxsi
##
#include /etc/nginx/naxsi_core.rules;
##
# nginx-passenger config
##
# Uncomment it if you installed nginx-passenger
##
##
# Unicorn Settings
##
upstream unicorn {
server unix:/var/www/railsapp/tmp/unicorn.sock fail_timeout=0;
}
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
なお、上記のnginx.conf
で以下の部分は各自の環境に合わせて変更する必要があります。
##
# Unicorn Settings
##
upstream unicorn {
server unix:/var/www/railsapp/tmp/unicorn.sock fail_timeout=0;
}
上記の/var/www/railsapp/tmp/unicorn.sock
の/var/www/railsapp
部分を各自のRailsのルートディレクトリパスに置き換える必要があります。また、Railsのルートディレクトリにtmp
ディレクトリがない場合はmkdir tmp
で作成しておく必要があります。
vagrantを使用している場合の注意点
なお、vagrantを使用している場合に、vagrantの仮想マシン(virtualboxを使用)とホストマシンの共有フォルダ上にRailsのルートディレクトリを設置することがあると思います(vagrantのデフォルトだと、仮想マシンからみて/vagrant
がホストマシンとの共有ディレクトリになっていると思います)。この場合に、nginx.conf
にunicorn.sock
の設置場所として以下のように記述することがあるかもしれません。
##
# Unicorn Settings
##
upstream unicorn {
server unix:/vagrant/railsapp/tmp/unicorn.sock fail_timeout=0;
}
上記のように記述すると、unicorn起動時にエラーが発生します。これは、virtualboxの共有ディレクトリがソケットの設置を許可していないためです。よって、vagrantの共有ディレクトリ配下にunicorn.sock
を設置しないように気をつける必要があります。例えば以下のように/tmp
に設置するのもいいかもしれません。
##
# Unicorn Settings
##
upstream unicorn {
server unix:/tmp/unicorn.sock fail_timeout=0;
}
私自身この事実をしらずに悩んだのでメモしておきます。
defaultの編集
続いて/etc/nginx/sites-available
にあるdefault
を以下のように編集します。
server {
listen 80;
root /var/www/railsapp;
index index.html index.htm;
keepalive_timeout 300;
client_max_body_size 4G;
# Make site accessible from http://localhost/
server_name localhost 192.168.0.10;
location /railsapp/ {
try_files $uri/index.html $uri.html $uri @unicorn;
}
location ~ ^/assets/(.*) {
alias /var/www/railsapp/public/assets/$1;
}
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
#try_files $uri $uri/ =404;
# Uncomment to enable naxsi on this location
# include /etc/nginx/naxsi.rules
proxy_set_header Host $http_host;
proxy_pass http://unicorn;
}
location @unicorn {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded_Proto $scheme;
proxy_redirect off;
# This passes requests to unicorn, as defined in /etc/nginx/nginx.conf
proxy_pass http://unicorn;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}
error_page 500 502 503 504 /500.html;
location = /500.html {
root /var/www/railsapp/public;
}
}
上記で各自の環境に合わせて変更する必要がある箇所は、以下の2箇所です。
/var/www/railsapp
の部分を各自のRailsのルートディレクトリのパスに置き換える必要があります。server_name localhost 192.168.0.10
のlocalhost
や192.168.0.10
を各自の環境にあわせて合わせて変更する必要があります。私の場合はローカル内でRailsアプリにアクセスしたかったので、Railsが動作するサーバのIPアドレスである192.168.0.10
を指定しています。
www-data
に変更し、アクセス権限として755
を設定しておきます。
$ sudo chown -R www-data:www-data /var/www/railsapp
$ sudo chmod -R 755 /var/www/railsapp
あとは以下のコマンドでnginxの設定ファイルを再読み込みし、さらに起動できるかを確認しておきます。
$ sudo service nginx reload
$ sudo service nginx start
以上でnginxのインストールと設定は完了です。
unicornのインストールと設定
unicornのインストール
unicornをインストールするために下記をGemfileに追記します。
gem ‘unicorn'
そしてRailsのルートディレクトリ(今回の場合は/var/www/railsapp
)に移動したあとでbundle install
を実行します。
$ bundle install
以上でunicornのインストールは完了です。なお、上記のbundle install
時にmysql2
パッケージ関連でエラーが出る場合があります。An error occurred while installing mysql2 (0.3.11)...
のようなエラーです。このエラーの解決策としては、以下コマンドを実行すればOKです。
$ sudo apt-get install libmysqld-dev
もし上記を実行してさらにエラーが出る場合や、別のエラーが出る場合は、こちらにいくつかのエラーとその解決策を載せているので参考になるかもしれません。
unicornをubuntuのサービスとして登録
unicornをubuntuのサービスとして登録してコマンドとして使用するために/etc/init.d
にunicorn
という名前の起動スクリプトを作成します。
そしてこのファイルの中身として以下を記述します。なお、以下の/etc/init.d/unicorn
の中身は冒頭に載せた参考サイト様のものをそのまま使わせて頂いてます。大変参考になりました
#!/bin/sh
# File: /etc/init.d/unicorn
### BEGIN INIT INFO
# Provides: unicorn
# Required-Start: $local_fs $remote_fs $network $syslog
# Required-Stop: $local_fs $remote_fs $network $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: starts the unicorn web server
# Description: starts unicorn
### END INIT INFO
# Feel free to change any of the following variables for your app:
# ubuntuのユーザ名 (ログインユーザのこと)
USER=user1 # 各自のubuntuのユーザ名を指定。
# Replace [PATH_TO_RAILS_ROOT_FOLDER] with your application's path. I prefer
# /srv/app-name to /var/www. The /srv folder is specified as the server's
# "service data" folder, where services are located. The /var directory,
# however, is dedicated to variable data that changes rapidly, such as logs.
# Reference https://help.ubuntu.com/community/LinuxFilesystemTreeOverview for
# more information.
#APP_ROOT=[PATH_TO_RAILS_ROOT_FOLDER]
APP_ROOT=/var/www/railsapp # 各自のRailsのルートディレクトリを指定
# Set the environment. This can be changed to staging or development for staging
# servers.
RAILS_ENV=production # Railsを動作させる環境を指定
# This should match the pid setting in $APP_ROOT/config/unicorn.rb.
PID=$APP_ROOT/tmp/unicorn.pid
# A simple description for service output.
DESC="Unicorn app - $RAILS_ENV"
# If you're using rbenv, you may need to use the following setup to get things
# working properly:
RBENV_RUBY_VERSION=`cat $APP_ROOT/.ruby-version`
RBENV_ROOT="/home/$USER/.rbenv"
PATH="$RBENV_ROOT/bin:$PATH"
SET_PATH="cd $APP_ROOT && rbenv rehash && rbenv local $RBENV_RUBY_VERSION"
# Unicorn can be run using `bundle exec unicorn` or `bin/unicorn`.
#UNICORN="bin/unicorn"
UNICORN="bundle exec unicorn"
# Execute the unicorn executable as a daemon, with the appropriate configuration
# and in the appropriate environment.
UNICORN_OPTS="-c $APP_ROOT/config/unicorn.rb -E $RAILS_ENV -D"
CMD="$SET_PATH && $UNICORN $UNICORN_OPTS"
# Give your upgrade action a timeout of 60 seconds.
TIMEOUT=60
# Store the action that we should take from the service command's first
# argument (e.g. start, stop, upgrade).
action="$1"
# Make sure the script exits if any variables are unset. This is short for
# set -o nounset.
set -u
# Set the location of the old pid. The old pid is the process that is getting
# replaced.
old_pid="$PID.oldbin"
# Make sure the APP_ROOT is actually a folder that exists. An error message from
# the cd command will be displayed if it fails.
cd $APP_ROOT || exit 1
# A function to send a signal to the current unicorn master process.
sig () {
test -s "$PID" && kill -$1 `cat $PID`
}
# Send a signal to the old process.
oldsig () {
test -s $old_pid && kill -$1 `cat $old_pid`
}
# A switch for handling the possible actions to take on the unicorn process.
case $action in
# Start the process by testing if it's there (sig 0), failing if it is,
# otherwise running the command as specified above.
start)
sig 0 && echo >&2 "$DESC is already running" && exit 0
su - $USER -c "$CMD"
;;
# Graceful shutdown. Send QUIT signal to the process. Requests will be
# completed before the processes are terminated.
stop)
sig QUIT && echo "Stopping $DESC" exit 0
echo >&2 "Not running"
;;
# Quick shutdown - kills all workers immediately.
force-stop)
sig TERM && echo "Force-stopping $DESC" && exit 0
echo >&2 "Not running"
;;
# Graceful shutdown and then start.
restart)
sig QUIT && echo "Restarting $DESC" && sleep 2 \
&& su - $USER -c "$CMD" && exit 0
echo >&2 "Couldn't restart."
;;
# Reloads config file (unicorn.rb) and gracefully restarts all workers. This
# command won't pick up application code changes if you have `preload_app
# true` in your unicorn.rb config file.
reload)
sig HUP && echo "Reloading configuration for $DESC" && exit 0
echo >&2 "Couldn't reload configuration."
;;
# Re-execute the running binary, then gracefully shutdown old process. This
# command allows you to have zero-downtime deployments. The application may
# spin for a minute, but at least the user doesn't get a 500 error page or
# the like. Unicorn interprets the USR2 signal as a request to start a new
# master process and phase out the old worker processes. If the upgrade fails
# for some reason, a new process is started.
upgrade)
if sig USR2 && echo "Upgrading $DESC" && sleep 10 \
&& sig 0 && oldsig QUIT
then
n=$TIMEOUT
while test -s $old_pid && test $n -ge 0
do
printf '.' && sleep 1 && n=$(( $n - 1 ))
done
echo
if test $n -lt 0 && test -s $old_pid
then
echo >&2 "$old_pid still exists after $TIMEOUT seconds"
exit 1
fi
exit 0
fi
echo >&2 "Couldn't upgrade, starting 'su - $USER -c \"$CMD\"' instead"
su - $USER -c "$CMD"
;;
# A basic status checker. Just checks if the master process is responding to
# the `kill` command.
status)
sig 0 && echo >&2 "$DESC is running." && exit 0
echo >&2 "$DESC is not running."
;;
# Reopen all logs owned by the master and all workers.
reopen-logs)
sig USR1
;;
# Any other action gets the usage message.
*)
# Usage
echo >&2 "Usage: $0 "
exit 1
;;
esac
上記の/etc/init.d/unicorn
の記述のうち、各自の環境に合わせて変更する必要がある箇所、確認が必要な箇所は以下の4箇所です。
USER=user1
は各自のubuntuのユーザ名(PCでログインしているユーザ名)を記述します。上記ではubuntuのユーザとしてuser1
を記述していますが、このuser1
を各自の環境にあわせて合わせて変更する必要があります。例えば、vagrantを使用している場合は、デフォルトのユーザ名はvagrant
です。APP_ROOT=/var/www/railsapp
は、各自のRailsのルートディレクトリを指定する必要があります。RAILS_ENV=production
は、各自のRailsを動作させる環境を指定する必要があります。ここでは本番環境であるproduction
を指定しています。RBENV_RUBY_VERSION=`cat $APP_ROOT/.ruby-version`
は、各自のRailsルートディレクトリにある.ruby-version
というファイルを読み込んでいます。この.ruby-version
にはそのファイル名とおり、使用しているRubyのバージョン番号が記述されています。もしRailsルートディレクトリにこのファイルがなければ、自分で作成し、使用しているRubyのバージョン番号を記述しておく必要があります。Rubyのバージョンはruby -v
で確認できます。また、私の場合は2.2.0
を使用しているので単純に.ruby-version
には2.2.0
とだけ記述しておけばOKです。
続いて今作成したunicorn
に実行権限を与えてさらにubuntuの起動と同時にunicorn
を起動させるためにupdate-rc.d
を実行します。
$ sudo chmod +x /etc/init.d/unicorn
$ sudo update-rc.d unicorn defaults
unicornの設定ファイル作成
Railsのunicronの設定ファイルとして/var/www/railsapp/config
にunicorn.rb
を作成します。そして以下を記述します。
app_path = File.expand_path(File.dirname(__FILE__) + '/..')
worker_processes 2
listen app_path + '/tmp/unicorn.sock', backlog: 64
timeout 300
working_directory app_path
pid app_path + '/tmp/unicorn.pid'
stderr_path app_path + '/log/unicorn.log'
stdout_path app_path + '/log/unicorn.log'
preload_app true
GC.respond_to?(:copy_on_write_friendly=) &&
GC.copy_on_write_friendly = true
before_fork do |server, worker|
defined?(ActiveRecord::Base) &&
ActiveRecord::Base.connection.disconnect!
end
after_fork do |server, worker|
defined?(ActiveRecord::Base) &&
ActiveRecord::Base.establish_connection
end
上記のunicorn.rb
では、app_path
がRailsのルートディレクトリのパスを値として持つため、listen app_path + '/tmp/unicorn.sock', backlog: 64
はlisten '/var/www/railsapp/tmp/unicorn.sock', backlog: 64
と同義です。そしてこの部分はnginx.conf
に記述したserver unix:/var/www/railsapp/tmp/unicorn.sock fail_timeout=0;
と合わせる必要があります。よって、もしvagrant(virtualboxを使用)の仮想マシンとホストマシンの共有フォルダ上にRailsのルートディレクトリを設置していて、nginx.conf
にserver unix:/tmp/unicorn.sock fail_timeout=0;
として記述した場合はunicorn.rb
をnginx.conf
に合わせて以下のように変更する必要があります。
listen '/tmp/unicorn.sock', backlog: 64
動作確認
最後に動作確認を行います。以下のコマンドでnginx、unicornをそれぞれ起動します。
$ sudo service nginx start
$ sudo service unicorn start
起動後、ブラウザを開いて192.168.0.10
にアクセスして各自のRailsアプリにアクセスできればOKです。もしアクセスした際に403
エラーが表示される場合は、各自のRailsルートディレクトリの権限などを確認すると解決につながるかもしれません。また、unicorn
が起動しない場合は、Railsルートディレクトリのlog/unicorn.log
を参照すると原因がわかるかもしれません。あとは、rails s -b 0.0.0.0
を実行してまずRails自体が正常に起動するかを確認するといいかもしれません。Railsが正常に起動できない状態だとunicorn
も起動できません。
なお、nginx, unicornは以下のコマンドで停止させることが可能です。
$ sudo service nginx stop
$ sudo service unicorn stop
おわりに
Railsをnginx + unicornで動作させるまでの手順をメモしました。nginx + unicorn環境だとRailsアプリの動作がwebrickなどの場合に比べて体感的に高速になりました。
関連記事
- 公開日:2019/10/04 更新日:2019/10/04
RailsとSendGridでメール送信処理を実装する
Ruby on RailsからAction Mailerを使用してSendGrid経由でメールを送信する処理を実装したのでその手順をまとめます。
- 公開日:2018/05/30 更新日:2018/05/30
ブラウザの操作を自動化できるSeleniumをWSLからRubyで使う
フォーム送信や繰り返し行う必要があるブラウザ操作を自動化できるSeleniumをWindows Subsystem for Linux のUbuntuからRubyを用いて使用するための手順をメモします。
- 公開日:2018/05/27 更新日:2018/05/27
rbenvとruby環境の構築手順
WindowsのWindows Subsystem for LinuxでUbuntuを使いはじめ、その中にrbenvとRuby環境を構築したのでその手順をメモします。なお、UbuntuであればWindows Subsystem for Linux、仮想マシン、純粋なUbuntuのいずれでも同じ手順になります。思っていた以上に簡単に構築できました。
- 公開日:2018/05/06 更新日:2018/05/06
RubyでGoogleスプレッドシートを読み込み・書き込みする
Googleスプレッドシートを自分で作成したRubyコードから読み込んだり、書き込んだりするためのコードについてまとめます。
- 公開日:2016/01/10 更新日:2016/01/10
Railsでwickedpdfを使ってPDF出力する
Ruby on RailsでPDF出力させるのに便利なgemはたくさんありますが、htmlをそのままPDF化してくれる「wickedpdf」が一番お手軽で楽でした。wickedpdfの導入手順と使用方法をメモします。