Using SSL with Passenger in Production

This article covers how to configure your webserver to serve your app over https in a production deployment, and how to check it for correctness.

Obtain a Trusted SSL Certificate

In order to have your production SSL configuration trusted by your users' browsers, you need a certificate signed by a trusted Certificate Authority (CA). While you have many choices in this regard, most of them cost money. One free option that you have though is to obtain your certificate from the Let's Encrypt organization.

Choose your tradeoffs

A secure production ready configuration is an exercise in tradeoffs; broad compatibility and speed for strongest security. A great resource in this regard is the Mozilla SSL Configuration Generator which will provide you with up-to-date web server configurations that either maximize compatibility or security. The following configuration was designed to be more broadly compatible, but your situation may warrant maximum security.

Configure Nginx

The following is a partial example configuration for the Nginx Web Server, meant to highlight the SSL configuration options you are likely to need in production. Replace example.com with your domain, and set the paths to your certificates, key, and app.

Generate the Diffie-Hellman parameters file using this command:

$ openssl dhparam -out /path/to/dhparam.pem 2048
server_tokens off;
server {
    # Redirect all HTTP requests to HTTPS with a 301 Moved Permanently response.
    listen 80 default_server;
    listen [::]:80 default_server;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    root /path/to/app/public;
    server_name example.dev;
    passenger_app_root /path/to/app;
    passenger_enabled on;
    passenger_app_env production;

    ssl_certificate /path/to/signed_cert_plus_intermediates.pem;
    ssl_certificate_key /path/to/private_key.pem;
    ssl_dhparam /path/to/dhparam.pem;
    ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates.pem;
    resolver <DNS server IP>;

    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;
    ssl_prefer_server_ciphers on;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
    ssl_stapling on;
    ssl_stapling_verify on;
    add_header Strict-Transport-Security max-age=15768000;

    #...
}

Test With SSL Labs

Qualys provides an excellent free test of your server's SSL configuration, you can use it here to check your setup for known issues. While a score of A or A+ is a good indication that you setup your config correctly, it is not a guarantee, so it's important to be informed or consult with someone who is.

You should also keep in mind that a secure configuration is a moving target, you have to stay up to date on the latest vulnerabilities that are discovered, and update your configuration accordingly.