Nginx Unicorn

Рассмотрим установку на сервере приложения с Nginx Unicorn, первый будет использоваться на фронтэнде, второй представлять собой бэкенд. Приложение работает в виртуальной среде vagrant, но если оно единственное на сервере и виртуализация не используется принципы сохраняются.

Предполагается, что на сервере уже установлен RVM и Ruby, а также имеется написанное приложение, которое и будем запускать. Также установлены гемы Unicorn и rails.

nginx unicorn

 

Установка проекта на Ruby-on-rails со связкой Nginx Unicorn

Проверяем версию Ruby, используемую по умолчанию

 

ruby -v

 

Переходим в каталог с проектом на Ruby-on-rails

cd /home/vagrant

 

Запускаем проект на порту 3000

bundle exec rails s

 

После выполнения команды в браузере по адресу localhost:3000 приложение на rails станет доступно

 

Устанавливаем и запускаем nginx

apt-get install nginx

 

/etc/init.d/nginx start

 

В vagrant настраиваем forward-инг с порта 80 на 8080

 

mcedit Vagrantfile

config.vm.forward_port «rails», 80, 8080

 

Перезапускаем

vagrant reload

 

Проверяем localhost:8080. Можно использовать любой другой свободный порт, но в данном случае Nginx будет переадресовывать запросы на порт 8080, на котором и будет работать приложение

 

cd /etc/nginx

 

Удаляем конфиг сайта по-умолчанию в Nginx

rm /etc/nginx/sites-enabled/default

 

Создаем новый

mcedit /etc/nginx/sites-enabled/app.conf

server {
listen 80 default;
#server_name example.com;
root /home/vagrant/public;

}

 

Делаем символьную ссылку на конфиг проекта и перезапускаем Nginx

ln -s /home/vagrant/config/nginx.conf app

 

/etc/init.d/nginx restart

 

 

На данном этапе статика должна отдаваться, чтобы отдавался и динамический контент отредактируем конфиг Nginx задав подключение к Unicorn

 

mcedit /etc/nginx/sites-enabled/app.conf

server {
listen 80 default;
#server_name example.com;
root /home/vagrant/public;
try_files $uri/index.html $uri $uri @unicorn;
location @unicorn {
proxy_pass http://localhost:3000

}
}

 

Перезапускаем Nginx и стартуем приложение

/etc/init.d/nginx restart

 

bundle exec rails s

 

Обратившись к localhost:8080 сейчас можно увидеть полностью фракционирующее приложение, оно уже работает на связке Nginx Unicorn, хотя для продакшн такое решение пока использовать нельзя.

 

 

Добавим страницу с ошибкой сервера в конфиг.

 

mcedit /etc/nginx/sites-enabled/app.conf

server {
listen 80 default;
#server_name example.com;
root /vagrant/public;
try_files $uri/index.html $uri $uri @unicorn;
location @unicorn {
proxy_pass http://localhost:3000
}
error_page 500 502 503 504 /500.html;

}

 

 

 

Как настроить Unicorn

Предполагалось, что Unicorn уже работает, но если это не так его можно запустить раскомментировав gem 'unicorn' в Gemfile

 

Затем выполнить команду bundle  чтобы установить

bundle

 

Создаем конфигурационный файл Unicorn

 

mcedit config/unicorn.rb

working directory «vagrant»
pid «/vagrant/tmp/pids/unicorn.pid»
stderr-path «vagrant/log/unicorn.log»
stdout-path «vagrant/log/unicorn.log»

listen «/tmp/unicorn.app.sock»
worker_processes 2
timout 30

 

Вместо сокета можно указать адрес и порт.

 

Запускаем указывая конфиг с опцией -c и ключом -D чтобы сделать процесс демоном

bundle exec unicorn -c config/unicorn.rb -D

 

 

Далее определяем upstream и задаем некоторые дополнительные параметры

 

mcedit /etc/nginx/sites-enabled/app.conf

 

upstream unicorn {

server unix:/tmp/unicorn.todo.sock fail_timeout=0;
}

