Fixing Blazor Apps Behind Nginx: Reverse Proxy Headers, WebSockets, and Redirect Hell
If you’ve ever deployed a Blazor app behind Nginx and thought:
“It kind of works… but redirects are broken, auth is weird, and the UI randomly stops responding”
—you’re not alone.
This post documents the issues I hit running Blazor behind an Nginx reverse proxy, why they happen, and the minimal set of fixes that actually made things stable.
The Problem
Blazor apps (especially Blazor Server) behave badly behind a reverse proxy unless the proxy correctly forwards request metadata.
Common symptoms:
- Infinite HTTP ↔ HTTPS redirect loops
- Auth callbacks failing (OIDC / OAuth / Twitch / Okta / Keycloak)
- Incorrect absolute URLs being generated
- Blazor Server disconnects or frozen UI
- Client IPs always showing as
127.0.0.1
At first glance, everything looks fine — the app responds — but things slowly fall apart.
Why This Happens
Nginx terminates TLS and forwards traffic to Kestrel.
By default, ASP.NET Core has no idea:
- What hostname the user actually hit
- Whether the request was HTTPS
- What port was used
- Who the real client IP is
Without that information, ASP.NET Core makes bad assumptions — and Blazor magnifies those mistakes.
The First Fix: Forwarded Headers
This is the bare minimum most people discover first.
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;
What this fixes
- Preserves the public hostname
- Preserves client IPs
- Tells ASP.NET Core whether the original request was HTTP or HTTPS
This improves things, but in many cases it does not fully fix them.
“Still having some issues, but this seems to be part of the solution.”
That’s because it is only part of the solution.
The Missing Headers Most Guides Don’t Mention
In practice, you usually also need:
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
Why?
- Some stacks rely on
X-Forwarded-Hostmore thanHost - Port mismatches can break redirects and auth callbacks
- Multi-proxy setups behave more consistently with explicit forwarding
Blazor Server-Specific Gotcha: WebSockets (SignalR)
Blazor Server requires WebSockets (SignalR).
Without explicit upgrade headers, the UI may:
- Load but not respond
- Randomly disconnect
- Freeze after navigation
You must include:
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
Long-Lived Connections Need Timeouts and Buffering Tweaks
Blazor Server keeps long-running connections open.
Default Nginx buffering and timeouts can eventually kill them.
These settings often help:
proxy_read_timeout 3600;
proxy_send_timeout 3600;
proxy_buffering off;
A “Known-Good” Nginx Config for Blazor Server
This is the configuration that finally stopped the weird behavior:
location / {
proxy_pass http://127.0.0.1:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_read_timeout 3600;
proxy_send_timeout 3600;
proxy_buffering off;
}
Assumptions:
- TLS is terminated at Nginx
- Kestrel is running HTTP internally
- You’re hosting at
/(not a sub-path)
Important: Nginx Alone Is Not Enough
Even with perfect headers, ASP.NET Core must be configured to trust them.
If your app doesn’t enable forwarded headers middleware, it will ignore what Nginx sends.
Typical symptoms when this is missing:
- HTTPS redirects still broken
- Auth callbacks still wrong
- Scheme mismatches persist
Make sure forwarded headers are enabled and your proxy/network is trusted.
Common Failure Modes (and What They Mean)
| Symptom | Likely Cause |
|---|---|
| HTTP ↔ HTTPS redirect loop |
X-Forwarded-Proto not honored |
| OAuth callback mismatch | Host / scheme incorrect |
| Blazor UI freezes/disconnects | WebSocket upgrade missing or timeouts |
| Random disconnects | Proxy timeouts / buffering |
| Client IP always localhost | Missing forwarded IP headers |
Final Thoughts
Blazor behind Nginx can be rock-solid, but only if:
- Forwarded headers are complete
- WebSockets are explicitly supported (Blazor Server)
- Timeouts are adjusted for long-lived connections
- The app actually trusts the proxy
Most guides cover some of this. Very few cover all of it.
Hopefully this saves someone else a few hours of head-scratching.
Top comments (0)