I'm sending HTTP GET Request to my API with custom Header
var request = new RestRequest(endpoint, Method.GET);
request.AddHeader("__Test", data);
var response = client.Execute(request);
Everything works fine on localhost, but when I deploy API on server which is using Nginx then this header is "lost"
That's my nginx config
location / {
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
Startup.cs
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
app.UseHttpsRedirection();
This works fine on localhost, but not on server:
HttpContext.Request.Headers.TryGetValue("__Test", out var data)
Anybody has an idea what can go wrong?
Problem occured because I used __ in header's name
Solution:
Use
underscores_in_headers on;
in
nginx.conf
Related
I'm trying to use Nginx as a reverse proxy and the upstream server is an ASP.NET Core application where I've registered the ForwardedHeadersMiddleware, which will read three different X-Forwarded-* headers:
X-Forwarded-For
X-Forwarded-Proto
X-Forwarded-Host
Now, I understand the first two, but find the last one (X-Forwarded-Host) confusing. It seems to me that effectively this has the same effect as just having the proxy rewrite the Host header, and I've seen Nginx reverse proxy configurations doing exactly that, like so:
location / {
proxy_pass http://app;
proxy_set_header Host $host;
}
But then I've also seen the X-Forwarded-Host being used instead:
location / {
proxy_pass http://app;
proxy_set_header X-Forwarded-Host $host;
}
In some cases both are used at the same time — which makes zero sense to me:
location / {
proxy_pass http://app;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Host $host;
}
I'm not sure what I should do. Why would you use both at the same time? Isn't it more idiomatic (or more "correct") to use X-Forwarded-Host (if your upstream server supports it) than rewriting Host? Changing Host feels like a hack to me. I've noticed that the result in my ASP.NET Core app will be the same regardless of whether I set Host or X-Forwarded-Host (or both), in either case, HttpContext.Request.Host is set to the expected value — provided that the forwarded headers middleware is registered, of course.
To my surprise, I couldn't find any relevant information on this issue by googling, so I had to ask this here. What is the right approach to take in this situation?
I'm trying to config a web api with SignalR enabled, so I can push real-time information to the clients via websockets. In front of the api I have a nginx reverse ssl proxy running in a docker container.
Clients can connect just fine via the reverse proxy when ssl is disabled in the nginx configuration:
server {
listen 55555;
# listen 55555 ssl;
ssl_certificate /config/keys/cert.crt;
ssl_certificate_key /config/keys/cert.key;
location / {
proxy_pass http://192.168.1.175:50000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
But when I configure the proxy to listen for ssl the clients can't seem to connect, or at least the client gets a "The server disconnected before the handshake could be started" IOException after what appears to be a time out.
WebAPI log:
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
Request starting HTTP/1.1 POST http://192.168.1.150/chatHub/negotiate?negotiateVersion=1 - 0
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
Executing endpoint '/chatHub/negotiate'
dbug: Microsoft.AspNetCore.Http.Connections.Internal.HttpConnectionManager[1]
New connection i-HjjQP9EsA_rBTX7vFs2Q created.
dbug: Microsoft.AspNetCore.Http.Connections.Internal.HttpConnectionDispatcher[10]
Sending negotiation response.
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
Executed endpoint '/chatHub/negotiate'
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
Request finished HTTP/1.1 POST http://192.168.1.150/chatHub/negotiate?negotiateVersion=1 - 0 - 200 316 application/json 117.3988ms
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
Request starting HTTP/1.1 POST http://192.168.1.150/chatHub/negotiate?negotiateVersion=1 - 0
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
Executing endpoint '/chatHub/negotiate'
dbug: Microsoft.AspNetCore.Http.Connections.Internal.HttpConnectionManager[1]
New connection K0y7OI3-3KvPIXWV92HEkA created.
dbug: Microsoft.AspNetCore.Http.Connections.Internal.HttpConnectionDispatcher[10]
Sending negotiation response.
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
Executed endpoint '/chatHub/negotiate'
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
Request finished HTTP/1.1 POST http://192.168.1.150/chatHub/negotiate?negotiateVersion=1 - 0 - 200 316 application/json 11.6330ms
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
Request starting HTTP/1.1 GET http://192.168.1.150/chatHub?id=zdDUpBZ-RsnQgEZsJ9Sctg - -
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
Executing endpoint '/chatHub'
dbug: Microsoft.AspNetCore.Http.Connections.Internal.HttpConnectionDispatcher[4]
Establishing new connection.
dbug: Microsoft.AspNetCore.SignalR.HubConnectionHandler[5]
OnConnectedAsync started.
dbug: Microsoft.AspNetCore.SignalR.HubConnectionContext[2]
Handshake was canceled.
dbug: Microsoft.AspNetCore.Http.Connections.Internal.HttpConnectionManager[2]
Removing connection zdDUpBZ-RsnQgEZsJ9Sctg from the list of connections.
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
Executed endpoint '/chatHub'
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
Request finished HTTP/1.1 GET http://192.168.1.150/chatHub?id=zdDUpBZ-RsnQgEZsJ9Sctg - - - 200 - text/event-stream 60079.4344ms
I've tried including the following in the WebApplication settings:
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.KnownProxies.Add(IPAddress.Parse("192.168.1.150")); // Proxy Server IP
});
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost
});
But as far as I can tell, it doesn't really make a difference.
I'm unsure whether this is a nginx reverse proxy/sll or a Webpi/SignalR issue. Any ideas? :)
I'm trying to deploy my ASP.NET web Application (with .NET 5.0 and ASP.NET MVC) to an debian 10 server with NGINX. I followed Microsoft's tutorial and after numerous testings can't find something that will work.
My current NGINX configuration:
server {
listen 80 default_server;
location / {
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Querying localhost with curl -v localhost:5000 gives me HTTP 307 redirect.
Querying curl -v --insecure https://localhost:5001 returns the actual content of my webpage, so kestrel is running fine.
My Startup.cs looks like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using SmapOneUpdater.Frontend.Model.Sortenumbuchung.Data;
namespace SmapOneUpdater.Frontend
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});
services.AddDbContext<SortenumbuchungContext>(options =>
options.UseSqlite(Configuration.GetConnectionString("SortenumbuchungContext")));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseForwardedHeaders();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Overview}/{action=Index}/{id?}");
});
}
}
}
Connecting to the ip-address of my server returns "This site can't be reached x.x.x.x unexpectedly closed the connection" after some loading. and it automatically changes the url to x.x.x.x:5001 which should be wrong since I'm not trying to directly access port 5001, or am I?
Nevertheless, I'm pretty sure it's not my NGINX configuration, since my browser somehow gets the information that he needs port 5001 AND because if I change the proxy_pass to https://www.google.com it works and redirects me to google
EDIT: SOLVED
The problem was inside my Properties/launchSettings.json. I had the applicationUrl set to http://localhost:5000;https://localhost:5001 It seems like ASP then only allows connections which call localhost (or 127.0.0.1). Since I couldn't reach kestrel from the server when calling it by ip. After that, I had to change nginx to forward the servers IP address, so the accessing client won't try to access localhost:5001 but the servers IP address with port 5001.
I'm setting the urls on the runtime environment now with the --urls command.
So my call looks like this:
dotnet /path/to/application/dll --urls "http://*:5000;https://*:5001"
As for NGINX, after reading TheRoadrunner's answer, I changed the config to redirect HTTP requests to HTTPS. Following the tutorial from NGINX I also created a self signed ssl certificate with:
openssl req -x509 -subj /CN=localhost -days 365 -set_serial 2 -newkey rsa:4096 -keyout /etc/nginx/cert.key -nodes -out /etc/nginx/cert.pem
My working NGINX config looks like this:
server {
listen 80;
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
ssl_certificate /etc/nginx/cert.pem;
ssl_certificate_key /etc/nginx/cert.key;
location / {
proxy_pass https://192.168.4.156:5001;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Interestengly enough, with this working configuration the port in my url bar in the browser does not show, that it's accessing port 5001
How did I found out
Maybe this will be interesting for some readers. I figured the issue out, by creating a local debian instance with virtualbox. I configured it just as my real server. But I installed GNOME, because I wanted to make sure, whether I can actually see the page with a local browser or not (In retrospective, I probably could've achieved this with curl).
It seemed interesting to me, since the redirect worked on the vm. entering localhost:80 in firefox redirected me to localhost:5001 and I saw the page. After some testing I tried it with the IP of the VM and had the exact same issue as on the other machines. So I tried to change the application URL.
I think this is interesting, since it seems so obvious, but was never mentioned in the documentation. As a proxy/nginx/webdev newbie I was not exactly sure how all of this works. Especially since the documentation mentions to redirect HTTPS to http://localhost:5000
I think you need two sections in your nginx config one for port 80 that redirects to the other on 443.
Something like:
server {
listen 80;
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
location / {
http://localhost:5000
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
In addition you will have to handle certificates to avoid browser warnings.
I published my ASP.NET Core app on my raspberrypi3 (raspbian) with nginx.
I configured nginx following the microsoft documentation: on localhost everything works correctly but I can't access the app from other devices on my local network (ERR_CONN_REFUSED).
I set the reverse proxy on port 81 because on port 80 I have another server that manages php sites (including phpmyadmin) like this:
server {
listen 80 default_server;
listen [::]:80;
root /var/www/html;
index index.php index.html index.htm index.nginx-debian.html;
server_name php.it *.php.it;
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php7.3-fpm.sock;
}}
and
server {
listen 81;
server_name example.com *.example.com;
location / {
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}}
I don't know if the problem is in the configuration of the /etc/nginx/sites-available/default file or in the asp.net Core application.
I think the problem is localhost, but I have no idea how to solve it.
Also, I'm not sure what I should put in server_sites, what does it refer to?
Thanks
In your first config, you have set up domain php.it so your site should be accessible via http://php.it/ if you had set up correct DNS.
But you have set up listening to default_server so it is accessible also without host.
In your second case, there is missing default_server so host ist mandatory. On example.com:81 should be your page accessible, again if you had set up correct DNS.
Solutions:
If you want to access website without domain, just pure IP, remove server_name.
If you want to set up default server even for port 81, add listen 81 default_server;
I have a asp.net core project. It is just a single page site. Im deployed this web site as a daemon on Linux. I use Nginx proxy-server + Kestrel.
When Im try to connect by http://#MyIPadress#:5000 - everything is alright. But When Im try to connect from computer, that dont have local connection with server - I catching error connection time-out.
Ping to server:
packets transmitted 9
received 0
packet loss 100 %
time 8162 ms
Open ports:
Command: sudo ufw status
80 ALLOW Anywhere
443 ALLOW Anywhere
80/tcp ALLOW Anywhere
443/tcp ALLOW Anywhere
80 (v6) ALLOW Anywhere (v6)
443 (v6) ALLOW Anywhere (v6)
80/tcp (v6) ALLOW Anywhere (v6)
443/tcp (v6) ALLOW Anywhere (v6)
Also, Ports 80 and 443 forwaded on my local IP.
Nginx settings
server {
listen 80;
server_name promzona.ddns.net;
proxy_send_timeout 1000;
proxy_read_timeout 1000;
location / {
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Connection $http_connection;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
ASP.NET CORE Program.cs
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseContentRoot("/home/promzona/All Works/ASP CORE Tutorial")
.UseStartup<Startup>()
.UseKestrel(options =>
{
options.Limits.RequestHeadersTimeout = new TimeSpan(0, 5, 0);
options.Limits.KeepAliveTimeout = new TimeSpan(0, 10, 0);
})
.Build();
}
ASP.NET CORE middleware
public void Configure(IApplicationBuilder app)
{
Console.WriteLine("NEW CONNECTION");
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider("/home/promzona/All Works/ASP CORE Tutorial")
});
app.UseMiddleware<CounterMiddleware>();
app.Run(async (context) =>
{
await context.Response.WriteAsync(System.IO.Directory.GetCurrentDirectory());
});
}
.
CounterMiddleware is my middleware, that count the number of pressing button and return number of this clicks.
Logs
Nginx logs show only success connections, connections from my computer. My server logs dont show unsuccess connection too.
Command: sudo tcpdump -i enp3s0 host (my_local_ip) and port 80
In this case I see when I am try to connect, but when I am try to connect from another machine - connection time-out
Command: sudo tcpdump -i enp3s0 dst (my_IP) and port 80
Similar situation.
Question
Why external coonnection to my server failing, and how to fix it?