Java behind IIS or Nginx: proxy headers, WebSocket and memory
Put Tomcat behind IIS ARR or Nginx, forward the real host/proto/client IP, keep WebSocket alive, and size the JVM instead of guessing.
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
The short answer
Section titled “The short answer”Terminate TLS at IIS/Nginx, proxy to Tomcat on 127.0.0.1:8080:
- forward
Host,X-Forwarded-For,X-Forwarded-Proto; - configure Tomcat’s
RemoteIpValveso the app sees the client, not the proxy; - allow WebSocket upgrades and long read timeouts;
- size the JVM (
-Xms/-Xmx) and Tomcat threads separately.
location / { proxy_pass http://127.0.0.1:8080; 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;}WebSocket:
proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection $connection_upgrade;proxy_read_timeout 3600s;map $http_upgrade $connection_upgrade goes in the http block.
IIS ARR
Section titled “IIS ARR”- Create a server farm pointing at
127.0.0.1:8080. - Preserve
Host; forwardX-Forwarded-For/X-Forwarded-Proto. - Increase proxy timeout for long requests; enable WebSocket if needed.
- Do not expose Tomcat’s 8080 directly to the internet.
Tomcat sees the proxy
Section titled “Tomcat sees the proxy”Enable RemoteIpValve in server.xml (inside the Host):
<Valve className="org.apache.catalina.valves.RemoteIpValve" remoteIpHeader="x-forwarded-for" protocolHeader="x-forwarded-proto" protocolHeaderHttpsValue="https" />Without it, request.getRemoteAddr() returns 127.0.0.1, and request.isSecure() may be false unless the connector is configured for scheme="https".
Memory and threads
Section titled “Memory and threads”set "JAVA_OPTS=-Xms1g -Xmx1g -XX:+UseG1GC"- Set
-Xms=-Xmxfor a server with dedicated memory; avoids heap growth pauses. - Leave headroom for Metaspace, thread stacks, direct buffers and the OS.
- Tomcat
maxThreadsis request concurrency, not heap. Raising threads does not fix a memory leak. - Check GC logs and
jcmd <pid> GC.heap_infobefore changing numbers.
Verify
Section titled “Verify”curl.exe -I https://lab.example/Get-Content C:\tomcat\logs\localhost.*.log -Tail 50jcmd <pid> VM.system_properties | Select-String "java.home|java.version"Check the app logs the real client IP and https scheme; check the JVM is the pinned JDK.
Lab boundary
Section titled “Lab boundary”E1. The lab did not run Tomcat or a Java app; the configuration is the proxy pattern to verify on Server 2025.