This is a rundown of how my local web development environment on macOS uses Traefik as a reverse proxy to route traffic to Docker containers over HTTPS. I created this for my own reference since I am not an expert, but hopefully it can help someone else and maybe find some suggested improvements.
Note: This guide was originally created using an Intel Mac, but some changes and additions were made after switching to Apple silicon. Exact file paths or steps may very between platforms.
- Reverse proxy for local Docker containers
- Fixes browser certificate warnings
- Automatically redirects http traffic to https
We will be using Dnsmasq to make sure all domains using the .test
TLD are pointed at our local machine and Traefik can handle the requests. We could use 127.0.0.1
as our target and everything will work fine on our host, but when we try to resolve a .test
domain from inside a container 127.0.0.1
will refer to the current container. To solve this we can create a loopback interface and use that IP.
- Install Dnsmasq using
brew install dnsmasq
on the host machine. - Start the service using
sudo brew services start dnsmasq
- Open the config file at
/opt/homebrew/etc/dnsmasq.conf
and uncomment the line#conf-dir=/opt/homebrew/etc/dnsmasq.d/,*.conf
near the end of the file. - Next we will configure Dnsmasq to point all domains using our
.test
TLD to10.254.254.254
. To do this create a file at/opt/homebrew/etc/dnsmasq.d/development.conf
with the contentsaddress=/.test/10.254.254.254
- Run
sudo ifconfig lo0 alias 10.254.254.254
to create an IP address alias (note: this will not persist across a reboot, so here is a potential solution) - Restart dnsmasq using
sudo brew services restart dnsmasq
- Confirm everything works so far by running
dig foobar.test @127.0.0.1 +short
. The output should match the alias we created. - Now we need to add a resolver. Create a directory using
sudo mkdir /etc/resolver
that will contain our resolver. Then create a file namedtest
(the name corresponds to our.test
TLD) with the contentsnameserver 127.0.0.1
- Confirm everything is set up using
ping -c 1 foobar.test
- Create a Docker network named "web" by running
docker network create web
- After you've configured your projects and set up your
dynamic_conf.yml
with the appropriate certs, rundocker-compose up -d
to start Traefik - The Traefik dashboard should now be visible at http://localhost:8080
For a container to be accessible to Traefik, we will be adding it to the "web" Docker network we created. We should also assign it to the "default" network if we want to connect to other containers (like a database) in the same project.
We will also need to add labels so that Traefik knows how to route traffic. Use the name of the project as our router name.
These can be added directly to our docker-compose.yml
file or to a docker-compose.override.yml
file if preferred.
services:
webserver:
networks:
- default
- web
labels:
- "traefik.enable=true"
- "traefik.http.routers.${ROUTER_NAME}.tls=true"
- "traefik.http.routers.${ROUTER_NAME}.rule=Host(`projectdomain.test`)"
- "traefik.http.routers.${ROUTER_NAME}.entrypoints=websecure"
- "traefik.docker.network=web"
- "traefik.http.services.${ROUTER_NAME}.loadbalancer.server.port=80"
networks:
web:
external: true
- Ensure mkcert is installed by running
brew install mkcert
as well asbrew install nss
if you use Firefox - Create local CA by running
mkcert -install
- Change into
certs
directory - Run
mkcert mydomain.test
ormkcert "*.mydomain.test
for a wildcard - Create
dynamic_conf.yml
by switching back to the root directory and runningcp dynamic_conf.example.yml dynamic_conf.yml
and then making the necessary changes
# Dynamic configuration
tls:
certificates:
- certFile: "/etc/traefik/certs/mydomain.test.pem"
keyFile: "/etc/traefik/certs/mydomain.test-key.pem"
- certFile: "/etc/traefik/certs/_wildcard.mydomain.test.pem"
keyFile: "/etc/traefik/certs/_wildcard.mydomain.test-key.pem"
Because our CA is on our host machine, we'll need to add it to any containers that connect to another via a secure URL using one of our generated certificates. The exact Dockerfile changes needed may vary based on the image, but this example seems to work on Ubuntu.
- Run
mkcert -CAROOT
in terminal to find the location of our CA - Copy
rootCA.pem
from this location into our build directory - Add the following to our Dockerfile to install the CA into the image
COPY rootCA.pem /usr/local/share/ca-certificates/rootCA.crt
RUN chmod 644 /usr/local/share/ca-certificates/rootCA.crt && update-ca-certificates;
Thanks to the authors of these articles that helped me scrape this together.