C4 Component — Traefik¶
Traefik v3 actúa como el único punto de entrada al sistema: termina TLS, aplica políticas de seguridad perimetrales y enruta el tráfico hacia Keycloak o los microservicios Spring WebFlux. Este documento descompone los componentes internos de Traefik y sus configuraciones relevantes para el MVP en VPS con Docker Compose.
Diagrama de componentes internos¶
flowchart TB
Internet((Internet\n:80 / :443)) --> EP
subgraph Traefik["Traefik v3 — Edge Proxy"]
EP["EntryPoints\n────────────────\n• web → :80\n• websecure → :443"]
CM["Certificate Manager\n────────────────\n• ACME / Let's Encrypt\n• TLS Challenge\n• Almacén local (acme.json)\n• Auto-renovación"]
Router_KC["Router: keycloak\n────────────────\n• Host: auth.ejemplo.com\n• EntryPoint: websecure\n• TLS: certResolver=letsencrypt\n• Middleware: secure-headers"]
Router_API["Router: api-service\n────────────────\n• Host: api.ejemplo.com\n• PathPrefix: /api\n• EntryPoint: websecure\n• TLS: certResolver=letsencrypt\n• Middleware: secure-headers, rate-limit"]
Router_HTTP["Router: http-redirect\n────────────────\n• EntryPoint: web\n• Middleware: https-redirect"]
MW_Headers["Middleware: secure-headers\n────────────────\n• Strict-Transport-Security\n• X-Frame-Options: DENY\n• X-Content-Type-Options\n• Referrer-Policy\n• Content-Security-Policy"]
MW_Rate["Middleware: rate-limit\n────────────────\n• average: 100 req/s\n• burst: 50\n• sourceCriterion: ipStrategy"]
MW_Redirect["Middleware: https-redirect\n────────────────\n• redirectScheme: https\n• permanent: true"]
Svc_KC["Service: keycloak\n────────────────\n• URL: http://keycloak:8080\n• healthCheck: /health/ready\n• passHostHeader: true"]
Svc_API["Service: api-service\n────────────────\n• URL: http://webflux-api:8080\n• healthCheck: /actuator/health\n• passHostHeader: true"]
EP --> Router_KC
EP --> Router_API
EP --> Router_HTTP
Router_HTTP --> MW_Redirect
Router_KC --> MW_Headers --> Svc_KC
Router_API --> MW_Headers
MW_Headers --> MW_Rate --> Svc_API
CM --> Router_KC
CM --> Router_API
end
Svc_KC -->|HTTP| Keycloak[Keycloak\n:8080]
Svc_API -->|HTTP| WebFlux[Spring WebFlux\n:8080]
EntryPoints¶
Los EntryPoints son los puntos de escucha de Traefik. Todo el tráfico externo entra por aquí antes de ser procesado.
# traefik.yml (configuración estática)
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
permanent: true
websecure:
address: ":443"
http:
tls:
certResolver: letsencrypt
Routers¶
Los routers evalúan cada petición entrante y la dirigen al servicio correspondiente según reglas declarativas.
# docker-compose labels — Keycloak
labels:
- "traefik.enable=true"
- "traefik.http.routers.keycloak.rule=Host(`auth.ejemplo.com`)"
- "traefik.http.routers.keycloak.entrypoints=websecure"
- "traefik.http.routers.keycloak.tls.certresolver=letsencrypt"
- "traefik.http.routers.keycloak.middlewares=secure-headers@file"
- "traefik.http.services.keycloak.loadbalancer.server.port=8080"
# docker-compose labels — Spring WebFlux API
labels:
- "traefik.enable=true"
- "traefik.http.routers.api.rule=Host(`api.ejemplo.com`) && PathPrefix(`/api`)"
- "traefik.http.routers.api.entrypoints=websecure"
- "traefik.http.routers.api.tls.certresolver=letsencrypt"
- "traefik.http.routers.api.middlewares=secure-headers@file,rate-limit@file"
- "traefik.http.services.api.loadbalancer.server.port=8080"
Middlewares¶
Los middlewares transforman o filtran las peticiones y respuestas antes de llegar al servicio backend.
# middlewares.yml (configuración dinámica en archivo)
http:
middlewares:
secure-headers:
headers:
stsSeconds: 31536000
stsIncludeSubdomains: true
stsPreload: true
forceSTSHeader: true
frameDeny: true
contentTypeNosniff: true
referrerPolicy: "strict-origin-when-cross-origin"
customResponseHeaders:
X-Powered-By: ""
Server: ""
rate-limit:
rateLimit:
average: 100
burst: 50
sourceCriterion:
ipStrategy:
depth: 1
https-redirect:
redirectScheme:
scheme: https
permanent: true
Certificate Manager (ACME)¶
Traefik gestiona certificados TLS de Let's Encrypt automáticamente mediante el protocolo ACME.
# traefik.yml — certificatesResolvers
certificatesResolvers:
letsencrypt:
acme:
email: "admin@ejemplo.com"
storage: "/letsencrypt/acme.json"
tlsChallenge: {}
Permisos de acme.json
El archivo acme.json debe tener permisos 600. Traefik lo verifica al iniciar y falla si los permisos son incorrectos.
Rate limits de Let's Encrypt
El límite es 5 certificados por dominio por semana en producción. Para pruebas, usa el staging endpoint de ACME para evitar bloqueos.
Tabla de configuraciones clave¶
| Componente | Parámetro | Valor en MVP | Impacto |
|---|---|---|---|
| EntryPoint web | address |
:80 |
Recibe HTTP, redirige a HTTPS |
| EntryPoint websecure | address |
:443 |
Recibe todo el tráfico HTTPS |
| ACME storage | storage |
/letsencrypt/acme.json |
Persiste certificados entre reinicios |
| ACME challenge | tlsChallenge |
habilitado | No requiere puerto 80 para validación |
| HSTS | stsSeconds |
31536000 (1 año) |
Fuerza HTTPS en navegadores |
| Rate limit | average |
100 req/s |
Protege backend de ataques volumétricos |
| Rate limit | burst |
50 |
Permite picos cortos legítimos |
| Keycloak passHostHeader | true |
true |
Keycloak necesita el Host original para construir las URLs de respuesta |
Tabla de rutas configuradas¶
| Router | Host | Path | Servicio | Middlewares |
|---|---|---|---|---|
keycloak |
auth.ejemplo.com |
/ (todo) |
keycloak:8080 |
secure-headers |
api |
api.ejemplo.com |
/api/* |
webflux-api:8080 |
secure-headers, rate-limit |
http-redirect |
* |
/ (todo) |
— | https-redirect |
Configuración de red Docker¶
# compose.yml — red interna compartida
networks:
proxy:
external: false
services:
traefik:
image: traefik:v3.0
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik/traefik.yml:/etc/traefik/traefik.yml:ro
- ./traefik/middlewares.yml:/etc/traefik/dynamic/middlewares.yml:ro
- ./letsencrypt:/letsencrypt
networks:
- proxy
keycloak:
networks:
- proxy
# No expone puertos al host — sólo accesible vía Traefik
webflux-api:
networks:
- proxy
# No expone puertos al host — sólo accesible vía Traefik
Exposición directa de puertos
Los contenedores Keycloak y Spring WebFlux no deben exponer puertos al host (127.0.0.1 o 0.0.0.0). Todo el tráfico debe pasar por Traefik para que los middlewares de seguridad sean efectivos.
Health checks y observabilidad¶
Traefik expone un API de administración en el puerto 8080 (sólo en red interna) para monitorear el estado de routers y servicios:
# traefik.yml
api:
dashboard: true
insecure: false # Exponer sólo vía router con autenticación en producción
ping:
entryPoint: "traefik"
log:
level: INFO
format: json
accessLog:
filePath: "/var/log/traefik/access.log"
format: json
fields:
defaultMode: keep
headers:
defaultMode: drop
names:
Authorization: redact