Ingress y TLS automático

Cómo exponer aplicaciones por el puerto 443 con certificados emitidos y renovados automáticamente, sin operar un router externo.

Red·7 min·última revisión 2026-04-26

HeroCtl trae un router integrado embebido en el plano de control. No lo instalas, no lo configuras, no lo actualizas. Al levantar el cluster, el router ya está activo en los puertos 80 y 443 de cada nodo servidor.

Eso significa que exponer una aplicación en internet es una línea en el spec del job.

El camino más corto

job: minha-api
ingress:
  host: api.exemplo.com
  port: http
  tls: true

Con eso el cluster hace tres cosas en secuencia:

  1. Resuelve el host api.exemplo.com a cualquier alocación saludable del job.
  2. Solicita un certificado válido para ese dominio en la primera request.
  3. Renueva ese certificado antes del vencimiento, sin intervención.

Solo necesitas apuntar el DNS de api.exemplo.com a las IPs de los nodos servidores. El resto corre solo.

Cómo se emite el certificado

HeroCtl usa Let's Encrypt como autoridad certificadora por defecto. Detrás de eso hay dos mecanismos de validación soportados.

HTTP-01 (default)

Funciona para cualquier dominio público que apunta al cluster. Cuando una autoridad pide prueba de posesión, el router integrado responde en la ruta /.well-known/acme-challenge/ automáticamente. Nada necesita ser configurado.

Atención: HTTP-01 exige que el puerto 80 esté accesible externamente. Si el firewall bloquea el 80, la emisión falla.

DNS-01 (para wildcards)

Si necesitas un certificado wildcard (*.exemplo.com), usa DNS-01. Configura el proveedor DNS en el spec del cluster:

acme:
  challenge: dns-01
  provider: cloudflare
  credentials:
    api_token: ${secret.cloudflare_token}

Proveedores soportados nativamente: Cloudflare, Route53, DigitalOcean, Hostinger, Hetzner. Otros van por plugin externo.

Con DNS-01 activo, basta declarar:

ingress:
  host: "*.exemplo.com"
  tls: true

Redirección HTTP → HTTPS

Cuando tls: true, todo tráfico que llega al puerto 80 es redirigido con 301 al 443. No necesitas duplicar configuración.

Para forzar HSTS:

ingress:
  host: api.exemplo.com
  tls: true
  hsts:
    enabled: true
    max_age: 31536000
    include_subdomains: true
    preload: false

No habilites preload sin entender el compromiso. Es difícil revertir.

Múltiples dominios para la misma app

Patrón común: www.exemplo.com y exemplo.com apuntando a la misma aplicación, con uno siendo canónico.

ingress:
  host: exemplo.com
  redirect_from:
    - www.exemplo.com
  tls: true

Cada dominio en redirect_from recibe su propio certificado y responde 301 al host canónico.

Ruteo por path

Mismo host, aplicaciones diferentes en paths diferentes:

# job: site-marketing
ingress:
  host: exemplo.com
  path: /
  tls: true

# job: api-publica
ingress:
  host: exemplo.com
  path: /api
  tls: true

El router resuelve la precedencia por especificidad. /api/users cae en api-publica. /sobre cae en site-marketing.

Cabeceras customizadas

Para agregar o remover headers en la respuesta:

ingress:
  host: api.exemplo.com
  tls: true
  headers:
    add:
      X-Frame-Options: DENY
      X-Content-Type-Options: nosniff
      Referrer-Policy: strict-origin
    remove:
      - Server
      - X-Powered-By

Rate limiting básico

Defensa en primera línea contra abuso:

ingress:
  host: api.exemplo.com
  tls: true
  rate_limit:
    requests_per_second: 100
    burst: 200
    by: ip

Límites más elaborados (por token, por endpoint, con bypass para partners) quedan en la aplicación.

Troubleshooting

El certificado no fue emitido

Chequea tres cosas, en orden:

SíntomaCausa probableQué hacer
dial tcp: timeout en el log del challengePuerto 80 cerradoLiberar 80/tcp inbound en los nodos servidores
unauthorized: Invalid responseDNS apunta a otro lugardig +short api.exemplo.com debe retornar IP de nodo servidor
too many failed authorizationsPegaste el rate limit de Let's EncryptAguardar 1h y revisar la config antes de intentar de nuevo

Inspecciona el estado de la emisión:

heroctl ingress cert-status api.exemplo.com

El certificado venció sin renovar

La renovación corre 30 días antes del vencimiento. Si pasó de eso, hay error acumulado:

heroctl ingress cert-renew api.exemplo.com --force

Verifica también si redirect_from aún apunta al cluster. Un dominio que fue movido a otro proveedor sin ser removido del spec rompe la renovación silenciosamente.

ACME challenge intermitente

Síntoma: a veces emite, a veces falla. Generalmente es DNS round-robin con una IP que no responde en 80, o un Cloudflare al frente en modo proxy. Para HTTP-01, el dominio debe resolver directo al cluster durante el desafío. Usa DNS-01 si mantienes Cloudflare proxy activado.

Próximos pasos

  • Configurar firewall para liberar solo lo necesario.
  • Entender el modelo de secretos antes de inyectar tokens DNS en el spec.
#ingress#tls#https#acme#lets-encrypt#red