Skip navigation

Effective October 28, 2019 Duo Security will be transitioning to Cisco's Privacy Statement. View the Duo Privacy Data Sheet.

Nick Mooney

Nick Mooney

Security R&D Engineer

Nick Mooney is a Security R&D Engineer at Duo Security as part of the Duo Labs team. Prior to arriving at Duo, Nick studied Computer Science at the University of Washington in Seattle. Outside of security research, Nick is passionate about boats, islands, and youth outdoor/wilderness education.

Local HTTPS Development

Nick Mooney January 30th, 2019 (Last Updated: January 30th, 2019)

01. Context

I wanted to run the Docker container locally, but I needed it to be served via HTTPS. The container serves up the demo site via HTTP.

This can be challenging since CAs will not issue certificates for localhost, but fortunately, Filippo Valsorda wrote a tool called mkcert that solves this problem.

We can use mkcert in tandem with Caddy to host a local HTTPS service.


mkcert works by installing a local CA in the system root store, and then allowing you to issue certificates against arbitrary domains that are signed by that CA. This means you can get browser-trusted certificates for localhost,, etc.

02. Setting it all up

I navigated to the directory before performing the following.

brew install mkcert
mkcert -install


mkdir tls; cd tls
mkcert localhost
cd ..

Docker config

You can set up the containers manually, but I prefer having a docker-compose.yml that will do it for me.

version: '3.2'

		build: .
			- "9005:9005"
		image: abiosoft/caddy
			- "443:443"
			 - "./tls:/srv/tls"
			 - "./Caddyfile:/etc/Caddyfile"


I put the following in ./Caddyfile.

https://localhost:443 {
	proxy / webauthn:9005 {
		fail_timeout 0s
	tls /srv/tls/localhost.pem /srv/tls/localhost-key.pem

Notice that I don’t have to use an IP in the proxy directive, I can just use the name of the target service that I defined in docker-compose.yml.

03. Running it

Just issue docker-compose up. You should now be able to navigate to https://localhost.