TLS automatico
Traefik puede obtener y renovar certificados Let's Encrypt (ACME) sin certbot. Declaras un certificate resolver, marcas routers con tls.certResolver, y Traefik pide el cert en el primer hit (o al detectar el dominio) y lo guarda en un almacenamiento persistente.
Certificate resolver (static)
HTTP-01 (puerto 80 publico, DNS apuntando al edge):
# traefik.yml
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: ":443"
certificatesResolvers:
le:
acme:
email: ops@example.com
storage: /letsencrypt/acme.json
httpChallenge:
entryPoint: web
providers:
docker:
exposedByDefault: falseTLS-ALPN-01 (challenge en 443, util si 80 esta cerrado):
certificatesResolvers:
le:
acme:
email: ops@example.com
storage: /letsencrypt/acme.json
tlsChallenge: {}DNS-01 (wildcards *.example.com, o hosts sin HTTP publico):
certificatesResolvers:
le:
acme:
email: ops@example.com
storage: /letsencrypt/acme.json
dnsChallenge:
provider: cloudflare
resolvers:
- "1.1.1.1:53"
- "8.8.8.8:53"El provider DNS exige variables de entorno del proveedor (token API). Ejemplo Cloudflare:
export CF_DNS_API_TOKEN="..."Persistencia de acme.json
Sin volumen, pierdes certs en cada recreate y golpeas rate limits de Let's Encrypt.
services:
traefik:
image: traefik:v3.3
environment:
- CF_DNS_API_TOKEN # si usas dnsChallenge
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt
- ./traefik.yml:/etc/traefik/traefik.yml:roPermisos:
mkdir -p letsencrypt
touch letsencrypt/acme.json
chmod 600 letsencrypt/acme.jsonTraefik se niega a usar acme.json si los permisos son demasiado abiertos.
Activar TLS en un router (Docker labels)
services:
app:
image: traefik/whoami:v1.10
labels:
- traefik.enable=true
- traefik.http.routers.app.rule=Host(`app.example.com`)
- traefik.http.routers.app.entrypoints=websecure
- traefik.http.routers.app.tls=true
- traefik.http.routers.app.tls.certresolver=le
- traefik.http.services.app.loadbalancer.server.port=80Equivalente en file provider:
http:
routers:
app:
rule: "Host(`app.example.com`)"
entryPoints: ["websecure"]
service: app
tls:
certResolver: leWildcard con DNS-01
# labels
- traefik.http.routers.app.rule=Host(`app.example.com`) || Host(`api.example.com`)
- traefik.http.routers.app.tls.certresolver=le
- traefik.http.routers.app.tls.domains[0].main=example.com
- traefik.http.routers.app.tls.domains[0].sans=*.example.comEn YAML file:
tls:
certResolver: le
domains:
- main: example.com
sans:
- "*.example.com"Staging de Let's Encrypt
Durante pruebas usa el entorno staging para no agotar el rate limit de produccion:
certificatesResolvers:
le:
acme:
email: ops@example.com
storage: /letsencrypt/acme.json
caServer: https://acme-staging-v02.api.letsencrypt.org/directory
httpChallenge:
entryPoint: webLos navegadores no confiaran en staging (esperado). Cuando la validacion funcione, quita caServer, borra acme.json de staging y regenera en prod.
Certificados propios (sin ACME)
Monta PEM y declaralos en dynamic:
tls:
certificates:
- certFile: /certs/app.crt
keyFile: /certs/app.key
stores:
default:
defaultCertificate:
certFile: /certs/default.crt
keyFile: /certs/default.keyOpciones TLS (min version, ciphers) via tls.options:
tls:
options:
modern:
minVersion: VersionTLS12
sniStrict: true
http:
routers:
app:
rule: "Host(`app.example.com`)"
entryPoints: ["websecure"]
service: app
tls:
options: modern
certResolver: leRedirect y HSTS
Redirect en entrypoint web (capitulo 2) + middleware HSTS en routers HTTPS:
http:
middlewares:
hsts:
headers:
stsSeconds: 31536000
stsIncludeSubdomains: true
stsPreload: trueNo actives stsPreload hasta que todos los subdominios sirvan HTTPS correcto.
Checklist de puesta en marcha
1. DNS A/AAAA del dominio -> IP publica de Traefik
2. Puertos 80 y/o 443 abiertos segun challenge
3. acme.json con chmod 600 y volumen persistente
4. email valido en el resolver
5. Router en entrypoint websecure + certResolver
6. Probar primero con caServer stagingVerificacion:
curl -vI https://app.example.com/
openssl s_client -connect app.example.com:443 -servername app.example.com </dev/null 2>/dev/null | openssl x509 -noout -dates -subjectErrores habituales
- DNS aun no apunta al servidor: ACME falla; Traefik reintenta y llena logs.
- HTTP-01 con redirect global en
webmal configurado que rompe/.well-known/acme-challenge/(el redirect nativo de entryPoint suele exceptuar el challenge; un middleware redirect casero puede no). acme.jsonsin persistir o con permisos644.- Pedir demasiados certs de prueba en produccion (rate limit LE).
Host(app.localhost)con ACME publico: Let's Encrypt no emite para localhost.- Firewall cloud que solo abre 443: usa
tlsChallengeodnsChallenge.
Ejercicios
- Configura resolver staging + HTTP-01, publica un whoami con dominio real de lab y comprueba el cert (aviso de CA staging).
- Fuerza un fallo de DNS, lee el log ACME, corrige el registro y verifica renovacion/emision.
- Monta DNS-01 con un provider que tengas (Cloudflare, Route53, etc.) y emite un wildcard.
- Anade
tls.optionsconminVersion: VersionTLS12y comprueba conopenssl s_client -tls1_1que el handshake falla.
Siguiente paso
En el capitulo 5 instalas Traefik como Ingress controller y defines IngressRoute.
