Skip to content

Instantly share code, notes, and snippets.

@faustman
Forked from mikhailov/0. nginx_setup.sh
Created February 12, 2013 15:05
Show Gist options
  • Save faustman/4770478 to your computer and use it in GitHub Desktop.
Save faustman/4770478 to your computer and use it in GitHub Desktop.

Revisions

  1. @mikhailov mikhailov revised this gist Feb 5, 2013. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion 2. nginx.conf
    Original file line number Diff line number Diff line change
    @@ -54,7 +54,7 @@ http {
    add_header Strict-Transport-Security "max-age=16070400; includeSubdomains";
    add_header X-Frame-Options DENY;

    limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;
    limit_req_zone $binary_remote_addr zone=one:10m rate=50r/s;

    include /home/app/public_html/app_production/current/config/server/nginx_host.conf;
    }
  2. @mikhailov mikhailov revised this gist Feb 5, 2013. No changes.
  3. @mikhailov mikhailov revised this gist Feb 5, 2013. 1 changed file with 30 additions and 9 deletions.
    39 changes: 30 additions & 9 deletions 5. deploy.rb
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    # Capistrano configuration
    # Capistrano configuration. Now with TRUE zero-downtime unless DB migration.
    #
    # require 'new_relic/recipes' - Newrelic notification about deployment
    # require 'capistrano/ext/multistage' - We use 2 deployment environment: staging and production.
    @@ -32,17 +32,14 @@
    set :normalize_asset_timestamps, false


    # Optional
    before "deploy", "deploy:web:disable"
    before "deploy:stop", "deploy:web:disable"
    before "deploy", "deploy:delayed_job:stop"
    before "deploy:migrations", "deploy:delayed_job:stop"

    after "deploy:update_code", "deploy:symlink_shared"
    before "deploy:migrate", "deploy:web:disable", "deploy:db:backup"

    # Optional
    after "deploy:start", "deploy:web:enable"
    after "deploy", "deploy:web:enable"

    after "deploy", "deploy:cleanup"
    after "deploy", "newrelic:notice_deployment", "deploy:cleanup", "deploy:delayed_job:restart"
    after "deploy:migrations", "deploy:web:enable", "newrelic:notice_deployment", "deploy:cleanup", "deploy:delayed_job:restart"


    namespace :deploy do
    @@ -65,6 +62,30 @@
    run "ln -nfs #{deploy_to}/shared/config/database.yml #{release_path}/config/database.yml"
    end

    namespace :delayed_job do
    desc "Restart the delayed_job process"
    task :restart, :roles => :app, :except => { :no_release => true } do
    run "cd #{current_path}; RAILS_ENV=#{rails_env} bundle exec script/delayed_job restart" rescue nil
    end
    desc "Stop the delayed_job process"
    task :stop, :roles => :app, :except => { :no_release => true } do
    run "cd #{current_path}; RAILS_ENV=#{rails_env} bundle exec script/delayed_job stop" rescue nil
    end
    end


    namespace :db do
    desc "backup of database before migrations are invoked"
    task :backup, :roles => :db, :only => { :primary => true } do
    filename = "#{deploy_to}/shared/db_backup/#{stage}_db.#{Time.now.utc.strftime("%Y-%m-%d_%I:%M")}_before_deploy.gz"
    text = capture "cat #{deploy_to}/current/config/database.yml"
    yaml = YAML::load(text)["#{stage}"]

    on_rollback { run "rm #{filename}" }
    run "mysqldump --single-transaction --quick -u#{yaml['username']} -h#{yaml['host']} -p#{yaml['password']} #{yaml['database']} | gzip -c > #{filename}"
    end
    end


    namespace :web do
    desc "Maintenance start"
  4. @mikhailov mikhailov revised this gist Feb 5, 2013. 1 changed file with 5 additions and 5 deletions.
    10 changes: 5 additions & 5 deletions 0. nginx_setup.sh
    Original file line number Diff line number Diff line change
    @@ -23,8 +23,8 @@


    $ cd /usr/src
    $ wget http://nginx.org/download/nginx-1.3.5.tar.gz
    $ tar xzvf ./nginx-1.3.5.tar.gz && rm -f ./nginx-1.3.5.tar.gz
    $ wget http://nginx.org/download/nginx-1.3.11.tar.gz
    $ tar xzvf ./nginx-1.3.11.tar.gz && rm -f ./nginx-1.3.11.tar.gz

    $ wget http://zlib.net/zlib127.zip
    $ unzip zlib127.zip && rm -f zlib127.zip
    @@ -35,9 +35,9 @@ $ tar xzvf pcre-8.30.tar.gz && rm -f ./pcre-8.30.tar.gz
    $ wget http://www.openssl.org/source/openssl-1.0.1c.tar.gz
    $ tar xzvf openssl-1.0.1c.tar.gz && rm -f openssl-1.0.1c.tar.gz

    $ cd nginx-1.3.5
    $ wget http://nginx.org/patches/spdy/patch.spdy.txt && patch -p0 < patch.spdy.txt
    $ ./configure --prefix=/opt/nginx --with-pcre=/usr/src/pcre-8.30 --with-zlib=/usr/src/zlib-1.2.7 --with-openssl-opt=no-krb5 --with-openssl=/usr/src/openssl-1.0.1c --with-http_ssl_module --without-mail_pop3_module --without-mail_smtp_module --without-mail_imap_module --with-http_stub_status_module --with-http_gzip_static_module
    $ cd nginx-1.3.11
    $ wget http://nginx.org/patches/spdy/patch.spdy.txt && patch -p1 < patch.spdy.txt
    $ ./configure --prefix=/opt/nginx --with-pcre=/usr/src/pcre-8.30 --with-zlib=/usr/src/zlib-1.2.7 --with-openssl-opt=no-krb5 --with-openssl=/usr/src/openssl-1.0.1c --with-http_ssl_module --with-http_spdy_module --without-mail_pop3_module --without-mail_smtp_module --without-mail_imap_module --with-http_stub_status_module --with-http_gzip_static_module

    $ make && make install

  5. @mikhailov mikhailov revised this gist Oct 9, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion 3. nginx_host.conf
    Original file line number Diff line number Diff line change
    @@ -25,7 +25,7 @@ server {

    server {
    ssl on;
    listen 443 ssl;
    listen 443 spdy ssl;
    server_name server.com;
    root /home/app/public_html/app_production/current/public;
    try_files $uri /system/maintenance.html @unicorn;
  6. @mikhailov mikhailov revised this gist Oct 9, 2012. 1 changed file with 6 additions and 4 deletions.
    10 changes: 6 additions & 4 deletions 0. nginx_setup.sh
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    # Nginx+Unicorn best-practices congifuration guide.
    # Nginx+Unicorn best-practices congifuration guide. Now with SPDY!
    # We use latest stable nginx with fresh **openssl**, **zlib** and **pcre** dependencies.
    # Some extra handy modules to use: --with-http_stub_status_module --with-http_gzip_static_module
    #
    @@ -23,8 +23,8 @@


    $ cd /usr/src
    $ wget http://nginx.org/download/nginx-1.2.2.tar.gz
    $ tar xzvf ./nginx-1.2.2.tar.gz && rm -f ./nginx-1.2.2.tar.gz
    $ wget http://nginx.org/download/nginx-1.3.5.tar.gz
    $ tar xzvf ./nginx-1.3.5.tar.gz && rm -f ./nginx-1.3.5.tar.gz

    $ wget http://zlib.net/zlib127.zip
    $ unzip zlib127.zip && rm -f zlib127.zip
    @@ -35,7 +35,9 @@ $ tar xzvf pcre-8.30.tar.gz && rm -f ./pcre-8.30.tar.gz
    $ wget http://www.openssl.org/source/openssl-1.0.1c.tar.gz
    $ tar xzvf openssl-1.0.1c.tar.gz && rm -f openssl-1.0.1c.tar.gz

    $ cd nginx-1.2.2 && ./configure --prefix=/opt/nginx --with-pcre=/usr/src/pcre-8.30 --with-zlib=/usr/src/zlib-1.2.7 --with-openssl-opt=no-krb5 --with-openssl=/usr/src/openssl-1.0.1c --with-http_ssl_module --without-mail_pop3_module --without-mail_smtp_module --without-mail_imap_module --with-http_stub_status_module --with-http_gzip_static_module
    $ cd nginx-1.3.5
    $ wget http://nginx.org/patches/spdy/patch.spdy.txt && patch -p0 < patch.spdy.txt
    $ ./configure --prefix=/opt/nginx --with-pcre=/usr/src/pcre-8.30 --with-zlib=/usr/src/zlib-1.2.7 --with-openssl-opt=no-krb5 --with-openssl=/usr/src/openssl-1.0.1c --with-http_ssl_module --without-mail_pop3_module --without-mail_smtp_module --without-mail_imap_module --with-http_stub_status_module --with-http_gzip_static_module

    $ make && make install

  7. @mikhailov mikhailov revised this gist Aug 14, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion 8. unicorn_init.sh
    Original file line number Diff line number Diff line change
    @@ -55,7 +55,7 @@ restart|reload)
    $CMD
    ;;
    upgrade)
    if sig USR2 && sleep 2 && sig 0 && oldsig QUIT
    if sig USR2 && sleep 15 && sig 0 && oldsig QUIT
    then
    n=$TIMEOUT
    while test -s $old_pid && test $n -ge 0
  8. @mikhailov mikhailov revised this gist Jul 25, 2012. 1 changed file with 20 additions and 1 deletion.
    21 changes: 20 additions & 1 deletion 0. nginx_setup.sh
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,25 @@
    # Nginx optimal congifuration guide.
    # Nginx+Unicorn best-practices congifuration guide.
    # We use latest stable nginx with fresh **openssl**, **zlib** and **pcre** dependencies.
    # Some extra handy modules to use: --with-http_stub_status_module --with-http_gzip_static_module
    #
    # Deployment structure
    #
    # SERVER:
    # /etc/init.d/nginx (1. nginx)
    # /home/app/public_html/app_production/current (Capistrano directory)
    #
    # APP:
    # config/server/production/nginx.conf (2. nginx.conf)
    # config/server/production/nginx_host.conf (3. nginx_host.conf)
    # config/server/production/nginx_errors.conf (4. nginx_errors.conf)
    # config/deploy.rb (5. deploy.rb)
    # config/deploy/production.rb (6. production.rb)
    # config/server/production/unicorn.rb (7. unicorn.rb)
    # config/server/production/unicorn_init.sh (8. unicorn_init.sh)






    $ cd /usr/src
  9. @mikhailov mikhailov revised this gist Jul 18, 2012. 1 changed file with 4 additions and 0 deletions.
    4 changes: 4 additions & 0 deletions 3. nginx_host.conf
    Original file line number Diff line number Diff line change
    @@ -48,6 +48,10 @@ server {
    add_header Cache-Control public;
    add_header Last-Modified "";
    add_header ETag "";

    open_file_cache max=1000 inactive=500s;
    open_file_cache_valid 600s;
    open_file_cache_errors on;
    break;
    }

  10. @mikhailov mikhailov revised this gist Jul 15, 2012. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions 2. nginx.conf
    Original file line number Diff line number Diff line change
    @@ -10,6 +10,7 @@
    user app;
    worker_processes 2;
    worker_priority -5;
    timer_resolution 100ms;

    error_log logs/nginx.error.log crit;

    @@ -28,6 +29,8 @@ http {
    default_type application/octet-stream;
    server_tokens off;
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 70;

    gzip on;
  11. @mikhailov mikhailov revised this gist Jul 9, 2012. 1 changed file with 12 additions and 4 deletions.
    16 changes: 12 additions & 4 deletions 7. unicorn.rb
    Original file line number Diff line number Diff line change
    @@ -7,23 +7,31 @@
    # preload_app true - the most interesting option that confuse a lot of us,
    # just setup is as true always, it means extra work on
    # deployment scripts to make it correctly
    # BUNDLE_GEMFILE - make Gemfile accessible with new master
    # before_fork, after_fork - reconnect to all dependent services: DB, Redis, Sphinx etc.
    # deal with old_pid only if CPU or RAM are limited enough
    #
    # config/server/production/unicorn.rb


    working_directory "/home/app/public_html/app_production/current"
    pid "/home/app/public_html/app_production/current/tmp/pids/unicorn.pid"
    stderr_path "/home/app/public_html/app_production/current/log/unicorn.log"
    stdout_path "/home/app/public_html/app_production/current/log/unicorn.log"
    app_path = "/home/app/public_html/app_production/current"

    working_directory "#{app_path}"
    pid "#{app_path}/tmp/pids/unicorn.pid"
    stderr_path "#{app_path}/log/unicorn.log"
    stdout_path "#{app_path}/log/unicorn.log"

    listen "/tmp/unicorn.production.sock"
    worker_processes 4
    timeout 30
    preload_app true


    before_exec do |server|
    ENV["BUNDLE_GEMFILE"] = "#{app_path}/Gemfile"
    end


    before_fork do |server, worker|
    if defined?(ActiveRecord::Base)
    ActiveRecord::Base.connection.disconnect!
  12. @mikhailov mikhailov revised this gist Jul 9, 2012. 1 changed file with 0 additions and 9 deletions.
    9 changes: 0 additions & 9 deletions 7. unicorn.rb
    Original file line number Diff line number Diff line change
    @@ -29,15 +29,6 @@
    ActiveRecord::Base.connection.disconnect!
    end

    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

    if defined?(Resque)
    Resque.redis.quit
    end
  13. @mikhailov mikhailov revised this gist Jul 9, 2012. 2 changed files with 7 additions and 12 deletions.
    13 changes: 2 additions & 11 deletions 3. nginx_host.conf
    Original file line number Diff line number Diff line change
    @@ -24,13 +24,11 @@ server {


    server {
    set $app_root "/home/app/public_html/app_production/current";

    ssl on;
    listen 443 ssl;
    server_name server.com;
    root $app_root;
    try_files $uri /public/system/maintenance.html @unicorn;
    root /home/app/public_html/app_production/current/public;
    try_files $uri /system/maintenance.html @unicorn;

    location @unicorn {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    @@ -45,7 +43,6 @@ server {
    }

    location ~ ^/(assets|images|javascripts|stylesheets|swfs|system)/ {
    root $app_root/public;
    gzip_static on;
    expires max;
    add_header Cache-Control public;
    @@ -54,12 +51,6 @@ server {
    break;
    }

    location = /favicon.ico {
    root $app_root/public;
    expires max;
    add_header Cache-Control public;
    }

    include /home/app/public_html/app_production/current/config/server/production/nginx_errors.conf;

    access_log /dev/null;
    6 changes: 5 additions & 1 deletion 5. deploy.rb
    Original file line number Diff line number Diff line change
    @@ -32,13 +32,17 @@
    set :normalize_asset_timestamps, false


    # Optional
    before "deploy", "deploy:web:disable"
    before "deploy:stop", "deploy:web:disable"

    after "deploy:update_code", "deploy:symlink_shared"

    # Optional
    after "deploy:start", "deploy:web:enable"
    after "deploy", "deploy:web:enable", "deploy:cleanup"
    after "deploy", "deploy:web:enable"

    after "deploy", "deploy:cleanup"


    namespace :deploy do
  14. @mikhailov mikhailov revised this gist Jul 8, 2012. 4 changed files with 0 additions and 238 deletions.
    86 changes: 0 additions & 86 deletions 4. deploy.rb
    Original file line number Diff line number Diff line change
    @@ -1,86 +0,0 @@
    # Capistrano configuration
    #
    # require 'new_relic/recipes' - Newrelic notification about deployment
    # require 'capistrano/ext/multistage' - We use 2 deployment environment: staging and production.
    # set :deploy_via, :remote_cache - fetch only latest changes during deployment
    # set :normalize_asset_timestamps - no need to touch (date modification) every assets
    # "deploy:web:disable" - traditional maintenance page (during DB migrations deployment)
    # task :restart - Unicorn with preload_app should be reloaded by USR2+QUIT signals, not HUP
    #
    # config/deploy.rb


    require 'bundler/capistrano'
    require 'capistrano/ext/multistage'
    require 'new_relic/recipes'

    set :stages, %w(staging production)
    set :default_stage, "staging"

    set :scm, :git
    set :repository, "..."
    set :deploy_via, :remote_cache
    default_run_options[:pty] = true

    set :application, "app"
    set :use_sudo, false
    set :user, "app"
    set :normalize_asset_timestamps, false


    before "deploy", "deploy:web:disable"
    before "deploy:stop", "deploy:web:disable"

    after "deploy:update_code", "deploy:symlink_shared"

    after "deploy:start", "deploy:web:enable"
    after "deploy", "deploy:web:enable", "deploy:cleanup"


    namespace :deploy do

    %w[start stop].each do |command|
    desc "#{command} unicorn server"
    task command, :roles => :app, :except => { :no_release => true } do
    run "#{current_path}/config/server/#{rails_env}/unicorn_init.sh #{command}"
    end
    end

    desc "restart unicorn server"
    task :restart, :roles => :app, :except => { :no_release => true } do
    run "#{current_path}/config/server/#{rails_env}/unicorn_init.sh upgrade"
    end


    desc "Link in the production database.yml and assets"
    task :symlink_shared do
    run "ln -nfs #{deploy_to}/shared/config/database.yml #{release_path}/config/database.yml"
    end


    namespace :web do
    desc "Maintenance start"
    task :disable, :roles => :web do
    on_rollback { run "rm #{shared_path}/system/maintenance.html" }
    page = File.read("public/503.html")
    put page, "#{shared_path}/system/maintenance.html", :mode => 0644
    end

    desc "Maintenance stop"
    task :enable, :roles => :web do
    run "rm #{shared_path}/system/maintenance.html"
    end
    end

    end


    namespace :log do
    desc "A pinch of tail"
    task :tailf, :roles => :app do
    run "tail -n 10000 -f #{shared_path}/log/#{rails_env}.log" do |channel, stream, data|
    puts "#{data}"
    break if stream == :err
    end
    end
    end
    9 changes: 0 additions & 9 deletions 5. production.rb
    Original file line number Diff line number Diff line change
    @@ -1,9 +0,0 @@
    # capistrano production config
    #
    # config/deploy/production.rb


    server "8.8.8.8", :app, :web, :db, :primary => true
    set :branch, "production"
    set :deploy_to, "/home/app/public_html/app_production"
    set :rails_env, "production"
    59 changes: 0 additions & 59 deletions 6. unicorn.rb
    Original file line number Diff line number Diff line change
    @@ -1,59 +0,0 @@
    # Unicorn configuration file to be running by unicorn_init.sh with capistrano task
    # read an example configuration before: http://unicorn.bogomips.org/examples/unicorn.conf.rb
    #
    # working_directory, pid, paths - internal Unicorn variables must to setup
    # worker_process 4 - is good enough for serve small production application
    # timeout 30 - time limit when unresponded workers to restart
    # preload_app true - the most interesting option that confuse a lot of us,
    # just setup is as true always, it means extra work on
    # deployment scripts to make it correctly
    # before_fork, after_fork - reconnect to all dependent services: DB, Redis, Sphinx etc.
    # deal with old_pid only if CPU or RAM are limited enough
    #
    # config/server/production/unicorn.rb


    working_directory "/home/app/public_html/app_production/current"
    pid "/home/app/public_html/app_production/current/tmp/pids/unicorn.pid"
    stderr_path "/home/app/public_html/app_production/current/log/unicorn.log"
    stdout_path "/home/app/public_html/app_production/current/log/unicorn.log"

    listen "/tmp/unicorn.production.sock"
    worker_processes 4
    timeout 30
    preload_app true


    before_fork do |server, worker|
    if defined?(ActiveRecord::Base)
    ActiveRecord::Base.connection.disconnect!
    end

    # Uncomment this out if your system can't house twice as many worker_processes as you have configured.
    #
    # 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

    if defined?(Resque)
    Resque.redis.quit
    end

    sleep 1
    end


    after_fork do |server, worker|
    if defined?(ActiveRecord::Base)
    ActiveRecord::Base.establish_connection
    end

    if defined?(Resque)
    Resque.redis = 'localhost:6379'
    end
    end
    84 changes: 0 additions & 84 deletions 7. unicorn_init.sh
    Original file line number Diff line number Diff line change
    @@ -1,84 +0,0 @@
    # Unicorn handle shell script
    #
    # APP_ROOT, PID - are the same as you setup above
    # CMD - use bundle binstubs (bundle install --binstubs) to
    # forget about "bundle exec" stuff, run in demonize mode
    # bin/unicorn is for Rack application (config.ru in root dir), but
    # bin/unicorn_rails is to use with Rails 2.3
    #
    # To handle "app_preload true" configuration we should use USR2+QUIT signals, not HUP!
    # So we rewrite capistrano deployment scripts to manage it.
    #
    # config/server/production/unicorn_init.sh


    #!/bin/sh
    set -e
    # Example init script, this can be used with nginx, too,
    # since nginx and unicorn accept the same signals

    TIMEOUT=${TIMEOUT-60}
    APP_ROOT=/home/app/public_html/app_production/current
    PID=$APP_ROOT/tmp/pids/unicorn.pid
    CMD="$APP_ROOT/bin/unicorn -D -c $APP_ROOT/config/server/unicorn.rb -E production"
    action="$1"
    set -u

    old_pid="$PID.oldbin"

    cd $APP_ROOT || exit 1

    sig () {
    test -s "$PID" && kill -$1 `cat $PID`
    }

    oldsig () {
    test -s $old_pid && kill -$1 `cat $old_pid`
    }

    case $action in
    start)
    sig 0 && echo >&2 "Already running" && exit 0
    $CMD
    ;;
    stop)
    sig QUIT && exit 0
    echo >&2 "Not running"
    ;;
    force-stop)
    sig TERM && exit 0
    echo >&2 "Not running"
    ;;
    restart|reload)
    sig HUP && echo reloaded OK && exit 0
    echo >&2 "Couldn't reload, starting '$CMD' instead"
    $CMD
    ;;
    upgrade)
    if sig USR2 && sleep 2 && 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 '$CMD' instead"
    $CMD
    ;;
    reopen-logs)
    sig USR1
    ;;
    *)
    echo >&2 "Usage: $0 <start|stop|restart|upgrade|force-stop|reopen-logs>"
    exit 1
    ;;
    esac
  15. @mikhailov mikhailov revised this gist Jul 8, 2012. 3 changed files with 7 additions and 2 deletions.
    2 changes: 1 addition & 1 deletion 0. nginx_setup.sh
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,7 @@
    # Nginx optimal congifuration guide.
    # We use latest stable nginx with fresh **openssl**, **zlib** and **pcre** dependencies.
    # Some extra handy modules to use: --with-http_stub_status_module --with-http_gzip_static_module
    #


    $ cd /usr/src
    $ wget http://nginx.org/download/nginx-1.2.2.tar.gz
    3 changes: 2 additions & 1 deletion 4. nginx_errors.conf
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,6 @@
    # nginx configuration piece to handle errorrs
    # it should be included in the nginx_host.conf
    #
    # config/server/production/nginx_errors.conf

    error_page 500 502 504 /500.html;
    error_page 503 @503;
    4 changes: 4 additions & 0 deletions 5. deploy.rb
    Original file line number Diff line number Diff line change
    @@ -7,6 +7,10 @@
    # "deploy:web:disable" - traditional maintenance page (during DB migrations deployment)
    # task :restart - Unicorn with preload_app should be reloaded by USR2+QUIT signals, not HUP
    #
    # http://unicorn.bogomips.org/SIGNALS.html
    # "If “preload_app” is true, then application code changes will have no effect;
    # USR2 + QUIT (see below) must be used to load newer code in this case"
    #
    # config/deploy.rb


  16. @mikhailov mikhailov revised this gist Jul 8, 2012. 1 changed file with 10 additions and 8 deletions.
    18 changes: 10 additions & 8 deletions 6. unicorn.rb
    Original file line number Diff line number Diff line change
    @@ -29,14 +29,16 @@
    ActiveRecord::Base.connection.disconnect!
    end

    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
    # Uncomment this out if your system can't house twice as many worker_processes as you have configured.
    #
    # 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

    if defined?(Resque)
    Resque.redis.quit
  17. @mikhailov mikhailov revised this gist Jul 8, 2012. 1 changed file with 3 additions and 2 deletions.
    5 changes: 3 additions & 2 deletions 9. sshconfig
    Original file line number Diff line number Diff line change
    @@ -4,8 +4,9 @@
    $ mkdir ~/.ssh/cm_socket
    $ vim ~/.ssh/config

    ```
    Host *
    ControlMaster auto
    ControlPath ~/.ssh/cm_socket/%r@%h:%p
    ```

    $ cd ~/app
    $ cap deploy
  18. @mikhailov mikhailov revised this gist Jul 8, 2012. 7 changed files with 296 additions and 43 deletions.
    59 changes: 16 additions & 43 deletions 3. nginx_host.conf
    Original file line number Diff line number Diff line change
    @@ -24,11 +24,12 @@ server {


    server {
    set $app_root "/home/app/public_html/app_production/current";

    ssl on;
    listen 443 ssl;
    server_name server.com;

    root /home/app/public_html/app_production/current;
    root $app_root;
    try_files $uri /public/system/maintenance.html @unicorn;

    location @unicorn {
    @@ -37,58 +38,30 @@ server {
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://unicorn;

    limit_req zone=one;

    access_log /dev/null;
    error_log logs/unicorn.error.log;
    }


    error_page 500 502 504 /500.html;
    error_page 503 @503;

    location = /50x.html {
    root html;
    }

    location = /404.html {
    root html;
    }

    location @503 {
    error_page 405 = /system/maintenance.html;
    if (-f $document_root/system/maintenance.html) {
    rewrite ^(.*)$ /system/maintenance.html break;
    }
    rewrite ^(.*)$ /503.html break;
    }

    if ($request_method !~ ^(GET|HEAD|PUT|POST|DELETE|OPTIONS)$ ){
    return 405;
    }

    if (-f $document_root/system/maintenance.html) {
    return 503;
    }


    location ~ ^/(assets|images|javascripts|stylesheets|swfs|system)/ {
    root /home/app/public_html/app_production/current/public;
    gzip_static on;
    expires max;
    add_header Cache-Control public;
    add_header Last-Modified "";
    add_header ETag "";
    root $app_root/public;
    gzip_static on;
    expires max;
    add_header Cache-Control public;
    add_header Last-Modified "";
    add_header ETag "";
    break;
    }


    location ~ \.(php|html)$ {
    return 405;
    location = /favicon.ico {
    root $app_root/public;
    expires max;
    add_header Cache-Control public;
    }

    include /home/app/public_html/app_production/current/config/server/production/nginx_errors.conf;

    access_log /dev/null;
    error_log /dev/null;
    access_log /dev/null;
    error_log /dev/null;
    }
    33 changes: 33 additions & 0 deletions 4. nginx_errors.conf
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,33 @@
    # nginx configuration piece to handle errorrs
    # it should be included in the nginx_host.conf

    error_page 500 502 504 /500.html;
    error_page 503 @503;

    location = /50x.html {
    root html;
    }

    location = /404.html {
    root html;
    }

    location @503 {
    error_page 405 = /system/maintenance.html;
    if (-f $document_root/system/maintenance.html) {
    rewrite ^(.*)$ /system/maintenance.html break;
    }
    rewrite ^(.*)$ /503.html break;
    }

    if ($request_method !~ ^(GET|HEAD|PUT|POST|DELETE|OPTIONS)$ ){
    return 405;
    }

    if (-f $document_root/system/maintenance.html) {
    return 503;
    }

    location ~ \.(php|html)$ {
    return 405;
    }
    86 changes: 86 additions & 0 deletions 5. deploy.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,86 @@
    # Capistrano configuration
    #
    # require 'new_relic/recipes' - Newrelic notification about deployment
    # require 'capistrano/ext/multistage' - We use 2 deployment environment: staging and production.
    # set :deploy_via, :remote_cache - fetch only latest changes during deployment
    # set :normalize_asset_timestamps - no need to touch (date modification) every assets
    # "deploy:web:disable" - traditional maintenance page (during DB migrations deployment)
    # task :restart - Unicorn with preload_app should be reloaded by USR2+QUIT signals, not HUP
    #
    # config/deploy.rb


    require 'bundler/capistrano'
    require 'capistrano/ext/multistage'
    require 'new_relic/recipes'

    set :stages, %w(staging production)
    set :default_stage, "staging"

    set :scm, :git
    set :repository, "..."
    set :deploy_via, :remote_cache
    default_run_options[:pty] = true

    set :application, "app"
    set :use_sudo, false
    set :user, "app"
    set :normalize_asset_timestamps, false


    before "deploy", "deploy:web:disable"
    before "deploy:stop", "deploy:web:disable"

    after "deploy:update_code", "deploy:symlink_shared"

    after "deploy:start", "deploy:web:enable"
    after "deploy", "deploy:web:enable", "deploy:cleanup"


    namespace :deploy do

    %w[start stop].each do |command|
    desc "#{command} unicorn server"
    task command, :roles => :app, :except => { :no_release => true } do
    run "#{current_path}/config/server/#{rails_env}/unicorn_init.sh #{command}"
    end
    end

    desc "restart unicorn server"
    task :restart, :roles => :app, :except => { :no_release => true } do
    run "#{current_path}/config/server/#{rails_env}/unicorn_init.sh upgrade"
    end


    desc "Link in the production database.yml and assets"
    task :symlink_shared do
    run "ln -nfs #{deploy_to}/shared/config/database.yml #{release_path}/config/database.yml"
    end


    namespace :web do
    desc "Maintenance start"
    task :disable, :roles => :web do
    on_rollback { run "rm #{shared_path}/system/maintenance.html" }
    page = File.read("public/503.html")
    put page, "#{shared_path}/system/maintenance.html", :mode => 0644
    end

    desc "Maintenance stop"
    task :enable, :roles => :web do
    run "rm #{shared_path}/system/maintenance.html"
    end
    end

    end


    namespace :log do
    desc "A pinch of tail"
    task :tailf, :roles => :app do
    run "tail -n 10000 -f #{shared_path}/log/#{rails_env}.log" do |channel, stream, data|
    puts "#{data}"
    break if stream == :err
    end
    end
    end
    9 changes: 9 additions & 0 deletions 6. production.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,9 @@
    # capistrano production config
    #
    # config/deploy/production.rb


    server "8.8.8.8", :app, :web, :db, :primary => true
    set :branch, "production"
    set :deploy_to, "/home/app/public_html/app_production"
    set :rails_env, "production"
    57 changes: 57 additions & 0 deletions 7. unicorn.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,57 @@
    # Unicorn configuration file to be running by unicorn_init.sh with capistrano task
    # read an example configuration before: http://unicorn.bogomips.org/examples/unicorn.conf.rb
    #
    # working_directory, pid, paths - internal Unicorn variables must to setup
    # worker_process 4 - is good enough for serve small production application
    # timeout 30 - time limit when unresponded workers to restart
    # preload_app true - the most interesting option that confuse a lot of us,
    # just setup is as true always, it means extra work on
    # deployment scripts to make it correctly
    # before_fork, after_fork - reconnect to all dependent services: DB, Redis, Sphinx etc.
    # deal with old_pid only if CPU or RAM are limited enough
    #
    # config/server/production/unicorn.rb


    working_directory "/home/app/public_html/app_production/current"
    pid "/home/app/public_html/app_production/current/tmp/pids/unicorn.pid"
    stderr_path "/home/app/public_html/app_production/current/log/unicorn.log"
    stdout_path "/home/app/public_html/app_production/current/log/unicorn.log"

    listen "/tmp/unicorn.production.sock"
    worker_processes 4
    timeout 30
    preload_app true


    before_fork do |server, worker|
    if defined?(ActiveRecord::Base)
    ActiveRecord::Base.connection.disconnect!
    end

    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

    if defined?(Resque)
    Resque.redis.quit
    end

    sleep 1
    end


    after_fork do |server, worker|
    if defined?(ActiveRecord::Base)
    ActiveRecord::Base.establish_connection
    end

    if defined?(Resque)
    Resque.redis = 'localhost:6379'
    end
    end
    84 changes: 84 additions & 0 deletions 8. unicorn_init.sh
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,84 @@
    # Unicorn handle shell script
    #
    # APP_ROOT, PID - are the same as you setup above
    # CMD - use bundle binstubs (bundle install --binstubs) to
    # forget about "bundle exec" stuff, run in demonize mode
    # bin/unicorn is for Rack application (config.ru in root dir), but
    # bin/unicorn_rails is to use with Rails 2.3
    #
    # To handle "app_preload true" configuration we should use USR2+QUIT signals, not HUP!
    # So we rewrite capistrano deployment scripts to manage it.
    #
    # config/server/production/unicorn_init.sh


    #!/bin/sh
    set -e
    # Example init script, this can be used with nginx, too,
    # since nginx and unicorn accept the same signals

    TIMEOUT=${TIMEOUT-60}
    APP_ROOT=/home/app/public_html/app_production/current
    PID=$APP_ROOT/tmp/pids/unicorn.pid
    CMD="$APP_ROOT/bin/unicorn -D -c $APP_ROOT/config/server/unicorn.rb -E production"
    action="$1"
    set -u

    old_pid="$PID.oldbin"

    cd $APP_ROOT || exit 1

    sig () {
    test -s "$PID" && kill -$1 `cat $PID`
    }

    oldsig () {
    test -s $old_pid && kill -$1 `cat $old_pid`
    }

    case $action in
    start)
    sig 0 && echo >&2 "Already running" && exit 0
    $CMD
    ;;
    stop)
    sig QUIT && exit 0
    echo >&2 "Not running"
    ;;
    force-stop)
    sig TERM && exit 0
    echo >&2 "Not running"
    ;;
    restart|reload)
    sig HUP && echo reloaded OK && exit 0
    echo >&2 "Couldn't reload, starting '$CMD' instead"
    $CMD
    ;;
    upgrade)
    if sig USR2 && sleep 2 && 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 '$CMD' instead"
    $CMD
    ;;
    reopen-logs)
    sig USR1
    ;;
    *)
    echo >&2 "Usage: $0 <start|stop|restart|upgrade|force-stop|reopen-logs>"
    exit 1
    ;;
    esac
    11 changes: 11 additions & 0 deletions 9. sshconfig
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,11 @@
    # deploy speed up via SSH ControlMaster
    #

    $ mkdir ~/.ssh/cm_socket
    $ vim ~/.ssh/config

    ```
    Host *
    ControlMaster auto
    ControlPath ~/.ssh/cm_socket/%r@%h:%p
    ```
  19. @mikhailov mikhailov revised this gist Jul 8, 2012. 2 changed files with 5 additions and 2 deletions.
    3 changes: 3 additions & 0 deletions 1. nginx
    Original file line number Diff line number Diff line change
    @@ -9,6 +9,9 @@
    # Short-Description: starts the nginx web server
    # Description: starts nginx using start-stop-daemon
    ### END INIT INFO
    #
    # /etc/init.d/nginx


    PATH=/opt/nginx/sbin:/sbin:/bin:/usr/sbin:/usr/bin
    DAEMON=/opt/nginx/sbin/nginx
    4 changes: 2 additions & 2 deletions 5. production.rb
    Original file line number Diff line number Diff line change
    @@ -1,9 +1,9 @@
    # capistrano production config
    #
    # /config/deploy.rb
    # config/deploy/production.rb

    server "8.8.8.8", :app, :web, :db, :primary => true

    server "8.8.8.8", :app, :web, :db, :primary => true
    set :branch, "production"
    set :deploy_to, "/home/app/public_html/app_production"
    set :rails_env, "production"
  20. @mikhailov mikhailov revised this gist Jul 8, 2012. 1 changed file with 6 additions and 1 deletion.
    7 changes: 6 additions & 1 deletion 0. nginx_setup.sh
    Original file line number Diff line number Diff line change
    @@ -22,4 +22,9 @@ $ make && make install

    $ mkdir /tmp/client_body_temp
    $ mkdir /opt/nginx/ssl_certs
    # make sure that you have SSL keys: server.crt, server.key
    # make sure that you have SSL keys: server.crt, server.key

    $ echo "include /home/app/public_html/app_production/current/config/server/production/nginx.conf;" > /opt/nginx/conf/nginx.conf

    $ vim /etc/init.d/nginx # see the config below
    $ chmod +x /etc/init.d/nginx && update-rc.d -f nginx defaults
  21. @mikhailov mikhailov revised this gist Jul 8, 2012. 2 changed files with 5 additions and 2 deletions.
    5 changes: 4 additions & 1 deletion 0. nginx_setup.sh
    Original file line number Diff line number Diff line change
    @@ -19,4 +19,7 @@ $ tar xzvf openssl-1.0.1c.tar.gz && rm -f openssl-1.0.1c.tar.gz
    $ cd nginx-1.2.2 && ./configure --prefix=/opt/nginx --with-pcre=/usr/src/pcre-8.30 --with-zlib=/usr/src/zlib-1.2.7 --with-openssl-opt=no-krb5 --with-openssl=/usr/src/openssl-1.0.1c --with-http_ssl_module --without-mail_pop3_module --without-mail_smtp_module --without-mail_imap_module --with-http_stub_status_module --with-http_gzip_static_module

    $ make && make install
    $ mkdir /tmp/client_body_temp

    $ mkdir /tmp/client_body_temp
    $ mkdir /opt/nginx/ssl_certs
    # make sure that you have SSL keys: server.crt, server.key
    2 changes: 1 addition & 1 deletion 2. nginx.conf
    Original file line number Diff line number Diff line change
    @@ -53,5 +53,5 @@ http {

    limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;

    include /home/app/public_html/app_production/current/config/server/nginx_host.conf;
    include /home/app/public_html/app_production/current/config/server/nginx_host.conf;
    }
  22. @mikhailov mikhailov revised this gist Jul 8, 2012. 8 changed files with 66 additions and 1 deletion.
    5 changes: 4 additions & 1 deletion 0. nginx_setup.sh
    Original file line number Diff line number Diff line change
    @@ -1,15 +1,18 @@
    # Nginx optimal congifuration guide.
    # We use latest stable nginx with fresh **openssl**, **zlib** and **pcre** dependencies.
    # Some extra handy modules to use: --with-http_stub_status_module --with-http_gzip_static_module

    #

    $ cd /usr/src
    $ wget http://nginx.org/download/nginx-1.2.2.tar.gz
    $ tar xzvf ./nginx-1.2.2.tar.gz && rm -f ./nginx-1.2.2.tar.gz

    $ wget http://zlib.net/zlib127.zip
    $ unzip zlib127.zip && rm -f zlib127.zip

    $ wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.30.tar.gz
    $ tar xzvf pcre-8.30.tar.gz && rm -f ./pcre-8.30.tar.gz

    $ wget http://www.openssl.org/source/openssl-1.0.1c.tar.gz
    $ tar xzvf openssl-1.0.1c.tar.gz && rm -f openssl-1.0.1c.tar.gz

    62 changes: 62 additions & 0 deletions 1. nginx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,62 @@
    #! /bin/sh

    ### BEGIN INIT INFO
    # Provides: nginx
    # Required-Start: $all
    # Required-Stop: $all
    # Default-Start: 2 3 4 5
    # Default-Stop: 0 1 6
    # Short-Description: starts the nginx web server
    # Description: starts nginx using start-stop-daemon
    ### END INIT INFO

    PATH=/opt/nginx/sbin:/sbin:/bin:/usr/sbin:/usr/bin
    DAEMON=/opt/nginx/sbin/nginx
    NAME=nginx
    DESC=nginx

    test -x $DAEMON || exit 0

    # Include nginx defaults if available
    if [ -f /etc/default/nginx ] ; then
    . /etc/default/nginx
    fi

    set -e

    case "$1" in
    start)
    echo -n "Starting $DESC: "
    start-stop-daemon --start --quiet --pidfile /opt/nginx/logs/$NAME.pid \
    --exec $DAEMON -- $DAEMON_OPTS
    echo "$NAME."
    ;;
    stop)
    echo -n "Stopping $DESC: "
    start-stop-daemon --stop --quiet --pidfile /opt/nginx/logs/$NAME.pid \
    --exec $DAEMON
    echo "$NAME."
    ;;
    restart|force-reload)
    echo -n "Restarting $DESC: "
    start-stop-daemon --stop --quiet --pidfile \
    /opt/nginx/logs/$NAME.pid --exec $DAEMON
    sleep 1
    start-stop-daemon --start --quiet --pidfile \
    /opt/nginx/logs/$NAME.pid --exec $DAEMON -- $DAEMON_OPTS
    echo "$NAME."
    ;;
    reload)
    echo -n "Reloading $DESC configuration: "
    start-stop-daemon --stop --signal HUP --quiet --pidfile /opt/nginx/logs/$NAME.pid \
    --exec $DAEMON
    echo "$NAME."
    ;;
    *)
    N=/etc/init.d/$NAME
    echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2
    exit 1
    ;;
    esac

    exit 0
    File renamed without changes.
    File renamed without changes.
    File renamed without changes.
    File renamed without changes.
    File renamed without changes.
    File renamed without changes.
  23. @mikhailov mikhailov revised this gist Jul 8, 2012. 7 changed files with 22 additions and 0 deletions.
    1 change: 1 addition & 0 deletions 0. nginx_setup.sh
    Original file line number Diff line number Diff line change
    @@ -2,6 +2,7 @@
    # We use latest stable nginx with fresh **openssl**, **zlib** and **pcre** dependencies.
    # Some extra handy modules to use: --with-http_stub_status_module --with-http_gzip_static_module


    $ cd /usr/src
    $ wget http://nginx.org/download/nginx-1.2.2.tar.gz
    $ tar xzvf ./nginx-1.2.2.tar.gz && rm -f ./nginx-1.2.2.tar.gz
    3 changes: 3 additions & 0 deletions 1. nginx.conf
    Original file line number Diff line number Diff line change
    @@ -3,6 +3,9 @@
    # Keep nginx configuration in repo, then just include it in /opt/nginx/conf/nginx.conf
    # And DDoS prevent attack with directive limit_req_zone (limit 10 request/sec from 1 IP address)
    # then it enables in the server block by "limit_req zone=one".
    #
    # config/server/production/nginx.conf


    user app;
    worker_processes 2;
    3 changes: 3 additions & 0 deletions 2. nginx_host.conf
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,8 @@
    # Nginx server block configuration with proxy_pass to Unicorn upstream
    # We use full-SSL site with web-server redirection, no mess with Rails application redirection
    #
    # config/server/production/nginx_host.conf


    upstream unicorn {
    server unix:/tmp/unicorn.production.sock fail_timeout=0;
    2 changes: 2 additions & 0 deletions 3. deploy.rb
    Original file line number Diff line number Diff line change
    @@ -6,6 +6,8 @@
    # set :normalize_asset_timestamps - no need to touch (date modification) every assets
    # "deploy:web:disable" - traditional maintenance page (during DB migrations deployment)
    # task :restart - Unicorn with preload_app should be reloaded by USR2+QUIT signals, not HUP
    #
    # config/deploy.rb


    require 'bundler/capistrano'
    9 changes: 9 additions & 0 deletions 4. production.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,9 @@
    # capistrano production config
    #
    # /config/deploy.rb

    server "8.8.8.8", :app, :web, :db, :primary => true

    set :branch, "production"
    set :deploy_to, "/home/app/public_html/app_production"
    set :rails_env, "production"
    2 changes: 2 additions & 0 deletions 4. unicorn.rb → 5. unicorn.rb
    Original file line number Diff line number Diff line change
    @@ -9,6 +9,8 @@
    # deployment scripts to make it correctly
    # before_fork, after_fork - reconnect to all dependent services: DB, Redis, Sphinx etc.
    # deal with old_pid only if CPU or RAM are limited enough
    #
    # config/server/production/unicorn.rb


    working_directory "/home/app/public_html/app_production/current"
    2 changes: 2 additions & 0 deletions 5. unicorn_init.sh → 6. unicorn_init.sh
    Original file line number Diff line number Diff line change
    @@ -8,6 +8,8 @@
    #
    # To handle "app_preload true" configuration we should use USR2+QUIT signals, not HUP!
    # So we rewrite capistrano deployment scripts to manage it.
    #
    # config/server/production/unicorn_init.sh


    #!/bin/sh
  24. @mikhailov mikhailov revised this gist Jul 8, 2012. 6 changed files with 0 additions and 0 deletions.
    File renamed without changes.
    File renamed without changes.
    File renamed without changes.
    File renamed without changes.
    File renamed without changes.
    File renamed without changes.
  25. @mikhailov mikhailov revised this gist Jul 5, 2012. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion nginx.conf
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,8 @@
    # Nginx main block configuration file.
    # The most important directives here are ssl_protocols and ssl_ciphers
    # Keep nginx configuration in repo, then just include it in /opt/nginx/conf/nginx.conf
    # And DDoS prevent attack with directive limit_req_zone (limit 10 request from 1 IP address)
    # And DDoS prevent attack with directive limit_req_zone (limit 10 request/sec from 1 IP address)
    # then it enables in the server block by "limit_req zone=one".

    user app;
    worker_processes 2;
  26. @mikhailov mikhailov revised this gist Jul 5, 2012. 2 changed files with 2 additions and 2 deletions.
    2 changes: 1 addition & 1 deletion deploy.rb
    Original file line number Diff line number Diff line change
    @@ -20,7 +20,7 @@
    set :deploy_via, :remote_cache
    default_run_options[:pty] = true

    set :application, "admin"
    set :application, "app"
    set :use_sudo, false
    set :user, "app"
    set :normalize_asset_timestamps, false
    2 changes: 1 addition & 1 deletion unicorn_init.sh
    Original file line number Diff line number Diff line change
    @@ -16,7 +16,7 @@ set -e
    # since nginx and unicorn accept the same signals

    TIMEOUT=${TIMEOUT-60}
    APP_ROOT=/home/app/public_html/admin_production/current
    APP_ROOT=/home/app/public_html/app_production/current
    PID=$APP_ROOT/tmp/pids/unicorn.pid
    CMD="$APP_ROOT/bin/unicorn -D -c $APP_ROOT/config/server/unicorn.rb -E production"
    action="$1"
  27. @mikhailov mikhailov created this gist Jul 5, 2012.
    84 changes: 84 additions & 0 deletions deploy.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,84 @@
    # Capistrano configuration
    #
    # require 'new_relic/recipes' - Newrelic notification about deployment
    # require 'capistrano/ext/multistage' - We use 2 deployment environment: staging and production.
    # set :deploy_via, :remote_cache - fetch only latest changes during deployment
    # set :normalize_asset_timestamps - no need to touch (date modification) every assets
    # "deploy:web:disable" - traditional maintenance page (during DB migrations deployment)
    # task :restart - Unicorn with preload_app should be reloaded by USR2+QUIT signals, not HUP


    require 'bundler/capistrano'
    require 'capistrano/ext/multistage'
    require 'new_relic/recipes'

    set :stages, %w(staging production)
    set :default_stage, "staging"

    set :scm, :git
    set :repository, "..."
    set :deploy_via, :remote_cache
    default_run_options[:pty] = true

    set :application, "admin"
    set :use_sudo, false
    set :user, "app"
    set :normalize_asset_timestamps, false


    before "deploy", "deploy:web:disable"
    before "deploy:stop", "deploy:web:disable"

    after "deploy:update_code", "deploy:symlink_shared"

    after "deploy:start", "deploy:web:enable"
    after "deploy", "deploy:web:enable", "deploy:cleanup"


    namespace :deploy do

    %w[start stop].each do |command|
    desc "#{command} unicorn server"
    task command, :roles => :app, :except => { :no_release => true } do
    run "#{current_path}/config/server/#{rails_env}/unicorn_init.sh #{command}"
    end
    end

    desc "restart unicorn server"
    task :restart, :roles => :app, :except => { :no_release => true } do
    run "#{current_path}/config/server/#{rails_env}/unicorn_init.sh upgrade"
    end


    desc "Link in the production database.yml and assets"
    task :symlink_shared do
    run "ln -nfs #{deploy_to}/shared/config/database.yml #{release_path}/config/database.yml"
    end


    namespace :web do
    desc "Maintenance start"
    task :disable, :roles => :web do
    on_rollback { run "rm #{shared_path}/system/maintenance.html" }
    page = File.read("public/503.html")
    put page, "#{shared_path}/system/maintenance.html", :mode => 0644
    end

    desc "Maintenance stop"
    task :enable, :roles => :web do
    run "rm #{shared_path}/system/maintenance.html"
    end
    end

    end


    namespace :log do
    desc "A pinch of tail"
    task :tailf, :roles => :app do
    run "tail -n 10000 -f #{shared_path}/log/#{rails_env}.log" do |channel, stream, data|
    puts "#{data}"
    break if stream == :err
    end
    end
    end
    53 changes: 53 additions & 0 deletions nginx.conf
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,53 @@
    # Nginx main block configuration file.
    # The most important directives here are ssl_protocols and ssl_ciphers
    # Keep nginx configuration in repo, then just include it in /opt/nginx/conf/nginx.conf
    # And DDoS prevent attack with directive limit_req_zone (limit 10 request from 1 IP address)

    user app;
    worker_processes 2;
    worker_priority -5;

    error_log logs/nginx.error.log crit;

    events {
    use epoll;
    worker_connections 2048;
    }


    http {
    client_max_body_size 25m;
    client_body_buffer_size 128k;
    client_body_temp_path /tmp/client_body_temp;

    include mime.types;
    default_type application/octet-stream;
    server_tokens off;
    sendfile on;
    keepalive_timeout 70;

    gzip on;
    gzip_http_version 1.1;
    gzip_disable "msie6";
    gzip_vary on;
    gzip_min_length 1100;
    gzip_buffers 64 8k;
    gzip_comp_level 3;
    gzip_proxied any;
    gzip_types text/plain text/css application/x-javascript text/xml application/xml;

    ssl_certificate /opt/nginx/ssl_certs/server.crt;
    ssl_certificate_key /opt/nginx/ssl_certs/server.key;
    ssl_session_timeout 15m;
    ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers RC4:HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;

    add_header Strict-Transport-Security "max-age=16070400; includeSubdomains";
    add_header X-Frame-Options DENY;

    limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;

    include /home/app/public_html/app_production/current/config/server/nginx_host.conf;
    }
    91 changes: 91 additions & 0 deletions nginx_host.conf
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,91 @@
    # Nginx server block configuration with proxy_pass to Unicorn upstream
    # We use full-SSL site with web-server redirection, no mess with Rails application redirection

    upstream unicorn {
    server unix:/tmp/unicorn.production.sock fail_timeout=0;
    }


    server {
    listen 80;
    server_name server.com;
    rewrite ^(.*) https://$host$1 permanent;

    location ~ \.(php|html)$ {
    deny all;
    }

    access_log /dev/null;
    error_log /dev/null;
    }


    server {
    ssl on;
    listen 443 ssl;
    server_name server.com;

    root /home/app/public_html/app_production/current;
    try_files $uri /public/system/maintenance.html @unicorn;

    location @unicorn {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://unicorn;

    limit_req zone=one;

    access_log /dev/null;
    error_log logs/unicorn.error.log;
    }


    error_page 500 502 504 /500.html;
    error_page 503 @503;

    location = /50x.html {
    root html;
    }

    location = /404.html {
    root html;
    }

    location @503 {
    error_page 405 = /system/maintenance.html;
    if (-f $document_root/system/maintenance.html) {
    rewrite ^(.*)$ /system/maintenance.html break;
    }
    rewrite ^(.*)$ /503.html break;
    }

    if ($request_method !~ ^(GET|HEAD|PUT|POST|DELETE|OPTIONS)$ ){
    return 405;
    }

    if (-f $document_root/system/maintenance.html) {
    return 503;
    }


    location ~ ^/(assets|images|javascripts|stylesheets|swfs|system)/ {
    root /home/app/public_html/app_production/current/public;
    gzip_static on;
    expires max;
    add_header Cache-Control public;
    add_header Last-Modified "";
    add_header ETag "";
    break;
    }


    location ~ \.(php|html)$ {
    return 405;
    }


    access_log /dev/null;
    error_log /dev/null;
    }
    18 changes: 18 additions & 0 deletions nginx_setup.sh
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,18 @@
    # Nginx optimal congifuration guide.
    # We use latest stable nginx with fresh **openssl**, **zlib** and **pcre** dependencies.
    # Some extra handy modules to use: --with-http_stub_status_module --with-http_gzip_static_module

    $ cd /usr/src
    $ wget http://nginx.org/download/nginx-1.2.2.tar.gz
    $ tar xzvf ./nginx-1.2.2.tar.gz && rm -f ./nginx-1.2.2.tar.gz
    $ wget http://zlib.net/zlib127.zip
    $ unzip zlib127.zip && rm -f zlib127.zip
    $ wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.30.tar.gz
    $ tar xzvf pcre-8.30.tar.gz && rm -f ./pcre-8.30.tar.gz
    $ wget http://www.openssl.org/source/openssl-1.0.1c.tar.gz
    $ tar xzvf openssl-1.0.1c.tar.gz && rm -f openssl-1.0.1c.tar.gz

    $ cd nginx-1.2.2 && ./configure --prefix=/opt/nginx --with-pcre=/usr/src/pcre-8.30 --with-zlib=/usr/src/zlib-1.2.7 --with-openssl-opt=no-krb5 --with-openssl=/usr/src/openssl-1.0.1c --with-http_ssl_module --without-mail_pop3_module --without-mail_smtp_module --without-mail_imap_module --with-http_stub_status_module --with-http_gzip_static_module

    $ make && make install
    $ mkdir /tmp/client_body_temp
    55 changes: 55 additions & 0 deletions unicorn.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,55 @@
    # Unicorn configuration file to be running by unicorn_init.sh with capistrano task
    # read an example configuration before: http://unicorn.bogomips.org/examples/unicorn.conf.rb
    #
    # working_directory, pid, paths - internal Unicorn variables must to setup
    # worker_process 4 - is good enough for serve small production application
    # timeout 30 - time limit when unresponded workers to restart
    # preload_app true - the most interesting option that confuse a lot of us,
    # just setup is as true always, it means extra work on
    # deployment scripts to make it correctly
    # before_fork, after_fork - reconnect to all dependent services: DB, Redis, Sphinx etc.
    # deal with old_pid only if CPU or RAM are limited enough


    working_directory "/home/app/public_html/app_production/current"
    pid "/home/app/public_html/app_production/current/tmp/pids/unicorn.pid"
    stderr_path "/home/app/public_html/app_production/current/log/unicorn.log"
    stdout_path "/home/app/public_html/app_production/current/log/unicorn.log"

    listen "/tmp/unicorn.production.sock"
    worker_processes 4
    timeout 30
    preload_app true


    before_fork do |server, worker|
    if defined?(ActiveRecord::Base)
    ActiveRecord::Base.connection.disconnect!
    end

    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

    if defined?(Resque)
    Resque.redis.quit
    end

    sleep 1
    end


    after_fork do |server, worker|
    if defined?(ActiveRecord::Base)
    ActiveRecord::Base.establish_connection
    end

    if defined?(Resque)
    Resque.redis = 'localhost:6379'
    end
    end
    82 changes: 82 additions & 0 deletions unicorn_init.sh
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,82 @@
    # Unicorn handle shell script
    #
    # APP_ROOT, PID - are the same as you setup above
    # CMD - use bundle binstubs (bundle install --binstubs) to
    # forget about "bundle exec" stuff, run in demonize mode
    # bin/unicorn is for Rack application (config.ru in root dir), but
    # bin/unicorn_rails is to use with Rails 2.3
    #
    # To handle "app_preload true" configuration we should use USR2+QUIT signals, not HUP!
    # So we rewrite capistrano deployment scripts to manage it.


    #!/bin/sh
    set -e
    # Example init script, this can be used with nginx, too,
    # since nginx and unicorn accept the same signals

    TIMEOUT=${TIMEOUT-60}
    APP_ROOT=/home/app/public_html/admin_production/current
    PID=$APP_ROOT/tmp/pids/unicorn.pid
    CMD="$APP_ROOT/bin/unicorn -D -c $APP_ROOT/config/server/unicorn.rb -E production"
    action="$1"
    set -u

    old_pid="$PID.oldbin"

    cd $APP_ROOT || exit 1

    sig () {
    test -s "$PID" && kill -$1 `cat $PID`
    }

    oldsig () {
    test -s $old_pid && kill -$1 `cat $old_pid`
    }

    case $action in
    start)
    sig 0 && echo >&2 "Already running" && exit 0
    $CMD
    ;;
    stop)
    sig QUIT && exit 0
    echo >&2 "Not running"
    ;;
    force-stop)
    sig TERM && exit 0
    echo >&2 "Not running"
    ;;
    restart|reload)
    sig HUP && echo reloaded OK && exit 0
    echo >&2 "Couldn't reload, starting '$CMD' instead"
    $CMD
    ;;
    upgrade)
    if sig USR2 && sleep 2 && 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 '$CMD' instead"
    $CMD
    ;;
    reopen-logs)
    sig USR1
    ;;
    *)
    echo >&2 "Usage: $0 <start|stop|restart|upgrade|force-stop|reopen-logs>"
    exit 1
    ;;
    esac