deploy · tutorial · vps
Deploy Next.js on Hetzner $5 by Dinner Tonight
CX22 to production: server setup, Tailscale mesh, Cloudflare Tunnel, PM2, swapfile, and the six gotchas with exact fixes.

"just get a VPS" hides forty small decisions
Every "ditch Vercel" thread ends with "just get a Hetzner box" and skips the part where founders burn a weekend: which image, what firewall, how does HTTPS work with no open ports, why does the build die with Killed, why does Google OAuth 400, why does SQLite segfault. The exit threads that succeed all share one trait — someone wrote down the boring parts.
This is that write-down, matching BoringPush's VPS guide and the Next.js stack that expects it.
The setup: box to HTTPS in an afternoon
1. The box. Hetzner CX22 (2 vCPU, 4GB RAM — verify current specs/pricing), Ubuntu LTS, SSH key at create time. Add a 2GB swapfile immediately — Next.js builds spike past small RAM and die with Killed otherwise:
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/fstab2. Zero open ports. Tailscale up with --ssh, then close public SSH and web ports entirely — Cloudflare Tunnel takes visitors through an outbound-only connection, Tailscale carries your admin traffic:
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up --ssh
sudo ufw delete allow OpenSSH
sudo ufw allow in on tailscale03. HTTPS without certbot pain. cloudflared tunnel → localhost:3000, hostname in the Zero Trust dashboard, free SSL + DDoS at the edge. PM2 keeps Next alive (pm2 reload = zero-downtime deploys), and git push production main becomes the entire CI: local gate runs, server builds natively for Linux, traffic swaps. Ship from anywhere on this Next.js stack — laptop, phone, cafe wifi, same command.
The six gotchas (all hit in production, all fixed)
| Gotcha | Symptom | Exact fix |
|---|---|---|
| Keyboard-layout prompt hangs setup | server-setup.sh stops asking country |
Type 35 (English US); export DEBIAN_FRONTEND=noninteractive forever |
| Deploy hangs at "Connecting…" | First Tailscale SSH needs browser approval | ssh coder@<TAILSCALE_IP> once interactively, approve, ssh-copy-id |
| Next.js "Internal Server Error", logo loads | MODULE_NOT_FOUND middleware manifest |
Build never ran: npm run build then pm2 reload |
OOM Killed on build |
1–2GB box dies compiling | 2GB swapfile above (already done if you followed step 1) |
| Google OAuth 400 redirect mismatch | Stale site address in the production settings plus a cached environment | Register the exact callback URI, then bp secret sync (reloads the app) |
| SQLite segfault on login | Node 20 + Ubuntu 24.04 ABI clash | Node 22 LTS + npm rebuild better-sqlite3 --build-from-source |
FAQ
Hetzner vs DigitalOcean vs Linode?
Interchangeable for this shape — pick by region latency to your users and current promo pricing (all hover $4–6 for 2vCPU/4GB; verify). The setup is provider-agnostic by design.
Do I need Docker for this?
No. Native PM2 + git-push deploys are simpler and use less RAM.
Docker enters when you need reproducible multi-service topologies — most SaaS never does.
What about staging?
Second $5 box, or same box with a second PM2 process on another port behind a staging. tunnel hostname. Cheap enough that there's no excuse for cowboy deploys.
How do backups work without a managed DB?
Daily consistent database snapshots plus hourly log trimming, both built in, plus volume snapshots at the provider for disasters. Single-file restores: copy back, restart.
IPv6, firewalls, fail2ban — needed?
Tailscale makes most of it moot: no public SSH means nothing to brute-force. Keep UFW default-deny, Cloudflare in front, and spend the saved hours on the product.
+ all the boring stuff (analytics, auth, SQLite ↔ Supabase, full marketplace, webhooks)
Command from your phone.
Built so autonomous AI agents build what you want without breaking what's already paying you.
- Built-in analytics — cookie-free mode, $0 forever, no PostHog bill
- SQLite ↔ Supabase: one setting, same field names
- Full digital marketplace & feedback boards included
- 3 payment rails: Stripe, LemonSqueezy & Dodo Payments
- Agent fences: lint gate, read-only data access, auto-rollback
- Ship from your phone via SSH & WireGuard/Tailscale in under a minute
$199
Get BoringPushOne-time payment · Lifetime updates · Unlimited projects.
Keep reading


