Docker vs Bare Processes on a VPS: When to Use Each
Do you need Docker on a VPS or can you run bare processes? Here is when containers earn their overhead and when a plain systemd service is simpler and faster.
Use Docker on a VPS when you are running several services together or when reproducible builds matter, and run bare processes when you have a single app and want the least moving parts. Both are legitimate. The dogma that everything must be containerized is wrong, and so is the reflex that Docker is always overhead. The right answer depends on how many things you are running and how much you value a clean, repeatable environment. I use both across my portfolio, and I pick per app.
When does Docker earn its place?
Docker earns its keep the moment you have more than one service that needs to run together. A web app, a database, a worker, and a reverse proxy is four processes with dependencies between them. Docker Compose describes all four in one file, wires up a private network so they find each other by name, and starts the whole stack with one command. That coordination is real value, and it is why I say Docker Compose is enough for a side project in production.
The other big win is reproducibility. A container bundles your app with its exact dependencies, so the thing that ran on your laptop is the thing that runs on the server, down to the library versions. No "works on my machine." No fighting the system Python or the wrong Node version on the box. You rebuild the image and you know precisely what is inside it. For anything with a non-trivial dependency tree, that alone justifies the container.
Containers also give you clean isolation and resource limits. You cap each service's memory and CPU, so a runaway worker cannot take down the web app sharing the box. That matters when you run staging alongside production on one VPS or several apps on the same machine.
When are bare processes the better call?
Run bare when you have one simple app and Docker would just add a layer between you and the thing. A static site, a single Go binary, a small script behind a systemd service: containerizing these buys you almost nothing and costs you a build step, an image to manage, and a daemon to keep running. A systemd unit that runs your binary with Restart=on-failure is simpler, starts faster, and has fewer parts to break.
Bare processes also win on raw resource footprint at the tiny end. There is no image layer overhead, no daemon, no container networking. On a very small box running one thing, that leanness is real. And a single binary deployed as a systemd service is genuinely easy to reason about: the unit file says what runs, the journal has the logs, and there is no container abstraction to peer through when something goes wrong. This is the same supervision model I use for background workers on a VPS.
The honest tradeoff
The tension is between reproducibility and simplicity. Docker gives you a guaranteed environment at the cost of a build-and-image workflow. Bare processes give you fewer moving parts at the cost of depending on what is installed on the host. Which one wins is not ideological, it is about your specific app.
A useful test: count your services and count your dependencies. One service with few dependencies, lean toward bare. Multiple services, or a messy dependency tree you do not want to reproduce by hand on every box, lean toward Docker. Do not containerize a shell script to feel modern, and do not hand-manage five interdependent services to avoid learning Compose. Match the tool to the shape of the work, the same way I approach sizing the box to the workload.
A pragmatic default for a portfolio
Across a portfolio, I default to Docker Compose because consistency across many boxes is worth more than squeezing the last bit of overhead out of any single one. When every app is a Compose file, my deploy, my backups, and my runbook are identical everywhere, which is the whole point of one runbook for twenty apps. The uniformity compounds. A new box is set up the same way as every other box.
But when a single tiny service does not fit that mold, I run it bare and do not feel guilty. The goal is not container purity, it is a stack I can operate cleanly and cheaply on HostSSH. Pick Docker when coordination and reproducibility pay off, pick bare processes when simplicity wins, and stop treating either one as the only correct answer. Both are tools. Use the one that fits.