Skip to content

Traefik Troubleshooting Reference

Comprehensive guide to diagnosing and resolving Traefik configuration and runtime issues.

Diagnostic Workflow

When something isn't working, follow this sequence:

1. Check if containers are running
   └─→ docker ps
2. Check Traefik logs
   └─→ docker logs traefik
3. Check container health
   └─→ docker ps (look for "healthy")
4. Check Traefik dashboard
   └─→ http://50.3.85.110:8080/dashboard/
5. Test network connectivity
   └─→ docker network inspect
6. Check container logs
   └─→ docker logs [container-name]
7. Test locally with curl
   └─→ docker exec [container] wget ...

Category 1: Container Not Accessible (404 Errors)

Issue: Getting 404 errors when accessing domain

Symptoms: - Visiting http://app.egygeeks.com returns 404 - Traefik dashboard shows route exists - Container appears to be running

Root Causes & Solutions

Root Cause 1: Container is not healthy

Traefik only routes to containers with status "healthy".

Check container health:

docker ps

Look at STATUS column:

STATUS
Up 2 minutes (healthy)     ✅ Good - routes should work
Up 2 minutes (unhealthy)   ❌ Bad - Traefik won't route here
Up 2 minutes               ⚠️  No health check - still routes but not ideal

If unhealthy:

# Check what's failing
docker logs my-app

# Test health check manually
docker exec my-app wget -O- http://127.0.0.1:8000/

# Or with curl
docker exec my-app curl -v http://127.0.0.1:8000/

Fix the health check:

# ✅ Correct - use 127.0.0.1 in Alpine
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s \
  CMD wget --quiet --tries=1 --spider http://127.0.0.1:8000/ || exit 1

# ✅ Also correct - using curl
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s \
  CMD curl -f http://127.0.0.1:8000/ || exit 1

# ❌ May fail - localhost DNS resolution
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s \
  CMD wget http://localhost:8000/ || exit 1

Common reasons for unhealthy status:

  • App not listening yet - Increase start-period
  • App listening on wrong port - App is on 5000, health check checks 8000
  • App only responds to specific path - Check /health instead of /
# Example: App only has /api endpoint
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s \
  CMD wget -O- http://127.0.0.1:8000/api/health || exit 1

Root Cause 2: traefik.enable not set

Traefik ignores containers without traefik.enable=true.

Check container labels:

docker inspect my-app | grep traefik

Fix: Add to docker-compose.yml:

services:
  my-app:
    labels:
      - traefik.enable=true
      - traefik.http.routers.my-app.rule=Host(`app.egygeeks.com`)
      - traefik.http.services.my-app.loadbalancer.server.port=8000

Root Cause 3: Wrong port configuration

The service port doesn't match where your app is actually listening.

What your app reports:

docker logs my-app
# Output: "Server listening on port 3000"

But you configured:

- traefik.http.services.my-app.loadbalancer.server.port=8000

Fix: Match the actual port:

# If app says "listening on port 3000"
- traefik.http.services.my-app.loadbalancer.server.port=3000

Common port mistakes:

# ❌ Port 8000 is on HOST machine (not used)
ports:
  - "8000:3000"
- traefik.http.services.my-app.loadbalancer.server.port=8000  # Wrong!

# ✅ Traefik uses container port (3000)
- traefik.http.services.my-app.loadbalancer.server.port=3000  # Correct!

To find the correct port:

# Check logs
docker logs my-app | grep -i "listening\|port\|started"

# Or try common ports
docker exec my-app curl http://127.0.0.1:3000/     # Node.js default
docker exec my-app curl http://127.0.0.1:5000/     # Flask default
docker exec my-app curl http://127.0.0.1:8000/     # Python/FastAPI default
docker exec my-app curl http://127.0.0.1:8080/     # Go default

Root Cause 4: Container not on traefik_public network

Container must be on the same network as Traefik.

Check networks:

docker network inspect traefik_public

Look for your container in the "Containers" section.

If not listed:

services:
  my-app:
    networks:
      - traefik_public

networks:
  traefik_public:
    external: true

Or add it manually:

docker network connect traefik_public my-app

Root Cause 5: Router rule doesn't match request

You're accessing a different domain/path than the router expects.

Check your rule:

- traefik.http.routers.my-app.rule=Host(`app.egygeeks.com`)

But you're visiting: http://50.3.85.110 or http://myapp.egygeeks.com

Fix: Update the rule or visit correct URL

# ✅ Match different hosts
- traefik.http.routers.my-app.rule=Host(`app.egygeeks.com`) || Host(`50.3.85.110`)

