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

"Contradictory scheme headers" when passing both X-Forwarded-Proto and X-Forwarded-Protocol #226

Closed
daliborfilus opened this issue Jul 17, 2020 · 6 comments · May be fixed by #406
Closed

Comments

@daliborfilus
Copy link

daliborfilus commented Jul 17, 2020

When using this nginx configuration:

    location / {
        proxy_http_version 1.1;
        proxy_pass_request_headers on;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $http_connection;
        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;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Protocol $scheme;
        #proxy_set_header X-Forwarded-Ssl on;
        proxy_set_header X-Forwarded-Host $http_host;
        proxy_set_header X-Scheme $scheme;
        proxy_pass http://127.0.0.1:8080/;
        proxy_buffering off;
    }

Seafile throws Bad request "Contradictory scheme headers".
I removed every single header one by one and the error disappears when you either remove X-Forwarded-Proto OR X-Forwarded-Protocol. If you have only one of them, it works. If both, it doesn't.

I know it isn't necessary to use all these headers, but they are surely not contradictory.
(I use all of them just because each app uses different one and I use this as a template for every app.)

Seafile version: Docker seafileltd/seafile-mc:latest, tag: e0edf79c2d14,

@rene-s
Copy link

rene-s commented Dec 28, 2020

I am able to reproduce this.
My vhost config:

server {
  listen 443 ssl;
  listen [::]:443 ssl;

  server_name test.*;

  ssl_certificate     /etc/acme.sh/certs/test.example.com.cert.pem;
  ssl_certificate_key /etc/acme.sh/certs/test.example.com.key.pem;

  include includes/security_tls.conf;
  include includes/security.conf;
  include includes/error_pages_default.conf;

  client_max_body_size 0;

  location / {
    include includes/proxy.conf;
    resolver 127.0.0.11 valid=30s;
    set $upstream_app 127.0.0.1;
    set $upstream_port 12080;
    set $upstream_proto http;
    proxy_pass $upstream_proto://$upstream_app:$upstream_port;
  }
}

proxy.conf:

# Timeout if the real server is dead
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;

# Proxy Connection Settings
proxy_buffers 32 4k;
proxy_connect_timeout 240;
proxy_headers_hash_bucket_size 128;
proxy_headers_hash_max_size 1024;
proxy_http_version 1.1;
proxy_read_timeout 240;
proxy_redirect  http://  $scheme://;
proxy_send_timeout 240;

# Proxy Cache and Cookie Settings
proxy_cache_bypass $cookie_session;
#proxy_cookie_path / "/; Secure"; # enable at your own risk, may break certain apps
proxy_no_cache $cookie_session;

# Proxy Header Settings
proxy_set_header Connection $connection_upgrade;
proxy_set_header Early-Data $ssl_early_data;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Ssl on;
proxy_set_header X-Real-IP $remote_addr;

Result when I request the Seafile login form:

Bad Request
Contradictory scheme headers 

However, when I change X-Forwarded-Ssl from on to off (thus making it indeed contradictory to X-Forwarded-Proto) or when I omit X-Forwarded-Ssl the error interestingly disappears.

@jonbranan
Copy link

For those sick and tired of being sick and tired:

If you use linuxservers SWAG or older letsencrypt server, the issue is slightly more nuanced. The challenge is that proxy_set_header X-Forwarded-Ssl ""; or proxy_hide_header X-Forwarded-Ssl; doesn't work. Apparently, you cannot allow SWAG's /config/nginx/proxy.conf to set the header and hide it in your new .conf file. You have to essentially comment out include /config/nginx/proxy.conf; and copy the contents minus the X-Forwarded-Ssl header.

Here is my working example:

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    server_name seafile.*;

    include /config/nginx/ssl.conf;

    client_max_body_size 0;


    location / {
        # Timeout if the real server is dead
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;

        # Proxy Connection Settings
        proxy_buffers 32 4k;
        proxy_connect_timeout 240;
        proxy_headers_hash_bucket_size 128;
        proxy_headers_hash_max_size 1024;
        proxy_http_version 1.1;
        proxy_read_timeout 240;
        proxy_redirect  http://  $scheme://;
        proxy_send_timeout 240;

        # Proxy Cache and Cookie Settings
        proxy_cache_bypass $cookie_session;
        #proxy_cookie_path / "/; Secure"; # enable at your own risk, may break certain apps
        proxy_no_cache $cookie_session;

        # Proxy Header Settings
        proxy_set_header Connection $connection_upgrade;
        proxy_set_header Early-Data $ssl_early_data;
        proxy_set_header Host $host;
        proxy_set_header Proxy "";
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Proto https;
        # DON'T ENABLE
        # proxy_set_header X-Forwarded-Ssl on;
        proxy_set_header X-Real-IP $remote_addr;
        
        # Only way to remove the X-Forwarded-Ssl header is to not set it in the first place.
        # include /config/nginx/proxy.conf;
        include /config/nginx/resolver.conf;
        set $upstream_app seafile;
        set $upstream_port 80;
        set $upstream_proto http;
        proxy_pass $upstream_proto://$upstream_app:$upstream_port;

    }
}

