TrafficServerLocal/docs/http-https.md
merios 33c368936e feat: infraestructura base de Traefik + generador de proyectos
- core/: reverse proxy Traefik v3 (HTTP 80 / HTTPS 443)
  - traefik.yml con provider Docker (exposedByDefault: false) y provider file
  - dynamic_tls.yml sanitizado con certificados .local comentados
  - certs/README.md con procedimiento de certificados auto-firmados
- init_project.sh: generador de proyectos base (SRV_DIR configurable)
  - plantilla compose con redireccion HTTP->HTTPS + Let's Encrypt
  - bloque alternativo comentado para dominios .local
- README.md: documentacion integral (puesta en marcha, HTTP/HTTPS,
  troubleshooting y seguridad)
- docs/arquitectura.md: guia de instalacion y gestion de URLs
- docs/http-https.md: referencia de etiquetas Traefik, TLS y certresolver
- .gitignore: excluye .env, acme.json, certificados, datos y respaldos
2026-10-15 11:34:39 -03:00

8.0 KiB

HTTP / HTTPS en Traefik — referencia de etiquetas

Todos los ejemplos son etiquetas de Docker Compose aplicables al servicio web del proyecto. Traefik las lee por el socket de Docker y construye la cadena Router → Middleware → Service.


1. Anatomía de una etiqueta

traefik.http.<scope>.<component>.<atributo>=<valor>
               │        │         │
               │        │         └─ propiedad (rule, entrypoints, tls, port…)
               │        └─────────── tipo (routers, services, middlewares)
               └──────────────────── ámbito/grupo (ej. "miapp-https")

Componentes usados:

Componente Función
routers Decide qué petición llega (Host, Path) y a qué entrypoint responde
middlewares Transformaciones (redirecciones, auth, headers)
services Traduce a con qué puerto interno del contenedor
tls Habilita TLS y define de dónde sale el certificado

2. Exponer un proyecto (mínimo funcional)

networks:
  default:
    driver: bridge
  proxy_network:
    external: true

services:
  web:
    build: { context: ./app, dockerfile: Dockerfile }
    container_name: miapp-web
    restart: unless-stopped
    networks: [ default, proxy_network ]     # ← ambas redes
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=proxy_network"
      - "traefik.http.routers.miapp.rule=Host(`miapp.local`)"
      - "traefik.http.routers.miapp.entrypoints=websecure"
      - "traefik.http.services.miapp.loadbalancer.server.port=80"

Notas:

  • traefik.enable=true es obligatorio (exposedByDefault: false).
  • traefik.docker.network=proxy_network fuerza a leer las etiquetas desde esa red cuando el contenedor está en varias.
  • El puerto del service es el puerto interno, no el publicado.

3. Modo A — Dominio público con Let's Encrypt

labels:
  - "traefik.enable=true"
  - "traefik.docker.network=proxy_network"

  # 1. Middleware de redirección
  - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
  - "traefik.http.middlewares.redirect-to-https.redirectscheme.permanent=true"

  # 2. Router HTTP (:80) → redirige
  - "traefik.http.routers.miapp-http.rule=Host(`app.ejemplo.com`)"
  - "traefik.http.routers.miapp-http.entrypoints=web"
  - "traefik.http.routers.miapp-http.middlewares=redirect-to-https"

  # 3. Router HTTPS (:443) → sirve el contenido
  - "traefik.http.routers.miapp-https.rule=Host(`app.ejemplo.com`)"
  - "traefik.http.routers.miapp-https.entrypoints=websecure"
  - "traefik.http.routers.miapp-https.tls=true"
  - "traefik.http.routers.miapp-https.tls.certresolver=letsencrypt"
  - "traefik.http.routers.miapp-https.service=miapp-svc"

  # 4. Servicio interno
  - "traefik.http.services.miapp-svc.loadbalancer.server.port=80"

