[solved] Routing using PathPrefix and StripPrefix, confusing behavior!

I am just starting with Traefik (migrating from nginx). Main draw for me is the label based config which are muct easier to manage than nginx config files. As a first test subject I am trying to get traefik dashboard and other end points to work. As of now its running on my internal network, not exposed to internet, so I don't want to use a Host rule. I can access the dashboard on a subpath (/traefik) just fine, but the /metrics endpoint isn't working. Since the same config is used for both (i.e. /dashboard and /metrics) I am not sure why the later isn't working.

bash>curl  http://myhost.local:9080
Moved Permanently
bash>curl  http://myhost.local:880/traefik/
<a href="/traefik/dashboard/">Found</a>.

bash>curl  http://myhost.local:880/traefik/metrics
404 page not found
bash>curl  http://myhost.local:9080/metrics
# HELP go_gc_duration_seconds A summary of the pause duration of garbage collection cycles.
# TYPE go_gc_duration_seconds summary

My config:

reverse-proxy:
    image: traefik:latest
    ports:
      - "880:80"
      - "9080:8080"
    command:
     - --entryPoints.web.address=:80
    #  - --log.level=DEBUG
     - --api
     - --api.insecure=true
     - --ping
     - --accesslog=true
     - --providers.docker
     - --providers.docker.exposedByDefault=false
     - --providers.docker.swarmMode=true
     - --metrics=true
     - --metrics.prometheus=true
     - --metrics.prometheus.addrouterslabels=true

    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.role == manager
      labels:
      - traefik.enable=true
      - traefik.http.routers.dashboard.rule= PathPrefix(`/traefik`) || HeadersRegexp(`Referer`, `.*/traefik/.*`)
      - traefik.http.routers.dashboard.middlewares=dashboard-stripprefix
      - traefik.http.middlewares.dashboard-stripprefix.stripprefix.prefixes=/traefik
      - traefik.http.routers.dashboard.service=api@internal
      # Dummy service for Swarm port detection. The port can be any valid integer value.
      - traefik.http.services.dummy-svc.loadbalancer.server.port=9999

Hi @mvadu,

welcome to the traefik community.

This behavoior confused me the first time using it with prometheus, too.

Try adding the following line to your configuration:

    - --metrics.prometheus.manualrouting=true

Hope this helps.

Best regards,
Wolfgang

1 Like

Thank you @wollomatic for that pointer. I ended up with creating another route for prometheus@internal service, and handling the double matches with a !.

  reverse-proxy:
    image: traefik:latest
    ports:
      - "880:80"
    command:
     - --entryPoints.web.address=:80
    #  - --log.level=DEBUG
     - --api
     - --api.insecure=true
     - --ping
     - --accesslog=true
     - --providers.docker
     - --providers.docker.exposedByDefault=false
     - --providers.docker.watch=true
     - --providers.docker.swarmMode=true
     - --providers.docker.network=shared_overlay
     - --metrics=true
     - --metrics.prometheus=true
     - --metrics.prometheus.addrouterslabels=true
     - --metrics.prometheus.manualrouting=true

    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.role == manager
      labels:
      - traefik.enable=true
      - traefik.http.routers.metrics.rule= Path(`/traefik/metrics`)
      - traefik.http.routers.metrics.middlewares=metrics-stripprefix
      - traefik.http.middlewares.metrics-stripprefix.stripprefix.prefixes=/traefik
      - traefik.http.routers.metrics.service=prometheus@internal

      - traefik.http.routers.dashboard.rule= Path(`/traefik`) || (PathPrefix(`/traefik`) && !Path(`/traefik/metrics`)) || HeadersRegexp(`Referer`, `.*/traefik/.*`)
      - traefik.http.routers.dashboard.middlewares=dashboard-stripprefix
      - traefik.http.middlewares.dashboard-stripprefix.stripprefix.prefixes=/traefik
      - traefik.http.routers.dashboard.service=api@internal
      

      # Dummy service for Swarm port detection. The port can be any valid integer value.
      - traefik.http.services.dummy-svc.loadbalancer.server.port=9999

Now I can get metrics end points routed through traefik subpath.

curl http://myhost.local:880/traefik/metrics
# HELP go_gc_duration_seconds A summary of the pause duration of garbage collection cycles.
# TYPE go_gc_duration_seconds summary
1 Like

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