Thumbnail saying, "Rails Dev SSL" with a picture of the HTTPS lock on a phone.

HTTPS Certificates for LocalHost with Ruby on Rails 7

HTTPS with LocalHost is a Pain!

In an era where security is paramount, the use of HTTPS (Hypertext Transfer Protocol Secure) over HTTP is becoming more and more ubiquitous. HTTPS provides encryption, data integrity, and authentication, ensuring that your application’s data remains secure during transit between the client and the server. However, when working on a local development environment – localhost – it’s common to see developers bypassing HTTPS and opting for HTTP instead. While this might seem like an insignificant detail during development, it can lead to unexpected issues when transitioning to production where HTTPS is typically enforced.

One might ask, “Why do I need an HTTPS certificate for localhost?” The answer is twofold. First, using HTTPS from the start, even in your local development environment, helps avoid potential surprises when deploying your application. It ensures consistency between your development and production environments. Second, it allows you to test features that require HTTPS, like Service Workers, HTTP/2, and more, right from your local setup.

Now, you might have noticed that different browsers handle HTTPS on localhost differently. If you’ve used Firefox, you may not have run into any issues with untrusted certificates on localhost. However, if you’re a user of Chromium-based browsers like Google Chrome or Microsoft Edge, you’ve likely found that they don’t support untrusted certificates for localhost. This is due to a specific design decision by the Chromium team aimed at enhancing security. While Firefox takes a more lenient approach to localhost, allowing developers to add exceptions for untrusted certificates, Chromium browsers enforce stricter security measures. This means that, without a valid certificate, your site on localhost might not function as expected in a Chromium browser.

Video Tutorial

This video tutorial covers essentially the same content as this blog post. If you prefer learning through video, then this YouTube tutorial on setting up HTTPS certificates for localhost with Ruby on Rails 7 might be for you. If you’ve been grappling with browser inconsistencies, or you’ve encountered some unexpected surprises when transitioning from your local development environment to production, then you’re in the right place.

In this tutorial I walk you through the same topics as the blog post in order to get you up and running with a Firefox supported solution. Chromium browsers can be a bit more difficult, since they prefer to require stricter security with the development certificates. That’s why I usually keep my HTTPS specific testing in development on Firefox, and use Chromium when those features aren’t required.

Step 1 - Creating A Simple Rails App

I typically prefer to teach from a blank canvas. So let’s start by creating a new Rails 7 app and generating a pages controller with a home action. We can then set this as the root of our application. This allows us to both have a familiar point of reference for the rest of this tutorial, so that translating these steps into your applications doesn’t require understanding my spaghetti code of a tech stack.

				
					# We name the project "tutorial"
rails new tutorial
cd tutorial

# Create the controller
rails g controller pages home

# Open up the codebase in VS Code.
code .

				
			
				
					# config/routes.rb
Rails.application.routes.draw do
  root "posts#index"
  resources :posts
  # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html

  # Defines the root path route ("/")
  # root "articles#index"
end
				
			

Step 2 - OpenSSL & Generating HTTPS Certificates

Now that we have a simple application, we can move onto setting up HTTPS. We start by ensuring the system has OpenSSL installed. Then we can use OpenSSL to generate a “localhost.crt” and a “localhost.key” file. We then move these files into a new directory inside of our config directory. This allows us to keep the keys in a consistent location so we can later tell Puma where to find them. 

				
					# Install OpenSSL if it isn't already installed (Assuming you use Apt)
sudo apt install openssl

# Generate the SSL Certificates
openssl req -x509 -sha256 -nodes -newkey rsa:2048 -keyout localhost.key -out localhost.crt -subj "/CN=localhost" -days 365

# Make the SSL directory
mkdir config/ssl

# Move the files to config/ssl
mv localhost.key localhost.crt config/ssl/

				
			

Step 3 - Running the Server

Finally we have two options. We can either run the server now with a longer command, or hack our puma file to run Rails with the traditional, “rails s” command. I’ll show you the command first, and then what you should add to your config/puma.rb file.

				
					# Running the server the long way by specifying both files
rails s -b "ssl://localhost:3000?key=config/ssl/localhost.key&cert=config/ssl/localhost.crt"


				
			

If you prefer to just use, “rails s” then this section is for you. Instead you’ll be opening up your puma.rb and allowing it to run two servers. One for HTTP connections and another for HTTPS. So now you can access both https://localhost:3001 and http://localhost:3000

IMPORTANT!

Notice that the HTTPS server is on port 3001 because of our config. Don’t try to access https for port 3000, or http for port 3001. It won’t work with this configuration!

				
					# config/puma.rb

#...rest of file...

# At the bottom, we add these lines
ssl_bind '0.0.0.0', '3001', { 
    key: ENV.fetch("SSL_KEY_PATH") { 'config/ssl/localhost.key' },
    cert: ENV.fetch("SSL_CERT_PATH") { 'config/ssl/localhost.crt' }
 }
				
			

Conclusion & Summary

The implementation of HTTPS in a local development environment or localhost can often be a source of confusion and unexpected issues. As we’ve discussed in this post, using HTTPS from the onset of your project not only helps maintain consistency between development and production environments but also enables you to test features that necessitate HTTPS right in your local setup.

Different browsers handle HTTPS on localhost in varying ways. Firefox, for example, allows exceptions for untrusted certificates, while Chromium-based browsers enforce stricter security measures due to their design philosophy. This difference can sometimes lead to your local site not functioning as expected in Chromium browsers without a valid certificate.

We’ve also explored how to create a simple Rails 7 app and set up HTTPS using OpenSSL to generate “localhost.crt” and “localhost.key” files. These files are then placed in a dedicated directory within our config directory. Finally, we’ve shown you how to run your server using a command that includes these files, or you can modify your config/puma.rb file to have Rails run two servers, one for HTTP and another for HTTPS connections.

Remember, if you’re using the latter configuration, HTTPS is accessed on port 3001, and HTTP is on port 3000. It’s crucial not to mix these up!

Whether you prefer a written guide or a video tutorial, we’ve got you covered. The aim is to help you navigate these technical waters smoothly, and we hope that you now feel more equipped to set up HTTPS certificates for localhost with Ruby on Rails 7.

Remember that while setting up HTTPS with localhost can seem challenging, especially when dealing with browser inconsistencies, it’s a necessary step to ensure the security and integrity of your application. Keep experimenting, keep learning, and happy coding!

Share this post

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.