Running Next.js on your own VPS is entirely practical: you get full control, flat server pricing, and no platform limits on execution time or regions. This guide uses Ubuntu 22.04/24.04, works for both the App and Pages routers, and assumes a plain next build app (no static export).
Prerequisites
A VPS with at least 1 GB RAM (2 GB is comfortable for builds), SSH access as root or a sudo user, your app in a git repository, and — for HTTPS — a domain with an A record pointing at the server's IP.
Step 1 — Install Node.js 22
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - sudo apt-get install -y nodejs git nginx node -v # v22.x
Step 2 — Clone and build
cd /var/www sudo git clone https://github.com/you/my-app.git cd my-app sudo npm ci sudo npm run build
If the build gets killed on a 1 GB server, add temporary swap first:
sudo fallocate -l 2G /swapfile && sudo chmod 600 /swapfile sudo mkswap /swapfile && sudo swapon /swapfile
Step 3 — Keep it running with PM2
PM2 restarts the app on crashes and on reboot. Next.js serves on port 3000 by default.
sudo npm install -g pm2 pm2 start npm --name my-app -- start pm2 startup systemd # prints a command — run it pm2 save
Step 4 — nginx reverse proxy
Create /etc/nginx/sites-available/my-app:
server {
listen 80;
server_name 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-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}sudo ln -s /etc/nginx/sites-available/my-app /etc/nginx/sites-enabled/ sudo nginx -t && sudo systemctl reload nginx
Step 5 — Free SSL with certbot
sudo snap install --classic certbot sudo certbot --nginx -d example.com
Certbot rewrites the nginx config for HTTPS and installs an auto-renewing Let's Encrypt certificate. Your app is now live at https://example.com.
Step 6 — Redeploys
Each update is a pull, build and restart. Save this as deploy.sh:
#!/usr/bin/env bash set -e cd /var/www/my-app git pull npm ci npm run build pm2 restart my-app
Note the trade-off: between pm2 restart and the app finishing boot there are a few seconds of downtime, and a failed build can leave the previous process serving a half-updated directory. Solving that properly means building in isolation and switching atomically — which is exactly what the automated route below does.
Gotchas worth knowing
- Set output: "standalone" in next.config to shrink what has to exist on the server at runtime.
- Environment variables: PM2 does not read .env.production automatically for npm start — Next.js does, at build and runtime, as long as the file sits in the app directory.
- next/image optimization uses sharp — npm ci installs it, but on minimal distros you may need build tools (sudo apt-get install -y build-essential).
- Open only ports 80/443 in your firewall; the Node port (3000) should stay internal.
The automated route
Everything above — the Docker build, nginx config, SSL, restarts — is what Pushify automates on the same servers. Connect the repo, pick the server (your own VPS or a managed one), and every git push builds in isolation and goes live with a zero-downtime blue-green switch. Framework detection covers Next.js out of the box.
Same server. One push.
git push → framework detected → Docker build → live with SSL, in under a minute.
Commands verified on Ubuntu 22.04/24.04 with Node 22 and Next.js 14/15, July 2026. Something not working? Email [email protected] and we'll fix the guide.