How to Run Coolify on Hetzner for $6/Month

by David Park
How to Run Coolify on Hetzner for $6/Month

Coolify is an open-source self-hosted PaaS that replaces Heroku, Render, and Railway — without the per-seat pricing. By the end of this guide you'll have Coolify running on a Hetzner CAX11 ARM VPS (€3.79/month, ~$6 billed monthly), serving apps over HTTPS with automatic Let's Encrypt certificates, a managed PostgreSQL instance, and webhook-triggered Git deploys. You'll spend under 30 minutes and own the entire stack.

Prerequisites

  • A Hetzner Cloud account (sign up at hetzner.com/cloud; new accounts get €20 credit)
  • A domain name with DNS you can edit (Cloudflare, Porkbun, or any registrar)
  • SSH key already added to your Hetzner project
  • Local machine running macOS or Linux with ssh and curl available
  • Basic comfort with a terminal and systemd

1. Provision the Hetzner CAX11 Server

Log in to the Hetzner Cloud Console at console.hetzner.cloud. Create a new project, then click Add Server with these settings:

  • Location: Falkenstein (EU) or Ashburn (US) — pick the region closest to your users
  • Image: Ubuntu 24.04
  • Type: CAX11 (2 vCPU ARM64, 4 GB RAM, 40 GB NVMe)
  • SSH keys: select your existing key
  • Firewall: none for now (Coolify manages its own rules)
  • Name: coolify-01

Note the public IPv4 address once the server is running. It appears on the server detail page within 30 seconds.


2. Point Your Domain at the Server

Before touching the server, create two DNS A records so Let's Encrypt can issue certificates by the time you need them. Replace 203.0.113.10 with your actual server IP.

Hostname Type Value
coolify.example.com A 203.0.113.10
*.coolify.example.com A 203.0.113.10

The wildcard record lets Coolify provision subdomains for each app you deploy (e.g., myapp.coolify.example.com) without additional DNS changes.

DNS propagation typically takes 2–5 minutes on Cloudflare and up to 30 minutes on other providers. Continue with the server setup while it propagates.


3. Harden the Server Before Installing Anything

SSH in as root:

ssh root@203.0.113.10

3.1 Update all packages:

apt update && apt upgrade -y

3.2 Create a non-root user with sudo access:

useradd -m -s /bin/bash -G sudo deploy
cp -r /root/.ssh /home/deploy/.ssh
chown -R deploy:deploy /home/deploy/.ssh

3.3 Disable root SSH login and password authentication:

sed -i 's/^PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
sed -i 's/^#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
systemctl restart ssh

3.4 Open only the ports Coolify needs:

ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw allow 8000/tcp
ufw --force enable

Port 8000 is the Coolify dashboard during initial setup; you can restrict it after configuration.

Log out and reconnect as the deploy user to confirm key auth works:

ssh deploy@203.0.113.10

4. Install Docker Engine (Required by Coolify)

Coolify orchestrates everything through Docker. Install the official Docker Engine — not the docker.io package from Ubuntu's repos, which lags behind.

4.1 Add Docker's GPG key and repository:

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker.gpg
echo "deb [arch=arm64 signed-by=/usr/share/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu noble stable" | sudo tee /etc/apt/sources.list.d/docker.list

4.2 Install Docker Engine and the Compose plugin:

sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

4.3 Add deploy to the docker group so it can run containers without sudo:

sudo usermod -aG docker deploy
newgrp docker

4.4 Verify Docker is running:

docker version

Expected output (versions will differ, ARM64 matters):

Client: Docker Engine - Community
 Version:           26.1.4
 ...
Server: Docker Engine - Community
 Engine:
  Version:          26.1.4
  ...
  Architecture:     aarch64

5. Install Coolify

Coolify ships an official install script that pulls the latest stable release, writes a systemd service, and starts the stack.

5.1 Run the installer as the deploy user:

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

The script takes 2–4 minutes on CAX11. It pulls several Docker images (Coolify itself, Traefik, Soketi, PostgreSQL, Redis) and writes the compose file to /data/coolify/.

Expected final lines:

Coolify installed successfully!
You can access it at http://203.0.113.10:8000

5.2 Confirm the Coolify service is active:

sudo systemctl status coolify

Expected output:

● coolify.service - Coolify
     Loaded: loaded (/etc/systemd/system/coolify.service; enabled; ...)
     Active: active (running) since ...

6. Complete Initial Setup in the Dashboard

6.1 Open http://203.0.113.10:8000 in your browser. You'll see the Coolify registration screen. Create your admin account — use a strong password; this is the only gate to your entire PaaS.

