How to redirect HTTPS requests when changing root domain?

I have a dozen services running on subdomains, *.legacy.net, and I'm trying to redirect all traffic to the new domain, *.new.com. I can't seem to get the configuration to work.

Static Config

providers:
  docker:
    watch: true
    exposedByDefault: false
    network: public_web
  file:
    filename: /etc/traefik/dyn.yaml

entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https
          permanent: true
  websecure:
    address: ":443"
    http:
      middlewares:
        - legacyRedirect@file

Dynamic Config

http:
  middlewares:
    legacyRedirect:
      redirectRegex:
        regex: "^https://([a-zA-Z0-9-]+).legacy.net/(.*)"
        replacement: "https://${1}.new.net/${2}"
        permanent: true

How can I send a HTTP redirect to the new domain for requests to the old domain?

Hello @hazmat,

What are expected to have ?

With my simple reproduction case, I get redirected to my new domain each time I make a call to the old domain.

Simple reproduction case

My docker-compose file:

version: '3.6'

services:
  traefik:
    image: traefik:v2.6
    command:
      - --providers.docker
      - --providers.file.Directory=/dyn
      - --entrypoints.web.address=:80
      - --entrypoints.web.http.middlewares=legacyRedirect@file
    ports:
      - "80:80"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./traefik-d:/dyn

  whoami:
    image: traefik/whoami
    labels:
      traefik.http.routers.whoami.rule: PathPrefix(`/`)

My traefik-d/redirect.yml file:

http:
  middlewares:
    legacyRedirect:
      redirectRegex:
        regex: "^http://([a-zA-Z0-9-]+).legacy.localhost/(.*)"
        replacement: "http://${1}.new.localhost/${2}"
        permanent: true

Note, I replaced the .net extension to .localhost.

Here are my tests:

$ curl -vL http://foo.legacy.localhost/bar # gets redirected to http://foo.new.localhost/bar
* Couldn't find host foo.legacy.localhost in the (nil) file; using defaults
*   Trying ::1:80...
* Connected to foo.legacy.localhost (::1) port 80 (#0)
> GET /bar HTTP/1.1
> Host: foo.legacy.localhost
> User-Agent: curl/7.79.0-DEV
> Accept: application/json, application/xml, text/plain, */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 301 Moved Permanently
< Location: http://foo.new.localhost/bar
< Date: Thu, 20 Jan 2022 14:28:29 GMT
< Content-Length: 17
< Content-Type: text/plain; charset=utf-8
< 
* Ignoring the response-body
* Connection #0 to host foo.legacy.localhost left intact
* Issue another request to this URL: 'http://foo.new.localhost/bar'
* Couldn't find host foo.new.localhost in the (nil) file; using defaults
*   Trying ::1:80...
* Connected to foo.new.localhost (::1) port 80 (#1)
> GET /bar HTTP/1.1
> Host: foo.new.localhost
> User-Agent: curl/7.79.0-DEV
> Accept: application/json, application/xml, text/plain, */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Content-Length: 422
< Content-Type: text/plain; charset=utf-8
< Date: Thu, 20 Jan 2022 14:28:29 GMT
< 
Name: whoami
Hostname: 47774af5a642
IP: 127.0.0.1
IP: 172.18.0.2
RemoteAddr: 172.18.0.3:45678
GET /bar HTTP/1.1
Host: foo.new.localhost
User-Agent: curl/7.79.0-DEV
Accept: application/json, application/xml, text/plain, */*
Accept-Encoding: gzip
X-Forwarded-For: 172.18.0.1
X-Forwarded-Host: foo.new.localhost
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: 95ab827c0c8b
X-Real-Ip: 172.18.0.1

* Connection #1 to host foo.new.localhost left intact

$ curl -vL http://baz.new.localhost/buz # does not get redirected
* Couldn't find host baz.new.localhost in the (nil) file; using defaults
*   Trying ::1:80...
* Connected to baz.new.localhost (::1) port 80 (#0)
> GET /buz HTTP/1.1
> Host: baz.new.localhost
> User-Agent: curl/7.79.0-DEV
> Accept: application/json, application/xml, text/plain, */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Content-Length: 422
< Content-Type: text/plain; charset=utf-8
< Date: Thu, 20 Jan 2022 14:29:26 GMT
< 
Name: whoami
Hostname: 47774af5a642
IP: 127.0.0.1
IP: 172.18.0.2
RemoteAddr: 172.18.0.3:45678
GET /buz HTTP/1.1
Host: baz.new.localhost
User-Agent: curl/7.79.0-DEV
Accept: application/json, application/xml, text/plain, */*
Accept-Encoding: gzip
X-Forwarded-For: 172.18.0.1
X-Forwarded-Host: baz.new.localhost
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: 95ab827c0c8b
X-Real-Ip: 172.18.0.1

* Connection #0 to host baz.new.localhost left intact

Your issue might be that your router does not match both the new and the old domain(see PathPrefix(`/`) from my example).

WDYT ?

Unfortunately I still get a 404. The difference is that my entrypoint has TLS?

Oh - I see I neglected to add that part of the dynamic config.. I cant update the original post but this part is missing in the dynamic config.

tls:
  options:
    default:
      sniStrict: false
  certificates:
  - certFile: /etc/traefik/server.crt
    keyFile: /etc/traefik/server.key
    stores:
    - default
  # Used for non-matching or absent SNIs
  stores:
    default:
      defaultCertificate:
        certFile: /etc/traefik/server.crt
        keyFile: /etc/traefik/server.key

This should work as well with HTTPs.

Can you share Traefik's logs ?

Absolutely.

"DEBUG" traefik log.

traefik_1         | time="2022-01-20T16:17:30Z" level=debug msg="Serving default certificate for request: \"whoami.legacy.net\""

Access log.

172.19.0.1 - - [20/Jan/2022:16:17:30 +0000] "GET / HTTP/2.0" 404 19 "-" "-" 28 "-" "-" 0ms

Curl command.

curl -k 'https://whoami.legacy.net'

The whoami docker-compose definition.

version: '3.9'
services:
  whoami:
    image: traefik/whoami:latest
    restart: always
    labels:
    - traefik.enable=true
    - traefik.port=80
    - traefik.http.routers.whoami.tls=true
    - traefik.http.routers.whoami.entrypoints=websecure
    - traefik.http.routers.whoami.rule=Host(`whoami.new.net`)