DEV Community

Cover image for Redirect HTTP to HTTPS and WWW to Non-WWW with Traefik 3
Fabian Reinders
Fabian Reinders

Posted on • Edited on

Redirect HTTP to HTTPS and WWW to Non-WWW with Traefik 3

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

And we registered the middleware to the my-website-frontend-http router:

- traefik.http.routers.my-website-frontend-http.middlewares=redirect-to-https
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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`)
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)