Linux VPS

Deploy a Next.js app on a Linux VPS (next start or standalone)

Build and run a Next.js app in production on a Linux VPS with next start or the smaller standalone output, keep it alive with PM2 and serve it through Nginx.

IntermediateLinux VPS2 min read

Next.js needs a Node.js server whenever your app uses server rendering, API routes, middleware or image optimisation. On a VPS you build the app once, start it with Node.js and put a web server in front. This guide covers both the classic next start method and the leaner standalone output.

Before you start

Get the code onto the server

  1. Log in as your app user and clone the project:
    cd ~
    git clone https://github.com/you/myapp.git
    cd myapp
  2. Create the production environment file with your real values (see Node.js environment variables):
    nano .env.production

Method 1: build and run with next start

  1. Install dependencies exactly as locked and build:
    npm ci
    npm run build
  2. Test the production server:
    npx next start -p 3000 -H 127.0.0.1
    Run curl -I http://127.0.0.1:3000 in a second session, then stop it with Ctrl+C.
  3. Run it under PM2:
    pm2 start npm --name myapp -- start -- -p 3000 -H 127.0.0.1
    pm2 save

Method 2: standalone output

Standalone mode copies only the files your app needs into .next/standalone, so you do not need the full node_modules at runtime. It is ideal for small VPS plans and Docker.

  1. Enable it in next.config.js:
    module.exports = {
      output: 'standalone',
    };
  2. Build, then copy the static assets next to the server (Next.js does not copy them for you):
    npm ci
    npm run build
    cp -r public .next/standalone/
    cp -r .next/static .next/standalone/.next/
  3. Start the generated server with PM2:
    cd .next/standalone
    PORT=3000 HOSTNAME=127.0.0.1 pm2 start server.js --name myapp
    pm2 save

Warning: If pages load without CSS or images in standalone mode, you forgot to copy public and .next/static. Repeat that step after every build.

Put Nginx in front

Proxy your domain to 127.0.0.1:3000 as shown in Node.js reverse proxy with Nginx, Apache or LiteSpeed, then add HTTPS with SSL for Node.js apps.

Deploy updates

cd ~/myapp
git pull
npm ci
npm run build
pm2 reload myapp

For standalone builds, copy the static folders again before reloading. To automate this, see Deploy to a VPS with GitHub Actions.

Troubleshooting

  • Build killed or JavaScript heap out of memory — add swap or more RAM, or build on your computer/CI and upload the result. See Fix common Node.js errors.
  • EADDRINUSE — something already uses port 3000. Run pm2 list and stop the old copy.
  • Old content after deploy — you rebuilt but did not reload PM2.

Next steps

Was this guide helpful?

Still stuck?

Ask MdmHost AI for a quick answer, or open a ticket and our team will take a look. We are here 24/7.