# ✅ Or route on IP with path
- traefik.http.routers.my-app.rule=Host(`50.3.85.110`) && PathPrefix(`/app`)

Verify router config:

# Check what Traefik sees
curl http://50.3.85.110:8080/api/http/routers -s | jq .

Diagnostic Commands

# See all containers and their health
docker ps -a --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"

# View container logs
docker logs --tail=50 -f my-app

# Test app directly inside container
docker exec my-app curl http://127.0.0.1:8000/

# Check Traefik sees the container
curl http://50.3.85.110:8080/api/http/services -s | jq '.'

# Check specific router config
curl http://50.3.85.110:8080/api/http/routers/my-app -s | jq '.'

# Test DNS (if using domain names)
docker exec my-app nslookup app.egygeeks.com

Category 2: SSL/HTTPS Certificate Issues

Issue: HTTPS not working or invalid certificate

Symptoms: - http://app.egygeeks.com works, but https://app.egygeeks.com doesn't - Browser shows "Not Secure" or certificate error - Certificates not being issued

Root Causes & Solutions

Root Cause 1: Wrong entrypoint configuration

HTTPS requires websecure entrypoint, not web.

Check current config:

- traefik.http.routers.my-app.entrypoints=web  # ❌ Wrong for HTTPS

Fix:

- traefik.http.routers.my-app.entrypoints=websecure    # ✅ HTTPS
- traefik.http.routers.my-app.tls.certresolver=letsencrypt

Root Cause 2: Certificate resolver not configured

Even with websecure entrypoint, you need to specify which resolver to use.

Check config:

- traefik.http.routers.my-app.entrypoints=websecure
# Missing: tls.certresolver

Fix:

- traefik.http.routers.my-app.entrypoints=websecure
- traefik.http.routers.my-app.tls.certresolver=letsencrypt

Root Cause 3: Not enough time for certificate provisioning

Let's Encrypt certificates take 30-60 seconds to obtain after first request.

Check current certificate status:

# View certificate file (if using Let's Encrypt)
cat /opt/traefik/acme.json

# Or check Traefik logs
docker logs traefik | grep -i "certificate\|acme\|let"

Solution: Wait 60 seconds and try again.

Root Cause 4: Port 443 not exposed

Traefik can't listen on HTTPS port.

Check Traefik port configuration:

docker ps | grep traefik
# Should show: 0.0.0.0:443->443/tcp

If not:

traefik:
  ports:
    - "80:80"       # HTTP
    - "443:443"     # HTTPS (add this)
    - "8080:8080"   # Dashboard

Then restart Traefik:

docker-compose restart traefik

Root Cause 5: Domain mismatch

Certificate issued for app.egygeeks.com, but accessing 50.3.85.110 or vice versa.

Check what domain Traefik will request certificate for:

- traefik.http.routers.my-app.rule=Host(`app.egygeeks.com`)

This tells Let's Encrypt to issue a certificate for app.egygeeks.com.

Fix: Make sure you access via the same domain:

# ✅ Works - certificate issued for app.egygeeks.com
https://app.egygeeks.com

# ❌ Certificate error - certificate for app.egygeeks.com, not IP
https://50.3.85.110

Root Cause 6: acme.json permissions

Let's Encrypt certificate storage file has incorrect permissions.

Check permissions:

ls -la /opt/traefik/acme.json
# Should be readable by Traefik container

Fix permissions:

chmod 600 /opt/traefik/acme.json
chown 65534:65534 /opt/traefik/acme.json  # Traefik user

Diagnostic Commands

# Check HTTPS is responding
curl -I https://app.egygeeks.com

# Check certificate details
echo | openssl s_client -servername app.egygeeks.com -connect 50.3.85.110:443

# View certificate expiry
curl https://app.egygeeks.com:443 -vI 2>&1 | grep -i "expire\|valid"

# Check Traefik HTTPS configuration
curl http://50.3.85.110:8080/api/http/routers -s | jq '.[] | select(.Name=="my-app")'

# Check certificate in acme.json
cat /opt/traefik/acme.json | jq '.ACME.Certificates[] | {domain: .domain, certificate: .certificate}'

# View Traefik logs for certificate issues
docker logs traefik | grep -i -E "certificate|acme|tls|https"

Category 3: Path-Based Routing Issues

Issue: PathPrefix routing not working correctly

Symptoms: - Path-based routes not matching - Containers receiving wrong paths - 404 on path-based routes

Root Causes & Solutions

Root Cause 1: Missing StripPrefix middleware

Container expects / but receives /api/users.

Example:

# ❌ Missing middleware
- traefik.http.routers.api.rule=PathPrefix(`/api`)
- traefik.http.services.api.loadbalancer.server.port=3000

