Local HTTPS Dev Proxy Using Lets Encrypt and Cloudflare

As a first step of switching over to a DNS based process for maintaining Lets Encrypt certificates, I opted to start with upgrading my local environment as I do some tinkering with Kubernetes and thus end up with quite dynamic endpoint urls. The primary reason though is to enable wildcard certificates as Lets Encrypt only support these using the DNS method.


As I currently do some Kubernetes based labs, I’ve also looked into the Traefik reverse proxy. The most obvious options are otherwise nginx and HAProxy, as demonstrated in my previous setup based on nginx, but Traefik belong to a new breed of easy to use and MSA oriented components. Compared to the aforementioned options, Traefik is still young and does lack production history as well as the best-of-breed performance figures.

So back to Lets Encrypt certificates. This setup is designed to run as a local Docker container, proxying all HTTP/s requests to other services, be them Dockerized or not. An integration to my DNS provider is setup to add appropriate DNS records for each new unique host name which Lets Encrypt uses to validate my domain ownership. Thus I avoid having to expose an external facing web host just to create local certificates. I will though setup a proper externally facing reverse proxy, however that is on my backlog for now.

So the moving parts in this setup is the actual Docker container containing Traefik, configuration of my DNS provider (Cloudflare), configuration of my local DNS (Windows Server), and some settings in the local configuration file for Traefik. You will need an existing account with LetsEncrypt of course.

I’m using the base Docker setup by SIL International and forked into my own repository (

GitHub project

I’ve create a quickstart project on GitHub which provides a docker-compose.yml file and a sample configuration file. Clone to a local directory and it can be run as is, after properly configuring the local settings.

I’ve created and published a public image at Docker Hub ( which is referenced from the docker-compose file.

Rename the local.env.example file by dropping the “.example” and fill in the settings.


This is a basic docker-compose file, using the published image.

In the same directory where the docker-compose.yml file exists, type “docker-compose up -d” (-d is for daemon) to start the Traefik instance. It will proxy all HTTPS requests on port 443 to whatever matches according to the local configuration file above.

  1. Provide your own custom traefik configuration file if you have more advanced needs and uncomment the mapping entry and provide your own Traefik configuration.

The LetsEncrypt certs and meta data are stored in the local certs folder.


TLD is your base domain
SANS is your comma separated list of hosts
BACKEND#_URL is your internal url to the backend service from the proxy
FRONTEND#_Domain is your DNS host name to proxy

This is the basic template based approach, but you can also use your own custom Traefik configuration, just point to the correct .toml configuration in your docker configuration in the docker-compose file as described above.

DNS setup - Cloudflare

I’m using Cloudflare for my public DNS needs. I do run a split scenario with an internal DNS server as well and I have configured a wildcard entry on both my internal and public DNS.

I need to configure API access to Cloudflare DNS in order for Traefik being able to dynamically create records for LetsEntrypt to query.

To do that, go into My Profile - API Keys.

Copy your global API key and enter it in your local local.env file for parameter CLOUDFLARE_API_KEY

Provide all details for accessing Cloudflare

When properly enabled, Traefik kan control you DNS entries at Cloudflare and thus create temporary records similar to this. These are only to validate with LetsEncrypt that you have control of the domain.

Configuring the DNS entries

Chose a hostname to use, in my case I have defined which points to my localhost endpoint. You could define a wildcard entry as shown above, which would send all non-defined hostnames to whatever ip you have defined.

Test it out

Navigate to your local url, in my case it is which points to The host-header is translated into the proper backend mapping in Traefik. In this test I’m forwarding to a local Proget instance.