Traefik
Traefik is an open source HTTP reverse proxy and load balancer written in golang. It can be integrated into various infrastructures such as Docker and Kubernetes or used as a standalone service. Traefik comes with lots of automation features such as dynamic configuration through container labels and automatic SSL certificate renewals using the ACME protocol.
Docker integration
Traefik can be used as the reverse proxy for all web-related services on a Docker host. The added benefit with this approach is that new web services that are added can be automatically configured through docker labels and SSL certificates are automatically obtained provided that the DNS names already resolve.
Extra care is required when using Traefik and Docker since Traefik needs to have access to the Docker socket in order to see container events for its automatic configuration. Since having access to the Docker socket is pretty much equivalent to owning the Docker host, from a security stand-point, it's best to have an intermediate Docker container proxy the Docker socket so that it can only be read from but not written to. More on this set up below.
Setting up Traefik with Docker Compose
Create a new 'traefik' Docker network. This network will be used by any other containers on the host that needs to be reverse proxied by Treafik.
# docker network create traefik
Next, we will set up the Traefik docker-compose stack. Traefik should be configured to work with Docker. We'll also restrict Traefik from exposing containers unless they are explicitly labeled. Review the Traefik Docker documentation for all the available Docker related options.
Included here is the socket-proxy which we'll use to restrict what Traefik can do to Docker in case it gets compromised.
version: '3.3'
services:
traefik:
image: traefik:latest
restart: always
command: --web --docker --docker.watch --docker.exposedbydefault=false --providers.docker.endpoint=tcp://socket-proxy:2375
volumes:
- ./config/traefik.yml:/traefik.yml
- ./config:/config
- /var/log/traefik:/var/log/traefik
networks:
- traefik
- internal
environment:
- "TZ=MST7MDT,M3.2.0,M11.1.0"
ports:
- "80:80"
- "443:443"
# https://github.com/Tecnativa/docker-socket-proxy
socket-proxy:
build:
context: ./socket-proxy
dockerfile: Dockerfile
restart: always
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
CONTAINERS: 1
networks:
- internal
expose:
- "2375"
networks:
internal:
traefik:
name: traefik
external: true
Bring the entire stack up and when everything comes up, you're done.
# docker-compose up -d
Using Traefik with your Docker containers
With the the Traefik container set up, we can now create containers to take advantage of Traefik as the ingress controller for the Docker host. This can be done through just container labels. Containers should be labeled with the following labels.
Description | Label (example) |
---|---|
Enable Traefik for this container | traefik.enable=true
|
Define the Docker network that Traefik needs to use to connect to this container | traefik.docker.network=traefik
|
Define a new service to this container. For example, if your container is listening on port 8888, define a new Traefik service that listens on port 8888. | traefik.http.services.my-new-service.loadbalancer.server.port=8888
|
Expose your container using the service created previously via the HTTPS entrypoint.
This will make Traefik forward HTTPS data matching your virtual host to this container. SSL certificates are handled with Let's Encrypt. |
traefik.http.routers.new-service-router-https.entrypoints=https
|
You can also expose your container via HTTP.
Be sure that your router name is distinct. |
traefik.http.routers.new-service-router.entrypoints=http
|
If you want your HTTP traffic redirected to the HTTPS version, create a new middleware that redirects to the HTTPS scheme. | traefik.http.routers.new-service-router.entrypoints=http
|
If your container exposes multiple services, you can define multiple services and routers in your labels. Just make sure things are named uniquely.
Here's the configuration for one of my test Wiki containers using Traefik.
wiki:
image: mediawiki:1.37
labels:
- traefik.enable=true
- traefik.docker.network=traefik
- traefik.http.middlewares.wiki-https-redirect.redirectscheme.scheme=https
# http
- traefik.http.routers.wiki.entrypoints=http
- traefik.http.routers.wiki.rule=Host(`wiki-test.example.com`)
- traefik.http.routers.wiki.middlewares=wiki-https-redirect
# https
- traefik.http.routers.wiki-https.entrypoints=https
- traefik.http.routers.wiki-https.rule=Host(`wiki-test.example.com`)
- traefik.http.routers.wiki-https.tls=true
- traefik.http.routers.wiki-https.tls.certresolver=letsencrypt
- traefik.http.routers.wiki-https.service=wiki-https
- traefik.http.services.wiki-https.loadbalancer.server.port=8080
networks:
- traefik
expose:
- "8080"
restart: always
Standalone setup
Traefik can be used as a standalone service to reverse proxy and do SSL termination. The example below will set up a simple reverse proxy for a local web service listening on port 8000. The SSL certificate will automatically be obtained using Let's Encrypt.
Create the following traefik.yml
configuration file at /etc/traefik/traefik.yml
:
log:
level: INFO
filepath: "/var/log/traefik.log"
accessLog:
filepath: "/var/log/access.log"
fields:
defaultMode: keep
headers:
defaultMode: keep
api:
dashboard: false
insecure: false
debug: true
entryPoints:
http:
address: ":80"
https:
address: ":443"
providers:
file:
filename: "/etc/traefik/dynamic_config.yml"
watch: true
certificatesResolvers:
letsencrypt:
acme:
email: my-email-address@example.com
storage: "/etc/traefik/acme.json"
httpChallenge:
entryPoint: http
Create a dynamic_config.yml
file at /etc/traefik/dynamic_config.yml
. This file will define our routes and backend services. You must have a separate router for each of the insecure http and secure https routes to your backend service.
http:
serversTransports:
ignorecert:
insecureSkipVerify: true
routers:
testing-http:
rule: Host(`testing.example.com`)
service: my-testing-service
entrypoints:
- http
testing-https:
rule: Host(`testing.example.com`)
service: my-testing-service
entrypoints:
- https
tls:
certresolver: letsencrypt
services:
my-testing-service:
loadBalancer:
servers:
- url: "http://127.0.0.1:8000"
Start traefik:
# traefik --web --config /etc/traefik/traefik.yml
Tasks
Add host header on requests to the backend
You can specify custom request headers by injecting a middleware. For example, when reverse proxying HTTP traffic for a website, you may wish to have the reverse proxy provide the 'Host' header. To do this, we can add the following dynamic config.
http:
routers:
public:
rule: Host(`public.example.com`)
service: public
entrypoints:
- http
middlewares:
- public
services:
public:
loadBalancer:
servers:
- url: "http://10.1.2.200"
middlewares:
public:
headers:
customRequestHeaders:
Host: "public.example.com"
Add a path prefix
To serve content under a specific path (eg. /downloads) using another container, create the service as you would normally but specify the router rule to include a PathPrefix
. Traefik can also strip out this path prefix so that the underlying server sees only the root path (eg. have /downloads/file become /file) using the stripprefix middleware.
Here is an example docker-compose.yml
definition:
services:
downloads:
build:
context: ./downloads
labels:
- traefik.enable=true
- traefik.docker.network=traefik
# http
- traefik.http.routers.downloads.entrypoints=http
- 'traefik.http.routers.downloads.rule=(Host(`example.com`) && PathPrefix(`/downloads/`))'
- traefik.http.routers.downloads.middlewares=downloads-https-redirect
- traefik.http.middlewares.downloads-https-redirect.redirectscheme.scheme=https
# https
- traefik.http.routers.downloads-https.entrypoints=https
- 'traefik.http.routers.downloads-https.rule=(Host(`example.com`) && PathPrefix(`/downloads/`))'
- traefik.http.routers.downloads-https.tls=true
- traefik.http.routers.downloads-https.tls.certresolver=letsencrypt
- traefik.http.services.downloads-https.loadbalancer.server.port=8080
- traefik.http.routers.downloads-https.service=downloads-https
- traefik.http.routers.downloads-https.middlewares=downloads-strip-prefix
- traefik.http.middlewares.downloads-strip-prefix.stripprefix.prefixes=/downloads
networks:
- traefik
expose:
- "8080"
Install a custom certificate
Installing a custom certificate and private key in Traefik is simple:
- Edit the traefik.conf and ensure that it has a dynamic configuration set.
providers: file: filename: "/config/dynamic_config.yml" watch: true
- In the dynamic configuration file, specify the certificate and key files. For example, here is what I would place for a *.example.com wildcard certificate:
tls: certificates: - certFile: /config/ssl/example.com.crt keyFile: /config/ssl/example.com.key
- Place the certificates in the /config/ssl directory.
Restart Traefik if you didn't previously have the dynamic config file defined in the traefik.conf previously. Traefik will automatically determine what domains it has certificates for and use it as required.
|