Read more

Creating a self-signed certificate for local HTTPS development

Arne Hartherz
January 17, 2024Software engineer at makandra GmbH

Your development server is usually running on an insecure HTTP connection which is perfectly fine for development.

Illustration online protection

Rails Long Term Support

Rails LTS provides security patches for old versions of Ruby on Rails (2.3, 3.2, 4.2 and 5.2)

  • Prevents you from data breaches and liability risks
  • Upgrade at your own pace
  • Works with modern Rubies
Read more Show archive.org snapshot

If you need your local dev server to be accessible via HTTPS for some reason, you need both a certificate and its key. For a local hostname, you need to create those yourself.
This card explains how to do that and how to make your browser trust the certificate so it does not show warnings for your own certificate.

Easy: self-signed certificate

To just create a certificate for localhost, you can use the following command.

openssl req \
  -x509 \
  -nodes \
  -days 10000 \
  -newkey rsa:2048 \
  -keyout development.key \
  -out development.crt \
  -subj "/CN=localhost"

This generates a development.crt certificate file and development.key key file.
Note that the certificate will be valid for 10000 days, just because we don't want to do this again in a month or a year.

Next, start your application server for HTTPS. For a Rails application with Puma:

bin/rails server -b 'ssl://0.0.0.0:3000?key=development.key&cert=development.crt'

You can then access your application at https://localhost:3000/. Your browser will complain about the self-signed certificate, but you can ignore the warning in that case, since you are connecting to your own machine.

Advanced: certificate with a custom CA for browser support

To make browser warnings go away, your browser needs to trust the certificate like it trusts any other certificate.
It wants to trust the CA (certificate authority) that signed the certificate, so you need to provide one.

While you can add exceptions for single certificates fairly easily in Firefox, that is not possible in e.g. Chrome or other Chromium-based browsers.

So, here is what we need to do:

  1. Create a custom CA key and certificate.
  2. Create a certificate for our local domain, and sign it with the CA's key.
  3. Import the CA's certificate into the browser and trust it.

Then, just start your application server like above. Your browser will no longer complain about the certificate.

For the following example, we assume that you are using a locally-resolving DNS entry, like daho.im, vcap.me, or lvh.me.
Doing that has its advantages but means we also want/need to generate a wildcard certificate (if visiting subdomains like myapp.daho.im).

Note that the commands below specify daho.im and/or *.daho.im. Adjust, if necessary.

Step 0: Create SAN extension configuration

This is required if you want a wildcard certificate for your local hostnames so that you can access daho.im as well as any subdomain, like app.daho.im.
If you want to keep using localhost, skip this step and omit the command arguments which reference this file.

printf "[req]\ndistinguished_name=req\n[SAN]\nsubjectAltName=DNS:*.daho.im,DNS:daho.im" > development-san.cnf

Step 1: Create a custom CA

openssl req \
  -new \
  -x509 \
  -nodes \
  -days 10000 \
  -newkey rsa:2048 \
  -keyout development-ca.key \
  -out development-ca.crt \
  -subj "/CN=daho.im Development CA"

Step 2: Create your certificate, and sign it with your custom CA

openssl req \
  -new \
  -nodes \
  -newkey rsa:2048 \
  -keyout development.key \
  -out development.csr \
  -subj "/CN=*.daho.im" \
  -config development-san.cnf
openssl x509 \
  -req \
  -in development.csr \
  -CA development-ca.crt \
  -CAkey development-ca.key \
  -CAcreateserial \
  -out development.crt \
  -days 10000 \
  -extensions SAN \
  -extfile development-san.cnf

If you skipped step 0, omit -extensions SAN and the arguments referencing development-san.cnf.

You'll now have several files in your working directory, but you only need 3 of them:

  • development.crt your certificate
  • development.key its key (your local server needs it as well as the certificate)
  • development-ca.crt the CA's certificate; you need to import it into your browser.

You should remove the other files since you don't need them, especially the CA key, unless you are absolutely sure you want to sign other certificates using it. (You don't want to.)

rm development-ca.key
rm development-ca.srl
rm development-san.cnf
rm development.csr

Step 3: Import the CA certificate into your browser

Chrome, Edge, and other Chromium browsers

Go to chrome://settings/certificates, switch to "certificate authorities", and import development-ca.crt (not development.crt). Choose to trust the CA to sign websites.

Firefox

In Firefox, open the settings, navigate to the security item and find the certificates section.
Click to manage certificates, and in the certificate authorities tab, import development-ca.crt and choose to trust the CA to sign websites.

Done.

That's it. Now start your application server with HTTPS like described earlier (bin/rails server -b 'ssl://0.0.0.0:3000?key=development.key&cert=development.crt') and visit https://app.daho.im:3000/ Show archive.org snapshot . There should be no certificate warnings or similar.

Arne Hartherz
January 17, 2024Software engineer at makandra GmbH
Posted by Arne Hartherz to makandra dev (2024-01-17 10:01)