Traefik v3.2 with Tailscale

Hi Everyone!

I came here to ask a question about my Traefik + Tailscale configuration as it seems I'm lost.

I have a NAS/homelab running some Docker services. I use Traefik, Cloudflare and my own DNS server to have valid certificates and routing on my local network. Each service is on a subdomain and works fine.

I would like to use Tailscale to access some of these services from outside my LAN. As I read the documentation, it seems that I can only do path based rooting (nas.myts-network.ts.net/myservice/). Even though I set up prefix stripping, the services are not reachable.

So I'm asking you to help me find a solution, if there is one, to my problem. Below are my configuration files:

compose.yml

services:
  
  traefik:
    image: traefik:v3.2
    container_name: traefik
    hostname: traefik
    restart: unless-stopped
    labels:
      # Do not update automatically
      - com.centurylinklabs.watchtower.enable=false
    environment:
      - CF_DNS_API_TOKEN=${CF_DNS_API_TOKEN}
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /var/run/tailscale/tailscaled.sock:/var/run/tailscale/tailscaled.sock
      - /srv/data/docker/traefik/traefik.yml:/etc/traefik/traefik.yml:ro
      - /srv/data/docker/traefik/certs:/var/traefik/certs:rw
      - /srv/data/docker/traefik/logs:/var/log/traefik:rw
    networks:
      - local-proxy
  
  budget:
    image: "actualbudget/actual-server:latest-alpine"
    container_name: budget
    hostname: budget
    restart: unless-stopped
    labels:
      # Do not update automatically
      - "com.centurylinklabs.watchtower.enable=false"
      # Local Traefik settings
      - traefik.enable=true
      - traefik.http.routers.budget-https.tls=true
      - traefik.http.routers.budget-https.tls.certresolver=cloudflare
      - traefik.http.routers.budget-https.entrypoints=websecure
      - traefik.http.routers.budget-https.rule=HOST("budget.nas.home.mydomain.tld")
      - traefik.http.services.budget.loadbalancer.server.port=5006
      # Tailscale Traefic settings
      - traefik.http.routers.budget-ts.rule=Host(`nas.myts-network.ts.net`) && PathPrefix(`/budget/`)
      - traefik.http.middlewares.strip-budget.stripprefix.prefixes=/budget/
      - traefik.http.routers.budget-ts.middlewares=strip-budget@docker
      - traefik.http.routers.budget-ts.tls.certresolver=tailsolver
      - traefik.http.routers.budget-ts.tls.domains[0].main=nas.myts-network.ts.net
      # Flame settings
      - flame.type=app
      - flame.name=Budget
      - flame.url=https://budget.nas.home.mydomain.tld
      - flame.icon=cash-multiple
    volumes:
      - /srv/data/docker/budget:/data
    networks:
      - local-proxy

networks:
  local-proxy:
    external: true

traefik.yml

global:
  checkNewVersion: false
  sendAnonymousUsage: false

log:
  level: DEBUG
  format: common
  filePath: /var/log/traefik/traefik.log

accesslog:
  format: common
  filePath: /var/log/traefik/access.log

api:
  dashboard: true
  disableDashboardAd: true
  insecure: true

entryPoints:
  web:
    address: :80
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https
  websecure:
    address: :443

providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false

certificatesResolvers:
  cloudflare:
    acme:
      email: "itsme@myemail.com"
      storage: /var/traefik/certs/cloudflare-acme.json
      caServer: "https://acme-v02.api.letsencrypt.org/directory"
      keyType: EC256
      dnsChallenge:
        provider: cloudflare
        resolvers:
          - "8.8.8.8:53"
          - "1.1.1.1:53"
  tailsolver:
    tailscale: {}

I can see that something is happening as the page in the browser loads some colored headers when I navigate to the nas.myts-network.ts.net/budget/ url but fails to load the whole page.

This is what I can see in the access log:

