DEV Community

Christopher
Christopher

Posted on • Edited on

NGINX Security

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

Why?

  • Some stacks rely on X-Forwarded-Host more than Host
  • 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";
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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)