Redirect non-www to www Traefik v2

4 minute read Published

How to create more timeless URLs using Traefik 2 with Docker labels.

I like cool URIs that don't change so whenever I’m making a new website I make sure I put my web content on the www subdomain where it belongs. This of course leaves the domain apex, or root of the domain, empty and user agents don’t always do what comes so natural to us humans — adding a www in front of a domain name.

Computers get even more clumsy when you add HTTPS into the equation and are working with new technologies. So if you’re looking for cool URIs too here’s how to redirect domain.example to www.domain.example with Traefik v2 over both HTTP and HTTPS using Docker labels in a docker-compose.override.yml YAML file:

 1version: '3.4'
 2
 3networks:
 4  web:
 5    external:
 6      name: web
 7services:
 8  web:
 9    labels:
10      - "traefik.enable=true"
11      - "traefik.http.routers.web.entrypoints=http"
12      - "traefik.http.routers.web.rule=Host(`jamupuri.com`) || Host(`www.jamupuri.com`)"
13      - "traefik.http.middlewares.web-https-redirect.redirectscheme.scheme=https"
14      - "traefik.http.routers.web.middlewares=web-https-redirect"
15      - "traefik.http.middlewares.web-www-https-redirect.redirectregex.regex=^http://(?:www.)?jamupuri.com/(.*)"
16      - "traefik.http.middlewares.web-www-https-redirect.redirectregex.replacement=https://www.jamupuri.com/$${1}"
17      - "traefik.http.routers.web.middlewares=web-www-https-redirect"
18      - "traefik.http.routers.web-secure.entrypoints=https"
19      - "traefik.http.routers.web-secure.rule=Host(`jamupuri.com`) || Host(`www.jamupuri.com`)"
20      - "traefik.http.routers.web-secure.tls=true"
21      - "traefik.http.routers.web-secure.service=web"
22      - "traefik.http.middlewares.web-secure-www-redirect.redirectregex.regex=^https://jamupuri.com/(.*)"
23      - "traefik.http.middlewares.web-secure-www-redirect.redirectregex.replacement=https://www.jamupuri.com/$${1}"
24      - "traefik.http.routers.web-secure.middlewares=web-secure-www-redirect"
25      - "traefik.http.services.web.loadbalancer.server.port=4000"
26      - "traefik.docker.network=web"

That is an example of combining Traefik RedirectRegex Middleware with the RedirectScheme middleware. It’s the equivalent of saying, “Please add www in front of my URL when I forget to type it and always use HTTPS.”

Let’s break down the RedirectRegex on highlighted lines 12, 15-17:

  • L12: Watch for traffic directed at jamupuri.com or www.jamupuri.com
  • L15: Filter the traffic using the regex provided
  • L16: Modify the traffic using the replacement rule provided
  • L17: And apply the changes to the http router named web

Notice there’s a break between L12 and L15 in the example. The order in which the middleware is defined is not important. What is important important, however, is that the middleware is given a name and is applied to a router. In our example we named the RedirectRegex middleware web-www-https-redirect and applied it to the web router, which just so happens to be set-up to handle inbound HTTP traffic.

Now let’s take a closer look at the regular expression used:

^http://(?:www.)?jamupuri.com/(.*)

The regex tells the middleware to identify any HTTP-related traffic it sees using www and non-www URLs so we can modify the URL with a replacement. Notice we’re using a non-capturing group around the www part of the expression. Without it we would not be able to capture the path for both www and non-www URLs and reference it with a single variable $$1 in the replacement:

https://www.jamupuri.com/$${1}

Notice how the replacement above specifies the scheme https even though there’s an existing RedirectScheme middleware defined on L13, L14. If we instead started the replacement with http://, that’s exactly what the user would get and that’s not what we want. When combining a RedirectScheme middleware with a RedirectRegex middleware the more specific of the two takes precedence and no assumptions are made about scheme redirection despite what one might expect.

Now that we’ve beaten that to death let’s move onto to handle HTTPS traffic. See lines L19 and L22-L24 in the above example. Notice there’s no scheme redirection needed and no fancy regex. If only things were always so simple right?

Once you add your redirect middlewares restart the docker container using Them. The middlewares will show up in the Traefik dashboard so you know they’re active. Verify they’re working as epected with: curl -I <YOUR_COOL_URI> (macOS). If everything is working you should see a 307 redirect for each of the following:

  • http://domain.example redirects to https://www.domain.example
  • http://www.domain.example redirects to https://www.domain.example
  • https://domain.example redirects to https://www.domain.example

“What!? 307! I expected a 301.” So did I, and that’s why you should always test your work. If you want to make those redirects permanent you need to specify the permanent option as indicated in the Traefik docs. Applied to the example above, drop the following two additional lines into the block of labels:

- "traefik.http.middlewares.web-www-https-redirect.redirectregex.permanent=true"
- "traefik.http.middlewares.web-secure-www-redirect.redirectregex.permanent=true"

Don’t forget to test. [Spoiler alert: you still won’t get a 301.] Just be sure you don’t get a 404 either because, if you do, you’re probably missing your A/AAAA DNS records for the naked domain. And that wouldn’t be very cool either.