-
-
Save ingeniarius/3083505 to your computer and use it in GitHub Desktop.
Nginx+Unicorn (production-ready setup)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# download and build nginx from sources | |
https://gist.github.com/3083579 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# nginx upstart config | |
https://gist.github.com/2024203 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# nginx.conf | |
user nginx; | |
worker_processes 8; | |
worker_priority -5; | |
error_log logs/nginx.error.log crit; | |
events { | |
use epoll; | |
worker_connections 8192; | |
} | |
timer_resolution 500ms; | |
http { | |
include mime.types; | |
default_type application/octet-stream; | |
server_name_in_redirect off; | |
server_tokens off; | |
log_format main '$remote_addr - $remote_user [$time_local] "$request" ' | |
'$status $body_bytes_sent "$http_referer" ' | |
'"$http_user_agent" "$http_x_forwarded_for"'; | |
sendfile on; | |
tcp_nopush on; | |
keepalive_timeout 10; | |
tcp_nodelay on; | |
client_max_body_size 1m; | |
client_body_buffer_size 128k; | |
client_body_timeout 30; | |
client_body_temp_path /tmp/client_body_temp; | |
client_header_timeout 30; | |
client_header_buffer_size 128; | |
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 expired no-cache no-store private auth; | |
gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript; | |
ssl_certificate /etc/nginx/ssl_certs/server.crt; | |
ssl_certificate_key /etc/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 /etc/nginx/sites-enabled/*; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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; | |
} | |
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/public; | |
try_files $uri /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; | |
} | |
location ~ ^/(assets|images|javascripts|stylesheets|swfs|system)/ { | |
gzip_static on; | |
expires max; | |
add_header Cache-Control public; | |
add_header Last-Modified ""; | |
add_header ETag ""; | |
break; | |
} | |
include /home/app/public_html/app_production/current/config/server/production/nginx_errors.conf; | |
access_log /dev/null; | |
error_log /dev/null; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# nginx configuration piece to handle errorrs | |
# | |
# config/server/production/nginx_errors.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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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 | |
# | |
# 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 | |
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 | |
# 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" | |
after "deploy", "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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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 | |
# 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 | |
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! | |
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# deploy speed up via SSH ControlMaster | |
# | |
$ mkdir ~/.ssh/cm_socket | |
$ vim ~/.ssh/config | |
Host * | |
ControlMaster auto | |
ControlPath ~/.ssh/cm_socket/%r@%h:%p | |
$ cd ~/app | |
$ cap deploy |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment