Traefik with multiple apps

Hello,

I'm trying to create multiple nodeJS apps stored on the same subdomain.
I'm managing those actions using ocker-compose. and for some reason i have an error while trying to use more then one middleware.
when I'm trying to use "replace regex" and "prefix strip" at the same time, it looks like only one of them is activating and the one written the last is overrides the first one.

traefik docker-compose

version: "3"

services:
  traefik:
    image: traefik:v2.0
    restart: always
    container_name: traefik
    ports:
      - "80:80" 
      - "8080:8080" 
    command:
      - --api.insecure=true
      - --api.dashboard=true 
      - --api.debug=true
      - --log.level=DEBUG
      - --providers.docker=true 
      - --providers.docker.exposedbydefault=false 
      - --entrypoints.web.address=:80

    volumes:
      - ./letsencrypt:/letsencrypt 
      - /var/run/docker.sock:/var/run/docker.sock 
      - ./dynamic.yaml:/dynamic.yaml 
    networks:
      - docker_secure-worker
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.api.rule=Host(`sub.domain.cloud`) && PathPrefix(`/`)" 
      - "traefik.http.routers.api.service=api@internal"


  node:
    image: worker_image
    command: python3 /app/node/run_app_node.py -m mongo -d node
    hostname: node
    restart: unless-stopped
    environment:
      PYTHONPATH: "/plugins:/app"
      DATASTORE_PATH: "/datastore"
      PLUGINS_PATH: "/plugins"
      VSFTPD_DIR: "/etc/vsftpd"
    ports:
      - "9999:9999"
    volumes:
      - '/secure/docker/volumes/node/datastore/:/datastore'
      - '/secure/docker/volumes/node/plugins/:/plugins'
      - '/secure/docker/volumes/node/vsftpd:/etc/vsftpd'
    networks:
      - docker_secure-worker
    cap_add:
      - SYS_PTRACE
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.worker.entrypoints=web"
      - "traefik.http.routers.worker.rule=Host(`sub.domain.cloud`) && PathPrefix(`/node`)"
      - "traefik.http.middlewares.test-replacepathregex.replacepathregex.regex=http://sub.domain.cloud/node/$$"
      - "traefik.http.middlewares.test-replacepathregex.replacepathregex.replacement=http://sub.domain.cloud/home"
      - "traefik.http.middlewares.node-strip.stripprefix.prefixes=/node"
      - "traefik.http.middlewares.node-strip.stripprefix.forceslash=true"
      - "traefik.http.routers.worker.middlewares=test-replacepathregex@docker"






networks:
  docker_secure-worker:
    external: true

I think I am missing something obvious but I definitely can't tell what. Hoping you can help.

Thanks!

Havent You forgot to create a chain for multiple middlewares?
https://docs.traefik.io/middlewares/chain/

@suxarik note that you do not have to use chain for multiple middlewares. According to the link you provided this is mostly to be able to re-use the same sequence of middlewares in multiple place. If you only use them in a single place, the chain is not useful.

Correct! See this answer.

@dor12126, have you resolved your challenge?

Hi ! , I tried with the link given for the correct answer. But I think Im going somewhere wrong with my configuration.

I already have a main app running as a service on the main domain. say : https://abc.com
My intentions is to host another app as a different service on https://abc.com/app2
I have pasted both the service labels here.

mainapp :

       labels:
        - "traefik.enable=true"
   # Routers 
        - "traefik.http.routers.mainapp.rule=Host(`abc.com`)"
        - "traefik.http.routers.mainapp.service=mainapp"
        - "traefik.http.routers.mainapp.entrypoints=web"
        - "traefik.http.routers.mainapp.middlewares=test-redirectscheme"
        - "traefik.http.routers.mainapp-secure.rule=Host(`abc.com`)"
        - "traefik.http.routers.mainapp-secure.entrypoints=websecure"
        - "traefik.http.routers.mainapp-secure.tls.certresolver=newresolver"
   # Services
        - "traefik.http.services.mainapp.loadbalancer.server.port=3000"
   # Middleware
        - "traefik.http.middlewares.test-redirectscheme.redirectscheme.scheme=https"
        - "traefik.http.middlewares.test-redirectscheme.redirectscheme.permanent=true"
   # Network
        - "traefik.docker.network=network1"

app2 :

       labels:
        - "traefik.enable=true"
   # Routers 
        - "traefik.http.routers.app2.rule=Host(`abc.com`) && PathPrefix(`/app2`)"
        - "traefik.http.routers.app2.service=app2"
        - "traefik.http.routers.app2.entrypoints=websecure"
        - "traefik.http.routers.app2.middlewares=test-redirectscheme"
        - "traefik.http.routers.app2.tls.certresolver=newresolver"
    # Services
        - "traefik.http.services.app2.loadbalancer.server.port=80"
   # Middleware
        - "traefik.http.middlewares.test-redirectscheme.redirectscheme.scheme=https"
        - "traefik.http.middlewares.test-redirectscheme.redirectscheme.permanent=true" 
   # Network
        - "traefik.docker.network=network1"

mainapp works fine with the domain https://abc.com but the
app2 on the url https://abc.com/app2 gives a 404.

Can't make out where I'm going wrong with the Paths.

Looking for some help.

I guess app2 does not expect the prefix /app2 in the request, as it is forwarded to app2.

