DriversRecommendedOutdated drivers can make a good PC feel brokenScan driver issues before chasing fixes manually.Scan NowHalloween DealsAmazon USHalloween week deals: useful picks before month-endAmazon US: current deals, useful picks and tech finds.Check DealsWindows FixRecommendedWindows errors stealing your time? Find the fix fastScan stability, cleanup and performance issues.Fix Now×
FREEDOM251

Freedom251 › Blog › DevOps

How to Deploy Next.js on a VPS with Git, Nginx and PM2 (Production Setup, 2026)

By Freedom251 Team · · 12 min read

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

To deploy Next.js on a VPS, run the application as a production Node.js server, keep its code at a deliberate Git revision, supervise the process with PM2, and place Nginx in front as the public reverse proxy. The normal release path is: install a compatible Node.js runtime, check out the intended revision, install dependencies, run npm run build, start the app with npm run start under PM2, configure PM2 to restore its process list after reboot, and proxy the public hostname to the app’s local port through Nginx.

This guide focuses on that Node.js-server architecture. It deliberately leaves distribution-specific firewall rules, DNS records, certificate commands and service-file paths to your VPS operating system and chosen providers. Those details vary; the responsibilities and verification steps below do not.

As an Amazon Associate I earn from qualifying purchases.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What the production architecture does

A VPS deployment is easier to troubleshoot when every component has one clear job. Your repository contains source code and revision history. Git selects the exact revision installed on the server. Node.js executes the built Next.js application. PM2 keeps that Node process running, records its status and can restore it after a machine reboot when startup integration is configured. Nginx accepts public HTTP requests and forwards them to the private listener where Next.js is running.

Clients should normally reach Nginx, not the Next.js port directly. A reverse proxy can absorb malformed requests, enforce request-size and connection policies, apply rate limits and provide a single place for TLS termination when you choose a certificate solution. Next.js documentation specifically recommends putting a proxy such as Nginx in front of a self-hosted server rather than exposing the application directly.

Request flow

  1. A browser resolves your hostname to the VPS address.
  2. Nginx receives the request on its public listener.
  3. Nginx forwards the request to the local address and port on which Next.js is listening.
  4. Node.js runs the production server created by the Next.js build.
  5. The response travels back through Nginx to the client.

Git and PM2 are not substitutes for one another. Git answers “which code is deployed?” PM2 answers “is the selected process running?” Nginx answers “how do public requests reach it safely?” Keeping those concerns separate makes a failed release diagnosable.

Choose a Next.js deployment mode before configuring the VPS

Next.js documents several deployment modes. A VPS can host more than one, but the operational consequences differ.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Mode Feature coverage Infrastructure control What you operate
Node.js server Supports all Next.js features when the project is configured for them. Direct control of the runtime, filesystem, proxy and process manager. Node.js, dependencies, builds, PM2, Nginx, updates, logs and the VPS itself.
Docker Supports all Next.js features, subject to the image and runtime you build. Control through images, containers and the host. Image builds, registry or delivery, container lifecycle, networking, storage and the VPS.
Static export Limited to features that can be generated as static files; server-only behavior is unavailable. Often simpler because a web server can serve files directly. Export builds, static assets, cache behavior and the web server.
Platform adapter Varies by platform and adapter. Less host-level control, with more platform-managed components. Adapter constraints, platform settings and application configuration.

The rest of this article assumes the Node.js server mode because it matches a conventional Git, Nginx and PM2 VPS setup. Standalone output is an optional packaging choice inside that mode, not a requirement for every application.

Prerequisites and decisions to make first

Confirm the application contract

Open package.json and verify that the project has production scripts equivalent to:

{
  "scripts": {
    "build": "next build",
    "start": "next start"
  }
}

The documented production sequence is npm run build followed by npm run start. If your repository uses another package manager or a custom server, use its lockfile and documented commands instead of blindly substituting npm.

Select a compatible Node.js runtime

The current Next.js installation guide lists Node.js 20.9 as the minimum version. Treat that as the current documented minimum, not as a promise that every future release will use the same requirement. Check the requirement for the exact Next.js version in your project before pinning a runtime on the VPS. Use the same major runtime for local builds and production where practical so native modules and build output behave consistently.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Decide where mutable configuration lives

Environment values such as database credentials, signing keys, API tokens and the public hostname should be supplied through the VPS environment or a protected deployment mechanism. Keep secrets out of Git history. Separate values needed while building from values needed only when the server runs, and follow the environment conventions already used by your project.

Choose a local listener

Pick an unprivileged local port, such as 3000, and have Next.js listen on the loopback interface unless you have a specific reason to bind elsewhere. Nginx can then reach the app locally while the application port remains outside the public interface. The exact bind address and port should be declared in your PM2 configuration or start command so an update does not depend on an interactive shell.

How do I deploy a Next.js app on a VPS?

1. Prepare the VPS account and runtime

