Noah writes practical guides for Next.js deploys, AI self-hosting (Ollama, n8n), and PaaS panels like Coolify and Dokploy. His focus is getting apps from git clone to HTTPS with the fewest moving parts.
Target architecture
Browser → Nginx (TLS) → Next.js on localhost:3000 managed by PM2. Optional: Postgres/Redis on the same VPS or managed elsewhere.
OrbitHost Ryzen NVMe VPS in FRA/AMS keeps TTFB low for European users. For git-push workflows later, jump to Coolify or Dokploy on the same base image.
Install Node.js 22
Install Node from NodeSource (or use fnm/nvm for per-user versions). Enable the firewall for SSH and HTTP/S only.
sudo apt update && sudo apt install -y curl nginx
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs
node -v && npm -v
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enableClone, install, and build
Deploy as a non-root user. Use `npm ci` when you have a lockfile. Set production env vars in a `.env.production` or PM2 ecosystem file — never commit secrets.
sudo useradd -m -s /bin/bash deploy
sudo -u deploy -i
mkdir -p ~/apps && cd ~/apps
git clone https://github.com/your-org/your-next-app.git app
cd app
npm ci
npm run buildRun with PM2
PM2 keeps the process alive and can start on boot. Point it at `node_modules/next/dist/bin/next start` or your standalone server entry.
sudo npm i -g pm2
cd ~/apps/app
pm2 start npm --name "next-app" -- start
pm2 save
pm2 startup systemd -u deploy --hp /home/deploy
# follow the command pm2 prints, then:
pm2 statusNginx reverse proxy
Proxy `/` to `http://127.0.0.1:3000` and forward common headers. Disable buffering quirks for streaming responses if you use them.
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
}TLS with Certbot
Point DNS A record at the VPS, enable the site, then run Certbot. Renewals are handled by the certbot timer on Ubuntu.
sudo ln -s /etc/nginx/sites-available/next-app /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d app.example.comZero-downtime updates
A simple loop: `git pull`, `npm ci`, `npm run build`, `pm2 reload next-app`. For zero-downtime with heavier traffic, use blue/green directories or container deploys.
Watch memory during `next build` on small VPS plans — add swap as a safety net or build in CI. OrbitHost `/vps-for-nextjs` is sized for this stack; Docker users can swap PM2 for Compose when ready.
- Keep NODE_ENV=production
- Reload PM2 after successful builds only
- Monitor with pm2 logs / journalctl
- Back up .env separately from git
FAQ
PM2 or Docker for Next.js?
PM2 is simple for a single Node app. Docker/Coolify/Dokploy scale better when you add workers, Redis, and preview environments. Start with PM2 if you want fewer moving parts.
Standalone output?
Setting `output: 'standalone'` in next.config shrinks what you ship to the server. Copy `.next/standalone`, static assets, and public/ as Next documents.
Which Node version?
Use an Active LTS that your Next version supports — Node 22 is a solid default on Ubuntu 24.04 via NodeSource or fnm.
Do I need a large VPS?
Builds are CPU-hungry; runtime is often fine on 2–4 GB. Build on CI and rsync artifacts if the VPS is small.
