How to setup rails, puma and nginx
Let’s suppose we have VPS server with ubuntu installed, we have developed a rails application that is ready to be deployed. We want to run the app in production mode.
At the end of this tutorial we will have the app that uses puma and revealed to the world via nginx.
Let’s start!
Make sure you have installed following packages on VPS:
sudo apt-get install gcc g++ make libssl-dev sqlite3 libsqlite3-dev libpq-dev postgresqlOpen Gemfile and add following gems:
group :development do
gem 'capistrano', '~> 3.8'
gem 'capistrano-lets-encrypt'
gem 'capistrano-rbenv', '~> 2.0'
gem 'capistrano3-puma'
gem 'capistrano-rails'
gem 'sshkit-sudo'
endGenerate capistrano files:
$ bundle exec cap install
mkdir -p config/deploy
create config/deploy.rb
create config/deploy/staging.rb
create config/deploy/production.rb
mkdir -p lib/capistrano/tasks
create Capfile
CapifiedUncomment and add these lines in Capfile:
require "capistrano/rbenv"
require "capistrano/rails/assets"
require "capistrano/rails/migrations"
require "capistrano/bundler"
require 'capistrano/puma'
require 'capistrano/puma/jungle'
require 'capistrano/puma/workers'
require 'capistrano/puma/nginx'
require 'capistrano/lets-encrypt'
require 'sshkit/sudo'Now trarget capistrano to your VPS server with editing of config\deploy\production.rb:
server 'www.my_server.com', user: 'my_vps_login', roles: %w[app db web], primary: true
set :lets_encrypt_domains, 'www.my_server.com'Nice. Now we need to edit config\deploy.rb file. Please add these lines:
set :application, "my_app"
set :repo_url, "git@github.com:login/my_app.git"
set :branch, :master
set :deploy_to, '/home/my_vps_login/projects/my_app'
append :linked_files, "puma.conf"
append :linked_dirs, 'log', 'tmp/pids', 'tmp/cache', 'tmp/puma', 'tmp/sockets', 'public/system', 'certs'
set :rails_env, 'production'
set :puma_state, "#{shared_path}/tmp/puma/state"
set :puma_pid, "#{shared_path}/tmp/puma/pid"
set :puma_preload_app, true
set :puma_conf, "#{shared_path}/puma.conf"
set :lets_encrypt_roles, :web
set :lets_encrypt_user, 'my_vps_login'
set :lets_encrypt_email, 'my_email'
set :lets_encrypt_account_key, "~/#{fetch(:lets_encrypt_email)}.account_key.pem"
set :lets_encrypt_challenge_public_path, "#{release_path}/public"
set :lets_encrypt_output_path, '/etc/nginx/ssl'
set :lets_encrypt_local_output_path, '~/certs'
set :lets_encrypt_days_valid, 90Ok, let’s try to deploy the app:
$ bundle exec cap production deploy
...
ERROR linked file ~/projects/my_app/shared/puma.conf does not exist on www.my_server.com
...You have to get errors. Let me explain a schema we’re going to use.
Normally if you use Rails 5 it uses puma as default server. When you start an app with rails s command puma reads config\puma.rb configuration file and gets started.
Since we’re going to use puma on VPS things could be a bit different and we need different configuration file.
Thus in order to not mess with default configuration file we will use puma.conf. This file will be used only on VPS.
Run bundle exec cap production puma:config command it will create and uploade puma.conf to shared folder.
Or you can log on you VPS and create ~/projects/my_app/shared/puma.conf and copy this:
directory '/home/my_vps_login/projects/my_app/current'
rackup '/home/my_vps_login/projects/my_app/current/config.ru'
threads_count = ENV.fetch('RAILS_MAX_THREADS') { 5 }.to_i
threads threads_count, threads_count
environment ENV.fetch('RAILS_ENV') { 'production' }
prune_bundler
preload_app!
plugin :tmp_restart
pidfile '/home/my_vps_login/projects/my_app/shared/tmp/puma/pid'
state_path '/home/my_vps_login/projects/my_app/shared/tmp/puma/state'
bind 'unix:///home/my_vps_login/projects/my_app/shared/tmp/sockets/puma.sock'
bind 'tcp://127.0.0.1:3000'
activate_control_appTry again. You should get something alike below:
$ bundle exec cap production deploy
...
puma:start
using conf file ~/projects/my_app/shared/puma.conf
01 $HOME/.rbenv/bin/rbenv exec bundle exec puma -C ~/projects/my_app/shared/puma.conf --daemon
01 Puma starting in single mode...
01
01 * Version 3.9.1 (ruby 2.4.1-p111), codename: Private Caller
01
01 * Min threads: 5, max threads: 5
01
01 * Environment: production
01
01 * Daemonizing...
...You can control your puma server with commands:
$ bundle exec cap production puma:status
$ bundle exec cap production puma:start
$ bundle exec cap production puma:stop
$ bundle exec cap production puma:restartNow we need to care about that our app is get started on system boot. For this we use jungle.
Do not use cap production puma:jungle:install instead log in on VPS server. Download two bash scripts:
wget https://raw.githubusercontent.com/puma/puma/master/tools/jungle/init.d/puma
wget https://raw.githubusercontent.com/puma/puma/master/tools/jungle/init.d/run-pumaAnd follow this instruction.
Now start out app
sudo /etc/init.d/puma startNow is turn of nginx. It’s easy. Just run:
bundle exec cap production puma:nginx_configYou will get /etc/nginx/sites-available/my_app_production conf file. Edit it as you needed.
Now restart nginx
sudo /etc/init.d/nginx restartYour app should be up and ready. Enjoy!