# Container receives: /api/users (wrong!)

Fix:

# ✅ Add StripPrefix middleware
- traefik.http.middlewares.api-strip.stripprefix.prefixes=/api
- traefik.http.routers.api.rule=PathPrefix(`/api`)
- traefik.http.routers.api.middlewares=api-strip
- traefik.http.services.api.loadbalancer.server.port=3000

# Container receives: /users (correct!)

Verify middleware is working:

# Check middleware configuration
curl http://50.3.85.110:8080/api/http/middlewares -s | jq '.'

# Check router has middleware applied
curl http://50.3.85.110:8080/api/http/routers/api -s | jq '.Middlewares'

Root Cause 2: Path doesn't match rule

Accessing /app/api but rule is PathPrefix(/api).

Check your rule:

- traefik.http.routers.api.rule=PathPrefix(`/api`)

But you're accessing: /app/api, /v1/api, or /api/v2

Verify what's being matched:

# Check all active routes
curl http://50.3.85.110:8080/api/http/routers -s | jq '.[] | {name: .Name, rule: .Rule}'

Fix: Update rule to match:

# Match /api and anything under it
- traefik.http.routers.api.rule=PathPrefix(`/api`)

# Match /app/api and anything under it
- traefik.http.routers.api.rule=PathPrefix(`/app/api`)

# Match multiple paths
- traefik.http.routers.api.rule=PathPrefix(`/api`) || PathPrefix(`/v1/api`)

Root Cause 3: Routing order matters (specific before general)

Define more specific routes before general ones.

Problematic configuration:

# ❌ General path first
- traefik.http.routers.api.rule=PathPrefix(`/api`)
- traefik.http.services.api.loadbalancer.server.port=3000

# Then specific path (may not match!)
- traefik.http.routers.api-v2.rule=PathPrefix(`/api/v2`)
- traefik.http.services.api-v2.loadbalancer.server.port=3001

First route matches both /api and /api/v2!

Fix: Specific paths first

# ✅ Specific path first
- traefik.http.routers.api-v2.rule=PathPrefix(`/api/v2`)
- traefik.http.services.api-v2.loadbalancer.server.port=3001

# Then general path
- traefik.http.routers.api.rule=PathPrefix(`/api`)
- traefik.http.services.api.loadbalancer.server.port=3000

Now /api/v2 matches the first route, /api/users matches the second.

Root Cause 4: Container app expects different path structure

App is built for /app path, but Traefik strips it.

Example:

App has routing:

app.get('/home')   // Expects: /app/home
app.get('/about')  // Expects: /app/about

Traefik config:

- traefik.http.middlewares.app-strip.stripprefix.prefixes=/app
- traefik.http.routers.app.rule=PathPrefix(`/app`)

Result: Request /app/home becomes /home, but app expects /app/home.

Fix: Don't strip prefix if app needs it

# ❌ Don't strip if app needs the path
# - traefik.http.routers.app.middlewares=app-strip

# ✅ Keep the full path
- traefik.http.routers.app.rule=PathPrefix(`/app`)

Or rebuild app without the path prefix.

Diagnostic Commands

# See all routers and their rules
curl http://50.3.85.110:8080/api/http/routers -s | jq '.[] | {Name, Rule, Middlewares}'

# Test path matching
docker exec [container] curl -H "X-Forwarded-Uri: /api/users" http://127.0.0.1:8000/

# Check if middleware is stripping correctly
# Request /api/users and check what app receives
# (App must log incoming request paths)

Category 4: Service Discovery Issues

Issue: Traefik doesn't see containers or routes

Symptoms: - New containers don't appear in Traefik dashboard - Routes not updating when containers start/stop - "service not available" errors

Root Causes & Solutions

Root Cause 1: Container not on traefik_public network

Container must be connected to the network Traefik monitors.

Check:

docker network inspect traefik_public | grep my-app

Not listed? Container is not on the network.

Fix:

services:
  my-app:
    networks:
      - traefik_public

networks:
  traefik_public:
    external: true

Then restart:

docker-compose up -d

Or manually connect:

docker network connect traefik_public my-app

Root Cause 2: Traefik not watching Docker socket

Traefik needs access to Docker socket to discover containers.

Check Traefik container:

docker inspect traefik | grep "docker.sock"

Should show volume mount.

Fix:

traefik:
  volumes:
    - /var/run/docker.sock:/var/run/docker.sock:ro

Restart Traefik:

docker-compose restart traefik

Root Cause 3: Label syntax error

Typo in label name prevents Traefik from reading configuration.

Examples of typos:

# ❌ Missing underscore
- traefik.http.routers.my.app.rule=...