MY.TS.IP.ADDR - - [05/Nov/2024:12:54:07 +0000] "GET / HTTP/2.0" 404 19 "-" "-" 1 "-" "-" 2ms
MY.TS.IP.ADDR - - [05/Nov/2024:12:54:12 +0000] "GET /budget/ HTTP/2.0" 304 0 "-" "-" 2 "budget-ts@docker" "http://172.20.0.14:5006" 3ms
MY.TS.IP.ADDR - - [05/Nov/2024:12:54:19 +0000] "GET /budget/ HTTP/2.0" 200 2907 "-" "-" 3 "budget-ts@docker" "http://172.20.0.14:5006" 3ms
MY.TS.IP.ADDR - - [05/Nov/2024:12:54:19 +0000] "GET /site.webmanifest HTTP/2.0" 404 19 "-" "-" 4 "-" "-" 0ms
MY.TS.IP.ADDR - - [05/Nov/2024:12:54:19 +0000] "GET /static/js/index.IdL7Qzmn.js HTTP/2.0" 404 19 "-" "-" 5 "-" "-" 0ms
MY.TS.IP.ADDR - - [05/Nov/2024:12:54:19 +0000] "GET /static/css/index._UHHVT8l.css HTTP/2.0" 404 19 "-" "-" 6 "-" "-" 0ms
MY.TS.IP.ADDR - - [05/Nov/2024:12:54:19 +0000] "GET /registerSW.js HTTP/2.0" 404 19 "-" "-" 7 "-" "-" 0ms
MY.TS.IP.ADDR - - [05/Nov/2024:12:56:08 +0000] "GET /budget/ HTTP/2.0" 200 2907 "-" "-" 8 "budget-ts@docker" "http://172.20.0.14:5006" 3ms
MY.TS.IP.ADDR - - [05/Nov/2024:12:56:08 +0000] "GET /site.webmanifest HTTP/2.0" 404 19 "-" "-" 9 "-" "-" 0ms
MY.TS.IP.ADDR - - [05/Nov/2024:12:56:08 +0000] "GET /registerSW.js HTTP/2.0" 404 19 "-" "-" 12 "-" "-" 0ms
MY.TS.IP.ADDR - - [05/Nov/2024:12:56:08 +0000] "GET /static/css/index._UHHVT8l.css HTTP/2.0" 404 19 "-" "-" 11 "-" "-" 0ms
MY.TS.IP.ADDR - - [05/Nov/2024:12:56:08 +0000] "GET /static/js/index.IdL7Qzmn.js HTTP/2.0" 404 19 "-" "-" 10 "-" "-" 0ms
MY.TS.IP.ADDR - - [05/Nov/2024:13:00:58 +0000] "GET /budget/ HTTP/2.0" 200 2907 "-" "-" 13 "budget-ts@docker" "http://172.20.0.14:5006" 3ms
MY.TS.IP.ADDR - - [05/Nov/2024:13:00:58 +0000] "GET /site.webmanifest HTTP/2.0" 404 19 "-" "-" 14 "-" "-" 0ms
MY.TS.IP.ADDR - - [05/Nov/2024:13:00:58 +0000] "GET /static/js/index.IdL7Qzmn.js HTTP/2.0" 404 19 "-" "-" 15 "-" "-" 0ms
MY.TS.IP.ADDR - - [05/Nov/2024:13:00:58 +0000] "GET /static/css/index._UHHVT8l.css HTTP/2.0" 404 19 "-" "-" 16 "-" "-" 0ms
MY.TS.IP.ADDR - - [05/Nov/2024:13:00:58 +0000] "GET /registerSW.js HTTP/2.0" 404 19 "-" "-" 17 "-" "-" 0ms

So what I'm asking is, am I missing something, or is what I'm trying to accomplish not possible?

Thanks,

Steve

What documentation? Most GUI web apps don't work with custom paths, they expect to be root, stripprefix does not help, so you should try to get multiple sub-domains.

Well, maybe I was naive to think that a simple PathPrefix would help here. However, it is not possible to get more subdomains for a given machine in Tailscale as of now, see issue #1543.

Maybe check this: Homelab Behind Tailscale with Wildcard DNS and Certificates | by Sven van Ginkel | Oct, 2024 | Medium

1 Like

A very nice find, I will definitely take a look. In the meantime I used this solution: GitHub - hollie/tailscale-caddy-proxy: Tailscale and Caddy proxy to expose docker containers over Tailscale with HTTPS access And I think this works better for my usecase, as I would like to use Traefik to expose my services to localhost and some of them to Tailscale at the same time.

There is another way: TSDProxy