iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
To deploy Next.js on a VPS, run the application with Node.js, manage its source and releases with Git, supervise the production process with PM2, and put Nginx in front as a reverse proxy. The reliable production sequence is: check the project’s Node.js requirement and scripts, check out a known Git revision, install dependencies, run npm run build, start the production server under PM2, configure PM2 to restore it after reboot, and route public traffic from Nginx to the local Node listener.
This guide centers on a self-managed Node.js deployment. Your VPS distribution, DNS provider, firewall, domain, and TLS certificate method are not specified, so the commands and Nginx example are deliberately distribution-neutral. Treat the operating-system service names, package-manager commands, certificate steps, and network policy as choices you must adapt to your environment rather than as one universal script.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallWhat the production architecture does
Each component has a separate responsibility. Keeping those boundaries clear makes failures easier to diagnose and prevents a common mistake: treating Git, Node.js, PM2, and Nginx as interchangeable parts of one command.
- Git stores the application source, lockfile, configuration templates, and revision history. A deployment should identify the exact revision intended to run.
- Node.js executes the built Next.js application. A regular Next.js Node deployment uses the project’s production start script rather than the development server.
- PM2 supervises the Node process. It can restart a crashed process and, when startup integration and a saved process list are configured, restore the process after a machine reboot.
- Nginx accepts public HTTP or HTTPS connections and proxies requests to the application’s private listener, usually bound to localhost. Next.js recommends a reverse proxy instead of exposing the Next.js server directly to the internet.
browser or API client
|
v
Nginx (public listener)
|
v
127.0.0.1:3000 <-- PM2 supervises --> Node.js / Next.js
^
|
checked-out Git revision
Nginx is more than a traffic relay. A proxy can help handle malformed requests, slow-connection attacks, request-size limits, and rate limiting before those requests reach the application. It also provides a natural place to terminate TLS, although the exact certificate workflow depends on your operating system and certificate provider.
#1 Best Overall
Choose the deployment mode before configuring the VPS
Next.js documents several deployment modes. A VPS gives you the most direct control when you choose the Node.js server mode, but it also leaves you responsible for the operating system, process supervision, proxy, updates, and recovery.
| Mode | Feature support | Infrastructure control | Operational responsibility |
|---|---|---|---|
| Node.js server | Supports all Next.js features when the application and runtime are configured correctly. | High: you control the VPS, Node process, proxy, and release layout. | You manage updates, monitoring, restarts, DNS, TLS, backups, and hardening. |
| Docker | Supports all Next.js features, subject to the image and runtime configuration. | High, with containers adding another packaging and orchestration layer. | You manage images, containers, persistent data, networking, and the host. |
| Static export | Limited to features that can be rendered and served as static files; server-side features requiring a running Node server are not available. | Lower runtime control because a static web server or object store can serve the output. | You manage the build and static-file delivery rather than a long-running Next.js process. |
| Platform adapter | Varies by the adapter and its hosting platform. | Usually lower than a self-managed VPS. | The platform supplies some operations, but you must verify supported features, limits, and deployment behavior. |
The remainder of this article assumes the Node.js server option. Standalone output is an optional packaging choice within that model, not a prerequisite for running Next.js on a VPS.
How do I prepare a Next.js app for a VPS?
Confirm the runtime requirement
The current Next.js installation documentation lists Node.js 20.9 as the minimum version. That number is a documented baseline, not a promise that every future Next.js release will use the same requirement. Check the requirement for the exact Next.js version in your project before choosing a runtime or pinning an NVM version.
On the VPS, record the versions you actually intend to use:
node --version
npm --version
git --version
If the project uses another package manager, use the version declared by its lockfile and package metadata instead of converting commands mechanically. A lockfile generated for one package manager should be installed with that package manager’s reproducible-install command.
Check the production scripts
A basic Node.js Next.js project should expose production build and start scripts. Inspect package.json and confirm that they invoke the intended commands:
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
}
}
The documented production flow is npm run build followed by npm run start. Do not use next dev as the process managed by PM2; development mode has different performance, caching, and error behavior.
List the values that belong outside Git
Make an inventory of environment variables needed at build time and at runtime. Decide which values are public by design and which are secrets. Keep secret values in the VPS environment or a deployment secret store, not in the repository, and make sure the deployed revision cannot accidentally overwrite them with a committed example file. Follow the project’s own environment-loading conventions because a variable used during next build may need to be present before the build, while a server-only value may be read only when the process starts.
Rank #2
How do I deploy a Next.js app on a VPS?
1. Select the release and check it out with Git
Create or select a non-root deployment user according to your VPS provider’s administration model, then place the application in a predictable directory. The exact directory and user are yours to choose; consistency matters more than a particular path.
For a first checkout, the shape of the workflow is:
git clone <repository-url> /srv/next-app
cd /srv/next-app
git checkout <release-or-commit>
The angle-bracket values in this example represent your repository URL and intended revision. For an existing checkout, fetch and inspect before switching:
cd /srv/next-app
git fetch --all --tags
git status
git checkout <release-or-commit>
A branch name is convenient for continuous delivery, while a tag or commit gives a more explicit release identity. Whichever you choose, record the revision that is running so a later rollback is an intentional checkout rather than an improvised merge.
PM2 also documents an SSH-based deployment configuration with fields for host, user, key, repository, revision, and lifecycle actions. That supports a Git-based update flow, but it does not choose your Git provider, credential storage, approval process, or CI security model. Restrict deploy keys to the access they need, keep private keys out of the repository, and decide how a failed build should stop a release.
2. Install dependencies reproducibly
From the checked-out revision, install dependencies using the package manager and lockfile selected by the project. For an npm project with a committed lockfile, the usual reproducible command is:
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Repair Windows errors before they cause bigger problems3Fix the driver behind crashes, sound loss and screen glitchesnpm ci
If the project does not use npm or does not have an npm lockfile, use its documented install command instead. Do not silently regenerate a lockfile on the server during every release; that makes the deployed dependency graph depend on the moment of deployment rather than on the reviewed revision.
3. Build the production application
With required build-time variables available, create the production build:
npm run build
A successful build should finish without an error exit status and leave the build artifacts expected by the project. If it fails, fix the code, dependency, environment, or memory issue before starting a new process. Starting an old process after a failed build can leave the VPS serving a release that no longer matches the checked-out source.
4. Run the production server locally first
Before adding Nginx, verify that the application can listen on a local port:
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
npm run start
Use the project’s configured port, or set it explicitly through the project’s supported environment variable. Test the local listener from the VPS and confirm that a representative page, API route, and any required server-side integration respond as expected. Stop this foreground test before handing the process to PM2.
How do I keep Next.js running with PM2?
Declare the process in an ecosystem file
An ecosystem file makes the working directory, command, and environment explicit. The following is an illustrative npm setup; adjust the path, name, port, and variables to your application:
module.exports = {
apps: [
{
name: "next-app",
cwd: "/srv/next-app",
script: "npm",
args: "run start",
env_production: {
NODE_ENV: "production",
PORT: "3000"
}
}
]
};
Keep secrets out of this file if it is committed to Git. PM2 supports environment declarations in ecosystem configuration, so use the file for non-secret process settings and supply sensitive values through the VPS’s approved environment mechanism.
Start and inspect the application
Start the declared production environment and inspect the process:
Free tools Windows power users keep installed
One-click scans. No signup required.
pm2 start ecosystem.config.js --env production
pm2 status
pm2 logs next-app
Check the PM2 status table for an online process, then make a local request to the configured port. Logs should show the actual application startup message rather than a development server command. If the process repeatedly restarts, inspect the first error in the logs; a restart loop is usually a symptom of a missing environment variable, wrong working directory, incompatible Node version, failed build, or port conflict.
Understand what PM2 does and does not do
PM2 supervises the process you give it. It does not install Node.js, create a successful Next.js build, configure DNS, issue a certificate, or make an unsafe deployment safe. A process showing as online only means PM2 has a running child process; it does not prove that every public route, database connection, background job, or health check works.
Rank #4
How do I keep Next.js running after a reboot?
PM2’s reboot recovery has two distinct parts: generate and install a startup integration, then save the process list that should be restored.
- Run
pm2 startup. PM2 prints a command tailored to the detected init system and user context. - Run the generated command with the privileges it requests. Do not replace it with an unrelated service command; the generated command captures the PM2 binary and account that need to start at boot.
- Save the currently managed process list with
pm2 save. - Verify the result by checking
pm2 statusafter a controlled reboot or by inspecting the generated service using the VPS distribution’s service tools.
The startup service and the saved list are tied to the account and Node.js binary path used when they were configured. If you change the Node.js version under NVM, PM2 documents that you should rerun the startup setup because the binary path changes. After a runtime change, start the application with the new version, run the startup command again, and save the intended process list once more.
How should Nginx proxy requests to Next.js?
Use a private application listener
Bind the Next.js server to a local interface and let Nginx own the public listener. This reduces direct exposure of the application process and gives you a controlled place to apply proxy behavior. The port number is not special; it simply must match the PM2 environment and Nginx upstream.
A minimal conceptual Nginx server block looks like this:
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;
}
}
This is an example of the proxy relationship, not a complete TLS or firewall recipe. Replace the example hostname, confirm the correct Nginx configuration directory for your distribution, validate the syntax with the Nginx test command provided by that installation, and reload the service using the service manager your VPS uses. Do not copy a certificate path, port policy, or system-user instruction from this example without adapting it to your host.
Recommended Free Tools
Account for streaming responses
App Router streaming depends on the proxy and the rest of the request path passing streaming responses through. If your application relies on streaming, test it through the public hostname, not only against localhost. Next.js’s self-hosting guidance gives X-Accel-Buffering: no as an Nginx-related approach. That header is an approach rather than a guarantee: an upstream proxy, CDN, load balancer, or client can still buffer data. Verify time-to-first-byte and incremental delivery across the entire path.
Decide TLS, DNS, and firewall policy separately
Point the domain’s DNS record at the VPS only after you know which public address should receive traffic. Choose a certificate issuance and renewal method that matches your operating system and domain control. Restrict inbound ports to the listeners you actually need, and decide whether administrative access is limited by source address or another control. Those choices are intentionally not prescribed here because the correct commands depend on the VPS distribution, provider network, domain, and certificate service.
How should I update a running Next.js deployment?
A safe update has a visible revision, a successful dependency installation, a successful build, and an explicit process reload. A simple manual sequence is:
Best Value
cd /srv/next-app
git fetch --all --tags
git checkout <new-release>
npm ci
npm run build
pm2 reload next-app --update-env
Use the package manager appropriate to the repository, and use the PM2 process name shown by pm2 status. Reloading is preferable to an unplanned kill when the application can start cleanly, but the exact behavior depends on the process configuration and application readiness. This guide does not establish a universal zero-downtime recipe for every Next.js version or project.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →For more controlled releases, build in a new release directory, verify the artifact, switch a stable path or process configuration, and retain the previous release for rollback. That pattern avoids changing files underneath a process that is still serving requests, but its implementation depends on your filesystem layout and deployment tooling.
PM2’s documented deployment configuration can connect to a host, obtain the configured repository revision, run lifecycle actions, and reload the application. Treat the lifecycle hooks as code: review what runs before and after deployment, ensure a failed build stops the release, and make credentials available only to the deployment mechanism that needs them.
Rollback procedure
- Identify the last known-good tag or commit.
- Check it out in the release location, or switch the active release path to that version.
- Install the matching dependencies and run the production build.
- Reload or restart the PM2 process using the same environment settings.
- Test a local endpoint and the public hostname, then record the rollback revision and cause.
Do not assume that reverting application code also reverts database migrations or external configuration. Those dependencies need their own rollback plan.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Should I use Next.js standalone output?
Standalone output is an optional way to package a Node deployment. When enabled, Next.js can generate .next/standalone and a minimal server.js containing the files needed by the standalone server. The generated directory omits public and .next/static by default, so copy those directories manually when the standalone server is expected to serve them.
Standalone output can reduce the files copied into a release, but it does not remove the need for a compatible Node runtime, environment configuration, process supervision, or reverse proxy. Test the packaged result from a clean release directory; a build that succeeds in the full repository can still fail at runtime if an omitted asset or environment value is required.
What changes when the VPS runs multiple instances?
A single PM2 process on one VPS has local assumptions that stop being true when you add workers, servers, containers, or ephemeral instances. Next.js documents that the default cache is local, so independently running instances can hold different cache state. Decide how cache data is coordinated or invalidated before scaling out.
Next.js also documents that multi-server instances need the same Server Functions encryption key. Generate and distribute that key through a secret-management process, keep it out of Git, and ensure every instance receives the same value during a deployment. A process manager can start multiple workers, but it cannot make local caches or encryption settings consistent by itself.
Common failures and precise checks
| Symptom | Likely area | Checks and corrective action |
|---|---|---|
npm run build fails |
Runtime, dependency tree, source code, or build-time environment | Confirm the Node version meets the project’s documented requirement, install from the lockfile, verify required build variables, and read the first actionable build error. |
| PM2 shows repeated restarts | Startup command or runtime environment | Run the same production command in the project directory, inspect pm2 logs, check the port and environment, and verify that the build completed. |
| Local request works but public request returns 502 | Nginx-to-Node connection | Confirm the Node listener address and port, compare them with proxy_pass, check that the PM2 process is online, and inspect Nginx’s error log. |
| Requests reach the wrong release | Git checkout or release path | Print the current commit, verify PM2’s cwd, remove stale release-path assumptions, and reload only after the intended revision is built. |
| Streaming arrives all at once | Proxy buffering somewhere in the path | Test through the public hostname, inspect response headers, consider the X-Accel-Buffering: no approach, and check every intermediary for buffering. |
| App does not return after reboot | PM2 startup integration or saved process list | Run pm2 startup again if the Node binary changed, execute the generated command, run pm2 save, and verify the service under the actual VPS user. |
| Static files are missing with standalone output | Packaging | Copy public and .next/static into the standalone release as required by the application, then rebuild or redeploy the package. |
Production readiness checklist
- The deployed Next.js release and its Node.js version are explicitly recorded.
- The runtime meets the documented minimum for the installed Next.js version; the current guide lists 20.9 as the minimum.
buildandstartscripts are tested in production mode.- Dependencies install from the repository’s lockfile.
- Build-time and runtime environment values are available without committing secrets.
- PM2 runs the intended working directory, command, port, and production environment.
pm2 startuphas been applied for the correct user and Node binary, andpm2 savehas stored the intended process list.- Nginx proxies only to the intended local listener and forwards the necessary host and protocol information.
- DNS, TLS renewal, firewall rules, and administrative access have been configured for the chosen VPS environment.
- Streaming behavior has been tested through every proxy or CDN in the request path when the application needs it.
- An update and rollback procedure identifies revisions and stops on failed builds.
- If more than one instance runs, cache coordination and a shared Server Functions encryption key are deliberate configuration decisions.
Final deployment decision
For a self-managed VPS, the dependable baseline is a regular Node.js Next.js deployment behind Nginx, supervised by PM2, with Git identifying each release. Build first, start only the production process, configure reboot recovery with both pm2 startup and pm2 save, and treat proxy buffering, secrets, updates, and multi-instance state as explicit operating decisions rather than defaults.
Quick Recap
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.

