Предположим, что у вас есть физический или виртуальный сервер, на котором вы собираетесь разворачивать свое Ruby On Rails приложение. Данный процесс сопровождается несколькими небольшими, но скучными задачами, которые приходится выполнять каждый раз, а именно:
1) Получить доступ к серверу (Например, логин через SSH в командной строке);
2) Перейти в папку приложения;
3) Обновить приложение до последней версии;
4) Выполнить прекомпиляцию ресурсов, если необходимо;
5) Перезапустить приложение, если необходимо.
Есть средства, позволяющие автоматизировать данный процесс и радоваться жизни.
Более того, необходимо настроить машину так, чтобы она обладала хорошей базой данных, быстрым веб-сервером и имела какую-никакую, а защиту от несанкционированного доступа.
В данной статье приведена пошаговая инструкция настройки сервера для разворачивания (deploy) Ruby On Rails приложения и автоматизация данного процесса. В ней рассмотрено:
- Первичная настройка сервера и закрытого доступа к нему;
- Установка веб-сервера nginx и базы данных PostgreSQL;
- Установка rvm и Ruby On Rails;
- Настройка гема foreman для управления процессами приложения;
- Настройка http-сервера Unicorn;
- Настройка гема Capistrano (v3.1) для автоматизации деплоя.
Инструкция протестирована на операционных системах Ubuntu 14.04 LTS и 12.10 LTS.
Для работы с файлами на удаленном сервере я использовал текстовый редактор vim (sudo apt-get install vim).
Допустим, что у Вас есть машинка с голой Ubuntu, к которой вы подключились по SSH. Для начала сменим пароль у пользователя root командой:
Создадим нового пользователя, от лица которого будет производится деплой (Выбирайте любое имя, которое вам удобно. Я выбрал deployer, пользуясь случаем):
Изменим настройки ssh сервера (запретим логин под root, доступ по доменному имени и разрешим логин только под нашим новым пользователем).
Nginx является веб-сервером для обслуживания статических запросов и хранения статичных файлов. Он будет использоваться в связке с unicorn (сервером для динамических страниц приложения).
Загружаем плагин pagespeed:
Загружаем и устанавливаем nginx с поддержкой pagespeed:
Файл настроек nginx лежит по адресу '/usr/local/nginx/conf/nginx.conf', но пока мы его трогать не будем. Мы его зальем автоматически при первой выкладке приложения.
Если upstart скрипты на ubuntu 16 не будут работать, переключитесь с режима systemd в upstart командой sudo apt-get install upstart-sysv и перезагрузите сервер.
PostgreSQL - свободная объектно-реляционная СУБД. Про ее достоинства и недостатки вы можете почитать отдельно.
И создаем нового пользователя. Для этого входим в оболочку PostgreSQL:
ПОЛЕЗНОЕ: Так же можно поставить веб-интерфейс teampostgresql. Управляется командами:
После этого в файле id_rsa.pub будет содержаться ключ, который и следует внести в настройки.
В папке '/config/' создаем файл unicon.rb c примерно таким содержимым (ИМЯ_ПРИЛОЖЕНИЯ заменяем на имя вашего приложения. Так будет называться папка на сервере):
- Выполнит bundle install;
- Выполнит db:migrate;
- Выполнит assets:precompile;
- Создаст symlink из папки приложения в папку рабочая_папка/имя_приложения/current
В файле 'config/deploy/production.rb' делаем изменения:
Публикуем изменения на github.
Выполняем cap production deploy:setup при самом первом деплое Вашего приложения.
Выполняем cap production deploy при каждом деплое Вашего приложения.
1) Получить доступ к серверу (Например, логин через SSH в командной строке);
2) Перейти в папку приложения;
3) Обновить приложение до последней версии;
4) Выполнить прекомпиляцию ресурсов, если необходимо;
5) Перезапустить приложение, если необходимо.
Есть средства, позволяющие автоматизировать данный процесс и радоваться жизни.
Более того, необходимо настроить машину так, чтобы она обладала хорошей базой данных, быстрым веб-сервером и имела какую-никакую, а защиту от несанкционированного доступа.
В данной статье приведена пошаговая инструкция настройки сервера для разворачивания (deploy) Ruby On Rails приложения и автоматизация данного процесса. В ней рассмотрено:
- Первичная настройка сервера и закрытого доступа к нему;
- Установка веб-сервера nginx и базы данных PostgreSQL;
- Установка rvm и Ruby On Rails;
- Настройка гема foreman для управления процессами приложения;
- Настройка http-сервера Unicorn;
- Настройка гема Capistrano (v3.1) для автоматизации деплоя.
Инструкция протестирована на операционных системах Ubuntu 14.04 LTS и 12.10 LTS.
Для работы с файлами на удаленном сервере я использовал текстовый редактор vim (sudo apt-get install vim).
Первичная настройка сервера
Допустим, что у Вас есть машинка с голой Ubuntu, к которой вы подключились по SSH. Для начала сменим пароль у пользователя root командой:
passwd
Создадим нового пользователя, от лица которого будет производится деплой (Выбирайте любое имя, которое вам удобно. Я выбрал deployer, пользуясь случаем):
adduser ИМЯ_ПОЛЬЗОВАТЕЛЯ_СИСТЕМЫ
Разрешим ему пользоваться командой sudo и укажем, какие команды можно выполнять без пароля. Для этого выполняем команду:
visudo
В открывшемся файле дописываем:
ИМЯ_ПОЛЬЗОВАТЕЛЯ_СИСТЕМЫ ALL=(ALL:ALL) ALL ИМЯ_ПОЛЬЗОВАТЕЛЯ_СИСТЕМЫ ALL=NOPASSWD: /usr/sbin/service, /bin/ln, /bin/rm, /bin/mv, /sbin/start, /sbin/stop, /sbin/restart, /sbin/status
Изменим настройки ssh сервера (запретим логин под root, доступ по доменному имени и разрешим логин только под нашим новым пользователем).
Для этого добавляем в файл '/etc/ssh/sshd_config':
PermitRootLogin no UseDNS no AllowUsers ИМЯ_ПОЛЬЗОВАТЕЛЯ_СИСТЕМЫ
Перезапустим ssh сервер командой:
reload ssh
Или для Ubuntu 16:
sudo service ssh restart
Установка и настройка nginx
Оригинал статьи по установке nginx с плагином pagespeed тут.
Необходимо установить его на сервере. Для этого логинимся под новым пользователем:
ssh ИМЯ_ПОЛЬЗОВАТЕЛЯ_СИСТЕМЫ@123.123.123.123
Обновляем репозитории, систему и скачиваем необходимые для успешной сборки пакеты:
sudo apt-get update sudo apt-get install build-essential zlib1g-dev libpcre3 libpcre3-dev unzip libssl-dev
NPS_VERSION=[check the release notes for the latest version] cd wget https://github.com/pagespeed/ngx_pagespeed/archive/v${NPS_VERSION}-stable.zip unzip v${NPS_VERSION}-stable.zip cd ngx_pagespeed-${NPS_VERSION}-stable/ psol_url=https://dl.google.com/dl/page-speed/psol/${NPS_VERSION}.tar.gz [ -e scripts/format_binary_url.sh ] && psol_url=$(scripts/format_binary_url.sh PSOL_BINARY_URL) wget ${psol_url} tar -xzvf $(basename ${psol_url}) # extracts to psol/
Загружаем и устанавливаем nginx с поддержкой pagespeed:
NGINX_VERSION=[check nginx's site for the latest version] cd wget http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz tar -xvzf nginx-${NGINX_VERSION}.tar.gz cd nginx-${NGINX_VERSION}/./configure --add-module=$HOME/ngx_pagespeed-${NPS_VERSION}-stable --with-http_ssl_modulemake sudo make install
Если подключение к серверу через HTTPS не требуется, флаг --with-http_ssl_module можно упустить.
Далее создадим upstart скрипт для управления nginx. Он позволит управлять сервером командами:
Далее создадим upstart скрипт для управления nginx. Он позволит управлять сервером командами:
sudo start/stop/restart/status nginx
Для этого создаём файл '/etc/init/nginx.conf' со следующим содержимым:
description "nginx http daemon" author "George Shammas <georgyo@gmail.com>" start on (filesystem and net-device-up IFACE=lo) stop on runlevel [!2345] env DAEMON=/usr/local/nginx/sbin/nginx env PID=/var/run/nginx.pid expect fork respawn respawn limit 10 5 #oom never pre-start script $DAEMON -t if [ $? -ne 0 ] then exit $? fi end script exec $DAEMON
Для наших веб приложений мы создадим нового пользователя и новую группу, добавим себя в эту группу, и создадим папку:
sudo useradd -s /sbin/nologin -r nginx sudo groupadd web sudo usermod -a -G web nginx sudo usermod -a -G web ИМЯ_ПОЛЬЗОВАТЕЛЯ_СИСТЕМЫ sudo mkdir /var/www sudo chgrp -R web /var/www sudo chmod -R 775 /var/www
После этого разлогинтесь и войдите под вашим пользователем снова, чтобы изменения вступили в силу, а так же запустите nginx:
sudo start nginx
Установка и настройка PostgreSQL
PostgreSQL установить лучше всего как на машине сервера, так и на клиенте, чтобы разработка приложения велась на той же базе данных, на которой оно будет поддерживаться.
В репозиториях ubuntu лежит устаревшая версия, так что мы добавим сторонний репозиторий. В файл '/etc/apt/sources.list.d/pgdg.list' добавим:
Затем добавляем ключ репозитория и устанавливаем PostgreSQL:
deb http://apt.postgresql.org/pub/repos/apt/ precise-pgdg main
Затем добавляем ключ репозитория и устанавливаем PostgreSQL:
wget --quiet -O - http://apt.postgresql.org/pub/repos/apt/ACCC4CF8.asc | sudo apt-key add - sudo apt-get update sudo apt-get install postgresql-9.3 postgresql-server-dev-9.3
sudo -u postgres psql
Создаем пользователя, даем ему привилегии и выходим из оболочки (На сервере я назвал пользователя db_deployer. На клиенте создал пользователя со своим привычным именем и без пароля):
create user ИМЯ_ПОЛЬЗОВАТЕЛЯ_БД with password 'ВАШ_ПАРОЛЬ'; alter role ИМЯ_ПОЛЬЗОВАТЕЛЯ_БД superuser createrole createdb replication login; \q
Далее разрешим удаленную работу с базой данных и предоставим доступ к базе данных от лица нового пользователя. Для этого только на сервере выполняем следующее:
1) в файле '/etc/postgresql/9.3/main/postgresql.conf' изменим параметр listen_addresses = 'localhost' на listen_addresses = '*';
2) добавим в файл '/etc/postgresql/9.3/main/pg_hba.conf' строчки:
local all ИМЯ_ПОЛЬЗОВАТЕЛЯ_БД md5
host all ИМЯ_ПОЛЬЗОВАТЕЛЯ_БД 0.0.0.0/0 md5
После этого Перезагружаем postgresql командой:
sudo service postgresql restart
ЗАМЕЧАНИЕ: Если при работе с PostgreSQL на клиенте будут возникать ошибки, пропишите соответствующие разрешения и на локальной машине.
sudo teampostgresql-service start sudo teampostgresql-service stop sudo teampostgresql-service status
Установка RVM, Ruby, Rails, Bundler
Устанавливаем на сервере Ruby On Rails и все необходимые для его работы примочки. Если Rails не установлены на вашем рабочем компьютере, устанавливаем и на нем. Про это здесь:
Если Вы еще не создали Rails приложение, то про это можно почитать тут:
Для продолжения работы по данной статье у Вас должно быть в наличии приложение в минимальной конфигурации, ибо что-то нужно разворачивать на сервере.
Создаем репозиторий на github
Мы будем использовать удаленный репозиторий git для разворачивания приложения. На сервере будет происходить загрузка последней версии приложения именно с него. Если у вас нет клиента git, его можно установить командой:
apt-get install git
Для удаленного хранения я использую сервис github. Регистрируемся, создаем репозиторий в сервисе, запоминаем его адрес.
Далее, создаем репозиторий в папке проекта:
git init
Добавляем адрес репозитория (Будет указан во время его создания):
git remote add origin АДРЕС_РЕПОЗИТОРИЯ
Но не спешим заливать на него наше приложение!
Для начала нужно отредактировать файл .gitignore, чтобы конфиденциальная информация и лишние файлы не попали в репозиторий. Добавляем в него строчки:
/config/database.yml # доступ к базе данным /Procfile # про него я еще расскажу /config/deploy/ # файлы Capistrano /shared/ # файлы, которых нет в репозитории, но они будут скопированы на сервер при первом деплое приложения
Теперь фиксируем изменения и производим их публикацию на github:
git add -A
git commit -m 'first commit'
git push -u origin master
Так же нужно добавить публичный ключ сервера в настройки github репозитория. Для этого, подключившись к серверу по ssh производим следующее:
chmod 700 ~/.ssh
cd ~/.ssh
ssh-keygen
После этого в файле id_rsa.pub будет содержаться ключ, который и следует внести в настройки.
Установка и первоначальная настройка гема foreman
Данный гем позволяет управлять запуском потоков приложения. Если ваше приложение является многопоточным (например, главный поток, и поток отложенных задач), то они оба должны быть запущены со стартом приложения. Foreman можно настроить так, чтобы оба этих потока запускались всего лишь одной командой - foreman start. Стоит всего лишь прописать их в Procfile, находящийся в корне приложения. Более того, имеется возможность создать upstart скрипт (командой foreman export upstart), чтобы приложением можно было управлять командами start/stop/status/restart ИМЯ_ПРИЛОЖЕНИЯ, а так же запуск потоков происходил автоматически со стартом компьютера.
Добавляем строчку в Gemfile:
gem 'foreman', '0.63.0'
И выполняем:
bundle install bundle update
Я использую статичную версию гема, так как от версии к версии происходит множество изменений, которые могут отразиться на работоспособности приложения. Тестировал создание upstart скриптов на версии 0.74.0. После половины дня геморроя вернулся на версию 0.63.0, и все сразу заработало.
В корне приложения создаем файл Procfile в котором прописываем, какие процессы необходимо запустить со стартом приложения:
web: rails s worker: bundle exec rake jobs:work
Я использую гем delayed_job для отложенных заданий, по-этому запускаю для него дополнительный поток. Если у вас такого нет, то можете обойтись только первой строчкой, запускающей приложение.
Позже мы напишем Production конфигурацию Procfile, для запуска приложения на сервере.
Установка Unicorn
Unicorn - это продвинутый http сервер для обработки множества http запросов и работы с динамическими страницами. Если nginx занимается обработкой и хранением статических файлов, то Unicorn необходим для взаимодействия с базой данных через Rack интерфейс и работы с динамическими страницами.
Установим его, добавив строчки в Gemfile:
group :production do gem 'unicorn' end
После чего не забудьте про bundle install
# Устанавливаем количество процессов на сервере (Чем больше поток пользователей, тем больше нужно процессов) worker_processes Integer(ENV["WEB_CONCURRENCY"] || 3) working_directory "/var/www/apps/ИМЯ_ПРИЛОЖЕНИЯ/current" # available in 0.94.0+ # Слушаем Unix domain socket и TCP порт listen "/var/www/apps/ИМЯ_ПРИЛОЖЕНИЯ/socket/.unicorn.sock", :backlog => 64 listen 8080, :tcp_nopush => true # уничтожаем workers после 30 секунд вместо 60 дефолтных timeout 30 # Устанавливаем путь к PID файлу главного процесса unicorn pid "/var/www/apps/ИМЯ_ПРИЛОЖЕНИЯ/run/unicorn.pid" # Направляем потоки вывода stderr_path "/var/www/apps/ИМЯ_ПРИЛОЖЕНИЯ/log/unicorn.stderr.log" stdout_path "/var/www/apps/ИМЯ_ПРИЛОЖЕНИЯ/log/unicorn.stdout.log" # Подгружаем приложение в память до того, как произойдет форк процессов. (Типа для memory savings) preload_app true GC.respond_to?(:copy_on_write_friendly=) and GC.copy_on_write_friendly = true #При включенной опции юникорн проверяет соединения клиентов, записывая начало #хедера HTTP запроса до того, как он вызовется приложением. Это #предотвращает вызов приложения для соединений, которые были отключены от очереди. #Это лишь гарантирует определение клиентов на том же хосте, что и юникорн. check_client_connection false before_fork do |server, worker| # Следующее особенно рекомендовано для Rails + "preload_app true" # as there's no need for the master process to hold a connection defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect! # The following is only recommended for memory/DB-constrained # installations. It is not needed if your system can house # twice as many worker_processes as you have configured. # # # This allows a new master process to incrementally # # phase out the old master process with SIGTTOU to avoid a # # thundering herd (especially in the "preload_app false" case) # # when doing a transparent upgrade. The last worker spawned # # will then kill off the old master process with a SIGQUIT. 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 # # Throttle the master from forking too quickly by sleeping. Due # to the implementation of standard Unix signal handlers, this # helps (but does not completely) prevent identical, repeated signals # from being lost when the receiving process is busy. # sleep 1 end after_fork do |server, worker| # per-process listener ports for debugging/admin/migrations # addr = "127.0.0.1:#{9293 + worker.nr}" # server.listen(addr, :tries => -1, :delay => 5, :tcp_nopush => true) # the following is *required* for Rails + "preload_app true", defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection # if preload_app is true, then you may also want to check and # restart any other shared sockets/descriptors such as Memcached, # and Redis. TokyoCabinet file handles are safe to reuse # between any number of forked children (assuming your kernel # correctly implements pread()/pwrite() system calls) end
Установка Capistrano
Capistrano - средство, позволяющее одной командой выполнить огромное количество операций на удаленном сервере, связанных с разворачиванием приложения. Необходимо лишь прописать их в скрипте Capistrano.
Capistrano скрипт будет выполнять некоторые команды от имени суперпользователя на сервере. Чтобы разрешить ему делать это, выполняем команду на сервере:
sudo visudo
и добавляем строчку:
ИМЯ_ПОЛЬЗОВАТЕЛЯ_СИСТЕМЫ ALL=NOPASSWD: /usr/sbin/service, /bin/ln, /bin/rm, /bin/mv, /sbin/start, /sbin/stop, /sbin/restart, /sbin/status
Установим Capistrano, добавив в Gemfile несколько строчек, и выполнив bundle update, bundle install:
group :development do gem 'capistrano', '3.1.0' gem 'capistrano-rails' gem 'capistrano-bundler' gem 'capistrano-rvm' end
Здесь я так же использовал статичную версию гема, чтобы не было проблем после его обновления.
Выполняем команду:
bundle exec cap install
В созданном файле Capfile добавляем:
require 'capistrano/deploy' require 'capistrano/rvm' require 'capistrano/bundler' require 'capistrano/rails'
Теперь, если указать в настройках Capistrano адрес сервера, репозитория и рабочую папку, то он одной командой:
- Загрузит ваше приложение из репозитория на сервер в папку рабочая_папка/имя_приложения/releases/дата_релиза/, не удаляя старую версию (по умолчанию он хранит 5 последних версий приложений);- Выполнит bundle install;
- Выполнит db:migrate;
- Выполнит assets:precompile;
- Создаст symlink из папки приложения в папку рабочая_папка/имя_приложения/current
Почти все, что нам надо. Однако, еще необходимо произвести настройку nginx, unicorn и foreman при первом деплое, а так же запускать unicorn при каждом последующем.
Файлы настроек для сервера
Файлы настроек, которые необходимо загрузить на сервер, будем хранить в папке shared (в папке проекта на локальной машине). Для этого мы добавили ее в .gitignore.
Сначала создадим там nginx.conf примерно с таким содержимым:
Если нужно подключение через HTTPS, воспользуйтесь Let's Encrypt и данной статьей:
https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-14-04
ВНИМАНИЕ! Если вы хотите, чтобы сервер работал как по HTTP, так и по HTTPS, все серверные настройки в файле nginx.conf должны находиться внутри одного блока server {}, а не в разных, как указано в статье по ссылке.
Теперь создаем Production конфигурацию Procfile в папке shared:
Там же создаём database.yml с настройками базы данных для сервера:
Сначала создадим там nginx.conf примерно с таким содержимым:
user nginx web; # В этот файл пишем pid процесса pid /var/run/nginx.pid; # Ошибки выводим сюда error_log /var/www/log/nginx.error.log; events { worker_connections 1024; # increase if you have lots of clients accept_mutex off; # "on" if nginx worker_processes > 1 use epoll; # enable for Linux 2.6+ # use kqueue; # enable for FreeBSD, OSX } http { # nginx will find this file in the config directory set at nginx build time include mime.types; types_hash_max_size 2048; server_names_hash_bucket_size 64; # fallback in case we can't determine a type default_type application/octet-stream; # click tracking! access_log /var/www/log/nginx.access.log combined; # you generally want to serve static files with nginx since neither # Unicorn nor Rainbows! is optimized for it at the moment sendfile on; tcp_nopush on; # off may be better for *some* Comet/long-poll stuff tcp_nodelay off; # on may be better for some Comet/long-poll stuff # we haven't checked to see if Rack::Deflate on the app server is # faster or not than doing compression via nginx. It's easier # to configure it all in one place here for static files and also # to disable gzip for clients who don't get gzip/deflate right. # There are other gzip settings that may be needed used to deal with # bad clients out there, see http://wiki.nginx.org/NginxHttpGzipModule gzip on; gzip_http_version 1.0; gzip_proxied any; gzip_min_length 0; gzip_vary on; gzip_disable "MSIE [1-6]\."; gzip_proxied expired no-cache no-store private auth; gzip_comp_level 9; gzip_types text/plain text/xml text/css text/comma-separated-values text/javascript application/x-javascript application/atom+xml; # this can be any application server, not just Unicorn/Rainbows! upstream app_server { server unix:/var/www/apps/ИМЯ_ПРИЛОЖЕНИЯ/socket/.unicorn.sock fail_timeout=0; } server { # PageSpeed pagespeed on; pagespeed FileCachePath /var/ngx_pagespeed_cache; location ~ "\.pagespeed\.([a-z]\.)?[a-z]{2}\.[^.]{10}\.[^.]+" { add_header "" ""; } location ~ "^/ngx_pagespeed_static/" { } location ~ "^/ngx_pagespeed_beacon$" { } location /ngx_pagespeed_statistics { allow 127.0.0.1; allow 5.228.169.73; deny all; } location /ngx_pagespeed_global_statistics { allow 127.0.0.1; allow 5.228.169.73; deny all; } pagespeed MessageBufferSize 100000; location /ngx_pagespeed_message { allow 127.0.0.1; allow 5.228.169.73; deny all; } location /pagespeed_console { allow 127.0.0.1; allow 5.228.169.73; deny all; } charset utf-8; # enable one of the following if you're on Linux or FreeBSD listen 80 default deferred; # for Linux # listen 80 default accept_filter=httpready; # for FreeBSD # If you have IPv6, you'll likely want to have two separate listeners. # One on IPv4 only (the default), and another on IPv6 only instead # of a single dual-stack listener. A dual-stack listener will make # for ugly IPv4 addresses in $remote_addr (e.g ":ffff:10.0.0.1" # instead of just "10.0.0.1") and potentially trigger bugs in # some software. # listen [::]:80 ipv6only=on; # deferred or accept_filter recommended client_max_body_size 4G; server_name _; # ~2 seconds is often enough for most folks to parse HTML/CSS and # retrieve needed images/icons/frames, connections are cheap in # nginx so increasing this is generally safe... keepalive_timeout 5; # path for static files root /var/www/apps/ИМЯ_ПРИЛОЖЕНИЯ/current/public; # Prefer to serve static files directly from nginx to avoid unnecessary # data copies from the application server. # # try_files directive appeared in in nginx 0.7.27 and has stabilized # over time. Older versions of nginx (e.g. 0.6.x) requires # "if (!-f $request_filename)" which was less efficient: # http://bogomips.org/unicorn.git/tree/examples/nginx.conf?id=v3.3.1#n127 try_files $uri/index.html $uri.html $uri @app; location ~ ^/(assets)/ { root /var/www/apps/ИМЯ_ПРИЛОЖЕНИЯ/current/public; expires max; add_header Cache-Control public; } location @app { # an HTTP header important enough to have its own Wikipedia entry: # http://en.wikipedia.org/wiki/X-Forwarded-For proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # enable this if you forward HTTPS traffic to unicorn, # this helps Rack set the proper URL scheme for doing redirects: # proxy_set_header X-Forwarded-Proto $scheme; # pass the Host: header from the client right along so redirects # can be set properly within the Rack application proxy_set_header Host $http_host; # we don't want nginx trying to do something clever with # redirects, we set the Host: header above already. proxy_redirect off; # set "proxy_buffering off" *only* for Rainbows! when doing # Comet/long-poll/streaming. It's also safe to set if you're using # only serving fast clients with Unicorn + nginx, but not slow # clients. You normally want nginx to buffer responses to slow # clients, even with Rails 3.1 streaming because otherwise a slow # client can become a bottleneck of Unicorn. # # The Rack application may also set "X-Accel-Buffering (yes|no)" # in the response headers do disable/enable buffering on a # per-response basis. # proxy_buffering off; proxy_pass http://app_server; } # Rails error pages error_page 500 502 503 504 /500.html; location = /500.html { root /var/www/apps/ИМЯ_ПРИЛОЖЕНИЯ/current/public; } } }
Только что Вы создали файл настроек веб-сервера nginx. ИМЯ_ПРИЛОЖЕНИЯ смените на имя, которое вы указали в unicorn.rb
Если нужно подключение через HTTPS, воспользуйтесь Let's Encrypt и данной статьей:
https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-14-04
ВНИМАНИЕ! Если вы хотите, чтобы сервер работал как по HTTP, так и по HTTPS, все серверные настройки в файле nginx.conf должны находиться внутри одного блока server {}, а не в разных, как указано в статье по ссылке.
Теперь создаем Production конфигурацию Procfile в папке shared:
web: bundle exec unicorn_rails -c /var/www/apps/ИМЯ_ПРИЛОЖЕНИЯ/current/config/unicorn.rb -E production worker: RAILS_ENV=production bundle exec rake jobs:work
Повторюсь, если вы не используете delayed_job, вам будет достаточно только первой строчки.
production: adapter: postgresql encoding: unicode database: ИМЯ_ПРИЛОЖЕНИЯ_production pool: 5 username: ИМЯ_ПОЛЬЗОВАТЕЛЯ_БД password: ПАРОЛЬ_ПОЛЬЗОВАТЕЛЯ_БД
Осталось настроить Capistrano и написать скрипт для разворачивания приложения.
Настройка Capistrano
role :app, %w{ИМЯ_ПОЛЬЗОВАТЕЛЯ_СИСТЕМЫ@IP_АДРЕС_СЕРВЕРА} role :web, %w{ИМЯ_ПОЛЬЗОВАТЕЛЯ_СИСТЕМЫ@IP_АДРЕС_СЕРВЕРА} role :db, %w{ИМЯ_ПОЛЬЗОВАТЕЛЯ_СИСТЕМЫ@IP_АДРЕС_СЕРВЕРА} server 'ИМЯ_ПОЛЬЗОВАТЕЛЯ_СИСТЕМЫ@IP_АДРЕС_СЕРВЕРА', user: 'ИМЯ_ПОЛЬЗОВАТЕЛЯ_СИСТЕМЫ', password: 'ПАРОЛЬ_ПОЛЬЗОВАТЕЛЯ_СИСТЕМЫ', roles: %w{web app db}, my_property: :my_value
Это необходимо для того, чтобы Capistrano знал, на каком сервере разворачивать приложение, и как получить к нему доступ. Данный файл занесен в .gitignore, так как это конфиденциальная информация.
Теперь редактируем файл 'config/deploy.rb'. Это собственно и есть скрипт, который будет выполняться при разворачивании приложения. Он должен выглядеть примерно так:
# config valid only for Capistrano 3.1 lock '3.1.0' set :application, 'ИМЯ_ПРИЛОЖЕНИЯ' set :deploy_to, '/var/www/apps/ИМЯ_ПРИЛОЖЕНИЯ' set :deploy_via, :copy set :scm, :git set :repo_url, 'git@github.com:ПОЛЬЗОВАТЕЛЬ_ГИТХАБА/ИМЯ_ПРИЛОЖЕНИЯ.git' set :branch, 'master' application = 'ИМЯ_ПРИЛОЖЕНИЯ' set :rvm_type, :user set :rvm_ruby_version, '2.0.0-p481' #set :port, 2222 namespace :foreman do desc 'Start server' task :start do on roles(:all) do sudo "start #{application}" end end desc 'Stop server' task :stop do on roles(:all) do sudo "stop #{application}" end end desc 'Restart server' task :restart do on roles(:all) do sudo "restart #{application}" end end desc 'Server status' task :status do on roles(:all) do execute "initctl list | grep #{application}" end end end namespace :git do desc 'Deploy' task :deploy do ask(:message, "Commit message?") run_locally do execute "git add -A" execute "git commit -m '#{fetch(:message)}'" execute "git push origin master" end end end # Default branch is :master # ask :branch, proc { `git rev-parse --abbrev-ref HEAD`.chomp } # Default deploy_to directory is /var/www/my_app # set :deploy_to, '/var/www/my_app' # Default value for :scm is :git # set :scm, :git # Default value for :format is :pretty # set :format, :pretty # Default value for :log_level is :debug # set :log_level, :debug # Default value for :pty is false # set :pty, true # Default value for :linked_files is [] # set :linked_files, %w{config/database.yml} # Default value for linked_dirs is [] # set :linked_dirs, %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system} # Default value for default_env is {} # set :default_env, { path: "/opt/ruby/bin:$PATH" } # Default value for keep_releases is 5 # set :keep_releases, 5 namespace :deploy do desc 'Setup' task :setup do on roles(:all) do execute "mkdir #{shared_path}/config/" execute "mkdir /var/www/apps/#{application}/run/" execute "mkdir /var/www/apps/#{application}/log/" execute "mkdir /var/www/apps/#{application}/socket/" execute "mkdir /var/www/log/" execute "mkdir /var/www/log/upstart/" execute "mkdir #{shared_path}/system" sudo "ln -s /var/log/upstart /var/www/log/upstart" upload!('shared/database.yml', "#{shared_path}/config/database.yml") upload!('shared/Procfile', "#{shared_path}/Procfile") upload!('shared/nginx.conf', "#{shared_path}/nginx.conf") sudo 'stop nginx' sudo "rm -f /usr/local/nginx/conf/nginx.conf" sudo "ln -s #{shared_path}/nginx.conf /usr/local/nginx/conf/nginx.conf" sudo 'start nginx' within release_path do with rails_env: fetch(:rails_env) do execute :rake, "db:create:all" end end end end desc 'Create symlink' task :symlink do on roles(:all) do execute "ln -s #{shared_path}/config/database.yml #{release_path}/config/database.yml" execute "ln -s #{shared_path}/Procfile #{release_path}/Procfile" execute "ln -s #{shared_path}/system #{release_path}/public/system" end end desc 'Foreman init' task :foreman_init do on roles(:all) do foreman_temp = "/var/www/tmp/foreman" execute "mkdir -p #{foreman_temp}" # Создаем папку current для того, чтобы foreman создавал upstart файлы с правильными путями execute "ln -s #{release_path} #{current_path}" within current_path do execute "cd #{current_path}" execute :bundle, "exec foreman export upstart #{foreman_temp} -a #{application} -u ИМЯ_ПОЛЬЗОВАТЕЛЯ_СИСТЕМЫ -l /var/www/apps/#{application}/log -d #{current_path}" end sudo "mv #{foreman_temp}/* /etc/init/" sudo "rm -r #{foreman_temp}" end end desc 'Restart application' task :restart do on roles(:app), in: :sequence, wait: 5 do sudo "restart #{application}" end end after :finishing, 'deploy:cleanup' after :finishing, 'deploy:restart' after :updating, 'deploy:symlink' after :setup, 'deploy:foreman_init' after :foreman_init, 'foreman:start' before :foreman_init, 'rvm:hook' before :setup, 'deploy:starting' before :setup, 'deploy:updating' before :setup, 'bundler:install' after :publishing, :restart after :restart, :clear_cache do on roles(:web), in: :groups, limit: 3, wait: 10 do # Here we can do anything such as: # within release_path do # execute :rake, 'cache:clear' # end end end end #before :deploy, 'git:deploy'
Данный скрипт, помимо стандартных умений Capistrano, загрузит на сервер файлы из папки shared, настроит nginx, unicorn, создаст upstart скрипт foreman для легкого запуска приложения.
Можете самостоятельно разобраться в этом файле, синтаксис довольно простой. Главное замените ИМЯ_ПРИЛОЖЕНИЯ на имя вашего приложения, введите адрес репозитория, а так же ИМЯ_ПОЛЬЗОВАТЕЛЯ_СИСТЕМЫ на имя пользователя на сервере, под которым производится деплой.
И так, все готово! Не прошло и пол года)
Как производить деплой
Публикуем изменения на github.
Выполняем cap production deploy:setup при самом первом деплое Вашего приложения.
Выполняем cap production deploy при каждом деплое Вашего приложения.
Спасибо за внимание)
За основу была взята статья:
http://habrahabr.ru/post/213269/
Код подсвечен сервисом http://hilite.me/
За основу была взята статья:
http://habrahabr.ru/post/213269/
Код подсвечен сервисом http://hilite.me/