| name | coolify-ops |
| description | Drive the official coolify CLI to remotely operate a self-hosted Coolify instance — deploy, operate, and troubleshoot apps / services / databases. Use this skill whenever the user wants to deploy, restart, redeploy, roll back, check logs or deployment status, scale or adjust resources, bind a domain, add/change/sync environment variables, create or back up databases, expose a database port, or troubleshoot any resource on a Coolify instance — including English phrases like "deploy to Coolify", "restart that service", "check the deploy logs", "sync env vars to production", "roll back to the previous version", "expose the database port", or Chinese phrases like "部署到 Coolify"、"重启那个服务"、"看下部署日志"、"查部署状态"、"同步环境变量到线上"、"加个环境变量"、"给它绑个域名"、"扩容/调一下资源"、"备份数据库"、"回滚到上一个版本"、"把数据库端口暴露出去"、"Coolify 上那个 app 挂了",or when they mention a Coolify app/service/database UUID and want an operation performed. Also trigger when the user wants to set up the coolify CLI for the first time or add a new Coolify context. |
Coolify Ops
Remotely operate a Coolify instance through the official coolify CLI (the Go version, coollabsio/coolify-cli). This skill assumes the target is the user's own self-hosted Coolify (typically: one VPS + a handful of deployed Node/Next.js/Docker services).
Core Principles
-
For everything in this skill's scope, the CLI is an HTTP API client — not SSH. All the operations covered here (deploy / app / service / database / env / logs / backup — the entire v1.6.2 command surface) go through the Coolify REST API with a Bearer token; they have nothing to do with the server's SSH credentials. If a command can't connect, suspect API reachability and the token first, not SSH.
[ALPHA] — experimental Coolify v5 commands, out of scope here. The Coolify v5 roadmap adds SSH-based bootstrap commands that, unlike everything above, run over SSH + root:
init — provisions a host (WireGuard mesh + Podman) over SSH.
firewall — manages a COOLIFY-ALLOW iptables chain / cross-host container rules over SSH.
common sshmesh — the underlying SSH-mesh plumbing.
⚠️ These are not present in the verified v1.6.2 binary (coolify --help does not list them), so this skill neither uses nor documents them as usable — treat any such command as experimental, root-level, and not a stable feature; verify against your own CLI build before touching it. In particular, do not confuse a future firewall command (which manages mesh container rules) with hardening a public database port — restricting a public DB port's source IPs is still done with ufw / your cloud security group, which is a different thing entirely (see references/database-access.md §2.3).
-
The CLI is self-documenting — --help (or a generated reference) is the source of truth for flags. The CLI keeps evolving and flags change. The authoritative flag values are whatever coolify <command> --help prints, or a version-exact reference generated by scripts/gen-reference.sh (which runs coolify docs markdown / coolify docs llms into references/_generated/). The hand-maintained references/cli-cheatsheet.md is only a high-frequency quick reference (+ jq recipes + troubleshooting table) and can drift — never guess flags from memory. Common levels:
coolify --help
coolify app --help
coolify app deployments --help
coolify database --help
bash scripts/gen-reference.sh
-
JSON for yourself, table for people. When you need to parse the output (grab a UUID, judge state), always add --format=json and extract with jq. When showing state directly to the user, use the default table.
-
Confirm destructive operations first. For irreversible operations or anything that affects production — delete, stop (production), forced deploys — you must restate to the user what you're about to do and wait for confirmation before executing. See references/safety-rules.md. Never add a confirmation-skipping flag on your own initiative — --force/-f on app delete, or --force on deploy. (Note: env sync's -f is --file, the .env path — safe and required, not --force.)
-
Always look up UUIDs, never guess them. Before any operation targeting a specific resource, run coolify <resource> list --format=json to get the real UUID. Never fabricate or reuse a UUID from memory.
First-Time Setup (only when the CLI isn't installed or there's no context)
coolify version || bash scripts/install-cli.sh
coolify context list
coolify context add <name> <url> <token> -d
coolify context verify
Token permissions (least privilege)
The token's abilities are the real control over how much damage a runaway agent can do — set them when generating the token in the Web UI, not afterward. Coolify (Laravel Sanctum) abilities:
| Ability | Grants | Recommendation |
|---|
read | read all non-sensitive resources | baseline, always include |
deploy | trigger deployments / restarts | include for day-to-day ops |
write | create / update / delete config & resources | add only when you'll change config or create resources |
read:sensitive | reveal passwords / secrets / full compose | add only if the agent genuinely needs secret values (see below) |
root | bypass every permission check; can even toggle the API itself | never — do not issue a root token to an agent |
- Day-to-day ops (deploy, logs, restart, status):
read + deploy.
- Changing config or creating resources (
app/service/database create, update, env sync): add write.
read:sensitive is server-side redaction, not an honor system. Without it, the server itself redacts passwords / keys / compose, and -s / --show-sensitive returns nothing — that's a harder guarantee than "the agent promises not to print secrets". Only grant it when secret values are actually needed.
- Allowed IPs: in the Coolify API settings, restrict the token's source IPs to your known address(es). Leaving it blank /
0.0.0.0 means any host with the token can use it — not recommended for production.
- Team scoping: a token only sees resources in its own team. To manage another team, generate a separate token for it.
When it can't connect, work through the "Troubleshooting" section of references/cli-cheatsheet.md item by item.
Operations Decision Tree
After receiving an operations request, first determine its type, then follow the matching path:
A. Deploy / Redeploy an Existing Resource
The most frequent scenario. Flow:
coolify app list --format=json (or service/database) to confirm the resource exists and get its name/uuid
- If the user changed environment variables, first run
coolify app env sync <uuid> --file <.env> (see path D)
- Trigger the deploy: prefer using the name (easier to remember),
coolify deploy name <app-name>
- You must follow up after deploying: use
scripts/deploy-and-watch.sh <app-uuid> to automatically tail logs until success/fail, or manually coolify app deployments logs <uuid> -f
- Report the result: confirm on success; on failure, pull out the key error lines and, together with
references/deploy-patterns.md, give a fix suggestion
For how deploy configuration differs by project type (Node / Next.js / Docker / static site), see references/deploy-patterns.md.
B. Troubleshoot a Down/Abnormal Resource
coolify resources list --format=json to see overall state
coolify app get <uuid> --format=json to see details of the target resource
coolify app logs <uuid> to see runtime logs (container stdout)
coolify app deployments logs <uuid> to see the most recent deployment logs (build/startup phase)
- Distinguish the failure phase: for a build failure look at the deployment logs, for a runtime crash look at the runtime logs, for something that won't start look at the health check configuration
- Give a diagnosis + fix plan; after fixing, run
coolify app restart <uuid> and re-verify
C. Lifecycle Operations (start / stop / restart)
coolify app start|stop|restart <uuid>
coolify service start|stop|restart <uuid>
coolify database start|stop|restart <uuid>
You must confirm before stop-ping a production resource (see safety rules).
D. Environment Variable Management
Prefer bulk syncing with a .env file over creating variables one by one:
coolify app env list <uuid> --format=json
coolify app env sync <uuid> --file .env.production
Key semantics: env sync is incremental — it overwrites existing variables and creates missing ones, but does not delete variables that aren't in the file. To mirror completely, first list and then delete each one (deletion is a destructive operation and requires confirmation).
For variables needed at build time, pass --build-time=true; for preview environments, use --preview. Caveat: --build-time (and --runtime) default to true, and sync applies one flag set to the whole file — so a bare sync of a .env containing secrets may carry them into the build layer. To keep secrets out, sync them in a separate pass with --build-time=false. For env layering conventions, see references/deploy-patterns.md.
E. Databases and Backups
coolify database list --format=json
coolify database create postgresql --server-uuid <s> --project-uuid <p> \
--environment-name production --name <n> --instant-deploy
coolify database backup create <db-uuid> --frequency "0 2 * * *" --enabled --retention-days-locally 7
coolify database backup trigger <db-uuid> <backup-uuid>
Supported types: postgresql / mysql / mariadb / mongodb / redis / keydb / clickhouse / dragonfly.
Before dropping a database, always go through the checklist in the safety rules.
External access branch: when a request involves "make the database externally accessible / reachable from another machine / reachable from Vercel", or "connect to the database via a domain" / "expose the database port", first read references/database-access.md, and confirm with the user following its recommended order (internal > tunnel > hardened public exposure); don't go straight to --is-public. Key points: a database speaks TCP, not HTTP (https://db.example.com won't connect); a client on the same machine as the database uses the internal network, an external machine that can keep a process running uses a tunnel, and serverless platforms like Vercel go through the HTTP layer (a raw TCP tunnel won't work for them); if public exposure is truly required, first follow the standard --is-public procedure in safety-rules.md and warn that there is no TLS by default.
F. Resource Creation (from scratch)
The CLI can create resources from scratch (this is no longer Web-UI-only). First gather the placement UUIDs, then run the create command:
coolify server list --format=json
coolify project list --format=json
coolify project get <project-uuid>
- App:
coolify app create <public|github|deploy-key|dockerfile|dockerimage> --server-uuid <s> --project-uuid <p> --environment-name <env> ... — binds a git repo (or Dockerfile/image), sets build pack and ports. Required for public: --git-repository, --git-branch, --build-pack, --ports-exposes (plus the three placement flags above). See references/cli-cheatsheet.md.
- One-click service:
coolify service create <type> --server-uuid <s> --project-uuid <p> --environment-name <env> (run coolify service create --list-types to list types like wordpress / ghost / n8n / supabase).
- Database:
coolify database create <type> ... (path E above).
- Project (if none exists yet):
coolify project create --name <n>.
Create commands carry many flags and change across CLI versions — always run coolify app create <source> --help (or the matching --help) to confirm the exact flags before executing.
The Web UI is still handy for first-time visual setup, dashboards/metrics, and some advanced settings — but creation no longer requires it.
Reference Files
references/cli-cheatsheet.md — full command cheatsheet + troubleshooting table + output formats and global flags. Read it when you need to look up specific command syntax.
references/deploy-patterns.md — deploy configuration templates for the four project types (Node / Next.js / Docker / static site), env layering conventions, and Coolify magic variables (SERVICE_URL_* / SERVICE_PASSWORD_*). Read it when deploying or troubleshooting build issues.
references/safety-rules.md — red lines for destructive operations and confirmation checklists. Read it before executing any delete/stop/forced operation.
references/database-access.md — how to access a database on Coolify from outside: protocol awareness, the four-tier internal/tunnel/hardened-public-exposure plan, connecting via a domain (Cloudflare gray cloud), and TLS warnings. Read it whenever "make the database externally accessible / expose the port / connect via a domain" comes up.
Scripts
scripts/doctor.sh [context] — run this first on install or when troubleshooting. One-screen preflight: CLI version ≥ verified baseline, jq present, context connectivity/auth, and token abilities (a read probe + a non-destructive deploy probe that targets a bogus uuid so nothing is ever deployed).
scripts/install-cli.sh — cross-platform install of the official CLI (macOS/Linux; curl → brew → go install fallback).
scripts/health-check.sh — one-shot health check: whether the CLI is present, whether the context connects, and the state of each resource. Run it first when troubleshooting "how's everything doing overall".
scripts/deploy-and-watch.sh <app-uuid-or-name> — triggers a deploy and automatically follows the logs, only returning once the deploy is success or failed. The default recommended way to deploy.
scripts/gen-reference.sh — dumps this CLI version's full command reference (via coolify docs markdown / coolify docs llms) into references/_generated/. Run it once after install/upgrade; treat the output as the authoritative flag source.