Introduction
After years of deploying Node.js applications on Linux servers, I recently faced an interesting challenge: building a truly production-ready infrastructure on Windows 11. The goal? Auto-start capabilities, zero downtime, and enterprise-grade reliabilityβall without relying on WSL (Windows Subsystem for Linux).
In this comprehensive guide, I'll walk you through the exact setup I built for a full-stack photography portfolio platform serving thousands of requests daily. You'll learn how to configure nginx for Windows, manage Node.js processes with PM2, and create Windows Services that survive reboots.
Why Windows for Production?
Before diving in, you might ask: "Why Windows instead of Linux?" Here's why this matters:
- Developer machines as servers: Many small businesses and solo developers run production workloads on their development machines
- Windows-first environments: Corporate IT infrastructures often standardize on Windows
- Hybrid cloud strategies: Not everyone deploys to AWS/Azureβlocal servers still power many applications
- Learning opportunity: Understanding Windows deployment broadens your DevOps skillset
The Architecture
Here's what we'll build:
Internet
β
HTTPS Reverse Proxy (Tailscale/Cloudflare)
β
nginx Windows Service (Port 8080)
βββ /api/* β Main Backend (Port 3000)
βββ /api/v1/* β Secondary API (Port 3001)
β
PM2 Process Manager
βββ main-backend (1 instance)
βββ secondary-api (2 instances, cluster mode)
β
PostgreSQL Database
Key Features:
- β Auto-starts on boot (no user login required)
- β Process monitoring and auto-restart
- β Load balancing via PM2 cluster mode
- β HTTPS with reverse proxy
- β Proper CORS and security headers
- β Production logging and error handling
Prerequisites
Before starting, ensure you have:
- Windows 11 (or Windows 10 Pro/Enterprise)
- Node.js v18+ installed
- Administrator access
- Basic PowerShell knowledge
- Your Node.js application ready to deploy
Step 1: Installing nginx for Windows
Unlike Linux, nginx on Windows requires a different approach. Here's how to set it up:
Download and Extract nginx
# Download nginx for Windows
$nginxUrl = "https://nginx.org/download/nginx-1.24.0.zip"
Invoke-WebRequest -Uri $nginxUrl -OutFile "C:\nginx-1.24.0.zip"
# Extract to C:\nginx
Expand-Archive -Path "C:\nginx-1.24.0.zip" -DestinationPath "C:\"
Rename-Item -Path "C:\nginx-1.24.0" -NewName "nginx"
Configure nginx
Create your production configuration at C:\nginx\conf\nginx.conf:
worker_processes auto;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
# Performance settings
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
keepalive_requests 100;
# Upstream servers
upstream main_api {
server 127.0.0.1:3000;
keepalive 32;
}
upstream secondary_api {
server 127.0.0.1:3001;
server 127.0.0.1:3001;
keepalive 32;
}
server {
listen 8080;
server_name _;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# Main API
location /api/ {
proxy_pass http://main_api/api/;
proxy_http_version 1.1;
proxy_set_header Connection "";
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;
}
# Secondary API
location /api/v1/ {
proxy_pass http://secondary_api/api/v1/;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
}
Key Configuration Notes:
keepalive 32: Maintains persistent connections to backendsproxy_set_header Connection "": Essential for HTTP/1.1 keepalivelisten 8080: Avoid port 80 (often blocked by Windows HTTP Service)
Test nginx
cd C:\nginx
.\nginx.exe -t # Test configuration
.\nginx.exe # Start nginx
Visit http://localhost:8080 to verify it's running.
Step 2: Setting Up PM2 for Windows
PM2 is the de facto process manager for Node.js applications. Here's how to configure it for production on Windows:
Install PM2 Globally
npm install -g pm2
Create Ecosystem Configuration
For each application, create an ecosystem.config.js:
module.exports = {
apps: [{
name: 'main-backend',
script: './src/server.js',
instances: 1,
exec_mode: 'cluster',
env: {
NODE_ENV: 'production',
PORT: 3000
},
max_memory_restart: '500M',
error_file: './logs/pm2-error.log',
out_file: './logs/pm2-out.log',
time: true
}]
}
Start Your Applications
cd C:\Projects\your-backend
pm2 start ecosystem.config.js
# Save PM2 state
pm2 save
# Check status
pm2 status
Pro Tip: Use cluster mode for CPU-bound applications to leverage multiple cores:
{
instances: 2, // Or 'max' for all CPU cores
exec_mode: 'cluster'
}
Step 3: Converting to Windows Services
This is where the magic happens. We'll use WinSW (Windows Service Wrapper) to create true Windows Services.
Download WinSW
$winswUrl = "https://github.com/winsw/winsw/releases/download/v3.0.0-alpha.11/WinSW-x64.exe"
Invoke-WebRequest -Uri $winswUrl -OutFile "C:\nginx\WinSW.exe"
Create nginx Service
Create C:\nginx\nginx-service.xml:
<service>
<id>nginx</id>
<name>nginx</name>
<description>nginx reverse proxy server</description>
<executable>C:\nginx\nginx.exe</executable>
<startmode>Automatic</startmode>
<logpath>C:\nginx\logs</logpath>
<log mode="roll-by-size">
<sizeThreshold>10240</sizeThreshold>
<keepFiles>8</keepFiles>
</log>
<onfailure action="restart" delay="10 sec"/>
<onfailure action="restart" delay="20 sec"/>
</service>
Install the service:
cd C:\nginx
.\WinSW.exe install nginx-service.xml
Start-Service nginx
Create PM2 Service
First, create a startup script C:\nginx\pm2-start.bat:
@echo off
cd /d C:\Projects\main-backend
call pm2 start ecosystem.config.js
timeout /t 5 /nobreak > nul
cd /d C:\Projects\secondary-backend
call pm2 start ecosystem.config.js
timeout /t 5 /nobreak > nul
call pm2 save --force
Then create C:\nginx\pm2-service.xml:
<service>
<id>pm2</id>
<name>PM2</name>
<description>PM2 Process Manager for Node.js</description>
<executable>C:\nginx\pm2-start.bat</executable>
<startmode>Automatic</startmode>
<logpath>C:\nginx\logs</logpath>
</service>
Install PM2 service:
Copy-Item "C:\nginx\WinSW.exe" "C:\nginx\WinSW-PM2.exe"
.\WinSW-PM2.exe install pm2-service.xml
Start-Service PM2
Step 4: CORS Configuration for Authenticated Requests
One critical lesson I learned: CORS behaves differently with authenticated requests. When using JWT tokens or OAuth, you must explicitly allow the Authorization header:
// Backend CORS configuration
app.use(cors({
origin: [
'https://yoursite.com',
'http://localhost:4200'
],
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
allowedHeaders: ['Content-Type', 'x-api-key', 'Authorization'], // β Critical!
credentials: true
}));
// Also enable trust proxy for nginx
app.set('trust proxy', 1);
Without this, OPTIONS preflight requests will succeed (204 No Content), but the actual authenticated requests will fail silently.
Step 5: Public Access Options
For secure HTTPS access, you have several options:
Option 1: Tailscale Funnel (Easiest)
# Install Tailscale from https://tailscale.com/download
# Enable Funnel
tailscale funnel --bg --https=443 8080
# Check status
tailscale funnel status
Your application is now accessible at https://your-machine.your-tailnet.ts.net!
Option 2: Cloudflare Tunnel
# Install cloudflared
# Follow https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/
cloudflared tunnel --url http://localhost:8080
Option 3: Traditional Port Forwarding
Configure your router to forward port 443 to your machine's port 8080, then use Let's Encrypt with Certbot for SSL.
Recommended Resources
π Essential Books for Windows Server Administration
Want to master Windows Server beyond this guide? These books are invaluable:
Mastering Windows Server 2022 by Jordan Krause
- Comprehensive coverage of Active Directory, DNS, Group Policy, and PowerShell automation
- Perfect for sysadmins managing Windows production environments
- Includes real-world scenarios and best practices
Windows Server Automation with PowerShell Cookbook
- 5th Edition updated for PowerShell 7.2 and Windows Server 2022
- Practical recipes for automating server tasks
- Essential companion for the infrastructure we just built
Mastering Active Directory (3rd Edition)
- Deep dive into Active Directory Domain Services for Windows Server 2022
- Security hardening and identity management
- Great for enterprise environments
Windows Internals, Part 1 by Mark Russinovich
- Understanding Windows architecture at the deepest level
- Essential for troubleshooting production issues
- The definitive guide to how Windows really works
π₯οΈ Hardware Recommendations for Home Lab Servers
If you're serious about running production workloads at home, consider these mini PCs. They're perfect for the setup we just built:
Budget Option ($160-200)
- Intel N150 CPU, 16GB RAM, 500GB SSD
- Dual 2.5GbE ports (perfect for nginx + backend separation)
- Low power consumption (~10W idle)
- Ideal for: Single-node production, file servers, Docker containers
- Why I recommend it: Best value for entry-level production servers. The dual NICs let you separate management traffic.
Mid-Range Powerhouse ($400-500)
- AMD Ryzen 5 5560U (6 cores, 12 threads)
- Expandable to 64GB RAM
- Dual M.2 NVMe slots
- Ideal for: PM2 cluster mode, multiple VMs, database servers
- Why I recommend it: Perfect balance of performance and power efficiency. This is what I'd buy for a serious home production setup.
Advanced/Prosumer ($600-800)
- Intel Core i9-12900H or i9-13900H
- Dual 10GbE SFP+ ports + Dual 2.5GbE
- Up to 96GB DDR5 RAM
- PCIe expansion slot
- Ideal for: High-availability clusters, storage servers, virtualization
- Why I recommend it: Enterprise-grade features in a mini PC. The dual 10GbE ports are perfect for building Ceph clusters or high-performance storage.
Intel NUC Option ($500-700)
- 12th Gen Intel Core (i3/i5/i7 options)
- Rock-solid reliability (Intel quality)
- Thunderbolt 4 support
- Ideal for: 24/7 uptime, mission-critical services
- Why I recommend it: If you need absolute reliability, Intel NUCs are the gold standard. Perfect for production environments where downtime is not an option.
π‘ Why These Mini PCs?
All of these can run the exact infrastructure we built in this guide:
- β Windows 11 compatible
- β Low power consumption (8-45W vs 200W+ for tower servers)
- β Silent operation (perfect for home/office)
- β Expandable RAM/storage
- β Multiple network ports (great for nginx setups)
- β Small footprint (fits anywhere)
Power Cost Comparison: A Beelink SER5 running 24/7 costs ~$2-3/month in electricity vs $15-20/month for a traditional server.
Production Checklist
Before going live, verify:
- Both services auto-start:
Get-Service nginx, PM2 - PM2 processes are running:
pm2 status - nginx is listening:
netstat -ano | findstr :8080 - Backends respond:
curl http://localhost:3000/health - Public access works
- CORS allows authenticated requests
- Logs are being written
- Error handling is in place
Troubleshooting Common Issues
Issue: Services don't start after reboot
Solution:
Get-Service nginx, PM2
Start-Service nginx
C:\nginx\pm2-start.bat
Issue: 502 Bad Gateway
Diagnosis:
pm2 status # Check if backends are running
Get-Content C:\nginx\logs\error.log -Tail 20
Solution: Usually means backends aren't running or listening on wrong ports.
Issue: CORS errors with authentication
Add Authorization to allowedHeaders in your CORS configuration (see Step 4).
Issue: Multiple nginx processes
This is normal! nginx spawns worker processes based on CPU cores. Check with:
Get-Process nginx | Measure-Object
Performance Considerations
With this setup on a modern Windows machine, typical resource usage:
- nginx: ~17 processes (1 master + 16 workers on 16-core CPU)
- Main backend: ~80MB RAM
- Secondary backend: ~130MB RAM (2 instances)
- Total overhead: ~210MB RAM
Response times average <50ms for API requests, with nginx efficiently load balancing across PM2 instances.
Security Best Practices
- Never expose raw backends: Always use nginx as a reverse proxy
- Enable rate limiting:javascript
const rateLimit = require('express-rate-limit'); app.use(rateLimit({ windowMs: 15 * 60 * 1000, max: 100 })); - Use Helmet.js: Automatically sets security headers
- Configure CORS strictly: Only allow known origins
- Enable trust proxy: Essential when behind nginx
- Keep Windows Firewall enabled: Let Windows manage port access
Monitoring and Maintenance
Daily Health Checks
# Quick status
pm2 status
Get-Service nginx, PM2
Weekly Maintenance
# Review error logs
pm2 logs --lines 100
# Check disk space
Get-PSDrive C
# Update dependencies
cd C:\Projects\your-backend
npm outdated
Monthly Tasks
- Review and rotate nginx logs
- Update Node.js packages
- Test disaster recovery
- Verify backups (if configured)
Lessons Learned
After running this setup in production for several months:
- All-Windows is simpler than WSL hybrid: Fewer networking issues, easier troubleshooting
- WinSW is rock-solid: Never had a service failure
- PM2 cluster mode is essential: Automatic load balancing and zero-downtime restarts
- nginx on Windows performs well: Don't let myths discourage you
- CORS authentication gotchas are real: Always test with auth headers
Conclusion
Building production-grade Node.js infrastructure on Windows 11 is not only possibleβit's practical and performant. By using nginx, PM2, and Windows Services, you can achieve:
- β True auto-start without user login
- β Process monitoring and auto-recovery
- β Load balancing and high availability
- β Professional-grade security
- β Minimal maintenance overhead
This setup can power production applications serving thousands of requests daily with 99.9%+ uptime.
Whether you're running this on a dedicated mini PC or your development machine, you now have enterprise-grade infrastructure that rivals Linux deployments.
Additional Resources
About the Author: Ricardo Gil is a Full Stack Software Engineer with 6+ years of experience specializing in C#/.NET Core, Angular, and cloud platforms. He builds scalable web applications and shares DevOps insights at gilricardo.com.
Disclaimer: This post contains Amazon affiliate links. As an Amazon Associate, I earn from qualifying purchases at no additional cost to you. I only recommend products I genuinely use or would use in my own infrastructure.
Need this built for your business?
I build bilingual (EN/ES) web apps and sites with .NET, Angular and AWS: production-ready, documented and handed off. See Full-Stack Development β