Create or select a non-root account for the application and make sure it can read the deployment directory and write only where the application needs to write. Install the Node.js version required by the project and verify it in the same account that will run PM2:

node --version
npm --version

Do not assume a shell profile loaded by your interactive login will also be loaded by a boot-time service. If you use a version manager, record the resolved Node.js path and test PM2 under the intended service user.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

2. Put the intended Git revision on the server

Clone the repository into a dedicated release or application directory, or fetch an existing checkout and select a tag, commit or branch that your release process has approved. A branch that moves between deployments is convenient, but a commit or immutable tag makes it easier to identify exactly what is running.

A basic update sequence might look like this after you have configured repository access:

git fetch --all --tags
git checkout <approved-revision>
git status

The placeholder above is a value you replace with your revision; keep deployment credentials, private keys and environment files outside the repository. PM2 also documents an SSH-based deployment configuration that can specify a host, user, key, repository, revision and lifecycle actions. That is an option for automating the same fetch, install, build and reload stages, but the credential design and release policy remain your responsibility.

3. Install dependencies reproducibly

Run the package manager that matches the committed lockfile. With npm, a production server commonly uses:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
npm ci

If the project intentionally requires development dependencies during its build, do not remove them before next build. Conversely, do not copy a local node_modules directory to the VPS: native modules may have been compiled for a different operating system or Node.js ABI.

4. Build the production application

Supply the build-time environment required by your application, then run:

npm run build

Inspect the command’s output and stop on errors. A successful build creates the production artifacts that next start serves. It does not prove that the database, external APIs, background jobs or runtime-only environment values are reachable; test those separately.

5. Define the PM2 application

An ecosystem file makes the process name, working directory, command and environment explicit. For example:

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
module.exports = {
  apps: [{
    name: "next-app",
    cwd: "/srv/next-app/current",
    script: "node_modules/next/dist/bin/next",
    args: "start -p 3000",
    env: {
      NODE_ENV: "production"
    }
  }]
};

You may instead set script to a project start script or use an npm entry with the appropriate arguments. The important points are that PM2 starts the same production command you tested, uses the intended working directory and receives an explicit production environment. Add only environment values that are safe for the process configuration; inject sensitive values through your protected server configuration.

Start and inspect the process:

pm2 start ecosystem.config.js
pm2 status
pm2 logs next-app

Visit the app locally from the VPS or use a local HTTP check against the chosen port. Confirm that the process remains online after a request and that the logs do not show missing environment variables, permission errors or failed upstream connections.

6. Configure PM2 to survive a reboot

PM2’s boot integration has two distinct steps: generate a startup script and save the process list that should be restored. Run:

pm2 startup
pm2 save

The first command prints a command tailored to the detected operating system and user. Run that printed command with the privileges it requests, then run pm2 save as the application user after the correct process is online. Verify the generated service, its user context and its Node.js path on your VPS distribution; do not assume they match a different operating system.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Reboot testing is worthwhile on a staging VPS or maintenance window. After the machine returns, check pm2 status, inspect logs and make a local request before declaring recovery complete. If you change Node.js under a version manager, PM2 documents that you should rerun the startup setup because the binary path may have changed, then save the desired process list again.

How should Nginx proxy requests to Next.js?

Configure a public Nginx server block for your hostname and proxy it to the local Next.js listener. The exact file location, service command and TLS configuration depend on your distribution and certificate choice, so treat this as a shape to adapt rather than a copy-paste universal recipe:

