Skip to content

Nginx server blocks and reverse proxy on Windows

Verified 1 min read

Host multiple names with server_name, serve static roots, proxy Node/Java upstreams, and forward Host/X-Forwarded headers without loops.

Tested onStandard / Datacenter · Build 26100.33650 · x64
E1
Build
26100.33650
Edition
Standard / Datacenter
Architecture
x64
Support
Documentation (E1)
Evidence
E1Official documentation
Verified
2026-10-29
Page type
Task

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.

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:

Terminal window
curl.exe -H "Host: lab.local" http://127.0.0.1:8082/

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.

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.

Terminal window
cd C:\nginx
.\nginx.exe -t
.\nginx.exe -s reload
curl.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 50

If 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.

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.

Sources