Global redirect www to non-www with HTTPS redirection

i have been back and forth trying to get @ldez solution to work but to no avail

i am using labels in two docker compose files, a main traefik file that also defines the dashboard.${DOMAIN}

the http -> https redirection for dashboard works fine

when i add lighttpd to handle the host={DOMAIN} , www.{DOMAIN} the strip www part doesn't work, it does strip it and redirect but i get a connection error

is it possible to get a complete example vs having snippets?

thanks for the help

I provided complete examples in my answer, you just have to click on items:

Hello @ldez, I tried to implement this improvement to include www to non-www redirecting on top of my http to https redirect using your previous method (that worked perfectly)

      # global redirect to https
      - "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)"
      - "traefik.http.routers.http-catchall.entrypoints=web"
      - "traefik.http.routers.http-catchall.middlewares=redirect-to-https"

      # middleware redirect
      - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"

Unfortunately, after replacing it with the code for docker provider (both the global and less global approach) to my docker-compose file, the opposite thing happened and when surfing to my domain.eu I got redirected to www.domain.eu

I reverted to the previous situation and had all the trouble in hell to remove the permanent redirects from browser caches. Do you have an idea as to why I got the reversed redirect?

Also, can we set the "redirectregex.permanent: true" to false (or something else), in order to test/debug without using 301 redirects ?

After release of Traefik v2.2 I guess the right approach to make http to https redirection will be:

## Static configuration
entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https

  websecure:
    address: ":443"

Docker www to non-www redirection:

labels:
      # Global redirection: https (www.) to https
      traefik.http.routers.websecure-catchall.rule: HostRegexp(`{host:(www\.).+}`)
      traefik.http.routers.websecure-catchall.entrypoints: websecure
      traefik.http.routers.websecure-catchall.middlewares: wwwtohttps

      # Middleware: http(s)://(www.) to  https://
      traefik.http.middlewares.wwwtohttps.redirectregex.regex: ^https?://(?:www\.)?(.+)
      traefik.http.middlewares.wwwtohttps.redirectregex.replacement: https://$${1}
      traefik.http.middlewares.wwwtohttps.redirectregex.permanent: true

But do we need to add acme resolver for www SSL certificate?

      traefik.http.routers.websecure-catchall.tls: true
      traefik.http.routers.websecure-catchall.tls.certresolver: myresolver

For anyone who is looking for a solution, to determine per domain whether it should be www or without www. I made 2 middlewares, which can be set per domain. I was looking after this. but couldn't find a quick answer. That's why i'm sharing my solution here:

Part of my global traefik labels (v2.1)

labels:
        # global redirect to https
        - traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)
        - traefik.http.routers.http-catchall.entrypoints=http
        - traefik.http.routers.http-catchall.middlewares=redirect-to-https

        # middleware redirect
        - traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https
        - traefik.http.middlewares.redirect-to-https.redirectscheme.permanent=true
        
        # middleware redirect to www
        - traefik.http.middlewares.redirect-to-www.redirectregex.regex=(https|http)://(?:www.)?(.*)
        - traefik.http.middlewares.redirect-to-www.redirectregex.replacement=https://www.$${2}
        
        # middleware redirect to non-www
        - traefik.http.middlewares.redirect-to-nonwww.redirectregex.regex=(https|http)://(www\.(.*))
        - traefik.http.middlewares.redirect-to-nonwww.redirectregex.replacement=https://$${3}

In a website for www. -> redirect to https://www.example.com

labels:
        - traefik.enable=true
        - traefik.http.services.${SERVICE}-app.loadbalancer.server.port=80
        - traefik.http.routers.${SERVICE}-app.rule=host(`example.com`,`www.example.com`)
        - traefik.http.routers.${SERVICE}-app.entrypoints=https
        - traefik.http.routers.${SERVICE}-app.tls=true
        - traefik.http.routers.${SERVICE}-app.tls.certresolver=letsencrypt
        - traefik.http.routers.${SERVICE}-app.service=${SERVICE}-app
        - traefik.http.routers.${SERVICE}-app.middlewares=redirect-to-www

In a website for no www -> redirect to https://example.com

labels:
        - traefik.enable=true
        - traefik.http.services.${SERVICE}-app.loadbalancer.server.port=80
        - traefik.http.routers.${SERVICE}-app.rule=host(`example.com`,`www.example.com`)
        - traefik.http.routers.${SERVICE}-app.entrypoints=https
        - traefik.http.routers.${SERVICE}-app.tls=true
        - traefik.http.routers.${SERVICE}-app.tls.certresolver=letsencrypt
        - traefik.http.routers.${SERVICE}-app.service=${SERVICE}-app
        - traefik.http.routers.${SERVICE}-app.middlewares=redirect-to-nonwww

you can also use the solution in my previous post

Your solution certainly looks good too. And is the answer to the original post. My swarm environment has multiple domains, with different wishes to www or non www and don't want people to go to the wrong url. But they will been forced to the correct www or non www environment.

Examples

Force to www environment

- traefik.http.routers.${SERVICE}-app.middlewares=redirect-to-www

Force to the non-www environment

