How to Auto-Start an Application on Windows Server Boot (NSSM + sc.exe)
Configure your Node, Python, or Java application to start automatically after Windows Server reboots using NSSM as a service — executable step-by-step guide.
Every production application has to survive reboots. Windows security updates, power outages, hypervisor maintenance — any of these events takes the server down, and if your Node, Python, or Java application is running inside an interactive session (node server.js in an open terminal), it dies along with it and does not come back on its own.
The correct solution on Windows is to register the application as a system service. Services run in session 0 — isolated from any interactive login —, start automatically on boot, restart on failure, and expose standardized controls (sc start, sc stop, Get-Service). This tutorial covers the most common path for applications that were not built as native Windows services: NSSM (Non-Sucking Service Manager).
Estimated time: 15 to 20 minutes, including verification. Target persona: a developer who already has the application running manually on the server and wants to make it persistent.
Prerequisites
Windows Server 2019, 2022, or 2025 with administrator RDP access. Your application already tested and running manually (node app.js, python app.py, java -jar app.jar). The absolute path to the runtime (Node, Python, JRE) and to the entry script noted down. PowerShell opened as administrator.
Windows Server 2019/2022/2025 2.24 (stable) Local Administrator Your choice (e.g. 3000) Before moving on, confirm that the application runs when you execute the command manually in PowerShell and responds on the expected port — turning it into a service does not fix configuration bugs inside the application itself.
Download and install NSSM
NSSM is a standalone binary (nssm.exe) — no MSI installer, no dependencies. The cleanest setup is to drop it into C:\Tools\nssm\ and add that directory to the system PATH.
Create the tools directory and download NSSM through PowerShell:
New-Item -ItemType Directory -Force -Path C:\Tools\nssm
Invoke-WebRequest -Uri "https://nssm.cc/release/nssm-2.24.zip" -OutFile C:\Tools\nssm.zip
Expand-Archive -Path C:\Tools\nssm.zip -DestinationPath C:\Tools\nssm-temp
Copy-Item C:\Tools\nssm-temp\nssm-2.24\win64\nssm.exe C:\Tools\nssm\
Remove-Item C:\Tools\nssm.zip, C:\Tools\nssm-temp -Recurse -ForceThe nssm.exe file now lives at C:\Tools\nssm\nssm.exe. Always use the win64 build on modern servers.
Add NSSM to the system PATH so you can call nssm from any directory:
$old = [Environment]::GetEnvironmentVariable("Path", "Machine")
[Environment]::SetEnvironmentVariable("Path", "$old;C:\Tools\nssm", "Machine")Close PowerShell and open it again to reload PATH. Confirm with nssm version — it should respond NSSM version 2.24.
If the server is exposed to the internet, it pays off to check the SHA256 hash of the downloaded file against the one published on nssm.cc. Executable binaries downloaded without verification are a classic compromise vector — the extra minute is worth it.
Register your application as a service
With NSSM available, each service is configured with nssm install <Name> (GUI mode) or nssm install <Name> <executable> <arguments> (headless mode). The headless path is shown below because it is reproducible, version-controllable, and works on Server Core.
Install the service pointing to the interpreter and the script. Replace the paths with the ones from your application:
nssm install MyApp "C:\Program Files\nodejs\node.exe" "C:\apps\myapp\server.js"For Python applications:
nssm install MyApp "C:\Python312\python.exe" "C:\apps\myapp\app.py"For Java applications:
nssm install MyApp "C:\Program Files\Java\jdk-21\bin\java.exe" "-jar C:\apps\myapp\app.jar"The service name (MyApp) is what shows up in services.msc and in sc query. Use descriptive names without spaces.
Set the working directory of the application. Without this, any relative path in the code (logs, config files, modules) breaks, because the service starts in C:\Windows\System32 by default:
nssm set MyApp AppDirectory "C:\apps\myapp"This is the most common misconfiguration on a first install. Remember: AppDirectory always points to the directory that contains the entry script.
Define environment variables that the application expects. NSSM accepts multiple variables separated by \0 (literal escape), or you can set one at a time:
nssm set MyApp AppEnvironmentExtra "NODE_ENV=production" "PORT=3000" "DATABASE_URL=postgres://..."Sensitive variables (tokens, passwords) can live here, but keep in mind that the Windows registry is readable by any administrator. For real secrets, prefer reading from a .env file protected by ACL or from a dedicated vault.
Configure stdout and stderr logs — without these, any message the application prints simply vanishes:
New-Item -ItemType Directory -Force -Path C:\apps\myapp\logs
nssm set MyApp AppStdout "C:\apps\myapp\logs\stdout.log"
nssm set MyApp AppStderr "C:\apps\myapp\logs\stderr.log"
nssm set MyApp AppRotateFiles 1
nssm set MyApp AppRotateOnline 1
nssm set MyApp AppRotateBytes 10485760AppRotateBytes 10485760 rotates the file once it reaches 10 MB. Without rotation, a forgotten log grows until it fills the disk.
Configure the crash restart policy. NSSM offers three modes: Restart (default — always restart), Ignore (do nothing), and Exit (do not restart). For production, keep the default but tune the delay:
nssm set MyApp AppExit Default Restart
nssm set MyApp AppRestartDelay 5000A 5-second delay prevents a tight crash loop from eating CPU when the application is failing right at startup.
Start the service and enable auto-start
With everything configured, two steps remain: flag the service to start on boot and launch it now for the first time as a service.
Mark the service as Automatic (starts on boot) and configure network dependencies:
sc config MyApp start= auto
sc config MyApp depend= Tcpip/DnscacheThe space after the = is mandatory — a quirk of sc.exe syntax. The dependency guarantees that the TCP/IP stack and the DNS Client are ready before the service starts — without this, applications that perform DNS lookups at startup randomly fail on boot.
Start the service now:
nssm start MyAppYou should see MyApp: START: The operation completed successfully.. If you get an error, jump to the verification section below before continuing.
In more mature environments, avoid running as LocalSystem (default). Create a local service account (net user svc_myapp <password> /add), grant only the required NTFS permissions on the application directory, and run nssm set MyApp ObjectName .\svc_myapp <password>. A compromise of the application stays contained — it will not escalate to SYSTEM.
Verification
Before considering the task complete, validate three things: the service responded to the start command, the application is responding on the expected port, and a real boot brings everything back up by itself.
Confirm that the service is running:
Get-Service MyAppThe Status column should show Running and StartType should be Automatic. If you see Stopped, open C:\apps\myapp\logs\stderr.log — the actual application error is there.
Test the application endpoint:
Invoke-WebRequest http://localhost:3000 -UseBasicParsing | Select-Object StatusCode, ContentReplace the port with the one you configured. A 200 OK response confirms that it is serving from session 0 correctly.
Reboot the server to validate auto-start for real. This is the only reliable way to make sure it will work tomorrow when you are not watching:
Restart-Computer -ForceReconnect via RDP after about 60 seconds and run Get-Service MyApp again. Status Running without you touching anything = correct configuration.
Troubleshooting
Service starts but stops immediately
The cause is almost always an incorrect AppDirectory or a missing environment variable. Open stderr.log — the application stack trace is there. For interactive debugging, run the exact command NSSM would run from an administrator PowerShell: cd C:\apps\myapp; & "C:\Program Files\nodejs\node.exe" server.js. If it breaks, the problem is in the app, not in NSSM.
Error “The service did not respond to the start or control request in a timely fashion”
The application took more than 30 seconds to open its listening port. Large Java applications or Python with lazy imports can hit this limit. Raise the Windows timeout:
nssm set MyApp AppThrottle 10000
sc config MyApp obj= LocalSystem
For the root cause, consider moving heavy initialization to a background task after binding the port.
Empty logs even when the application is crashing
Check that the process is actually writing to stdout/stderr and not to its own file. Some logging libraries (Winston, Log4j) need explicit configuration to send output to stdout. Also confirm that the service user has NTFS write permission on C:\apps\myapp\logs.
Next steps
With the application running as a persistent service, it is worth hardening the environment:
- Set up a Windows Defender Firewall rule that exposes only the application port (
New-NetFirewallRule -DisplayName "MyApp" -Direction Inbound -LocalPort 3000 -Protocol TCP -Action Allow) - Put IIS or a reverse proxy (Caddy, nginx for Windows) in front to terminate TLS and add HTTP/2
- Configure automatic backups of the application directory and the service registry (
nssm dump MyApp > C:\backup\myapp-service.cmd) - Monitor the service externally —
Get-Serviceonly confirms that the process is alive, not that it is responding correctly
If you are taking this to production, a Hostini VPS with pre-configured Windows Server delivers stable RDP and scheduled snapshots before every deploy, so rolling back a service configuration change is a minutes operation, not hours.
Frequently asked questions
Can I use Task Scheduler instead of NSSM?
Yes, but with limitations. Task Scheduler with an "At startup" trigger works for simple scripts, but it does not restart the process if it crashes, does not capture stdout/stderr to a file, and does not run in the isolated session 0. NSSM handles all three out of the box. For production applications, NSSM or sc.exe with a native Windows Service binary is the correct choice.
Does the service need to run as Administrator?
No. Use the LocalSystem account (NSSM default) or create a dedicated service account with the minimum privileges required. Running as Administrator is unnecessary for most web applications — read permissions on the code directory and write permissions on the log directory are enough.
How do I view the application logs once it runs as a service?
NSSM redirects stdout and stderr to the files configured in AppStdout and AppStderr. Set up rotation with AppRotateFiles=1, AppRotateBytes=10485760 (10 MB) to avoid unbounded logs. Service-level events (start, stop, crash) end up in Event Viewer → Windows Logs → Application.
The application starts before the network is ready — how do I avoid that?
Set the service dependency with `sc config ServiceName depend= Tcpip/Dnscache/LanmanWorkstation`. This forces Windows to start the service only after TCP/IP, DNS Client, and the network workstation are ready. NSSM also exposes AppStopMethodSkip for fine-grained shutdown control.
Can I install multiple instances of the same application on different ports?
Yes. Create one NSSM service per instance with distinct names (MyApp-3000, MyApp-3001) and use AppParameters or environment variables (AppEnvironmentExtra PORT=3001) to differentiate them. Each service manages its process independently.
Does NSSM work on Windows Server Core (no GUI)?
Yes. Every NSSM interaction can happen via command line — `nssm install`, `nssm set`, `nssm start`. The GUI (nssm install with no arguments) only opens when a graphical shell is available. Core is fully supported.