Creating TLS Certificates for Local Development

Some will argue we don’t need to use TLS in local development. For some, that may be true. However, I have found in the projects I have been on over the years, that when devs aren’t developing with TLS enabled, odd issues crop up in either in testing (with TLS) or in production that could easily have been caught early. If you are authenticating with an OpenId Connect provider, depending on the provider, your app needs to be using TLS. I personally always use TLS in local development if production will require TLS.

Using TLS in our local development environments means we need a certificate. There are a few ways we can do this. If you are using dotnet like I am, Microsoft has built creating a development cert into the SDK:

dotnet dev-certs https 

Or you can create certs using openssl. This approach is a bit more involved, requires several steps, and manual deployment of the certs to their appropriate stores.

In the past, I’ve used CertificateTools.com to create dev certs. I like that this site not only give you the cert(s), but also the openssl commands and config it used so you can make scripts for your dev team.

Then I was introduced to mkcert. It uses openssl under the hood but not only simplifies the creation of the cert but also deploys them to the appropriate store. It is my new favorite way to create local dev certs. Let’s take a look.

You can find mkcert on GitHub at https://github.com/FiloSottile/mkcert

Step 1. Install the tool

I use Ubuntu, so to install on my system…

sudo apt install mkcert libnss3-tools

…the GitHub readme has instructions for other operating systems.

Step 2. Install the Certificate Authority

‘mkcert’ uses a certificate authority to sign any dev certs. This makes your local environment more like a real production environment. I’ve run into issues where validating a certificate chain failed in production and wasn’t caught earlier because dev and QA were using self-signed certs.

To install the certificate authority (CA) used to sign our certificates…

mkcert -install

Step 2. Create your certs

Now we are ready to create certs! It couldn’t be easier. Just pass mkcert the subject name(s) for the certificate you want to create…

mkcert app.localhost

.localhost TLD

Issues can also be missed in a local dev environment when every deployed component of your application is running on “localhost”, especially around things like CORS and SAME-SITE/SAME-ORIGIN with cookies and iframes.

I used to create dummy DNS entries in my /etc/hosts file like: db.example.com, app.example.com, idp.example.com so that configuration was more like a production setup and I could ensure things like CORS and cookies are working correctly.

But no more! In modern operating systems we have the .localhost top level domain as defined in RFC 6761.

The .localhost top level domain (TLD) is supported by Windows, MacOS, and Linux. The local resolver will automatically resolve any host or host.subdomain of .localhost to 127.0.0.1–the local loopback address without the need to add entries to your /etc/hosts file.

Try it for yourself, ping an arbitrary host using that domain. You will see it resolve and successfully ping 127.0.0.1…

ping app.localhost

Putting the two together, you can create certificates for specific apps you are building and get more production-like behavior.

Conclusion

While we don’t always need TLS locally, in some cases, it is beneficial. mkcert takes the pain away. Using the .localhost top-level domain allows us to ensure our app works locally when dealing with things like CORS and SAME-SITE/SAME-ORIGIN.