Want to replace a Traefik docker site with a redirect; can't get it working

I have a blog at https://oberbrunner.com. It's served by my traefik instance running in a docker-swarm. Traefik does the SSL termination and I have a docker server for the actual web server (using nginx).

I'm trying to replace this with https://blog.oberbrunner.com which is now hosted by cloudflare pages (including SSL). So I want to strip out all of the oberbrunner.com config from traefik, and just have it permanent-redirect everything from http[s]://oberbrunner.com to https://blog.oberbrunner.com.

I tried to do this, but I get "bad gateway" errors. Here's my traefik config:

# Traefik static (initial) config file

# We use docker and a config file to provide dynamic configuration
providers:
  docker: {}
  file:
    directory: /etc/traefik/config
    watch: true

entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: websecure
  websecure:
    address: ":443"
    http:
      tls: {}

certificatesResolvers:
  myresolver:
    acme:
...

and my traefik-dynamic.yaml:

http:
  middlewares:
    oberbrunner-redirect-to-blog:
      redirectregex:
        regex: "^https://oberbrunner.com/(.*)"
        replacement: "^https://blog.oberbrunner.com/$${1}"
  routers:
    oberbrunnerdotcom:
      rule: Host("oberbrunner.com")
      middlewares:
        - oberbrunner-redirect-to-blog
      service: dummy-service
   ...etc...
  services:
    dummy-service:              # for oberbrunner.com
      loadBalancer:
        servers:
          - url: "http://127.0.0.1"

and my docker-compose:

version: "3"

services:
  reverse-proxy:
    image: traefik:v2.5
    container_name: reverse-proxy
    restart: unless-stopped
    ports:
      - 80:80
      - 443:443
    volumes:
      # So that Traefik can listen to the Docker events
      - /var/run/docker.sock:/var/run/docker.sock
      # Traefik static config file
      - ./traefik.yaml:/etc/traefik/traefik.yaml
      # Traefik dynamic config files
      - ./traefik-config:/etc/traefik/config
      # ACME (LetsEncrypt) certs:
      - ./acme.json:/acme.json

This config is all in my github repo https://github.com/garyo/docker-web-server/tree/oberbrunner-redirect

Traefik v2.5 is 2 years old and should be upgraded.

Use v2.11 or v3.1, then changing to providers.swarm.

Maybe that’s enough to make the example from current doc work:


# Redirect with domain replacement
http:
  middlewares:
    test-redirectregex:
      redirectRegex:
        regex: "^http://localhost/(.*)"
        replacement: "http://mydomain/${1}"
# Redirect with domain replacement
# Note: all dollar signs need to be doubled for escaping.
labels:
  - "traefik.http.middlewares.test-redirectregex.redirectregex.regex=^http://localhost/(.*)"
  - "traefik.http.middlewares.test-redirectregex.redirectregex.replacement=http://mydomain/$${1}"

Enable and check Traefik debug log and access log.

Thanks -- I've just tried 2.11 and 3.1; same issue (3.1 had some other issues, I'd probably have to update other parts of my config). I couldn't change provider to swarm, since I'm only using docker-compose. I'm using your first example, with the middleware defined in my traefik-dynamic.yaml along with the call to the middleware in the router. I do need a router for that host still, right? I don't want traefik to do SSL termination, just return a redirect.

I also added tls.passthrough: true but I get 404 errors. Nothing significant in the logs.

I presume the middleware should use https in the regex and replacement, right?

There are http and tcp routers, no https.

You still need to terminate TLS, otherwise Traefik can not process any https requests. It needs to decrypt TLS, match the domain, and send a http redirect back encrypted to the client/browser.

1 Like

Hmm. Perhaps traefik can't do what I want then. I was hoping to just repoint my DNS record to the new web host, but as it is at the root of the domain, I can't easily do that.

domain.com needs to point to Traefik so the request can be processed, Traefik can easily get a TLS cert for it.

What you do with blog. is totally independent.

Ah, good point. So I need to terminate the oberbrunner.com ssl (with a traefik-managed cert) and then redirect to the actual blog (which has its own SSL cert). That makes sense. I guess that means the redirect regex should be http:// since the SSL will already have been terminated by the time the middleware sees it.
One followup question though: I'm using acme/letsencrypt for the certs, using http challenge via :80. That authenticates via a special http route, right? Will that work given the total redirect?

Traefik will fully handle httpChallenge.

Hi, sorry to keep on this -- I'm almost there I think. I'm terminating SSL and have set up to use middleware, but now I have a redirect loop because it's not using my replacement URL properly.
My dynamic config:

  middlewares:
    # redirect oberbrunner.com to blog
    # Note: TLS has already been terminated, so use http urls
    oberbrunner-redirect-to-blog:
      redirectRegex:
        regex: "^http://oberbrunner.com/(.*)"
        replacement: "https://blog.oberbrunner.com/$${1}"
        permanent: true

But the test results are redirect to self:

% curl -I https://oberbrunner.com/thing1/thing2
HTTP/2 308 
content-type: text/plain; charset=utf-8
date: Wed, 24 Jul 2024 13:36:41 GMT
location: https://oberbrunner.com/thing1/thing2
content-length: 18

Clearly it's using my middleware because I'm getting a 308 as expected. But it's not applying the replacement -- just using the original URL as location. What could I be doing wrong?

$-escaped $${1} is needed in Docker labels, not in yaml file.

Note that with permanent: true you are shooting yourself in the foot, as the browser will cache the value and not request again. So updates now will have no effect on what's happening in the browser.

1 Like

Thanks -- tried without $$ and removed permanent: true (good point). Same error.
I think the actual 308 is coming from my http-to-https redirect here, now commented out:

entryPoints:
  web:
    address: ":80"
    # http:
    #   redirections:
    #     entryPoint:
    #       to: websecure
  websecure:
    address: ":443"
    http:
      tls: {}

because with that commented out, I just get a 404 when I curl (curl should avoid any caches). So my middleware isn't actually getting triggered, looks like.
The log only says this:

reverse-proxy    | 127.0.0.1 - - [24/Jul/2024:14:58:27 +0000] "HEAD /thing1/thing2 HTTP/1.1" 404 19 "-" "-" 2 "-" "-" 0ms
reverse-proxy    | 172.18.0.1 - - [24/Jul/2024:14:58:27 +0000] "HEAD /thing1/thing2 HTTP/2.0" 404 0 "-" "-" 1 "websecure-oberbrunnerdotcom@file" "http://127.0.0.1" 1ms

the 127.0.0.1 is presumably from the dummy service I had to add to the router, even though the redirect should catch everything. Looks like the middleware isn't triggering, and the dummy service serves a 404.
(Note: I'm running Traefik 2.11 now.)

EDIT: aha -- using ^https?://oberbrunner.com as the regex (i.e. adding optional "s") makes it work. So I guess the regex is applied to the URL before TLS termination.
Whew -- thanks for sticking with me til I got it working!

This topic was automatically closed 3 days after the last reply. New replies are no longer allowed.