# ❌ Wrong component name
- traefik.http.router.my-app.rule=...  # Should be "routers"

# ❌ Mixed case
- Traefik.http.routers.my-app.rule=...  # Should be lowercase "traefik"

# ✅ Correct
- traefik.http.routers.my-app.rule=...

Validate labels:

docker inspect my-app | grep traefik

# Each should start with "traefik.http"
# Should not have typos or wrong case

Root Cause 4: Service name doesn't match router name

Service referenced by router must exist.

Example problem:

labels:
  - traefik.http.routers.api.rule=Host(`api.egygeeks.com`)
  # ❌ Missing service definition
  # Container will route to non-existent service "api"

Fix: Add matching service

labels:
  - traefik.http.routers.api.rule=Host(`api.egygeeks.com`)
  - traefik.http.services.api.loadbalancer.server.port=3000

Or use different service name:

labels:
  - traefik.http.routers.api.rule=Host(`api.egygeeks.com`)
  # Explicitly reference existing service
  # (Only needed if names don't match)

Root Cause 5: Docker daemon not accessible

Traefik container can't communicate with Docker daemon.

Check:

docker exec traefik docker ps
# If this fails, Docker socket is not accessible

Verify volume mount:

docker inspect traefik | grep "docker.sock"

If socket not mounted:

traefik:
  volumes:
    - /var/run/docker.sock:/var/run/docker.sock:ro

Restart:

docker-compose restart traefik

Diagnostic Commands

# Check service discovery logs
docker logs -f traefik | grep -i "container\|service\|discover"

# List all discovered services
curl http://50.3.85.110:8080/api/http/services -s | jq '.[].Name'

# List all routers
curl http://50.3.85.110:8080/api/http/routers -s | jq '.[].Name'

# Check specific container labels
docker inspect my-app | grep -A 20 "Labels"

# Verify Docker socket is accessible in Traefik
docker exec traefik ls -la /var/run/docker.sock

Category 5: Performance & Load Balancing

Issue: Slow responses or uneven load distribution

Root Causes & Solutions

Root Cause 1: Health checks too strict

Container marked unhealthy, even though it's working.

Check health check configuration:

HEALTHCHECK --interval=30s --timeout=3s --start-period=5s \
  CMD wget --quiet --tries=1 --spider http://127.0.0.1:8000/

Parameters: - interval - How often to check (30s good) - timeout - How long before failing (3s too short if slow app) - start-period - Grace period before first check (5s may be too short)

Fix for slow apps:

# Increase timeout for slow responses
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s \
  CMD wget --quiet --tries=1 --spider http://127.0.0.1:8000/

# Or check simpler endpoint
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s \
  CMD wget -O- http://127.0.0.1:8000/health || exit 1

Root Cause 2: Load balancer not configured

Multiple instances of same container, but Traefik sending all traffic to one.

Check service configuration:

# Missing explicit load balance strategy
- traefik.http.services.app.loadbalancer.server.port=3000

Add load balancing:

# Round-robin (default, usually fine)
- traefik.http.services.app.loadbalancer.server.port=3000

# For multiple instances, Traefik auto-discovers and balances
services:
  app-1:
    labels:
      - traefik.http.routers.app.rule=Host(`app.egygeeks.com`)
      - traefik.http.services.app.loadbalancer.server.port=3000

  app-2:
    labels:
      - traefik.http.routers.app.rule=Host(`app.egygeeks.com`)
      - traefik.http.services.app.loadbalancer.server.port=3000

Root Cause 3: No compression middleware

Responses not compressed, large payloads slow.

Add compression:

labels:
  - traefik.http.middlewares.compress.compress=true
  - traefik.http.routers.app.middlewares=compress

Result: 60-80% smaller responses.

Root Cause 4: Unneeded middlewares slowing requests

Each middleware adds latency. Remove unnecessary ones.

Review middleware stack:

labels:
  # Avoid chaining too many middlewares
  - traefik.http.routers.app.middlewares=strip,auth,compress,ratelimit
  # Each adds ~5-10ms latency

Optimize:

# Only use needed middlewares
- traefik.http.routers.app.middlewares=strip,compress
# Removed auth and ratelimit if not needed

Diagnostic Commands

# Check load distribution
curl http://50.3.85.110:8080/api/http/services/app -s | jq '.'

# Monitor response times
watch -n 1 'docker stats'

# Check if all instances healthy
docker ps --format "table {{.Names}}\t{{.Status}}"

# Monitor Traefik requests
docker logs -f traefik | grep -E "time_duration|Status"

Category 6: Docker Network Issues

Issue: Containers can't reach each other or Traefik

