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

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

Ricardo Gil
February 9, 2026
15 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

  • nginx for Windows Documentation
  • PM2 Documentation
  • WinSW GitHub Repository
  • Tailscale Funnel Guide
  • ---

    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.

    πŸ“¬Weekly Newsletter

    Get the best home lab & AI content

    No spam. One email per week. Unsubscribe anytime.

    Share this article