Guide: Moving Traefik Dashboard and API to a Subpath (/traefik/dashboard and /traefik/api)
This guide focuses on relocating the Traefik dashboard and API from their default paths (/dashboard and /api) to subpaths like /traefik/dashboard and /traefik/api. This is useful when the default paths conflict with other services behind Traefik, and a dedicated domain or subdomain isn’t feasible.
Key Concepts
- Why Subpaths Are Challenging: The Traefik dashboard and API are served internally at fixed paths (
/dashboardand/api). They use relative URLs for assets, API calls, and navigation. Simply changing the entry path requires path rewriting to make internal requests work correctly. Without this, the dashboard will fail to load properly (e.g., missing styles, broken links).
Recommended Setup: Using File-Based Config (Static + Dynamic)
We’ll use Docker Compose with file providers for cleanliness. This mirrors your original label-based approach but moves config to files.
Step 1: Static Configuration (traefik.yml)
Enable the API (which includes the dashboard) here. No path customization possible.
global:
checkNewVersion: true
log:
level: DEBUG
entryPoints:
http:
address: :80
providers:
docker:
constraints: Label(`traefik.constraint-label`,`traefik-public`)
exposedByDefault: false
file:
filename: /etc/traefik/dynamic.yml # Loads dynamic config
accessLog: {}
api: {} # Enables api@internal (required for dashboard and API)
Step 2: Dynamic Configuration (dynamic.yml)
Define routers with PathPrefix for your subpaths and middlewares to rewrite paths (strip /traefik/ and forward to internal /dashboard or /api). Include basic auth for security. Also, add direct routers for sub-API endpoints if needed (as in your original setup).
http:
middlewares:
admin-auth:
basicAuth:
users:
- "admin:$$xxxx$$xxxxxxxx$$xxxxxxxxxxxxxxxxxxxx" # Use your hashed password (e.g., from htpasswd)
api-rewrite:
replacePathRegex:
regex: ^/traefik/api(.*)
replacement: /api${1}
dashboard-rewrite:
replacePathRegex:
regex: ^/traefik/dashboard(.*)
replacement: /dashboard${1}
routers:
api:
rule: PathPrefix(`/traefik/api`)
entryPoints:
- http
service: api@internal
middlewares:
- admin-auth
- api-rewrite
dashboard:
rule: PathPrefix(`/traefik/dashboard`)
entryPoints:
- http
service: api@internal
middlewares:
- admin-auth
- dashboard-rewrite
# Additional API subpaths (direct, no rewrite needed if not under /traefik/)
overview:
rule: PathPrefix(`/api/overview`)
entryPoints:
- http
service: api@internal
middlewares:
- admin-auth
version:
rule: PathPrefix(`/api/version`)
entryPoints:
- http
service: api@internal
middlewares:
- admin-auth
entrypoints:
rule: PathPrefix(`/api/entrypoints`)
entryPoints:
- http
service: api@internal
middlewares:
- admin-auth
httprouters:
rule: PathPrefix(`/api/http/routers`)
entryPoints:
- http
service: api@internal
middlewares:
- admin-auth
udprouters:
rule: PathPrefix(`/api/udp/routers`)
entryPoints:
- http
service: api@internal
middlewares:
- admin-auth
tcprouters:
rule: PathPrefix(`/api/tcp/routers`)
entryPoints:
- http
service: api@internal
middlewares:
- admin-auth
httpservices:
rule: PathPrefix(`/api/http/services`)
entryPoints:
- http
service: api@internal
middlewares:
- admin-auth
httpmiddlewares:
rule: PathPrefix(`/api/http/middlewares`)
entryPoints:
- http
service: api@internal
middlewares:
- admin-auth
tcpservices:
rule: PathPrefix(`/api/tcp/services`)
entryPoints:
- http
service: api@internal
middlewares:
- admin-auth
tcpmiddlewares:
rule: PathPrefix(`/api/tcp/middlewares`)
entryPoints:
- http
service: api@internal
middlewares:
- admin-auth
udpservices:
rule: PathPrefix(`/api/udp/services`)
entryPoints:
- http
service: api@internal
middlewares:
- admin-auth
Note: If you want the sub-API paths also under /traefik/ (e.g., /traefik/api/overview), add similar rewrite middlewares and adjust rules accordingly.
Step 3: Docker Compose File
Mount the config files and enable Traefik on itself.
networks:
traefik-public:
name: "traefik-public"
services:
traefik:
image: "traefik:3.2.3"
ports:
- "0.0.0.0:80:80"
networks:
- "traefik-public"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "./traefik.yml:/etc/traefik/traefik.yml:ro"
- "./dynamic.yml:/etc/traefik/dynamic.yml:ro"
restart: "always"
deploy:
resources:
limits:
cpus: "1.0"
memory: "1024M"
reservations:
cpus: "1.0"
memory: "512M"
labels:
- "traefik.enable=true"
- "traefik.docker.network=traefik-public"
- "traefik.constraint-label=traefik-public"
Step 4: Deployment and Testing
- Save files and run
docker compose up -d. - Access dashboard at
http://your-host/traefik/dashboard/(authenticate with your credentials). - Test API at
http://your-host/traefik/api/. - Verify sub-API paths like
http://your-host/api/overview. - Check logs for issues:
docker compose logs traefik.
Alternatives if Static-Only Is Required
- Use a subdomain (e.g.,
dashboard.example.com): Enable API in static, then add a simple dynamic router withHost(dashboard.example.com) && (PathPrefix(/api) || PathPrefix(/dashboard)). - For conflicts, consider Traefik’s
api.insecure=false(default) and secure with TLS/middlewares.
This setup works reliably. If Traefik adds static path customization in future versions (post-v3.2), check the docs for updates.