Docker Compose Guide: Multi-Container Application Management
Define and manage multi-container applications with Docker Compose: service dependencies, environment variables, health checks, scaling, and production deployment. Comprehensive guide.
Traefik installation, automatic service discovery with Docker provider, Let's Encrypt SSL, middleware configuration, dashboard, Kubernetes Ingress Controller, and load balancing.
Traefik is a modern edge router and reverse proxy designed for microservice architectures. Thanks to its deep integration with Docker and Kubernetes, it automatically discovers and routes services.
Key features of Traefik:
Traefik v3 offers better performance and new features compared to v2. This guide focuses on Traefik v3.
# docker-compose.yml
services:
traefik:
image: traefik:v3.0
container_name: traefik
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "8080:8080" # Dashboard (close in production)
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik.yml:/etc/traefik/traefik.yml:ro
- ./config:/etc/traefik/config:ro
- traefik_certs:/certs
networks:
- traefik-net
labels:
- "traefik.enable=true"
# Dashboard
- "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`)"
- "traefik.http.routers.dashboard.service=api@internal"
- "traefik.http.routers.dashboard.middlewares=auth"
- "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$xyz$$hash"
- "traefik.http.routers.dashboard.tls.certresolver=letsencrypt"
volumes:
traefik_certs:
networks:
traefik-net:
external: true
# traefik.yml
global:
checkNewVersion: true
sendAnonymousUsage: false
api:
dashboard: true
insecure: false # false in production
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
permanent: true
websecure:
address: ":443"
http:
tls:
certResolver: letsencrypt
http3:
advertisedPort: 443
certificatesResolvers:
letsencrypt:
acme:
email: admin@example.com
storage: /certs/acme.json
httpChallenge:
entryPoint: web
# DNS challenge (for wildcard)
# dnsChallenge:
# provider: cloudflare
# resolvers:
# - "1.1.1.1:53"
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
network: traefik-net
file:
directory: /etc/traefik/config
watch: true
log:
level: INFO
filePath: /var/log/traefik/traefik.log
accessLog:
filePath: /var/log/traefik/access.log
bufferingSize: 100
Register services automatically with Traefik using Docker labels:
# Example application
services:
webapp:
image: nginx:alpine
networks:
- traefik-net
labels:
# Enable Traefik
- "traefik.enable=true"
# HTTP router
- "traefik.http.routers.webapp.rule=Host(`app.example.com`)"
- "traefik.http.routers.webapp.entrypoints=websecure"
- "traefik.http.routers.webapp.tls.certresolver=letsencrypt"
# Service port
- "traefik.http.services.webapp.loadbalancer.server.port=80"
# Apply middleware
- "traefik.http.routers.webapp.middlewares=security-headers,rate-limit"
networks:
traefik-net:
external: true
services:
api:
image: myapi:latest
networks:
- traefik-net
labels:
- "traefik.enable=true"
- "traefik.http.routers.api.rule=Host(`api.example.com`)"
- "traefik.http.routers.api.entrypoints=websecure"
- "traefik.http.routers.api.tls.certresolver=letsencrypt"
- "traefik.http.services.api.loadbalancer.server.port=3000"
# Health check
- "traefik.http.services.api.loadbalancer.healthcheck.path=/health"
- "traefik.http.services.api.loadbalancer.healthcheck.interval=30s"
frontend:
image: myfrontend:latest
networks:
- traefik-net
labels:
- "traefik.enable=true"
- "traefik.http.routers.frontend.rule=Host(`example.com`) || Host(`www.example.com`)"
- "traefik.http.routers.frontend.entrypoints=websecure"
- "traefik.http.routers.frontend.tls.certresolver=letsencrypt"
- "traefik.http.services.frontend.loadbalancer.server.port=80"
networks:
traefik-net:
external: true
# config/middlewares.yml
http:
middlewares:
# Security headers
security-headers:
headers:
stsSeconds: 31536000
stsIncludeSubdomains: true
stsPreload: true
forceSTSHeader: true
contentTypeNosniff: true
frameDeny: true
referrerPolicy: "strict-origin-when-cross-origin"
customResponseHeaders:
X-Powered-By: ""
Server: ""
# Rate limiting
rate-limit:
rateLimit:
average: 100
burst: 50
period: 1m
sourceCriterion:
ipStrategy:
depth: 1
# Basic auth
basic-auth:
basicAuth:
users:
- "admin:$apr1$xyz$hashedpassword"
removeHeader: true
# IP allowlist
ip-whitelist:
ipAllowList:
sourceRange:
- "192.168.1.0/24"
- "10.0.0.0/8"
# Redirect www to non-www
www-redirect:
redirectRegex:
regex: "^https://www\\.(.*)"
replacement: "https://${1}"
permanent: true
# Compress
compress:
compress:
excludedContentTypes:
- text/event-stream
labels:
# Define and apply middleware
- "traefik.http.middlewares.myapp-auth.basicauth.users=user:$$apr1$$hash"
- "traefik.http.middlewares.myapp-ratelimit.ratelimit.average=50"
- "traefik.http.middlewares.myapp-ratelimit.ratelimit.burst=20"
- "traefik.http.routers.myapp.middlewares=myapp-auth,myapp-ratelimit"
# Redirect middleware
- "traefik.http.middlewares.redirect-https.redirectscheme.scheme=https"
- "traefik.http.middlewares.redirect-https.redirectscheme.permanent=true"
# Secure dashboard configuration
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik-dashboard.rule=Host(`traefik.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))"
- "traefik.http.routers.traefik-dashboard.service=api@internal"
- "traefik.http.routers.traefik-dashboard.entrypoints=websecure"
- "traefik.http.routers.traefik-dashboard.tls.certresolver=letsencrypt"
- "traefik.http.routers.traefik-dashboard.middlewares=dashboard-auth"
- "traefik.http.middlewares.dashboard-auth.basicauth.users=admin:$$apr1$$xyz$$hash"
Generating basic auth password:
# Generate password with htpasswd
echo $(htpasswd -nB admin) | sed -e s/\\$/\\$\\$/g
# Or with openssl
echo "admin:$(openssl passwd -apr1 'yourpassword')" | sed -e 's/\$/\$\$/g'
# Add Traefik Helm repository
helm repo add traefik https://traefik.github.io/charts
helm repo update
# Install Traefik
helm install traefik traefik/traefik \
--namespace traefik \
--create-namespace \
--set deployment.replicas=2 \
--set ports.web.redirectTo.port=websecure \
--set ingressRoute.dashboard.enabled=true
# ingressroute.yml
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: webapp-ingress
namespace: default
spec:
entryPoints:
- websecure
routes:
- match: Host(`app.example.com`)
kind: Rule
services:
- name: webapp-service
port: 80
middlewares:
- name: security-headers
tls:
certResolver: letsencrypt
# middleware.yml
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: security-headers
namespace: default
spec:
headers:
stsSeconds: 31536000
stsIncludeSubdomains: true
contentTypeNosniff: true
frameDeny: true
# traefik.yml - TCP entrypoint
entryPoints:
mysql:
address: ":3306"
redis:
address: ":6379"
# config/tcp.yml
tcp:
routers:
mysql-router:
entryPoints:
- mysql
rule: "HostSNI(`*`)"
service: mysql-service
services:
mysql-service:
loadBalancer:
servers:
- address: "mysql:3306"
# Load balancing with multiple instances
services:
api:
image: myapi:latest
deploy:
replicas: 3
networks:
- traefik-net
labels:
- "traefik.enable=true"
- "traefik.http.routers.api.rule=Host(`api.example.com`)"
- "traefik.http.services.api.loadbalancer.server.port=3000"
# Sticky sessions
- "traefik.http.services.api.loadbalancer.sticky.cookie=true"
- "traefik.http.services.api.loadbalancer.sticky.cookie.name=traefik_session"
- "traefik.http.services.api.loadbalancer.sticky.cookie.secure=true"
# Health check
- "traefik.http.services.api.loadbalancer.healthcheck.path=/health"
- "traefik.http.services.api.loadbalancer.healthcheck.interval=10s"
- "traefik.http.services.api.loadbalancer.healthcheck.timeout=3s"
Traefik is a powerful reverse proxy and load balancer solution for modern microservice infrastructures. With its deep integration with Docker and Kubernetes, automatic SSL management, and rich middleware ecosystem, it's a reliable choice for production environments. Its label-based configuration allows each service to define its own routing rules.
Traefik has deep integration with Docker/Kubernetes and automatically discovers services. Nginx requires static configuration and needs a reload for every change. Traefik supports dynamic configuration and updates with zero downtime. Nginx is more mature and may perform better under very high traffic. Traefik is preferred for microservice environments, Nginx for traditional web servers.
Never expose the dashboard in insecure mode (port 8080) in production. Protect the dashboard with HTTPS and basic auth by adding labels to the Traefik container. Restrict access to specific IPs with the IP whitelist middleware. Alternatively, completely disable the dashboard and use Prometheus/Grafana for monitoring.
Set the dnsChallenge provider under certificatesResolvers in traefik.yml. For Cloudflare, 'provider: cloudflare' and the 'CF_DNS_API_TOKEN' environment variable are required. Define the relevant API keys as environment variables for other DNS providers. DNS challenge is more secure than HTTP challenge and enables wildcard certificate issuance.
Yes, middlewares are applied in the order they are defined. The generally recommended order is: IP whitelist → Rate limit → Auth → Headers. Wrong ordering can lead to unexpected behavior. For example, if you put the auth middleware before rate limiting, unauthenticated requests will also count toward the rate limit.
Use rolling updates in Docker Swarm or Kubernetes. Traefik automatically routes traffic when new containers are ready. Health check configuration is critical: traffic is not sent to unhealthy containers. Define the health check endpoint with the 'traefik.http.services.myapp.loadbalancer.healthcheck.path=/health' label.
Traefik obtains separate certificates for each domain. For multiple domains, use 'Host(`a.com`) || Host(`b.com`)' in the router rule. Separate certificates are automatically obtained for each domain. DNS challenge is required for wildcard certificates. Manual configuration or external certificate usage may be needed for SAN certificates.
Define and manage multi-container applications with Docker Compose: service dependencies, environment variables, health checks, scaling, and production deployment. Comprehensive guide.
Build CI/CD pipelines with GitHub Actions: Docker build and push, SSH server deployment, test automation, secrets management, and workflow optimization.
Ansible installation, inventory file, playbook writing, role structure, variables, encrypted vault, ad-hoc commands, and server configuration automation. Step-by-step guide.