# Coolify

> Use when self-hosting apps and databases with Coolify on a VPS you own — install, first-admin lockdown, Git-to-deploy (Nixpacks/Dockerfile/compose), managed Postgres/Redis, scheduled S3 backups, domains + auto-SSL. NOT a PaaS someone else runs (that is `railway`), NOT sizing/hardening the box (that is `hetzner`), NOT authoring Dockerfiles (that is `docker`).

- Skill: `ericrisco/coolify` (Agent Skill, multi-file: 7 files)
- Install (CLI): `npx skillmds@latest add ericrisco/coolify`
- Raw SKILL.md: https://api.skillmd.com/api/skills/ericrisco/coolify/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: ericrisco (https://skillmd.com/u/ericrisco)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/ericrisco/coolify

---


# Coolify — own-the-box PaaS on your VPS

Coolify is an open-source, self-hostable control plane that turns a plain Linux VPS into a Vercel/Heroku
replacement: Git-to-deploy, managed databases, automatic SSL, scheduled backups — for a flat VPS bill
instead of per-request metering. This skill is operational. It produces the exact install one-liner, the
port matrix, env wiring, a lint-clean compose artifact, and a backup-to-S3 cron with a tested restore.
Coolify 4.x (stable in 2026); v4.1 added Railpack, structured audit logging, and a read-only MCP server.

## Mental model — read this first

1. **Coolify is the control plane, not the box.** It runs *on* a VPS you provisioned elsewhere. Hardware
   sizing, the cloud firewall, SSH hardening, OS patching → that is the VPS layer (hetzner /
   digitalocean), not this skill. Coolify orchestrates what runs on the box.
2. **You own the data and the uptime now.** No vendor takes nightly snapshots for you. So backups are
   non-optional and a backup you have never restored is not a backup (see the backup section).
3. **Everything underneath is Docker.** Coolify generates compose/Dockerfile runs and a Traefik proxy. So
   every Docker rule still applies — named volumes, healthchecks, pinned images, env-injected secrets.
   For image-authoring depth (multi-stage, layer caching) go to the `docker` skill; here we wire it.
4. **First account to register owns the instance — forever.** There is no "admin invite" recovery if a
   stranger registers first. Claim it within seconds of install (see step 4).

## Decision — where should this app actually run?

| Option | Who owns the box | Cost shape | Ops burden | Choose when |
| --- | --- | --- | --- | --- |
| **Coolify self-hosted** (this skill) | You (your VPS) | Flat VPS/month | You patch + back up | Predictable bill, data sovereignty, many apps on one box |
| **Coolify Cloud** | You bring the server; they host the control plane | VPS + small SaaS fee | They run the control plane | Want Coolify UX without babysitting the dashboard's own uptime |
| **Managed PaaS** (railway / render / fly-io / vercel / netlify) | The provider | Per-usage, scales up fast | Near-zero | Spiky scale-to-zero, no box to own — the inverse of Coolify |

Choose Coolify when a few always-on apps on a known-cost box beats per-request metering. If the user wants
`git push` and never touches a server, that is railway — route there.

## Install — the 6-minute path

Provision the box first (this is the hetzner / digitalocean step, not this skill). Floor is 2 CPU / 2 GB
RAM / 30 GB disk; Coolify itself idles around 1 GB RAM. For comfortable multi-app production aim for
4 vCPU / 8 GB / 100 GB NVMe. Ubuntu 22.04/24.04 LTS recommended (Debian, Fedora/Alma/Rocky, Alpine, Arch,
Raspberry Pi OS 64-bit also supported; non-LTS needs manual steps — see references).

```bash
# 1. SSH in AS ROOT. Non-root is not fully supported by the installer — log in as root.
ssh root@<server-ip>

# 2. One-liner install (root). Takes ~2–5 min: installs Docker, sets up Coolify's own stack.
curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash
```

```text
# 3. The installer prints the dashboard URL: http://<server-ip>:8000
# 4. CRITICAL — within seconds, open http://<server-ip>:8000 and REGISTER.
#    That first account becomes the permanent root admin of the instance. First-come-owns-the-box;
#    there is no later "claim ownership" flow. Do not walk away between step 2 and this.
# 5. In the dashboard: set the instance FQDN (coolify.example.com) and force HTTPS, so you stop
#    hitting the raw :8000 IP and the dashboard itself gets a real certificate.
```

