Guide: Moving Traefik Dashboard and API to a Subpath (/traefik/dashboard and /traefik/api)

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 (/dashboard and /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

  1. Save files and run docker compose up -d.
  2. Access dashboard at http://your-host/traefik/dashboard/ (authenticate with your credentials).
  3. Test API at http://your-host/traefik/api/.
  4. Verify sub-API paths like http://your-host/api/overview.
  5. 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 with Host(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.