Build Vercel
KINDAreplaces $20/mosaves $240/yrback to the verdict
Coolify on one server, deploying your application on every push, giving each branch its own preview URL with its own certificate, keeping the previous release ready for an instant rollback, and backing up both the application data and the platform's own configuration off the machine.
Before step 1
Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.
- have readyroughly 10 to 25 USD a month depending on provider and memory
Why Coolify idles around 2 GB and a build wants the rest. On 2 GB the build kills production, which looks like a mystery outage.
Get it Any virtual server provider. Choose a region close to your users, because that choice is now your entire content delivery strategy. open ↗
Verify
free -m reports 4 GB or more - have readya few USD if deleted the same day
Why The drill proves nothing on the machine that already has the state. Create it for a day and destroy it after.
Get it The same provider, smallest plan meeting the memory floor.
Verify
You can SSH to it - have readyroughly 10 to 15 USD a year
Why Wildcard certificates for preview hostnames need a DNS challenge, which needs an API token. A registrar without an API makes previews far harder.
Get it Use a registrar or DNS host with an API, create a token scoped to the zone, and add both the A record and the wildcard record.
Verify
The wildcard hostname resolves and the token can create a TXT record - accountfree for personal repositories
Why The whole pipeline is webhook driven. Without it you are deploying by hand, which is the thing you were trying to stop doing.
Get it GitHub, GitLab or a self-hosted forge. Connect it in the platform and authorise the webhook.
Verify
A test push shows up as a deployment - accounta few USD a month at these volumes
Why Backups on the server die with the server. This includes the platform configuration, which exists nowhere else.
Get it Object storage from any provider, with credentials scoped to write into one bucket.
Verify
A test file uploads and lists from your laptop
Data model
Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.
- This is infrastructure, so the state worth writing down is operational. - server · address, memory, disk, and what else is running on it - services · one per application, with its repository, branch, build command and environment variables - domains · production hostname, and the wildcard used for preview hostnames - secrets · every environment variable per service, kept somewhere that is not the server - backups · application data, Coolify configuration, and the date of the last restore drill
Environment variables
These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.
| Variable | Needed | Example | Where the value comes from |
|---|---|---|---|
COOLIFY_DOMAIN | required | deploy.example.com | Hostname for the platform dashboard. Keep it off your production domain so an application misconfiguration cannot shadow it. |
PREVIEW_WILDCARD_DOMAIN | required | *.preview.example.com | The wildcard used for per-branch preview hostnames. |
DNS_API_TOKENsecret | required | replace-with-provider-token | Your DNS provider's API token, scoped to the zone. Needed for wildcard certificate issuance. |
PRODUCTION_DATABASE_URLsecret | required | postgres://user:pass@db:5432/app | Set in the platform, never in the repository. |
PREVIEW_DATABASE_URLsecret | required | postgres://user:pass@db:5432/app_preview | A different database from production. This variable is the isolation. |
BACKUP_DEST | required | s3://your-bucket/deploy | Where both nightly artefacts go: application data and platform configuration. |
The build, in order
Server, DNS and the platform
Coolify runs, you can reach its dashboard safely, and DNS is ready for preview hostnames.
A non-root user, SSH keys only, and a firewall allowing SSH, 80 and 443. Verify with a scan from your laptop rather than by reading the configuration.
terminalufw allow OpenSSH && ufw allow 80,443/tcp && ufw enable nmap -Pn YOUR_SERVER_IP
Its installation script sets up Docker and the platform. Change the initial dashboard credentials immediately.
terminalcurl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash
An A record for the dashboard and for production, plus a wildcard for preview hostnames. Add a DNS provider API token so wildcard certificates can be issued.
terminaldig +short app.example.com dig +short test.preview.example.com
done when · tick each as it passeswatch out- Preview deployments need a wildcard DNS record, and a wildcard needs a wildcard certificate, which needs a DNS challenge rather than the usual HTTP one. That means an API token for your DNS provider. Sort this out in Phase 1, because discovering it when your first preview URL fails to get a certificate is a bad afternoon.
First deploy from a push
Pushing to the main branch deploys, without you touching the server.
Point at the repository and branch. Let the platform detect the build, then check what it detected rather than assuming it guessed right.
Every secret goes in the platform's own storage, never into the repository. This is also what makes preview environments possible later.
Run top on the server while the build runs. This one observation prevents the most common self-hosting outage.
terminalfree -m top -o %MEM
done when · tick each as it passeswatch out- Builds run on the same server as production by default, and a Node build can consume more memory than the running application. On a 4 GB server this shows up as the build killing production, which looks like a random outage. Watch memory during the first build, and add swap or move builds elsewhere before it bites.
Preview deployments per branch
Every pull request gets its own URL, which is the feature you were actually paying for.
Configure the wildcard domain for previews and confirm certificate issuance works through the DNS challenge.
A separate database, seeded rather than copied from production. Override the connection variable at the preview level.
Write a record from a preview and confirm it is absent from production. Do this once, deliberately, before you trust it.
done when · tick each as it passeswatch out- A preview environment that inherits production environment variables will happily write to the production database, and the first time it does you will find out through data rather than through an error. Give previews their own database and their own variables from the very first preview, not after the first accident.
Rollback and health
A bad deploy is a one-click problem rather than an emergency.
An endpoint that queries the database. A static endpoint returns healthy while the application is unable to serve anyone, which is worse than no check.
Files
src/healthThe old container keeps serving until the new one passes. Verify by watching requests during a deploy.
Push a commit that fails to start. Confirm the site stays up, then roll back and time it.
done when · tick each as it passeswatch out- A deployment strategy that stops the old container before the new one is healthy gives you downtime on every deploy and an outage on every bad one. Configure the health check and confirm the old container keeps serving until the new one passes.
Backups, including the platform itself
You can rebuild everything, including the configuration that describes everything.
Database dumps and any uploaded files, dated, off the machine, several generations retained.
Files
scripts/backup.shCoolify's own database and configuration directory. This is what stores your services, domains and variables.
Files
scripts/backup.shCheck each morning that today's files exist. Silence is not evidence that a backup ran.
Files
scripts/check_backup.sh
done when · tick each as it passeswatch out- Backing up your database and not the platform configuration means a restore leaves you re-entering every service, domain and environment variable from memory. The environment variables in particular exist nowhere else once the server is gone.
The restore drill and the honest comparisonproduct builder
You have rebuilt it on a new server, and you know what this actually costs.
New server, fresh platform install, restore the configuration, restore the data, point DNS at it temporarily and verify.
In the README. A restore you did once and dated is worth more than a runbook you have never followed.
Files
README.mdUse a testing service that requests your site from several continents. Compare with the same measurement against the platform you left.
Files
docs/comparison.md
done when · tick each as it passeswatch out- Measure page load from somewhere far away, not from your desk. One server in one region will be markedly slower for distant visitors than an edge network, and this is the single largest thing you gave up. If most of your visitors are far from your server, that difference may outweigh the saving.
That is the whole plan for Vercel. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- The global edge network, which is the largest thing you give up.
- Automatic scaling under traffic you did not expect.
- Framework-specific optimisations and edge functions.
- Someone else carrying the pager.
- edge/CDN performance
- preview deployments
- scaling
- observability
- image functions
- team workflows
- Next.js integration
- Moving builds to a separate machine once they compete with production
- A staging environment restored nightly from production backups, which also exercises the restore
- A content delivery network in front for static assets, which recovers some of the edge benefit cheaply
Need the files? The project pack on the verdict page hands your agent the whole brief · more hosting.