89 lines
4.7 KiB
Markdown
89 lines
4.7 KiB
Markdown
# Caso: deploy de oh-daddy en Coolify (2026-09-08)
|
|
|
|
**App:** [oh-daddy](https://github.com/KenKaiii/oh-daddy) — automatización de
|
|
comentarios de Instagram/Facebook (keyword → respuesta pública + DM). Next.js 16,
|
|
`postgres` (sin ORM), **Inngest self-hosted** como cola. El repo está diseñado
|
|
para Railway (`railway.json`, `scripts/railway-setup.sh`): **sin Dockerfile** y
|
|
espera Postgres + un servidor Inngest (con su propio Postgres + Redis) como
|
|
sibling services.
|
|
|
|
**Resultado:** `https://ohdaddy.urieljareth.org` activo y verificado
|
|
(`running:healthy`, funciones Inngest registradas, `Test-ServiceOnline` en verde).
|
|
|
|
## Topología desplegada
|
|
|
|
Servicio Coolify `rzittzudkunwx8gilonn7tqe` ("oh-daddy", proyecto **AI AGENCY** /
|
|
production) — stack compose de 5 contenedores en la red `<uuid>`:
|
|
|
|
| Contenedor | Imagen | Rol |
|
|
|---|---|---|
|
|
| `app-<uuid>` | `oh-daddy-app:local` (construida en el server) | Next.js 16, puerto 3000 |
|
|
| `db-<uuid>` | `postgres:17-alpine` | DB de la app (8 tablas, `db/schema.sql`) |
|
|
| `inngest-<uuid>` | `inngest/inngest:v1.44.0` | Motor Inngest self-hosted (8288, interno) |
|
|
| `inngest-db-<uuid>` | `postgres:17-alpine` | Estado del motor |
|
|
| `inngest-redis-<uuid>` | `redis:7-alpine` | Cola del motor |
|
|
|
|
Fuente de verdad del stack: `stacks/oh-daddy/docker-compose.coolify.yml` (sin
|
|
secretos; llegan por envs del servicio). Redeploy: `scripts/apps/Deploy-OhDaddy.ps1`.
|
|
|
|
## Wiring de la app (replica el contract de railway-setup.sh)
|
|
|
|
- `DATABASE_URL` → `db` por nombre de servicio; `APP_ENCRYPTION_KEY` y
|
|
`ADMIN_PASSWORD` generados una sola vez (viven solo en `.env.local.ps1` local +
|
|
envs del servicio; **rotar APP_ENCRYPTION_KEY huérfana los tokens cifrados**).
|
|
- `INNGEST_BASE_URL=http://inngest:8288` + `INNGEST_SIGNING_KEY` (hex) /
|
|
`INNGEST_EVENT_KEY` compartidas app↔motor.
|
|
- `NEXT_PUBLIC_APP_URL=https://ohdaddy.urieljareth.org` (build arg + runtime).
|
|
- La imagen arranca con `bash scripts/start.sh` (el contract de `railway.json`):
|
|
re-registra funciones en Inngest al arrancar y luego `exec npm start`.
|
|
- Registro manual: `curl -X PUT https://ohdaddy.urieljareth.org/api/inngest`.
|
|
Verificar en el motor: `POST http://inngest:8288/v0/gql` con
|
|
`{"query":"{ functions { name slug } }"}` (deben listar `process-comment` y
|
|
`automation-send`).
|
|
- Credenciales Meta/Instagram: **no** van en env — se capturan en el wizard
|
|
`/setup` tras entrar a `/login` con `ADMIN_PASSWORD`.
|
|
|
|
## Cómo se desplegó (patrón Solo Leveling, imagen local)
|
|
|
|
1. `New-CoolifyService.ps1 -NoDeploy` creó el servicio (compose base64 + `urls`
|
|
→ FQDN del servicio `app`).
|
|
2. Un `POST /services/{uuid}/start` (que **falla en el pull** de
|
|
`oh-daddy-app:local`, esperado) materializó en disco el compose normalizado
|
|
con labels Traefik completos, el `.env` y la red `<uuid>`.
|
|
3. Build en el server: clone + `stacks/oh-daddy/Dockerfile` inyectado (multi-stage
|
|
node:22-alpine, `NEXT_PUBLIC_APP_URL` como build arg) → `oh-daddy-app:local`.
|
|
4. `docker compose up -d` manual + `docker network connect <uuid> coolify-proxy`.
|
|
5. `db/schema.sql` aplicado con `docker exec -i db-<uuid> psql` (idempotente).
|
|
6. `PUT /api/inngest` público → 200.
|
|
|
|
## Gotchas nuevos (no documentados antes)
|
|
|
|
- **`POST /services/{uuid}/envs` da 409** si el compose ya declaró `${VAR}`:
|
|
Coolify auto-crea las claves vacías al parsear. Usar **`PATCH
|
|
/services/{uuid}/envs/bulk`** con `{"data":[{key,value,is_literal:true}]}`.
|
|
- **`GET /deploy?uuid=` da 405 en 4.3.17** — el trigger válido es
|
|
`POST /services/{uuid}/start`.
|
|
- **El primer re-sync de Inngest del arranque falla con `503 no available
|
|
server`**: `start.sh` hace el PUT antes de que Traefik considere healthy el
|
|
contenedor. Es benigno — reintentar el PUT cuando la app esté healthy.
|
|
- El `wget` de busybox (imagen alpine) soporta `--post-data`/`--header` para
|
|
golpear el gql del motor desde el contenedor app.
|
|
|
|
## Verificación (2026-09-08)
|
|
|
|
- `GET /resources` → `running:healthy`; 5 contenedores healthy; DNS entre
|
|
hermanos OK (`db`, `inngest`, `inngest-db`, `inngest-redis`).
|
|
- Motor: `{"data":{"functions":[{"name":"automation-send"...},{"name":"process-comment"...}]}}`,
|
|
app "oh-daddy" registrada, `/health` OK.
|
|
- `Test-ServiceOnline.ps1 -Fqdn https://ohdaddy.urieljareth.org -Path /login`:
|
|
HTTP 200 + render Chromium limpio (título "Oh Daddy. Comment automations on
|
|
autopilot"), sin `pageerror`.
|
|
- Restart policy `unless-stopped` en los 5 contenedores (sobreviven reinicios
|
|
del LXC junto con el autostart de Docker).
|
|
|
|
## Pendiente humano
|
|
|
|
Entrar a `https://ohdaddy.urieljareth.org/login` con `ADMIN_PASSWORD` (única
|
|
copia en plaintext: el reporte del deploy / `.env.local.ps1`) y completar el
|
|
wizard `/setup` con las credenciales de la app de Meta.
|