- 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)
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.ymllocal. El archivo/etc/cloudflared/config.ymldentro del contenedor solo contiene el UUID del túnel, las credenciales y el comodín*.urieljareth.org. Todas las rutas decoolify.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íneaINF 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 Gatewayo530
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 sanotls: first record does not look like a TLS handshake→ ruta 6001/6002 enhttps://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.jsonni 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; conhttps://aparecetls: first record does not look like a TLS handshakey 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.orgsiempre al final, connoTLSVerify: true(Traefik usa cert autofirmado interno).
4. Solución vía Dashboard (rápida, sin token)
- Entrar a Cloudflare Zero Trust → Networks → Tunnels →
coolify-tunnel→ Public Hostnames. - Corregir cada ruta que esté mal según la tabla del paso 3. Lo más común:
/app/*(6001): ServiceHTTPS→HTTP./terminal/ws*(6002): ServiceHTTPS→HTTP; path sin barra final.
- 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 handshakeprevios 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. cloudflaredes distroless: para leer archivos internos usadocker cp, nocatdirecto.
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).