Wetin Docker Change for VPS? RAM, UFW and Reboot
Docker for VPS still use the same engine, but RAM fit finish, published ports fit bypass UFW, containers stay down after reboot, and disk fit full.
Wetin change when you run Docker for VPS
Docker for VPS dey run the same engine and same images like Docker for your laptop, so every command wey you sabi still go work. Wetin change na the space around am. Laptop get spare memory, firewall wey nobody dey scan, and disk wey big enough make you no need check am. Rented server get fixed memory limit, public IP address wey scanners go reach within minutes after boot, and root filesystem wey Docker go fill without asking.
Four differences dey cause most wahala for small server:
- Memory no unlimited, and kernel go settle shortage by killing process.
- Published port go pass straight through UFW (uncomplicated firewall), because Docker dey write im own firewall rules.
- Containers no go come back after reboot unless you configure am before time.
- Images, containers, volumes and build cache go keep growing until disk full.
Each section below go name the failure, the exact string wey you go see, and the guide wey explain how to fix am properly. If you never write compose file, read Docker Compose basics for VPS first, then come back. This page assume say you fit already bring stack up.
How much RAM container Docker dey use?
E dey use less than wetin most people expect. Container na process wey dey inside cgroup (control group), no be virtual machine. So e no get guest kernel and no fixed allocation. The cost na whatever the process inside touch. Na why complete stack fit work with 2 GB when the same stack wey dem build with virtual machines no fit.
The figures below na normal idle numbers for stock images on Ubuntu 24.04 with default configuration. Dem read am from docker stats few minutes after start. Use dem as starting point for planning, no be benchmark for your workload. Run docker stats --no-stream for your own box before you trust any figure, including these ones.
The data behind this chart
[
{
"label": "nginx",
"idle_mb": 8,
"budget_mb": 64
},
{
"label": "Redis 7",
"idle_mb": 12,
"budget_mb": 128
},
{
"label": "Traefik v3",
"idle_mb": 40,
"budget_mb": 128
},
{
"label": "PostgreSQL 16",
"idle_mb": 45,
"budget_mb": 512
},
{
"label": "Uptime Kuma",
"idle_mb": 95,
"budget_mb": 256
},
{
"label": "MariaDB 11",
"idle_mb": 190,
"budget_mb": 512
},
{
"label": "Nextcloud (Apache)",
"idle_mb": 210,
"budget_mb": 768
}
]The two columns get different work. idle_mb na wetin container dey use when e no dey do anything. budget_mb na wetin you suppose reserve when you dey plan, because real use no be idle. PostgreSQL dey idle near 45 MB and e need 512 MB when connections, sorts, and cache don dey active. Plan with the budget column. Debug with the idle column.
Notice the pattern for those 7 rows. nginx dey idle at 8 MB and Nextcloud at 210 MB. The proxy wey dey in front of your applications almost no dey use memory. Na the database and PHP application be wetin you suppose size the box for.
One warning about docker stats: the memory figure include page cache wey the container own file reads bring inside. So e go increase for some time after start, then e go settle. Monitor am for one hour before you decide say something dey leak.
VPS sizing: wetin fit inside 2 GB, 4 GB and 8 GB
First remove the host share from the total. The kernel, systemd, journald, sshd and the Docker daemon all dey use the same RAM wey your containers dey use, and dockerd with containerd dey hold around 100 MB of am. You also need free memory for page cache, and for the sudden increase when image build or database dump dey run.
The data behind this chart
[
{
"plan": "2 GB VPS",
"total_mb": 2048,
"host_reserve_mb": 768,
"container_mb": 1280
},
{
"plan": "4 GB VPS",
"total_mb": 4096,
"host_reserve_mb": 1024,
"container_mb": 3072
},
{
"plan": "8 GB VPS",
"total_mb": 8192,
"host_reserve_mb": 1536,
"container_mb": 6656
}
]host_reserve_mb cover the operating system, the Docker daemon and the extra space wey keep the box responsive under load. Wetin remain na container_mb, and na only that number you fit spend. The reserve dey increase with the plan, from 768 MB for the smallest box to 1536 MB for the biggest one, because bigger box dey run more containers, write more logs and need more page cache.
A 2 GB plan leave 1280 MB for containers. Use 512 MB of am for PostgreSQL and 128 MB for Traefik, and half of the memory don already finish. The remaining memory fit carry two small applications at roughly 256 MB each. Na real and useful server be this. But e no get enough space for Nextcloud and search cluster on top.
A 4 GB plan leave 3072 MB. That one fit carry database, reverse proxy, three applications and monitoring container at the same time. Na the smallest size wey make sense for anything wey matter to you, because the spare memory na wetin absorb bad deploy.
An 8 GB plan leave 6656 MB from its 8192 MB, and the limit usually move from memory to CPU or disk throughput. One type of container dey size itself from its configuration instead of load: local model server reserve KV cache according to its context window, so increasing Ollama's num_ctx fit add gigabytes to the budget before even one request arrive. If the calculation show say your stack no fit, buy the bigger plan instead of trying to tune around the limit: the real cost of a VPS explain wetin the extra gigabytes worth per month.
Two rules go keep the calculation correct. Set memory limit for every service, so one runaway process no fit carry the whole box down. Also leave the top part of the budget unused, because docker compose build and pg_dump both need memory at the worst time. Memory limits for Docker Compose get the syntax and the common traps.
Why my container dey exit with code 137?
Na kernel kill am. 137 na 128 plus 9, and signal 9 na SIGKILL. Container ask for more memory than wetin dem allow am, so out of memory (OOM) killer end am.
CONTAINER ID IMAGE STATUS
9f2c1a4d7b3e postgres:16 Exited (137) 4 minutes agoConfirm the cause instead of guessing:
docker inspect my-db | grep -i oomkilled
sudo journalctl -k | grep -i "out of memory""OOMKilled": true mean say container reach im own cgroup limit, and kernel log name the process wey e choose:
Memory cgroup out of memory: Killed process 2417 (postgres) total-vm:1284416kBNa the better case be that one, because the damage stop for one container. The bad case na container wey no get limit at all. Without limit, im ceiling na the whole machine, so memory leak for one service go use up host resources, then kernel go choose one victim based on size across the whole system. The log line no get the Memory cgroup prefix again and e read Out of memory: Killed process 2417 (postgres). The process wey e choose often na your database, while the container wey leak memory continue to run. Na why limit for every service matter pass the exact value of any single limit.
Swap change the timing, but e no change the arithmetic. Most VPS images ship with no swap. Check with swapon --show, wey no go print anything when swap no dey. Swap file give kernel somewhere to put cold pages, and this fit give you some minutes to notice problem.
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
free -hfree -h suppose show non-zero total for the Swap row now. Swap no add RAM. Box wey memory pressure dey affect constantly fit slow reach point wey you no fit SSH in to fix am, so treat swap as alarm buffer and correct the sizing.
Why UFW no dey block my published Docker port?
Because the traffic no dey reach the chain wey UFW dey guard. When you publish port with -p 5432:5432 or compose ports: entry, the daemon dey write DNAT (destination network address translation) rule inside nat table and accept rule inside e own DOCKER chain. Packet wey dey target container dey forward go that container instead of delivering am to host, so FORWARD path dey handle am and e no dey pass through INPUT rules wey UFW write.
You fit watch this happen for server:
sudo ufw status | grep 5432
sudo iptables -t nat -L DOCKER -n | grep 5432UFW fit print 5432 DENY IN Anywhere while nat table get DNAT tcp ... to:172.18.0.2:5432 rule for the same port. From another machine, nc -vz your.server.ip 5432 still dey connect. The database dey public internet and firewall dey say say e no dey.
The fix na to publish less. Containers for one compose project dey share network and fit reach each other with service name, so database wey only dey serve the application beside am no need ports: entry at all. When you want local access, bind the publish to loopback:
services:
db:
image: postgres:16
ports:
- "127.0.0.1:5432:5432"After docker compose up -d, nc -vz your.server.ip 5432 from outside go fail, while psql -h 127.0.0.1 -p 5432 for the box still dey work. For small stack wey dey healthy, na only reverse proxy dey publish anything, for 80 and 443. Why Docker published ports dey bypass UFW covers the DOCKER-USER chain for cases wey you must publish port and still filter am, while UFW firewall basics covers the host rules underneath.
Containers reboot bihindin disappear, why?
Na because nobody tell dem make dem come back. When you create container, e get restart policy no unless you set another one. So, reboot go leave am stopped, and daemon no go do anything. Reboot no dey rare for VPS: kernel updates from unattended upgrades, provider maintenance, and the OOM sequence above fit all end with one.
Two things must dey true. Daemon must start when system boot:
systemctl is-enabled dockerFor normal Ubuntu installation, this go print enabled. Then every service need restart policy:
services:
app:
image: ghcr.io/example/app:1.4
restart: unless-stoppedunless-stopped go bring container back after reboot, and e respect container wey you stop deliberately. always too go restart containers wey you stop on purpose whenever daemon restart, and this fit surprise you while you dey debug. Editing the file alone no enough, because restart policy dey set when you create container. Run docker compose up -d make e recreate the container, then check the active value:
docker inspect my-app | grep -A3 RestartPolicyThen reboot the server deliberately and run docker compose ps inside the project directory. If stack survive planned reboot, e go survive unplanned reboot too. If your stack need guaranteed startup order or one-time job during boot, systemd unit na better tool: start Docker Compose when system boot. To confirm say container wey come back dey really serve traffic, add Compose healthchecks.
Why my VPS disk full dey?
Because Docker dey keep everything until you tell am make e stop. Every image tag wey you don ever pull, every stopped container, every anonymous volume wey recreate leave behind, and every layer of build cache dey remain for disk. For root filesystem wey get 40 GB or 80 GB, wey normal for these plan sizes, this fit cause outage within months instead of years.
Full disk no dey look like crash. You go get no space left on device from container, from apt, from journald and from docker pull within the same hour. PostgreSQL go stop accepting writes. The box still dey up, so e harder to notice than reboot loop.
Check before you delete:
docker system df
df -h /docker system df dey divide the total into images, containers, local volumes and build cache, with RECLAIMABLE column beside each one. For box wey dey build its own images, build cache normally na the biggest line.
docker image prune -a
docker builder prune
docker system dfdocker image prune -a go remove every image wey no container dey use. docker builder prune go clear the build cache. Both safe while services dey run, because anything wey dey use dem go skip. But docker system prune --volumes no safe, because e dey delete every volume wey no container reference right now. Stack wey you stop for weekend get exactly this shape, and its database volume go disappear with am. Read bind mounts versus named volumes before you type that flag, and take backup first.
Container logs na the quieter way disk dey grow. Default json-file driver no get size limit, so one chatty container fit write gigabytes into /var/lib/docker/containers. Set limit for every container inside /etc/docker/daemon.json:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}Apply am with sudo systemctl restart docker. This go restart your containers, so choose the right time. The limit go apply to containers wey you create after the change. Recreate the ones wey dey run with docker compose up -d --force-recreate, then confirm:
docker inspect my-app | grep -A5 LogConfig
sudo du -sh /var/lib/docker/containersThe inspect output suppose show say max-size don set. If e empty, that container old pass the change and e still dey write without limit.
Habits wey go keep small Docker box healthy
None of dis one need dashboard or tool wey you must learn.
- Run
docker system dfanddf -h /for the first day of every month. Na two commands and thirty seconds, and you go see the trend long before e turn outage. - Give every service memory limit, including the ones wey you sure say small. The limit go turn host-wide outage into one container wey restart.
- Monitor the box from another place, so you go hear about memory or disk pressure before kernel take action. Uptime Kuma dey run for container and e dey idle around 95 MB.
- Back up volumes, no be containers. Container fit throw away, but volume no be so. restic backups for VPS cover schedule and restore test.
- Pin image tags for compose file and update dem on the day wey you choose. With
latest, the version wey you get from the nextdocker compose pullna the one wey release that morning.
Small VPS wey dey run Docker fit stay healthy for years when four numbers remain within range: memory budget, list of published ports, restart policy for each service, and free disk space. Everything else na the same Docker wey you already dey run for house.
FAQ
How much RAM I need to run Docker for VPS?
Docker by itself no dey cost plenty resource. The daemon and containerd together dey use around 100 MB, and na your containers go determine the remaining requirement. First reserve the host share: 768 MB for a 2048 MB box for the operating system, the daemon and headroom. This one leave 1280 MB for your containers. Database wey dey use 512 MB, reverse proxy wey dey use 128 MB, and two small applications fit enter there. Use docker stats --no-stream measure your own stack instead of trusting any published figure.
I fit run Docker for 1 GB VPS?
Yes, if na one or two light containers. Add swap file before you start. Roughly half of 1 GB box don finish after operating system and Docker daemon start, so small application and reverse proxy still fit get space. But database under real load no go fit. If you build images for box wey get that size, e fit fail or kill another process. Build for another machine, then pull the finished image.
UFW dey protect Docker container?
E no dey protect ports wey you publish. Docker dey write im own DNAT and forward rules. So packet wey target published container port go forward to the container instead of going to the host. This mean say INPUT rules wey UFW manage no dey see am. ufw deny 5432 fit dey active while that port still dey answer from internet. Publish to loopback with 127.0.0.1:5432:5432, leave internal services unpublished, or filter for DOCKER-USER chain.
My containers go restart after VPS reboot?
Only if you create dem with restart policy. Set restart: unless-stopped for each service. Run docker compose up -d so the containers recreate with the policy. Confirm say systemctl is-enabled docker print enabled. Then reboot intentionally and check docker compose ps. Restart policy wey you never test no be reliable restart policy.
How often I suppose prune Docker images?
Once every month dey enough for most small servers. You fit also run am whenever docker system df report reclaimable space wey you need. docker image prune -a and docker builder prune both safe while services dey run, because dem skip images and cache wey dey in use. Avoid docker system prune --volumes unless you know exactly which volumes no get reference, because e go delete data for any stack wey happen to dey stopped.