6.2 On the Server screen, Coolify auto-detects localhost (the same VPS). Click Validate Server — it SSHes back into itself via the Docker socket. You should see a green Reachable badge.

6.3 Navigate to Settings → Instance → Domain and enter your Coolify subdomain:

https://coolify.example.com

Save. Coolify instructs Traefik to request a Let's Encrypt certificate for that domain. Within 60 seconds the dashboard becomes available at https://coolify.example.com. The port-8000 URL stays active as a fallback.

6.4 Once HTTPS is confirmed working, close port 8000:

sudo ufw delete allow 8000/tcp

7. Deploy Your First App and Database

This step proves the entire pipeline works end-to-end.

7.1 In the Coolify dashboard, click Projects → New Project, name it demo.

7.2 Click Add Resource → Public Repository. Paste in a simple Node.js or static site repo — Coolify supports any repo with a Dockerfile or a Nixpacks-compatible project (Next.js, Laravel, Django, etc.).

For a quick smoke test, use the official Coolify demo:

https://github.com/coollabsio/coolify-examples

Select the nodejs-fastify subdirectory.

7.3 Set the domain to demo.coolify.example.com. Coolify creates a Traefik router and requests a certificate automatically.

7.4 Click Deploy. The build log streams in real time. A successful deploy ends with:

Container started.
Health check passed.

7.5 Add a managed PostgreSQL database: click Add Resource → Database → PostgreSQL 16. Set a strong password, leave the port internal (not exposed to the internet), and click Start. Copy the internal connection string — it's available under the database's Connection tab and works from any container in the same Coolify project.


Verify It Works

Run each check from your local machine:

Check 1 — Dashboard HTTPS:

curl -I https://coolify.example.com

Expected:

HTTP/2 200
server: Caddy  (or traefik)

Check 2 — App is reachable:

curl -I https://demo.coolify.example.com

Expected: HTTP/2 200

Check 3 — Docker containers on the server:

ssh deploy@203.0.113.10 "docker ps --format 'table {{.Names}}\t{{.Status}}'"

Expected output includes coolify, coolify-proxy (Traefik), coolify-db, coolify-redis, and your app container.

Check 4 — Coolify service survives a reboot:

ssh deploy@203.0.113.10 "sudo reboot"
# wait 30 seconds
curl -I https://coolify.example.com

Expected: HTTP/2 200 after the server comes back up.


Troubleshooting

Dashboard not reachable on port 8000 after install Confirm UFW allows the port: sudo ufw status. If 8000/tcp is missing, re-run sudo ufw allow 8000/tcp && sudo ufw reload. Also check sudo systemctl status coolify for startup errors.

Let's Encrypt certificate not issuing Verify DNS has propagated: dig +short coolify.example.com should return your server IP. Traefik logs show ACME errors: docker logs coolify-proxy 2>&1 | grep -i acme.

Docker group permissions not applying If docker ps returns a permission error after newgrp docker, log out completely and SSH back in. Group membership changes require a new login session.

Coolify shows server as unreachable The installer creates an SSH key at /data/coolify/ssh/keys/id.root@host.docker.internal. Confirm it exists: sudo ls -la /data/coolify/ssh/keys/. If missing, re-run the installer.

ARM64 image not found for your app Some Docker Hub images are x86-only. Check the image's tags for linux/arm64. If unavailable, add a Dockerfile that builds from source rather than pulling a pre-built binary.

App container keeps restarting Stream logs from Coolify's UI under the deployment's Logs tab, or on the server: docker logs <container-name> --tail 50. 99% of restart loops are a misconfigured environment variable or a missing PORT binding.


Next Steps

  • Add a Hetzner Volume for persistent database storage: create a 20 GB volume in the console, attach it to coolify-01, mount it at /data/coolify/databases, and update the Coolify compose override at /data/coolify/source/docker-compose.yml to bind-mount that path.
  • Set up S3-compatible backups using Hetzner Object Storage (€0.023/GB) — Coolify has a built-in backup scheduler under Settings → Backups.
  • Enable webhook deploys from GitHub or Gitea: each Coolify resource exposes a webhook URL you paste into your repo's settings. Push to main, get a deploy.
  • Add team members under Settings → Teams — Coolify's free tier supports unlimited users on a self-hosted instance.

You now have a production-grade PaaS running on $6/month of Hetzner infrastructure — SSL, databases, Git deploys, and a web UI included. Every dollar you'd have paid Render or Railway stays in your pocket.