Back to blog

Deploy Like You Mean It

Docker, nginx, SSL, CI/CD — the unglamorous stuff that makes your app actually work in production.

You can write the cleanest code in the world. If it doesn't run in production, it doesn't matter. Deployment is where most projects fail — not because it's hard, but because people treat it as an afterthought.

Start with a VPS

Serverless and PaaS platforms are fine for prototypes, but for production apps where you need control, a VPS is hard to beat. $5-20/month gets you a server you actually own. You control the networking, the processes, the logs, everything.

I use Ubuntu LTS for everything. It's stable, well-documented, and has the largest community. The first thing I do on any new server: update packages, set up a non-root user, configure SSH keys, and enable the firewall.

Nginx as the front door

Every production app I deploy sits behind nginx. It handles SSL termination, static file serving, reverse proxying, rate limiting, and compression. One config file, and your app is production-ready.

The key insight: your application server shouldn't handle TLS or serve static files. Let nginx do what it's good at, and let your app focus on business logic.

SSL is not optional

There's no excuse for running HTTP in 2026. Let's Encrypt gives you free certificates with automatic renewal via Certbot. Or if you're behind Cloudflare, you get SSL for free with their tunnel. Either way, HTTPS is table stakes.

Process management

Your app needs to survive a crash, a reboot, and a deploy. PM2 handles all of this for Node.js apps — auto-restart, log management, cluster mode, and zero-downtime reloads. For Python, systemd services or Gunicorn with supervisor work well.

The rule: if you can't ssh into your server after a power outage and find everything running, your deployment is incomplete.

CI/CD: automate the boring stuff

Manual deployments are error-prone. A GitHub Actions workflow that runs tests, builds, and deploys on push to main takes 20 minutes to set up and saves hours of manual work over the life of a project.

Keep it simple. Most apps don't need Kubernetes or ArgoCD. A workflow that SSHs into the server, pulls the latest code, installs dependencies, and restarts the process is perfectly fine.

Monitor everything

If your app goes down at 3 AM, you should know about it before your users do. At minimum: uptime monitoring (UptimeRobot is free), error tracking (Sentry has a generous free tier), and log aggregation (even just PM2 logs piped to a file).

Deployment isn't glamorous work. But it's the difference between "I built a thing" and "I shipped a thing." And shipping is what matters.