deploy_skill: soporte para Coolify v4.1.2 (API /applications 404) + flujo UI Playwright
Aprendido desplegando cotizador (Next.js+FastAPI+Postgres, Docker Compose, repo privado) en coolify.urieljareth.org (v4.1.2): - Documenta que /applications/* devuelve 404 en esta instancia y que configurar apps git build-from-source solo es posible por la UI web. - Nuevos scripts scripts/coolify-ui/: coolify-login.mjs (guarda storageState) y Configure-CoolifyComposeApp.mjs (build pack -> Docker Compose, Reload Compose File, env vars por Developer view, dominios por servicio). - references/coolify-4.1.2-notes.md: mapa de API funcional/404, gotchas (BOM UTF-8 rompe el parser YAML de Coolify; Reload Compose File obligatorio; pin de dominios por servicio o 503; no encolar deploys concurrentes; PowerShell [IO.File]::ReadAllText para payloads de llaves). - env.local.template.ps1: COOLIFY_EMAIL/COOLIFY_PASSWORD para la UI. - SKILL.md/TOOLS.md: seccion "instance reality" y flujo UI paso a paso. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
cd998ce6b0
commit
e7d1c33cd5
@@ -0,0 +1,246 @@
|
||||
# Coolify Deploy — Tooling
|
||||
|
||||
All commands assume PowerShell from the project root. Load env first:
|
||||
|
||||
```powershell
|
||||
. .\.env.local.ps1
|
||||
```
|
||||
|
||||
Required env vars (in `.env.local.ps1`, gitignored):
|
||||
|
||||
- `COOLIFY_TOKEN` — for Coolify API.
|
||||
- `GITHUB_TOKEN` — PAT for GitHub API (create repo, list). `git push` uses
|
||||
wincred, NOT this PAT.
|
||||
- (Optional) `GITHUB_OWNER` — override the default `urieljarethbusiness-cpu`.
|
||||
- `COOLIFY_EMAIL` / `COOLIFY_PASSWORD` — Coolify **web UI** login. Required for the
|
||||
UI-driven flow below (this instance's `/applications/*` API is 404 — see
|
||||
`references/coolify-4.1.2-notes.md`).
|
||||
|
||||
## UI-driven config for git build-from-source apps (this instance, v4.1.2)
|
||||
|
||||
Because `/applications/*` is 404 here, configure git-based Docker-Compose apps through the
|
||||
UI with Playwright (run from the manager repo root so `require('playwright')` resolves):
|
||||
|
||||
```powershell
|
||||
. .\.env.local.ps1
|
||||
$env:CF_EMAIL = $env:COOLIFY_EMAIL; $env:CF_PASS = $env:COOLIFY_PASSWORD
|
||||
$scratch = "$env:TEMP\cf"; New-Item -ItemType Directory -Force $scratch | Out-Null
|
||||
|
||||
# 1. Log in once, save the session
|
||||
node .\deploy_skill\scripts\coolify-ui\coolify-login.mjs "$scratch\state.json"
|
||||
|
||||
# 2. Configure an EXISTING app (find its uuid/project/env via GET /resources + /projects/{u}/environments)
|
||||
$env:CF_STATE = "$scratch\state.json"
|
||||
$env:CF_APP_URL = "https://coolify.urieljareth.org/project/<proj>/environment/<env>/application/<app>"
|
||||
$env:CF_BUILDPACK = "dockercompose" # optional
|
||||
$env:CF_RELOAD = "1" # MANDATORY after buildpack switch / repo compose change
|
||||
$env:CF_ENVBULK = (Get-Content .\myapp\.env.coolify -Raw) # KEY=VALUE lines -> "Save All Environment Variables"
|
||||
$env:CF_DOMAINS = '{"web":"https://myapp.urieljareth.org"}' # pin per-service domains (else Coolify assigns random ones -> 503)
|
||||
node .\deploy_skill\scripts\coolify-ui\Configure-CoolifyComposeApp.mjs
|
||||
|
||||
# 3. Trigger the deploy (API works even though app CRUD is 404) and watch it
|
||||
.\coolify_skill\scripts\Invoke-CoolifyApi.ps1 -Path "/deploy?uuid=<app>"
|
||||
# poll GET /deployments/{deployment_uuid} for status+logs; then verify:
|
||||
.\deploy_skill\scripts\Test-ServiceOnline.ps1 -Fqdn https://myapp.urieljareth.org -ExpectTitle "<regex>"
|
||||
```
|
||||
|
||||
## Pipeline scripts
|
||||
|
||||
> **One-time setup:** run `npm install` in the manager repo root to enable the
|
||||
> Playwright-based operational verification (final pipeline step). Chromium
|
||||
> binaries live at `%LOCALAPPDATA%\ms-playwright`. Without it,
|
||||
> `Test-ServiceOnline.ps1` falls back to curl-only.
|
||||
|
||||
> **Two pipelines:** `Publish-ProjectToCoolify.ps1` is for single-app
|
||||
> Dockerfile builds (POST /applications/public). `New-CoolifyService.ps1` is
|
||||
> for multi-container Docker Compose stacks (POST /services). Use the right
|
||||
> one for your project shape.
|
||||
|
||||
### Full pipeline (one shot)
|
||||
|
||||
```powershell
|
||||
.\deploy_skill\scripts\Publish-ProjectToCoolify.ps1 `
|
||||
-AppPath .\my-app `
|
||||
-AppName my-app `
|
||||
-Fqdn https://my-app.urieljareth.org `
|
||||
-Stack node -AppPort 8080 -Init
|
||||
```
|
||||
|
||||
Runs: init → checklist → create GitHub repo → push → create Coolify app →
|
||||
deploy → Coolify-state inspection → **operational verification (HTTP 200 +
|
||||
Playwright browser)**. One confirmation per step unless `-Force`.
|
||||
|
||||
### Step by step
|
||||
|
||||
```powershell
|
||||
# 1. Scaffold Dockerfile/compose/.dockerignore/.gitignore additions
|
||||
.\deploy_skill\scripts\Initialize-CoolifyProject.ps1 -Path .\my-app -Stack node -AppPort 8080
|
||||
|
||||
# 2. Validate against AGENTS-coolify-apps.md hard rules
|
||||
.\deploy_skill\scripts\Test-PreDeployChecklist.ps1 -Path .\my-app -ExpectedPort 8080 -Strict
|
||||
|
||||
# 3. Create GitHub repo (idempotent; aborts if it already exists)
|
||||
.\deploy_skill\scripts\New-GitHubRepo.ps1 -Name my-app -Description "..." [-Private]
|
||||
|
||||
# 4. Push (uses wincred, not the PAT)
|
||||
cd .\my-app
|
||||
git init -b main
|
||||
git remote add origin https://github.com/urieljarethbusiness-cpu/my-app.git
|
||||
git add -A
|
||||
git commit -m "Initial commit"
|
||||
git push -u origin main
|
||||
|
||||
# 5. Create Coolify app + push envs + trigger deploy
|
||||
.\deploy_skill\scripts\New-CoolifyApplication.ps1 `
|
||||
-RepoUrl https://github.com/urieljarethbusiness-cpu/my-app.git `
|
||||
-Branch main `
|
||||
-Fqdn https://my-app.urieljareth.org `
|
||||
-PortsExposes 8080 `
|
||||
-EnvFile .\.env.coolify
|
||||
|
||||
# 6. Verify (Coolify state: containers, proxy logs, sibling DNS)
|
||||
.\deploy_skill\scripts\Test-PostDeploy.ps1 `
|
||||
-Fqdn https://my-app.urieljareth.org `
|
||||
-ContainerName my-app-main `
|
||||
-SiblingService postgres
|
||||
|
||||
# 7. Verify (OPERATIONAL: HTTP 200 + Playwright browser render)
|
||||
.\deploy_skill\scripts\Test-ServiceOnline.ps1 `
|
||||
-Fqdn https://my-app.urieljareth.org `
|
||||
-ExpectTitle "My App" -Retries 8
|
||||
```
|
||||
|
||||
### Multi-container stack (Docker Compose) — `New-CoolifyService.ps1`
|
||||
|
||||
For projects that ship a `docker-compose.coolify.yml` (app + DB + sidecars).
|
||||
POSTs the compose to Coolify's `/services` endpoint. The compose must already
|
||||
satisfy the hard rules (no published 80/443, DB by service name,
|
||||
`SERVICE_FQDN_<svc>_<port>` placeholders for Coolify to wire routes, named
|
||||
volumes, healthchecks).
|
||||
|
||||
```powershell
|
||||
.\deploy_skill\scripts\New-CoolifyService.ps1 `
|
||||
-AppPath .\my-stack `
|
||||
-AppName my-stack `
|
||||
-ComposeFile docker-compose.coolify.yml `
|
||||
-Fqdn https://my-stack.urieljareth.org `
|
||||
-PrimaryService web `
|
||||
[-ExtraUrls @{ api = 'https://my-stack-api.urieljareth.org' }] `
|
||||
[-ProjectName default] [-EnvironmentName production] `
|
||||
[-EnvFile .\my-stack\.env.coolify] `
|
||||
[-InstantDeploy | -NoDeploy] `
|
||||
[-ServiceUuid <existing-uuid-to-update>] `
|
||||
[-Force]
|
||||
```
|
||||
|
||||
`-PrimaryService web` maps the FQDN to the `web` service in the compose (via
|
||||
the `urls` payload). `-ExtraUrls` adds extra service→FQDN mappings for stacks
|
||||
with multiple public services. On success, prints `service_uuid`,
|
||||
`primary_fqdn`, `primary_service` — pipe those into `Test-PostDeploy.ps1` and
|
||||
`Test-ServiceOnline.ps1` for verification.
|
||||
|
||||
## Rollback / redeploy from a previous commit
|
||||
|
||||
```powershell
|
||||
.\deploy_skill\scripts\Invoke-CoolifyRollback.ps1 `
|
||||
-AppPath .\my-app `
|
||||
-ApplicationUuid og88wk4 `
|
||||
-CommitSha a1b2c3d
|
||||
```
|
||||
|
||||
Pushes the SHA to `rollback/<sha>` (main untouched), repoints Coolify, deploys.
|
||||
You will be prompted for the SHA if you omit `-CommitSha`.
|
||||
|
||||
## GitHub API (low level)
|
||||
|
||||
```powershell
|
||||
# Who am I?
|
||||
.\deploy_skill\scripts\Invoke-GitHubApi.ps1 -Path "/user"
|
||||
|
||||
# List my repos (paginated; first 30)
|
||||
.\deploy_skill\scripts\Invoke-GitHubApi.ps1 -Path "/user/repos?per_page=30"
|
||||
|
||||
# Check if a repo exists
|
||||
.\deploy_skill\scripts\Invoke-GitHubApi.ps1 -Path "/repos/urieljarethbusiness-cpu/my-app"
|
||||
|
||||
# Anything else: see https://docs.github.com/rest
|
||||
```
|
||||
|
||||
## Coolify API (already documented in coolify_skill)
|
||||
|
||||
The deploy skill reuses `coolify_skill/scripts/Invoke-CoolifyApi.ps1`. Useful
|
||||
endpoints for the deploy flow:
|
||||
|
||||
```powershell
|
||||
.\coolify_skill\scripts\Invoke-CoolifyApi.ps1 -Path "/projects"
|
||||
.\coolify_skill\scripts\Invoke-CoolifyApi.ps1 -Path "/servers"
|
||||
.\coolify_skill\scripts\Invoke-CoolifyApi.ps1 -Path "/applications"
|
||||
.\coolify_skill\scripts\Invoke-CoolifyApi.ps1 -Path "/applications/<uuid>"
|
||||
.\coolify_skill\scripts\Invoke-CoolifyApi.ps1 -Path "/applications/<uuid>/deployments"
|
||||
.\coolify_skill\scripts\Invoke-CoolifyApi.ps1 -Method POST -Path "/deploy" -BodyJson (@{ uuid = "<uuid>" } | ConvertTo-Json)
|
||||
```
|
||||
|
||||
For per-endpoint schemas, search `coolify_skill/references/ops/` with `rg`.
|
||||
|
||||
## Templates
|
||||
|
||||
| File | Use |
|
||||
|------|-----|
|
||||
| `references/templates/Dockerfile.node` | Node app with healthcheck on `/health` |
|
||||
| `references/templates/Dockerfile.python` | Python/gunicorn app |
|
||||
| `references/templates/docker-compose.app-db.yml` | App + sibling Postgres, external `coolify` network, named volumes |
|
||||
| `references/templates/env.local.template.ps1` | Template for the operator's `.env.local.ps1` |
|
||||
|
||||
## Operational verification — Test-ServiceOnline.ps1
|
||||
|
||||
The "definition of done". Confirms the deployed service actually serves a
|
||||
working page (not just that Coolify reports the container as running).
|
||||
|
||||
```powershell
|
||||
.\deploy_skill\scripts\Test-ServiceOnline.ps1 `
|
||||
-Fqdn https://my-app.urieljareth.org `
|
||||
[-Path /] `
|
||||
[-ExpectedStatusCode 200] `
|
||||
[-ExpectTitle "<regex>"] `
|
||||
[-Screenshot <png-path>] `
|
||||
[-SkipBrowser] `
|
||||
[-Retries 8] [-TimeoutMs 30000]
|
||||
```
|
||||
|
||||
Two layers (both must pass):
|
||||
|
||||
1. **HTTP (curl)**: status code in 2xx/3xx range. Catches Traefik 502, wrong
|
||||
`ports_exposes`, TLS DNS challenge not done, missing Cloudflare tunnel route.
|
||||
2. **Browser (Playwright + Chromium)**: real page navigation. Catches
|
||||
client-side JS crashes (`pageerror`), failed main-frame requests, blank
|
||||
error pages. Saves a PNG screenshot for evidence.
|
||||
|
||||
Retries default to 8 (≈80s of attempts with 10s gaps) to absorb Traefik/TLS
|
||||
warm-up after a fresh deploy. Exits 0 on success, non-zero on failure.
|
||||
|
||||
`-SkipBrowser` runs curl-only (for CI without a display, or when Chromium is
|
||||
unavailable). If Node/Playwright are missing entirely, the browser layer is
|
||||
auto-skipped with a warning (NOT a failure) — install with `npm install` in
|
||||
the manager repo root.
|
||||
|
||||
## Commands that always require confirmation
|
||||
|
||||
- Creating a GitHub repo (`New-GitHubRepo.ps1` warns if it already exists).
|
||||
- Any `git push` (the pipeline asks before pushing).
|
||||
- Any Coolify `POST`/`PATCH`/`DELETE` (project, environment, application, env,
|
||||
deploy).
|
||||
- Rollback (push + repoint + deploy).
|
||||
- Anything touching Cloudflare tunnel/DNS.
|
||||
|
||||
`-Force` skips the prompts. Use only after manually reviewing the plan.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Symptom | Likely cause | Fix |
|
||||
|---------|--------------|-----|
|
||||
| `git push` asks for username/password | wincred cache miss | Run any git HTTPS op once interactively; or `cmdkey /generic:git:https://github.com /user:urieljarethbusiness-cpu /pass:<PAT>` |
|
||||
| GitHub API 401 | `GITHUB_TOKEN` not loaded or expired | `. .\.env.local.ps1`; regenerate PAT at https://github.com/settings/tokens |
|
||||
| Coolify API 401 | `COOLIFY_TOKEN` not loaded | `. .\.env.local.ps1` |
|
||||
| App at 502 after deploy | `ports_exposes` mismatch (default is 3000) | `New-CoolifyApplication.ps1 -PortsExposes <real-port>` |
|
||||
| App can't reach DB | used `localhost` or wrong network | Use service name + external `coolify` network (see §2.1, §2.2 in AGENTS-coolify-apps.md) |
|
||||
| FQDN auto-generated UUID | FQDN not set before first deploy | Always pass `-Fqdn https://<name>.urieljareth.org` |
|
||||
Reference in New Issue
Block a user