Configuring Rails and Vite to use HTTPS in local development

The localhost gem does most of the heavy-lifting.

By default, when Rails starts a server in development, it listens on localhost:3000 using regular HTTP. To more closely simulate a production scenario, I wanted to configure my Rails app to use HTTPS instead. Here’s how that works.

Install the localhost gem

Rails uses the puma web server, which is capable of serving HTTPS as long as it is provided an appropriate private key and certificate. This is where the localhost gem comes in.

The localhost gem integrates directly with puma to generate a key and certificate; it then makes those available to puma during the startup process.

group :development do
  gem "localhost"
Add the localhost gem and run bundle install.

Start the Rails server with ssl specified

Even with the localhost gem installed, Rails will still default to HTTP on port 3000 unless told otherwise. To instruct Rails to use HTTPS, I start Rails like this:

bin/rails s -b ssl://localhost:4000
Start the Rails server using HTTPS on port 4000.

Trust the certificate

The first time visiting https://localhost:4000, the browser will complain about an untrusted certificate. This is because the certificate generated by the localhost gem is self-signed.

Google Chrome showing a “your connection is not private” error

Browser setup

The specifics are different for each browser, but generally speaking, I needed to dismiss the security warning and add the certificate to the operating system’s registry to avoid future warnings. It takes just a few clicks, following these guides:


In addition, in case I need to use Ruby to make HTTPS connections to localhost, it is a good idea to make OpenSSL was aware of the certificate as well. An explanation can be found on Stack Overflow, but to make a long story short:

$ cp ~/.localhost/localhost.crt /usr/local/etc/openssl@3/certs/
$ /usr/local/opt/openssl@3/bin/c_rehash
Run these two commands to make OpenSSL – and by extension, Ruby – trust the localhost self-signed certificate. On an Apple Silicon Mac, the paths may start with /opt/homebrew instead of /usr/local.

Configure the vite dev server to use HTTPS

With Rails now using HTTPS, I needed to configure Vite to use HTTPS as well, if I wanted hot-reloading to work seamlessly in the browser. Whereas the localhost gem magically passes its key and certificate to puma, with Vite I needed to be more explicit:

import { defineConfig } from "vite";

import { existsSync, readFileSync } from "node:fs";
import { resolve } from "node:path";
import { homedir } from "node:os";

const certPath = resolve(homedir(), ".localhost/localhost.crt");
const keyPath = resolve(homedir(), ".localhost/localhost.key");
const https = existsSync(certPath)
  ? { key: readFileSync(keyPath), cert: readFileSync(certPath) }
  : {};

export default defineConfig({
  plugins: [
    // ...
  server: { https },
Specify server.https using key and certificate generated by the localhost gem.

The vite_ruby config needed to be updated as well:

"development": {
  "autoBuild": true,
  "https": true,
  "publicOutputDir": "vite-dev",
  "port": 3036
Add "https": true to the development settings.

Disable HSTS if using force_ssl in development

With everything working, I was tempted to set config.force_ssl=true in my Rails development config to further simulate a production environment. However, this caused problems because it enables HSTS by default. Once my browser saw the HSTS header, it now required all apps hosted on my machine to use HTTPS. That’s a bit more than I bargained for!

To prevent security restrictions from one app spilling over onto other apps, I recommend turning off HSTS (in development only):

config.force_ssl = true
config.ssl_options = {hsts: false}
If using force_ssl=true in development, consider turning off HSTS.
You just read

The localhost gem does most of the heavy-lifting.

May 2023

Share this post?  Copy link

About the author

Hi! I’m a Ruby and CSS enthusiast, regular open source contributor, software engineer, and occasional blogger writing from the San Francisco Bay Area. Thanks for stopping by! —Matt

GitHub Email LinkedIn