Why root: the installer wires Docker and system services; the docs state non-root is not fully supported.
Why claim immediately: the registration page is open until someone takes it.

Full install transcript, non-LTS/other-OS steps, dashboard-domain setup, Traefik (default) vs Caddy,
wildcard domains + the DNS-01 challenge, and common SSL failures with their fixes →
`references/install-and-proxy.md`.

## Port & firewall matrix

Set these at the cloud firewall (hetzner/digitalocean layer) AND keep them in mind on the box.

| Port | Purpose | Exposure |
| --- | --- | --- |
| 22 | SSH | Restrict to your IP / VPN; key-only |
| 8000 | Coolify dashboard | **Restrict** to your IP after setup, or front with the proxy on a FQDN; never leave open to the world |
| 80 | Proxy HTTP (Traefik) → redirects to 443 | Public |
| 443 | Proxy HTTPS, app traffic + Let's Encrypt | Public |
| 6001 | Realtime / websocket | Open as the dashboard needs (same audience as 8000) |
| 6002 | Realtime / terminal websocket | Same as 6001 |

Rule: 80/443 are the only ports the public should reach. 8000/6001/6002 are operator surface — lock them
to your IP or put the dashboard behind its FQDN. Why: an open :8000 plus an unclaimed instance is a
takeover; an open :8000 on a claimed instance is still your full control plane exposed to brute force.

## Deploy an app

Pick the build pack first, then wire source → env → storage → domain.

| Build pack | Use when | Note |
| --- | --- | --- |
| **Nixpacks** (default) | Standard app, you want zero config | Auto-detects the language/runtime; start here |
| **Railpack** (v4.1, beta) | Need build-time env vars, config merge, or multi-stage control | Newer; reach for it when Nixpacks can't express the build |
| **Dockerfile** | You already have a Dockerfile / want full build control | You own the build; pin a base image |
| **docker-compose** | Multi-service app deployed as a unit | Coolify runs your compose; this is the verify.sh-linted artifact shape |

Then:

1. **Connect the Git source** — GitHub/GitLab app or a deploy key; pick branch; enable auto-deploy on push
   (or trigger from CI — that wiring is the `github-actions` skill).
2. **Set env vars as Coolify secrets** — inject at runtime via the UI/API; never bake secrets into the
   image or commit them to the compose. Why: a baked secret ships in every image layer and leaks on pull.
3. **Add persistent storage** — any path that must survive a redeploy (uploads, sqlite) gets a named
   volume. A container without one loses its writes on every recreate.
4. **Attach the domain + SSL** — add `app.example.com`, point its DNS A record at the box (DNS itself is
   the `domains-dns` skill), and the Traefik proxy provisions Let's Encrypt automatically on ports 80/443.

Build-pack decision deep-dive plus a worked, lint-clean `docker-compose.yml` (env-ref secrets, named
volumes, healthcheck, pinned image) — the verify.sh target → `references/deploy-recipes.md`.

## Managed databases

Coolify provisions Postgres, MySQL, MariaDB, MongoDB, Redis (and more) in-product — one-click, with
generated credentials.

- **Connect apps over the internal Docker network hostname**, not a public IP. Coolify gives each DB an
  internal service name; the app reaches it on the private network. Why: zero public attack surface.
- **Do NOT publicly expose the DB port** unless you genuinely need an external client. If you must, bind
  it deliberately and firewall it to known IPs — an open 5432/3306 is scanned within minutes.
- **Every DB gets a named volume.** Without it, recreating the service wipes the data. This is the single
  most common Coolify data-loss footgun.

This skill provisions and connects the DB; it does not teach SQL, indexing, or query tuning — that is the
`postgresdb` skill. Per-engine details and connection strings → `references/databases-and-backups.md`.

## Backups to S3 — non-negotiable

You own the data now. Coolify runs scheduled dumps (`pg_dump` / `mysqldump` / `mongodump`) on a cron
expression, stores them locally, and optionally pushes to S3-compatible storage: AWS S3, Cloudflare R2,
Backblaze B2, MinIO, Wasabi.

1. **Add an S3 destination** — endpoint, region, bucket, access key/secret (as Coolify secrets, never in
   a committed file). Off-box storage is the point: a backup on the same disk dies with the disk.
2. **Set the cron schedule** — e.g. `0 3 * * *` for nightly 03:00. Match frequency to how much data you
   can afford to lose (RPO doctrine across systems is the `backups` skill; here we wire the in-product job).
