Ruby on Rails. C локального хоста на VDS за 15 минут

Доброго времени суток, хабровчане!

Как переехать на VDS за 15 минут и не углубляться в изучение nginx, unicorn и capistrano. Пошаговая инструкция под катом.

Я постоянно слышу от многих своих знакомых программистов PHP, что они не хотят переходить на рельсы только из-за того, что нет адекватного и дешевого хостинга с нормальной панелью управления. На самом деле вопрос где хостится, если пишешь на рельсах, поднимался уже раз сто на хабре, именно поэтому я об этом и не буду говорить. Когда я первый раз делал проект на рельсах я столкнулся с поиском хостера, но дело даже не в этом, главное было для меня это нетрудоемкий процесс запуска приложения на хостинге. Я решил приобрести себе VDS и использовать его в качестве тестового сервера. Процесс настройки и подготовки VDS был усложнен тем, что я не нашел инструкции от А до Я, а так как я, грубо говоря, не блистал знаниями в настроке не только VDS но и nginx и unicorn и много чего еще. Мне не нужны были конфиги в 200 строк и жутко замороченные настройки для высоконагруженных приложений, моей задачей было просто запустить сайт за минимум денег и времени и отдать его заказчику вместе с этим VDS. В этой статье я хочу написать именно ту инструкцию, которая так была мне нужна, надеюсь, что она будет полезна многим начинающим писать на рельсах и послужит, возможно, дополнительным стимулом для тех PHP программистов, кто все еще сомневается и продолжает юзать фреймворки, которые копируют функционал и фишки Ruby On Rails. Мне кажется это тоже самое, что ставить движок от мерседеса в копейку. Вроде резвенько, но что все равно не то.

Итак, приступим

Что вы должны иметь для начала:
  • Купленный и работающий VDS c любой системой Debian семейства
  • Купленный домен у любого регистратора

Для справки: все действия, в моем случае, выполняются на VDS с Ubuntu Server 11.10.

Установка и настройка nginx

Заходим на машину по ssh через терминал:
:~ ssh root@<ip машины>

Ставим nginx из репозитория:
:~ apt-get install nginx

Создаем директорию для конфигов наших приложений, вдруг их будет несколько:
:~ mkdir /etc/nginx/sites

Пишем конфиг для первого приложения. Я использую vim, но это дело вкуса, можно использовать хоть стандартный nano:
:~ vi /etc/nginx/sites/first_app.conf

Пишем сюда следующее содержимое:
server {
listen 80;
# Имя сервера это то, что будет запускаться.
# Некоторые провайдеры генерируют случайное доменное имя, если это ваш случай, то пишем его сюда.
server_name first_app.com;
root /home/first_app/web-app/public;
client_max_body_size 32m;
location / {
try_files $uri @unicorn;
}
location @unicorn {
proxy_set_header Client-Ip $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_pass unix:/home/first_app/web-app/tmp/sockets/unicorn.sock;
}
}


Теперь редактируем кофиг самого сервера nginx. Ниже приведен полный файл конфига:
user nobody nogroup;
worker_processes 4;
pid /var/run/nginx.pid;

events {
worker_connections 4096;
# multi_accept on;
}

