← Blog
devopsdeploypm2indie devproduct

My Production Server Doesn't Use Containers

3 April 2026

My Production Server Doesn't Use Containers

There's a moment in every personal project where you wonder if you should containerize everything.

You've read about Docker. You know Kubernetes, or at least you've heard about it enough to know "it's not for this project." You've seen elegant deploy configurations with compose files, health checks, restart policies. Then you look at your server — a twenty-euro-a-month VPS running Ubuntu — and wonder if you're doing things the wrong way.

The answer, in my case, is no. And it took me a while to get there without guilt.

What's Running in Production

ReD Sposi is an app for my wedding. The backend is an Express server on Node.js. The landing page is Next.js. The admin panel is Vite + React. Three processes, one server, one domain with subdomains.

Barba Studio is a booking app for barbershops. Another Express server, another process.

Gestionale Molinari is my internal accounting system. More Express.

Everything runs on a Ubuntu VPS, managed with PM2. Nginx in front as a reverse proxy. Let's Encrypt certificates via Certbot. Deploy via SSH + git pull + pm2 reload.

ssh server
cd /var/www/red-sposi-api
git pull
npm install --production
pm2 reload red-sposi-api

Done. There's nothing else.

Why Not Docker

It's not that Docker is wrong. Docker is the right tool for many contexts: reproducible development environments, deploy on managed cloud infrastructure, teams with multiple people who need to align their environments, applications that scale horizontally.

For my projects, none of these conditions apply.

I'm the only developer. The development and production environments diverge a little, but little enough not to cause real problems — I use the same Node versions, the same MongoDB schema, the same environment variables. When something breaks, I know in ten minutes and I'm already at the laptop.

Scale isn't a problem. ReD Sposi has a few hundred guests. Barba Studio has real users but no traffic spikes that a single process can't handle. Gestionale Molinari is just me.

Containerizing these services wouldn't add reliability — it would add layers of abstraction to understand, maintain, and debug when something goes wrong at three in the morning.

What PM2 Does That's Enough

PM2 handles three fundamental things I actually need:

Automatic restart. If a process crashes, PM2 restarts it. It's not as sophisticated as an orchestrator, but it covers the most common case — an unhandled error that crashes the process — without needing anything else.

Log management. pm2 logs gives me logs for all processes in one place. pm2 logs red-sposi-api --lines 100 gives me the last hundred lines of a specific process. That's enough.

Reload without downtime. pm2 reload restarts the process gracefully — waits for active connections to close before replacing the process. For applications with a few hundred non-simultaneous users, it works.

┌────────────────────┬────┬─────────┬──────┬──────┬────────┐
│ name               │ id │ status  │ cpu  │ mem  │ uptime │
├────────────────────┼────┼─────────┼──────┼──────┼────────┤
│ red-sposi-api      │ 0  │ online  │ 0%   │ 85mb │ 12D    │
│ red-sposi-landing  │ 1  │ online  │ 0%   │ 120mb│ 12D    │
│ red-sposi-admin    │ 2  │ online  │ 0%   │ 55mb │ 12D    │
│ barba-studio-api   │ 3  │ online  │ 0%   │ 72mb │ 45D    │
│ gestionale         │ 4  │ online  │ 0%   │ 61mb │ 7D     │
└────────────────────┴────┴─────────┴──────┴──────┴────────┘

That's all I see when I open the server. It's readable, immediate, and sufficient.

The Hidden Cost of Complexity

There's a real cost to adopting tools more sophisticated than what you need. It's not just the initial configuration time — it's the permanent cognitive load.

Every layer of infrastructure you add is a layer you need to understand when things go wrong. A container that won't start, a network bridge that won't route traffic, a volume that won't mount — these problems have solutions, but they require time and attention at moments when you'd rather not spend them.

For a single developer managing multiple products in parallel, infrastructure simplicity isn't a tradeoff — it's a multiplier. The simpler the deploy, the faster the iteration cycle, the lower the threshold for shipping a fix.

When I'll Change My Mind

I'll change my deploy stack when I have a concrete reason. Some examples of concrete reasons:

  • A product starts receiving traffic spikes that require horizontal scaling
  • I join a team that already uses containers and I need to align
  • I need staging and production environments that are perfectly identical to reproduce a hard bug
  • The cost of a service outage exceeds the cost of more robust infrastructure

None of these conditions apply today. When they do, I'll adopt the right tool.

In the meantime, pm2 reload takes me two seconds.