I've recently been playing with Docker, getting to grips with what it can do, and increasingly trying to adapt all my side projects to make full use of it. I have a Docker swarm running on my increasingly growing collection of Raspberry Pi's, and each of my apps managed through a docker-compose.yml
file.
One of the initial issues I had, was that I had to access each of these apps on different ports. Since this was running within my home network, I also had to open the port on my router and forward the traffic to the Pi's IP on my network. This didn't feel very secure, and it also meant I couldn't add an SSL certificate.
Then I stumbled across Traefik. At its core, Traefik is just a reverse HTTP proxy and load balancer, but what makes it really powerful is that it can integrate with other infrastructure components, such as Kubernetes, Amazon ECS, and in my case, Docker (including Swarm mode).
Traefik can automatically watch your Docker processes, when it finds one with the necessary labels, it'll automatically setup the routing for it, and can provision an SSL certificate for the domain, or use a wildcard certificate if it's been generated already. If you're running if swarm mode, it can load balance all the traffic between the nodes in a variety of methods, and automatically take a node out of the pool if it becomes unhealthy.
Traefik has made my setup much more secure, now I can set up a wildcard DNS record to point all subdomains to my machine, and I just need the 2 ports open on my router, 80
and 443
, with a letsencrypt certificate securing it.
The config for Traefik is relatively simple, a basic docker-compose.yml
file like the following is enough to get it up and running:
version: '3'
services:
traefik:
image: traefik:latest
restart: always
environment:
- DO_AUTH_TOKEN=secret_token
ports:
- 80:80
- 443:443
networks:
- home_proxy
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./traefik.toml:/traefik.toml
- ${PWD}/acme.json:/acme.json
deploy:
replicas: 1
placement:
constraints:
- node.hostname == HomeServer1
labels:
traefik.backend: "traefik"
traefik.enable: "true"
traefik.frontend.rule: "Host:proxy.myhomedomain.com"
traefik.port: "9002"
traefik.docker.network: "home_proxy"
# This bit is important, all Docker containers must be on the same network to be accessible to Traefik.
networks:
home_proxy:
external: true
and the following traefik.toml
file manages the configuration:
logLevel = "INFO"
defaultEntryPoints = ["https","http"] # Accept traffic over both protocols
[file]
[entryPoints]
[entryPoints.http]
address = ":80" # Listen on 80 for HTTP traffic
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":443" # Listen on 443 for HTTPS traffic
[entryPoints.https.tls]
[entryPoints.traefik]
address = ":9002" # Listen on 9002 for the Traefik dashboard UI
[retry]
[docker]
endpoint = "unix:///var/run/docker.sock" # Use this socket to monitor the docker processes
domain = "myhomedomain.com" # The domain this swarm is running on
watch = true # Watch for changes
swarmMode = true # Use Docker Swarm
exposedByDefault = false # Don't add all processes by default, only those with the enable label
[acme]
email = "myemail@address.com" # Email address to send letsencrypt notifications to
storage = "acme.json" # Store the certificates in this file
entryPoint = "https"
onHostRule = true
[acme.dnsChallenge]
provider = "digitalocean" # Use digitalocean as the DNS provider
[[acme.domains]]
main = "*.myhomedomain.com" # Generate a wildcard certificate for this domain
[api]
entryPoint = "traefik"
To enable a docker process for use in Traefik, you just need to add the following labels to your compose file:
version: '3'
services:
minio:
image: minio/minio:RELEASE.2019-02-20T22-44-29Z
restart: always
labels:
- "traefik.enable=true" # Enable in Traefik
- "traefik.frontend.rule=Host:minio.myhomedomain.com" # Route traffic from this hostname
- "traefik.port=9000" # To this container port
networks:
- home_proxy
networks:
home_proxy:
external: true
Here's a quick list of some of the things I have running on my swarm network: