Traefik listening twice to ports

I am a noob here trying to configure safe external access to various home services (jellyfin, homeassistant, etc.). I can’t figure out how to get Traefik to work properly, and I don’t know where in the process the issue is. The stripped down relevant pieces of my docker compose file is as follows:

networks:
  mediastack:
    name: mediastack
    driver: bridge
    ipam:
      driver: default
      config:
      - subnet: ${DOCKER_SUBNET:?err}
        gateway: ${DOCKER_GATEWAY:?err}
services:
 traefik:
    image: traefik:latest
    container_name: traefik
    restart: unless-stopped
    networks:
      - mediastack
    user: root
    environment:
      - TZ=${TIMEZONE:?err}
      - CF_DNS_API_TOKEN=${CLOUDFLARE_DNS_API_TOKEN:?err}
    ports:
      - ${REVERSE_PROXY_PORT_HTTP:?err}:80
      - ${REVERSE_PROXY_PORT_HTTPS:?err}:443
      - ${WEBUI_PORT_TRAEFIK:?err}:8080
      - ${METRICS_PORT_TRAEFIK:?err}:8082
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ${FOLDER_FOR_DATA:?err}/logs/traefik:/var/log
      - ${FOLDER_FOR_DATA:?err}/traefik:/etc/traefik
      - ${FOLDER_FOR_DATA:?err}/traefik/letsencrypt:/letsencrypt
    labels:
      - traefik.enable=true
    # ROUTERS
      - traefik.http.routers.traefik.service=api@internal
      - traefik.http.routers.traefik.rule=Host(`traefik.${CLOUDFLARE_DNS_ZONE:?err}`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))
      - traefik.http.routers.traefik.entrypoints=secureweb
      - traefik.http.routers.traefik.middlewares=authentik-forwardauth@file,security-headers@file,traefik-bouncer@file
    # SERVICES
      - traefik.http.services.traefik.loadbalancer.server.scheme=http
      - traefik.http.services.traefik.loadbalancer.server.port=8080
    # MIDDLEWARES
  traefik-certs-dumper:
    image: ldez/traefik-certs-dumper:latest
    container_name: traefik-certs-dumper
    restart: always
    networks:
      - mediastack
    user: ${PUID:?err}:${PGID:?err}
    entrypoint: sh -c '
      while ! [ -e /data/acme.json ]
      || ! [ `jq ".[] | .Certificates | length" /data/acme.json | jq -s "add" ` != 0 ]; do
      sleep 1
      ; done
      && traefik-certs-dumper file --version v2 --watch
      --source /data/acme.json --dest /certs'
    volumes:
      - ${FOLDER_FOR_DATA:?err}/traefik/letsencrypt:/data:ro
      - ${FOLDER_FOR_DATA:?err}/traefik-certs-dumper:/certs
  crowdsec:
    image: crowdsecurity/crowdsec:latest
    container_name: crowdsec
    restart: always
    networks:
      - mediastack
    user: ${PUID:?err}:${PGID:?err}
    environment:
      - TZ=${TIMEZONE:?err}
    ports:
      - 127.0.0.1:${CROWDSEC_PORT:?err}:8080
      - 6060:6060        # Provides Metrics for Prometheus
      - 7422:7422        # Provides WAF AppSec
    depends_on:
      - traefik
    volumes:
      - ${FOLDER_FOR_DATA:?err}/crowdsec:/etc/crowdsec
      - ${FOLDER_FOR_DATA:?err}/crowdsec/data:/var/lib/crowdsec/data/
      - ${FOLDER_FOR_DATA:?err}/logs:/logs:ro
  postgresql:
    image: docker.io/library/postgres:latest
    container_name: postgresql
    restart: unless-stopped
    networks:
      - mediastack
    user: ${PUID:?err}:${PGID:?err}
    ports:
      - ${POSTGRESQL_PORT:?err}:5432
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
      start_period: 20s
      interval: 30s
      retries: 5
      timeout: 5s
    volumes:
      - ${FOLDER_FOR_DATA:?err}/postgresql:/var/lib/postgresql
    environment:
      - TZ=${TIMEZONE:?err}
      - POSTGRES_DB=${AUTHENTIK_DATABASE:?err}
      - POSTGRES_USER=${POSTGRESQL_USERNAME:?err}
      - POSTGRES_PASSWORD=${POSTGRESQL_PASSWORD:?err}

My .env includes:

WEBUI_PORT_TRAEFIK=8080
REVERSE_PROXY_PORT_HTTP=81
REVERSE_PROXY_PORT_HTTPS=5443
CROWDSEC_PORT=9080
METRICS_PORT_TRAEFIK=8083

I have 3 files related to Traefik (with my domain obscured below):

traefik-static.yaml

global:
checkNewVersion: true
sendAnonymousUsage: true

log:
level: INFO    # Options are:  TRACE , DEBUG , INFO , WARN , ERROR , FATAL , and PANIC

accessLog:
filePath: /var/log/access.log
format: json

api:
dashboard: true
insecure: true

entryPoints:
web:
address: :80
http:
redirections:
entryPoint:
to: secureweb
scheme: https
permanent: true
secureweb:
address: :443
http:
tls:
options: default
certResolver: letsencrypt
domains:
- main: example.com
sans:
- "*.example.com"
metrics:
address: :8083

metrics:
prometheus:
entryPoint: metrics
manualRouting: true
headerLabels:
useragent: User-Agent
buckets:
- 0.1
- 0.3
- 1.2
- 5.0

providers:
docker:
exposedByDefault: false
file:
directory: /etc/traefik
watch: true

certificatesResolvers:
letsencrypt:
acme:
storage: /letsencrypt/acme.json
keyType: EC384
caServer: https://acme-v02.api.letsencrypt.org/directory
dnsChallenge:
provider: cloudflare
resolvers:
- 1.1.1.1:53
- 1.0.0.1:53
propagation:
delayBeforeChecks: 2s

experimental:
plugins:
crowdsec-bouncer-traefik-plugin:
moduleName: 

version: v1.4.2

traefik-dynamic.yaml
tls:
stores:
default:
defaultGeneratedCert:
resolver: letsencrypt
domain:
main: ``example.com
sans:
- "*.example.com"
options:
default:
minVersion: VersionTLS12
cipherSuites:
- TLS_AES_256_GCM_SHA384
- TLS_CHACHA20_POLY1305_SHA256
- TLS_AES_128_GCM_SHA256
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
curvePreferences:
- CurveP521
- CurveP384
sniStrict: true

http:
middlewares:
security-headers:
headers:
accessControlAllowCredentials: true
accessControlAllowHeaders: "*"
accessControlAllowMethods:
- GET
- OPTIONS
- PUT
accessControlAllowOriginList:
- ``https://example.com
- https://*.example.com
accessControlMaxAge: 100
addVaryHeader: true
browserXssFilter: true
stsSeconds: 63072000
stsIncludeSubdomains: true
stsPreload: true
forceSTSHeader: true
frameDeny: true
customFrameOptionsValue: SAMEORIGIN
contentTypeNosniff: true
# contentSecurityPolicy: default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'none'
referrerPolicy: strict-origin-when-cross-origin
permissionsPolicy: camera=(), microphone=(), geolocation=(), payment=(), usb=()

authentik-forwardauth:
forwardAuth:
address: ``http://authentik:9000/outpost.goauthentik.io/auth/traefik
trustForwardHeader: true
authResponseHeaders:
- X-authentik-username
- X-authentik-groups
- X-authentik-email
- X-authentik-name
- X-authentik-uid
- X-authentik-jwt
- X-authentik-meta-jwks
- X-authentik-meta-outpost
- X-authentik-meta-provider
- X-authentik-meta-app
- X-authentik-meta-version

traefik-bouncer:
plugin:
crowdsec-bouncer-traefik-plugin:
enabled: true
defaultDecisionSeconds: 60
crowdsecMode: live
crowdsecAppsecEnabled: false
crowdsecAppsecHost: crowdsec:7422
crowdsecAppsecFailureBlock: true
crowdsecAppsecUnreachableBlock: true
crowdsecLapiKey: j9beWrQh3moZwdLhr2u1vKzpxsyiDALtDKtZSTMeoWE
crowdsecLapiHost: crowdsec:8080
crowdsecLapiScheme: http
crowdsecLapiTLSInsecureVerify: false
forwardedHeadersTrustedIPs:
- ********/8
- ********/12
- ********/16
clientTrustedIPs:
- ********/8
- ********/12
- ********/16
and traefik-internal.yaml

http:
  routers:
    gateway:                                 # Ubiquiti Dream Machine
      rule: "Host(`example.com`)"
      service: gateway
      entryPoints:
        - secureweb
      tls:
        certResolver: letsencrypt
      middlewares:
        - authentik-forwardauth@file
        - security-headers@file
        - traefik-bouncer@file

  services:      

    gateway:
      loadBalancer:
        servers:
          - url: "**********"        # Ubiquiti Web UI - HTTPS
        passHostHeader: true
        serversTransport: insecure-no-verify

  serversTransports:
    insecure-no-verify:
      insecureSkipVerify: true

I can run the containers, and pull up the Traefik web UI, which shows everything as working. When I jump onto the Traefik container and run traefik –ping healthcheckit is constantly saying that a port is in use and that it can’t create the entrypoint.

When I have the Traefik container up and running and do sudo lsof -i -P -n | grep :5443 or for 8083, I get multiple docker lines listening to the port.

Screenshot from 2025-11-29 11-18-07

Everytime I try and tweak something, it lists a different port as the issue, but I think the problem is that Traefik is duplicating many of the ports due to some issue in my configuration from one of the files above.