Symptoms: - Container can't reach other containers - "Name resolution failed" errors - Containers can't reach Traefik

Root Causes & Solutions

Root Cause 1: Containers on different networks

Services on internal network can't reach traefik_public network.

Check networks:

docker inspect my-app | grep NetworkSettings

Shows all networks the container is on.

Fix: Add to both networks

services:
  app:
    networks:
      - traefik_public    # To access Traefik
      - internal          # To access database

  database:
    networks:
      - internal          # NOT on traefik_public

networks:
  traefik_public:
    external: true
  internal:
    driver: bridge

Root Cause 2: Container-to-container communication using wrong names

Containers can't resolve names unless on same network.

Wrong:

services:
  app:
    environment:
      - DATABASE_URL=postgresql://mydb:5432/db
    networks:
      - traefik_public

  database:
    container_name: mydb
    networks:
      - internal

app can't reach mydb (on different networks, wrong name).

Fix:

services:
  app:
    environment:
      - DATABASE_URL=postgresql://database:5432/db
    depends_on:
      - database
    networks:
      - traefik_public
      - internal

  database:
    container_name: database
    networks:
      - internal

networks:
  traefik_public:
    external: true
  internal:
    driver: bridge

Now app reaches database (same network, correct name).

Root Cause 3: localhost vs container name

localhost won't work for inter-container communication.

Wrong:

environment:
  - DATABASE_URL=postgresql://localhost:5432/db
  # localhost = app container itself, not database

Correct:

environment:
  - DATABASE_URL=postgresql://database:5432/db
  # database = the database service name

Diagnostic Commands

# Check container networks
docker inspect my-app | jq '.NetworkSettings.Networks'

# Test container-to-container connectivity
docker exec app ping database

# Test name resolution
docker exec app nslookup database

# Test port connectivity
docker exec app nc -zv database 5432

# View network structure
docker network inspect traefik_public
docker network inspect internal

Category 7: Debugging Tools

Essential Commands

View Traefik configuration:

# See all routers
curl http://50.3.85.110:8080/api/http/routers -s | jq

# See all services
curl http://50.3.85.110:8080/api/http/services -s | jq

# See all middlewares
curl http://50.3.85.110:8080/api/http/middlewares -s | jq

# Check specific router
curl http://50.3.85.110:8080/api/http/routers/my-app -s | jq

Monitor logs:

# Traefik logs
docker logs -f traefik

# Container logs
docker logs -f my-app

# Both with timestamps
docker logs -f --timestamps traefik

# Last N lines
docker logs --tail=100 traefik

Test connectivity:

# Test container can reach endpoint
docker exec my-app curl -v http://app.egygeeks.com

# Test health check
docker exec my-app wget -O- http://127.0.0.1:8000/

# Test with specific host
docker exec my-app curl -H "Host: app.egygeeks.com" http://traefik:80/

# Dump response headers
docker exec my-app curl -i http://127.0.0.1:8000/

Inspect containers:

# Full container info
docker inspect my-app

# Just labels
docker inspect my-app | grep -A 50 "Labels"

# Just networks
docker inspect my-app | grep -A 10 "NetworkSettings"

# Just health
docker inspect my-app | grep -A 5 "Health"

Category 8: Common Error Messages

404 Not Found

Meaning: Request matched no router or service.

Check: 1. Router rule matches your request 2. Container is healthy 3. Service port is correct

502 Bad Gateway

Meaning: Traefik reached the service but got error.

Check: 1. Is container healthy? 2. Is app listening on configured port? 3. Are there application-level errors?

docker logs my-app

503 Service Unavailable

Meaning: No healthy instances available.

Check:

docker ps
# All containers must be "healthy"

Connection Refused

Meaning: Can't connect to container.

Check: 1. Is container running? 2. Is port correct? 3. Is app actually listening?

docker exec my-app lsof -i  # What ports is app listening on

Network Unreachable

Meaning: Container not on same network as target.

Check:

docker network inspect traefik_public
# Both containers should be listed

Quick Reference Checklist

When something breaks:

  • docker ps - Are containers running and healthy?
  • docker logs traefik - Any Traefik errors?
  • docker logs my-app - Any app errors?
  • curl http://50.3.85.110:8080/api/http/routers - Routes exist?
  • Check labels syntax - Any typos?
  • Container on traefik_public network?
  • Service port matches app's actual port?
  • Router rule matches your request?
  • Health check passing?

  • Overview - Architecture and concepts: overview.md
  • Labels Reference - All label options: labels.md
  • Templates - Ready-to-use configurations: Templates

For how-to guides on deploying with Traefik, see the Journey guides.