Hi everyone!
I'm posting my problem here after spending several hours searching and trying different configurations.
I have a Raspberry-based app that is accessed directly through IP when in local LAN and through Teleport from outside.
On that system I have several http services running (portainer
, syncthing
, pgweb
, nodered
and others) running on a docker stack. Each service has internally a different ip/port and Traefik serves a central point in order to access them as http//:<IP>/portainer
, http//:<IP>/nodered
, http//:<IP>/pgweb
, etc.
On NodeRed, the Dashboard plugin serves a central framed UI that allows the user to browse the different services from it.
I've managed to configure Traefik to handle url rewrites and redirections to, for example route from http//:<IP>/nodered/
to http://<docker-IP>:1880/
and http//:<IP>/dasboard/
to http//:<docker-IP>/:1880/ui
. I even added redirects to handle the case of missing trailing slashes.
The problem comes when I access the device through Teleport. On our Teleport cluster this device gets an address like device.our-domain.net
and accessing it with https://device.our-domain.net/nodered/
woks as expected but using https://device.our-domain.net/nodered
(with no trailing slash) triggers the Traefik redirection and the browser is redirected to http://internal-docker-IP:<Traefik-port>/nodered
(the raefik redirection replacement target.
If I hardcode the redirection rule like:
http:
middlewares:
add-trailing-slash:
RedirectRegex:
regex: "^(https?://[^/]+/)([a-z0-9_]+)$"
replacement: "https://device.our-domain.net/${2}/"
permanent: true
The redirection works as expected but that would break when accessed from the local LAN
I would be able to distinguish when the request comes from Teleport thanks to the Referer
header, but I don't know how to use it in the redirection rule.
Any help?
PS: Part of my config
middlewares.yml
# traefik.yml (or a file in the dynamic configuration directory)
http:
middlewares:
add-trailing-slash:
RedirectRegex:
regex: "^(https?://[^/]+/)([a-z0-9_]+)$"
replacement: "https://device.our-domain.net/${2}/"
permanent: true
strip-prefix:
StripPrefixRegex:
regex: "/[a-z0-9_]+"
# Header Dump plugin config
my-headerdump:
plugin:
headerdump:
Prefix: HDlog
TLS: "true"
# This middleware is used on almost all docker service routers
handle-service:
chain:
middlewares:
- my-headerdump
- add-trailing-slash
- strip-prefix
Docker-compose
name: mx100
services:
traefik:
container_name: traefik
image: traefik:3
command:
# - "--api.dashboard"
- "--api.insecure"
- "--providers.docker"
- "--providers.docker.network=mx100"
- "--providers.docker.exposedbydefault=false"
- "--providers.file=true"
- "--providers.file.filename=/config/middlewares.yml"
- "--entrypoints.web.address=:3088"
- "--experimental.plugins.headerdump.modulename=github.com/jaybubs/headerdump"
- "--experimental.plugins.headerdump.version=v0.1.0"
- "--log.level=INFO"
# - "--log.level=DEBUG"
extra_hosts:
- "host.docker.internal:host-gateway"
ports:
- "3088:3088" # Traefik Web UI
- "8080:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ${MX100_DATA}/traefik/middlewares.yml:/config/middlewares.yml
networks:
- mx100
portainer:
container_name: portainer
image: portainer/portainer:1.24.1
restart: unless-stopped
command: --no-auth
volumes:
- ${MX100_DATA}/portainer:/data
- /var/run/docker.sock:/var/run/docker.sock
ports:
- "9000:9000" # Acceso GUI
labels:
- "traefik.enable=true"
- "traefik.docker.network=mx100"
- "traefik.http.routers.portainer.rule=PathRegexp(`^/portainer.*`)"
- "traefik.http.routers.portainer.middlewares=handle-service@file"
nodered:
container_name: nodered
restart: unless-stopped
image: ghcr.io/digicard/nodered:${NODERED_IMAGE_TAG}
depends_on:
- "mqtt"
healthcheck:
disable: true
user: root
environment:
- TZ=America/Argentina/Buenos_Aires
- NODE_OPTIONS=--max-old-space-size=128
- MX100_COMPANY_NAME=digi
- MX100_COMPANY_SITE=alirpi5
- MX100_PANELID=05
- PLATFORM=RPI5
volumes:
- ${MX100_DATA}/nodered:/data
- /etc/localtime:/etc/localtime:ro
- /root/.ssh:/root/.ssh:ro
ports:
- "1880:1880" # Acceso GUI
labels:
- "traefik.enable=true"
- "traefik.docker.network=mx100"
- "traefik.http.routers.nodered.rule=PathPrefix(`/dashboard`) || PathPrefix(`/nodered`)"
- "traefik.http.middlewares.nodered-dashboard.RedirectRegex.regex=^(https?://[^/]+)/dashboard/?$$"
- "traefik.http.middlewares.nodered-dashboard.RedirectRegex.replacement=$${1}/nodered/ui/"
- "traefik.http.middlewares.nodered-dashboard.RedirectRegex.permanent=true"
- "traefik.http.middlewares.nodered.replacepathregex.regex=^/nodered/(.*)"
- "traefik.http.middlewares.nodered.replacepathregex.replacement=/$${1}"
- "traefik.http.routers.nodered.middlewares=nodered-dashboard,nodered,add-trailing-slash@file"
networks:
- mx100
... Other services...