> ## Content Index
> Fetch the complete content index at: https://blog.sudowl.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Coolify — Self-Hosted PaaS, and the Cheats I Wish I'd Known
- URL: https://blog.sudowl.com/coolify-self-hosted-paas/
- Published: 2026-07-01T16:00:00.000Z
- Updated: 2026-10-11T10:16:27.000Z
- Description: Run Coolify as your own Heroku — install, deploy apps and docker-compose services, automatic HTTPS, plus the API, sslip testing and path-routing cheats.
- Author: Lukas
- Tags: Docker, Linux

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:**

```bash
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/](https://blog.sudowl.com/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:

```bash
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:

```yaml
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:

```bash
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/](https://blog.sudowl.com/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:

```bash
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:

```bash
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.sh` gives you HTML. Use `cdn.coollabs.io/coolify/install.sh`. It's the single most common "install failed" cause.
- **Open first-run registration.** Register instantly. An exposed `:8000` with 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 `.env` in 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/](https://blog.sudowl.com/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/](https://blog.sudowl.com/prometheus-grafana-monitoring-stack-docker/), and if you're spinning the host itself from scratch, [/proxmox-cloud-init-vm-template-ubuntu/](https://blog.sudowl.com/proxmox-cloud-init-vm-template-ubuntu/) makes the base box a two-minute job.

---

### Related posts

- [A Prometheus + Grafana Monitoring Stack in Docker](https://blog.diengdoh.com/prometheus-grafana-monitoring-stack-docker/?ref=blog.sudowl.com)
- [Self-Hosted Uptime Monitoring with Uptime Kuma](https://blog.diengdoh.com/uptime-kuma-self-hosted-monitoring/?ref=blog.sudowl.com)
- [Apache as a Reverse Proxy for Docker Apps (and the Panel Trap)](https://blog.diengdoh.com/apache-reverse-proxy-docker-apps/?ref=blog.sudowl.com)