Files
Proxmox-Coolify-Manager/docs/runbooks/cloudflare-tunnel.md
T
urieljareth f587a8baa2 Agrega scripts y runbooks: Cloudflare API, autostart Coolify, parche Chatwoot, deploy Solo Leveling + docs de casos
- scripts/Invoke-CloudflareApi.ps1: control de tunnel/DNS via API
- scripts/Install-CoolifyAutostart.ps1 + scripts/host/: autostart de LXC 102 + tunnel tras corte
- scripts/Apply-ChatwootEnterprisePatch.ps1: parche enterprise (autodetecta creds)
- Deploy-SoloLeveling.ps1: deploy build-on-server verificado
- docs/runbooks/cloudflare-tunnel.md y autostart-coolify.md
- docs/casos/chatwoot-enterprise-patch.md (credenciales redactadas)
- docs/AGENTS-coolify-apps.md + issues y reportes
- deploy_skill/references/coolify-4.1.2-notes.md: hallazgos verificados (seccion 7)
- package.json para verify-online.mjs del coolify-deploy skill
- .gitignore: excluye .claude/ y .opencode/ (config local de herramientas)
2026-07-18 11:31:31 -06:00

8.9 KiB

Runbook: Cloudflare Tunnel (coolify-tunnel)

Procedimiento para diagnosticar y corregir el túnel de Cloudflare que expone Coolify (coolify.urieljareth.org) y las apps (*.urieljareth.org).

Dato clave: el túnel está gestionado desde el dashboard de Cloudflare (remotely-managed), no por el config.yml local. El archivo /etc/cloudflared/config.yml dentro del contenedor solo contiene el UUID del túnel, las credenciales y el comodín *.urieljareth.org. Todas las rutas de coolify.urieljareth.org (incluidas 6001/6002) viven en el dashboard / la API de Cloudflare. Por eso un cambio de rutas NO se arregla editando archivos en el servidor — se arregla en el dashboard (rápido) o por la API (control total). La firma de esto en los logs es la línea INF Updated to new configuration version=N.

Síntomas típicos que llevan aquí:

  • En la terminal de Coolify: Terminal websocket connection lost. Reconnecting...
  • UI de Coolify inestable / reconexiones constantes / página en blanco al abrir una app
  • En logs de cloudflared: tls: first record does not look like a TLS handshake
  • Dominio de app con 502 Bad Gateway o 530

Documentos relacionados: ISSUE_cloudflare-tunnel_routing_websocket-tls-handshake.md · cloudflare-tunnel-coolify-agent_1.md · issue-coolify-static-app-deploy.md


1. Cargar entorno y verificar conexión

# Secretos privados (gitignored) — necesario solo para llamadas a API
. .\.env.local.ps1

# Verifica config + SSH + Docker + API (sale 1 si algo falla)
.\scripts\Test-ProxmoxConnection.ps1

El SSH funciona con los defaults aunque no cargues .env.local.ps1.


2. Diagnóstico rápido (solo lectura)

2.1 Logs recientes del túnel

.\scripts\Invoke-ProxmoxSsh.ps1 -Command "pct exec 102 -- docker logs cloudflared --tail 40"

Buscar:

  • Registered tunnel connection ... protocol=http2 (x4) → túnel arriba y sano
  • tls: first record does not look like a TLS handshake → ruta 6001/6002 en https://
  • Lost connection with the edge / failed to dial to edge with quic → ver nota de --protocol http2

2.2 Ver la configuración ACTIVA del túnel (lo que realmente aplica)

.\scripts\Invoke-ProxmoxSsh.ps1 -Command "pct exec 102 -- docker logs cloudflared --tail 60" |
  Select-String "Updated to new configuration"

Toma la línea con el version=N más alto (es la config vigente) y revisa el JSON ingress. Los puertos 6001 y 6002 deben decir http://, nunca https://. Cada vez que se guarda un cambio en el dashboard/API, version se incrementa.

2.3 Ver el config.yml local (opcional)

La imagen cloudflared es distroless (no tiene cat/sh propios para leer el archivo directo), así que se copia con docker cp y se lee desde el LXC:

.\scripts\Invoke-ProxmoxSsh.ps1 -Command "pct exec 102 -- sh -c 'docker cp cloudflared:/etc/cloudflared/config.yml /tmp/cf-config.yml && cat /tmp/cf-config.yml; rm -f /tmp/cf-config.yml'"

Esperado: solo tunnel:, credentials-file: y el comodín. Si aquí NO aparecen las rutas de coolify.urieljareth.org, confirma que el túnel es dashboard-managed.

Nunca leas credentials.json ni lo imprimas — contiene el secreto del túnel.


3. Reglas de oro de las rutas (ingress)

Cloudflare evalúa las rutas de arriba hacia abajo; las específicas van ANTES del comodín. Esta es la configuración correcta (orden exacto):

# Hostname Path Servicio Protocolo Notas
1 coolify.urieljareth.org /build/* 192.168.0.117:8000 http Build logs
2 coolify.urieljareth.org /project/* 192.168.0.117:8000 http Crítico: UI de apps
3 coolify.urieljareth.org /app/* 192.168.0.117:6001 http ⚠️ Websocket realtime
4 coolify.urieljareth.org /terminal/ws* 192.168.0.117:6002 http ⚠️ Terminal websocket
5 coolify.urieljareth.org * 192.168.0.117:8000 http Catch-all Coolify UI
6 *.urieljareth.org * 192.168.0.117:443 https Apps via Traefik (noTLSVerify: true)

Reglas no negociables:

  • 6001 y 6002 → http:// siempre. Esos puertos no hablan TLS; con https:// aparece tls: first record does not look like a TLS handshake y la terminal/realtime no conecta.
  • /project/* va ANTES de /app/*. Si no, las URL con /application/... las captura /app/* (puerto 6001) y la UI carga en blanco.
  • /terminal/ws* sin barra final (no /terminal/ws/ ni /terminal/ws/*).
  • *.urieljareth.org siempre al final, con noTLSVerify: true (Traefik usa cert autofirmado interno).

4. Solución vía Dashboard (rápida, sin token)

  1. Entrar a Cloudflare Zero Trust → Networks → Tunnels → coolify-tunnel → Public Hostnames.
  2. Corregir cada ruta que esté mal según la tabla del paso 3. Lo más común:
    • /app/* (6001): Service HTTPSHTTP.
    • /terminal/ws* (6002): Service HTTPSHTTP; path sin barra final.
  3. Guardar. Cloudflared aplica el cambio solo, sin reinicio (verás un nuevo version=N).

5. Solución vía API de Cloudflare (control total, requiere token)

Para gestionar el túnel sin tocar el dashboard (automatizable). Requiere un token y los IDs cargados en .env.local.ps1 (ver Set-ProxmoxEnv.example.ps1):

$env:CLOUDFLARE_API_TOKEN  = "<token con Account:Cloudflare Tunnel:Edit + Zone:DNS:Edit>"
$env:CLOUDFLARE_ACCOUNT_ID = "<account id>"
$env:CLOUDFLARE_ZONE_ID    = "<zone id de urieljareth.org>"
$env:CLOUDFLARE_TUNNEL_ID  = "5f0e5c5b-a180-46f2-a090-44d151006a62"

Wrapper PowerShell: scripts/Invoke-CloudflareApi.ps1 (mismo patrón que Invoke-CoolifyApi.ps1: Bearer token, Invoke-RestMethod).

. .\.env.local.ps1

# Verificar que el token es válido y sus permisos
.\scripts\Invoke-CloudflareApi.ps1 -Path "/user/tokens/verify"

# Leer la configuración (ingress) actual del túnel
.\scripts\Invoke-CloudflareApi.ps1 `
  -Path "/accounts/$($env:CLOUDFLARE_ACCOUNT_ID)/cfd_tunnel/$($env:CLOUDFLARE_TUNNEL_ID)/configurations"

# Aplicar la configuración corregida (PUT) — CONFIRMAR antes de ejecutar
$body = @{
  config = @{
    ingress = @(
      @{ hostname = "coolify.urieljareth.org"; path = "/build/*";       service = "http://192.168.0.117:8000" }
      @{ hostname = "coolify.urieljareth.org"; path = "/project/*";     service = "http://192.168.0.117:8000" }
      @{ hostname = "coolify.urieljareth.org"; path = "/app/*";         service = "http://192.168.0.117:6001" }
      @{ hostname = "coolify.urieljareth.org"; path = "/terminal/ws*";  service = "http://192.168.0.117:6002" }
      @{ hostname = "coolify.urieljareth.org";                          service = "http://192.168.0.117:8000" }
      @{ hostname = "*.urieljareth.org"; service = "https://192.168.0.117:443"; originRequest = @{ noTLSVerify = $true } }
      @{ service = "http_status:404" }
    )
  }
} | ConvertTo-Json -Depth 10

.\scripts\Invoke-CloudflareApi.ps1 -Method PUT `
  -Path "/accounts/$($env:CLOUDFLARE_ACCOUNT_ID)/cfd_tunnel/$($env:CLOUDFLARE_TUNNEL_ID)/configurations" `
  -BodyJson $body

⚠️ El último elemento http_status:404 (sin hostname) es obligatorio o la API rechaza la configuración. La referencia completa de endpoints (DNS, crear túnel, obtener token) está en cloudflare-tunnel-coolify-agent_1.md.

Cualquier PUT/POST a Cloudflare es un cambio de estado → confirmar con el usuario y capturar el estado actual (paso 2.2) antes de aplicar, para tener rollback.


6. Verificación

# Debe aparecer un version=N mayor con 6001/6002 ya en http://
.\scripts\Invoke-ProxmoxSsh.ps1 -Command "pct exec 102 -- docker logs cloudflared --tail 10"

Luego en el navegador: recargar la UI de Coolify con Ctrl+Shift+R y abrir una terminal en cualquier contenedor. Debe conectar sin Terminal websocket connection lost.


Notas

  • Los errores tls: first record does not look like a TLS handshake previos al cambio son residuales de conexiones ya abiertas; desaparecen solos.
  • Si el túnel se cae cada ~5 min con failed to dial to edge with quic: timeout, el contenedor debe correr con --protocol http2 (UDP/7844 suele estar bloqueado en redes domésticas). Ver PASO 6 de cloudflare-tunnel-coolify-agent_1.md.
  • cloudflared es distroless: para leer archivos internos usa docker cp, no cat directo.

Verificado: 2026-06-03 — corregidas rutas /app/* (6001) y /terminal/ws* (6002) de https:// a http:// desde el dashboard; terminal de Coolify operativa (config version=16).