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

🔼 added $resolved_proto map #4262

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from

Conversation

MansourM
Copy link

@MansourM MansourM commented Dec 29, 2024

Improve Protocol Forwarding Accuracy Using resolved_proto

This PR enhances the accuracy of protocol forwarding in Nginx Proxy Manager by introducing a resolved_proto map variable. The resolved_proto variable ensures that the X-Forwarded-Proto and X-Forwarded-Scheme headers consistently reflect the most authoritative protocol information, particularly in setups involving upstream proxies like Cloudflare or AWS.

Context

While learning Nginx, I encountered an issue where protocol mismatches occurred in setups using Cloudflare's proxy feature, leading to errors in applications like Laravel. Specifically, in my case, Laravel's Livewire file upload feature failed with unauthorized errors when the X-Forwarded-Proto header was incorrectly set to http instead of https.

After investigating further, I discovered that the proxy.conf file in Nginx Proxy Manager always sets X-Forwarded-Proto to $scheme, which can conflict with the upstream X-Forwarded-Proto header set by proxies such as Cloudflare. This issue is compounded because these lines are automatically included in the default location block, leaving no way to override them through the UI.

Changes in This PR

To address this issue:
A resolved_proto map is introduced:

map $http_x_forwarded_proto $resolved_proto {
    default $scheme;
    ~.+ $http_x_forwarded_proto;
}

X-Forwarded-Proto and X-Forwarded-Scheme headers now use $resolved_proto instead of $scheme in proxy.conf and _location.conf.

Benefits

  • Ensures that the X-Forwarded-Proto and X-Forwarded-Scheme headers correctly reflect the protocol information from upstream sources.
  • Resolves compatibility issues with upstream proxies like Cloudflare and AWS, ensuring seamless integration with applications relying on accurate protocol headers.

Notes

This PR serves as a suggestion and might not cover every edge case, as I’m still learning Nginx. However, it addresses a common issue many users face, as documented in this discussion, and many more I saw in Laravel, Livewire or Filament issues while researching.
any feedback is welcome to refine the implementation further.

 to ensure that the X-Forwarded-Proto and X-Forwarded-Scheme headers reflect the most accurate protocol. The resolved_proto variable prioritizes the X-Forwarded-Proto header (set by sources like Cloudflare or AWS) and falls back to $scheme when unavailable, then this value is used to set Scheme and Proto instead of $scheme
@jc21
Copy link
Member

jc21 commented Dec 29, 2024

This is a beautiful example of a well written PR comment :)

Thanks for looking into this - NPM was originally written with the concept that it would be the edge server and not behind another proxy.

CI is currently failing with:

16:42:43  nginx: [emerg] unknown "resolved_proto" variable

… should put it in `/docker/rootfs/etc/nginx/conf.d/include/resolved_proto_map.conf` instead.
@MansourM
Copy link
Author

MansourM commented Dec 29, 2024

This is a beautiful example of a well written PR comment :)

Thank you very much :)
I'm trying to make an easy to use deployment script for Laravel apps and found NPM a very useful tool in doing so, still have a lot to learn though, if you know any good resource, let me know

one thing i do not understand is how this setting can effect my nginx config in laravel container for example if i manually set
proxy_set_header X-Forwarded-Proto https; this value still gets overwritten by what is inside proxy host config, should not my config overwrite that? but its working the other way around.

@jc21
Copy link
Member

jc21 commented Jan 1, 2025

See this file which has the default location /. That then includes this file which sets the header on that level.

In order to override this, you'll have to define the entire location / { block in the Advanced config tab:

location / {
  add_header       X-Served-By $host;
  proxy_set_header Host $host;
  proxy_set_header X-Forwarded-Scheme $scheme;
  proxy_set_header X-Forwarded-Proto  https;
  proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
  proxy_set_header X-Real-IP          $remote_addr;
  proxy_pass       $forward_scheme://$server:$port$request_uri;
}

and in doing so, the host won't use the default location / {. Also be aware that the default block includes access control config and other config statements that would need to be added if your host needed them.

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

Successfully merging this pull request may close these issues.

2 participants