How to Install and Configure Nginx on a Windows Server VPS
A practical guide to install, register as a service, and use Nginx as a reverse proxy or static file server on a Windows Server VPS step by step.
Nginx is more commonly associated with Linux environments, but an official Windows binary exists and covers scenarios where the server has to run on that operating system — typically when there is a mixed stack of legacy .NET applications, IIS, and modern services coexisting on the same VPS. It works well as a reverse proxy for Node.js, .NET Core, or Java apps running on internal ports, and as a fast static file server.
This guide is for developers and administrators who have already provisioned a Windows Server VPS (2019, 2022, or 2025) and need to put Nginx into production as a Windows service, with the firewall configured, virtual hosts defined, and reverse proxy working. The average execution time is 25 to 40 minutes, depending on how much you customize the virtual hosts.
The Windows build of Nginx has performance limitations compared to the Linux one (it does not use IOCP in an optimized way and is restricted to the select model), but for most internal proxy or admin panel hosting scenarios it is more than enough.
Prerequisites
A VPS with Windows Server 2019 or higher, RDP access with an administrator account, an active internet connection, and at least 200 MB free on C:. You will need to open PowerShell as administrator at several points.
Windows Server 2019+ 1.27.x mainline C:\nginx 80, 443 Confirm that you have administrative access by opening PowerShell and running whoami /groups | findstr Administrators. If the output lists the group, you are ready.
Download and extract Nginx
This section pulls the official binary and lays it out in a stable directory that will be referenced by the service.
Open PowerShell as administrator and create the installation directory:
New-Item -ItemType Directory -Path "C:\nginx" -Force
Set-Location "C:\nginx"This directory will hold the binary, the configuration files, and the logs. Keeping everything under C:\nginx simplifies the paths in nginx.conf and avoids problems with spaces (do not use C:\Program Files\).
Download the latest stable Windows release of Nginx:
Invoke-WebRequest -Uri "https://nginx.org/download/nginx-1.27.3.zip" -OutFile "nginx.zip"Check the current version at nginx.org/en/download.html before running — the mainline branch (1.27.x) receives fixes more frequently. The stable branch (1.26.x) is a more conservative alternative for production.
Extract the archive and lay out the contents at the root of C:\nginx:
Expand-Archive -Path "nginx.zip" -DestinationPath "C:\nginx-temp"
Move-Item -Path "C:\nginx-temp\nginx-1.27.3\*" -Destination "C:\nginx" -Force
Remove-Item -Path "C:\nginx-temp", "C:\nginx\nginx.zip" -Recurse -ForceAfter this, C:\nginx should contain nginx.exe and the conf, html, logs, and temp folders.
Start Nginx manually to validate
Before turning it into a service, confirm that the binary runs correctly.
Start Nginx in the foreground:
Set-Location "C:\nginx"
.\nginx.exeThe command returns immediately — Nginx keeps running in the background. Open a browser on the VPS itself and visit http://localhost. The default “Welcome to nginx!” page should appear.
Stop the process manually before moving on:
.\nginx.exe -s stopUse -s quit to shut down gracefully (waits for active connections to finish) or -s stop to terminate immediately.
If Nginx fails with “bind() to 0.0.0.0:80 failed”, IIS or the World Wide Web Publishing service (W3SVC) is using the port. Stop it with Stop-Service W3SVC -Force and disable it with Set-Service W3SVC -StartupType Disabled if you are not going to use IIS.
Open ports on the Windows firewall
Windows Defender Firewall blocks external connections by default. Without this step, Nginx only responds from inside the VPS.
Create rules for HTTP and HTTPS:
New-NetFirewallRule -DisplayName "Nginx HTTP" -Direction Inbound -Protocol TCP -LocalPort 80 -Action Allow
New-NetFirewallRule -DisplayName "Nginx HTTPS" -Direction Inbound -Protocol TCP -LocalPort 443 -Action AllowBy default, this applies to every profile (Domain, Private, Public). If your VPS sits on a mixed network, validate with Get-NetFirewallRule -DisplayName "Nginx*" | Format-List.
Register as a Windows service with NSSM
nginx.exe does not natively support services. NSSM solves this by wrapping the binary in a managed service.
Download and extract NSSM:
Invoke-WebRequest -Uri "https://nssm.cc/release/nssm-2.24.zip" -OutFile "C:\nssm.zip"
Expand-Archive -Path "C:\nssm.zip" -DestinationPath "C:\nssm-temp"
Move-Item -Path "C:\nssm-temp\nssm-2.24\win64\nssm.exe" -Destination "C:\nginx\nssm.exe"
Remove-Item -Path "C:\nssm-temp", "C:\nssm.zip" -Recurse -ForceThe win64 folder contains the 64-bit binary. If your VPS is 32-bit (rare today), use win32.
Register the service pointing at nginx.exe:
C:\nginx\nssm.exe install Nginx "C:\nginx\nginx.exe"
C:\nginx\nssm.exe set Nginx AppDirectory "C:\nginx"
C:\nginx\nssm.exe set Nginx Start SERVICE_AUTO_START
C:\nginx\nssm.exe set Nginx AppStdout "C:\nginx\logs\service-stdout.log"
C:\nginx\nssm.exe set Nginx AppStderr "C:\nginx\logs\service-stderr.log"The AppDirectory parameter is critical — without it, Nginx looks for conf/nginx.conf in the wrong directory and fails silently.
Start the service and enable autostart:
Start-Service Nginx
Get-Service NginxThe Status column should show Running. From now on, Nginx comes up automatically when the server reboots.
Configure NSSM to restart the service if it crashes: C:\nginx\nssm.exe set Nginx AppExit Default Restart and C:\nginx\nssm.exe set Nginx AppRestartDelay 5000. A five-second delay avoids a restart loop when the error is structural (broken config).
Configure a virtual host and reverse proxy
Here you define how Nginx serves your site or proxies to an application running on another port.
Edit the main configuration file:
notepad C:\nginx\conf\nginx.confInside the http { ... } block, add a server block to reverse-proxy an application running on localhost:3000 (typical for Node.js):
server {
listen 80;
server_name app.yourdomain.com;
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;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}The X-Real-IP and X-Forwarded-For headers preserve the real client IP for the backend application. The Upgrade and Connection lines enable WebSockets.
To serve static files directly, add another server block:
server {
listen 80;
server_name static.yourdomain.com;
root C:/sites/static;
index index.html;
location / {
try_files $uri $uri/ =404;
}
location ~* \.(jpg|jpeg|png|gif|svg|css|js|woff2)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
}Pay attention to path format: inside nginx.conf use forward slashes (C:/sites/static), never backslashes. Nginx on Windows interprets \ as an escape character.
Validate the configuration before reloading:
C:\nginx\nginx.exe -tThe expected output is syntax is ok followed by test is successful. Any error reports the exact line number.
Reload Nginx without stopping the service:
C:\nginx\nginx.exe -s reloadThe master process reads the new nginx.conf and spawns updated workers, while the old ones keep serving in-flight connections until they finish.
Verification
Confirm that the service is up, listening on the correct ports, and responding externally.
Get-Service Nginx
netstat -ano | findstr ":80 :443"
Invoke-WebRequest -Uri "http://localhost" -UseBasicParsing | Select-Object StatusCode
The first line should show Running, the second lists nginx.exe (PID) listening on the ports, and the third returns StatusCode : 200.
From an external machine, open the VPS public IP in a browser. If the default page or your virtual host shows up, the firewall is properly opened. Otherwise, validate the rules with Get-NetFirewallRule -DisplayName "Nginx*".
Troubleshooting
Service starts and stops immediately
Almost always a configuration error. Check C:\nginx\logs\error.log — it is usually an invalid path or a busy port. Run C:\nginx\nginx.exe -t to validate the syntax before any restart.
Site responds locally but not externally
Firewall or wrong bind. Confirm that listen 80; is not restricted to 127.0.0.1:80 and that the firewall rule exists for the active network profile.
Error “could not build server_names_hash”
The domain name in server_name exceeds the default bucket size. Increase it inside http { ... }:
server_names_hash_bucket_size 128;
Next steps
With Nginx running, the natural next step is to add TLS via Let’s Encrypt (use win-acme, the native ACME client for Windows), configure gzip/brotli compression for better performance, and apply rate limiting with limit_req_zone if you expose public APIs.
For monitoring, enable the stub_status module on an internal route and scrape the metrics with any compatible agent. Structured JSON logs make ingestion in observability systems easier.
If you are taking this stack to production, a Hostini Windows VPS ships with a Windows Server license included, dedicated IPv4, and DDoS protection at the edge — so you do not have to size the packet filter for abusive traffic on port 80 yourself.
Frequently asked questions
Does Nginx on Windows perform as well as on Linux?
No. The official Windows binary uses the select() model instead of optimized epoll/IOCP, which limits efficient concurrent connections to around 1024. For heavy production traffic, Nginx on Linux or WSL2 delivers higher throughput. For internal reverse proxy, admin panels, or low-concurrency static sites, the Windows build is perfectly viable.
Can I run Nginx and IIS on the same Windows Server?
Yes, as long as they listen on different ports. The common pattern is to leave IIS on 80/443 or move it to 8080/8443 and place Nginx in front as a reverse proxy on the public ports. Use netstat -ano to confirm who is on each port before starting the second service.
How do I make Nginx start automatically with Windows?
The nginx.exe executable is not a native service. The standard solution is to wrap it with NSSM (Non-Sucking Service Manager) or WinSW, which registers a Windows service pointing to the binary and allows you to configure automatic restart on failure.
Where are the Nginx logs stored on Windows?
By default at C:\nginx\logs\access.log and error.log. Unlike Linux, there is no automatic rotation — you need to configure a scheduled task to run nginx -s reopen after moving the files, or use logrotate via WSL.
How do I reload the configuration without stopping the service?
Run nginx -s reload inside the installation directory. This command makes the master process re-read nginx.conf and spawn new workers, while the old ones keep serving in-flight connections until they finish — zero downtime.
Do I need to open a port on the Windows firewall?
Yes. Windows Defender Firewall blocks inbound connections by default. Create explicit rules for TCP 80 and TCP 443 (or the ports you use), for both the public and private profiles if the VPS sits on a mixed network.