Traefik (v2)
An HTTP Reverse-Proxy
Pieces of the Request Lifecycle
Entry Points
The entry point defines what port and protocol a request must match for Traefik to handle it.
Routers
A router checks to see if a request matches a given set of rules and, if so, applies a given set of middleware to the request (potentially changing it) before forwarding the request to a service.
Services
A service is a server which will handle the request (ex. load balancing, mirroring).
Configuration
Static
When Traefik starts it will load a static configuration which cannot change until Traefik is restarted. This configuration consists of the entry points Traefik should handle as well as any provider connection info (eg. how to access the Docker host.)
Traefik can be statically configured by specifying flags at the commandline when starting it, or providing .TOML or .YAML files. Certain configuration options can be specified in other formats as well (eg. Docker labels & Kubernetes resources).
Dynamic
Traefik has various events that it listens for which allows you to dynamically configure its routers, middlewares, services, and certificates while it is running.
It does not matter if traefik is started before or after the containers its meant to route to. When it starts it will canvas all containers it has access to and compile their provided configuration. This does mean, however, that traefik's container and the containers it's meant to interact with must be on the same network; traefik can neither read the configuration of nor route requests to containers it's virtually or physically isolated from.
Quick & Dirty Nuxt-Development Example
docker run --rm \
--net=reverse-proxy \
--name=reverse-proxy \
-p 80:80 -p 8080:8080 \
-v /var/run/docker.sock:/var/run/docker.sock \
traefik:v2.0 \
--log.level=DEBUG \
--api.insecure=true \
--providers.docker
- --net=reverse-proxy specifies that docker should add the traefik container to the network named reverse-proxy. All the containers traefik should be routing to will also be placed in this network.
- --name=reverse-proxy just specifies that the traefik container should be accessible via the custom name reverse-proxy.
- -p 80:80 and -p 8080:8080 enable docker (and thus traefik) to handle requests on those ports. 8080 is the default port for the optional traefik dashboard.
- -v *.sock:*.sock mounts our host's docker socket to the traefik container so that traefik can listen to and manipulate our docker instance.
- traefik:2.0 is just the traefik docker image used for this example.
- --log.level=DEBUG specifies what types of messages traefik should log, with DEBUG being the most permissive and INFO being the most restrictive.
- --api.insecure=true is a flag telling traefik, when it starts, to enable the dashboard (listening on port 8080 by default).
- --providers.docker is a flag telling traefik, when it starts, that it should be using docker to orchestrate the various servers; traefik supports multiple providers including Amazon ECS and Kubernetes.
docker run --rm \
--expose=3000 \
--network=reverse-proxy \
--label="traefik.http.routers.nuxt.rule=Host(\"nuxt.test\")" \
-v $(pwd):/code -w /code \
samueldavis/vue:latest \
npm run dev
- --expose=3000 the Nuxt development server listens on port 3000 by default and by explicitly exposing only one port traefik can dynamically infer it should be forwarding its port 80 traffic to port 3000 on the nuxt container.
- --network=reverse-proxy tells docker to put the nuxt container in the same network as traefik so that traefik can listen to events and configuration provided by the nuxt container.
- --label="traefik.http.routers.nuxt.rule=Host(\"nuxt.test\")" is a label which traefik is looking for when containers boot up which informs traefik it should set up a router which forwards requests matching the nuxt.test domain to the nuxt container.
- -v $(pwd):/code and -w /code just mount the current working directory on the host to the /code directory in the nuxt container and set t as the default working directory. This allows the npm run command not to have to specify the project root to run.
- samueldavis/vue:latest is just a node docker container with vue-cli & nuxt pre-installed.
- npm run dev just invokes the default nuxt (development) server to start listening for incoming requests (by default on port 3000) and serving the nuxt app.
WordPress with HTTPS Example
version: '3'
networks:
reverse-proxy: {}
wp-test: {}
volumes:
wp-test-db: {}
services:
reverse-proxy:
image: traefik:v2.0
restart: always
ports:
- "8080:8080"
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./certs:/certs # directory to store letsEncrypt certs
networks:
- reverse-proxy
command:
# API SETTINGS
- --api.insecure=true # enable the (insecure) API
- --api.dashboard=true # enable the dashboard
# LOG SETTINGS
- --log.level=DEBUG # most extensive logging
# PROVIDER SETTINGS
- --providers.docker # use docker (as opposed to kubernetes, etc.)
- --providers.docker.exposedByDefault=false # ignore containers unless they're specially labled
- --providers.docker.network=reverse-proxy # docker network to look for containers in
# ENTRYPOINTS
- --entrypoints.insecure.address=:80 # listen on port 80
- --entrypoints.secure.address=:443 # listen on port 443
# AUTOMAGICALLY GENERATE LETSENCRYPT CERTIFICATES
# WARNING: LETS ENCRYPT CAN ONLY VALIDATE ICANN TLDS, THUS *.test WILL ERROR & BE INVALID
# - --certificatesResolvers.le.acme.email=example@gmail.com
# - --certificatesResolvers.le.acme.storage=/certs/acme.json
# - --certificatesResolvers.le.acme.httpChallenge.entryPoint=insecure
labels:
# PRETTY URL FOR TRAEFIK DASHBOARD
- "traefik.enable=true" # enable host routing for dashboard
- "traefik.http.routers.traefik.rule=Host(\"traefik.test\")" # set url for dashboard
- "traefik.http.routers.traefik.service=api@internal" # point the router at the dashboard backend, not frontend
# HTTP > HTTPS REDIRECT MIDDLEWARE
- "traefik.http.middlewares.secure-redirect.redirectscheme.scheme=https"
# PROVIDED OWN CERTIFICATES
# - "traefik.https.routers.secure.tls.certificates.certFile=\"/certs/test.crt\"" # specify own cert
# - "traefik.https.routers.secure.tls.certificates.keyFile=\"/certs/test.key\"" #specify own key
wp-test:
image: wordpress:latest
restart: always
depends_on:
- wp-test-db
volumes:
- ./src:/var/www/html
networks:
- reverse-proxy # traefik needs to be able to send requests to this container
- wp-test # this container, but not traefik, needs to be able to talk to the db
environment:
WORDPRESS_DB_HOST: wp-test-db
WORDPRESS_DB_USER: wp-test-user
WORDPRESS_DB_PASSWORD: wp-test-pass
WORDPRESS_DB_NAME: wp-test-db
labels:
- "traefik.enable=true" # traefik should handle this container
- "traefik.http.routers.insecure.rule=Host(\"wp.test\", \"www.wp.test\")" # traefik should handle this container
- "traefik.http.routers.insecure.entrypoints=insecure" # listen for HTTP
- "traefik.http.routers.insecure.middlewares=secure-redirect" # redirect to https
- "traefik.https.routers.secure.rule=Host(\"wp.test\", \"www.wp.test\")" # traefik should handle this container
- "traefik.https.routers.secure.entrypoints=secure" # listen for HTTPS
# - "traefik.https.routers.secure.tls.certResolver=le" # use letsEncrypt to certify
wp-test-db:
image: mysql:5.7
restart: always
networks:
- wp-test # this container can talk to the wp-test container, but is secure from traefik traffic
volumes:
- wp-test-db:/var/lib/mysql
environment:
MYSQL_DATABASE: wp-test-db
MYSQL_USER: wp-test-user
MYSQL_PASSWORD: wp-test-pass
MYSQL_ROOT_PASSWORD: root