Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot proxy to sites that require a correct Host header #2675

Open
bataras opened this issue Mar 13, 2023 · 8 comments · May be fixed by #3247
Open

Cannot proxy to sites that require a correct Host header #2675

bataras opened this issue Mar 13, 2023 · 8 comments · May be fixed by #3247

Comments

@bataras
Copy link

bataras commented Mar 13, 2023

This line...

https://github.com/NginxProxyManager/nginx-proxy-manager/blame/develop/docker/rootfs/etc/nginx/conf.d/include/proxy.conf#L2

I believe should be...

proxy_set_header Host $proxy_host;

(I got the below to work by doing it)

Without that, proxy requests are being forwarded to websites with the original Host header and those sites are returning an error or a 404. For example, trying proxying data.example.com to an S3 bucket like mybucket.s3-website-us-east-1.amazonaws.com:80

S3 will reply with something like..

404 Not Found
Code: NoSuchBucket
Message: The specified bucket does not exist
BucketName: data.example.com
RequestId: J8K24Y80A04JNFY4
HostId: ksf8GNLOX46prb58795rY6bxvr81Lfm6xzKnWTJcXLEaomW69xYWmBJBvcWV4VMZJEZohq4CF4s=

Further, you cannot override this proxy_set_header command by adding it to the advanced custom config in the UI because it simply appends the value to the existing header. ie, S3 will reply as blow (note the BucketName)...

404 Not Found
Code: NoSuchBucket
Message: The specified bucket does not exist
BucketName: data.example.com mybucket.s3-website-us-east-1.amazonaws.com

Nor have I found a way to "unset" proxy_set_header Host. I tried using "Headers More" to no avail: https://www.nginx.com/resources/wiki/modules/headers_more/

@bataras bataras added the bug label Mar 13, 2023
@kabadisha
Copy link

If I understand correctly, currently NPM passes the hostname from the original request through to the upstream server. In many use-cases (perhaps the majority) this is probably the desired behaviour.

Do you want the upstream server (S3 in your case) to see the value you entered in the UI for "Forward Hostname / IP"?

@bataras
Copy link
Author

bataras commented Mar 19, 2023

I believe with reverese proxying, the target should not receive the original request's Host header. The target should receive a new Host header specific to the target (ie the s3 host example above) and it should additionally receive an X-Forwarded-For header indicating the original request's host header (actually XFF is a chain of forwarding headers beginning with the original request's Host header.

@kabadisha
Copy link

You may just be right about that. I wonder if there is a public RFC which sets out the standard behaviour?

You could create a pull request for the change and see if the maintainers will accept it. You'd also need to check the same change is applied to custom location declarations too.

@qzydustin
Copy link

qzydustin commented Jul 5, 2023

I met the same problem, I needed to use $proxy_host because I aim to speed up visiting a website.

For example, I visit abc.com slowly, so I use my VPS and my domain abc.mydomain.com to proxy it. In this case, I should use $proxy_host instead of $host.

Solution: Edit Advanced - Custom Nginx Configuration like below.

location / {
  proxy_pass       $forward_scheme://$server:$port$request_uri;
#  The following line is the nginx default configuration, so there is no difference whether it is commented
#  proxy_set_header Host $proxy_host;
}

Further, you cannot override this proxy_set_header command by adding it to the advanced custom config in the UI because it simply appends the value to the existing header.

This is different from what I tested. The content in Advanced - Custom Nginx Configuration will replace config instead of appending

I highly recommend that developers add an option in the web page graphical configuration, proxy_set_header Host is followed by $host or $proxy_host. Give the users a choice.

@vbraun
Copy link

vbraun commented Aug 27, 2023

I'm having the same problem. In my case the proxied app redirects to $HOST/login.html, whereas it has to redirect to $HOST/location/login.html for login to work.

And you can indeed work around it by just pasting the custom nginx configuration, but thats kind of besides the point.

The nginx default for Host is $proxy_host (https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/), probably precisely for this reason:

By default, NGINX redefines two header fields in proxied requests, “Host” and “Connection”, and eliminates the header fields whose values are empty strings. “Host” is set to the $proxy_host variable, and “Connection” is set to close.

IMHO the default should be respected, in the unlikely case that you truly want to overide Host with $host then you can always set up the location and add a custom header.

@weiyuDatawiza
Copy link

I deleted the line
proxy_set_header Host $host;
in /etc/nginx/conf.d/include/proxy.conf

vbraun added a commit to vbraun/nginx-proxy-manager that referenced this issue Oct 8, 2023
* $host is the Host sent by the user's browser. This is the correct
  setting if the service has built-in support for being proxied.

* $proxy_host is the Host as if the browser would run on the
  proxy. This is the correct setting if the service does not have
  built-in support for reverse proxies. It is also the nginx default.

* In nginx, you cannot unset the Host header. Configuring headers
  multiple times just sends multiple values with the http request. So
  there is no way to "fix" the Host by adding a custom header if it is
  already set.

For these reasons, Host should not be set (and default to
$proxy_host). In the unlikely case that your service needs something
else you can then just set the header in the GUI.

Fixes NginxProxyManager#2675
vbraun added a commit to vbraun/nginx-proxy-manager that referenced this issue Oct 8, 2023
* $host is the Host sent by the user's browser. This is the correct
  setting if the service has built-in support for being proxied.

* $proxy_host is the Host as if the browser would run on the
  proxy. This is the correct setting if the service does not have
  built-in support for reverse proxies. It is also the nginx default.

* In nginx, you cannot unset the Host header. Configuring headers
  multiple times just sends multiple values with the http request. So
  there is no way to "fix" the Host by adding a custom header if it is
  already set.

For these reasons, Host should not be set (and default to
$proxy_host). In the unlikely case that your service needs something
else you can then just set the header in the GUI.

Fixes NginxProxyManager#2675
@vbraun vbraun linked a pull request Oct 8, 2023 that will close this issue
Copy link

Issue is now considered stale. If you want to keep it open, please comment 👍

@github-actions github-actions bot added the stale label Apr 17, 2024
@clhey
Copy link
Contributor

clhey commented Apr 28, 2024

I conducted a test using the custom location feature and concluded that the header configuration within the custom location cannot override the default header configurations provided by nginxproxymanager, such as:

perl
Copy code
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Scheme $scheme;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://192.168.1.250:8080;
Is there a method available to ensure that the headers in the custom configuration can override the default headers?

config:
image

nginx proxy file:
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants