Coolify is actually pretty cool
Exploring a cheap single node VPS setup with Hetzner, Coolify (hosting Clojure application with PostgreSQL database)
I was looking for a cheap and convenient way to improve deployment for my hobby projects. My current setup is a DigitalOcean Droplet, which costs me ~8$/month. Inside I have Docker and Docker Compose that run: a Clojure application, a PostgreSQL database, an additional container that does database S3 backups on a schedule and Nginx as reverse proxy which also is configured to generate and renew LetsEncrypt certificates. That actually worked for me for many years, but there are a couple of things I don’t like:
The cost of DigitalOcean Droplet is quite high for the resources.
My deployment process is quite manual: GitHub Actions pipeline is building a docker image for me and after I need to manually pull the repo on the host with `docker-compose.yaml` and restart the container.
On the other hand, the Hetzner Cloud offering is appealing. They have the CX22 plan: 2 vCPU, 4GB RAM, 40TB for €3.79/month. Also, you will probably what to pay for IPv4 on top of that.
But I didn’t really want to replicate my poor deployment pipeline, so I’ve looked for alternatives.
Coolify was on my radar for quite a while, but the thing I didn’t understand is how many features it has. I saw it advertised as a self-hosted Vercel alternative and without looking into much detail I assumed that it’s Javascript-focused - I was wrong.
You can literally run anything - I was able to deploy a Clojure application without any modifications.
To build and deploy your application you can still use Docker, but by default, it’s using Nixpacks. It was new to me and better read official docs (https://nixpacks.com/docs), but It has Clojure support: https://nixpacks.com/docs/providers/clojure by just detecting a `project.clj` file in your repo.
Let’s talk about installing Coolify - it is really simple and takes just a couple of minutes and a single command to run:
curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash
You need to run it from your Hetzner host and it’s probably the last time you need to SSH there. At the end of the installation, you’ll get a URL for the Coolify UI running on the host, everything else is done from there.
Running PostgreSQL
My application requires a PostgreSQL database, so that was the first thing I’ve tried. You can basically deploy a PostgreSQL instance from the UI with a couple of clicks.
My instance was up and running in no time. Extra features I really liked:
I was able to expose my database port to the outside (make it publically available for a short period), so I could easily transfer data from my old database with pg_dump and the psql restore.
You can configure database backups from Coolify, so you don’t need extra tools: the destination could be most of the S3-compatible object stores.
Deploying the Clojure application
I have a private GitHub repo with my Clojure application. The way you configure the CI pipeline for it in Coolify is by creating a GitHub application with permission to read the repo, it will also automatically receive webhooks for new commits in the main branch and trigger new deployments.
The other killer feature is the preview branches on PRs, I don’t really use it in my project, but I definitely see the value.
So the build process as I’ve mentioned is using Nixpacks by default and it actually worked without problems for the Clojure application, it detected the environment like so:
One thing to mention, I got an issue with the Java runtime version in another app, but the fix was to set the build environment variable to configure Nixpack Clojure:
NIXPACKS_JDK_VERSION=latest
Coolify is also solving the problem of storing secrets, instead of setting them manually on the host or storing them in GitHub private repo (as I used to do) — you just set them in UI (similar to Vercel):
Also, you get a nice you to view logs and you can configure log drain to a 3rd party (like NewRelic):
Other features I’ve tried are:
Configuring custom domain
Basic built-in host monitoring (CPU, Memory, DiscUsage)
Email notifications (you need a Resend API key for that)
Push notification to Telegram Bot
The most impressive thing really is that during my experiments I encountered 0 issues (except that one with Java runtime version, which I solved in 10 minutes by reading Nixpacks docs and setting one extra var).
Well done, Coolify!
P.S.
I’ve not switched my project to run on the Coolify Hetzner host, but I’ll run a replica of it for a while, check that everything is stable — and hopefully switch!
That should save me a couple of USD per month and improve the developer experience :)