Maybe you want / need to include this:

        - "traefik.http.routers.app2.middlewares=test-redirectscheme,app2-stripprefix"
        - "traefik.http.middlewares.app2-stripprefix.stripprefix.prefixes=/app2"
        - "traefik.http.middlewares.app2-stripprefix.stripprefix.forceslash=true"
1 Like

Thanks for the solution. I removed the PathPrefix. and added the two stripprefix middleware. Now the abc.com also opens up app2 instead of mainapp.
I am looking to have the main app on abc.com and the app2 on abc.com/app2

Hi, you still need to keep the PathPrefix.
The PathPrefix rule and the stripprefix middleware serve completely different purposes.

  • The PathPrefix rule is used to route all request within /app2 to to your app2 service.
  • The stripprefix middleware modifies the request presented to the service app2.

If you call htts://abc.com/app2/test.html without stripprefix, then Traefik sends an request for /app2/test.html to app2. But with stripprefix Traefik sends an request for /test.html to app2, thus removing the /app2/ component.

It might or might not work - depending on how app2 creates links. If app2 use absolute links like https://abc.com/css/style.css instead of a relative css/style.css, then it will not work, as those requests still will be send to app1.

1 Like

Thanks much for explaining. understood it better now.

So now, here is my config, but still getting 404. The mainapp on a different stack, works fine on main domain . The maindomain/app2 throws 404. I'm trying to give more thoughts to this..

  labels:
        - "traefik.enable=true"
   # Routers 
        - "traefik.http.routers.app2.rule=Host(`maindomain.com`) && PathPrefix(`/app2`)"
        - "traefik.http.routers.app2.service=app2"
        - "traefik.http.routers.app2.entrypoints=websecure"
        - "traefik.http.routers.app2.middlewares=test-redirectscheme,app2-stripprefix"
        - "traefik.http.routers.app2.tls.certresolver=newresolver"
    # Services
        - "traefik.http.services.app2.loadbalancer.server.port=80"
   # Middleware
        - "traefik.http.middlewares.test-redirectscheme.redirectscheme.scheme=https"
        - "traefik.http.middlewares.test-redirectscheme.redirectscheme.permanent=true" 
        - "traefik.http.middlewares.app2-stripprefix.stripprefix.prefixes=/app2"
        - "traefik.http.middlewares.app2-stripprefix.stripprefix.forceslash=true"
   # Network
        - "traefik.docker.network=network1"

It now works :slight_smile:

This is the working config for app2 , same as you suggested

labels:
        - "traefik.enable=true"
   # Routers 
        - "traefik.http.routers.app2.rule=Host(`maindomain.com`) && PathPrefix(`/app2`)"
        - "traefik.http.routers.app2.service=app2"
        - "traefik.http.routers.app2.entrypoints=websecure"
        - "traefik.http.routers.app2.middlewares=test-redirectscheme,app2-stripprefix"
        - "traefik.http.routers.app2.tls.certresolver=newresolver"
    # Services
        - "traefik.http.services.app2.loadbalancer.server.port=80"
   # Middleware
        - "traefik.http.middlewares.test-redirectscheme.redirectscheme.scheme=https"
        - "traefik.http.middlewares.test-redirectscheme.redirectscheme.permanent=true" 
        - "traefik.http.middlewares.app2-stripprefix.stripprefix.prefixes=/app2"
        - "traefik.http.middlewares.app2-stripprefix.stripprefix.forceslash=true"
   # Network
        - "traefik.docker.network=network1"

I also had to a pathprefix to the main apps host rule, so that it could start redirecting to the subpages ( referred to this post , second answer by Timo : go - Multi path routing with traefik marathon on the same host - Stack Overflow )

"traefik.http.routers.mainapp.rule=Host(`maindomain . com`) && PathPrefix(`/`)"

and this worked like a charm.

now only issue is on the browser the /app2/ renders the app correctly but if only /app2 in the address doesn't renders the css. I have to add / to ensure that app renders correctly. Any clues to solve this issue ?

Please try setting forceslash=false:

        - "traefik.http.middlewares.app2-stripprefix.stripprefix.forceslash=false"

It maybe enough to fix the problem. Otherwise you could cheat and do a redirect to /app2/ if only /app2 is called.

1 Like

Thanks for the Tip :slight_smile: :slight_smile:
Setting the value to 'false' did not work.
Shall try the cheat and redirect.

Hi,

it should work without this trick.... But anyways:

You can use another middleware to redirect /app2 => /app2/, which should solve the issue.

        - "traefik.http.middlewares.app2-redirect.redirectregex.regex=^(.*/app2)$$"
        - "traefik.http.middlewares.app2-redirect.redirectregex.replacement=$${1}/"

The middleware must go before the stripprefix:

        - "traefik.http.routers.app2.middlewares=test-redirectscheme,app2-redirect,app2-stripprefix"

By the way:
You can remove the test-redirectscheme middleware, as you are only listening on websecure - so there are no http connections.

And just another quick remark:
In the future it is better to start a new thread instead posting in an 1.5 year old oneb y someone else.

1 Like

Awesome ! this works like flawlessly. :smiley: :smiling_face_with_three_hearts: :partying_face:
After adding the regex , I set the forceslash as true again.

and thanks for the suggestion ,shall open a new thread next time. :slight_smile: