16.3. Setting Up a New Rails Project

To keep this guide as simple as possible, we create a simple blog in the homedirectory of the user deployer.
root@debian:~# su - deployer
deployer@debian:~$ rails new blog
[...]
deployer@debian:~$ cd blog
deployer@debian:~/blog$ rails generate scaffold post subject content:text
[...]
deployer@debian:~/blog$

Adapting Gemfile

Please add the following content into the file Gemfile:
gem 'mysql', group: :production
gem 'unicorn', group: :production
Then install all gems with bundle install:
deployer@debian:~/blog$ bundle install
[...]
deployer@debian:~/blog$
To get a root URL we'll change to config/routes.rb file to this:
Blog::Application.routes.draw do
  resources :posts
  root 'posts#index'
end

Production Database Configuration

In the file config/database.yml you need to enter the database configuration for the MySQL database for the production system. Please make sure you enter the correct password.
# SQLite version 3.x
#   gem install sqlite3
#
#   Ensure the SQLite 3 gem is defined in your Gemfile
#   gem 'sqlite3'
development:
  adapter: sqlite3
  database: db/development.sqlite3
  pool: 5
  timeout: 5000

# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
  adapter: sqlite3
  database: db/test.sqlite3
  pool: 5
  timeout: 5000

production:
  adapter: mysql
  encoding: utf8
  database: blog
  username: deployer
  password: YourFavoritePassword

Buy the new Rails 5.1 version of this book.

Again: Please change the password!

Unicorn Configuration

For the Unicorn configuration, we use the file https://raw.github.com/defunkt/unicorn/master/examples/unicorn.conf.rb as basis and save it as follows in the file config/unicorn.rb after we adapt it to our server:
# Sample verbose configuration file for Unicorn (not Rack)
#
# This configuration file documents many features of Unicorn
# that may not be needed for some applications. See
# http://unicorn.bogomips.org/examples/unicorn.conf.minimal.rb
# for a much simpler configuration file.
#
# See http://unicorn.bogomips.org/Unicorn/Configurator.html for complete
# documentation.

# Use at least one worker per core if you're on a dedicated server,
# more will usually help for _short_ waits on databases/caches.
worker_processes 4

# Since Unicorn is never exposed to outside clients, it does not need to
# run on the standard HTTP port (80), there is no reason to start Unicorn
# as root unless it's from system init scripts.
# If running the master process as root and the workers as an unprivileged
# user, do this to switch euid/egid in the workers (also chowns logs):
user "deployer", "www-data"

# Help ensure your application will always spawn in the symlinked
# "current" directory that Capistrano sets up.
APP_PATH = "/home/deployer/blog"
working_directory APP_PATH # available in 0.94.0+

# listen on both a Unix domain socket and a TCP port,
# we use a shorter backlog for quicker failover when busy
listen "/tmp/.unicorn_blog.sock", :backlog => 64
listen 8080, :tcp_nopush => true

# nuke workers after 30 seconds instead of 60 seconds (the default)
timeout 30

# feel free to point this anywhere accessible on the filesystem
pid "/var/run/unicorn_blog.pid"

# By default, the Unicorn logger will write to stderr.
# Additionally, ome applications/frameworks log to stderr or stdout,
# so prevent them from going to /dev/null when daemonized here:
stderr_path APP_PATH + "/log/unicorn_blog.stderr.log"
stdout_path APP_PATH + "/log/unicorn_blog.stdout.log"

# combine Ruby 2.0.0dev or REE with "preload_app true" for memory savings
# http://rubyenterpriseedition.com/faq.html#adapt_apps_for_cow
preload_app true
GC.respond_to?(:copy_on_write_friendly=) and
  GC.copy_on_write_friendly = true

# Enable this flag to have unicorn test client connections by writing the
# beginning of the HTTP headers before calling the application.  This
# prevents calling the application for connections that have disconnected
# while queued.  This is only guaranteed to detect clients on the same
# host unicorn runs on, and unlikely to detect disconnects even on a
# fast LAN.
check_client_connection false

