Skip to content

Instantly share code, notes, and snippets.

@rummelonp
Last active April 16, 2023 03:57
Show Gist options
  • Save rummelonp/4106900 to your computer and use it in GitHub Desktop.
Save rummelonp/4106900 to your computer and use it in GitHub Desktop.
Ubuntu+Nginx+Unicorn+Rails+Capistrano

Ubuntu+Nginx+Unicorn+Rails+Capistrano

諸事情で自宅鯖ちゃんが死んだのでノリでさくら VPS 借りた — Gist

ひとまずは一番アクセスの多い Undersky を復活させつつ
Apache+Passenger から乗り換えるべく Nginx+Unicorn 環境を試行錯誤してみた

以下は Undersky における設定もとい作業ログ
設定はググって出てきたものを寄せ集めてコピペしてきただけである

Ubuntu バージョン

Ubuntu 12.04 amd64

Nginx インストール

Nginx は apt パッケージのものを使用した
バージョンは 1.2.4

sudo add-apt-repository ppa:nginx/stable
sudo apt-get update
sudo apt-get install nginx
sudo ufw allow http

Nginx の設定は特筆することはない
ワーカー数を CPU コア数に合わせ、サーバートークンを出さないようにした

-worker_processes 4;
+worker_processes 3;
-    # server_tokens off;
+    server_tokens off;

静的ファイルは Rails をかいさず Nginx から直接返すようにしてある
Unicorn との接続は Unix Socket を使うことにした

upstream unicorn.undersky.co {
    server unix:/tmp/unicorn.undersky.co.sock;
}

server {
    listen 80;
    server_name undersky.co;
    root /var/www/undersky.co/current/public;

    access_log /var/log/nginx/undersky.co.access.log;
    error_log /var/log/nginx/undersky.co.error.log;
                                                      
    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;
        proxy_pass http://unicorn.undersky.co;
    }

    location = /favicon.ico {
    }

    location = /robots.txt {
    }

    location ~ ^/(assets|images|javascripts|stylesheets|system)/ {
        gzip_static on;
        expires     max;
        add_header  Cache-Control public;
    }
}

Unicorn インストール

他の Ruby アプリケーションでも使用する予定なのでグローバルに入れた
そのためアプリケーションの Gemfile には gem の指定をしていない バージョンは 4.4.0

sudo gem install unicorn

下記は Undersky における config/unicorn.rb の設定

ワーカー数は Nginx と同様に CPU コア数に合わせてある

Unicorn の設定に色々と書いてある記事は見るが
どういう意図で書かれてるのかよく分からなかったので
取り敢えず最低限必要なものだけ書いた

*.pid, *.sock は $RAILS_ROOT/tmp 以下に置いても良かったが
パス指定が長くなってなんとなく美しくなかったので /tmp に置いた

worker_processes 3

listen '/tmp/unicorn.undersky.co.sock'

pid '/tmp/unicorn.undersky.co.pid'

stderr_path 'log/unicorn.log'
stdout_path 'log/unicorn.log'

(サーバ側に)Unicorn 操作用のデーモンは書いてない
再起動した時は手動で立ち上げないといけない

Capistrano の設定

下記を development group に入れて bundle install

gem 'capistrano'

config/deploy.rb の設定

ローカルのリポジトリ の production ブランチから sftp でコピーしてる
db は使ってないので role を書いてない
Unicorn 用のデーモン操作タスクはコピペしてきた

# deploy 時に自動で bundle install
require 'bundler/capistrano'

# deploy 時に自動で rake assets:precompile
load 'deploy/assets'

# アプリケーションの設定
set :application, 'undersky'
set :domain, 'undersky.co'
set :rails_env, 'production'

set :repository, 'file://.'
set :branch, 'production'

set :deploy_via, :copy
set :deploy_to, '/var/www/undersky.co'
set :use_sudo, false

server domain, :app, :web

# 再起動後に古い releases を cleanup
after 'deploy:restart', 'deploy:cleanup'

# Unicorn 用の設定
set :unicorn_config, "#{current_path}/config/unicorn.rb"
set :unicorn_bin, 'unicorn'
set :unicorn_pid, '/tmp/unicorn.undersky.co.pid'

# Unicorn 用のデーモン操作タスク
def remote_file_exists?(full_path)
  capture("if [ -e #{full_path} ]; then echo 'true'; fi").strip == 'true'
end

def process_exists?(pid_file)
  capture("ps -p `cat #{pid_file}`; true").strip.split("\n").size == 2
end

namespace :deploy do
  desc 'Start Unicorn'
  task :start, roles: :app, except: {no_release: true} do
    if remote_file_exists? unicorn_pid
      if process_exists? unicorn_pid
        logger.important 'Unicorn is already running!', 'Unicorn'
        next
      else
        run "rm #{unicorn_pid}"
      end
    end

    logger.important 'Starting Unicorn...', 'Unicorn'
    run "cd #{current_path} && bundle exec unicorn -c #{unicorn_config} -E #{rails_env} -D"
  end

  desc 'Stop Unicorn'
  task :stop, :roles => :app, :except => {:no_release => true} do
    if remote_file_exists? unicorn_pid
      if process_exists? unicorn_pid
        logger.important 'Stopping Unicorn...', 'Unicorn'
        run "kill -s QUIT `cat #{unicorn_pid}`"
      else
        run "rm #{unicorn_pid}"
        logger.important 'Unicorn is not running.', 'Unicorn'
      end
    else
      logger.important 'No PIDs found. Check if unicorn is running.', 'Unicorn'
    end
  end

  desc 'Reload Unicorn'
  task :reload, :roles => :app, :except => {:no_release => true} do
    if remote_file_exists? unicorn_pid
      logger.important 'Reloading Unicorn...', 'Unicorn'
      run "kill -s HUP `cat #{unicorn_pid}`"
    else
      logger.important 'No PIDs found. Starting Unicorn...', 'Unicorn'
      run "cd #{current_path} && bundle exec unicorn -c #{unicorn_config} -E #{rails_env} -D"
    end
  end

  desc 'Restart Unicorn'
  task :restart, :roles => :app, :except => {:no_release => true} do
    stop
    start
  end
end

後はデプロイするだけ

cap deploy:setup # 初回時のみ
cap deploy

その他

  • Unicorn の設定もっと詰めたいけど取り敢えず様子見てみる
  • デーモン操作タスクが適当なのでマシにしたい 色々調べてひとまず操作タスクで良いかなって思ってる

次にすること

  • Unicorn のドキュメント読んで設定とか詰める
  • 他のアプリケーションとかも復活させる

参考リンク

今回の作業の参考にした記事とか

花見の季節にさくらVPS: Nginx+Unicorn+Rails+Capistrano #nginx #Rails #Ubuntu #unicorn #capistrano - Qiita
Capistrano + Rails + Bundler + RVM + Unicorn + EC2 - Vasily's Blog
Rails3アプリをnginx+unicornで動かしたら速すぎた - どっかのBlogの前身のような

Nginx

インフラエンジニアway - powerd by HEARTBEATS: nginxアーカイブ
ConfigurationJa
nginx設定メモ - おおにしあきらの日記
入門! nginx - 馬鹿と天才は紙一重

Unicorn

Unicorn!
次世代RailsサーバーUnicornを使ってみた | TechRacho unicornにどんなシグナル送るとどうなるのかまとめました - life.should be_happy # => 1 examples, ? failures unicornのpreload_app - motsatのブログ

Capistrano

Bundler: The best way to manage Ruby applications Capistrano力を上げよう « blog.udzura.jp

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment