How to manage multiple ports exposed on port 80 with docker?

I have the following setup:

version: '3'

services:
  traefik:
    image: traefik:v2.0
    container_name: traefik
    ports:
      - 80:80
    command:
      - --api.debug=true
      - --api.insecure=true
      - --providers.docker=true
      - --entrypoints.web.address=:80
      - --providers.docker.exposedByDefault=true
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    labels:
      - traefik.http.routers.traefik.service=api@internal
      - traefik.http.routers.traefik.rule=Host(`monitor.domain.org`)
      - traefik.http.routers.traefik.entrypoints=web
    networks:
      - web
  db:
    image: registry.domain.com/repo/db:latest
    container_name: db
    restart: always
    networks:
      - internal
  api:
    image: registry.domain.com/repo/api:latest
    container_name: api
    ports:
      - 80:3001
    volumes:
      - /root/rsa.pem:/root/certs/rsa.pem
      - /root/rsa_pub.pem:/root/certs/rsa_pub.pem
    restart: always
    depends_on:
      - db
    environment:
      - MAIL_ADDRESS=${MAIL_ADDRESS}
      - MAIL_PASSWORD=${MAIL_PASSWORD}
      - MAIL_HOST=${MAIL_HOST}
    labels:
      - traefik.http.routers.api.rule=Host(`api.domain.org`)
      - traefik.http.routers.api.entrypoints=web
    networks:
      - internal
      - web
  app:
    image: registry.domain.com/repo/app:latest
    container_name: app
    restart: always
    depends_on:
      - api
      - db
    labels:
      - traefik.http.routers.app.rule=Host(`domain.org`,`www.domain.org`)
      - traefik.http.routers.app.entrypoints=web
    networks:
      - web

networks:
  web:
    external: true
  internal:
    external: false

Obviously I get an error from docker saying Bind for 0.0.0.0:80 failed: port is already allocated. Either exposing the port 80 of the traefik service or the api service separately works perfectly. If I do not expose the port 80 on those both services it does not work for both of them. The app service which runs on Nginx works without exposing port 80 seamlessly. How can I make the api and traefik service both run together on port 80?

Regards,

Thilo

Hello,

you don't need to expose the port of your service named api, you just need to define the port of the related service: traefik.http.services.<name>.loadbalancer.server.port=<port number>

version: '3'

services:
  traefik:
    image: traefik:v2.0
    container_name: traefik
    ports:
      - 80:80
    command:
      - --api=true
      - --providers.docker=true
      - --entrypoints.web.address=:80
      - --providers.docker.exposedByDefault=true
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    labels:
      - traefik.http.routers.traefik.service=api@internal
      - traefik.http.routers.traefik.rule=Host(`monitor.domain.org`)
      - traefik.http.routers.traefik.entrypoints=web
    networks:
      - web

  db:
    image: registry.domain.com/repo/db:latest
    container_name: db
    restart: always
    networks:
      - internal

  api:
    image: registry.domain.com/repo/api:latest
    container_name: api
    volumes:
      - /root/rsa.pem:/root/certs/rsa.pem
      - /root/rsa_pub.pem:/root/certs/rsa_pub.pem
    restart: always
    depends_on:
      - db
    environment:
      - MAIL_ADDRESS=${MAIL_ADDRESS}
      - MAIL_PASSWORD=${MAIL_PASSWORD}
      - MAIL_HOST=${MAIL_HOST}
    labels:
      - traefik.http.routers.api.rule=Host(`api.domain.org`)
      - traefik.http.routers.api.entrypoints=web
      - traefik.http.services.api.loadbalancer.server.port=3001
    networks:
      - internal
      - web

  app:
    image: registry.domain.com/repo/app:latest
    container_name: app
    restart: always
    depends_on:
      - api
      - db
    labels:
      - traefik.http.routers.app.rule=Host(`domain.org`,`www.domain.org`)
      - traefik.http.routers.app.entrypoints=web
    networks:
      - web

networks:
  web:
    external: true
  internal:
    external: false
1 Like

@ldez Thank you for your effort! I dont know why but this does not seam to work in my case. I am also wondering why there is a difference between the app service and the api. The app is Nginx and the api is a node container. Here is my repo:

https://gitlab.thiloilg.com/repo/blicc/blob/master/docker-compose.yml

The weird thing is when I expose port 80 separately for each service it works perfectly.

I think your problem is related to your network configuration.

app uses web.
api uses web and internal

So try to set the same network for all your containers or use the label traefik.docker.network

https://docs.traefik.io/v2.0/providers/docker/#traefikdockernetwork


Also:

1 Like

@ldez Yes I think you are right this is probably my network setup. So I tried to add the label - traefik.docker.network=web to the api to tell traefik that it should use this network instead of the internal but this does not seam to work. What am I doing wrong here?

I probably should just use one network and use Traefik for securing the database. Is there any boilerplate with a Traefik docker compose setup I can take a look at?

There is an example in the documentation here: https://docs.traefik.io/user-guides/docker-compose/basic-example/

1 Like