Traefik as reverse-proxy in front of 2 docker containers exposing one port each

Hi guys,

I am completely new to traefik, so please excuse me still being a noob. I am trying to switch over from a nginx reverse proxy to traefik, but can't get it to work even after hours of fiddling around with it.

Maybe someone can be so kind and point me in the right direction! :smiley:

Following situation:
2 docker containers (named app-test-1 and app-test-2) both run the same node webapp (built Meteor apps) - one container uses/exposes port 3000, the other 3002.

What I need now is a traefik config to handle all the incoming traffic on ports 80/443 and redirect/load-balance to the 2 containers at port 3000 and 3002 - as simple as that. But I can't get it to work for the life of me.

my current docker-compose.yml:

version: "3.8"
services:

  traefik:
    image: traefik:v2.3
    container_name: traefik
    networks:
      - frontend
      - backend
    command:
      - --entrypoints.web="Name:http Address::80"
      - --providers.docker=true
      - --providers.docker.watch=true
      - --providers.docker.network=backend
      - --providers.docker.exposedbydefault=false
      - --api.insecure=true
      - --accesslog.filepath=/var/log/traefik_access.log
      - --log=true
      - --log.filepath=/var/log/traefik.log
      - --log.level=DEBUG
    ports:
      - 80:80
      - 8080:8080
      - 443:443
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - loadbalancerdata:/data
    deploy:
      restart_policy:
        condition: on-failure

  app-test-1:
    build:
      context: /opt/my-app
      dockerfile: ~/scripts/docker/Dockerfile
    image: myapp:build1
    container_name: app-test-1
    networks:
      - backend
    environment:
      - PORT=3000
      - METEOR_SETTINGS
    ports:
      - 3000:3000
    labels:
      - traefik.enable=true
      - traefik.docker.network=backend
      - traefik.http.routers.app-test-1.rule=Host(`test.mydomain.com`)
      - traefik.http.routers.app-test-1.entrypoints=web
      - traefik.http.services.app-test-1.loadbalancer.server.port=3000
      - traefik.http.services.app-test-1.loadbalancer.sticky=true

  app-test-2:
    build:
      context: /opt/my-app
      dockerfile: ~/scripts/docker/Dockerfile
    image: myapp:build1
    container_name: app-test-2
    networks:
      - backend
    environment:
      - PORT=3002
      - METEOR_SETTINGS
    ports:
      - 3002:3002
    labels:
      - traefik.enable=true
      - traefik.docker.network=backend
      - traefik.http.routers.app-test-2.rule=Host(`test.mydomain.com`)
      - traefik.http.routers.app-test-2.entrypoints=web
      - traefik.http.services.app-test-2.loadbalancer.server.port=3002
      - traefik.http.services.app-test-2.loadbalancer.sticky=true

networks:
  frontend:
  backend:

As I said, I am a bit lost here, I really hope someone can help me getting this to work!

Thanks a lot, best,
Patrick

Hi @Twisterking,

Thanks for your interest in Traefik!

