Nginx server blocks and reverse proxy on Windows
Host multiple names with server_name, serve static roots, proxy Node/Java upstreams, and forward Host/X-Forwarded headers without loops.
- Build
- 26100.33650
- Edition
- Standard / Datacenter
- Architecture
- x64
- Support
- Documentation (E1)
- Evidence
- E1Official documentation
- Verified
- 2026-10-29
- Page type
- Task
The short answer
Section titled “The short answer”One server block = one virtual host:
server { listen 8082; server_name lab.local;
root C:/nginx/html/lab; index index.html;
location / { try_files $uri $uri/ =404; }}server_name matches the HTTP Host header. Without it, the first/default_server block answers. Use one block per hostname, not one port per app.
Static site
Section titled “Static site”server { listen 8082; server_name lab.local; root C:/sites/lab; index index.html;
location /assets/ { expires 7d; add_header Cache-Control "public"; }
location / { try_files $uri $uri/ /index.html; }}Use forward slashes in Windows paths. Relative root resolves against the Nginx working directory, so absolute paths are safer.
Test with a Host header:
curl.exe -H "Host: lab.local" http://127.0.0.1:8082/Reverse proxy
Section titled “Reverse proxy”Node/Java/Python upstream on localhost:
upstream app_backend { server 127.0.0.1:3000; keepalive 16;}
server { listen 8083; server_name app.local;
location / { proxy_pass http://app_backend; 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_read_timeout 60s; }}Do not append a URI to proxy_pass unless you intend to rewrite the path. proxy_pass http://app_backend; preserves the request URI; proxy_pass http://app_backend/; changes it.
WebSocket
Section titled “WebSocket”map $http_upgrade $connection_upgrade { default upgrade; '' close;}
location /ws/ { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_read_timeout 3600s;}map must be in the http block, not inside server.
Verify
Section titled “Verify”cd C:\nginx.\nginx.exe -t.\nginx.exe -s reloadcurl.exe -I -H "Host: lab.local" http://127.0.0.1:8082/curl.exe -I -H "Host: app.local" http://127.0.0.1:8083/Get-Content .\logs\error.log -Tail 50If every hostname returns the same site, server_name/Host is not matching, or another block is default_server. If a proxy returns 502, the upstream is not listening or the port is wrong.
Lab boundary
Section titled “Lab boundary”E1. The lab ran Nginx 1.28.0 on 8081, but did not add a second server block or a proxied upstream. The configs are the verification path for Server 2025.