This setup log describes and records the process I completed to configure reverse proxying with SSL certificates for my internal selfhosted services.
DNS setup
Static IP
I will be hosting my reverse proxy using Docker, which is running in an LXC within Proxmox. This Docker host must have a static IP, which will be referenced by the domains configured with certificates in following steps. All configuration is performed from the docker user on this LXC, an unprivileged member of the docker group.
I created the LXC, and added the default adapter’s MAC address to my router’s DHCP lease reservations as 192.168.1.200.
DNS forwarding
Although DNS entries for the IP configured above could be added as CNAME records in the DNS provider’s dashboard (Cloudflare in my case), I opted to configure my local DNS forwarder instead to keep all requests internal.
On EdgeOS, as in the case of my Edgerouter X, the following commands can be used to add forwarding for all subdomains to dnsmasq, the provider of DNS forwarding. As I am already using dnsmasq to forward requests to external nameservers when needed, adding additional configuration was a minor change.
configureset service dns forwarding options 'address=/athome.rodeo/192.168.1.200'
This will resolve a.athome.rodeo, a.b.athome.rodeo, ... to the IP address on which my reverse proxy is running.
NOTE
If adapting this configuration to your own environment, be sure to modify any IP addresses, domains, and file paths/usernames where appropriate. This applies to configuration files, as well as commands.
Traefik setup
I used the following three configuration files to setup Traefik on the Docker host configured as the endpoint for my newly forwarded domain. As I am also using Portainer for container management, the docker-compose.yml file was used to create a stack within it. The starting point for these configuration files was adapted from the reference published here.
Folder configuration
To use the absolute paths specified below, create the following files and folders as the docker user on the Docker host:
cd ~mkdir -p config/portainer/datamkdir config/traefikcd $_touch acme.jsonchmod 600 acme.json
Create the remaining files included below in the same ~/config/traefik/ directory.
Explicitly setting external resolvers for the DNS challenge prevents the local network DNS forwarding configured previously from interfering with requests associated with certificate management. This may not be necessary if configuring DNS through e.g. a registrar’s dashboard.
If using Portainer, environment variables can be defined when creating a stack with the Docker compose file, so the API token could be varied between deployments, rotated easily, etc.
The docker-compose.yml above requires a Cloudflare API token (CF_DNS_API_TOKEN), which can be created from the Cloudflare dashboard →My Profile → API Tokens → Create Token. The token requires these scopes:
Zone / Zone / Read
Zone / DNS / Edit
Select the zone(s) which will be used as domain(s) for internal services. An email and API key can be used instead, but will be granted less restrictive access to your Cloudflare account.
Basic auth password
With the above configuration, Traefik, uses HTTP basic auth when accessing the dashboard. Generate a password hash using htpasswd, as recommended in the docs:
sudo apt install apache2-utilshtpasswd -nB <username> | sed -e s/\\$/\\$\\$/g
Any references to $ are escaped by doubling them to $$ via sed. When evaluated, this results in a single $ in the Docker label.
Paste the htpasswd output, including the username, in the traefik.http.middlewares.traefik-auth.basicauth.users config key in docker-compose.yml.
Keep the original output format of user:hash, e.g. reed:$$apr1$$fakehash$$somehashtext. Multiple user:hash combinations may be supplied, comma-separated, with no spaces. See here for a full reference.
Starting service
Creating network
Prior to creating the Traefik container with docker compose (or Portainer), the network proxy must be created. As the compose specifies this as an external network, Docker expects it to already exist and will not create it.
To create the network using Docker, run:
docker network create proxy
To create the network in Portainer, use the Networks list. All options may be left as default, with the name set to proxy.
Starting
Once the proxy network has been created, run the Docker compose file with docker, by creating a Portainer stack, etc.
At this point, the Traefik dashboard should be available (behind basic auth using the credentials created above) at the domain configured in compose file labels. In my case, this is at https://traefik.athome.rodeo.
No valid certificate on the dashboard?
If the dashboard is still using the Traefik default certificate and a provider has been correctly configured, the permissions on the storage file may be too open. Set the file permissions for /home/docker/config/traefik/acme.json (if using the config above) to 600.
Adding new entries
Here is an example of a Docker compose file to deploy Portainer behind Traefik:
Next, access Portainer at port 9443, create an account, and create a Traefik stack using the relevant files. Once this has started, stop the portainer container. Recreate it from the compose file above using docker-compose up --force-recreate -d, at which point Portainer will be available behind Traefik, but the latter can still be managed from within Portainer.