All deployment targets
Self-hosted platform

Deploy to Coolify

Open-source self-hosted PaaS. Similar shape to Dokploy, larger ecosystem.

From
Cost of the VPS (~$5)
Ops effort
Medium
Managed Postgres
Persistent disk
Best for

Self-hosting with a big library of one-click services alongside your app, and multi-server support once one box is not enough.

Not for

Minimal setups: it carries more moving parts than a plain Docker Compose file.

Quick setup

  1. 1

    Install

    Same shape as Dokploy: one script on a clean VPS, then everything else through the panel.

    curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash
  2. 2

    Add the application

    Choose the Dockerfile build pack and set the base directory to the API. Coolify reads the Dockerfile as-is, so the image Grit generates needs no changes.

    Build pack: Dockerfile
    Base directory: /apps/api
    Ports exposed: 8080
  3. 3

    Attach databases and set the health check

    Add Postgres and Redis as resources in the same project, then copy their internal connection strings into the app. Set the health check path to /api/health so a failed boot is caught rather than served.

What catches people out

Internal connection strings use the container name, not localhost. Using localhost is the single most common Coolify support question.

Coolify keeps every build image by default and will fill the disk. Set a cleanup schedule on day one.

Coolify runs the real Compose engine, which is why it needs the fewest edits: depends_on with condition: service_healthy behaves exactly as it does locally, and services still resolve each other by compose service name.

Full walkthrough

Deploying Sentex: VPS + Coolify

The example application below is called sentex and its domains are on gritcms.com. Substitute your own project name and hostnames as you go — every other detail, including the service layout and the Compose translation, applies unchanged to any Grit project.

Coolify also runs your Compose file close to as-is (it literally runs docker compose under the hood), but it manages its own reverse-proxy network and strongly warns against custom Compose networks. You’ll make a small, mechanical edit to docker-compose.prod.yml for this platform — everything else (services, builds, volumes, the migrate job) stays exactly as written.

2.1 Provision the VPS and install Coolify

  1. Spin up a VPS (same sizing guidance as Dokploy). Ubuntu 24.04 or Debian 13 are the best-supported targets.
  2. Point the same three DNS A records at this VPS’s IP (a different VPS than Dokploy’s, obviously, if you’re comparing platforms — don’t point both at the same IP at the same time).
  3. SSH in and run the official installer:
    curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash
  4. Open http://<VPS public IP>:8000, create your admin account, and (recommended) attach a domain + HTTPS to the Coolify dashboard itself under server settings.

2.2 Make a Coolify-specific branch/copy of the Compose file

Create docker-compose.coolify.yml (or a coolify branch — whatever fits your workflow) with two changes from docker-compose.prod.yml:

  1. Remove the networks: block at every service, and delete the top-level networks: section entirely (both the sentex bridge and the dokploy-network: external: true reference). Coolify creates its own isolated bridge network per Compose stack and attaches its own Traefik to it automatically — defining custom networks alongside that causes exactly the kind of intermittent 504/unreachable behavior Coolify’s docs specifically warn about, because your containers would sit on two networks at once and Traefik might pick the wrong one.
  2. Remove the labels: blocks (the traefik.* labels) from api, admin, and web. You’ll set domains through Coolify’s UI instead in Part 2.4 — its proxy is still Traefik, but its label names/entrypoint names don’t necessarily match Dokploy’s, so hand-rolled labels are more likely to conflict with what Coolify generates than to help.

Everything else — build:, image:, environment:, env_file:, volumes:, depends_on:, healthcheck:, command:, restart: — stays identical. In particular, leave the migrate service and its depends_on: condition: service_completed_successfully exactly as-is — Coolify runs real Docker Compose, so this ordering guarantee works without any translation, the same as on Dokploy.

Optionally, mark migrate as excluded from Coolify’s aggregate healthchecks, since it’s meant to exit rather than stay running:

services:
migrate:
exclude_from_hc: true
# ...rest unchanged

2.3 Create the resource in Coolify

  1. In the Coolify dashboard, create a Project, then a new Resource inside it.
  2. Choose your Git source (Public Repository, or GitHub App / Deploy Key for a private repo — set up whichever you haven’t already under Sources).
  3. Select the sentex repository and branch.
  4. When prompted for a Build Pack, change it from the Nixpacks default to Docker Compose.
  5. Set:
    • Base Directory: / (repo root)
    • Docker Compose Location: docker-compose.coolify.yml (the file from Part 2.2 — match the exact filename/extension you used)
  6. Click Continue.

2.4 Domains

Coolify reads your Compose file’s services and lets you assign a domain to each one directly — no labels needed since you removed them in Part 2.2.

  1. On the resource’s configuration screen, find the domain field for each service and set:
    • apihttps://api.sentex.gritcms.com:8080 (append :8080 because that’s the container port api listens on — Coolify’s proxy still serves the public side on the normal HTTPS port; the :8080 just tells it where to send traffic internally)
    • adminhttps://admin.sentex.gritcms.com:3000
    • webhttps://sentex.gritcms.com:3000
  2. Leave postgres and redis with no domain assigned — without a domain or a ports: mapping, Coolify keeps a service private and reachable only over the internal network at http://postgres:5432 / http://redis:6379-style hostnames (i.e., exactly the plain service-name DNS your Compose file’s POSTGRES_HOST=postgres / REDIS_URL values already assume).

2.5 Environment variables

  1. Coolify auto-detects every ${VARIABLE} referenced in your Compose file (in environment:, env_file:-driven values you reference, and build.args) and lists them in the resource’s Environment Variables tab.
  2. Fill in the same values you’d put in .env.production: POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB, WEB_DOMAIN, ADMIN_DOMAIN, API_DOMAIN, THEME, SOCIAL_AUTH_ENABLED, NEXT_PUBLIC_DEMO_LOGINS, the R2_* credentials, and any app secrets.
  3. Coolify injects these both as build args (for admin/web’s NEXT_PUBLIC_* values) and as runtime environment — matching how the Compose file already declares them.

2.6 Deploy and verify

  1. Click Deploy. Watch the build/deploy log stream in the UI.
  2. Confirm migrate runs and exits cleanly before api, admin, and web start (same ordering as Dokploy — real Compose semantics).
  3. Give Coolify’s Traefik a short moment to issue Let’s Encrypt certs for the three domains, then visit each in a browser and confirm no CORS errors and that the seeded demo login works.
  4. Under the resource’s Webhooks/Source settings, confirm auto-deploy on push is enabled if you want GitHub pushes to redeploy automatically.

Platform dashboards and CLI flags change faster than these docs. For anything that looks different from what is written here, Coolify's own documentation is the authority: coolify.io/docs/