Install Node.js on Windows Server
This guide shows how to install Node.js on Windows Server with the MSI installer or winget, and how to manage several versions with nvm-windows, which winget can install too. It then covers deploying an app, running it as a Windows service at boot and opening the firewall. The commands target a OuiHeberg Windows VPS, delivered with Windows Server 2025. First connect over Remote Desktop, as explained in Connect to a Windows VPS via RDP.
Choose a version and a method
Always install an LTS release, which is supported for longer. Since 28 October 2026, the active LTS is Node.js 26. Node.js 24 and 22 still get security fixes. Node.js 20 has been out of support since 30 April 2026. The official release schedule has the current dates.
There are three ways to install Node.js on Windows Server.
| Method | Use | Strength | Limit |
|---|---|---|---|
| MSI installer | One app in production | Installed system-wide | Changing major version means reinstalling |
| winget | The same in one command | Built into Windows Server 2025 | One version at a time |
| nvm-windows | Testing several versions | Switch versions with one command | Installed in your profile, unusable by a service |
For an app that must run all the time, use the MSI or winget. The Windows service described below relies on that Node.js. Keep nvm-windows for a development or test server.
Install Node.js with the MSI installer
On the VPS, open the Node.js download page.
Pick the LTS release for Windows on x64, then download the Windows Installer (.msi).
Run the file and keep the default options. The Add to PATH option must stay enabled.
Open a new PowerShell window and check the installed versions.
node -v
npm -v
The first line shows the Node.js version, for example v26.13.0. The second shows the npm version. To change major version, uninstall Node.js from the Windows settings, then install the MSI of the other version.
Install Node.js with winget
winget, the Windows package manager, is installed by default on Windows Server 2025, according to Microsoft. One command installs the current LTS.
winget install OpenJS.NodeJS.LTS
The package installs the same MSI, system-wide. Close PowerShell, open it again, then check with node -v. This command updates Node.js later on.
winget upgrade OpenJS.NodeJS.LTS
Install nvm-windows to switch versions
nvm-windows installs several Node.js versions side by side and switches between them. It is a separate project from nvm, which only runs on Linux and macOS. Version 2 installs into your user profile, without administrator rights.
Node.js already installed with the MSI or winget? Uninstall it first. Two Node.js installs in the PATH lead to confusion.
Install nvm-windows with winget. You can also download the setup.exe installer from the nvm-windows releases page.
winget install nvm-windows
Open a new PowerShell window. Check that nvm responds, then install and switch to the latest LTS.
# Check that nvm-windows responds
nvm env
# Install and switch to the latest LTS
nvm install lts
nvm use lts
node -v
npm -v
nvm use changes the default version, which is kept for later sessions. The other commands are described in the nvm-windows documentation.
Switch versions and update Node.js
nvm-windows keeps each version in its own folder. You can test your app on another version without uninstalling anything.
# Install other major versions
nvm install 24
nvm install 22
# Switch to Node.js 24
nvm use 24
# List installed versions (* = active version)
nvm list
To move to a new LTS, install it, test your app, then remove the old version.
# Install the new LTS and switch to it
nvm install lts
nvm use lts
# Remove the old version once everything works
nvm uninstall 22
Test your app before switching versions in production. Some npm packages depend on a specific Node.js major version.
With the MSI or winget, you update through winget upgrade or the MSI of the new version.
Deploy a Node.js application on Windows Server
A small Express app checks the whole setup end to end. Create the project folder, then install Express.
mkdir C:\apps\monapp
cd C:\apps\monapp
npm init -y
npm install express
Create the server.js file and open it in Notepad.
New-Item server.js
notepad server.js
Paste this code, save, then close Notepad.
const express = require('express');
const app = express();
const PORT = 3000;
app.get('/', (req, res) => {
res.send('Hello from OuiHeberg VPS!');
});
app.listen(PORT, () => {
console.log(`Server started on port ${PORT}`);
});
Start the app.
node server.js
In a browser on the VPS, open http://localhost:3000. The page shows this message.
Hello from OuiHeberg VPS!
Press Ctrl+C to stop the app. Started this way, it also stops when you close PowerShell.
Monitor the app with PM2
PM2 restarts a Node.js app that crashes and gathers its logs. It is free software under the MIT license. Its paid plan, PM2 Plus, adds online monitoring that most projects can do without.
npm install -g pm2
pm2 start C:\apps\monapp\server.js --name "monapp"
| Command | Effect |
|---|---|
pm2 list | Lists the processes |
pm2 logs monapp | Shows live logs |
pm2 restart monapp | Restarts the app |
pm2 stop monapp | Stops the app |
pm2 monit | Shows live CPU and memory use |
pm2 delete monapp | Removes the app from PM2 |
PM2 runs inside your Windows session. Its pm2 startup command, which restarts it at boot, only knows the init systems of Linux, macOS, BSD and Solaris, according to the PM2 documentation. It does not work on Windows. To start the app with the server, install it as a Windows service.
Start the app at boot with a Windows service
A Windows service starts with the server, with no open session, and can restart after a crash. Node.js cannot register itself as a service. WinSW, a free tool under the MIT license, bridges the gap. The service uses the Node.js from the MSI or winget, installed in C:\Program Files\nodejs.
Create a folder for the service and download WinSW as monapp.exe. The last command opens the configuration file in Notepad.
New-Item -ItemType Directory -Path C:\services\monapp
Invoke-WebRequest -Uri "https://github.com/winsw/winsw/releases/download/v2.12.0/WinSW-x64.exe" -OutFile "C:\services\monapp\monapp.exe"
notepad C:\services\monapp\monapp.xml
Paste this configuration, then save. The XML file has the same name as the executable.
<service>
<id>monapp</id>
<name>monapp (Node.js)</name>
<description>Node.js monapp</description>
<executable>C:\Program Files\nodejs\node.exe</executable>
<arguments>C:\apps\monapp\server.js</arguments>
<workingdirectory>C:\apps\monapp</workingdirectory>
<env name="NODE_ENV" value="production" />
<startmode>Automatic</startmode>
<onfailure action="restart" delay="10 sec" />
<log mode="roll-by-size">
<sizeThreshold>10240</sizeThreshold>
<keepFiles>8</keepFiles>
</log>
</service>
The onfailure tag restarts the app if it stops. The monapp.out.log and monapp.err.log logs are written to the service folder, with a new file every 10 MB.
In PowerShell run as administrator, install and start the service.
# Free the port if PM2 is already running the app
pm2 delete monapp
cd C:\services\monapp
.\monapp.exe install
.\monapp.exe start
.\monapp.exe status
Get-Service monapp
status should return Started, and Get-Service should show Running. The service also appears in the Services console, with automatic startup. Restart the VPS to check that the app comes back on its own.
# After updating the code
.\monapp.exe restart
# Remove the service
.\monapp.exe stop
.\monapp.exe uninstall
By default, WinSW runs the service under the LocalSystem account, which has full rights on the machine. Its documentation shows how to pick a less privileged account with the
serviceaccounttag.
Configure the Windows Firewall for Node.js
The client area has no network firewall for VPS. Only the Windows Firewall filters connections. Open the ports in PowerShell run as administrator.
# Port 3000 (testing)
New-NetFirewallRule -DisplayName "Node.js Dev" -Direction Inbound -Protocol TCP -LocalPort 3000 -Action Allow
# Port 80 (HTTP)
New-NetFirewallRule -DisplayName "Node.js HTTP" -Direction Inbound -Protocol TCP -LocalPort 80 -Action Allow
# Port 443 (HTTPS)
New-NetFirewallRule -DisplayName "Node.js HTTPS" -Direction Inbound -Protocol TCP -LocalPort 443 -Action Allow
Then check the rules. Each one should show True in the Enabled column.
Get-NetFirewallRule -DisplayName "Node.js*" | Select Name, Enabled
Only open port 3000 while you test. In production, put a reverse proxy such as IIS or Nginx on ports 80 and 443. It routes requests to your apps, each on its own port (3000, 3001, 3002…). The guide How to install IIS on Windows Server covers the IIS setup. For the rest of the firewall, follow How to open a port in Windows Firewall on a VPS.
Fix common errors
"node" is not recognized
PowerShell has not read the new PATH yet. Close it, then open it again. With nvm-windows, also run nvm use lts.
"nvm" is not recognized
Open a new PowerShell window. If the error persists, reinstall nvm-windows.
EACCES or EPERM error during npm install -g
Restart PowerShell as administrator, then run the command again.
Port 3000 is already in use
Another process holds the port, often a first copy of the app. Find its number, then stop it.
netstat -ano | findstr :3000
taskkill /PID [PID] /F
Replace [PID] with the number shown in the last column.
The service does not start
Read monapp.err.log in C:\services\monapp. Also check the node.exe path in the XML file. The service cannot see a Node.js installed with nvm-windows.
Modules are missing after a version switch
Each Node.js version has its own global modules. After nvm use, run npm install again in the project folder. Reinstall PM2 too if you use it.
Need help?
Open a ticket from Tickets › Open a Ticket, or from the Contact support tile at the bottom of the VPS page. In the Related Service field, pick the VPS so the team saves time. You can also ask your question on the OuiHeberg Discord.
Windows Server 2025 with the license included, Remote Desktop access and management from the client area.
View plans →