3. **Set retention** — keep N days/copies so the bucket doesn't grow unbounded.
4. **Run the restore drill — once, before you need it.** Download a dump, decompress, replay it into a
   throwaway DB, confirm the row counts. An untested backup is a guess. Schedule a recurring drill.

S3 destination setup for R2/B2/MinIO/Wasabi/AWS, per-engine dump/restore commands, retention, the
step-by-step restore runbook and its consistency caveats → `references/databases-and-backups.md`.

## Operate the box

- **Resource planning.** Coolify idles ~1 GB RAM; budget the rest for your apps + databases. Multi-app
  sweet spot is 4 vCPU / 8 GB / 100 GB NVMe. Watch RAM headroom before adding the next app.
- **Updates.** Update Coolify from the dashboard's settings; pin/snapshot before a major bump.
- **Logs & audit.** Per-resource logs live in the UI. v4.1 adds a structured audit log — use it to see who
  changed what.
- **MCP server (v4.1, read-only).** Coolify exposes an instance-level MCP server with read-only tools for
  AI-agent integration. Useful for letting an agent inspect status; it is read-only by design — do not
  treat it as a deploy channel, and still lock down the network in front of it.

## Anti-patterns → STOP

| Rationalization | Reality → STOP |
| --- | --- |
| "I'll install with my sudo user, root feels risky" | The installer wires Docker + system services and the docs say non-root is not fully supported. SSH in as root for install. |
| "I'll register the admin account later" | First account to hit `:8000` owns the instance permanently. A stranger registering first = takeover. Claim it within seconds. |
| "Leave :8000 open, it's password-protected" | That is your full control plane exposed to brute force. Restrict 8000/6001/6002 to your IP; only 80/443 are public. |
| "Pin the app image to `:latest`, it's simpler" | `:latest` floats — a silent base change breaks a redeploy you can't reproduce. Pin a tag or digest. |
| "The database doesn't need a named volume yet" | Recreating the service wipes an anonymous volume. Data gone. Named volume from day one. |
| "Put the DB password in the compose so deploys are reproducible" | Secrets in a committed file leak in git history and image layers. Inject via Coolify env/secrets, env-ref only. |
| "Expose 5432 so I can connect from my laptop" | An open DB port is scanned in minutes. Use the internal hostname; if you truly need external access, firewall it to known IPs. |
| "Backups are configured, we're covered" | A backup you've never restored is a guess. Run the restore drill before you need it. |
| "Coolify will harden the server for me" | Coolify is the control plane, not the OS-hardening layer. Firewall/SSH/patching is the VPS skill (hetzner/digitalocean). |
| "Use Coolify because I just want to git push and forget the server" | That's the opposite of own-the-box. Use a managed PaaS — railway. |

## Verify

Run `scripts/verify.sh` against your project (or this skill's `references/`). It statically lints the
example/your `docker-compose.y*ml`: fails on a hardcoded secret literal (must be env-ref), a DB service
without a named volume, a missing `healthcheck:`, or a floating `:latest` tag on a build-context service;
and confirms the canonical port matrix (8000/80/443/6001/6002) is documented. Read-only, no network, no
live deploy. Exits 0 on a clean/empty target.

## Project grounding (02-DOCS + CLAUDE.md)

When this skill runs in a project with a `02-DOCS/` layer (the harness Karpathy wiki), record this
instance's deploy topology there and index it in `02-DOCS/wiki/index.md`, so the next agent inherits it
instead of re-deriving it.

1. **Find the article** `02-DOCS/wiki/stack/coolify.md`, indexed in `02-DOCS/wiki/index.md` (the Knowledge map index; root `CLAUDE.md` points to it).
2. **If missing or stale**, create/update it with the real choices — the box (provider/specs), instance
   FQDN, which apps/databases run on it, build packs in use, the backup destination + cron + retention,
   and the port/firewall decisions — then index it in `02-DOCS/wiki/index.md` (the Knowledge map; root `CLAUDE.md` keeps only a short pointer to it).
3. **Read it first on every use** and stay consistent; when the topology changes, update the article (bump
   its `Updated` date) in the same change. Never commit credentials here — record *where* secrets live,
   not their values.

No `02-DOCS/` layer? Skip silently. Topology is recorded, not gated — never block the task on this.