First, you have mixed Traefik v1 and v2 configuration in the entrypoint configuration. The Traefik container configuration should look like the following (I've also removed some unnecessary configurations).

Is it normal that there is no entrypoint attached to port 443?

traefik:
    image: traefik:v2.3
    container_name: traefik
    networks:
      - frontend
      - backend
    command:
      - --entrypoints.web.address=:80
      - --providers.docker.network=backend
      - --providers.docker.exposedbydefault=false
      - --api.insecure=true
      - --accesslog.filepath=/var/log/traefik_access.log
      - --log.filepath=/var/log/traefik.log
      - --log.level=DEBUG
    ports:
      - 80:80
      - 8080:8080
      - 443:443
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - loadbalancerdata:/data
    deploy:
      restart_policy:
        condition: on-failure

Then, if you want to load balance all the incoming traffic on port 80 (web) to your app containers you will have to configure the same router and service on your apps. Something like:

app-test-1:
    build:
      context: /opt/my-app
      dockerfile: ~/scripts/docker/Dockerfile
    image: myapp:build1
    container_name: app-test-1
    networks:
      - backend
    environment:
      - PORT=3000
      - METEOR_SETTINGS
    ports:
      - 3000:3000
    labels:
      - traefik.enable=true
      - traefik.docker.network=backend
      - traefik.http.routers.app-test.rule=Host(`test.mydomain.com`)
      - traefik.http.routers.app-test.entrypoints=web
      - traefik.http.services.app-test.loadbalancer.server.port=3000
      - traefik.http.services.app-test.loadbalancer.sticky=true

  app-test-2:
    build:
      context: /opt/my-app
      dockerfile: ~/scripts/docker/Dockerfile
    image: myapp:build1
    container_name: app-test-2
    networks:
      - backend
    environment:
      - PORT=3002
      - METEOR_SETTINGS
    ports:
      - 3002:3002
    labels:
      - traefik.enable=true
      - traefik.docker.network=backend
      - traefik.http.routers.app-test.rule=Host(`test.mydomain.com`)
      - traefik.http.routers.app-test.entrypoints=web
      - traefik.http.services.app-test.loadbalancer.server.port=3002
      - traefik.http.services.app-test.loadbalancer.sticky=true

As a side note, if your apps are the same maybe you could look at the docker-compose scale option. By doing that, you will have to configure your app router and service only once and leverage docker-compose to scale your service.

Hope this helps!

Hello,

Thanks a lot for your help, I got it working! :smiley:

I ended up with the following traefik container:

traefik:
  image: traefik:v2.3
  container_name: traefik
  command:
    - --entrypoints.web.address=:80
    - --entrypoints.websecure.address=:443
    - --providers.docker=true
    - --providers.docker.watch=true
    - --providers.docker.exposedbydefault=false
    - --api.insecure=true
    - --certificatesresolvers.le.acme.email=email@mydomain.com
    - --certificatesresolvers.le.acme.storage=/acme.json
    - --certificatesresolvers.le.acme.httpchallenge.entrypoint=web
    - --certificatesresolvers.le.acme.tlschallenge=true
    - --accesslog.filepath=/var/log/traefik_access.log
    - --log=true
    - --log.filepath=/var/log/traefik.log
    - --log.level=DEBUG
  ports:
    - 80:80
    - 8080:8080
    - 443:443
  volumes:
    - "/var/run/docker.sock:/var/run/docker.sock:ro"
    - "./acme.json:/acme.json"
    - loadbalancerdata:/data
  restart: unless-stopped

... now I am a bit stuck at getting to run another nodejs app, my worker:

worker:
  image: myworkerimage
  container_name: myworker
  environment:
    - PORT=3010
    - METEOR_SETTINGS
  ports:
    - 3010:3010
  labels:
    - traefik.enable=true
    - traefik.http.routers.worker.rule=Host(`worker.mydomain.com`)
    - traefik.http.routers.worker.tls=true
    - traefik.http.routers.worker.tls.certresolver=le
    - traefik.http.routers.worker.entrypoints=websecure
    - traefik.http.services.worker.loadbalancer.server.port=3010
  restart: unless-stopped

When I now try to access worker.mydomain.com, no matter if I try http or https, I always end up with either a "404 page not found" error or "gateway timeout" ... logs show absolutely nothing.

Can you please help again and tell me what I am doing wrong here?

Thanks a lot, cheers, Patrick


EDIT: Maybe I need to use networks to make this work? I would prefer to get it working without networks though, because I am working with 2 seperate docker-compose.yml files here - the main app with its 2 instances has one compose file, and the worker (in a separate directory!) has also its own compose file!

One more thing: Why are all my logs completely empty? I have both my log files set at chmod 777 but they are still empty. Do I need to "mount" the /var/log directy via volumes?

Hello @Twisterking,

Maybe I need to use network s to make this work? I would prefer to get it working without networks though, because I am working with 2 seperate docker-compose.yml files here - the main app with its 2 instances has one compose file, and the worker (in a separate directory!) has also its own compose file!

When you deploy a stack with docker-compose a network will be created by default as explained in the following documentation. That being said, if Traefik and your worker are not in the same network, Traefik will not be able to forward the request to the worker container and return a Gateway Timeout error. In order to fix that, you could use external networks as explained here.

One more thing: Why are all my logs completely empty? I have both my log files set at chmod 777 but they are still empty. Do I need to "mount" the /var/log directy via volumes ?

I've just made a test and if I look at the content of the file inside the container and the logs are well written. How do you access those logs?

Hope this helps.

Thanks a bunch for your clarifications! I think I understand now how this all works together and got it working! :smiley: if any other problems come up I will post here.

Great work on traefik guys!

Okay, I got one more thing:
Additionally to my several docker containers/apps, I have a java applet running on port 8070 which should also be exposed on a certain domain behind a "basic-auth" wall.

I tried the following docker-compose.yml:

traefik:
  image: traefik:v2.3
  container_name: traefik
  command:
    - --entrypoints.web.address=:80
    - --entrypoints.websecure.address=:443
    - --providers.docker=true
    - --providers.docker.watch=true
    - --providers.docker.exposedbydefault=false
    - --api.insecure=true
    - --certificatesresolvers.le.acme.email=dev@app.com
    - --certificatesresolvers.le.acme.storage=/acme.json
    - --certificatesresolvers.le.acme.httpchallenge.entrypoint=web
    - --certificatesresolvers.le.acme.tlschallenge=true
    - --log=true
    - --log.filepath=/var/log/traefik.log
    - --log.level=DEBUG
  ports:
    - 8080:8080
    - 443:443
  labels:
    - "traefik.http.middlewares.javaapplet-auth.basicauth.users=verwalter:$$blubblabbleb"
    - "traefik.http.routers.javaapplet.rule=Host(`applet.mydomain.com`)"
    - "traefik.http.routers.javaapplet.entrypoints=web"
    - "traefik.http.routers.javaapplet.middlewares=javaapplet-auth"
    - "traefik.http.services.javaapplet.loadbalancer.server.port=8070"
  volumes:
    - "/var/run/docker.sock:/var/run/docker.sock:ro"
    - "./acme.json:/acme.json"
    - "/var/log:/var/log"
    - loadbalancerdata:/data
  networks:
    - web
  restart: unless-stopped

What am I doing wrong here? I always end up just with a 404 error page.

Thanks a lot in advance! :smiley:

Sidenote: I feel like you guys really have to improve your docs. Traefik is not that complicated, but for some reason I can't for the life of me figure out the simplest stuff! :frowning_face: There are so many different config options. For example: I couldn't find any docs for having a "global config" via labels for the traefik container itself anywhere - where are the docs for this feature?

Is it normal that the configuration labels for the javaapplet app are defined on the Traefik container?

Maybe I am missing something here but my java applet is NOT running inside a docker container. Or would I have to do exactly that and it won't work without it?! At the moment the java applet is just running on the host server itself.

It's possible to use labels on the Traefik container to configure a service but this service will have the IP of the Traefik container. The service you are trying to call should be accessible on the same IP. Maybe you can use the Host networking mode in order to do that as explained in the following documentation.

By the way, I think you forgot to add the traefik.enable=true label configuration to the Traefik container configuration as explained here.

For your next questions (not related to the main topic), I think it's better to create a new topic. This topic will be easier to find if someone encounters the same problem.

Hope this helps.

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