http {

##
# Basic Settings
##

sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# server_tokens off;

# server_names_hash_bucket_size 64;
# server_name_in_redirect off;

include /etc/nginx/mime.types;
default_type application/octet-stream;

##
# Logging Settings
##

log_format main '$remote_addr - $remote_user[$time_local] "$request"'
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "http_x_forwarded_for"'

access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;

##
# Gzip Settings
##

gzip on;
gzip_disable "msie6";

# gzip_vary on;
gzip_proxied any;
# gzip_comp_level 6;
# gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;

##
# Virtual Host Configs
##

include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites/*.conf;
}

#mail {
# # See sample authentication script at:
# # wiki.nginx.org/ImapAuthenticateWithApachePhpScript
#
# # auth_http localhost/auth.php;
# # pop3_capabilities "TOP" "USER";
# # imap_capabilities "IMAP4rev1" "UIDPLUS";
#
# server {
# listen localhost:110;
# protocol pop3;
# proxy on;
# }


Теперь нам надо, чтобы nginx запускался автоматически при запуске VDS. Для этого устанавливаем супервайзер runit:
:~ apt-get install runit
:~ mkdir /etc/sv/nginx

Создадим исполняемый файл для запуска nginx:
:~ vi /etc/sv/nginx/run

И напишем туда вот что:
#!/bin/sh
exec 2>&1
exec /usr/sbin/nginx

Делаем его исполняемым:
:~ chmod +x /etc/sv/nginx/run

Проверим заработало ли все это дело:
:~ /etc/sv/nginx/run
:~ ps aux | grep nginx


Если все хорошо вы увидете 4 запущенных worker_process и сервер nginx. Проблемы могут возникнуть только в том случае если на VDS по-умолчанию был установлен Apache. Так было у меня, что естественно означает занятый 80 порт. Смело сносите Apache и убивайте все его процессы. Надеюсь, что у вас все хорошо и мы продолжим. Осталось сделать симлинк для автоматического запуска:
:~ ln -s /etc/sv/nginx/ /etc/service

Поздравляю nginx утановлен и настроен. На все про все при должной снаровке уйдет минуты 2. Нужно еще создать пользователя, из-под которого будет запускаться приложение:
:~ adduser first_app
:~ vi home/itnotes/.bashrc


Дописываем в этот файл:
export RAILS_ENV=production

Установка RVM и RubyGems

В том же терминале продолжаем:
:~ apt-get install curl
:~ bash -s stable < <(curl -s raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer)
:~ apt-get install build-essential bison openssl libreadline6 libreadline6-dev zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-0 libsqlite3-dev sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev ncurses-dev
:~ gpasswd -a first_app rvm
:~ apt-get install rubygems
:~ rvm use --create ruby-1.9.2-p318@first_app
:~ rvm ruby-1.9.2-p318@global gem install bundler
:~ mkdir /home/first_app/web-app
:~ apt-get install git-core git-gui git-doc


Здесь мы устанавливаем curl, затем с его помощь ставим rvm, доставляем пачку пакетов, которые пригодятся для компиляции Ruby, работы sqlite и т.д. После этого ставим Rubygems, создаем гемсет для нашего проекта, утанавливаем bundler для всех проектов и создаем папку для нашего приложения в home директории созданного нами пользователя. Устанавливаем Git.
Выходим из рута, завершаем ssh.

Установка Ruby

Заходим под созданным пользоватлем по ssh:
:~ ssh first_app@<IP машины>
:~ rvm install ruby-1.9.2-p318

Выходим и снова заходим под рутом.

БД, Capistrano и Unicorn

В подавляющем большинстве случаев в качестве бд используется mysql, но знаете, мое личное мнение таково, что если проект не большой, а так себе сайтик чего там делает, то не стоит ему юзать такую бд, ему вполне хватит и sqlite. Кроме того, мы сэкономими еще кучу времени. Переехать потом на mysql, если такое вообще понадобится, можно произвести без особых проблем. Поэтому мы не будем настраивать никаких субд, а сразу перейдем к Capistrano.
Допишите в Gemfile приложения:
group :development do
...
gem 'capistrano-deploy', '~> 0.1.1', :require => nil
end
group :production do
...
gem 'unicorn', '~> 3.6.2', :require => nil
end


Создайте в корне проекта Capfile со следующим содержимым:
$:.unshift(File.expand_path('./lib', ENV['rvm_path']))
require "rvm/capistrano"
set :rvm_ruby_string, '1.9.2'

require 'capistrano-deploy'
use_recipes :git, :rails, :bundle, :unicorn

server '<IP машины>', :web, :app, :db, :primary => true
set :user, 'first_app'
set :deploy_to, '/home/first_app/web-app'
set :repository, 'git@github.com:<репозиторий>'

after 'deploy:update', 'bundle:install'
after 'deploy:restart', 'unicorn:stop'


Тут есть маленький нюанс, если у вас как и у меня git репозиторий находится на github, то надо не забыть из под созданного юзера на VDS сгенерировать rsa ключи. Как это сделать подробно написано на github.com.

В терминале пишем:
:~ mkdir /etc/sv/first_app_unicorn
:~ touch /etc/sv/first_app_unicorn/run
:~ chmod +x /etc/sv/first_app_unicorn/run
:~ vi /etc/sv/first_app_unicorn/run


Пишем в этот файлик вот это:
#!/bin/sh
exec 2>&1
export USER=first_app
export HOME=/home/$USER
export RAILS_ENV=production
UNICORN="/usr/local/rvm/bin/rvm ruby-1.9.2-p318@first_app exec bundle exec unicorn"
UNICORN_CONF=/etc/unicorn/first_app.rb
cd $HOME/web-app
exec chpst -u $USER:$USER $UNICORN -c $UNICORN_CONF


Далее заполняем файл /etc/unicorn/first_app.rb вот этим:
worker_processes 4
working_directory "/home/first_app/web-app"
listen "/home/first_app/web-app/tmp/sockets/unicorn.sock", :backlog => 64
pid "/home/first_app/web-app/tmp/pids/unicorn.pid"
stderr_path "/home/first_app/web-app/log/unicorn.stderr.log"
stdout_path "/home/first_app/web-app/log/unicorn.stdout.log"


Последний рывок:
ln -s /etc/sv/first_app_unicorn /etc/service

Настройка домена

Необходимо добавить 2 записи А типа: для субдомена @ и www, с указанием IP вашего VDS. Хорошо бы это сделать до настройки сервера, тогда пока вы все настроите изменения вступят в силу.

Идем делаем бутерброды и запускаем в браузере.

Заключение

Для быстрого обновления мелких изменений на сайте я создал такой файлик в корне приложения:
git add .
git commit -a -m "Release"
git push
cap deploy:update
cap deploy:restart


Назвал его deploy и сделал его исполняемым. Теперь чтобы обновить сайт на github и VDS требуется всего одна команда:
:~ ./deploy
Поделиться публикацией
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама
Комментарии 22
  • 0
    Было бы классно, если бы Вы еще расписали как настроить ssh на VDS для Ruby on Rails?
    • 0
      Чего-то я не понял вопроса. Вроде как VDS доступен по ssh без каких либо дополнительных теложвижений. Не сталкивался с отсутсвием ssh на сервере.
      • 0
        простите — опечатался — доступ по https (SSL)
        • 0
          Теперь понял. Если есть такая потребность, то обязательно напишу в ближайшее время.
          • 0
            Никаких проблем:

            server {
            listen 443;
            server_name <ВАШ_ДОМЕН или *.ВАШ_ДОМЕН>;
            ssl on;
            ssl_certificate <ПУТЬ_К_ВАШЕМУ.crt>;
            ssl_certificate_key <ПУТЬ_К_ВАШЕМУ.key>;
            }
            Это настройка конфига
      • +1
        >apt-get install rubygems

        после установки rvm это лишнее
        • 0
          Так оно так. Не могу сказать сейчас почему, но именно эта строчка меня спасла, однажды, как бы не удвительно это было.
        • +1
          а почему не chef?
          • +2
            railscasts.com/episodes/335-deploying-to-a-vps правда для pro аккаунта.
            • –3
              Вот они жмоты, нужные уроки только за бабло. А платить за месяц ради того чтобы посмотреть одно видео как то не хочется.
              • 0
                В месяц выходит минимум 4 pro-ролика и стоит это каких-то $9, практически все pro-ролики полезные и очень понятно объясняются. На самообразовании экономить глупо и в долгосрочной перспективе — убыточно. Инвестиции в знания дают самые лучшие дивиденды ;)

                Кстати говоря, последние ролики по деплою стоили пожалуй даже всех предыдущих оплаченных месяцев, очень классные практики показаны.
            • 0
              Извините, но после прочтения поста возникло какое то странное чувство негодования.
              • 0
                что-то вы накрутили с супервайзером runit. После установки nginx из пакета мы имеем инитскрипт /etc/init.d/nginx
                Который автоматом прописан c помощью update-rc.d. Если компилировать nginx, то тогда нужно самому писать этот скрипт и делать update-rc.d nginx default. И ненужен никакой супервайзер.
                • 0
                  1) Для задачи «собрать не заморачиваясь с настройками и администрированием» вполне подошел бы nginx + passenger. Ставится легко и никаких дополнительных серверов в виде Unicorn. А так как необходимость в нем отпадает, то и runit не нужен будет.
                  2) Смысл ставить rvm? Если подразумевается что это production сервер, то вряд ли там будет более одной версии Ruby, поэтому можно спокойно оставлять связку ruby + bundler

                  Итого вся инструкция может изрядно сократиться, ИМХО.
                  • 0
                    1) и бэкенд сервером будет не unicorn, а passenger, в чем профит?
                    2) на production могут быть проекты с разными версиями ruby
                    • 0
                      1) минус одно звено в виде runit,
                      2) рассматривал конкретно этот случай, так понял автор отдает сайт + VDS => другого там ничего не будет (скорее всего)
                      Просто я к тому, что можно было конечную схему упростить. Но тут опять же, нужно смотреть по итоговой производительности на конкретной задаче.
                  • 0
                    За 15 минут разве можно вложится с такими плясками? А если еще Rails 3 и ассеты нужно компилить? Вот на хероку, например, можно
                    • 0
                      на хероку дорого и файловая система рид онли.
                      • 0
                        на S3 сохраняйте ассеты и файлы с upload
                    • 0
                      Хм,
                      ** [myserver.com :: err] tput:
                      ** [myserver.com :: err] No value for $TERM and no -T specified
                      ** [myserver.com :: err]


                      pastebin.com/6aBWuDA1

                      Правда конфигурация несколько отличается от вашей…
                      • 0
                        rvm get head исправил ситуацию
                      • 0
                        Ещё пару таких статей и я напишу свою «Антипаттерны установки Rails на VDS».

                        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.