PathPrefix and strip

Hi,
I'd like to route requests based on Host and Path (PathPrefix) for portainer service.
Running traefik v2 of course.
So i have docker-compose.yml for portainer with such entries:

    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.portainer.rule=Host(`admin.domain.name`) && PathPrefix(`/portainer`)"
      - "traefik.http.middlewares.portainerpathstrip.stripprefix.prefixes=/portainer"
      - "traefik.http.routers.portainer.middlewares=portainerpathstrip@docker"
      - "traefik.http.routers.portainer.entrypoints=http"
      - "traefik.http.routers.portainer.service=portainer"
      - "traefik.http.services.portainer.loadbalancer.server.port=9000"

But unfortunately it does not work. As first request is fine, but next ones come with 404 error.
The idea is to have one admin.domain.name host with a few /service1, /service2 /servicen routed to the appropriate containers.
How to achive this?
https://docs.traefik.io/v2.0/middlewares/stripprefix/

Use a StripPrefix middleware if your backend listens on the root path ( / ) but should be routeable on a specific prefix.

I posted some thoughts on a similar topic here:

In your case imaging that you are accessing portainer at http://host/portainer/mainpage for the sake of an example. Portainer does not expect to be hosted at /portainer. So all references to other pages and/or assets might be on the page in form of /asset/bla that is absolute. In this case your browser will request from trafik http://host/asset/bla with portainer nowhere to be seen. Of course you will get 404 in that case.

This is not a traefik limitation. It's just that many web application are not written to be used this way. Not much you, or traefik can do about that.

For reasons outlined above I would personally not go for this approach, this is just inviting misery. One way when this is workable if all /service1 /service2 /servicen is written by you and/or your company, so you can make sure that they play nice and support being hosted on arbitrary URLs. Another way this is workable if application author is willing to support this which might be indicated in their documentation with examples of setting up reverse proxy for their app in this way.

got it working with such config:

labels:
      - "traefik.enable=true"
      - "traefik.http.routers.portainer.rule=Host(`admin.domain.name`) && PathPrefix(`/portainer/`)"
      - "traefik.http.middlewares.portainerpathstrip.stripprefix.prefixes=/portainer"
      - "traefik.http.routers.portainer.middlewares=portainerpathstrip@docker"
      - "traefik.http.routers.portainer.entrypoints=http"
      - "traefik.http.routers.portainer.service=portainer"
      - "traefik.http.services.portainer.loadbalancer.server.port=9000"

Note the ending '/' in PathPrefix. Also, i need to connect (browser) to admin.domain.name/portainer/
This way, it works.

EDIT:

3 Likes

Thanks for the config! However, this is working with portainer, but if I configure some of my other services the same way, it doesn't work and the path gets stripped. As @przemas75 mentioned, I have the following portainer configuration:

    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.portainer.rule=Host(`example.com`) && PathPrefix(`/portainer/`)"
      - "traefik.http.middlewares.portainerpathstrip.stripprefix.prefixes=/portainer"
      - "traefik.http.routers.portainer.middlewares=portainerpathstrip@docker"
      - "traefik.http.routers.portainer.entrypoints=web"
      - "traefik.http.routers.portainer.service=portainer"
      - "traefik.http.services.portainer.loadbalancer.server.port=9000"

That currently works. Adding some more services like:

    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.loccmsapi.rule=Host(`example.com`) && PathPrefix(`/loccmsapi/`)"
      - "traefik.http.middlewares.loccmsapipathstrip.stripprefix.prefixes=/loccmsapi"
      - "traefik.http.routers.loccmsapi.middlewares=loccmsapipathstrip@docker"
      - "traefik.http.routers.loccmsapi.entrypoints=web"
      - "traefik.http.routers.loccmsapi.service=loccmsapi"
      - "traefik.http.services.loccmsapi.loadbalancer.server.port=80"

Receives the requests, but when I go to example.com/loccmsapi/swagger it loads the request but fails with the internal ones as it strips the path:

1. Request URL:http://example.com/swagger/v1/swagger.json
2. Request Method: GET
3. Status Code: 404 Not Found

But the file exists at http://example.com/loccmsapi/swagger/v1/swagger.json

What am I missing?

Uhm, when you request http://example.com/swagger/v1/swagger.json why do you expect http://example.com/loccmsapi/swagger/v1/swagger.json to be hit?

Is it possible, in Traefik, to add the prefix loccmsapito each and every requests made by the loccmsapi service, so that it can find its internal resources?