Introduction
Traefik is awesome! If you, like me, have moved all your web services to Docker and Docker Compose, there is no better option for a reverse proxy and load balancer than Traefik in my opinion.
You can get things done quickly without having to write massive config files.
However, when you're just starting out with Traefik it might take some getting used to.
Looking at some useful, real-world examples might help in that situation!
Redirecting HTTP to HTTPS
One of the most common things you would want your reverse proxy to handle is automatically redirecting HTTP traffic to HTTPS.
Example: http://fabiancdng.com should automatically be redirected to https://fabiancdng.com to establish a secure connection.
The example web service
To show you how we could go about automatically redirecting HTTP to HTTPS in Traefik, it makes sense to look at an example Docker Compose stack that is already set up to run behind Traefik as a reverse proxy.
version: '3.7'
services:
fabiancdng-website:
image: registry/.../my-website-image:latest
labels:
- traefik.enable=true
- traefik.http.routers.my-website-frontend-http.rule=Host(`fabiancdng.com`)
- traefik.http.routers.my-website-frontend-http.entrypoints=http
- traefik.http.services.my-website-frontend.loadbalancer.server.port=3000
networks:
- proxy
networks:
proxy:
external: true
Traefik and this example service can communicate through the external Docker network "proxy". This can differ in your case based on your own configuration.
The above example creates an HTTP router my-website-frontend-http
that accepts incoming traffic to http://fabiancdng.com and routes it to port 3000 of the underlying container (that port is not exposed publicly though; only in the Docker network).
Routing HTTPS traffic to the same container
Let's extend the docker-compose.yml
to also accept HTTPS traffic at https://fabiancdng.com:
version: '3.7'
services:
fabiancdng-website:
image: registry/.../my-website-image:latest
labels:
- traefik.enable=true
- traefik.http.routers.my-website-frontend-http.rule=Host(`fabiancdng.com`)
- traefik.http.routers.my-website-frontend-http.entrypoints=http
- traefik.http.routers.my-website-frontend-https.rule=Host(`fabiancdng.com`)
- traefik.http.routers.my-website-frontend-https.entrypoints=https
- traefik.http.routers.my-website-frontend-https.tls=true
- traefik.http.routers.my-website-frontend-https.tls.certresolver=letsencrypt
- traefik.http.services.my-website-frontend.loadbalancer.server.port=3000
networks:
- proxy
networks:
proxy:
external: true
In this example configuration, we simply added the router my-website-frontend-https
that accepts HTTPS traffic on https://fabiancdng.com.
Additionally, we introduced a certificate resolver letsencrypt
.
The certificate resolver is optional but I highly recommend using an SSL certificate on HTTPS routes.
The traefik.yml configuration file
For all of this to work it's important that you configured the basics in Traefik correctly. There need to be corresponding entry points for http
and https
on the correct ports.
This is how my traefik.yml configuration file handles those:
entryPoints:
http:
address: ':80'
https:
address: ':443'
providers:
docker:
network: proxy
certificatesResolvers:
letsencrypt:
acme:
email: ...
storage: acme.json
httpChallenge:
entryPoint: http
Again, the certificate resolver is optional but if you want to use it, you need a volume to store the acme.json
for the certificates persistently. Also, make sure to adjust the Docker network to your existing configuration.
Finally: The redirect from HTTP to HTTPS
Now that we accept incoming traffic both at http://fabiancdng.com and https://fabiancdng.com, we can simply redirect the traffic hitting the my-website-frontend-http
router to the my-website-frontend-https
router using a RedirectScheme middleware:
version: '3.7'
services:
fabiancdng-website:
image: registry/.../my-website-image:latest
labels:
- traefik.enable=true
- traefik.http.routers.my-website-frontend-http.rule=Host(`fabiancdng.com`)
- traefik.http.routers.my-website-frontend-http.entrypoints=http
- traefik.http.routers.my-website-frontend-http.middlewares=redirect-to-https
- traefik.http.routers.my-website-frontend-https.rule=Host(`fabiancdng.com`)
- traefik.http.routers.my-website-frontend-https.entrypoints=https
- traefik.http.routers.my-website-frontend-https.tls=true
- traefik.http.routers.my-website-frontend-https.tls.certresolver=letsencrypt
- traefik.http.services.my-website-frontend.loadbalancer.server.port=3000
- traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https
- traefik.http.middlewares.redirect-to-https.redirectscheme.permanent=true
networks:
- proxy
networks:
proxy:
external: true
As you can see in this example, we created a middleware for the http
entrypoint that redirects with a 301 to HTTPS:
- traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https
- traefik.http.middlewares.redirect-to-https.redirectscheme.permanent=true
And we registered the middleware to the my-website-frontend-http
router:
- traefik.http.routers.my-website-frontend-http.middlewares=redirect-to-https
Great! That should do it for the HTTPS redirect.
Redirecting WWW to Non-WWW
One thing that might be important as well when deploying a public website is to redirect traffic hitting the www
subdomain to the non-www domain (or vice-versa).
When both your main domain and the www subdomain (or even all subdomains) point to your server running Traefik, it makes sense to redirect the traffic to your preferred version.
Why even redirect?
Even though you could use canonicalization to prevent duplicate content SEO issues, it's better to not have duplicate content in the first place and just redirect to your preferred URL for a piece of content.
Regex middleware to redirect www to non-www
As you might have figured, we need another middleware to pull off this redirect as well.
Simply add the following labels to your configuration:
- traefik.http.middlewares.redirect-to-non-www.redirectregex.regex=^https?://www.fabiancdng.com/(.*)
- traefik.http.middlewares.redirect-to-non-www.redirectregex.replacement=https://fabiancdng.com/$${1}
- traefik.http.middlewares.redirect-to-non-www.redirectregex.permanent=true
Also, you need to accept the www subdomain in your router as well. You can simply use ||
and add another Host to both the my-website-frontend-http
and my-website-frontend-https
router:
- traefik.http.routers.my-website-frontend-http.rule=Host(`fabiancdng.com`) || Host(`www.fabiancdng.com`)
- traefik.http.routers.my-website-frontend-https.rule=Host(`fabiancdng.com`) || Host(`www.fabiancdng.com`)
Make sure to change the domain to your domain.
The last step now is to hook up the new middleware to your my-website-frontend-https
router (that one router should be sufficient as all traffic gets redirected there anyway):
- traefik.http.routers.my-website-frontend-https.middlewares=redirect-to-non-www
Everything put together
The whole configuration should look something like this now:
version: '3.7'
services:
fabiancdng-website:
image: registry/.../my-website-image:latest
labels:
- traefik.enable=true
- traefik.http.routers.my-website-frontend-http.rule=Host(`fabiancdng.com`) || Host(`www.fabiancdng.com`)
- traefik.http.routers.my-website-frontend-http.entrypoints=http
- traefik.http.routers.my-website-frontend-http.middlewares=redirect-to-https
- traefik.http.routers.my-website-frontend-https.rule=Host(`fabiancdng.com`) || Host(`www.fabiancdng.com`)
- traefik.http.routers.my-website-frontend-https.entrypoints=https
- traefik.http.routers.my-website-frontend-https.tls=true
- traefik.http.routers.my-website-frontend-https.tls.certresolver=letsencrypt
- traefik.http.routers.my-website-frontend-https.middlewares=redirect-to-non-www
- traefik.http.services.my-website-frontend.loadbalancer.server.port=3000
- traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https
- traefik.http.middlewares.redirect-to-https.redirectscheme.permanent=true
- traefik.http.middlewares.redirect-to-non-www.redirectregex.regex=^https?://www.fabiancdng.com/(.*)
- traefik.http.middlewares.redirect-to-non-www.redirectregex.replacement=https://fabiancdng.com/$${1}
- traefik.http.middlewares.redirect-to-non-www.redirectregex.permanent=true
networks:
- proxy
networks:
proxy:
external: true
Done, both redirects should be working now!
Conclusion and further resources
Once you've gotten used to the way you write configuration and middlewares using the labels in Traefik, it's not that complicated after all (well- except when you need regex 😅; but you can just google that).
And being able to handle all these things properly in your reverse proxy can massively improve the user experience and SEO of your web services.
Lastly, if you want to learn even more about Traefik and how to work with it in more complex scenarios, I can recommend deploying a more complex service like, for instance, Nextcloud (even if it's just for practicing).
A while back, I wrote a blog post going into detail on how Nextcloud can be deployed with Docker and run behind Traefik as a reverse proxy.
Feel free to check that out: https://fabiancdng.com/blog/running-nextcloud-using-docker-and-traefik-3
I even wrote an article on how Traefik can work as a load balancer for Docker containers: https://fabiancdng.com/blog/scaling-next-js-web-apps-with-docker
Traefik is an awesome reverse proxy and I hope this example helped you gain more inside in Traefik's configuration system.
Cheers!
Top comments (0)