Deploy Next.js on a VPS: from build to HTTPS
Deploy a Next.js application on a Linux VPS with a production server, systemd, a reverse proxy and checks before switching traffic.
An agency might host several demos, a marketing site and a small internal tool. Sharing one VPS is an option when you decide how resources are divided and what happens when one application receives a traffic spike.
The number of projects a server can host is not a function of available ports. Routes, databases, builds and overlapping peaks determine capacity. This guide explains how to organize and verify that sharing.
Assign each application a release directory, supervised process, local port and its own environment variables. A shared reverse proxy selects the destination by domain. Restarts should target one identifiable service without touching the others.
For different clients, examine service accounts and permissions too. Processes sharing an account can access files readable by that account. A separate port is not security isolation. Containers or separate machines may be needed for the required boundary.
This table illustrates one arrangement. Replace the example.com names with your domains. Local ports are not public URLs: the browser connects to the proxy.
Each domain needs a valid certificate and appropriate configuration. Check absolute links, authentication callbacks and cookies for that domain. Sharing one domain under separate paths requires additional prefix and asset configuration. Subdomains often avoid that coupling.
On small screens, scroll the table horizontally.
| Application | Domain | Local listener |
|---|---|---|
| Marketing site | www.example.com | 127.0.0.1:3101 |
| Demo | demo.example.com | 127.0.0.1:3102 |
| Internal tool | tools.example.com | 127.0.0.1:3103 |
Record idle, ordinary load and representative peak usage for each service. Add shared services, the operating system and deployment headroom. Count a shared database once in the total budget, with its own peak.
Then load two applications at the same time. Isolated tests can miss competition for CPU, disk and database connections. If a team presents demos during working hours, activity periods may coincide.
On a system with the required controllers, systemd can monitor and constrain a process group. In a drop-in for the tested service, MemoryHigh introduces reclaim pressure, while MemoryMax sets a hard boundary that can lead to termination. CPUQuota caps CPU time.
This fragment illustrates the syntax. Replace the values after measuring; they are not recommended Next.js sizing. An application hitting its limit can slow down or fail, so inspect latency, memory events and logs. The boundary must cover child processes as well as the parent.
[Service]
MemoryAccounting=yes
MemoryHigh=512M
MemoryMax=768M
CPUQuota=100%Plan builds and cleanup separately from active processes. When possible, build in compatible CI and deploy a verified artifact. Otherwise include the build in the shared resource budget and avoid concurrent expensive compilations.
Use a directory per release and verify before switching. Existing connections and assets needed by already-open tabs require attention. Database backups remain separate from application archives; periodically test restoration using test data.
PRNext can release idle workers’ memory at the cost of wake-up work. That may help when idle periods are long and initial visits can accept the delay. Frequent probes or background requests can change the behavior.
Before adding projects, test simultaneous wake-ups too. PRNext’s published memory probe covers one small application; it does not establish a guaranteed site count. Databases, the proxy, system and caches retain their own requirements.