before_fork do |server, worker|
  # the following is highly recomended for 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

rake db:migration

We still need to create the database:
deployer@debian:~/blog$ rake db:migrate RAILS_ENV=production
[...]
deployer@debian:~/blog$ 

Buy the new Rails 5.1 version of this book.

Please ensure that the rake db:migrate concludes with a RAILS_ENV=production. This is to migrate the production database.

rake assets:precompile

rake assets:precompile ensures that all assets in the asset pipeline are made available for the production environment (see Chapter 12, Asset Pipeline).
deployer@debian:~/blog$ rake assets:precompile
[...]
deployer@debian:~/blog$

Unicorn Init Script

Now you need to continue working as user root:
deployer@debian:~$ exit
Abgemeldet
root@debian:~# 
Create the init script /etc/init.d/unicorn_blog with the following content:
#!/bin/bash

### BEGIN INIT INFO
# Provides:          unicorn
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Unicorn webserver
# Description:       Unicorn webserver for the blog
### END INIT INFO

UNICORN=/home/deployer/.rvm/bin/bootup_unicorn
UNICORN_ARGS="-D -c /home/deployer/blog/config/unicorn.rb -E production"
KILL=/bin/kill
PID=/var/run/unicorn_blog.pid

sig () {
  test -s "$PID" && kill -$1 `cat $PID`
}

case "$1" in
        start)
                echo "Starting unicorn..."
                $UNICORN $UNICORN_ARGS
                ;;
        stop)
                sig QUIT && exit 0
                echo >&2 "Not running"
                ;;
        restart)
                $0 stop
                $0 start
                ;;
        status)
                ;;
        *)
                echo "Usage: $0 {start|stop|restart|status}"
                ;;
esac
You still have to activate the init script and start Unicorn:
root@debian:~# chmod +x /etc/init.d/unicorn_blog 
root@debian:~# update-rc.d -f unicorn_blog defaults
update-rc.d: using dependency based boot sequencing
root@debian:~# /etc/init.d/unicorn_blog start
root@debian:~# 
Your Rails project is now accessible via the IP address of the web server.

nginx Configuration

For the Rails project, we add a new configuration file /etc/nginx/sites-available/blog.conf with the following content:
upstream unicorn {
  server unix:/tmp/.unicorn_blog.sock fail_timeout=0;
}

server {
  listen 80 default deferred;
  # server_name example.com;
  root /home/deployer/blog/public;

  location / {
    gzip_static on;
  }

  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
  }

  try_files $uri/index.html $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;
  client_max_body_size 4G;
  keepalive_timeout 10;
}
We link this configuration file into the /etc/nginx/sites-enabled directory to have it loaded by Nginx. The default file can be deleted. After that we restart Nginx and are all set. You can access the Rails application through the IP address of this server.
root@debian:~# ln -s /etc/nginx/sites-available/blog /etc/nginx/sites-enabled/
root@debian:~# rm /etc/nginx/sites-enabled/default
root@debian:~# /etc/init.d/nginx restart
Restarting nginx: nginx.
root@debian:~#

Loading Updated Versions of the Rails Project

If you want to activate Updates to the Rails project, you need to copy them into the directory /home/deployer/blog and log in as user deployer to run rake assets:precompile (see Chapter 12, Asset Pipeline).
deployer@debian:~/blog$ rake assets:precompile
[...]
deployer@debian:~/blog$
If you bring in new migrations, you of course also need to do a rake db:migrate RAILS_ENV=production:
deployer@debian:~/blog$ rake db:migrate RAILS_ENV=production
[...]
deployer@debian:~/blog$ 
Then you need to restart Unicorn as user root:
root@debian:~# /etc/init.d/unicorn_blog restart
root@debian:~#