When it comes time to deploy your Rails app to a production environment, there are myriad options available. This article will explain the nginx/unicorn combo, as deployed on Ubuntu linux. After reading this article, not only will you be able to set up your own server with the unicorn Rails server and the nginx web server, but you’ll also understand many of the available configuration options so that you can adjust your server setup to fit your application properly. While I won’t get into the details of comparing the nginx/unicorn combo with other options, I will give an overview of what each component provides and why it is a solid choice for your production server environment.
In this article, I’ll be using unicorn as the Rails server. There are definitely other options out there. Rails servers such as puma and thin are quite similar and have their own benefits. I’m going to use unicorn because it is a tried and tested tool that can also teach the basics of similar Rails servers.
First, it’s a Rack HTTP server. This means that it implements the HTTP protocol for Rack applications. I won’t go into the HTTP protocol, but you can read more about it on wikipedia. Rack is a gem that provides a basic interface for ruby applications to respond to web requests. Basically, rack applications must respond with an array of three elements: an HTTP response code, a hash of headers, and the response body that responds to an
each block. Modern versions of Rails run on Rack, which enables servers like unicorn, thin, and puma to work with them directly.
Next, unicorn is a server for fast clients and Unix. What is a fast client? A fast client is another application or server that can interface with the Rack server quickly, without much latency. Unicorn is not good as a standalone server: it wasn’t designed to handle slow requests that occur over network connections. It relies on Nginx or Apache to handle the buffering and queuing of web requests so that it doesn’t have to worry about concurrency and event-driven programming2. Unicorn is basically the glue between nginx and rack, where Nginx is the fast client.
Unicorn has some features, while not necessarily unique to it, that make it ideal for a Rails server. One such feature that comes in handy is the ability to deploy changes to your application without causing downtime. The problem of zero-downtime deployment is often more complex than a simple unicorn no-downtime reload, but for the most part it is all you need. Unicorn is made to handle high-CPU loads, and is usually configured so that there are the same number of worker processes as CPUs.
The following sections explain, in a fair amount of detail, how to set up your server with unicorn and nginx.
This tutorial was written under the assumption that the server used is Ubuntu linux, release 12.04 or 14.04. You will need root or sudo access to the server to complete the setup properly. You should also be familiar with the basics of git and the linux command line.
Step 1: Set up unicorn
To set up your server correctly, you’ll first need to set up your application’s code base. If you’re using bundler (and you should be if your app is written in Ruby), then all you need to do is add the unicorn gem to your Gemfile:
bundle install, or just
bundle for short, from your application’s
One more recommendation I’d like to make is that you use binstubs. You can set your application up with binstubs by running
bundle --binstubs. This will create a
bin/ directory in your application root with all of the executables for the gems in your Gemfile. Having binstubs will make development easier: you can set your
PATH by add the following line to your
Then, instead of always prefixing your commands with
bundle exec, you can type just the command (e.g.
rake instead of
bundle exec rake). If you don’t want to change your bash’s
PATH variable, you can still use
bin/unicorn and the like. This will also become handy when configuring your server’s unicorn init script, as you’ll see later in this article.
The unicorn command accepts a configuration file as one of its options. The defaults are pretty sane, but you’ll still need to configure a few things to match your application’s setup. The unicorn config file is written in Ruby and is usually located at
config/unicorn.rb within your application’s root folder.
First, it’s helpful to set a variable to your application’s root folder:
1 2 3
Next, we’ll want to configure the number of worker processes. Unicorn always runs with one master process that can terminate and start one or more worker processes. A good guideline on how many worker processes to set is to match the number of CPU cores your server has. I like to set a different default for production, but you can do whatever meets your needs here:
1 2 3
Unicorn can listen on ports and/or sockets. I prefer listening on a socket to remind myself that unicorn works best with fast (non-networked) clients. You can set each worker to listen on a separate port in the
after_fork block below for testing.
1 2 3 4 5 6 7 8
The default unicorn timeout is 60 seconds, so if your application needs a longer timeout (for generating reports or the like), make sure you set a reasonable timeout here:
1 2 3 4
Use unicorn’s DSL (Domain-Specific Language) to set the working directory, pid file, and standard in and standard out. We’ll be using the pid file location later on, so take note of how you set it here.
1 2 3 4 5 6 7 8 9 10 11
Finish up the file with some Rails-friendly settings:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
Test that your unicorn configuration works by running the following from your app’s root directory:
1 2 3
Use Ctrl-C to exit the process.
Commit and push your changes (
bin/*) and move on to the next step.
Step 2: Set up Ruby, Git, and Your Database
I won’t beat a dead horse here. There’s already a very nice blog post on how to set up Ruby on your server using rbenv. You’ll also want to set up git (also in that article), and your preferred database. Postgresql setup is explained in that article, but you could just as easily set up MySQL using the following command:
Step 3: Set up Unicorn Init Script
You’ve already set up your application to work with unicorn, so now set up your server to work with unicorn as well. Unicorn should start automatically when your server (re)boots so that you don’t have to worry about that every time your server restarts. An init script can make managing your unicorn processes much easier. In this section, I will show you how to set up an init script for your unicorn process.
The unicorn init script should be located in the
/etc/init.d folder, and is usually called
unicorn. With such a setup on an Ubuntu server, you’ll be able to run commands like
sudo service unicorn upgrade or
sudo service unicorn status.
The init script is written in bash, and should start with an
INIT INFO section5:
1 2 3 4 5 6 7 8 9 10 11 12 13
The above section tells your server (when we add
unicorn to the startup scripts) that the
$syslog boot facilities must be available before this script can start. Likewise,
Required-Stop indicates that this script should be stopped before those facilities to prevent conflicts. It also sets some default start and stop init levels, a short description and a multiline description. You probably shouldn’t touch much in the above settings.
In the next part, you’ll set some variables to help get your app started properly:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
Once you get the variables set up properly, you should be able to copy and paste the rest of the init script. Note the comments for more information on how things work and why.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
The above script doesn’t include all the possible options for signaling the unicorn master process. See the unicorn signal documentation for more possibilities.
Make sure your init script has permission to be executed:
Now, you can run
sudo service unicorn start to start your unicorn process. Check your logs (whatever you set
stdout_path to in
unicorn.rb) to troubleshoot issues. When you’ve updated your code base, you can run
sudo service unicorn upgrade to gracefully phase in new workers. To make sure unicorn starts on reboot, update the
rc.d startup configuration using the following command:
This will add a symlink to the unicorn init script in the appropriate
/etc/rc.d folders, which are used to determine what starts when.
Using unicorn with RVM or rbenv
The above init script works with rbenv, but you can use RVM just as well. The main difference, from my experience, is that you won’t have to set all the extra
RBENV_ variables like I have above. In fact, the following should be sufficent:
1 2 3 4 5 6 7 8 9
Step 4: Nginx configuration
You should now have unicorn properly configured to serve up your application. To expose your application to the world, you’ll now have to configure and start Nginx.
Installing nginx on ubuntu is very simple. Use
apt-get to install a stable version:
If you need the most recent stable nginx build, you can use the nginx download documentation to configure your server.
The nginx install process on ubuntu creates a folder at
/etc/nginx. In this folder you’ll find a few configuration files, along with a
sites-available and a
sites-enabled folder. The
sites-available folder is where you’ll configure your application-specific nginx setup, and
/etc/nginx/nginx.conf is most likely where you’ll configure global nginx settings. The following is a sensibly configured
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
As noted in the inline comments, make sure the path to the unicorn socket matches what you set up in
This is the final step in setting up your server: your application-specific nginx configuration. The following file shows the basics of setting things up.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
To enable the site you just configured, all you have to do is add a symlink to the configured file into the
sites-enabled folder, then reload nginx.
1 2 3 4 5 6 7 8 9
Make sure all your processes are running:
And you’re done!
You should now have a good idea of how to set up your production Rails server to run on unicorn and nginx. I’ll list the steps here for your reference:
- Prepare your Rails app:
- Add the unicorn gem to your Gemfile.
- Configure unicorn for your Rails app by adding and modifying
- Install ruby and other dependencies on your server.
- Configure the unicorn init script on your server (
- Install and configure nginx (
- Confirm everything is running, and you’re done!