What Kamal actually does
Kamal is a deployment tool that assumes you have servers and Docker, and nothing else. There's no Kubernetes, no control plane and no managed platform, just SSH and containers. That's a smaller set of moving parts than most alternatives, and it's why Kamal fits a single VPS.
The whole model in one paragraph
Kamal builds a Docker image on your machine, pushes it to a registry, connects to your servers over SSH, pulls the image there and starts containers from it. A reverse proxy in front routes traffic to whichever container is currently healthy.
That's the entire model. Everything else in config/deploy.yml is detail on top of those five steps.
What this application's file says
service: newbieonrails
image: gxolivei/nor
servers:
web:
hosts:
- <%= ENV.fetch("NOR_SERVER_IP") %>
There's one server, named by an environment variable instead of being written into the repository. ENV.fetch with no default means a missing variable fails loudly at deploy time, before anything deploys somewhere unexpected.
That works because the file is ERB: Kamal renders it before parsing the YAML.
flowchart TB
L["your machine"] --> B["docker build"]
B --> R["push to ghcr.io"]
R --> S["ssh to the server"]
S --> P["docker pull"]
P --> C["start the new container"]
C --> H["health check on /up"]
H --> X["proxy switches traffic. old container stops"]
The registry step people skip past
registry.server: ghcr.io means the image travels through GitHub's container registry, and not directly from your laptop to the server.
That indirection does real work. The server never needs your source code or a build toolchain. Each image is tagged with its git commit, so rolling back means pulling a previous tag instead of rebuilding.
builder.arch: amd64 forces the build target, which matters on an Apple Silicon machine. Without it, you'd build an arm64 image, and the server couldn't run it.
Why this instead of a platform
A managed platform does all of this and more. What Kamal offers instead is that every piece is visible: the containers are Docker containers, the proxy is a process you can inspect, and the server is one you can SSH into.
The trade is operational responsibility in exchange for legibility and cost. For a single application on a single VPS, that trade is usually favorable, and it's the one this project made.
Key takeaways
- Kamal builds an image, pushes it to a registry and starts containers over SSH.
config/deploy.ymlis ERB, so the server address can come from the environment.ENV.fetchwithout a default fails loudly instead of deploying somewhere wrong.- The registry means the server needs no source code or build tools, and a rollback is a tag.
- The trade is operational responsibility in exchange for legibility and cost.
Keep going with lesson 2
The proxy and the swap
How kamal-proxy checks a new container's health on /up and switches traffic without a gap.
A free account also gives you the quizzes, your progress and notes, and the discussion.