Handling forwarded headers in ASP.NET Core behind Nginx
/ 2 min read / Ejan Shrestha
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.Schememight returnhttpeven when the client used HTTPS. -
Request.Hostmay showlocalhostor proxy IP instead of the original host. -
HttpContext.Connection.RemoteIpAddresswill 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.comand 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
KnownProxiesif your proxy has a fixed IP:options.KnownProxies.Add(IPAddress.Parse("127.0.0.1")); -
Use
KnownNetworksif 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
KnownProxiesorKnownNetworks. -
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.