Answers · Deploying

Why does a Kamal deploy hang on the health check?

The new container started and exited before Rails could answer /up. Kamal waits, then rolls back and leaves the old container serving. Run kamal app logs to see the real error. On a first deploy it is almost always a missing or wrong RAILS_MASTER_KEY, which raises before any route exists to answer the check.

Read the container's own logs first

Kamal's output tells you the health check failed. It does not tell you why, because the failure happened inside the container. That is a separate log:

bin/kamal app logs --lines 100
bin/kamal app logs --lines 100 --grep Error

Nine times out of ten the last lines are a Ruby backtrace from boot, and the error is legible.

The three that account for most of them

A missing or wrong RAILS_MASTER_KEY. Rails cannot decrypt config/credentials.yml.enc, so it raises during initialization. Nothing is listening on the port, so the health check gets connection refused rather than a 500. Confirm the key is actually reaching the server:

bin/kamal secrets print

If the value is blank, .kamal/secrets is not exporting it. That file is not committed, so a fresh clone or a new CI runner will not have it.

A database the container cannot write. One Shot runs on SQLite, and the database file lives on a mounted volume. If the volume is missing or owned by the wrong user, the first write raises and the boot aborts. bin/kamal app exec 'ls -la db' shows what the container actually sees.

A port mismatch. The health check asks the container for /up on the port Kamal thinks it exposes. If you changed the Puma port without changing config/deploy.yml, the check talks to nothing.

What Kamal does while you debug

Nothing bad. The old container keeps serving traffic for the whole wait, and a failed deploy leaves it in place. That is the behavior you want: a deploy that cannot boot does not take the site down, it just fails.

The check that catches it before the deploy

The same boot happens locally with the production environment. This is faster than a round trip to the server:

RAILS_ENV=production bin/rails runner 'puts "boots"'

If that raises, the deploy will too, for the same reason.

Related questions

What do I need before a first deploy to production?

Four things: a Linux server you can SSH into, somewhere to push a container image, a domain pointed at the server, and RAILS_MASTER_KEY. That last one is the only secret production will not boot without. Billing, email and bot checking all fall back to in-process fakes, so you can ship before you have those keys.

Why does Kamal fail with pull access denied on deploy?

The server cannot log in to the registry that holds your image. Kamal pushes from your machine, where you are already authenticated, then asks the server to pull, where it is not. Check the registry block in config/deploy.yml names the right username, and that KAMAL_REGISTRY_PASSWORD is actually set in .kamal/secrets.

Can I run SQLite in production for a Rails app?

Yes, for one server. Rails 8 ships SQLite configured for production use, and One Shot runs on it: the database is a file on a mounted volume, backups are a file copy, and there is no second service to operate. The limit is real though. Two application servers cannot write to the same SQLite file, so horizontal scaling is where it stops.