Traefik — reverse proxy z automatycznym SSL dla Docker
Opublikowano: 9 kwietnia 2026 · Kategoria: VPS / Docker / DevOps
Traefik to nowoczesny reverse proxy zaprojektowany dla środowisk kontenerowych. Zamiast ręcznie edytować pliki konfiguracyjne przy każdym nowym serwisie, Traefik automatycznie wykrywa kontenery Docker przez labels i konfiguruje routing w czasie rzeczywistym. Zarządza też certyfikatami SSL przez Let's Encrypt — zero ręcznej konfiguracji certbot.
Traefik vs Nginx — kiedy wybrać Traefik?
| Cecha | Traefik v3 | Nginx |
|---|---|---|
| Auto-discovery Docker | Tak — przez labels | Nie — ręczna edycja conf |
| Certyfikaty SSL | Automatyczne (ACME) | Ręczne (certbot + cron) |
| Reload po zmianach | Zero downtime, automatyczny | nginx -s reload (ręczny) |
| Dashboard | Wbudowany (Web UI) | Brak (osobne narzędzia) |
| Krzywa uczenia | Wyższa na start | Niższa (znajomy format) |
| Wydajność | Bardzo dobra | Bardzo dobra (dojrzalszy) |
Krok 1 — Sieć Docker i plik acme.json
# Utwórz zewnętrzną sieć Docker dla Traefik docker network create traefik-net # Utwórz plik na certyfikaty Let's Encrypt (chmod 600 OBOWIĄZKOWE) touch acme.json chmod 600 acme.json # Struktura katalogów mkdir -p /opt/traefik cd /opt/traefik # acme.json — certyfikaty SSL (NIE commituj do git!) # docker-compose.yml — konfiguracja Traefik
Krok 2 — docker-compose.yml dla Traefik
# /opt/traefik/docker-compose.yml
services:
traefik:
image: traefik:v3.0
container_name: traefik
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
# Dostęp do socket Docker (auto-discovery kontenerów)
- /var/run/docker.sock:/var/run/docker.sock:ro
# Certyfikaty Let's Encrypt
- ./acme.json:/acme.json
command:
# Providers
- --providers.docker=true
- --providers.docker.exposedbydefault=false # Tylko kontenery z traefik.enable=true
- --providers.docker.network=traefik-net
# Entrypoints
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
# HTTP → HTTPS redirect globalny
- --entrypoints.web.http.redirections.entrypoint.to=websecure
- --entrypoints.web.http.redirections.entrypoint.scheme=https
# Let's Encrypt ACME
- --certificatesresolvers.myresolver.acme.email=admin@twojadomena.pl
- --certificatesresolvers.myresolver.acme.storage=/acme.json
- --certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web
# Dashboard (tylko dev — wyłącz w produkcji lub zabezpiecz!)
- --api.dashboard=true
- --api.insecure=false # Dashboard przez HTTPS z labels
# Logi
- --log.level=INFO
- --accesslog=true
labels:
- "traefik.enable=true"
# Dashboard router
- "traefik.http.routers.dashboard.rule=Host(`traefik.twojadomena.pl`)"
- "traefik.http.routers.dashboard.tls=true"
- "traefik.http.routers.dashboard.tls.certresolver=myresolver"
- "traefik.http.routers.dashboard.service=api@internal"
- "traefik.http.routers.dashboard.middlewares=auth"
# BasicAuth middleware dla dashboardu
# Generuj hash: htpasswd -nb admin haslo
- "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$xyz$$hash"
networks:
- traefik-net
networks:
traefik-net:
external: true Krok 3 — Labels na kontenerze aplikacji
Każda aplikacja deklaruje swoją konfigurację przez Docker labels. Traefik odczytuje je automatycznie:
# /opt/moja-app/docker-compose.yml
services:
webapp:
image: moja-aplikacja:latest
restart: unless-stopped
expose:
- "3000" # Port wewnętrzny (NIE mapuj przez ports: na host)
labels:
# Włącz Traefik dla tego kontenera
- "traefik.enable=true"
# Router — nazwa unikalny identyfikator (kebab-case)
- "traefik.http.routers.webapp.rule=Host(`moja-domena.pl`)"
- "traefik.http.routers.webapp.entrypoints=websecure"
- "traefik.http.routers.webapp.tls=true"
- "traefik.http.routers.webapp.tls.certresolver=myresolver"
# Service — port na który Traefik kieruje ruch
- "traefik.http.services.webapp.loadbalancer.server.port=3000"
# Opcjonalnie: middleware rate limiting
- "traefik.http.routers.webapp.middlewares=rate-limit"
- "traefik.http.middlewares.rate-limit.ratelimit.average=100"
- "traefik.http.middlewares.rate-limit.ratelimit.burst=50"
networks:
- traefik-net
networks:
traefik-net:
external: true Middleware — rate limiting i nagłówki bezpieczeństwa
Traefik obsługuje middleware jako łańcuch przekształceń żądania. Najpopularniejsze:
# Rate limiting — max 100 req/s, burst do 200 - "traefik.http.middlewares.ratelimit.ratelimit.average=100" - "traefik.http.middlewares.ratelimit.ratelimit.burst=200" # Nagłówki bezpieczeństwa - "traefik.http.middlewares.security-headers.headers.stsSeconds=31536000" - "traefik.http.middlewares.security-headers.headers.stsIncludeSubdomains=true" - "traefik.http.middlewares.security-headers.headers.contentTypeNosniff=true" - "traefik.http.middlewares.security-headers.headers.browserXssFilter=true" # IP whitelist — dostęp tylko z wybranych IP - "traefik.http.middlewares.ipwhitelist.ipallowlist.sourcerange=10.0.0.0/8,192.168.1.0/24" # Strip prefix — usuń /api z URL przed przekazaniem do backendu - "traefik.http.middlewares.strip-api.stripprefix.prefixes=/api" # Compress — gzip kompresja odpowiedzi - "traefik.http.middlewares.compress.compress=true"
Multi-domain — wiele aplikacji na jednym VPS
# Aplikacja 1: sklep.pl
- "traefik.http.routers.sklep.rule=Host(`sklep.pl`)"
- "traefik.http.routers.sklep.tls.certresolver=myresolver"
- "traefik.http.services.sklep.loadbalancer.server.port=3000"
# Aplikacja 2: blog.pl
- "traefik.http.routers.blog.rule=Host(`blog.pl`)"
- "traefik.http.routers.blog.tls.certresolver=myresolver"
- "traefik.http.services.blog.loadbalancer.server.port=8080"
# Path-based routing: ta sama domena, różne ścieżki
- "traefik.http.routers.api.rule=Host(`app.pl`) && PathPrefix(`/api`)"
- "traefik.http.routers.frontend.rule=Host(`app.pl`) && PathPrefix(`/`)"
# www → non-www redirect (middleware)
- "traefik.http.middlewares.www-redirect.redirectregex.regex=^https://www\\.(.*)"
- "traefik.http.middlewares.www-redirect.redirectregex.replacement=https://${1}"
- "traefik.http.middlewares.www-redirect.redirectregex.permanent=true" Uruchomienie i weryfikacja
# Uruchom Traefik cd /opt/traefik docker compose up -d # Sprawdź logi docker compose logs -f traefik # Sprawdź aktywne routery przez API curl http://localhost:8080/api/rawdata | python3 -m json.tool # Zweryfikuj certyfikat SSL curl -I https://moja-domena.pl # Sprawdź czy HTTP przekierowuje na HTTPS curl -I http://moja-domena.pl