6.0 KiB
+++ title = "Caddy: arquitectura de dos capas y alta de dominios con DNS-01/Route53" description = "Las dos capas de Caddy, cómo agregar un dominio interno con certificado real vía DNS-01/Route53, y los dos gotchas conocidos de propagación." date = 2026-08-19T20:25:10Z authors = ["gen"] slug = "run-20260819-a3b63b-caddy-arquitectura-de-dos-capas-y-alta-de-dominios-con-dns-01-route53" template = "page.html" weight = 26
[taxonomies] categories = ["manuales"] tags = ["caddy", "dns-01", "route53", "tls"] systems = ["caddy"]
[extra] id = "RUN-20260819-A3B63B" kind = "manuales" author_id = "gen" author_fingerprint = "SHA256:JhN1Tt4jYqWoJIznDJ6QkMAiOR6HFHr3xLz9aBJqmPg" +++
Arquitectura: dos Caddys, dos capas
Internet ──HTTPS(443)──> Caddy #1 (mcps-vpn-server, IP pública)
│ termina TLS real (Let's Encrypt)
│ reenvía HTTP plano por el túnel WireGuard
▼
mcps-hpc-01 (10.8.0.18)
│
Caddy #2 (ahí mismo)
│ segundo enrutamiento por Host header
┌──────────────┼──────────────┬─────────────┐
▼ ▼ ▼ ▼
nginx/Apache/gunicorn/Grafana/etc (los backends reales)
- Config de Caddy #1:
/etc/caddy/Caddyfile+/etc/caddy/tenants/*.caddy. - Config de Caddy #2:
/mnt/cephfs/hot/caddy/Caddyfile(montado en el contenedor víacontainer-caddy.service, systemd+podman en.18). mcps-net(red podman en.18) tienedns_enabled: false— por eso el Caddyfile de ahí usa IPs fijas, no nombres de contenedor. Si un contenedor se recrea sin--ipfijo, su IP cambia y hay que actualizar el Caddyfile a mano. Ponga siempre--ip 10.89.0.Xfijo a cualquier contenedor nuevo que Caddy vaya a referenciar ahí.
Dominios VPN-only vs. públicos
Los dominios internos (Cockpit, Zammad, pgAdmin, RStudio, Jupyter, Snipe-IT, etc.) apuntan en Route53 a propósito a 10.8.0.18 (IP privada, solo alcanzable por VPN), nunca a la IP pública. Con eso, tls internal (certificado autofirmado) da warning de navegador — el patrón correcto es DNS-01 vía Route53, que da certificado real de Let's Encrypt sin necesitar reachability pública.
Prerrequisitos (infraestructura de una sola vez, ya existe)
- Usuario IAM dedicado
caddy-route53-dns01, con permisos mínimos:route53:ChangeResourceRecordSetsyroute53:ListResourceRecordSetssobre la zonamcps-epcm.org(Z05793723RVTGN4VZAAUN), másGetChange/ListHostedZones*(globales). Nunca usar las credenciales del usuarioAdministrator. - Imagen Caddy custom con el plugin de Route53 (la oficial no lo trae):
Imagen:
FROM caddy:builder AS builder RUN xcaddy build --with github.com/caddy-dns/route53 FROM caddy:latest COPY --from=builder /usr/bin/caddy /usr/bin/caddylocalhost/caddy-route53:latest. - Credenciales en
/etc/caddy-route53.env(root:root,600), inyectadas al contenedor vía--env AWS_ACCESS_KEY_ID --env AWS_SECRET_ACCESS_KEY(forma "bare" de podman: toma el valor del entorno del proceso llamador, por eso elEnvironmentFile=en el systemd unit).
Procedimiento: agregar un dominio nuevo a este patrón
- En Route53, apunte el registro del dominio a
10.8.0.18(VPN-only) o a la IP pública correspondiente (público). - En
/mnt/cephfs/hot/caddy/Caddyfile, agregue el bloque del sitio con:tls { dns route53 { access_key_id {env.AWS_ACCESS_KEY_ID} secret_access_key {env.AWS_SECRET_ACCESS_KEY} } propagation_delay 20s propagation_timeout -1 } caddy validatesobre el Caddyfile antes de aplicar.caddy reload(no reinicia el proceso, no tira el resto de sitios).
Por qué propagation_timeout -1 y propagation_delay 20s, no el default
La red de .18 redirige por transparencia todo el tráfico DNS al resolver 132.248.204.1 (red UNAM), sin importar qué servidor le pidas — confirmado con nslookup ... 8.8.8.8 desde dentro de un contenedor, devolviendo NXDOMAIN mientras el registro sí existía y propagaba bien visto desde mcps-vpn-server. El chequeo de propagación propio de Caddy (usando ese resolver secuestrado/con caché negativo viejo) se queda colgado indefinidamente.
propagation_timeout -1: Caddy no verifica localmente, deja que Let's Encrypt valide directo desde su red.propagation_delay 20s: espera fija para dar tiempo real a Route53, evita condición de carrera si el registro aún no propagó del todo.
Nota: esto no es una ruta de red real hacia la UNAM, solo el DNS configurado en el router — la salida real a internet de .18 es Telmex (única default route). No hay forma de salir con IP de la UNAM desde esta infraestructura.
Verificación
curl -v https://<dominio>.mcps-epcm.orgmuestraSSL certificate verify okcon emisor Let's Encrypt, no un certificado autofirmado.- El sitio responde sin advertencia de certificado en el navegador (dentro de la VPN, si es VPN-only).
Solución de problemas
Duplicate Resource Recordal reintentar DNS-01: si se mata/reinicia Caddy a medio intento, puede quedar un registro_acme-challenge.<dominio>huérfano en Route53 que choca con el siguiente intento. Bórrelo a mano:aws route53 list-resource-record-sets --hosted-zone-id Z05793723RVTGN4VZAAUN \ --query "ResourceRecordSets[?Name=='_acme-challenge.<dominio>.mcps-epcm.org.']" # luego change-resource-record-sets con Action=DELETE y el mismo valor- El challenge se queda colgado indefinidamente: confirme que el bloque
tlstienepropagation_timeout -1— sin eso, Caddy intenta verificar la propagación usando el resolver secuestrado de la red de.18y nunca termina. - Un contenedor backend cambia de IP y el sitio deja de responder: confirme que el contenedor se recreó con
--ipfijo; si no, actualice el Caddyfile a la IP nueva.