21+ years in hosting · Jaipur, India · INR billing with 18% GST · 24/7 email support
Blog · WebJi® India

Deploy Next.js on a VPS

Quick answer

To deploy Next.js on a VPS, install Node.js 22 or 24 LTS on Ubuntu, run npm ci and npm run build, start next start under PM2 on 127.0.0.1:3000, then put Nginx in front and add HTTPS with Certbot. Only a static export can skip the Node process.

For developers moving a Next.js app off Vercel or shared hosting onto their own Ubuntu VPS with a repeatable build and deploy routine.

✓ In business since 2005
✓ INR + GST billing
✓ 24/7 Email Support — avg reply < 60 min
GuideWebJi®
knowledge
Read time
4 min
Sections
6
Updated
14 Nov 2026
Written by
WebJi® team

Why Next.js needs a VPS rather than file hosting

Any Next.js app that renders on request, uses route handlers, middleware or server actions runs as a Node.js process, so it needs a server where that process can stay running. Only a full static export can live on plain file hosting.

Next.js build modes and where each can be hosted
Build modeWhat runs in productionFile / shared hostingVPS
next build + next startNode server on a port (default 3000)NoYes
output: 'standalone'A trimmed server.js with only needed packagesNoYes, smaller footprint
output: 'export'Nothing; HTML, CSS and JS files onlyYesYes, served by Nginx

If you want the server without running it yourself, WebJi® Next.js hosting is the managed route, and Vercel alternatives in India compares platform options. The rest of this guide is the do-it-yourself path on Ubuntu 24.04.

Preparing the Ubuntu VPS: Node.js, firewall and swap

Install a current LTS release of Node.js, allow only SSH, HTTP and HTTPS through the firewall, and add swap if the VPS has under 4 GB of RAM. Next.js 16 needs Node.js 20.9 or newer; Node 20 reached end of life in April 2026, so use Node 22 or 24 LTS.

sudo apt update && sudo apt upgrade -y

# Node.js 24 LTS from NodeSource
curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -
sudo apt install -y nodejs
node -v && npm -v

# firewall: port 3000 stays closed to the internet
sudo ufw allow OpenSSH
sudo ufw allow 80,443/tcp
sudo ufw enable

# 2 GB swap so "next build" is not killed for lack of memory
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/fstab

Allowing OpenSSH before ufw enable stops you locking yourself out. Log in with an SSH key rather than a password, as shown in generating an SSH key on Ubuntu.

Building the Next.js app on the server

Clone the repository, install exactly the locked dependencies with npm ci, place the production environment file, and run npm run build. Do not start anything until the build exits without errors.

sudo mkdir -p /var/www/app && sudo chown $USER: /var/www/app
git clone https://github.com/you/your-app.git /var/www/app
cd /var/www/app
nano .env.production      # API keys, database URL; never commit this file
npm ci
npm run build

Variables prefixed NEXT_PUBLIC_ are baked into the browser bundle at build time, so changing them later needs a rebuild. Server-only variables are read when the process starts.

Running Next.js with PM2 so it survives crashes and reboots

PM2 keeps next start running, restarts it after a crash and brings it back after a reboot once you register it with pm2 startup and pm2 save. Binding to 127.0.0.1 keeps port 3000 reachable only through Nginx.

sudo npm install -g pm2

# /var/www/app/ecosystem.config.js
module.exports = {
  apps: [{
    name: 'nextapp',
    cwd: '/var/www/app',
    script: 'node_modules/next/dist/bin/next',
    args: 'start -p 3000 -H 127.0.0.1',
    env: { NODE_ENV: 'production' }
  }]
};

pm2 start ecosystem.config.js
pm2 startup            # run the command it prints
pm2 save
curl -I http://127.0.0.1:3000

A 200 from curl and online in pm2 status mean the app is running. With output: 'standalone', copy the static assets first (cp -r public .next/standalone/ && cp -r .next/static .next/standalone/.next/) and point script at .next/standalone/server.js with PORT and HOSTNAME set in env.

Putting Nginx in front of Next.js as a reverse proxy

Nginx listens on ports 80 and 443 and forwards every request to the Node process on 127.0.0.1:3000, passing the original host, client IP and protocol. Proxy everything, including /_next/, because next start serves its own hashed assets with long cache headers.

sudo apt install -y nginx

# /etc/nginx/sites-available/nextapp
server {
    listen 80;
    server_name example.in www.example.in;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        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;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

sudo ln -s /etc/nginx/sites-available/nextapp /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx

A 502 Bad Gateway at this point means the Node process is down or listening on a different port; check pm2 logs nextapp. Compression and HTTP/2 tuning are in enabling gzip on Nginx and enabling HTTP/2 on Nginx.

Adding the domain and a free HTTPS certificate

Point the domain's A record at the VPS IPv4 address, wait until dig +short example.in returns it, then let Certbot's Nginx plugin issue the certificate and add the HTTPS redirect.

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.in -d www.example.in
sudo certbot renew --dry-run

Certbot installs a timer that renews the certificate automatically before its 90-day expiry; the dry run proves renewal will work. Troubleshooting and wildcard certificates are covered in Certbot SSL on Nginx.

Shipping updates without taking the site down

Pull, install, build, and reload PM2 only if the build succeeds; chaining the commands with && stops a broken build from replacing the live app.

cd /var/www/app && git pull && npm ci && npm run build && pm2 reload nextapp
  • Logs: pm2 logs nextapp for the app, /var/log/nginx/error.log for the proxy.
  • Build memory: if the build is "Killed", the VPS ran out of RAM; add swap or build in CI and copy the output.
  • Busy sites: building into the live .next folder can break in-flight requests; build in a second folder and switch a symlink for true zero downtime.
  • Disk: old builds and logs add up; pm2 install pm2-logrotate keeps PM2 logs in check.

What size VPS does a Next.js app need?

The build, not the running app, sets the memory floor: 2 GB RAM with swap builds a small site, while 4 GB is comfortable for a typical business app with images and several dynamic routes. WebJi®'s sample VPS-Start configuration is 2 vCPU, 4 GB RAM and 60 GB NVMe; every VPS is quoted in INR before payment, with 18% GST added. For a React single-page app with no server rendering, React hosting is the simpler fit.

FAQ

Frequently asked questions

Can I deploy Next.js on cPanel shared hosting?

Only as a static export, unless the host offers a Node.js app manager with enough memory to build. A shared plan cannot keep next start running reliably. Use output: 'export' for a purely static site, or a VPS for anything rendered on the server.

Is Docker better than PM2 for Next.js on a VPS?

Docker gives reproducible builds and easy rollbacks, and pairs well with output: 'standalone'. PM2 is simpler for one app on one server. Choose Docker when several services or developers share the machine; what a Docker container is explains the trade-off.

Does next/image work on a self-hosted VPS?

Yes. next start includes the image optimiser, which resizes and caches images on the server. It uses CPU and disk, so busy image-heavy sites may prefer an external image CDN configured as a custom loader.

How do I run two Next.js apps on one VPS?

Give each app its own port (3000, 3001), its own PM2 entry and its own Nginx server block with a different server_name. Certbot can then issue a certificate for each domain separately.

Checked 14 November 2026 against the Next.js self-hosting documentation · Reviewed by the WebJi® team, Jaipur.

WebJi® since 2005

Ready to get started with WebJi®?

Join 12,000+ businesses across India and overseas. INR pricing, 18% GST shown before payment and 24/7 email support in Hindi and English — average first reply under 60 minutes.