Guide

Deploy Next.js to your own server

The complete manual path — Node 22, PM2, nginx, free SSL — on any Ubuntu VPS. About 30 minutes the first time. (There's a one-command shortcut at the end.)

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.

Deploy Next.js with Pushify

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.