Deploying sinatra app on DigitalOcean with nginx and thin

Published by Michael Carrano on September 22, 2012



When I relaunched my personal site, I ran into several issues that I would like to share how I overcame.

The issue that took me longest to troubleshoot and figure out was actually deploying a Sinatra app to work with nginx and thin.

DigitalOcean provides fantastic community guides to help you get started with their service. Since the guides are great, I will just link you to the guides I followed to get started.

Initial server setup for Ubuntu

Install RVM and Ruby

Setup nginx virtual hosts

Those three guides will give you the basic process of getting started with development on your droplet. You will also want to install bundler so it is easy to install ruby gems that are required in your sinatra app.

Now lets move onto the technical part of getting nginx and thin to work together.

Since the guide above tells you how to install and setup nginx, the next step is to have thin installed.

gem install thin
thin install

Those two lines of code will allow you to install thin. Then follow the on screen instructions on how to set thin to run on startup automatically.

Next, I created a thin config file (yaml) for the application I want to run. Make a note that I decided to use sockets.

You can put this file in /etc/thin/myapp.yml as an example. Just remember the path for later.

user: root
group: root
pid: tmp/pids/thin.pid
timeout: 30
wait: 30
log: /var/log/thin/thin.log
max_conns: 1024
require: []
environment: production
max_persistent_conns: 512
servers: 2
onebyone: true
threaded: true
no-epoll: true
daemonize: true
socket: tmp/sockets/thin.sock
chdir: /var/www/example.com/public_html
tag: example aux

You may have to manually create the directories that you specified for log and pid. Also, having onebyone set to true is very handy. If you ever need to restart thin due to changes, then it will just restart each server at a time so you experience no downtime.

Now that we have thin configured how we want, we now need to make it work with nginx.

If you followed the guide on setting up an nginx virtual host, the guide had you use default nginx settings. We need to change this to use upstream, proxy_pass and proxy_set_header to work with thin.

Edit /etc/nginx/sites-available/example.com/ with the following:

upstream www_example_com {
  ip_hash;
  server unix:/var/www/example.com/public_html/tmp/sockets/thin.0.sock max_fails=1 fail_timeout=15s;
  server unix:/var/www/example.com/public_html/tmp/sockets/thin.1.sock max_fails=1 fail_timeout=15s;
}

server {

  listen 80;
  server_name example.com  www.example.com;

  location / {
    proxy_pass http://www_example_com;
    proxy_set_header HOST $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }

  root /var/www/example.com/public_html;

  access_log /var/log/nginx/access.log;
  error_log /var/log/nginx/error.log;

}

There are a few things going on in the above configuration:

  1. Notice in the upstream section we are using sockets. This is because our thin configuration is using sockets. Thin and nginx can communicate using sockets or tcp, sockets are faster which is why I use them.

  2. The use of proxy_pass, proxy_set_header and ip_hash is so you can use sessions when a client visits your site.

  3. You may have to manually create some of the directories. Particularly the upstream directory paths.

Now that you have all of that ready to go all that is left is to start nginx and thin.

service nginx start
thin start -s 2 -C /etc/thin/myapp.yml -R config.ru

If you ever need to restart thin simply use:

thin restart -C /etc/thin/myapp.yaml

Let me know if you run into any issues and I will do my best to help you.