Building Production-Ready Node.js Infrastructure on Windows 11: A Complete Guide
Development

Building Production-Ready Node.js Infrastructure on Windows 11: A Complete Guide

Ricardo Gil
February 9, 2026
11 min read
#Node.js" #"Windows 11" #"nginx" #"PM2" #"DevOps" #"Production" #"Backend" #"Infrastructure

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:

code
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

powershell
# 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:

nginx
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 backends
  • proxy_set_header Connection "": Essential for HTTP/1.1 keepalive
  • listen 8080: Avoid port 80 (often blocked by Windows HTTP Service)

Test nginx

powershell
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

powershell
npm install -g pm2

Create Ecosystem Configuration

For each application, create an ecosystem.config.js:

javascript
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

powershell
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:

javascript
{
  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

powershell
$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:

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:

powershell
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:

batch
@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:

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:

powershell
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:

javascript
// 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)

powershell
# 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

powershell
# 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)

Beelink EQ14 Mini PC

  • 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)

Beelink SER5 Mini PC

  • 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)

Minisforum MS-01 Workstation

  • 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)

Intel NUC 12 Pro Mini PC

  • 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:

powershell
Get-Service nginx, PM2
Start-Service nginx
C:\nginx\pm2-start.bat

Issue: 502 Bad Gateway

Diagnosis:

powershell
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:

powershell
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

  1. Never expose raw backends: Always use nginx as a reverse proxy
  2. Enable rate limiting:
    javascript
    const rateLimit = require('express-rate-limit');
    app.use(rateLimit({
      windowMs: 15 * 60 * 1000,
      max: 100
    }));
  3. Use Helmet.js: Automatically sets security headers
  4. Configure CORS strictly: Only allow known origins
  5. Enable trust proxy: Essential when behind nginx
  6. Keep Windows Firewall enabled: Let Windows manage port access

Monitoring and Maintenance

Daily Health Checks

powershell
# Quick status
pm2 status
Get-Service nginx, PM2

Weekly Maintenance

powershell
# 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:

  1. All-Windows is simpler than WSL hybrid: Fewer networking issues, easier troubleshooting
  2. WinSW is rock-solid: Never had a service failure
  3. PM2 cluster mode is essential: Automatic load balancing and zero-downtime restarts
  4. nginx on Windows performs well: Don't let myths discourage you
  5. 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 β†’

Book a free discovery call.

πŸ“¬Weekly Newsletter

Get the best home lab & AI content

No spam. One email per week. Unsubscribe anytime.

Share this article