Adding Traefik StripPrefix middleware to docker-compose labels results in 504

Viewed 7773

I have developed several docker-ized full-stack web applications that I am trying to route requests to using Traefik. I want to take advantage of the dynamic configuration via docker-compose labels. I would like to apply the stripPrefix middleware option so I can use the same application routing as if each app were served at the root. However, once these rules are applied it results in a 504 Gateway Timeout response.

Here's my set up:

  • Traefik 2.0.1
  • Docker 19.03.2, Compose 1.24.1
  • NGINX:latest images
  • A global docker network on which the Traefik container runs
  • Multiple multi-container applications, each of which includes an NGINX web server
  • All applications have their own local networks and the NGINX containers are also on the global network.
  • Each application is configured to be listening at /

Here is the docker-compose.yml definition for the offending NGINX container:

nginx:
        image: nginx:latest
        container_name: "mps_nginx"
        volumes:
        - ./nginx/confs/nginx.conf:/etc/nginx/default.conf
        - ./static:/www/static
        restart: "always"
        labels:
            - traefik.http.routers.mps.rule=Host(`localhost`) && PathPrefix(`/mps`)
            - traefik.http.middlewares.strip-mps.stripprefix.prefixes=/mps
            - traefik.http.routers.mps.middlewares=strip-mps@docker
        networks:
        - default
        - mps

The aggravating part is, when I comment out the middlewares labels, it runs just fine but cannot find a matching URL pattern.

Prior to this I tested my approach using the whoami container that is defined in the Traefik Quickstart Tutorial:

# Test service to make sure our local docker-compose network functions
  whoami:
    image: containous/whoami
    labels:
      - traefik.http.routers.whoami.rule=Host(`localhost`) && PathPrefix(`/whoami`)
      - traefik.http.middlewares.strip-who.stripprefix.prefixes=/whoami
      - traefik.http.routers.whoami.middlewares=strip-who@docker

A request to http://localhost/whoami returns (among other things) GET / HTTP/1.1.

This is exactly how I expected my routing approaches to work for all my other applications. The Traefik dashboard shows green all around for every middleware I register and yet all I see is 504 errors.

If anyone has any clues I would sincerely appreciate it.

3 Answers

There is an issue with prefix without ending with '/'. Test your config like this:

      - "traefik.http.routers.whoami.rule=Host(`localhost`) && (PathPrefix(`//whoami/`) || PathPrefix(`/portainer`))"
      - "traefik.http.middlewares.strip-who.stripprefix.prefixes=/whoami"

To summarize my solution to a similar problem

  my-service:
    image: some/image
    ports: # no need to expose port, just to show that service listens on 8090
      - target: 8090
        published: 8091
        mode: host
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.myservice-router.rule=PathPrefix(`/myservice/`)"
      - "traefik.http.routers.myservice-router.service=my-service"
      - "traefik.http.services.myservice-service.loadbalancer.server.port=8090"
      - "traefik.http.middlewares.myservice-strip.stripprefix.prefixes=/myservice"
      - "traefik.http.middlewares.myservice-strip.stripprefix.forceslash=false"
      - "traefik.http.routers.myservice-router.middlewares=myservice-strip"

Now details

Routing rule

... redirect all calls thats path starts with /myservice/

- "traefik.http.routers.myservice-router.rule=PathPrefix(`/myservice/`)"

... to service my-service

- "traefik.http.routers.myservice-router.service=my-service"``

... to port 8090

- "traefik.http.services.myservice-service.loadbalancer.server.port=8090"

... and uses myservice-strip middleware

- "traefik.http.routers.myservice-router.middlewares=myservice-strip"

... this middleware will strip /myservice from path

- "traefik.http.middlewares.myservice-strip.stripprefix.prefixes=/myservice"

... and will not add trailing slash (/) if path becomes an empty string

- "traefik.http.middlewares.myservice-strip.stripprefix.forceslash=false"

I had a similar problem that was solved with the addition of

- "traefik.http.middlewares.strip-who.stripprefix.forceslash=true"

It makes sure the strip prefix doesn't also remove the forward slash.

You can read more about the forceslash documentation https://docs.traefik.io/middlewares/stripprefix/

Related