Is there something obvious I need to fix here? I tried so many different things at this point I hope I didn’t create new headaches for myself once this part is sorted out.

You state you are a noob, but have one of the most complex setup I have seen in months :wink:

You try a lot of templating, not sure if that works:

Run docker compose config to see results of templating.

Well I made the mistake of starting with a project called mediastack that has compose files for 30+ containers in it, including Traefik. I was able to iron out all of the issues with the other containers including gluetun, but waited to try and sort out Traefik. Now I have a better understanding at least of the basics of the docker compose setup, but I am needing to go back to basics on Traefik so I am only spinning up the few containers I think are most relevant to testing this all out.

Here is the Traefik specific component of docker compose config:

traefik:
    container_name: traefik
    environment:
      CF_DNS_API_TOKEN: ********
      TZ: AMERICA/LOS_ANGELES
    image: traefik:latest
    labels:
      traefik.enable: "true"
      traefik.http.routers.traefik.entrypoints: secureweb
      traefik.http.routers.traefik.middlewares: authentik-forwardauth@file,security-headers@file,traefik-bouncer@file
      traefik.http.routers.traefik.rule: Host(`traefik.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))
      traefik.http.routers.traefik.service: api@internal
      traefik.http.services.traefik.loadbalancer.server.port: "8080"
      traefik.http.services.traefik.loadbalancer.server.scheme: http
    networks:
      mediastack: null
    ports:
      - mode: ingress
        target: 80
        published: "81"
        protocol: tcp
      - mode: ingress
        target: 443
        published: "5443"
        protocol: tcp
      - mode: ingress
        target: 8080
        published: "8080"
        protocol: tcp
      - mode: ingress
        target: 8082
        published: "8083"
        protocol: tcp
    restart: unless-stopped
    user: root
    volumes:
      - type: bind
        source: /var/run/docker.sock
        target: /var/run/docker.sock
        read_only: true
        bind:
          create_host_path: true
      - type: bind
        source: /mediastack/appdata/logs/traefik
        target: /var/log
        bind:
          create_host_path: true
      - type: bind
        source: /mediastack/appdata/traefik
        target: /etc/traefik
        bind:
          create_host_path: true
      - type: bind
        source: /mediastack/appdata/traefik/letsencrypt
        target: /letsencrypt
        bind:
          create_host_path: true

What’s the output of netstat -tulpn?

This morning I wanted to isolate the issue as much as possible, so I have all other docker containers closed. I am now just running the most basic traefik setup I could find from Traefik Getting Started Quickly - Traefik where the docker-compose file consists of only:

# docker-compose.yml
services:
  traefik:
    image: traefik:v3.6
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--entrypoints.web.address=:80"
    ports:
      - "80:80"
      - "8080:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

netstat -tulpn prior to starting the container is:

Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
udp        0      0 0.0.0.0:5353            0.0.0.0:*                           582/avahi-daemon: r 
udp        0      0 0.0.0.0:58171           0.0.0.0:*                           582/avahi-daemon: r 
udp6       0      0 :::59762                :::*                                582/avahi-daemon: r 
udp6       0      0 :::5353                 :::*                                582/avahi-daemon: r 

after starting the container is:

Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      11814/docker-proxy  
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      11836/docker-proxy  
tcp6       0      0 :::80                   :::*                    LISTEN      11822/docker-proxy  
tcp6       0      0 :::8080                 :::*                    LISTEN      11842/docker-proxy  
udp        0      0 0.0.0.0:5353            0.0.0.0:*                           582/avahi-daemon: r 
udp        0      0 0.0.0.0:58171           0.0.0.0:*                           582/avahi-daemon: r 
udp6       0      0 :::59762                :::*                                582/avahi-daemon: r 
udp6       0      0 :::5353                 :::*                                582/avahi-daemon: r 

This docker compose file is in a different directory, so I assume that all of the files in my initial post are no longer relevant (and the output of netstat appears to line up with that). So it is still trying to listen twice, once on ipv4 and another on ipv6.

The output of sudo lsof -i -P -n | grep LISTEN is simiilar:

docker-pr 11814     root    7u  IPv4  55470      0t0  TCP *:80 (LISTEN)
docker-pr 11822     root    7u  IPv6  55471      0t0  TCP *:80 (LISTEN)
docker-pr 11836     root    7u  IPv4  54692      0t0  TCP *:8080 (LISTEN)
docker-pr 11842     root    7u  IPv6  54693      0t0  TCP *:8080 (LISTEN)

Within the container I still am getting the same result from the healthcheck:

traefik --ping healthcheck
2025-11-30T19:02:14Z ERR Command error error="command traefik error: error while building entryPoint http: building listener: error opening listener: listen tcp :80: bind: address already in use"

ok… let’s sort it out: netstat is correct, for each port you have one IPv4 addressing and one IPv6 addressing on the same port. They are completely different networking stacks so it’s normal.

about the error it’s because your command is trying to start another instance of traefik inside the container, hence the port is already taken