Actualizar Traefik.md: limpiar duplicados y añadir serversTransport insecure@file

2025-12-01 18:06:04 +01:00
parent 47ddd97d7c
commit 1ae70cc991

@@ -60,6 +60,7 @@ services:
# Service backend # Service backend
- "traefik.http.services.portainer.loadbalancer.server.port=9443" - "traefik.http.services.portainer.loadbalancer.server.port=9443"
- "traefik.http.services.portainer.loadbalancer.server.scheme=https" - "traefik.http.services.portainer.loadbalancer.server.scheme=https"
- "traefik.http.services.portainer.loadbalancer.serversTransport=insecure@file"
# Middlewares de seguridad (opcional) # Middlewares de seguridad (opcional)
- "traefik.http.routers.portainer.middlewares=security-headers@file" - "traefik.http.routers.portainer.middlewares=security-headers@file"
@@ -180,9 +181,19 @@ El middleware `ip-allowlist@file` ya incluye rangos privados (10.0.0.0/8, 172.16
email: tu-email@tudominio.com # Debe estar configurado email: tu-email@tudominio.com # Debe estar configurado
``` ```
### Certificado Autofirmado en Logs ### Certificado Autofirmado (Error 500)
Es normal. Traefik se comunica con Portainer por HTTPS (cert autofirmado interno), pero el usuario final ve el certificado de Let's Encrypt. Portainer usa certificado SSL autofirmado. Traefik necesita el `serversTransport` para aceptarlo:
```yaml
labels:
- "traefik.http.services.portainer.loadbalancer.server.scheme=https"
- "traefik.http.services.portainer.loadbalancer.serversTransport=insecure@file"
```
El transport `insecure@file` está definido en `dynamic/config.yml` del repositorio de Traefik.
**Nota**: El usuario final ve el certificado de Let's Encrypt, no el autofirmado de Portainer.
## Ejemplo Completo ## Ejemplo Completo
@@ -200,6 +211,7 @@ services:
- "traefik.http.routers.portainer.tls.certresolver=letsencrypt" - "traefik.http.routers.portainer.tls.certresolver=letsencrypt"
- "traefik.http.services.portainer.loadbalancer.server.port=9443" - "traefik.http.services.portainer.loadbalancer.server.port=9443"
- "traefik.http.services.portainer.loadbalancer.server.scheme=https" - "traefik.http.services.portainer.loadbalancer.server.scheme=https"
- "traefik.http.services.portainer.loadbalancer.serversTransport=insecure@file"
networks: networks:
proxy: proxy:
@@ -208,6 +220,26 @@ networks:
### docker-compose.override.yaml con Seguridad ### docker-compose.override.yaml con Seguridad
```yaml
services:
portainer:
networks:
- proxy
labels:
- "traefik.enable=true"
- "traefik.http.routers.portainer.rule=Host(`portainer.tudominio.com`)"
- "traefik.http.routers.portainer.entrypoints=websecure"
- "traefik.http.routers.portainer.tls.certresolver=letsencrypt"
- "traefik.http.services.portainer.loadbalancer.server.port=9443"
- "traefik.http.services.portainer.loadbalancer.server.scheme=https"
- "traefik.http.services.portainer.loadbalancer.serversTransport=insecure@file"
- "traefik.http.routers.portainer.middlewares=security-headers@file,rate-limit@file"
networks:
proxy:
external: true
```
```yaml ```yaml
services: services:
portainer: portainer:
@@ -234,448 +266,3 @@ networks:
- [Wiki Traefik](https://git.ictiberia.com/groales/traefik/wiki) - [Wiki Traefik](https://git.ictiberia.com/groales/traefik/wiki)
**Volver a**: [Página Principal](Home) **Volver a**: [Página Principal](Home)
```yaml
services:
portainer:
networks:
- traefik_network
labels:
- "traefik.enable=true"
- "traefik.http.routers.portainer-http.rule=Host(`portainer.tudominio.com`)"
- "traefik.http.routers.portainer-http.entrypoints=web"
- "traefik.http.routers.portainer-http.middlewares=redirect-to-https"
- "traefik.http.routers.portainer.rule=Host(`portainer.tudominio.com`)"
- "traefik.http.routers.portainer.entrypoints=websecure"
- "traefik.http.routers.portainer.tls=true"
- "traefik.http.routers.portainer.tls.certresolver=letsencrypt"
- "traefik.http.services.portainer.loadbalancer.server.port=9443"
- "traefik.http.services.portainer.loadbalancer.server.scheme=https"
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
- "traefik.http.middlewares.redirect-to-https.redirectscheme.permanent=true"
networks:
traefik_network:
external: true
```
**Ventaja**: El `docker-compose.yaml` base permanece sin cambios, y los overrides se aplican automáticamente.
### 4. Reiniciar Portainer
```bash
docker compose down
docker compose up -d
```
### 5. Verificar
```bash
# Ver logs de Traefik
docker logs traefik
# Verificar que Portainer está en la red de Traefik
docker network inspect traefik_network
```
Acceder a: `https://portainer.tudominio.com`
## Configuración de Traefik
### traefik.yml Mínimo
Si aún no tienes Traefik configurado, aquí un ejemplo básico:
```yaml
# traefik.yml
api:
dashboard: true
insecure: false
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: ":443"
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
network: traefik_network
certificatesResolvers:
letsencrypt:
acme:
email: admin@tudominio.com
storage: /letsencrypt/acme.json
httpChallenge:
entryPoint: web
```
### docker-compose.yml de Traefik
```yaml
version: '3.8'
services:
traefik:
image: traefik:latest
container_name: traefik
restart: always
ports:
- "80:80"
- "443:443"
- "8080:8080" # Dashboard (proteger en producción)
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik.yml:/traefik.yml:ro
- ./letsencrypt:/letsencrypt
networks:
- traefik_network
labels:
# Dashboard (opcional, configurar autenticación)
- "traefik.enable=true"
- "traefik.http.routers.traefik.rule=Host(`traefik.tudominio.com`)"
- "traefik.http.routers.traefik.entrypoints=websecure"
- "traefik.http.routers.traefik.tls=true"
- "traefik.http.routers.traefik.tls.certresolver=letsencrypt"
- "traefik.http.routers.traefik.service=api@internal"
networks:
traefik_network:
external: true
```
Iniciar Traefik:
```bash
docker network create traefik_network
mkdir letsencrypt
touch letsencrypt/acme.json
chmod 600 letsencrypt/acme.json
docker compose up -d
```
## Configuración Avanzada
### Autenticación Básica (Opcional)
Proteger Portainer con autenticación HTTP básica:
```bash
# Generar password hash
echo $(htpasswd -nb admin tu_password) | sed -e s/\\$/\\$\\$/g
# Resultado: admin:$$apr1$$...
```
Añadir labels:
```yaml
labels:
# ... labels existentes ...
- "traefik.http.routers.portainer.middlewares=portainer-auth"
- "traefik.http.middlewares.portainer-auth.basicauth.users=admin:$$apr1$$..."
```
### Headers de Seguridad
```yaml
labels:
# ... labels existentes ...
- "traefik.http.routers.portainer.middlewares=security-headers"
- "traefik.http.middlewares.security-headers.headers.stsSeconds=31536000"
- "traefik.http.middlewares.security-headers.headers.stsIncludeSubdomains=true"
- "traefik.http.middlewares.security-headers.headers.stsPreload=true"
- "traefik.http.middlewares.security-headers.headers.forceSTSHeader=true"
- "traefik.http.middlewares.security-headers.headers.frameDeny=true"
- "traefik.http.middlewares.security-headers.headers.contentTypeNosniff=true"
- "traefik.http.middlewares.security-headers.headers.browserXssFilter=true"
```
### Rate Limiting
Limitar peticiones para prevenir abusos:
```yaml
labels:
# ... labels existentes ...
- "traefik.http.routers.portainer.middlewares=rate-limit"
- "traefik.http.middlewares.rate-limit.ratelimit.average=100"
- "traefik.http.middlewares.rate-limit.ratelimit.burst=50"
```
### IP Whitelist
Restringir acceso solo desde IPs específicas:
```yaml
labels:
# ... labels existentes ...
- "traefik.http.routers.portainer.middlewares=ip-whitelist"
- "traefik.http.middlewares.ip-whitelist.ipwhitelist.sourcerange=192.168.1.0/24,10.0.0.0/8"
```
### Múltiples Dominios
Acceder a Portainer desde varios dominios:
```yaml
labels:
- "traefik.http.routers.portainer.rule=Host(`portainer.tudominio.com`) || Host(`docker.tudominio.com`)"
```
### Configuración con Subdirectorio
Acceder en `https://tudominio.com/portainer`:
```yaml
labels:
- "traefik.http.routers.portainer.rule=Host(`tudominio.com`) && PathPrefix(`/portainer`)"
- "traefik.http.routers.portainer.middlewares=portainer-stripprefix"
- "traefik.http.middlewares.portainer-stripprefix.stripprefix.prefixes=/portainer"
```
⚠️ **Nota**: Portainer puede tener problemas con subdirectorios. Recomendamos usar subdominios.
## Wildcard Certificates
Para certificados wildcard con DNS challenge:
```yaml
# traefik.yml
certificatesResolvers:
letsencrypt:
acme:
email: admin@tudominio.com
storage: /letsencrypt/acme.json
dnsChallenge:
provider: cloudflare # O tu proveedor DNS
delayBeforeCheck: 30
```
Variables de entorno para Cloudflare:
```yaml
# docker-compose.yml de Traefik
services:
traefik:
environment:
- CF_API_EMAIL=tu@email.com
- CF_API_KEY=tu_api_key
```
Labels en Portainer:
```yaml
labels:
- "traefik.http.routers.portainer.tls.domains[0].main=tudominio.com"
- "traefik.http.routers.portainer.tls.domains[0].sans=*.tudominio.com"
```
## Docker Compose Completo
### Portainer con Traefik
Archivo completo `docker-compose.override.yaml`:
```yaml
version: '3.8'
services:
portainer:
networks:
- traefik_network
labels:
# Habilitar Traefik
- "traefik.enable=true"
# Dominio
- "traefik.http.routers.portainer.rule=Host(`portainer.tudominio.com`)"
# Entrypoints
- "traefik.http.routers.portainer.entrypoints=websecure"
# TLS
- "traefik.http.routers.portainer.tls=true"
- "traefik.http.routers.portainer.tls.certresolver=letsencrypt"
# Service backend
- "traefik.http.services.portainer.loadbalancer.server.port=9443"
- "traefik.http.services.portainer.loadbalancer.server.scheme=https"
# Middlewares (opcional)
- "traefik.http.routers.portainer.middlewares=security-headers"
- "traefik.http.middlewares.security-headers.headers.stsSeconds=31536000"
- "traefik.http.middlewares.security-headers.headers.stsIncludeSubdomains=true"
- "traefik.http.middlewares.security-headers.headers.frameDeny=true"
- "traefik.http.middlewares.security-headers.headers.contentTypeNosniff=true"
- "traefik.http.middlewares.security-headers.headers.browserXssFilter=true"
networks:
traefik_network:
external: true
```
## Troubleshooting
### Certificado No Se Genera
1. **Verificar logs de Traefik**:
```bash
docker logs traefik | grep -i error
```
2. **Revisar permisos de acme.json**:
```bash
chmod 600 letsencrypt/acme.json
```
3. **Verificar DNS**:
```bash
nslookup portainer.tudominio.com
dig portainer.tudominio.com
```
4. **Rate limits de Let's Encrypt**:
- Máximo 5 certificados por semana por dominio
- Usar staging durante pruebas:
```yaml
certificatesResolvers:
letsencrypt:
acme:
caServer: https://acme-staging-v02.api.letsencrypt.org/directory
```
### Error 502 Bad Gateway
1. **Verificar que Portainer está corriendo**:
```bash
docker ps | grep portainer
```
2. **Verificar red compartida**:
```bash
docker network inspect traefik_network | grep portainer
```
3. **Revisar puerto del servicio**:
```yaml
# Asegurarse de usar el puerto interno correcto
- "traefik.http.services.portainer.loadbalancer.server.port=9443"
```
4. **Verificar scheme HTTPS**:
```yaml
- "traefik.http.services.portainer.loadbalancer.server.scheme=https"
```
### Redirección Infinita
Si hay loop de redirecciones:
```yaml
labels:
# Remover redirección HTTP si Traefik ya lo maneja globalmente
# Comentar estas líneas:
# - "traefik.http.routers.portainer-http.rule=..."
# - "traefik.http.routers.portainer-http.middlewares=redirect-to-https"
```
### Certificado Autofirmado Aún Se Muestra
Portainer usa su propio certificado SSL. Traefik termina SSL antes de llegar a Portainer, por lo que:
1. **Es normal** que Portainer siga usando su cert autofirmado internamente
2. El usuario final ve el certificado de Let's Encrypt de Traefik
3. Traefik se comunica con Portainer por HTTPS (con cert autofirmado)
Si quieres evitar warnings en logs de Traefik:
```yaml
labels:
- "traefik.http.services.portainer.loadbalancer.server.scheme=https"
- "traefik.http.services.portainer.loadbalancer.serversTransport=ignorecert"
# En traefik.yml:
# http:
# serversTransports:
# ignorecert:
# insecureSkipVerify: true
```
## Monitorización
### Logs de Traefik
```bash
# Ver requests a Portainer
docker logs -f traefik | grep portainer
# Ver errores TLS
docker logs traefik | grep -i "tls\|certificate"
```
### Verificar Certificado SSL
```bash
# Ver información del certificado
echo | openssl s_client -servername portainer.tudominio.com -connect localhost:443 2>/dev/null | openssl x509 -noout -dates
# Verificar desde exterior
curl -vI https://portainer.tudominio.com 2>&1 | grep -i "SSL\|certificate"
```
## Seguridad Adicional
### 1. Fail2ban con Traefik
Proteger contra brute-force:
```bash
# /etc/fail2ban/filter.d/traefik-auth.conf
[Definition]
failregex = ^<HOST> - - .* "(GET|POST|HEAD).*HTTP.*" 401 .*$
ignoreregex =
```
```ini
# /etc/fail2ban/jail.local
[traefik-auth]
enabled = true
port = http,https
logpath = /var/log/traefik/access.log
maxretry = 5
bantime = 3600
```
### 2. Autenticación de Dos Factores
Portainer tiene 2FA integrado (no depende de Traefik):
1. **Settings****Authentication**
2. Habilitar **OAuth** o **LDAP** con 2FA
3. O usar middleware de Traefik con OAuth2 Proxy
### 3. VPN como Alternativa
Para máxima seguridad, no exponer Portainer a Internet:
1. Acceso solo via VPN (WireGuard, OpenVPN)
2. Traefik escucha solo en IP privada
3. Usuarios conectan primero a VPN
---
**Recursos adicionales**:
- [Documentación Traefik](https://doc.traefik.io/traefik/)
- [Let's Encrypt Rate Limits](https://letsencrypt.org/docs/rate-limits/)
- [Traefik Middlewares](https://doc.traefik.io/traefik/middlewares/overview/)
**Volver a**: [Página Principal](Home)