This chapter walks you through the setup process of a production server which runs Nginx as a reverse proxy webserver and Puma as the Ruby on Rails webserver behind the Nginx. We start with a fresh Debian system and install all the software we need. The Rails 5.2 project will be run with Ruby 2.4 which gets installed with RVM and runs for the user deployer.
The example Rails application we use is called blog
. It will contain a post
scaffold.
Warning
|
If you have never set up a Nginx or Apache web server by yourself on a Linux system before you will likely get lost somewhere in this chapter. |
We build our production web server on a minimal Debian 8.7 system. To carry out this installation, you need to have root rights on the web server!
This description assumes that you have a freshly installed Debian GNU/Linux 8.7 (Jessie). You will find an ISO image for the installation at http://www.debian.org. I recommend the approximately 250 MB net installation CD image. For instructions on how to install Debian-GNU/Linux, please go to http://www.debian.org/distrib/netinst.
Tip
|
VMware or any other virtual PC system is a great playground to get a feeling how this works. |
Login as root, update the package lists and upgrade the system:
root@debian:~# apt-get update
[..]
root@debian:~# apt-get upgrade
Installation of the packages required for the RVM installation:
root@debian:~# apt-get -y install curl gawk g++ \
make libreadline6-dev zlib1g-dev libssl-dev \
libyaml-dev libsqlite3-dev sqlite3 autoconf \
libgdbm-dev libncurses5-dev libtool bison nodejs \
pkg-config libffi-dev libgmp-dev libgmp-dev git
Our Rails project is going to use RVM in the user space.
So we create a new user with the name deployer
:
root@debian:~# adduser deployer
Adding user `deployer' ...
Adding new group `deployer' (1001) ...
Adding new user `deployer' (1001) with group `deployer' ...
Creating home directory `/home/deployer' ...
Copying files from `/etc/skel' ...
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
Changing the user information for deployer
Enter the new value, or press ENTER for the default
Full Name []: Deployer
Room Number []:
Work Phone []:
Home Phone []:
Other []:
Is the information correct? [Y/n] Y
root@debian:~#
In this setup we use PostgreSQL as our production database.
We need to install the database software:
root@debian:~# apt-get -y install postgresql postgresql-client libpq-dev
To create a database user deployer
and a database blog_production
we need to
do the following steps:
root@debian:~# su - postgres
postgres@debian:~$ createuser -W --createdb deployer
Password:
postgres@debian:~$ createdb blog_production
postgres@debian:~$ exit
logout
root@debian:~#
For this example we use the password 123456. It should be obvious that this is a bad idea for your application to copy.
With su - deployer
we’ll become the user deployer:
root@debian:~# su - deployer
As user deployer
, please carry out the steps for installing Ruby 2.4
and Rails 5.2 via RVM.
deployer@debian:~$ gpg --keyserver hkp://keys.gnupg.net \
--recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
[...]
deployer@debian:~$ curl -sSL https://get.rvm.io | bash
[...]
deployer@debian:~$ source /home/deployer/.rvm/scripts/rvm
deployer@debian:~$ rvm install 2.4 --autolibs=read-only
[...]
deployer@debian:~$ gem install rails
[...]
deployer@debian:~$
Tip
|
You need to run gem install rails --pre in case Rails 5.2 is still
beta while you read this text.
|
To keep this guide as simple as possible, we create a simple blog in the
home directory of the user deployer
.
deployer@debian:~$ rails new blog --database=postgresql
[...]
deployer@debian:~$ cd blog
deployer@debian:~/blog$ rails generate scaffold post subject content:text
[...]
deployer@debian:~/blog$
Note
|
--database=postgresql takes care of installing the pg gem for
using PostgreSQL. In case you already have a Rails application you
need to add the line gem 'pg' to your Gemfile and run
a bundle install afterwards.
|
In the file config/database.yml
you need to change the production database
user to deployer
:
[...]
production:
<<: *default
database: blog_production
username: deployer
password: <%= ENV['BLOG_DATABASE_PASSWORD'] %>
We still need to create the production database tables:
deployer@debian:~/blog$ rails db:migrate RAILS_ENV=production BLOG_DATABASE_PASSWORD=123456
[...]
deployer@debian:~/blog$
Warning
|
You probably want to set BLOG_DATABASE_PASSWORD as an environment
variable in your .bash_profile because it is not a good idea
to have the DB password in your bash history.
|
rails assets:precompile
ensures that all assets in the asset pipeline
are made available for the production environment.
deployer@debian:~/blog$ rails assets:precompile
Puma needs the tmp/puma
directory to store a pid file:
deployer@debian:~/blog$ mkdir tmp/puma
deployer@debian:~/blog$ exit
logout
root@debian:~#
The Puma web server has to be started automatically at every booting process. Plus it has to be killed when the server shuts down. That’s been taken care of by an init script.
Please do the following commands as root
.
$ cd /etc/init.d
$ wget https://raw.githubusercontent.com/puma/puma/master/tools/jungle/init.d/puma
$ chmod a+x puma
$ cd /usr/local/bin
$ wget https://raw.githubusercontent.com/puma/puma/master/tools/jungle/init.d/run-puma
$ chmod a+x run-puma
$ touch /etc/puma.conf
$ chmod 640 /etc/puma.conf
$ update-rc.d -f puma defaults
Now we have to create the configuration for the production instance.
It includes the environment variables BLOG_DATABASE_PASSWORD
and
SECRET_KEY_BASE
.
Tip
|
To create a new SECRET_KEY_BASE you should run rails secret in your
rails project directory.
|
/home/deployer/blog,deployer,/home/deployer/blog/config/puma.rb,/home/deployer/blog/log/production.log,RAILS_ENV=production;PORT=3001;BLOG_DATABASE_PASSWORD=123456;SECRET_KEY_BASE=AASD...ASDF
Tip
|
If you don’t want to store the environment variables in /etc/puma.conf
you can use the bin/rails secrets:setup mechanism.
|
It’s time to start puma:
$ /etc/init.d/puma start
[ ok ] Starting puma (via systemctl): puma.service.
$
Now puma runs and is available at http://localhost:3001
. To make it
available to the internet we have to setup nginx.
For the Rails project, we add a new configuration file
/etc/nginx/sites-available/blog.conf
with the following content:
server {
listen 80 default deferred;
# server_name example.com;
root /home/deployer/blog/public;
location / {
gzip_static on;
try_files $uri/index.html $uri @puma;
}
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
location @puma {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://localhost:3001;
}
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.
$ ln -s /etc/nginx/sites-available/blog.conf /etc/nginx/sites-enabled/
$ rm /etc/nginx/sites-enabled/default
$ /etc/init.d/nginx restart
[ ok ] Restarting nginx (via systemctl): nginx.service.
$
You’re all set. Your new Rails project is online. You can access the posts
.
You’ll have to configure the root
path in config/routes.rb
to get a proper
root path URL.
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 rails assets:precompile
(see
"Asset Pipeline").
deployer@debian:~/blog$ rails assets:precompile
[...]
deployer@debian:~/blog$
If you bring in new migrations, you of course also need to do a
rails db:migrate RAILS_ENV=production
:
deployer@debian:~/blog$ rails db:migrate RAILS_ENV=production
[...]
deployer@debian:~/blog$
Then you need to restart Puma as user root
:
root@debian:~# /etc/init.d/puma restart
The RVM, Puma and Nginx way is fast and makes it possible to setup different Ruby versions on one server. But many admins prefer an easier installation process which is promised by Phusion Passenger. Have a look at https://www.phusionpassenger.com for more information about Passenger. It is a very good and reliable solution.
Please always consider the following points - every admin has to decide these for him- or herself and implement them accordingly:
-
Automatic and regular backup of database and Rails project.
-
Set up log rotations of log files.
-
Set up monitoring for system load and hard drive space.
-
Regularly install Debian security updates as soon as they become available.
Finally, please look into the public
directory in your Rails project
and adapt the HTML pages saved there to your own requirements.
Primarily, this is about the design of the pages. In the default
setting, these are somewhat sparse and do not have any relation to the
rest of your website. If you decide to update your web page and shut
down your Puma server to do so, nginx will deliver the web page
public/500.html
in the meantime.
You will find a list of HTTP error codes at http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
You can runs several Rails servers on one system without any problems. You need to set up a separate Puma for each Rails server. You can then distribute to it from nginx. With nginx you can also define on which IP address a Rails server is accessible from the outside.
If you do not have a web server available on the internet or want to deploy to a PaaS (Platform as a Service) system right from the start, you should have a look at what the various providers have to offer. The two US market leaders are currently Heroku (http://www.heroku.com/) and Engine Yard (http://www.engineyard.com/).
PaaS as platform usually offers less options than your own server. But you have 7x24 support for this platform if anything does not work properly.