- 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)
170 lines
6.8 KiB
Markdown
170 lines
6.8 KiB
Markdown
# Issue: Despliegue de App Estática en Coolify — Página en Blanco y 502
|
|
|
|
**Fecha:** 2026-04-11
|
|
**Entorno:** Coolify v4.0.0-beta.472 — Proxmox LXC CT 102 — Cloudflare Tunnel
|
|
**Estado:** Resuelto ✅
|
|
|
|
---
|
|
|
|
## Síntomas
|
|
|
|
- Al crear una app desde GitHub y dar clic en **Continue**, la UI redirige a una URL como:
|
|
`coolify.urieljareth.org/project/{uuid}/environment/{uuid}/application/{uuid}`
|
|
y muestra **página en blanco** o **HTTP 404**.
|
|
- Al hacer clic en una app existente desde la lista de proyectos, también carga en blanco.
|
|
- El dominio de la app desplegada devuelve **502 Bad Gateway** desde Cloudflare.
|
|
|
|
---
|
|
|
|
## Causas Raíz (múltiples)
|
|
|
|
### 1. Regla del Cloudflare Tunnel capturaba rutas de la UI incorrectamente
|
|
|
|
La ruta `/app/*` del tunnel (usada para websockets del puerto 6001) hacía match parcial con `/application/...` porque Cloudflare evalúa prefijos. Cualquier URL con `/application/` en el path era enviada al puerto 6001 (websocket) en lugar del puerto 8000 (Coolify UI).
|
|
|
|
**Solución:** Agregar una regla explícita `/project/*` antes de `/app/*` para que las rutas de la UI de Coolify sean enrutadas correctamente al puerto 8000.
|
|
|
|
### 2. Certificados SSL fallaban por "Always Use HTTPS" en Cloudflare
|
|
|
|
Let's Encrypt valida dominios por HTTP (`/.well-known/acme-challenge/`). Con "Usar siempre HTTPS" activo en Cloudflare, esas solicitudes eran redirigidas a HTTPS antes de llegar a Traefik, causando error 502 en la validación y rate limit 429.
|
|
|
|
**Solución:** Configurar Traefik para usar **DNS Challenge via API de Cloudflare** en lugar de HTTP Challenge. Esto elimina la dependencia de validación HTTP para siempre.
|
|
|
|
### 3. Puerto incorrecto en etiquetas de Traefik
|
|
|
|
Coolify asignaba puerto 3000 por defecto a apps nuevas. Las apps nginx escuchan en puerto 80. Traefik enviaba tráfico al 3000 y obtenía 502.
|
|
|
|
**Solución:** Actualizar `ports_exposes` en la base de datos a `80` antes del primer deploy.
|
|
|
|
### 4. Dominio UUID autogenerado
|
|
|
|
Coolify genera un UUID como subdominio cuando no detecta el dominio durante la creación. Esos subdominios UUID no tienen registro DNS y no funcionan.
|
|
|
|
**Solución:** Actualizar `fqdn` en la base de datos inmediatamente después de crear la app.
|
|
|
|
---
|
|
|
|
## Solución Permanente
|
|
|
|
### Paso 1 — Configurar DNS Challenge en Traefik
|
|
|
|
Crear token de API en Cloudflare con permisos `Zona → DNS → Editar` para `urieljareth.org`.
|
|
|
|
Editar `/data/coolify/proxy/docker-compose.yml`:
|
|
|
|
```yaml
|
|
environment:
|
|
- CF_DNS_API_TOKEN=<token>
|
|
command:
|
|
# Reemplazar httpchallenge por dnschallenge:
|
|
- '--certificatesresolvers.letsencrypt.acme.dnschallenge=true'
|
|
- '--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=cloudflare'
|
|
- '--certificatesresolvers.letsencrypt.acme.dnschallenge.resolvers=1.1.1.1:53,8.8.8.8:53'
|
|
- '--certificatesresolvers.letsencrypt.acme.storage=/traefik/acme.json'
|
|
```
|
|
|
|
Limpiar certificados anteriores y reiniciar:
|
|
|
|
```bash
|
|
echo '{}' > /data/coolify/proxy/acme.json && chmod 600 /data/coolify/proxy/acme.json
|
|
docker compose -f /data/coolify/proxy/docker-compose.yml up -d --force-recreate
|
|
```
|
|
|
|
### Paso 2 — Configurar rutas del Cloudflare Tunnel
|
|
|
|
Orden correcto en **Zero Trust → Networks → Tunnels → coolify-tunnel → Rutas de aplicación publicada:**
|
|
|
|
| # | Dominio | Ruta | Servicio | Notas |
|
|
|---|---------|------|---------|-------|
|
|
| 1 | coolify.urieljareth.org | /build/* | http://192.168.0.117:8000 | Build logs |
|
|
| 2 | coolify.urieljareth.org | /project/* | http://192.168.0.117:8000 | **Crítico: UI de apps** |
|
|
| 3 | coolify.urieljareth.org | /app/* | http://192.168.0.117:6001 | Websocket realtime |
|
|
| 4 | coolify.urieljareth.org | /terminal/ws* | http://192.168.0.117:6002 | Terminal websocket |
|
|
| 5 | coolify.urieljareth.org | * | http://192.168.0.117:8000 | Catch-all Coolify |
|
|
| 6 | *.urieljareth.org | * | https://192.168.0.117:443 | Apps via Traefik |
|
|
|
|
> ⚠️ La regla `/project/*` en posición 2 es crítica. Sin ella, `/application/...` es capturada por `/app/*` y la UI falla.
|
|
|
|
---
|
|
|
|
## Flujo de Trabajo para Nuevas Apps (mientras dure el bug de UI)
|
|
|
|
Debido a un bug de Coolify beta.472, la UI de apps individuales no carga correctamente tras la creación. El flujo correcto es:
|
|
|
|
**1. Crear la app en la UI** (seleccionar repo, Build Pack: Static, continuar)
|
|
|
|
**2. Obtener el ID de la app recién creada:**
|
|
```bash
|
|
docker exec coolify-db psql -U coolify -d coolify \
|
|
-c "SELECT id, name, fqdn FROM applications ORDER BY id DESC LIMIT 3;"
|
|
```
|
|
|
|
**3. Actualizar dominio y puerto antes del deploy:**
|
|
```bash
|
|
docker exec coolify-db psql -U coolify -d coolify \
|
|
-c "UPDATE applications SET fqdn='https://miapp.urieljareth.org', ports_exposes='80' WHERE id=<ID>;"
|
|
```
|
|
|
|
**4. Hacer deploy via API:**
|
|
```bash
|
|
curl -X POST "http://localhost:8000/api/v1/deploy?uuid=<UUID>&force=false" \
|
|
-H "Authorization: Bearer <TOKEN>"
|
|
```
|
|
|
|
**5. Verificar que el puerto en el docker-compose generado sea 80:**
|
|
```bash
|
|
grep "server.port" /data/coolify/applications/<UUID>/docker-compose.yaml
|
|
```
|
|
|
|
Si sigue mostrando 3000, corregir manualmente:
|
|
```bash
|
|
sed -i 's/loadbalancer.server.port=3000/loadbalancer.server.port=80/g' \
|
|
/data/coolify/applications/<UUID>/docker-compose.yaml
|
|
sed -i 's/upstreams 3000/upstreams 80/g' \
|
|
/data/coolify/applications/<UUID>/docker-compose.yaml
|
|
docker compose -f /data/coolify/applications/<UUID>/docker-compose.yaml up -d --force-recreate
|
|
```
|
|
|
|
---
|
|
|
|
## Comandos de Diagnóstico
|
|
|
|
```bash
|
|
# Ver estado de todos los contenedores Coolify
|
|
docker ps --format "table {{.Names}}\t{{.Status}}" | grep coolify
|
|
|
|
# Ver logs de Traefik (certificados, errores)
|
|
docker logs coolify-proxy --tail 50 2>&1 | grep -i "error\|certificate\|acme"
|
|
|
|
# Ver logs del tunnel
|
|
docker logs cloudflared --tail 30
|
|
|
|
# Verificar etiquetas Traefik de una app
|
|
docker inspect <nombre-contenedor> | grep "server.port\|rule\|certresolver"
|
|
|
|
# Listar apps en la base de datos
|
|
docker exec coolify-db psql -U coolify -d coolify \
|
|
-c "SELECT id, name, fqdn, ports_exposes FROM applications;"
|
|
```
|
|
|
|
---
|
|
|
|
## Lecciones Aprendidas
|
|
|
|
| Problema | Causa | Solución |
|
|
|----------|-------|---------|
|
|
| UI página en blanco al abrir app | `/app/*` captura `/application/...` en Cloudflare | Agregar regla `/project/*` antes de `/app/*` |
|
|
| 502 en dominio de app | Traefik sin certificado SSL | DNS Challenge con token Cloudflare |
|
|
| 502 en dominio de app | Puerto 3000 en lugar de 80 | Actualizar `ports_exposes` en DB |
|
|
| UUID como subdominio | Dominio no configurado al crear | Actualizar `fqdn` en DB antes del deploy |
|
|
| Rate limit 429 de Let's Encrypt | Intentos fallidos de validación HTTP | DNS Challenge elimina la validación HTTP |
|
|
|
|
---
|
|
|
|
## Configuración de Referencia
|
|
|
|
**Archivo:** `/data/coolify/proxy/docker-compose.yml`
|
|
**Backup:** `/data/coolify/proxy/docker-compose.yml.bak`
|
|
**Certificados:** `/data/coolify/proxy/acme.json`
|
|
**Apps:** `/data/coolify/applications/<UUID>/docker-compose.yaml`
|