TutorialsAugust 4, 20264 min read

How to Deploy a Next.js App to a VPS

Build, run, and serve a production Next.js app on Ubuntu 24.04: PM2 process management, an Nginx reverse proxy, and free HTTPS.

NBy Nxeon

You do not need Vercel to run Next.js. A modest Ubuntu 24.04 VPS runs a production Next.js app comfortably, with full control over cost, environment, and data. This guide takes you from source code to a live HTTPS site using PM2 and Nginx.

What you will build

The flow is: Node runs the Next.js production server on a local port, PM2 keeps it alive, and Nginx terminates TLS and proxies traffic to it. First, make sure Node is installed — installing Node.js with NVM is the cleanest way.

Get your code onto the server

Clone your repository (or set up automated pushes with git-based deploys):

cd ~
git clone https://github.com/you/your-next-app.git app
cd app
npm install

Build for production

Next.js must be compiled before it can run in production mode:

npm run build

This creates the optimised .next build. Test the production server:

npm run start

By default it listens on port 3000. Confirm with curl http://127.0.0.1:3000 from another session, then stop it with Ctrl+C — PM2 will run it properly.

The Nxeon game-server control panel — live console, player slots, and TPS
The Nxeon game-server control panel — live console, player slots, and TPS

Keep it running with PM2

Install PM2 and start the Next.js server through it. The cleanest way is to point PM2 at the npm start script:

npm install -g pm2
pm2 start "npm run start" --name nextapp
pm2 save
pm2 startup

Run the sudo command pm2 startup prints so the app survives reboots. Our dedicated guide to deploying Node apps with PM2 covers logs, reloads, and clustering in more depth.

Set environment variables

Production apps need secrets and config. Create a .env.production file (or .env.local) in the project root with your variables — database URLs, API keys, NODE_ENV=production. Keep it out of git. Rebuild after changing any NEXT_PUBLIC_ variable, since those are baked in at build time.

Put Nginx in front

Create /etc/nginx/sites-available/app.example.com:

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 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";
    }
}

Enable and reload:

sudo ln -s /etc/nginx/sites-available/app.example.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

The Upgrade/Connection headers matter because Next.js uses WebSockets for features like fast refresh and some server actions. The full detail is in our Nginx reverse proxy guide.

Add HTTPS

Finish with a free certificate:

sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d app.example.com

Certbot rewrites the server block for TLS and sets up auto-renewal — see the Certbot guide for details.

Trim the production footprint

Next.js can emit a self-contained standalone build that bundles only the files needed to run, which starts faster and uses less disk. In next.config.js:

module.exports = { output: 'standalone' };

After npm run build, the .next/standalone folder contains a minimal server you can run with node .next/standalone/server.js — especially handy if you later containerise the app. A few production reminders that save headaches: set NODE_ENV=production so Next.js uses optimised code paths; run the build on a machine with enough RAM, since compiling is the memory-hungry part; and remember NEXT_PUBLIC_ variables are inlined at build time, so changing one means rebuilding, not just restarting.

Deploying updates

To ship a new version:

git pull
npm install
npm run build
pm2 reload nextapp

FAQ

Do I need a Node server, or can I export a static site?

If your app uses SSR, API routes, or server actions, you need the Node server as above. If it is fully static, next build with output: 'export' produces plain files you can serve directly — see hosting a static website with Nginx.

How much RAM does a Next.js app need on a VPS?

The build step is the memory-hungry part; 1–2 GB is fine for small-to-medium apps, more for large ones. If builds get killed, they ran out of memory — build locally or in CI and deploy the .next output.

Why does my app work locally but 502 on the VPS?

A 502 from Nginx means the upstream is not answering. Check pm2 status and pm2 logs nextapp — the app probably crashed or is on a different port than your proxy_pass.

Can I run several Next.js apps on one VPS?

Yes. Give each its own port, its own PM2 name, and its own Nginx server block with a different server_name. See running staging and production on one VPS.

Run Next.js your way on Nxeon Node.js hosting or a developer VPS — full root, NVMe SSDs, and free migration help to lift an app off a pricier platform.

#nextjs#nodejs#vps#deployment#nginx#seobatch

Deploy your first server in under a minute

Creating an account is free and takes no card details. You pay when you deploy — choose a billing term and pay from your wallet or by card at checkout.