tobogranyte
tobogranyte

Reputation: 939

Why isn't Rails with nginx and a self-signed SSL certificate working?

I'm trying to test my SSL setup before migrating over a site from Heroku to a (Digital Ocean) VPS, so I'm using a self-signed certificate as per these instructions.

I used the following command to create the certificates, and they are present in the appropriate directory:

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crt

Here are the relevant lines from the server block on my nginx.conf:

server {
  listen 80 default_server;
  listen 443 ssl;
  server_name migration.my_domain.com;
  ssl_certificate /etc/nginx/ssl/nginx.crt;
  ssl_certificate_key /etc/nginx/ssl/nginx.key;

Additionally, in production.rb I've used the following line:

config.force_ssl = true

my_domain (not the actual domain name) and its subdomain migration are both set up in my DNS and are correctly pointing to my server's IP address. At present, when I access via http://migration.my_domain.com pages get served up. But when I access via https://migration.my_domain.com, I'm getting an error in Chrome:

This site can’t be reached

migration.my_domain.com refused to connect.
Try:
Reloading the page
Checking the connection
Checking the proxy and the firewall
ERR_CONNECTION_REFUSED

Any idea what I'm missing here?

Upvotes: 2

Views: 1302

Answers (1)

tobogranyte
tobogranyte

Reputation: 939

Figured it out. First, I'm deploying via Capistrano which I had mistakenly thought was restarting nginx after a deploy. Turns out it doesn't. So I needed to do that manually. So deployed with this at the beginning of my server block:

server {
  listen 443 ssl default_server deferred;
  server_name migration.my_domain.com;
  ssl_certificate /etc/nginx/ssl/nginx.crt;
  ssl_certificate_key /etc/nginx/ssl/nginx.key;
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  ssl_prefer_server_ciphers on;
  ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';

Deployed that, but after restarting nginx, first got the warning from Chrome about a self-signed certificate and that the site can't be trusted (which is fine and expected). After moving past that got a message about too many redirects. Turns out that the line from above in my production.rb file:

config.force_ssl = true

was causing a problem. Saw this which from what I can tell means that what nginx sends through to puma does not contain whether it's ssl or not, so puma redirects everything, even the https requests because it just doesn't know what it's getting. So, now I have two near-duplicate server blocks. The first one which handles http requests has the following relevant statements:

server {
  listen 80;
  server_name migration.my_domain.com;

  # ...bunch of non-relevant config...

  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://puma;
  }
}

This handles all the 80 requests which puma will redirect all of to ssl (I believe) thanks to config.force_ssl = true in production.rb. Nginx will then receive an https request for the same URL which will be handled by this block:

server {
  listen 443 ssl;
  server_name migration.my_domain.com;
  ssl_certificate /etc/nginx/ssl/nginx.crt;
  ssl_certificate_key /etc/nginx/ssl/nginx.key;
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  ssl_prefer_server_ciphers on;
  ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';

  # ...bunch of non-relevant config...

  location @puma {
    proxy_set_header X-Forwarded-Proto https; # IMPORTANT!! I believe this tells puma that everything sent through via this block is https. Thus, puma no longer redirects.
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;

    proxy_pass http://puma;
  }
}

This seems to work correctly, albeit with all the appropriate warnings one should get in the browser when receiving a self-signed certificate. I'm confident that once I switch in my actual certificates, I will now have a functioning ssl setup.

Thanks again @doon!

Upvotes: 2

Related Questions