What You'll End Up With
By the end of this guide you'll have Coolify — an open-source, self-hosted PaaS — running on a Hetzner CAX11 ARM VPS (€3.79/month, ~$6 with VAT depending on region). Coolify gives you a Heroku-like dashboard to deploy Git repos, Docker containers, databases (Postgres, MySQL, Redis, MongoDB), and one-click services (Plausible, Umami, Minio, etc.) without paying $25+/month to Railway or Render.
Prerequisites
- A Hetzner Cloud account (sign up at hetzner.com/cloud; new accounts get €20 credit)
- A domain name with an A record you can edit (e.g.,
coolify.yourdomain.com) - SSH key already added to your Hetzner account
- Local machine running macOS or Linux with
sshavailable - Basic comfort at a Linux terminal
Step 1 — Provision the Hetzner CAX11 Instance
The CAX11 is Hetzner's cheapest ARM64 instance: 2 vCPU, 4 GB RAM, 40 GB NVMe. Coolify's minimum is 2 vCPU / 2 GB RAM, so this fits with headroom.
1.1 Log into console.hetzner.cloud, click New Server, and choose:
- Location: Falkenstein or Helsinki (lowest latency to EU; pick Ashburn if US-focused)
- Image: Ubuntu 24.04
- Type: Arm64 → CAX11
- SSH key: select your existing key
- Name:
coolify-prod
Click Create & Buy Now. The server is up in under 30 seconds.
1.2 Note the public IPv4 address shown in the console (e.g., 65.21.x.x).
Step 2 — Point Your Domain at the Server
Coolify needs a wildcard DNS record so every app you deploy gets its own subdomain automatically.
2.1 In your DNS provider, create two records:
Type Name Value
A coolify.yourdomain.com 65.21.x.x
A *.coolify.yourdomain.com 65.21.x.x
Replace 65.21.x.x with your actual server IP. TTL 300 is fine.
2.2 Verify propagation before continuing (saves debugging later):
dig +short coolify.yourdomain.com
Expected output:
65.21.x.x
If you get nothing, wait 2–5 minutes and retry.
Step 3 — Harden the Server Before Installing Anything
Don't skip this. A fresh VPS with a public IP gets probed within minutes.
3.1 SSH in as root:
ssh root@65.21.x.x
3.2 Update all packages:
apt update && apt upgrade -y
3.3 Create a non-root user and grant sudo:
useradd -m -s /bin/bash deploy
usermod -aG sudo deploy
mkdir -p /home/deploy/.ssh
cp /root/.ssh/authorized_keys /home/deploy/.ssh/
chown -R deploy:deploy /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keys
3.4 Disable root SSH login and password auth:
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.5 Install and configure UFW:
apt install -y ufw
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw allow 8000/tcp # Coolify dashboard port
ufw --force enable
3.6 Open a second terminal and verify you can still SSH as deploy before closing the root session:
ssh deploy@65.21.x.x
Step 4 — Install Coolify
Coolify ships an official install script that sets up Docker, the Coolify containers, and a systemd service in one pass.
4.1 SSH in as deploy (or stay in the session from 3.6):
ssh deploy@65.21.x.x
4.2 Run the official installer as root (the script requires it):
curl -fsSL https://cdn.coollabs.io/coolify/install.sh | sudo bash
The script installs Docker CE, pulls the Coolify images, writes /etc/coolify/ configs, and registers the coolify systemd service. On CAX11 this takes 3–5 minutes.
Expected tail of output:
Coolify installed successfully!
You can access it at http://65.21.x.x:8000
4.3 Confirm the service is running:
sudo systemctl status coolify
Expected output (truncated):
● coolify.service - Coolify
Loaded: loaded (/etc/systemd/system/coolify.service; enabled)
Active: active (running) since ...
Step 5 — First-Run Configuration in the Dashboard
5.1 Open http://65.21.x.x:8000 in your browser. You'll see the Coolify registration screen. Create your admin account — use a strong password, this instance is public.
5.2 On the Settings page (top-right gear icon), set:
- App URL:
https://coolify.yourdomain.com - Wildcard Domain:
*.coolify.yourdomain.com
Save settings.
5.3 Navigate to Servers → localhost. Coolify manages its own host by default. Click Validate Server — it should return green.
5.4 Enable automatic SSL. Go to Settings → SSL and toggle Let's Encrypt on. Enter your email address for cert expiry notices. Coolify uses Traefik internally; it will issue and renew certs automatically.
5.5 Restart Coolify to apply the domain change:
sudo systemctl restart coolify
Wait 60 seconds, then visit https://coolify.yourdomain.com. You should see the login page over HTTPS with a valid Let's Encrypt certificate.
Step 6 — Deploy Your First App
This step proves the whole pipeline works end-to-end.
6.1 In the Coolify dashboard, click Projects → New Project. Name it test.
6.2 Click New Resource → Application → Public Repository.
Enter:
https://github.com/coollabsio/coolify-examples
Select the nodejs-fastify example, branch main.
6.3 Under Domains, Coolify auto-assigns a subdomain like nodejs-fastify.coolify.yourdomain.com. Leave it or customize it.
6.4 Click Deploy. Watch the build log in real time. A Node.js app builds and starts in under 2 minutes on CAX11.
6.5 Visit the assigned domain in your browser. You should see:
{"hello":"world"}
SSL is active, subdomain resolves, app responds — the PaaS is working.
Verify It Works
Run these checks after setup to confirm everything is healthy:
Check Coolify service:
sudo systemctl is-active coolify
Expected output:
active
Check Docker containers:
sudo docker ps --format "table {{.Names}}\t{{.Status}}"
You should see coolify, coolify-proxy (Traefik), and coolify-db (SQLite or Postgres) all with Up X minutes status.
Check HTTPS cert:
curl -sI https://coolify.yourdomain.com | grep -i "HTTP/"
Expected output:
HTTP/2 200
Check UFW rules are active:
sudo ufw status verbose
Confirm ports 22, 80, 443, and 8000 are listed as ALLOW.
Troubleshooting
Coolify dashboard shows "502 Bad Gateway"
The Traefik proxy started before Coolify's API was ready. Run sudo systemctl restart coolify and wait 90 seconds.
Let's Encrypt cert fails to issue
DNS hasn't propagated yet, or port 80 is blocked. Verify with dig +short coolify.yourdomain.com and confirm ufw status shows port 80 open.
systemctl status coolify shows "failed"
Docker isn't running. Fix with sudo systemctl start docker, then sudo systemctl start coolify.
Build logs show "exec format error" on ARM
The app's Docker image is x86-only and has no ARM64 layer. Switch to a multi-arch base image (e.g., node:20-alpine supports ARM64) or use Nixpacks build instead of a custom Dockerfile.
UFW blocked port 8000 after reboot
Rules persist across reboots by default on Ubuntu 24.04. If they don't, run sudo ufw enable again and check /etc/ufw/ufw.conf has ENABLED=yes.
Wildcard subdomain doesn't resolve
Some DNS providers require the wildcard record to be *.coolify (relative) not *.coolify.yourdomain.com (absolute). Check your provider's notation.
Next Steps
With Coolify self-hosted PaaS running, here's what to tackle next:
- Add a Postgres database: Dashboard → New Resource → Database → PostgreSQL 16. Coolify provisions it in a container and injects
DATABASE_URLinto your apps automatically. - Set up S3-compatible storage: Deploy Minio as a one-click service under New Resource → Services → Minio. Pair it with your apps for file uploads without paying AWS.
- Enable server backups: Hetzner's snapshot feature costs €0.0119/GB/month. Automate weekly snapshots via the Hetzner API or the console — cheap insurance.
- Add a second server: Coolify supports multi-server deployments. Add a second CAX11 and assign heavier workloads there while keeping the primary for the dashboard and routing.
- Monitor resource usage: Run
htopor install Netdata (sudo docker run -d --name=netdata -p 19999:19999 netdata/netdata) for real-time metrics without a SaaS subscription.
The total running cost for this setup — CAX11 at €3.79/month plus domain (~$12/year) — stays well under $10/month. You get a deployment platform that would cost $50–$150/month on managed alternatives, with full control over your data and no per-seat pricing.