Skip to content

Latest commit

 

History

History
437 lines (342 loc) · 12 KB

production-webserver.adoc

File metadata and controls

437 lines (342 loc) · 12 KB

Web Server in Production Mode

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.

Debian 8.7

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.

Buildsystem

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

nginx

Nginx will be our web server to the outside world.

root@debian:~# apt-get -y install nginx

User Deployer

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:~#

Database

In this setup we use PostgreSQL as our production database.

PostgreSQL Installation

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.

Setting up Rails Environment for User deployer

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.

Setting Up a New Rails Project

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.

Production Database Configuration

In the file config/database.yml you need to change the production database user to deployer:

config/database.yml
[...]

production:
  <<: *default
  database: blog_production
  username: deployer
  password: <%= ENV['BLOG_DATABASE_PASSWORD'] %>

rails db:migrate

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

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 pid

Puma needs the tmp/puma directory to store a pid file:

deployer@debian:~/blog$ mkdir tmp/puma
deployer@debian:~/blog$ exit
logout
root@debian:~#

Puma Init Script

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.
/etc/puma.conf
/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.

nginx Configuration

For the Rails project, we add a new configuration file /etc/nginx/sites-available/blog.conf with the following content:

/etc/nginx/sites-available/blog.conf
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.

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 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

Performance

If performance is key for your production webserver you want to use a socket connection instead of the TCP connection.

Misc

Alternative Setups

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.

What Else There Is To Do

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.

404 and Co.

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

Multiple Rails Servers on One System

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.

Cloud Platform as Service Provider

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.