- traefik.http.routers.${SERVICE}-app.middlewares=redirect-to-nonwww

I realize now that the placement of my solution was not completely fitting to question of the tropic starter

A word of note:
If you plan on submitting your domain to HSTS preload a single redirect will not work and is against the standard of HSTS.

And in my testing, redirects don't support headers (or didn't before).

1 Like

Hey mate - great work on the solution.

I found the regex in your KubernetesCRD to not work, I had to change
^https?://(?:www\.)?(.+)
To
^https?:\/\/(?:www\.)?(.+)

But otherwise all is well.

Hey,
Where are you setting the labels in the kubernetesCRD setup?
In the deployment YAML or as part of an IngressRoute?

Would be great if you could post a more complete yml example of what you did.

Thanks!

Big thanks for the code! But... why this? [http.routers.wwwsecure-catchall.tls]

Big thanks for the code! But... why this? [http.routers.wwwsecure-catchall.tls]

Could be because traefik 2.2 was not there back then.

In my case (w/ Traefik 2.2.5), without:

traefik.http.routers.wwwsecure-catchall.tls: true

The rule https://www.whoami.localhost/ -> https://whoami.localhost is broken. Details:

      # Global redirection: http to https
      traefik.http.routers.http-catchall.rule: HostRegexp(`{host:(www\.)?.+}`)
      traefik.http.routers.http-catchall.entrypoints: webinsecure
      traefik.http.routers.http-catchall.middlewares: wwwtohttps
      
      # Global redirection: https (www.) to https
      traefik.http.routers.wwwsecure-catchall.rule: HostRegexp(`{host:(www\.).+}`)
      traefik.http.routers.wwwsecure-catchall.entrypoints: websecure
      traefik.http.routers.wwwsecure-catchall.tls: true # I need this!
      traefik.http.routers.wwwsecure-catchall.middlewares: wwwtohttps

      # middleware: http(s)://(www.) to  https://
      traefik.http.middlewares.wwwtohttps.redirectregex.regex: ^https?://(?:www\.)?(.+)
      traefik.http.middlewares.wwwtohttps.redirectregex.replacement: https://$${1}
      traefik.http.middlewares.wwwtohttps.redirectregex.permanent: true

@floatingpurr not really surprising, right? You are not using the entry point redirection at all in that config.

Yep :slight_smile: but I did not get your post where you say:

Could be because traefik 2.2 was not there back then.

Isn't it a valid configuration for Traefik v.2.2.x?

I was referring to the fact that the entry point redirection was added in that version.

1 Like

Oh, I wasn't aware of that!

Please, don't hate me :stuck_out_tongue: Just to grasp better how v.2 works under the hood, I'm trying to mix redirections up and I moved http > https rule at the entry point level. This is my example:

command:
      - --entrypoints.webinsecure.address=:80
      - --entrypoints.webinsecure.http.redirections.entrypoint.to=websecure
      - --entrypoints.webinsecure.http.redirections.entrypoint.scheme=https
      - --entrypoints.websecure.address=:443
labels:
      # Global redirection: http to https (no more necessary now)
      # traefik.http.routers.http-catchall.rule: HostRegexp(`{host:(www\.)?.+}`)
      # traefik.http.routers.http-catchall.entrypoints: webinsecure
      # traefik.http.routers.http-catchall.middlewares: wwwtohttps

      # Global redirection: https (www.) to https
      traefik.http.routers.wwwsecure-catchall.rule: HostRegexp(`{host:(www\.).+}`)
      traefik.http.routers.wwwsecure-catchall.entrypoints: websecure
      traefik.http.routers.wwwsecure-catchall.tls: true
      traefik.http.routers.wwwsecure-catchall.middlewares: wwwtohttps

      # middleware: http(s)://(www.) to  https://
      traefik.http.middlewares.wwwtohttps.redirectregex.regex: ^https?://(?:www\.)?(.+)
      traefik.http.middlewares.wwwtohttps.redirectregex.replacement: https://$${1}
      traefik.http.middlewares.wwwtohttps.redirectregex.permanent: true

The redirection chain is:
http://www.foo.com -> https://www.foo.com -> https://foo.com

However, If I remove the option traefik.http.routers.wwwsecure-catchall.tls, I get:
http://www.foo.com -> https://www.foo.com but now I get a 404 for https://www.foo.com

Shouldn't wwwsecure-catchall take care of https://www.foo.com regardless of that option?

Sorry, I do not understand. No? Why do you expect it to? 404 means that no rules match and indeed in this case you won’t have a tls router with a matching rule.

Sorry, my bad. I do not want to take advantage of your time. The thing is that from these previous posts:

Big thanks for the code! But... why this? [http.routers.wwwsecure-catchall.tls]

Could be because traefik 2.2 was not there back then.

Isn't it a valid configuration for Traefik v.2.2.x?

I was referring to the fact that the entry point redirection was added in that version

I erroneously understood that http.routers.wwwsecure-catchall.tls could have been avoided when you use the entry point redirection... but it is exactly the contrary.

As the doc says, you need to explicitly dedicate the router to HTTPS. So, my example could work iif traefik.http.routers.wwwsecure-catchall.tls is there.