Setting Thin up behind Nginx & with Lets Encrypt certificates

Part of Booko’s infrastructure includes a Sinatra application served by Thin. This application takes CSV / XML / JSONL files containing product pricing data, loads it into PostgreSQL and presents it via an API.

Thin is perfectly capable of being internet facing, but I have a preference for reverse proxying it behind Nginx. There are plenty of ways to deploy an app like this, but here’s a very standard approach.

Create a Systemd Service

Running applications as daemons is straight forward. Systemd will ensure that it’s started up at boot time and will be restarted it on failure.

[Unit]
Description=CSV To API Service
After=syslog.target

[Service]
Type=simple
User=deploy

Environment=MM_ENV=production

WorkingDirectory=/var/www/c2a/
ExecStart=/home/deploy/.rbenv/bin/rbenv exec bundle exec thin start -e production -p 1234 -a 127.0.0.1

Restart=on-failure
SyslogIdentifier=c2a

[Install]
WantedBy=multi-user.target

This will start up your app at boot, and restart it if it fails. The app will log to syslog and will be tagged as c2a in the syslog file. I’ve set an environment variable MM_ENV in this script, and the app will run as the user deploy.

Note that the app listens on 127.0.0.1 and will not be accessible on the internet.

Create an Nginx server

Next up, we’ll create an Nginx host. First, we’ll create a host which responds to the correct name but listens only on port 80. This is needed for Lets Encrypt to verify we’re in control of the domain name.

server {
listen 80;
server_name c2a.booko.info;
root /var/www/c2a;

location '/.well-known/acme-challenge' {
default_type "text/plain";
}

location / {
return 301 https://$host$request_uri;
}

access_log  logs/c2a.log combined;
error_log   logs/c2a.error;
}

This will respond to the specify requests that Lets Encryption will make looking for the challenge file. Any other request will be redirected to https and will currently fail.

Now to get an SSL Certificate from Lets Encrypt.

sudo certbot certonly -d c2a.booko.info --webroot

When asked for the webroot, we enter it as in the Nginx configuration : /var/www/c2a

Certbot will store your certificate in /etc/letsencrypt/live/<domain> and we can refer to them in the Nginx configuration. Next, we can add the HTTPS server configuration:

server {
listen 443 ssl http2;

server_name c2a.booko.info;

ssl                  on;
ssl_certificate      /etc/letsencrypt/live/c2a.booko.info/fullchain.pem;
ssl_certificate_key  /etc/letsencrypt/live/c2a.booko.info/privkey.pem;

location / {
auth_basic "Booko's CSV to API service";
auth_basic_user_file /var/www/c2a/etc/c2a_auth;
proxy_pass http://127.0.0.1:8081;
}

access_log  logs/c2a.log combined;
error_log   logs/c2a.error;
}

You can see I’ve added one extra component here – basic authentication. Basic Auth for a single client via HTTPS is straight forward way of restrict access. You can generate the auth file with htpasswd -c <file> <user> and you’ll be prompted to enter a password.

And that’s it, we’re done!