# Red y exposición Los 5 dominios de abajo son reales y comparten exactamente el mismo camino de red — ninguno tiene un caso especial. ## Dominios activos | Dominio | Servicio | Namespace | TLS | |---|---|---|---| | `shop.cruzcloud.net` | Frontend Next.js (storefront) | `ecommerce` | Cloudflare (edge) | | `commerce.cruzcloud.net` | Medusa Store/Admin API | `ecommerce` | Cloudflare (edge) | | `media.cruzcloud.net` | MinIO (imágenes de producto) | `ecommerce` | Cloudflare (edge) | | `gitea.cruzcloud.net` | Gitea | — | Cloudflare (edge) | | `docs.cruzcloud.net` | Este portal | `docs` | Cloudflare (edge) | ## Por qué todos van "proxied" (naranja), ninguno "DNS-only" Un registro DNS-only en Cloudflare expondría directamente la IP real del túnel — pero acá no hay IP pública fija que exponer: el NAS está detrás de NAT residencial. El modo proxied es lo que hace que Cloudflare Tunnel tenga sentido en primer lugar (el tráfico entra por el edge de Cloudflare, nunca directo al origen), así que no hay ningún dominio de este lab para el que DNS-only sea una opción real. ## Dónde termina TLS de verdad ```mermaid flowchart LR User(["Usuario"]) -->|HTTPS| CF["Cloudflare edge
🔒 TLS termina acá"] CF -->|túnel cifrado, HTTP/2| CFD["cloudflared"] CFD -->|HTTP plano| NPM["Nginx Proxy Manager"] NPM -->|HTTP plano| LB["k3d-proxy :90"] LB -->|HTTP plano| TR["Traefik"] TR -->|HTTP plano| SVC["Service interno"] ``` TLS termina en el **edge de Cloudflare**, no en Traefik ni en NPM. De ahí hacia adentro (`cloudflared` → NPM → `k3d-proxy` → Traefik → Service) todo el tráfico va en HTTP plano — seguro en este contexto porque ese tramo entero vive dentro de la red local del NAS, nunca sale a internet. Ningún componente interno necesita certificado propio ni gestionar renovación de TLS. ## Por qué HTTP/2 y no QUIC en el túnel `cloudflared` puede usar QUIC (UDP) o HTTP/2 (TCP) para sus conexiones salientes hacia el edge. Este lab fuerza HTTP/2 explícitamente — no es el default. Un incidente real de `504 Gateway Timeout` intermitente en **todos** los subdominios (no solo uno) se rastreó hasta fallos recurrentes del "control stream" de QUIC sobre la red doméstica del NAS. Ver [ADR 0003](../decisiones/0003-por-que-http2-sobre-quic-tunnel.md) para la decisión completa y el [playbook del 504](../playbooks/incidente-504-gitea-tunnel.md) para el diagnóstico paso a paso. ## Patrón de diagnóstico: "interno sano, público roto" Cuando un dominio público falla pero todo dentro del cluster responde bien (pods `Running`, probes verdes, `kubectl exec` con `curl` al Service funciona), la causa casi nunca está en Kubernetes — está en la capa NPM. La forma rápida de confirmarlo es saltarse NPM a propósito: `curl -H "Host: " http://192.168.68.61:90/` habla directo con `k3d-proxy`/Traefik sin pasar por NPM. Si eso funciona pero el dominio público no, el problema está específicamente en el `forward_host`/ `forward_port` del proxy host en NPM (ej.: un scheme o un path colado en `forward_host`, que rompe todo el enrutamiento). Este patrón se repitió dos veces en este lab con la misma causa raíz exacta: el [incidente de imágenes en `media.cruzcloud.net`](../playbooks/incidente-imagenes-npm.md) (playbook completo) y un incidente posterior de `commerce.cruzcloud.net` devolviendo 400 por el mismo tipo de `forward_host` roto (sin playbook propio todavía). Una lección adicional de ese segundo incidente: editar el `proxy_host` a mano en el sqlite de NPM **no** regenera el `.conf` de nginx automáticamente — el cambio tiene que pasar por la propia UI/API de NPM, o el `.conf` hay que parchearlo a mano y recargar nginx.