server {
    listen 80;
    server_name app.example.test;

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

Replace the example hostname and port, validate the configuration with your distribution’s Nginx test command, then reload Nginx through its service manager. Confirm both paths: a request from the VPS to the local port and a request through the public hostname. If the local request works but the public request fails, investigate Nginx’s configuration, listener, DNS and certificate layer separately.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Streaming and buffering

App Router streaming depends on every proxy and intermediary passing streaming responses through. Next.js’s self-hosting guidance gives X-Accel-Buffering: no as an Nginx-related approach. This is not the only possible configuration and it does not by itself guarantee end-to-end streaming: check buffering, timeouts and intermediaries across the complete path. Test with an endpoint that actually streams and observe whether chunks arrive incrementally instead of waiting for the entire response.

Do not expose the application listener unnecessarily

Binding Next.js to loopback and allowing Nginx to be the public entry point reduces accidental bypasses. If you intentionally bind to a network interface for another architecture, document the reason and apply the access controls appropriate to your VPS. Firewall and TLS commands are distribution- and provider-specific and should be selected from current documentation for that environment.

How do updates work with Git and PM2?

Every update should identify the revision, rebuild when source or dependencies require it, and reload the process through the same PM2 application definition. A manual npm-based flow is:

  1. Record the currently running revision and check PM2 status.
  2. Fetch the approved Git revision and check it out.
  3. Install dependencies from the lockfile.
  4. Apply the required build-time environment and run npm run build.
  5. Reload or restart the named PM2 application.
  6. Check PM2 status and logs, then exercise a health endpoint and an important user path.
git fetch --all --tags
git checkout <approved-revision>
npm ci
npm run build
pm2 reload next-app
pm2 status

Use pm2 restart when a full process restart is required; use pm2 reload only when its behavior is appropriate for your application and PM2 configuration. Do not describe a release as zero-downtime merely because a reload command completed. Confirm how your version of PM2 handles workers, in-flight requests, long-lived connections and failed starts.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

PM2’s documented SSH deployment feature can express host, user, key, repository, revision and lifecycle actions, including connecting, pulling and reloading. It does not choose your secret-storage model, branch policy, approval process or rollback design. Keep those decisions explicit. A practical rollback is to check out the last known-good revision, reinstall its dependencies if necessary, rebuild and reload, then verify the same health checks.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Optional packaging: Next.js standalone output

Next.js can generate a standalone package containing .next/standalone and a minimal server.js. This can reduce what you copy into a runtime directory, but it changes the packaging workflow rather than removing the need for Node.js, PM2 or Nginx.

By default, the standalone directory omits public and .next/static. If the standalone server must serve those assets, copy them into the locations expected by the generated server as part of your release process. Test image delivery, static files, route handling and environment loading after packaging; a build that succeeds is not proof that omitted assets are available.

Single-instance versus multiple-instance deployments

A single PM2 process on one VPS avoids many coordination problems, but it is still dependent on that machine. Adding workers, multiple VPS instances or ephemeral replacements introduces shared-state requirements.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • Next.js documents that the default cache is local, so multiple instances need an explicit cache-coordination review.
  • Multiple server instances need the same Server Functions encryption key.
  • Session storage, uploaded files, background jobs and rate-limit state may also need shared services, depending on the application.
  • Deployments must ensure that every instance receives the same revision and compatible environment before traffic is shifted.

Do not infer that a PM2 cluster or a second VPS automatically provides consistency or high availability. Define where state lives, how instances are drained and how a failed rollout is reversed.

Production verification checklist

  • Runtime: The installed Node.js version satisfies the requirement for the exact Next.js release, and PM2 uses that same binary.
  • Code: The server checkout reports the approved commit, tag or revision.
  • Build: The production build completes on the VPS with the required build-time configuration.
  • Process: PM2 shows the expected application name as online and logs are free of startup errors.
  • Reboot: The startup script and saved process list restore the application under the intended user.
  • Proxy: Nginx forwards the hostname to the correct local port and preserves the headers your application needs.
  • Streaming: If used, responses arrive incrementally through every proxy layer rather than being buffered unexpectedly.
  • Assets: JavaScript, CSS, images, fonts and any standalone copies are served successfully.
  • Updates: A tested revision can be installed, rebuilt, reloaded and rolled back without editing production files by hand.
  • Scale: If more than one instance exists, cache coordination and a shared Server Functions encryption key are deliberately configured.

Common failure symptoms and targeted fixes

“It works with next dev but not in production”

Development mode does not validate the production build path. Run npm run build and npm run start using production environment values, then inspect the PM2 logs for missing variables, unsupported Node.js features or runtime-only dependencies.

PM2 reports online, but requests fail

Check the local listener first: confirm the port, bind address and working directory. Then inspect Nginx’s upstream target and reload status. A process can be alive while listening on a different port than the proxy expects.

The app disappears after reboot

Confirm that pm2 startup was completed with the generated command, that pm2 save was run after the correct app was started, and that the service launches under the same user and Node.js path. Re-run startup setup after changing a version-manager-managed Node.js installation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Static files are missing after switching to standalone

Copy public and .next/static as required by the standalone packaging layout, then rebuild or redeploy and test asset URLs through Nginx. The standalone directory does not include those directories by default.

Streaming arrives as one delayed response

Check Nginx buffering and response headers, including the documented X-Accel-Buffering: no approach, then inspect any additional proxy, CDN or load balancer. Streaming must be preserved across the entire path, not just at the Node.js process.

Only one of several instances sees fresh data

Review the local default cache and move coordination to an appropriate shared design. Verify that every instance uses the same Server Functions encryption key and the same application revision.

What this setup does—and does not—standardize

The Git, Node.js, PM2 and Nginx division of labor gives you a repeatable production model without pretending that every VPS is identical. It does not select an operating-system package manager, dictate firewall syntax, create DNS records or choose a certificate authority. Those are environment decisions. Document them alongside the deployment so another operator can reproduce the server, verify a reboot and roll back a release without guessing.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

DevOpsGitNext.jsNGINXNode.jsPM2self-hostingVPS

Leave a Reply

Your email address will not be published. Required fields are marked *

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Recommended PC Tool
Recommended PC Tool
Crashes, No Sound, or Screen Glitches?Free driver scan
PC Slower Than It Used to Be?Free scan - under a minute

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.