Requisitos:

  1. DNS A/AAAA apuntando a la IP del servidor.
  2. Puertos 80 y 443 abiertos (el challenge HTTP-01 de Let's Encrypt usa el 80).
  3. ~/srv/core/data/acme.json existente y con permisos 600.

Traefik emite el certificado la primera vez que recibe tráfico HTTPS por ese Host. Para forzarlo: docker logs -f core-proxy y hacer un curl al dominio.

Mejorar el router HTTP con challenge sin romper la redirección

  - "traefik.http.routers.miapp-http.tls=true"
  - "traefik.http.routers.miapp-http.tls.certresolver=letsencrypt"
  - "traefik.http.routers.miapp-http.middlewares=redirect-to-https"

Esto permite que Let's Encrypt valide por el puerto 80 aunque todo el tráfico se redirija a HTTPS.


4. Modo B — Dominio local .local con certificado auto-firmado

4.1 Generar el certificado

cd ~/srv/core/data/certs
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
  -keyout miapp.local.key -out miapp.local.crt \
  -subj "/CN=miapp.local" \
  -addext "subjectAltName=DNS:miapp.local"
chmod 600 miapp.local.key

Certificado multi-dominio:

openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
  -keyout intranet.local.key -out intranet.local.crt \
  -subj "/CN=intranet.local" \
  -addext "subjectAltName=DNS:intranet.local,DNS:app.intranet.local,DNS:api.intranet.local"

4.2 Declararlo en el provider file

~/srv/core/data/dynamic_tls.yml (montado en /etc/traefik/dynamic_tls.yml):

tls:
  certificates:
    - certFile: /etc/traefik/certs/miapp.local.crt
      keyFile:  /etc/traefik/certs/miapp.local.key

La ruta es la de dentro del contenedor, porque el directorio se monta en /etc/traefik/certs.

4.3 Etiquetar el proyecto (sin certresolver)

labels:
  - "traefik.enable=true"
  - "traefik.docker.network=proxy_network"
  - "traefik.http.routers.miapp.rule=Host(`miapp.local`)"
  - "traefik.http.routers.miapp.entrypoints=websecure"
  - "traefik.http.routers.miapp.tls=true"
  - "traefik.http.services.miapp.loadbalancer.server.port=80"

Recargar:

cd ~/srv/core && docker compose restart traefik

4.4 Resolver el nombre en el cliente

echo "192.168.1.50  miapp.local" | sudo tee -a /etc/hosts

5. Modo C — Solo HTTP (entornos internos)

labels:
  - "traefik.enable=true"
  - "traefik.docker.network=proxy_network"
  - "traefik.http.routers.miapp.rule=Host(`miapp.local`)"
  - "traefik.http.routers.miapp.entrypoints=web"
  - "traefik.http.services.miapp.loadbalancer.server.port=80"

6. Varios dominios en un mismo proyecto

Dos approaches:

a) Múltiples reglas en un router (OR lógico):

  - "traefik.http.routers.miapp.rule=Host(`app.local`) || Host(`www.app.local`)"

b) Un router por dominio, apuntando al mismo service:

  - "traefik.http.routers.www.rule=Host(`www.app.local`)"
  - "traefik.http.routers.www.entrypoints=websecure"
  - "traefik.http.routers.www.tls=true"
  - "traefik.http.routers.www.service=miapp-svc"

Ambos necesitan los certificados correspondientes en dynamic_tls.yml o en Let's Encrypt (agregando los dominios a la regla del router con certresolver).


7. Errores frecuentes

Error Causa Solución
404 en todos los dominios traefik.enable ausente Agregar la etiqueta
404 solo en un dominio Regla Host() mal escrita Verificar comillas invertidas: Host(`dominio`)
502 Bad Gateway Puerto interno incorrecto Confirmar EXPOSE del Dockerfile y el puerto real
too many redirects Router HTTP con redirectscheme sin HTTPS válido Verificar que exista el router websecure
TLS handshake error / no certificate dynamic_tls.yml mal cargado o certificado expirado Rutas internas correctas + docker compose restart traefik
cannot generate ACME certificate DNS mal, puertos cerrados o acme.json sin permisos dig, revisar firewall y chmod 600 acme.json
El router no cambia al editar el compose Etiquetas cacheadas docker compose up -d --force-recreate

Verificación:

curl -sI http://miapp.local        # 301 → https://miapp.local
curl -sk https://miapp.local -I    # respuesta del backend (-k ignora el cert)

8. Cheatsheet de etiquetas

Etiqueta Efecto
traefik.enable=true Publica el contenedor
traefik.docker.network=<red> Red desde la que leer etiquetas
...routers.X.rule=Host(\d`)` Enruta por dominio
...routers.X.rule=PathPrefix(\/api`)` Enruta por ruta
...routers.X.entrypoints=web|websecure Puerto de escucha (80 / 443)
...routers.X.tls=true Habilita TLS en ese router
...routers.X.tls.certresolver=letsencrypt Emite/obtiene el certificado
...routers.X.middlewares=mw1,mw2 Aplica middlewares (orden izquierda→derecha)
...routers.X.service=svc Fuerza el service (si hay más de uno)
...services.X.loadbalancer.server.port=N Puerto interno del contenedor
...middlewares.X.redirectscheme.scheme=https Redirige HTTP → HTTPS
...middlewares.X.redirectscheme.permanent=true 301 en vez de 302
...middlewares.X.basicauth.users=file Protección básica