Published: 2026-07-13
Earlier this year I wrote about how I build and deploy projects using AI. At the time I used Render for everything. At the end I mentioned some small rumblings I had seen about Kamal. It seemed like exactly what I wanted, but I wasn't sure if coding agents would understand it.
Anyways, they do. I now deploy Metner and Minnas to Hetzner with Kamal. It's cheaper and I have more control over what is running.
Render is great. You connect a repo, give it a blueprint, and it handles almost everything. The problem is that Rails apps rarely stay as one service. You start with a web server, then add a background worker, Postgres, and Redis. Each one adds to the bill.
As of writing this, the smallest paid web service is $7 per month, Postgres is $6, and Redis is $10. Add a $7 worker and a pretty normal Rails app costs around $30 per month. That's fine for a business. It's harder to justify for a project with three users when two of them are me.
Render has free services, but they sleep and the free database expires. I build too many projects to pay for each service separately.
Hetzner cloud servers currently start at $6.49 per month before tax and an IPv4 address. That's an entire server, not one 512 MB process. I can run Rails, background jobs, Postgres, Redis, and whatever other weird thing the project needs on the same machine.
Kamal makes the plain server feel like a deployment platform. It builds the Docker image, pushes it to a registry, connects to the server, and starts the new version. Its proxy waits for the Rails healthcheck to pass before moving traffic over and stopping the old container.
The production setup lives in config/deploy.yml. The first deploy is kamal setup, then every deploy after that is kamal deploy. Codex can read the config and Dockerfile, run the deploy, and usually figure out failures from the logs.
Metner is the boring version. It has a Rails web process, a background job process, Postgres, and Caddy for its storefront subdomains and custom domains. GitHub runs the tests when I push to main, then runs bin/kamal deploy if they pass. Most of the time I don't think about the server.
Minnas is less boring. It runs Rails, Sidekiq, Redis, a Node.js builder, and a self-hosted Firecrawl setup with even more containers. On a managed platform that would be a pile of separate services. With Kamal they are accessories on the same Hetzner server.
I wouldn't do this for an app with serious traffic, but Minnas does not have serious traffic. If it ever does, Kamal can move workers or the database to another server. I don't need to start with that bill.
In my last post I mentioned the servers running in my house and wanting a good way to deploy small projects to them. The answer was also Kamal. It doesn't care if the server is in a Hetzner data center or in a server rack that overheats my office. If it can connect over SSH and run Docker, it can deploy there.
I run the self-hosted version of Minnas this way. Kamal deploys the web app and worker to my home server. Docker volumes keep its data and generated workspaces there, and I can access it through my private network without making it public.
This is great for internal tools and AI experiments that need more storage or compute than I want to rent. I already own the hardware, so another small app doesn't add a monthly bill beyond electricity. It won't have perfect uptime, but my personal tools do not need a data center.
The best part is that home and cloud deployments are the same. They are both a Docker image, a Kamal config, and a server reachable over SSH. If a home project needs to become public, I can point it at Hetzner. If a cloud experiment isn't worth the bill, I can bring it home.
Maybe not entirely wrong, in my last post I said I wasn't a fan of Docker, and I'm still not a fan. With one condition. I still don't want to use it for local development. I like starting Rails normally and going to localhost:3000. If I'm working on a specific thing that doesn't need sidekiq, I don't want sidekiq running. Docker doesn't have an easy way to do that in my experience, it's all or nothing.
It makes sense for production though. Rails generates a really useful Dockerfile, Kamal only needs the server to run containers, and every deploy gets the same environment. I develop. Well Codex develops, and I manage (that deserves another post), running only the portions that I need at that moment.
Hetzner and Kamal are cheaper because I'm doing work Render did for me. I need to watch the server, back up the database, and know how to restore it. A single server is also a single server. If it disappears, everything on it disappears together.
I'm comfortable with that for my projects. Render is still a good choice when I want a managed database and less responsibility. I just build too many Rails apps for it to be my default. The self-hosting setup I described as an ideal future in January is now how I deploy things.