Answers · Deploying

How do I fix no space left on device on a deploy server?

Old container images are the cause, not your app. Every deploy pushes a new image and the server keeps the old ones. Run docker image prune -a -f to reclaim the space, then check with df -h. On a 25GB VPS this usually returns several gigabytes, and it is worth doing before you are locked out rather than after.

Reclaim the space now

ssh your-server 'df -h /'
ssh your-server 'docker image prune -a -f'
ssh your-server 'docker system df'

docker system df is the one worth reading: it separates images, containers, volumes and build cache, so you can see which one actually grew. On a deploy host the answer is almost always images.

Be deliberate about -a. It removes every image not currently used by a running container, which includes the previous release you would roll back to. Prune when you are happy with what is live, not in the middle of an incident.

Why it fills up

Each deploy builds an image, pushes it to the registry, and pulls it on the server. The old image stays: that is what makes a rollback instant. Nothing removes it on a schedule. At roughly 400MB per image, a small VPS runs out somewhere between thirty and sixty deploys, and the symptom is a deploy that fails at the pull step with no obvious connection to disk.

Stop it recurring

Set a retention limit on the Docker daemon so it prunes as it goes:

ssh your-server 'cat /etc/docker/daemon.json'
{ "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" } }

Container logs are the second thing that fills a disk, and unlike images nothing rotates them by default. The setting above caps each container at 30MB.

What this does not cover

SQLite. If df -h shows the disk full and pruning reclaims nothing, look at the database volume and at storage for uploaded files, which grow with real use rather than with deploys. The volume mounts are declared in config/deploy.yml, so that file tells you which host directories to size. See Production Database and Storage for where those live and how to size them.

Related questions

How do I deploy a Rails 8 app without Heroku?

Use Kamal, which ships with Rails 8. You give it a server over SSH and a container registry in config/deploy.yml, run kamal setup once, and kamal deploy after that. It builds an image, pushes it, and swaps containers with no downtime. A $5 VPS replaces the PaaS.

How do I deploy a Rails app from GitHub Actions?

Run kamal deploy as a workflow step. Kamal needs three things in the runner: an SSH key that can reach the server, registry credentials, and RAILS_MASTER_KEY. All three go in as repository secrets and are read by .kamal/secrets. Gate the deploy job behind the test job so a red build never ships.

How do I open a Rails console on a production server?

Run kamal app exec --interactive --reuse 'bin/rails console'. That attaches to the running container rather than booting a new one, so you see live data. One Shot ships no admin UI on purpose, so the console is the supported way to inspect and fix records, and everything you touch must go through an Account.