I just moved a pile of sites off a dying control-panel box onto Coolify, and I'm not going back. Coolify is the "self-hosted Heroku" that actually delivers: point it at a git repo or a docker-compose file, and it builds, deploys, wires up a domain and gets you a Let's Encrypt cert without you touching an nginx config. It's Traefik + Docker under a genuinely good dashboard. Here's the setup, and — more usefully — the cheats and gotchas that cost me an evening so they won't cost you one.
TL;DR — install on a fresh Debian/Ubuntu box:
curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash
# dashboard: http://YOUR_IP:8000 (register the first admin immediately)
Details — and the important cheats — below. New to Docker itself? Start at /docker-install-ubuntu/.
The install gotcha that wasted my time first
Half the guides (and older Coolify docs) tell you to curl cdn.coolify.io/v4/install.sh. That URL is dead — it 302-redirects to the marketing homepage and hands you an HTML page, so bash chokes on <!doctype html>. The one that works:
curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash
Note the domain: coollabs.io, not coolify.io. That's it. The installer stands up the whole stack in Docker — the app, a Postgres, Redis, a realtime service, and the Traefik proxy that fronts everything on 80/443. Give the box 2 GB RAM minimum; 4 GB if you'll build images on it.
After it finishes, open http://YOUR_IP:8000 and register the first account right away — that first-run registration is open, so anyone who hits it before you owns your instance. Do it in the first sixty seconds.
The mental model
Coolify has a hierarchy worth learning up front:
- Server — a machine Coolify deploys to (the one it's installed on by default; you can add more over SSH).
- Project → Environment — logical grouping (e.g. project "sites", environment "production").
- Resource — the actual thing: an Application (built from git), a Service (a docker-compose stack), or a Database.
Everything routes through the one Traefik proxy per server. You don't configure Traefik by hand — Coolify writes the labels from the fields you fill in.
Deploying an app from git
The happy path: New Resource → Public/Private Repository → paste the URL. Coolify detects the build (Nixpacks, Dockerfile, or static) and deploys on every push if you add the webhook. Set the domain in the resource's Domains field as a full URL:
https://app.example.com
Save, redeploy, and Traefik requests a Let's Encrypt cert automatically. No certbot, no renewal cron — it's handled. Point the DNS A record at the server first, or the ACME challenge fails and you'll stare at a "certificate pending" that never resolves.
Deploying anything as a docker-compose service
This is the feature I use most. New Resource → Docker Compose, paste a compose file, and Coolify runs it as a managed service — WordPress, a Postgres-backed app, whatever. It injects its own network and proxy labels. To expose a service, Coolify reads a magic env var:
services:
app:
image: my/app:latest
environment:
- SERVICE_FQDN_APP=https://app.example.com
SERVICE_FQDN_<SERVICENAME> tells Coolify which service to route the domain to and on what path. That one convention is the key to the whole compose workflow.
Now the cheats
1. Test with a real domain before you own DNS — sslip.io
Every new resource gets a free sslip.io hostname like app-abc123.YOUR_IP.sslip.io that resolves to your server IP with zero DNS setup. It's perfect for verifying a deploy works before you cut real DNS over. sslip.io is a public wildcard-DNS service — anything.1.2.3.4.sslip.io → 1.2.3.4. Deploy, test on the sslip URL, then swap in the real domain.
2. Turn on the API and script it
Coolify ships a full REST API, but it's off by default. Enable it under Settings → and generate a token. Then everything the dashboard does, you can do from a script:
TOKEN=xxxxx
# list your services
curl -s https://coolify.example.com/api/v1/services \
-H "Authorization: Bearer $TOKEN" | jq '.[].name'
# trigger a deploy by resource uuid
curl -s "https://coolify.example.com/api/v1/deploy?uuid=RESOURCE_UUID" \
-H "Authorization: Bearer $TOKEN"
Creating a compose service via API takes the compose file base64-encoded in a docker_compose_raw field — worth knowing before you fight the payload format.
3. Path-based routing (and the StripPrefix trap)
You can route example.com/blog to one service and example.com/shop to another by putting a path in the domain: https://example.com/shop. Coolify's Traefik matches the longest path first.
The trap: by default Coolify strips the path prefix before passing the request on. That's right for an app that expects to live at /, and wrong for one that already knows it lives at /shop (a WordPress in a subfolder, a Next.js app with a basePath). Symptom: 404s or redirect loops on every sub-page. The fix is to disable "Strip Prefix" for that resource so the app receives the full path it expects. If a sub-path deploy 404s everything below the landing page, this is almost always why.
4. Backups are one toggle — use it
For every database resource, Coolify has scheduled backups built in (cron expression + retention, optional S3 target). Turn it on the day you create the DB, not the day you need it. Pair off-box copies with something like /restic-backup-s3-minio-encrypted/ so a dead host isn't a dead business.
5. Useful shell pokes on the host
Coolify is just Docker underneath, so when something's weird, drop to the host:
docker ps --format '{{.Names}}\t{{.Status}}' # what's actually running
docker logs -f coolify-proxy # Traefik: cert + routing errors live here
docker inspect <container> --format \
'{{range $k,$v := .Config.Labels}}{{$k}}={{$v}}{{println}}{{end}}' | grep traefik # see the generated routing rules
docker exec -it <db-container> psql -U postgres # straight into a managed DB
docker logs coolify-proxy is the first place I look for any "my domain doesn't work" problem — the ACME failure or the routing miss is right there in plain text.
6. Reclaim disk before it bites
Build-heavy instances fill up with old images and layers. Coolify has a cleanup in the UI, but the blunt instrument works too:
docker system df # where the space went
docker image prune -a # drop unused images (careful on multi-app boxes)
docker builder prune # clear the build cache
Gotchas
- The dead installer URL.
cdn.coolify.io/v4/install.shgives you HTML. Usecdn.coollabs.io/coolify/install.sh. It's the single most common "install failed" cause. - Open first-run registration. Register instantly. An exposed
:8000with no admin yet is an open door. - DNS before HTTPS. The A record must point at the box before you set the domain, or the Let's Encrypt challenge can't complete and the cert never issues.
- StripPrefix on sub-paths. Apps with their own base path need Strip Prefix off. Default-on breaks them subtly (works on the landing page, 404s everywhere else).
- Back up the instance secret. The
.envin Coolify's own source dir holds the app key. Save it off-box — restoring the instance without it is pain. - Sentinel wants resources. The metrics agent and build steps eat RAM. A 1 GB VPS will OOM mid-build; give it 2–4 GB.
Is it worth it?
If you're running more than two or three small apps and you're tired of hand-writing reverse-proxy configs and renewing certs, yes — enormously. Coolify gave me git-push deploys, automatic HTTPS and one dashboard over a fleet, on my own hardware, for the cost of a VPS. It's the self-hosting sweet spot between "raw Docker on the CLI" and paying per-seat for someone else's platform. If your workload is specifically game servers, a control panel like /pelican-panel-pterodactyl-successor/ fits that shape better — but for web apps and services, Coolify is the one I reach for now. Watch it with /prometheus-grafana-monitoring-stack-docker/, and if you're spinning the host itself from scratch, /proxmox-cloud-init-vm-template-ubuntu/ makes the base box a two-minute job.