force_ssl
is a very useful setting in Ruby on Rails 6 (and below), but can be tricky to setup. In this guide I’ll walk you through how to configure it.
It’s very useful for security purposes, of which can be summed up nicely with this StackOverflow answer:
"It doesn't just force your browser to redirect HTTP to HTTPS. It also sets your cookies to be marked "secure", and it enables HSTS, each of which are very good protections against SSL stripping."
Overall it’s a great configuration for your Rails application to implement, and with the following guide, it’s quick to setup as well.
force_ssl
Let’s begin:
force_ssl
In your Rails application, simply go to /config/enviorments/production.rb
and update the following line (it may be commented out):
/config/enviorments/production.rb
Rails.application.configure do
# ...
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
config.force_ssl = true
# ...
end
Then save and you’re set for now.
If you haven't already, take a moment to configure your server with Let's Encrypt SSL certificates. Here's a great tutorial.
When prompted to redirect all traffic to HTTPS or do nothing, choose "Do Nothing" (option 1). If you've already picked to redirect, we can fix it below.
If you're looking for a good tutorial on how to deploy your Rails application, or need some more info on the nginx.conf
configuration, check out my previous tutorial about it.
Once you’ve setup HTTPS with Certbot, we need to configure our nginx.conf
file. For your nginx.conf
file, update it with the following (adjusting with your appropriate configuration):
Production Server: /etc/nginx/sites-enabled
# This configuration uses Puma. If using another rack server, substitute appropriate values throughout.
upstream puma {
server unix:///home/root/apps/app_name/shared/tmp/sockets/app_name-puma.sock;
}
# We need to be listing for port 80 (HTTP traffic).
# The force_ssl option will redirect to port 443 (HTTPS)
server {
listen 80 default_server deferred;
# Update this
server_name example.com;
# Don't forget to update these, too.
# For help with setting this part up, see:
# http://localhost:4000/2018/09/18/deploying-ruby-on-rails-for-ubuntu-1804.html
root /home/user_name/apps/app_name/current/public;
access_log /home/user_name/apps/app_name/current/log/nginx.access.log;
error_log /home/user_name/apps/app_name/current/log/nginx.error.log info;
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
try_files $uri/index.html $uri @puma;
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;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 10M;
keepalive_timeout 10;
}
# This is the configuration for port 443 (HTTPS)
server {
listen 443 ssl;
# Update this
server_name example.com;
# Don't forget to update these, too.
# I like to update my log files to include 'ssl' in the name.
# If there's ever any need to consult the logs, it's handy to have HTTP and HTTPS traffic separated.
root /home/user_name/apps/app_name/current/public;
access_log /home/user_name/apps/app_name/current/log/nginx.ssl.access.log; # Updated file name
error_log /home/user_name/apps/app_name/current/log/nginx.ssl.error.log info; # Updated file name
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
try_files $uri/index.html $uri @puma;
location @puma {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# This is an important line to help fix some redirect issues.
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://puma;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 10M;
keepalive_timeout 10;
# The following is most likely added by Certbot. Simply copy that config over to here.
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
# If you chose Certbot to redirect all traffic to HTTPS, this will be in your current config.
# Remove it or you'll run into redirection errors:
# server {
# if ($host = example.com) {
# return 301 https://$host$request_uri;
# } # managed by Certbot
#
#
# listen 80 default_server deferred;
# server_name example.com;
# return 404; # managed by Certbot
# }
Don’t forget to update your local nginx.conf
file as well if it’s part of your deployments.
Once done, save it and let’s test to make sure it’s working:
Production Server Terminal
sudo nginx -t
If everything succeeds, reload the Nginx config:
Production Server Terminal
sudo systemctl reload nginx
Now simply deploy your new changes and everything will work!
If you run into a "Redirection" error, it's most likely due to Certbot and Rails fighting trying to redirect all traffic to HTTPS (port 443). Make sure your nginx.conf
file isn't redirecting.