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[edit | edit source]
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[edit | edit source]
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[edit | edit source]
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.
|Enable Traefik for this container|
|Define the Docker network that Traefik needs to use to connect to this container|
|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.|
|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.
|You can also expose your container via HTTP.
Be sure that your router name is distinct.
|If you want your HTTP traffic redirected to the HTTPS version, create a new middleware that redirects to the HTTPS scheme.|
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
Tasks[edit | edit source]
Add host header on requests to the backend[edit | edit source]
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[edit | edit source]
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
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"