server {
listen 80 default deffered;
#server_name example.com;
root /home/vagrant/public;
try_files $uri/index.html $uri $uri @unicorn;
location @unicorn {

proxy-set_header X-Forwarded_for $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://unicorn;
}
error_page 500 502 503 504 /500.html;
clien_max_body_size 4G;
keepalive_timeout 10;

}

 

Перезапускаем Nginx

/etc/init.d/nginx restart

 

Далее потребуется создать инициализационный скрипт для Unicorn

Его можно скачать по адресу https://github.com/defunkt/unicorn/blob/master/examples/init.sh

mcedit config/unicorn_init.sh

 

В скрипт вносим изменения:

    • меняем APP_ROOT
    • проверяем путь к PID
    • проверяем команду CMD (в примере использовали bundler, поэтому меняем на -bundle install —binstubs, что сгенерирует директрию для бинарных файлов приложения
    • INIT_CONF удаляем;
    • по умолчанию скрипты выполняется от рута, если хотим поменять на пользователя  vagrant, тодоавляем следующий блок:

start)
sig 0 && echo >&2 «Already running» && exit 0
su -c «$CMD» — vagrant меняем в инит скрипте для всех вхождений)

 

Инициализационный скрипт после внесения коррективов должен выглядеть так:

#!/bin/sh
set -e
TIMEOUT=${TIMEOUT-60}
APP_ROOT=/vagrant
PID=$APP_ROOT/tmp/pids/unicorn.pid
CMD=»/usr/bin/unicorn -D -c $APP_ROOT/config/unicorn.rb»
INIT_CONF=$APP_ROOT/config/init.conf
UPGRADE_DELAY=${UPGRADE_DELAY-2}
action=»$1"
set -utest -f «$INIT_CONF» && . $INIT_CONFOLD=»$PID.oldbin»cd $APP_ROOT || exit 1sig () {
test -s «$PID» && kill -$1 $(cat $PID)
}oldsig () {
test -s «$OLD» && kill -$1 $(cat $OLD)
}case $action in
start)
sig 0 && echo >&2 «Already running» && exit 0
su -c «$CMD» — vagrant
;;
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»
su -c «$CMD» — vagrant
;;
upgrade)
if oldsig 0
then
echo >&2 «Old upgraded process still running with $OLD»
exit 1

ficur_pid=
if test -s «$PID»
then
cur_pid=$(cat $PID)
fiif test -n «$cur_pid» &&
kill -USR2 «$cur_pid» &&
sleep $UPGRADE_DELAY &&
new_pid=$(cat $PID) &&
test x»$new_pid» != x»$cur_pid» &&
kill -0 «$new_pid» &&
kill -QUIT «$cur_pid»
then
n=$TIMEOUT
while kill -0 «$cur_pid» 2>/dev/null && test $n -ge 0
do
printf '.' && sleep 1 && n=$(( $n — 1 ))
done
echoif test $n -lt 0 && kill -0 «$cur_pid» 2>/dev/null
then
echo >&2 «$cur_pid still running after $TIMEOUT seconds»
exit 1
fi
exit 0
fi
echo >&2 «Couldn't upgrade, starting '$CMD' instead»
su -c «$CMD» — vagrant
;;
reopen-logs)
sig USR1
;;
*)
echo >&2 «Usage: $0 <start|stop|restart|upgrade|force-stop|reopen-logs>»
exit 1
;;
esac

 

Делаем скрипт исполняемым

 

chmod +x config-unicorn/init.sh

 

Содаем символьную ссылку для того чтобы управлять Unicorn как любым другим сервисом через /etc/ini.t/SERVICENAME start|stop|restart

sudo ln -s /vagrant/config/unicorn_init.sh /etc/init.d/unicorn

Перезапускаем unicorn, vagrant, затем Nginx

sudo /etc/init.d/unicorn restart

vagrant reload

sudo /etc/init.d/nginx restart

 

С приведенным init-скриптом приложение работает в режиме DEVELOPMENT, чтобы сменить режим на PRODUCTION в конфиге нужно поправить одну строку приведя ее к виду:

scriptCMD=»/usr/bin/unicorn -D -c $APP_ROOT/config/unicorn.rb -E production»

Nginx Unicorn является самой распространенной связкой для деплоя Ruby проектов, но существуют и другие варианты — например, Unicorn с Apache