Handling Forwarded Headers in ASP.NET Core with Nginx

When hosting an ASP.NET Core application behind a reverse proxy like Nginx, you must configure your app to handle forwarded headers properly. This ensures that properties like Request.Scheme
, Request.Host
, and HttpContext.Connection.RemoteIpAddress
reflect the original client values, not the proxy.
Why Forwarded Headers Matter
When a client makes a request to your app through a proxy (like Nginx), the original request metadata is hidden from the app unless forwarded explicitly. To preserve these details:
Nginx forwards the headers (e.g.,
X-Forwarded-For
,X-Forwarded-Proto
,X-Forwarded-Host
).ASP.NET Core must be told to trust and read those headers.
If you don’t configure this correctly:
Request.Scheme
might returnhttp
even when the client used HTTPS.Request.Host
may showlocalhost
or proxy IP instead of the original host.HttpContext.Connection.RemoteIpAddress
will reflect the proxy's IP.
Nginx Configuration for Forwarded Headers
Here is the correct Nginx server
block configuration to forward the necessary headers:
server {
listen 443 ssl;
server_name your-domain.com;
location / {
proxy_pass http://localhost:5000; # Your .NET app port
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_cache_bypass $http_upgrade;
}
ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}
Remember to replace
your-domain.com
and app port appropriately.
ASP.NET Core Configuration
In your Program.cs
or Startup.cs
, you must enable forwarded headers middleware early in the pipeline:
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor |
ForwardedHeaders.XForwardedProto |
ForwardedHeaders.XForwardedHost,
KnownProxies = { IPAddress.Parse("127.0.0.1") } // or the IP of your reverse proxy
});
Middleware Placement
Ensure UseForwardedHeaders()
is placed before any middleware that relies on HttpContext
(like UseRouting
, UseAuthentication
, etc.).
Security Consideration: Header Spoofing
ASP.NET Core does not trust forwarded headers by default for security reasons. Without validation, a malicious client could send spoofed X-Forwarded-For
or X-Forwarded-Proto
headers directly and trick your app.
How to Secure It
Use
KnownProxies
if your proxy has a fixed IP:options.KnownProxies.Add(IPAddress.Parse("127.0.0.1"));
Use
KnownNetworks
if you're behind a load balancer or container network:options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("10.0.0.0"), 8));
This ensures ASP.NET Core will only process forwarded headers from trusted sources.
Summary
Configure Nginx to forward all necessary headers.
Configure ASP.NET Core to read and trust those headers using
UseForwardedHeaders()
.Protect your app from header spoofing by explicitly listing
KnownProxies
orKnownNetworks
.Always test your setup with:
sudo nginx -t && sudo systemctl reload nginx
With this setup, your ASP.NET Core app will correctly reflect the original request information, even when running behind a reverse proxy like Nginx.
Subscribe to my newsletter
Read articles from Ejan Shrestha directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
