Coolify on Hostinger VPS: Self-Hosted Deploy Guide
What Coolify Actually Is
Coolify is an open-source, self-hostable platform-as-a-service. You install it on a server you control, point it at a Git repository, and it handles the rest: building your code into a Docker container, running that container, routing traffic to it through a reverse proxy, issuing and renewing TLS certificates, and redeploying automatically whenever you push a commit.
That description matches what Vercel, Netlify, Render, and Heroku do. The difference is architectural rather than functional. Those platforms run your code on infrastructure they own and meter your consumption of it. Coolify runs your code on infrastructure you rent directly, and meters nothing, because there is no billing relationship between you and the software. The project is Apache 2.0 licensed and free forever in the self-hosted configuration. Your only cost is the server.
The project describes itself as a self-hostable alternative to Vercel, Heroku, and Netlify that deploys static sites, databases, full-stack applications, and 280+ one-click services onto your own servers. The community framing has shifted over time. In 2023 and 2024 the shorthand was "Heroku alternative." By 2026, in high-engagement developer threads, the phrase you see more often is "self-hosted Vercel." That shift tracks where the pricing pain moved.
Coolify reached v4.0.0 stable on April 27, 2026, after an unusually long beta. The maintainer, Andras Bacsai, was direct about it in the release notes: the release was overdue because the project had been in beta for a long time, thousands of companies and individuals had been running it in production for one to two years, and it still has plenty of bugs that get fixed daily. That candor is worth noting up front. This is not a polished commercial product with an SLA. It is a very actively maintained open-source project with a large user base.
As of this writing, the current tagged stable release is v4.1.2, shipped June 4, 2026. The repository sits near 59,000 GitHub stars with 575+ contributors, making it the most-starred self-hosted PaaS on GitHub.
Worth knowing before you start: v4.2 was merged into the release branch on July 19, 2026 but has not yet been tagged as a public release. It carries breaking changes that affect API clients, deploy webhooks, and team permissions. I flag the specifics at the relevant points below so what you build today does not break when you upgrade.
Why the Cost Conversation Changed in 2026
The economic case for self-hosting used to be marginal. A $20/month Vercel Pro seat versus a $10/month VPS plus your own time was not an obvious win. Two things changed that calculation.
The first is that per-seat pricing scales with team size rather than with resource consumption. Vercel Pro remains $20 per developer seat per month in 2026. A ten-developer team pays $200/month in seats before serving a single request. Netlify moved the opposite direction — its Pro tier went to a flat $20/month with unlimited members — but replaced the old bandwidth-and-build-minutes model with a credit system that consumes from a single pool for deploys, bandwidth, and compute simultaneously.
The second and larger change is metered egress. Vercel Pro includes 1TB of fast data transfer and 10 million edge requests, with a $20 usage credit per seat. Past that, bandwidth bills at $0.15/GB and edge requests at $2 per million. Fast Origin Transfer, the data moving from your function to the edge, is a separate meter at $0.06/GB charged from the first byte.
The failure mode here is well documented and it is not theoretical. Reported incidents include a $23,000 bill following a DDoS attack, a $3,200 invoice sent to a college student for attack traffic, and a $1,477 bill of which roughly $1,267 was bandwidth overage after a crawler pulled 8.4TB of media files. Vercel bills all served bandwidth at the standard rate including DDoS and bot traffic, and there are documented cases of a $20/month Pro account jumping to $700 and then $1,100 during traffic spikes.
Netlify's credit model has its own edges. The bandwidth credit rate doubled on April 14, 2026, to 20 credits per GB. On the free tier, the 300-credit monthly pool works out to roughly 15GB of bandwidth. On Pro, 3,000 credits is approximately 150GB, with overages auto-recharging at $10 per 1,500 credits — around $0.13/GB. A site serving 500GB/month on Pro burns through the included credits and needs roughly 4.7 additional packs, landing near $67/month for bandwidth alone.
Set against that, a Hostinger KVM 2 VPS includes 8TB of monthly bandwidth for a flat single-digit monthly rate. The unit economics are not comparable. They are different orders of magnitude, and that gap is the entire argument for Coolify.
What Self-Hosting Actually Costs
Numbers only mean something with the assumptions stated, so here are mine: a small team running a production web application, a staging environment, a Postgres database, and a handful of internal tools.
On Vercel Pro, three developer seats is $60/month baseline. Add 1.5TB of bandwidth and you are at roughly $135/month with the seat credits applied. Build minutes matter too — Turbo machines became the default for new Pro projects in February 2026 at $0.105/min, roughly 7.5x the Standard rate of $0.014/min. Preview deployments consume the same pool as production. A team running 20 PRs/day with 5-minute Turbo builds can generate several hundred dollars per month in build charges alone; switching previews to Standard machines cuts that dramatically. Add managed Postgres from a third party and you are comfortably in the $200-300/month range.
On Coolify with a Hostinger VPS, the same workload runs on one KVM 4 instance: $12.99/month promotional, $28.99/month at renewal. Postgres runs as a container on the same box. Staging is another application in the same Coolify instance. Bandwidth is included up to 16TB. Total: under $30/month even after the promotional period ends.
The honest accounting has to include what you are buying with that difference, because it is not free money.
What you give up: global edge distribution — your app runs in one datacenter unless you deliberately front it with a CDN, which Cloudflare's free tier handles well. Automatic scaling — a VPS has fixed resources and you scale by resizing or adding servers. Managed database operations — backups, upgrades, and failover become yours. Someone else's on-call rotation. Compliance posture: Coolify is not a fit for SOC 2 or HIPAA workloads without substantial additional work, and the project has a CVE on record (CVE-2026-31431), which is normal for software of this scope but means patching is your job.
What you gain: predictable billing that does not respond to traffic spikes, no per-seat cost as the team grows, root access to everything, no vendor lock-in because your configuration lives on your own server, and the ability to run anything Docker can run rather than only what the platform supports.
The break-even point commonly cited is around $20/month of platform spend. Below that, managed platforms are probably worth the convenience. Above it, particularly if bandwidth or seats are what is driving your bill, the math tilts hard.
Prerequisites and Server Sizing
Coolify's official minimum is 2 CPU cores, 2GB RAM, and 30GB of free storage. Treat that as a floor for experimentation, not a production target. Coolify itself consumes roughly 1GB of RAM before you deploy anything, and builds are memory-hungry — running builds and the Coolify control plane on the same underpowered box is the most common way to make a server unresponsive.
For reference, the maintainer runs his own production applications on a server with 8GB RAM (averaging 3.5GB used), 4 CPU cores (20-30% average utilization), and 150GB of storage (40GB used). That setup comfortably handles three Node.js apps, four static sites, Plausible Analytics, Fider, Uptime Kuma, Ghost, three Redis databases, and two PostgreSQL databases.
Mapping that onto Hostinger's KVM lineup:
Hostinger's current KVM lineup, as listed on their VPS page at the time of writing:
Plan | vCPU | RAM | NVMe | Bandwidth | Promo | Renews at |
|---|---|---|---|---|---|---|
KVM 1 | 1 | 4 GB | 50 GB | 4 TB | $6.49/mo | $11.99/mo |
KVM 2 | 2 | 8 GB | 100 GB | 8 TB | $8.79/mo | $14.99/mo |
KVM 4 | 4 | 16 GB | 200 GB | 16 TB | $12.99/mo | $28.99/mo |
KVM 8 | 8 | 32 GB | 400 GB | 32 TB | $25.99/mo | $49.99/mo |
KVM 1 is adequate for learning Coolify or running a few small static sites. The single vCPU becomes a bottleneck during builds — expect slow deploys.
KVM 2 is the sensible starting point for production. Two vCPUs remove the single-core build bottleneck, and 8GB handles your app, a database, Redis, and OS overhead with headroom.
KVM 4 is right if you are consolidating several projects or running memory-heavy builds like large Next.js applications.
KVM 8 is multi-project agency territory.
Three things about that pricing table matter more than the headline numbers. First, all plans are paid upfront — the monthly figure is the total divided by the term length, not a monthly billing option. Second, the renewal rates are the real long-term cost, and they roughly double: KVM 4 goes from $12.99 to $28.99. Budget against the renewal column, not the promo column. Third, these are promotional rates tied to a specific sale and they change frequently, so verify current pricing at checkout rather than trusting any article, including this one.
Even at renewal pricing, the comparison holds. KVM 2 at $14.99/month with 8TB of bandwidth is still dramatically cheaper than a three-seat Vercel Pro plan before a single gigabyte of overage.
You will also need a domain with DNS you can edit, a GitHub account with the repository you want to deploy, and an SSH client.
Two Paths: Template or Manual Install
Hostinger offers an "Ubuntu 24.04 with Coolify" VPS template that ships Coolify preinstalled. It is genuinely convenient, and Hostinger markets a dedicated Coolify VPS product around it, including an AI agent for server management tasks.
There is one detail worth knowing before you choose: Hostinger's template serves the Coolify dashboard on port 3000, not the standard port 8000 that a manual install uses. Hostinger's own documentation instructs you to browse to http://your-vps-ip:3000. Nearly every Coolify guide, including the official docs, references port 8000. If you use the template and then follow a tutorial that says 8000, you will get a connection timeout and conclude the install is broken when it is fine.
I am going to walk through the manual install for the rest of this guide. It takes about ten extra minutes, produces a standard configuration that matches the official documentation exactly, and — more importantly — teaches you what the pieces are. When something breaks at 2am, that knowledge is the difference between a five-minute fix and a lost evening. If you prefer the template, skip to the DNS and dashboard sections and substitute port 3000 wherever you see 8000.
Step 1: Provision the VPS
From the Hostinger control panel:
Select VPS and choose your plan (KVM 2 or higher recommended).
Choose a datacenter location close to your users. Latency to your primary audience matters more than proximity to you.
For the operating system, select Ubuntu 24.04 LTS, plain — not the Coolify template, since we are installing manually.
Set a root password or, preferably, upload an SSH public key. Key authentication is more secure and we will disable password login shortly.
Complete provisioning and note the assigned IPv4 address.
Coolify's automatic installation script supports Ubuntu LTS versions only — 20.04, 22.04, and 24.04. Non-LTS versions such as 24.10 require the manual installation path documented separately. Debian, RHEL-family distributions (CentOS, Fedora, AlmaLinux, Rocky), SUSE-family, Arch, Alpine, and 64-bit Raspberry Pi OS are also supported.
Use a fresh server. Coolify's installer configures Docker, writes to /data/coolify, and manages SSH keys. Installing it alongside an existing application stack invites conflicts.
Step 2: Point DNS at the Server
Do this before installing, because DNS propagation takes time and Let's Encrypt certificate issuance depends on it.
In your DNS provider's panel, create two records:
Type | Name | Value | TTL |
|---|---|---|---|
A |
| your.vps.ip.address | 300 |
A |
| your.vps.ip.address | 300 |
The first gives you coolify.yourdomain.com for the dashboard. The second is a wildcard so you can assign subdomains to deployed applications without editing DNS for each one.
An important distinction about that wildcard. Wildcard DNS and wildcard TLS certificates are two different things, and conflating them is the single most common source of "why is my SSL broken" on Coolify. The *.apps A record means any subdomain resolves to your server — that part works on any DNS provider, free tier included. But Let's Encrypt will not issue a wildcard certificate through the HTTP-01 challenge that Coolify uses by default. Wildcard certificates require the DNS-01 challenge, which means Traefik needs API credentials for your DNS provider so it can create TXT records to prove domain control.
In practice this is fine, because you do not usually need a wildcard certificate. With the wildcard A record in place, you assign a specific domain like app.apps.yourdomain.com to each application, and Coolify requests an ordinary single-domain certificate for it via HTTP-01. That works out of the box. You only need to configure DNS-01 if you are serving genuinely dynamic subdomains — per-tenant URLs, per-PR preview domains you do not want to enumerate — and Coolify documents that setup under Traefik's DNS challenge configuration.
If you are proxying through Cloudflare, set both records to DNS only (grey cloud) initially. Cloudflare's proxy intercepts the HTTP-01 validation request and the certificate never issues. Turn the proxy on after certificates are working, and if you do, set Cloudflare's SSL mode to Full (Strict) — anything less either breaks or gives you encryption theatre. Note also that Cloudflare's free plan supports wildcard DNS but not wildcard certificates through their proxy, which is another reason to prefer per-app certificates.
Verify propagation before continuing:
bash
dig +short coolify.yourdomain.comThe output should be your server's IP. If it is empty or wrong, wait and retry — a low TTL of 300 keeps this to minutes rather than hours.
Step 3: Initial Server Hardening
SSH in as root:
bash
ssh root@your.vps.ip.addressUpdate the system first:
bash
apt update && apt upgrade -ySet a recognizable hostname:
bash
hostnamectl set-hostname coolify-prodCoolify's installer handles most tooling, but on minimal images curl may not be present:
bash
apt install -y curl wget git jq opensslNow harden SSH. Open the configuration:
bash
nano /etc/ssh/sshd_configSet these values, uncommenting the lines if needed:
PermitRootLogin prohibit-password
PasswordAuthentication no
PubkeyAuthentication yesBefore you restart SSH, confirm your public key is installed and working. Open a second terminal and verify you can log in with your key. Locking yourself out of a fresh VPS is recoverable through the provider console, but it is an unnecessary detour.
bash
systemctl restart sshA note on root: Coolify requires root or sudo access, and non-root users are not fully supported for the installation itself. Setting PermitRootLogin prohibit-password allows key-based root login while blocking password attempts, which is the configuration Coolify's installer expects.
Enable a swap file if your plan is memory-constrained. Builds spike memory usage, and swap prevents the OOM killer from terminating your containers:
bash
fallocate -l 2G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstabConfirm it took:
bash
free -hStep 4: Configure the Firewall
Coolify needs specific ports open. Configure UFW before installing, allowing SSH first so you do not sever your own connection:
bash
ufw default deny incoming
ufw default allow outgoing
ufw allow OpenSSH
ufw allow 80/tcp comment 'HTTP - Lets Encrypt and redirects'
ufw allow 443/tcp comment 'HTTPS - application traffic'
ufw allow 8000/tcp comment 'Coolify dashboard'
ufw allow 6001/tcp comment 'Coolify realtime websocket'
ufw allow 6002/tcp comment 'Coolify terminal proxy'
ufw enableWhat each port does: 8000 serves the Coolify dashboard. 6001 carries realtime websocket updates — live deployment logs and UI state. 6002 is the browser terminal proxy. 80 and 443 are for Traefik, which fronts your deployed applications and handles ACME certificate validation.
Verify:
bash
ufw status verboseAn important caveat about UFW and Docker. Coolify's documentation is explicit on this point: Docker uses NAT-based iptables rules that can bypass traditional Linux firewalls, so blocking ports with UFW alone is not reliably effective for containers Docker has published. The official recommendation is to use your provider's firewall — Hostinger includes one in the VPS control panel — rather than relying solely on UFW. Configure the same rule set there. For a UFW-only setup, the community-maintained ufw-docker tool bridges the gap; consult its repository for setup.
Once you have the dashboard reachable on your custom domain over HTTPS, ports 8000, 6001, and 6002 can be closed to the public internet. Coolify's documentation confirms this is safe when you access the dashboard through the reverse proxy. We will do that in Step 9.
Step 5: Install Coolify
One command:
bash
curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bashIf you are not root, prefix with sudo:
bash
curl -fsSL https://cdn.coollabs.io/coolify/install.sh | sudo bashInstallation takes two to five minutes. Here is what the script actually does, so the output is not a black box:
Installs essential tooling: curl, wget, git, jq, openssl
Installs Docker Engine version 24 or later, configuring logging and daemon settings
Creates the directory tree under
/data/coolify— subdirectories for source, ssh, applications, databases, backups, services, proxy, and webhooksGenerates an ed25519 SSH keypair Coolify uses to manage the server, and adds the public key to
authorized_keysDownloads
docker-compose.yml,docker-compose.prod.yml, and.env.productionfrom the Coolify CDNGenerates cryptographic secrets —
APP_ID,APP_KEY, database and Redis passwords, and Pusher credentialsCreates an attachable Docker network named
coolifyStarts the container stack
Docker installed via snap is not supported. If your image has snap Docker, remove it before running the installer. On some distributions — AlmaLinux is the documented example — Docker must be preinstalled; if the script fails there, install Docker manually and rerun.
To pin a specific version rather than taking latest:
bash
curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash -s v4.1.2When the script finishes it prints your dashboard URL, typically http://your.vps.ip:8000.
Verify the stack is healthy:
bash
docker psYou should see containers for coolify, coolify-db (Postgres), coolify-redis, and coolify-realtime.
Step 6: Create Your Admin Account Immediately
Open http://your.vps.ip:8000 in a browser right away.
This is time-sensitive and it is the single most important security step in this guide. Coolify's registration page is open until the first account is created. Anyone who reaches that URL before you do gains full administrative control of your server. The official documentation flags this in a caution block for good reason. Do not install Coolify and then walk away to make coffee.
Create your account. Password requirements: minimum 8 characters, mixed case, at least one number, at least one special character, and not a commonly compromised password.
Once you are in, immediately lock down registration. Go to Settings → Configuration and confirm self-registration is disabled. Coolify v4 added a two-step confirmation before self-registration can be enabled, specifically to prevent accidental exposure.
Enable two-factor authentication under your user settings while you are here.
Step 7: Attach Your Coolify Instance Domain
Serving the dashboard over plain HTTP on an IP address is fine for the first ten minutes and unacceptable after that.
Navigate to Settings → Configuration and set the Instance Domain to https://coolify.yourdomain.com. Save.
Coolify configures Traefik to route that hostname to the dashboard and requests a Let's Encrypt certificate automatically. Give it thirty seconds, then load https://coolify.yourdomain.com. You should get a valid certificate and the dashboard.
If the certificate does not issue, the cause is almost always one of three things: DNS has not propagated (recheck with dig), port 80 is blocked so the ACME HTTP-01 challenge cannot complete, or Cloudflare's orange-cloud proxy is intercepting validation. Fix the cause and Coolify retries automatically.
Setting the instance domain matters beyond aesthetics. The GitHub App integration in the next section registers a webhook endpoint with GitHub, and that endpoint is derived from your instance domain. If you leave it as a bare IP and later add a domain, you will need to reconfigure the webhook URLs in GitHub. Set the domain first.
Step 8: Connect GitHub via a GitHub App
Coolify supports three GitHub authentication methods, and choosing correctly on day one saves real pain.
Public repository requires no authentication but supports no automatic deployment from push.
Deploy key uses an SSH key for private repository access. Simpler to set up, but it gives you no pull request preview deployments and no commit status reporting back to GitHub.
GitHub App is the right answer for essentially everyone. It provides scoped per-repository access, automatic webhook configuration, pull request preview deployments, and commit status posting. Coolify's documentation makes the case plainly: the GitHub App lets you grant access to a specific repository, a selected group, or all of them, giving you meaningful control over Coolify's reach.
Coolify v4.1.2 specifically improved the GitHub App setup flow, and v4.1.1 fixed several bugs in the installation and reinstall path. If you have read older guides describing this process as finicky, that criticism is somewhat dated.
The automated GitHub App path
In the Coolify sidebar, click Sources.
Click + Add.
Enter a name for the app — "Production Deploy" or similar.
If you are installing to a GitHub organization, enter the organization name. For a personal account, leave this field empty. This trips people up.
The System wide checkbox makes this source available to all teams on your instance. Leave it unchecked if you want it scoped to the current team only.
Click Continue.
Next, the webhook endpoint:
Select the endpoint GitHub will call when push and pull request events fire. This must be publicly reachable. If you intend to close port 8000, set this to your Coolify dashboard domain —
https://coolify.yourdomain.com— not the IP-and-port form. Getting this wrong is the most common cause of "auto-deploy silently does nothing."Preview deployments are enabled by default. Disable if you do not want them.
Click Register now. This redirects you to GitHub.
On GitHub:
Name the app. This is the display name in your GitHub app list and is editable later.
Click Create app. GitHub redirects you back to Coolify.
Back in Coolify, click Install repositories on Github.
Select which repositories the app may access — all, or a specific subset. Scope this narrowly; there is no reason to grant access to repositories you will not deploy.
Click Install.
You are returned to Coolify with a working source.
If you need the manual path
Organizations with policies preventing the automated flow, or self-hosted GitHub Enterprise instances, need manual configuration. You will collect an App ID, Installation ID, Client ID, Client Secret, Webhook Secret, and a private key .pem file, then enter them into Coolify.
The two URLs you configure on GitHub's side, substituting your instance domain and the Source ID that appears in Coolify's URL bar after /github/:
Setup URL:
https://coolify.yourdomain.com/webhooks/source/github/install?source=YOUR_SOURCE_ID— with Redirect on Update enabledWebhook URL:
https://coolify.yourdomain.com/webhooks/source/github/events
Required permissions: Contents read-only, Email addresses read-only, and Pull Requests read and write if you want preview deployments. Under Subscribe to events, enable Push, plus Pull requests for previews. Select Only on this account so others cannot install your app.
Generate a private key — GitHub downloads a .pem file — then in Coolify go to Keys & Tokens → Private keys → + Add and paste its contents. Return to Sources, select your app, fill in the collected IDs, select the private key, and click Sync Name. A success message confirms the configuration is correct.
Step 9: Deploy Your First Application
With a source connected, deploying is short.
From the dashboard, create or select a Project.
Click + New.
Choose Private Repository (with GitHub App).
Select your server. If
localhostis your only server, Coolify selects it automatically.Choose the GitHub App you configured.
Select the repository and click Load Repository.
Choose your branch — typically
main.
Choosing a build pack
Coolify builds every application into a Docker container. The build pack determines how that image gets created.
Nixpacks analyzes your codebase and generates a Dockerfile automatically. It handles Node, Python, Go, Ruby, PHP, Rust, and more without configuration. Best default for getting something running quickly.
Railpack arrived in v4.1.0 as a beta alternative to Nixpacks, with support for build-time environment variables, config merging, and multi-stage builds. If Nixpacks is not handling your build-time environment variables the way you need, Railpack is worth trying. It is beta — expect rough edges. Note that v4.1.2 fixed a Railpack Buildx cache metadata persistence bug, so run current if you are using it.
Static builds your project and serves the output through Nginx. Correct for Astro, Hugo, Eleventy, plain HTML, or any static site generator. Set your build command and publish directory and you are done.
Dockerfile uses a Dockerfile already in your repository. Full control over the image. My recommendation for anything production-critical — build reproducibility beats build convenience when you are debugging at 2am.
Docker Compose deploys multi-service applications from a compose file in your repository.
Configuration
Set your exposed port to whatever your application listens on — 3000 for a typical Node app, 8000 for Django, 80 for static. As of v4.1.2, exposed ports are optional for portless applications.
Add a domain under the general settings. Either a subdomain of your wildcard record or a custom domain with its own A record. Coolify provisions the Let's Encrypt certificate automatically.
Add environment variables under the Environment Variables tab. Coolify distinguishes build-time from runtime variables, which matters for frameworks like Next.js that inline certain variables at build. There is a known history of build-time variables breaking Next.js builds; if you hit it, verify your variables are flagged correctly. Environment variable search was added in v4.1.2, which helps once you have accumulated dozens.
Click Deploy. The log stream is live. First builds take a few minutes as Docker layers are cached.
Step 10: Wire Up Push-to-Deploy
This is the part that turns a server into a platform.
If you used the GitHub App
Auto-deploy is generally enabled automatically after GitHub App setup. Verify it:
Open your application's configuration page.
Go to the Advanced tab.
Confirm Auto Deploy is enabled under the general section.
That is the whole configuration. The GitHub App registers webhooks for you. Push to your configured branch and GitHub fires a push event at Coolify's webhook endpoint. Coolify pulls the commit, builds it, starts the new container, switches Traefik routing, and stops the old container.
If you are using webhooks manually
For deploy-key setups or public repositories:
On the application's Advanced page, enable Auto Deploy.
Enter a GitHub webhook secret — a random string. This functions as a shared password; Coolify rejects webhook calls whose signature does not match.
Copy the webhook URL Coolify displays.
In your GitHub repository, go to Settings → Webhooks → Add webhook.
Paste the Coolify URL into Payload URL.
Paste your secret into Secret.
Enable SSL verification.
Select Just the push event.
Ensure Active is checked.
Click Add webhook.
GitHub shows a delivery history for each webhook, including the response Coolify returned. When a push does not trigger a deployment, that page is the first place to look — it tells you immediately whether GitHub is failing to reach your server or Coolify is rejecting the payload.
Verifying the pipeline
Make a trivial change, commit, and push:
bash
echo "<!-- deploy test -->" >> README.md
git add README.md
git commit -m "test: verify auto-deploy pipeline"
git push origin mainWatch the Coolify deployments view. Within seconds a new deployment should appear and begin building.
Skipping deployments
v4.1.0 added support for [skip ci] and [skip cd] markers in commit messages and PR titles. Documentation updates and README edits do not need to trigger a build:
bash
git commit -m "docs: fix typo in setup instructions [skip ci]"Watch paths
For monorepos, configure watch paths so only changes to relevant directories trigger a rebuild. A change to packages/marketing-site should not redeploy your API. Set this in the application's advanced settings.
Step 11: Preview Deployments for Pull Requests
Preview deployments give each pull request its own running environment at its own URL. This is one of the features that made Vercel's DX compelling, and Coolify does it too.
With a GitHub App source and preview deployments enabled, opening a PR triggers Coolify to build that branch and deploy it separately. Coolify posts a comment on the PR with the preview URL, and as of a recent release, a link to the application logs. When the PR closes or merges, Coolify tears down the preview containers automatically.
Two safety improvements worth knowing: v4.1.1 fixed preview image tags so different commits on the same PR no longer reuse shared tags, and v4.1.2 skips preview deployments for fork pull requests — a meaningful security fix, since building arbitrary code from forked PRs on your own infrastructure is a real risk.
Preview deployments consume server resources. On a KVM 2 with several open PRs simultaneously, you may feel it. Watch memory usage or move builds to a dedicated build server.
Step 12: Advanced CI/CD with GitHub Actions
Push-to-deploy is sufficient for most projects. When you need tests to gate deployment, build images on GitHub's runners instead of your VPS, or deploy only after multiple checks pass, use GitHub Actions and trigger Coolify via its API.
The architecture: GitHub Actions builds and pushes a Docker image to a registry, then calls Coolify's deploy webhook to pull and run the new image.
Enable the API
Go to Settings → Configuration → Advanced.
Check API Access.
Create a deploy token
Go to Keys & Tokens → API Tokens.
Check the Deploy permission.
Name the token and click Create.
Copy the token immediately — it is shown once.
v4.0.0-beta.474 added optional expiration for API tokens with advance warning before expiry. Use it.
Get the deploy webhook URL
Open your application's configuration page.
Go to the Webhook tab.
Copy the Deploy webhook URL.
Add repository secrets
In GitHub, under Settings → Secrets and variables → Actions, add:
COOLIFY_WEBHOOK— the deploy webhook URLCOOLIFY_TOKEN— the API token
The workflow
yaml
name: Build and Deploy
on:
push:
branches: ["main"]
env:
REGISTRY: ghcr.io
IMAGE_NAME: "yourusername/yourapp"
jobs:
build-and-deploy:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v3
- name: Login to registry
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push image
uses: docker/build-push-action@v4
with:
context: .
file: Dockerfile
platforms: linux/amd64
push: true
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
- name: Deploy to Coolify
run: |
curl --request GET '${{ secrets.COOLIFY_WEBHOOK }}' \
--header 'Authorization: Bearer ${{ secrets.COOLIFY_TOKEN }}'Place the deploy step after your tests and checks so it only runs when everything upstream passes.
A forward-compatibility warning on that curl line. The workflow above uses GET, which is what Coolify's current documentation specifies and what works on v4.1.2. The v4.2 release changes this: state-changing API endpoints will require POST, and legacy GET requests return 405 Method Not Allowed. The affected endpoints include /deploy, /enable, /disable, /servers/{uuid}/validate, and the start, restart, and stop routes for applications, databases, and services.
If you are writing this workflow now, the forward-compatible version is a one-word change:
yaml
- name: Deploy to Coolify
run: |
curl --request POST '${{ secrets.COOLIFY_WEBHOOK }}' \
--header 'Authorization: Bearer ${{ secrets.COOLIFY_TOKEN }}'Verify against your running version — if POST fails on v4.1.2, fall back to GET and set a reminder to switch when you upgrade. Two other v4.2 changes are worth planning for: team members with the Member role become read-only and can no longer deploy or modify resources, so audit your team roles before upgrading and promote anyone who needs write access; and API responses hide sensitive fields by default, requiring tokens with sensitive-read access to receive secrets, credentials, and private keys.
On the Coolify side, configure the application to consume a prebuilt image rather than building from source. For Docker Compose applications, replace the build block with an image reference:
yaml
services:
web:
image: ghcr.io/yourusername/yourapp:latest
ports:
- "8080:8080"If your registry is private, authenticate on the server so Docker can pull:
bash
echo $GH_TOKEN | docker login ghcr.io -u $USERNAME --password-stdinStep 13: Databases and Persistent Storage
Running your database on the same box as your application is a legitimate choice at this scale, and it is a large part of the cost savings.
From your project, click + New and select a database. Coolify supports PostgreSQL (including official Postgres 18 and pgvector 18 as of v4.0.0-beta.463), MySQL, MariaDB, MongoDB, Redis, KeyDB, Dragonfly, and ClickHouse.
Coolify generates credentials and exposes the database on the internal Docker network. Your application connects using the container name as hostname — no public exposure needed, which is the correct default. Only enable public access when you genuinely need external connections, and set a public port explicitly if so.
Backups
Coolify supports scheduled backups to any S3-compatible storage. Configure this before you need it.
Go to Storages and add your S3 endpoint, bucket, and credentials.
On the database resource, open Backups.
Set a cron schedule and retention policy.
Select the S3 destination.
v4.1.2 added S3 storage validation before scheduling, which surfaces misconfiguration at setup rather than at 3am when a backup silently fails. Standalone database health checks also became configurable in that release.
Test your restore path. An untested backup is a hypothesis.
Volumes
Persistent storage is configured per-resource under Storages. Data written outside a declared volume does not survive a redeploy — Docker containers are ephemeral, and Coolify replaces the container on every deployment. Uploaded files, generated assets, SQLite databases: all need volumes.
Step 14: Close the Extra Ports
Now that the dashboard is reachable over HTTPS at your domain, close the direct-access ports.
Verify HTTPS works first:
bash
curl -I https://coolify.yourdomain.comA 200 or 302 response means Traefik is serving the dashboard correctly. Then:
bash
ufw delete allow 8000/tcp
ufw delete allow 6001/tcp
ufw delete allow 6002/tcp
ufw status verboseAlso remove these rules from Hostinger's control panel firewall, which is the one Docker cannot bypass.
Do not close these until you have confirmed the domain works. If Traefik is misconfigured and you close 8000, you have no way into the dashboard short of SSH and container surgery.
If realtime features stop working — logs not streaming, UI not updating live — you closed 6001 or 6002 too aggressively at the Docker level rather than just the public firewall. Reopen them and investigate.
The Security Reality You Need to Plan For
This section is not optional reading, and most Coolify tutorials omit it entirely.
On January 8, 2026, the project disclosed eleven critical vulnerabilities in a single day. Five carried a CVSS score of 10.0 — authenticated command injection ending in root access on the host. Grouped by class: command injection through database backup and import, PostgreSQL init scripts, proxy config, and storage mounts (CVE-2025-66209 through 66213, all 10.0, fixed in 4.0.0-beta.451); private key disclosure allowing a low-privileged user to read the root SSH key and log in as root (CVE-2025-64420, 10.0); injection via docker-compose.yaml and Git input fields (CVE-2025-64419, -64424, -59156, -59157, rated 9.4 to 10.0); and stored XSS via project name that fires in an admin's browser (CVE-2025-59158, 9.4).
At the time of disclosure, Censys counted 52,890 Coolify dashboards reachable from the public internet.
January was not the end. Through spring 2026 came a Sentinel-token injection leading to host RCE (CVE-2026-34034), command injection during deployment (CVE-2026-34038), an authorization bypass letting users reach other teams' servers (CVE-2026-34592), and a command injection via application settings that escapes container confinement (CVE-2026-34158, CVSS 8.8, disclosed July 7, 2026). No exploitation in the wild has been confirmed as of July 2026.
Why this keeps happening, and why it does not mean Coolify is bad software. Coolify's entire function is to take user input — a Git URL, a compose file, a database name — and convert it into privileged operations on your servers, usually as root. That is the largest attack surface a self-hosted tool can have. The recurring pattern is the same across nearly all of these: user input reaching a shell without sufficient sanitization, across many independent code paths. Combine that with a young product's feature velocity and a small core team, and this class of bug will keep surfacing. The project patches quickly and works with researchers through responsible disclosure, which is the part that actually matters.
The correct conclusion is not "avoid Coolify." It is: treat it as production infrastructure holding root on your servers, not as a weekend toy.
What this means for your setup
Most of these CVEs require authentication. If you are the sole admin, nobody else has an account, and your dashboard is not publicly reachable, your real risk is far below what the headlines suggest. The problem is that real installations rarely look like that — hence 52,890 exposed dashboards.
The practical checklist, in priority order:
1. Get the dashboard off the public internet. This single step neutralizes most of the risk. Put it behind WireGuard or Tailscale, or restrict access by IP allowlist at your provider's firewall. Closing ports 8000, 6001, and 6002 as described in Step 14 is the minimum; VPN-only access is the real answer for anything holding customer data. Note that unauthenticated vectors have existed — host-header injection in the password reset flow and a login rate-limit bypass — so "it needs a login" is not by itself a defense for an exposed dashboard.
2. Patch on a schedule, not on a whim. Subscribe to the repository's GitHub security advisories. New critical CVEs have appeared every few months. Decide now who applies a critical patch within 24 hours, including during holidays. If that question has no answer, you have found a real argument for a managed platform.
3. Rotate secrets if you ever ran an old version. Anything at or below 4.0.0-beta.434 allowed low-privileged users to read private keys. Updating does not un-leak a key that was already readable. Rotate SSH keys, API tokens, and database credentials.
4. Be deliberate about team roles. Every member account has historically been one CVE away from root. Grant resource-management rights only to people you would hand root to anyway. Coolify has been tightening this steadily — v4.1.1 scoped sources, private keys, servers, and networks to the current team, and the forthcoming v4.2 makes the Member role read-only by default.
5. Separate the control plane where you can. Running Coolify on its own host rather than alongside your production workloads limits the blast radius when the next CVE lands.
6. Keep backups off the Coolify host. A root compromise of the control plane must not take your backups with it. This is the strongest argument for the S3 backup configuration in Step 13 rather than local-only backups.
7. Monitor for the right things. Alert on new SSH keys, unusual API calls, and configuration changes on the Coolify host — not just on whether containers are up.
Ongoing Operations
Updates
Coolify surfaces available updates in the dashboard with a one-click upgrade. It also supports automatic updates, configurable under settings. My recommendation: enable automatic updates for patch releases, review minor releases manually. Coolify ships frequently and release notes occasionally contain breaking changes — v4.1.0 removed the deprecated Docker Compose application API endpoint and changed MCP enable/disable routes from GET to POST.
Manual update to a specific version:
bash
curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash -s v4.1.2Downgrading is supported but not recommended, since database migrations do not always reverse cleanly.
Monitoring
Coolify includes Sentinel for server and container metrics — CPU, memory, disk, per-container resource usage. v4.1.2 moved Sentinel into a dedicated tab with improved metric refresh.
Configure notifications under settings. Coolify supports Discord, Telegram, Slack, Mattermost, and email, and will alert on deployment failures, server unreachability, and disk pressure. Set these up on day one. Silent failures are the real risk in self-hosting.
For deeper observability, Uptime Kuma and Healthchecks are both available as one-click services — Healthchecks was added in v4.1.2. Running your monitoring on the same server it monitors has an obvious flaw; consider a separate small instance or an external service for uptime checks.
The observability gap
This is worth stating plainly because it affects the cost comparison. Coolify is a deployment platform. It does not include web analytics, error tracking, session replay, or external uptime monitoring. Assembling a comparable production observability stack from commercial tools — error tracking, analytics, session replay, uptime monitoring — commonly runs $250+/month, which dwarfs your hosting savings.
The self-hosted alternative is to run open-source equivalents as one-click services: Plausible or GoatCounter for analytics, GlitchTip or Bugsink for error tracking, Uptime Kuma for monitoring. All available in Coolify's service catalog, all free, all running on your server and consuming its resources. That is the actual tradeoff — you are substituting your own capacity and attention for someone else's subscription.
Rollbacks
Every deployment is recorded. If a release breaks, redeploy the previous image from the deployments view. Coolify retains previous build images for rollback, controlled by the "keep for rollback" setting. Confirm that setting is enabled and sized appropriately, since retained images consume disk.
Troubleshooting: The Failures You Will Actually Hit
Ordered roughly by how often they occur.
The dashboard will not load after installation. Check the containers are running with docker ps — you want coolify, coolify-db, coolify-redis, and coolify-realtime. If they are missing, docker logs coolify will tell you why. If containers are healthy but the page times out, it is the firewall: confirm port 8000 is open both in UFW and in Hostinger's control panel firewall. And if you used Hostinger's Coolify template rather than installing manually, the dashboard is on port 3000, not 8000.
The SSL certificate will not issue. Three causes, in order of likelihood. DNS has not propagated — verify with dig +short yourdomain.com and confirm it returns your server IP. Port 80 is closed, so the ACME HTTP-01 challenge cannot complete; Let's Encrypt needs it even though your traffic ends up on 443. Or Cloudflare's proxy is intercepting validation — set the record to DNS-only (grey cloud) until the certificate issues. If you are trying to get a certificate for *.something, re-read the wildcard section: HTTP-01 cannot issue wildcard certificates at all.
Push does not trigger a deployment. Start at GitHub's webhook delivery log — repository Settings → Webhooks, click the webhook, open Recent Deliveries. That page tells you immediately whether GitHub reached your server and what Coolify returned. A timeout means Coolify is unreachable at the configured webhook endpoint, which usually means you set the endpoint to an IP-and-port form and then closed port 8000. Fix the endpoint to your dashboard domain. A 401 or 403 means the webhook secret does not match. A 200 with no deployment means "Auto Deploy" is disabled on the application's Advanced page, or the push was to a branch other than the one configured, or your commit message contained [skip ci].
Builds fail with out-of-memory errors. Almost always a KVM 1, or a KVM 2 running a large Next.js or monorepo build. Add swap (Step 3) if you have not. If swap is present and builds still fail, you have three options: upgrade the plan, switch to a Dockerfile build pack with a multi-stage build that keeps memory bounded, or configure a separate build server so builds do not compete with your running containers for RAM.
The application deploys successfully but returns 502 Bad Gateway. Traefik is routing correctly but nothing is listening where it expects. The exposed port in Coolify does not match the port your application actually binds. Check your application's logs, confirm what port it is listening on, and make sure it binds 0.0.0.0 rather than 127.0.0.1 — a container listening only on localhost is unreachable from Traefik.
Environment variables are missing at build time. Coolify distinguishes build-time from runtime variables. Frameworks that inline variables during the build — Next.js with NEXT_PUBLIC_* being the canonical case — need them marked as build-time. There is a documented history of build-time variables breaking Next.js builds specifically, so if your build succeeds locally and fails in Coolify with undefined variables, check that flag first.
Realtime features stop working — logs do not stream, the UI does not update. Ports 6001 and 6002 are blocked. You closed them at the Docker level rather than only at the public firewall. Reopen them.
Data disappears after a redeploy. Whatever wrote it was not on a declared volume. Docker containers are ephemeral and Coolify replaces the container on every deployment. Uploaded files, generated assets, and SQLite databases all need persistent storage configured under the resource's Storages tab.
The deployment succeeds but the old version is still being served. Usually browser or CDN caching rather than a Coolify problem. Hard-refresh, and if Cloudflare's proxy is on, purge the cache. If the container genuinely did not restart, the deployment log will show it.
When Coolify Is the Wrong Answer
Every honest guide needs this section.
You need global edge distribution. Coolify runs your app in one datacenter. Vercel and Netlify run it in dozens. For a globally distributed audience where latency is a product requirement, Coolify plus a CDN gets you partway, but is not equivalent.
You need automatic scaling under unpredictable load. A VPS has fixed capacity. If traffic can 50x without warning, serverless platforms absorb that and a fixed VPS does not. Note the tradeoff cuts both ways: that same elasticity is what produces the $23,000 bandwidth bills.
You have regulatory requirements. SOC 2, HIPAA, GDPR, and NIS2 impose infrastructure controls that self-hosting on a budget VPS does not satisfy without substantial additional work. Given the CVE history above, "we patch when we remember" is not a defensible control narrative to an auditor.
Nobody on your team wants to own a server. Coolify reduces operational burden enormously, but it does not eliminate it. Someone must patch the OS, monitor disk, respond when a deployment wedges, and read release notes. If that person does not exist on your team, the managed platform's markup is buying something real.
You need multi-server orchestration today. Coolify v4 does not do it. Docker Swarm support exists but was marked deprecated ahead of removal in v5. The v5 rewrite promises full scalability in the core, but as of mid-2026 there is no published timeline and no announced v4-to-v5 migration path. Adopting v4 now means accepting that as a known unknown.
What to Watch Next
The near-term question for Coolify is v5. The maintainer has described the headline feature as full scalability in the core — cloud-like infrastructure running on servers you own — and confirmed v4 will continue to be supported alongside it. What has not been published is a timeline or a migration path. The v4 release cadence remains healthy, so this is not a stagnation risk, but if multi-server orchestration is on your roadmap, plan around v4's current limits rather than v5's promises.
The second thing to watch is the pricing direction of the platforms Coolify competes with. Netlify's move to flat-fee Pro with unlimited seats in 2026 was a direct response to per-seat fatigue, while simultaneously making bandwidth harder to reason about through the credit model. Vercel's Turbo-by-default build machines increased effective costs for teams that did not notice the change. Both patterns suggest the industry is converging on usage-based metering, which is precisely the model that makes a fixed-price VPS look attractive.
The third, and the one with a date attached, is v4.2. It merged into the release branch on July 19, 2026 and will be tagged shortly. Beyond the API and permissions changes covered above, it adds DigitalOcean droplet provisioning and Vultr integration, Hetzner firewall and private network options during server creation, scheduled ClickHouse backups, a per-team MCP toggle, and substantial API surface expansion. If you are reading this after it ships, check the changelog before upgrading — the Member-role and POST-only changes will break working setups that were not audited first.
The fourth is Coolify's security posture. Reading the v4.1.x release notes, the sheer volume of hardening work — input validation, shell escaping, team scoping, command injection fixes — reflects a project that grew faster than its security review process and is now catching up in public. That is a healthy sign in a maintained project, and it is also why the patching discipline in the security section is not optional advice. Expect more advisories. Plan for them.
Bottom Line
Coolify converts a commodity VPS into something that feels close to Vercel's developer experience: git push, automatic build, automatic TLS, preview environments, one dashboard. On a Hostinger KVM 2 at single-digit dollars per month with 8TB of included bandwidth, it eliminates the two cost drivers that make managed platforms expensive at scale — per-seat pricing and metered egress.
What it does not eliminate is responsibility. You own the patching, the monitoring, the backups, and the pager. That is a heavier obligation than most tutorials admit: this is software that holds root on your servers, has shipped eleven CVSS-critical vulnerabilities in a single day, and will ship more. Run it behind a VPN, patch it promptly, and keep backups somewhere it cannot reach, and it is a solid piece of infrastructure. Expose the dashboard to the internet and update it twice a year and you have built a liability.
For a solo developer or a small team with any sysadmin comfort, that is a fair trade and the savings are substantial. For a team without that capacity, or with compliance obligations, or with genuinely global latency requirements, the managed platform premium is buying something real.
The break-even is roughly $20/month of platform spend. If your bill is above that and bandwidth or seats are driving it, an afternoon setting up Coolify pays for itself in the first month and keeps paying every month after.