Reason proxy_set_header or proxy_hide_header doesn't work.

@akostadinov
Copy link

akostadinov commented Sep 3, 2024

@SkywalkerSpace , could you clarify how and where was this fixed? I'm hitting this issue with docker.io/seafileltd/seafile-mc:11.0-latest which presently is 12fb3ba5694a from 2 weeks ago.

For anybody ending up here with such issue, I fixed by preventing nginx running inside the seafile container from overriding the X-Forwarded-Proto and x-forwarded-ssl headers.

Because the container host running seafile is running multiple services, I have to have an outer reverse proxy. And that reverse proxy is setting the X-Forwarded-Proto and x-forwarded-ssl headers. But seafile's nginx overrides X-Forwarded-Proto .

This makes these two header inconsistent and causes gunicorn to show the error "Contradictory scheme headers".

To fix, I edited nginx/conf/seafile.nginx.conf and removed the following lines:

  • proxy_set_header Forwarded
    
  • proxy_set_header X-Forwarded-Proto
    
  • proxy_set_header X-Real-IP
    

That's enough but for setting properly X-Real-IP I added the following line:

set_real_ip_from 192.168.70.0/24;

This is my entire local network but service can only be accessed through the local outer reverse proxy anyway, so it doesn't really matter. I could put 0.0.0.0/0 in there.

@Thidsa
Copy link

Thidsa commented Oct 20, 2024

@akostadinov Hi. Cant seem to find this file nginx/conf/seafile.nginx.conf in any seafile container

Disregard this...found it somewhere else :) Thanks for the help. This worked

@espadrine
Copy link

I have the same setup as @akostadinov (exterior proxy handling TLS, and the service in docker being HTTP-only). Commenting proxy_set_header X-Forwarded-Proto "$scheme"; works, and I check that I get X-Forwarded-Proto=https, along with X-Forwarded-Ssl=on, in the requests.

To avoid the issue altogether, I wonder whether the project can remove the proxy_set_header X-Forwarded-Proto "$scheme" altogether. It is clearly incorrect in some setups. I understand that it wants to have it be set when NGINX is the proxy that does the TLS termination. Something like this would be more general:

    if ($http_x_forwarded_proto = "") {
        proxy_set_header X-Forwarded-Proto $scheme;
    }

espadrine added a commit to espadrine/seafile-docker that referenced this issue Oct 28, 2024
When the seafile docker container
is behind a proxy that does the TLS termination,
such that the seafile docker sees HTTP only,
then, it receives requests
where the following headers are set in the following way:

    X-Forwarded-Proto: https
    X-Forwarded-Ssl: on

Because the default NGINX template has this directive:

    proxy_set_header X-Forwarded-Proto $scheme

the request gets transmitted to gunicorn with the following,
contradictory values:

    X-Forwarded-Proto: http
    X-Forwarded-Ssl: on

Thus Seafile rejects the requests
with a "Contradictory scheme headers" error.

We instead change the header only when it is not set.

Fixes haiwen#226.
espadrine added a commit to espadrine/seafile-docker that referenced this issue Oct 28, 2024
When the seafile docker container
is behind a proxy that does the TLS termination,
such that the seafile docker sees HTTP only,
then, it receives requests
where the following headers are set in the following way:

    X-Forwarded-Proto: https
    X-Forwarded-Ssl: on

Because the default NGINX template has this directive:

    proxy_set_header X-Forwarded-Proto $scheme

the request gets transmitted to gunicorn with the following,
contradictory values:

    X-Forwarded-Proto: http
    X-Forwarded-Ssl: on

Thus Seafile rejects the requests
with a "Contradictory scheme headers" error.

We instead change the header only when it is not set.

Fixes haiwen#226.
espadrine added a commit to espadrine/seafile-docker that referenced this issue Oct 28, 2024
When the seafile docker container
is behind a proxy that does the TLS termination,
such that the seafile docker sees HTTP only,
then, it receives requests
where the following headers are set in the following way:

    X-Forwarded-Proto: https
    X-Forwarded-Ssl: on

Because the default NGINX template has this directive:

    proxy_set_header X-Forwarded-Proto $scheme

the request gets transmitted to gunicorn with the following,
contradictory values:

    X-Forwarded-Proto: http
    X-Forwarded-Ssl: on

Thus Seafile rejects the requests
with a "Contradictory scheme headers" error.

We instead change the header only when it is not set.

Fixes haiwen#226.
@freeplant
Copy link
Member

In version 12.0, we will redesign the docker based deployment and move HTTPS to a dedicated reverse proxy. See https://manual.seafile.com/12.0/setup/overview/

At that time, please check the issue again.

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 a pull request may close this issue.

8 participants