myappを/var/www/myappに配置し、serviceとして起動させる場合
1.myapp直下でprepare_deploy.shを実行
prepare_deploy.sh
bundle install
bundle exec rake db:migrate RAILS_ENV=production
RAILS_ENV=production bundle exec rake assets:precompile
sudo mkdir -p tmp
sudo mkdir -p tmp/pids
sudo mkdir -p tmp/sockets
sudo chgrp -R nginx /var/www
sudo chmod -R 777 /var/www
bundle exec whenever --clear-crontab /var/www/myapp
bundle exec whenever --update-crontab /var/www/myapp
rvm alias create myapp ruby-2.0.0-p247
rvm wrapper myapp --no-links unicorn
sudo cp config/myapp_initd /etc/init.d/myapp
sudo chmod +w /etc/init.d/myapp
sudo mkdir -p /etc/unicorn/
sudo cp config/myapp_unicorn.conf /etc/unicorn/myapp.conf
sudo cp config/myapp_nginx.conf /etc/nginx/conf.d/myapp.conf
sudo /sbin/chkconfig --add myapp
sudo /sbin/chkconfig myapp on
sudo cp config/myapp_logrotate /etc/logrotate.d/
#sudo /usr/sbin/logrotate /etc/logrotate.d/myapp_logrotate
config/myapp_initd
#!/bin/bash
### BEGIN INIT INFO
# chkconfig: - 85 15
# description: myapp on unicorn start/stop script.
### END INIT INFO
# This is /etc/init.d/unicorn init.d script for single or multiple unicorn installations.
# Expects at least one .conf file in /etc/unicorn/
#
## A sample /etc/unicorn/my_app.conf
##
## RAILS_ENV=production
## RAILS_ROOT=/var/apps/www/my_app/current
## UNICORN="/usr/local/rvm/wrappers/my_app/unicorn_rails"
#
# This configures a unicorn master for your app at /var/apps/www/my_app/current running in
# production mode. It will read config/unicorn.rb for further set up.
#
## To get the UNICORN script run:
##
## rvm alias create my_app 2.0.0
## rvm wrapper 2.0.0 --no-links unicorn_rails
#
# This way it will allow changing the alias when new ruby is used without changing anything else.
#
# You should ensure different ports or sockets are set in each config/unicorn.rb if
# you are running more than one master concurrently.
#
# If you call this script without any config parameters, it will attempt to run the
# init command for all your unicorn configurations listed in /etc/unicorn/*.conf
#
# /etc/init.d/unicorn start # starts all unicorns
#
# If you specify a particular config, it will only operate on that one
#
# /etc/init.d/unicorn start my_app
__sig()
{
typeset __pid
[[ -s "$2" ]] &&
__pid="$(cat "$2")" &&
[[ -n "${__pid}" ]] &&
kill -$1 "${__pid}" >/dev/null 2>&1 ||
return $?
}
sig()
{
__sig "$1" "$PID" || return $?
}
oldsig()
{
__sig "$1" "$OLD_PID" || return $?
}
run()
{
echo -n "$1 - "
shift
if
"$@"
then
echo "OK"
else
typeset result=$?
echo "Failed!" >&2
return $result
fi
}
prefix_command_with_su_fix_quoting()
{
typeset -a __temp
__temp=()
while
(( $# ))
do
__temp+=( "'$1'" )
shift
done
CMD=( su - "${__owner}" -c "cd '$RAILS_ROOT' && ${__temp[*]}" )
}
setup ()
{
echo "$RAILS_ROOT: "
cd $RAILS_ROOT || return $?
export PID=$RAILS_ROOT/tmp/pids/unicorn.pid
export OLD_PID="$PID.oldbin"
export RAILS_ENV=production
CMD=( bundle exec "$UNICORN" -c "${RAILS_ROOT}/config/unicorn.rb" -E "${RAILS_ENV}" -D )
typeset __owner="$(stat -c "%U" "${RAILS_ROOT}")"
if
[[ "${USER:=$(whoami)}" == "${__owner}" ]]
then
true # it's all fine we run as owner of the app
elif
(( UID == 0 ))
then
prefix_command_with_su_fix_quoting "${CMD[@]}"
else
echo "ERROR: running not as owner(${__owner}) of '$RAILS_ROOT' and not as root($USER), prefix with 'sudo' and try again!"
return 2
fi
}
cmd_start()
{
if sig 0
then echo "Already started"
else run "Starting" "${CMD[@]}" || return $?
fi
}
wait_pid_kill()
{
typeset __count=$1
while
(( __count > 0 )) &&
sig 0
do
: $(( __count-- ))
sleep 1s
done
sig 0 || return $?
}
cmd_stop()
{
run "Stopping" sig QUIT
if
wait_pid_kill 5
then
run "Force stop" sig TERM
if wait_pid_kill 3
then return 1
fi
fi
}
cmd_restart()
{
cmd_stop && cmd_start || return $?
}
cmd_reload()
{
run "Reloading" sig USR2 &&
wait_pid_kill 5 &&
oldsig QUIT ||
oldsig TERM ||
cmd_restart ||
return $?
}
cmd_rotate()
{
run "Rotate" sig USR1 ||
cmd_start ||
return $?
}
cmd()
{
setup || return $?
case "$1" in
start|stop|restart|reload|rotate)
cmd_$1 || return $?
;;
upgrade)
cmd_reload || return $?
;;
*)
echo "Usage: $0 <start|stop|restart|reload|upgrade|rotate>" >&2
return 1
;;
esac
}
# either run the start/stop/reload/etc command for every config under /etc/unicorn
# or just do it for a specific one
# $1 contains the start/stop/etc command
# $2 if it exists, should be the specific config we want to act on
start_stop ()
{
if
[[ -n "$2" ]]
then
. "/etc/unicorn/$2.conf" || return $?
cmd "$1" || return $?
else
for CONFIG in /etc/unicorn/*.conf
do
. "$CONFIG" || return $?
cmd "$1" || return $?
done
fi
}
start_stop "$@"
config/myapp_unicorn.conf
RAILS_ENV=production
RAILS_ROOT=/var/www/myapp
UNICORN="~/.rvm/wrappers/myapp/unicorn"
config/myapp_nginx.conf
upstream myapp {
server unix:/var/www/myapp/tmp/sockets/unicorn.sock;
}
server {
listen 443;
server_name myapp_server;
ssl on;
ssl_certificate /etc/nginx/ssl_certfile/server_pem.crt;
ssl_certificate_key /etc/nginx/ssl_certfile/server_pem.key;
ssl_protocols SSLv3 TLSv1;
ssl_ciphers HIGH:!ADH:!MD5;
location / {
try_files $uri $uri/index.html $uri.html @myapp;
client_max_body_size 10M;
}
location @myapp {
proxy_read_timeout 300;
proxy_connect_timeout 300;
proxy_redirect off;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://myapp;
proxy_send_timeout 60;
}
}
config/unicorn.rb
# Sample verbose configuration file for Unicorn (not Rack)
#
# This configuration file documents many features of Unicorn
# that may not be needed for some applications. See
# http://unicorn.bogomips.org/examples/unicorn.conf.minimal.rb
# for a much simpler configuration file.
#
# See http://unicorn.bogomips.org/Unicorn/Configurator.html for complete
# documentation.
# Use at least one worker per core if you're on a dedicated server,
# more will usually help for _short_ waits on databases/caches.
worker_processes 4
# Since Unicorn is never exposed to outside clients, it does not need to
# run on the standard HTTP port (80), there is no reason to start Unicorn
# as root unless it's from system init scripts.
# If running the master process as root and the workers as an unprivileged
# user, do this to switch euid/egid in the workers (also chowns logs):
# user "unprivileged_user", "unprivileged_group"
# Help ensure your application will always spawn in the symlinked
# "current" directory that Capistrano sets up.
working_directory File.expand_path('', ENV['RAILS_ROOT']) # available in 0.94.0+
# listen on both a Unix domain socket and a TCP port,
# we use a shorter backlog for quicker failover when busy
listen File.expand_path('tmp/sockets/unicorn.sock', ENV['RAILS_ROOT'])
#listen 3000, :tcp_nopush => true
# nuke workers after 30 seconds instead of 60 seconds (the default)
timeout 30
# feel free to point this anywhere accessible on the filesystem
pid File.expand_path('tmp/pids/unicorn.pid', ENV['RAILS_ROOT'])
# By default, the Unicorn logger will write to stderr.
# Additionally, ome applications/frameworks log to stderr or stdout,
# so prevent them from going to /dev/null when daemonized here:
stderr_path File.expand_path('log/unicorn.stderr.log', ENV['RAILS_ROOT'])
stdout_path File.expand_path('log/unicorn.stdout.log', ENV['RAILS_ROOT'])
# combine Ruby 2.0.0dev or REE with "preload_app true" for memory savings
# http://rubyenterpriseedition.com/faq.html#adapt_apps_for_cow
preload_app true
GC.respond_to?(:copy_on_write_friendly=) and
GC.copy_on_write_friendly = true
# Enable this flag to have unicorn test client connections by writing the
# beginning of the HTTP headers before calling the application. This
# prevents calling the application for connections that have disconnected
# while queued. This is only guaranteed to detect clients on the same
# host unicorn runs on, and unlikely to detect disconnects even on a
# fast LAN.
check_client_connection false
before_fork do |server, worker|
# the following is highly recomended for Rails + "preload_app true"
# as there's no need for the master process to hold a connection
defined?(ActiveRecord::Base) and
ActiveRecord::Base.connection.disconnect!
# The following is only recommended for memory/DB-constrained
# installations. It is not needed if your system can house
# twice as many worker_processes as you have configured.
#
# # This allows a new master process to incrementally
# # phase out the old master process with SIGTTOU to avoid a
# # thundering herd (especially in the "preload_app false" case)
# # when doing a transparent upgrade. The last worker spawned
# # will then kill off the old master process with a SIGQUIT.
# old_pid = "#{server.config[:pid]}.oldbin"
# if old_pid != server.pid
# begin
# sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU
# Process.kill(sig, File.read(old_pid).to_i)
# rescue Errno::ENOENT, Errno::ESRCH
# end
# end
#
# Throttle the master from forking too quickly by sleeping. Due
# to the implementation of standard Unix signal handlers, this
# helps (but does not completely) prevent identical, repeated signals
# from being lost when the receiving process is busy.
# sleep 1
end
after_fork do |server, worker|
# per-process listener ports for debugging/admin/migrations
# addr = "127.0.0.1:#{9293 + worker.nr}"
# server.listen(addr, :tries => -1, :delay => 5, :tcp_nopush => true)
# the following is *required* for Rails + "preload_app true",
defined?(ActiveRecord::Base) and
ActiveRecord::Base.establish_connection
# if preload_app is true, then you may also want to check and
# restart any other shared sockets/descriptors such as Memcached,
# and Redis. TokyoCabinet file handles are safe to reuse
# between any number of forked children (assuming your kernel
# correctly implements pread()/pwrite() system calls)
end
config/myapp_logrotate
/var/www/myapp/log/*.log {
daily
missingok
rotate 5
dateext
compress
delaycompress
notifempty
lastaction
pid=/var/www/myapp/tmp/pids/unicorn.pid
test -s $pid && kill -USR1 "$(cat $pid)"
endscript
}
2./var/www/直下に入れ替えスクリプトchgapp.shを配置
chgapp.sh
sudo /sbin/service myapp stop
sudo /sbin/service nginx stop
mv /var/www/myapp /var/www/myapp_`date +"%Y%m%d%H%M%S"`
mv /var/www/myapp_master /var/www/myapp
sudo /sbin/service myapp start
sudo /sbin/service nginx start
3.時間指定でchgapp.sh起動
2/27 23:00に入れ替える場合
$ crontab -e
00 23 27 02 * /var/www/chgapp.sh
1つのサーバーに対しlocal addressとglobal addressを割り振り、 どちらもHTTPSでアクセスしたい場合の設定です。
例:
local address:xxx.xxx.xxx.xxx
global address:yyy.yyy.yyy.yyy
1.まずxxx.xxx.xxx.xxx用とyyy.yyy.yyy.yyy用の証明書を配置します。
yyy.yyy.yyy.yyy用
/etc/nginx/ssl_certfile/key_yyy_yyy_yyy_yyy/server_pem.crt
/etc/nginx/ssl_certfile/key_yyy_yyy_yyy_yyy/server_pem.key
xxx.xxx.xxx.xxx用
/etc/nginx/ssl_certfile/key_xxx_xxx_xxx_xxx/server_pem.crt
/etc/nginx/ssl_certfile/key_xxx_xxx_xxx_xxx/server_pem.key
2.次のように両アドレス用の設定を作成します。 (冗長な書き方になっていますが)
sample_app.conf
upstream sample_app {
server unix:/var/www/sample_app/tmp/sockets/unicorn.sock;
}
server {
listen yyy.yyy.yyy.yyy:443;
server_name sample_app;
ssl on;
ssl_certificate /etc/nginx/ssl_certfile/key_yyy_yyy_yyy_yyy/server_pem.crt;
ssl_certificate_key /etc/nginx/ssl_certfile/key_yyy_yyy_yyy_yyy/server_pem.key;
ssl_protocols SSLv3 TLSv1;
ssl_ciphers HIGH:!ADH:!MD5;
location / {
try_files $uri $uri/index.html $uri.html @sample_app;
client_max_body_size 2M;
}
location @sample_app {
proxy_read_timeout 300;
proxy_connect_timeout 300;
proxy_redirect off;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://sample_app;
proxy_send_timeout 30;
}
}
server {
listen xxx.xxx.xxx.xxx:443;
server_name sample_app;
ssl on;
ssl_certificate /etc/nginx/ssl_certfile/key_xxx_xxx_xxx_xxx/server_pem.crt;
ssl_certificate_key /etc/nginx/ssl_certfile/key_xxx_xxx_xxx_xxx/server_pem.key;
ssl_protocols SSLv3 TLSv1;
ssl_ciphers HIGH:!ADH:!MD5;
location / {
try_files $uri $uri/index.html $uri.html @sample_app;
client_max_body_size 2M;
}
location @sample_app {
proxy_read_timeout 300;
proxy_connect_timeout 300;
proxy_redirect off;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://sample_app;
proxy_send_timeout 30;
}
3.Nginxがglobal addressをbindできるようにします
/etc/sysctl.conf に次の設定を追加します。
net.ipv4.ip_nonlocal_bind = 1
システムに設定を反映します。
$ sysctl -p /etc/sysctl.conf
※設定がない場合、Nginxを起動する時に次のようなエラーが出ます。
$ sudo /sbin/service nginx start
Starting nginx: [emerg]: bind() to yyy.yyy.yyy.yyy failed (99: Cannot assign requested address)
[rails_app_root]/config/unicorn.rbを作成。
配置用ディレクトリ作成と配置
$ sudo mkdir /var/www
$ sudo cp -r [rails_app_path] /var/www/
$ cd /var/www/[rails_app_path]
$ sudo mkdir tmp
$ sudo mkdir tmp/pids
$ sudo mkdir tmp/sockets
$ sudo chgrp -R nginx /var/www
$ sudo chmod -R 777 /var/www
unicorn起動。(デーモンとして起動)
$ bundle exec unicorn -c config/unicorn.rb -E production -D
nginx起動。
$ sudo /sbin/service nginx start
nginx停止。
$ sudo /sbin/service nginx stop
unicorn停止。(デーモンで起動したのでkillコマンドで停止)
$ kill -QUIT `cat tmp/pids/unicorn.pid`
参考
http://support.citrix.com/article/CTX108031
http://d.hatena.ne.jp/donbulinux/20130729/1375096134
秘密鍵(server.key)の作成
$ openssl genrsa -aes128 1024 > server.key
Nginx起動時にパスフレーズ入力を省略させる設定
$ mv server.key server.key.back
$ openssl rsa -in server.key.back > server.key
公開鍵(server.csr)の作成
$ openssl req -new -key server.key > server.csr
デジタル証明書(server.crt)の作成
$ openssl x509 -in server.csr -days 365 -req -signkey server.key > server.crt
証明書をPEM形式に変換
openssl x509 -in server.crt -out server_pem.crt -outform PEM
キーをPEM形式に変換
openssl rsa -in server.key -out server_pem.key -outform PEM
キーと証明書をpkcs12形式にエクスポート
openssl pkcs12 -export -in server_pem.crt -inkey server_pem.key -out bundle.p12
必要に応じてbundle.p12をブラウザやシステムにインポート
配置
$ sudo mkdir /etc/nginx/ssl_certfile
$ sudo mv server.* /etc/nginx/ssl_certfile/
Nginxのconfファイル修正
upstream sample_app {
server unix:/var/www/sample_app/tmp/sockets/unicorn.sock;
}
server {
listen 443;
listen *:3000;
server_name localhost;
ssl on;
ssl_certificate /etc/nginx/ssl_certfile/server_pem.crt;
ssl_certificate_key /etc/nginx/ssl_certfile/server_pem.key;
ssl_protocols SSLv3 TLSv1;
ssl_ciphers HIGH:!ADH:!MD5;
location / {
try_files $uri $uri/index.html $uri.html @sample_app;
}
location @sample_app {
proxy_read_timeout 300;
proxy_connect_timeout 300;
proxy_redirect off;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://sample_app;
}
}
Rails appのconfig/application.rb等に追記
config.force_ssl = true