The Unpopular Opinion: Docker Isn't Always the Answer
In an era where Docker has become the de facto standard for deployment, I made a conscious decision to deploy my Next.js applications without containers. Before you close this tab thinking I'm stuck in 2015, let me explain why this approach might actually be the smarter choice for many real-world scenarios.
My Story: Working with Indonesian SMBs
When I started working with small and medium businesses (UMKM) in Indonesia, I quickly realized that the "Docker everything" mentality doesn't always fit. My clients typically use:
- VPS with 512MB to 2GB RAM
- Limited budgets (around $5-15/month for hosting)
- Simple deployment needs without complex orchestration
Running Docker on a 512MB VPS? That's like trying to run a marathon in flip-flops. The overhead alone would consume most of the available resources.
Why I Chose the Manual Route
1. Resource Efficiency
Docker daemon itself consumes memory. On a low-spec VPS, every megabyte counts. Without Docker:
- No container overhead
- No Docker daemon running 24/7
- Direct process management with PM2
For a simple Next.js app, this can mean the difference between smooth performance and constant crashes.
2. Simplicity for Small Teams
Not every project needs enterprise-grade infrastructure. When you're a solo developer or working with a small team:
# This is all you need to deploy
git pull
npm run build
pm2 restart nextapp
No need to rebuild images, push to registries, or manage container networks. It just works.
3. Faster Debugging
When something goes wrong (and it will), debugging is straightforward:
# Check your logs directly
pm2 logs nextapp
# Monitor in real-time
pm2 monit
No need to docker exec into containers or parse complex container logs.
The Complete Setup: What I Use
After deploying dozens of Next.js apps this way, here's my battle-tested stack:
| Component | Tool |
|---|---|
| Process Manager | PM2 |
| Reverse Proxy | NGINX |
| SSL | Let's Encrypt (Certbot) |
| DNS & CDN | Cloudflare |
| Monitoring | UptimeRobot + BetterStack |
The Architecture
[User] → [Cloudflare CDN] → [NGINX :443] → [Next.js :4300]
Simple, efficient, and rock-solid.
Key Optimizations I've Learned
1. Swap File for Low-Memory VPS
This single trick has saved countless deployments:
fallocate -l 2G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstab
Without this, npm run build on a 1GB VPS will crash. With it, builds complete successfully (just a bit slower).
2. PM2 Auto-Restart on Reboot
Don't forget this crucial step:
pm2 startup
pm2 save
Your app will automatically restart after server reboots—no manual intervention needed.
3. Cloudflare Full (Strict) SSL
After setting up Let's Encrypt, configure Cloudflare for Full (Strict) SSL mode. This ensures end-to-end encryption without the "flexible" SSL security holes.
When Should You NOT Use This Approach?
Let me be honest—this isn't for everyone:
- ❌ Microservices architecture → Use Docker + Kubernetes
- ❌ Large teams with CI/CD pipelines → Containerization helps consistency
- ❌ Multi-environment deployments → Docker's "works on my machine" benefit shines here
- ❌ Horizontal scaling needs → Container orchestration is your friend
When This Approach Shines
- ✅ Single Next.js app on a budget VPS
- ✅ Small teams or solo developers
- ✅ Clients with limited hosting budgets
- ✅ Quick prototypes that need fast deployment
- ✅ Legacy systems where Docker isn't an option
The Full Guide
I've documented my entire deployment process in a GitHub repository that you can fork and adapt:
The guide covers:
- VPS initial setup
- Domain configuration with Cloudflare
- Next.js deployment with PM2
- NGINX reverse proxy configuration
- Free SSL with Let's Encrypt
- Monitoring and alerting setup
- Low-memory optimization tricks
Conclusion
The best technology choice is the one that fits your context. Docker is amazing, but it's not a silver bullet. For many real-world projects—especially in emerging markets where budget VPS hosting is common—the traditional deployment approach is not just viable, it's often optimal.
Don't let the hype dictate your architecture decisions. Understand your constraints, evaluate your options, and choose what works best for your specific situation.
Have questions about VPS deployment or want to share your own experiences? Feel free to reach out via the contact form or connect with me on GitHub.
