janeczku / calibre-web

:books: Web app for browsing, reading and downloading eBooks stored in a Calibre database
GNU General Public License v3.0
13k stars 1.39k forks source link

Reverse Proxy Authentication Not Functional #2599

Closed Ryonez closed 1 week ago

Ryonez commented 1 year ago

Describe the bug/problem I've configured calibre-web and oauth2-proxy to use Reverse Proxy Authentication. However all I get after signing into my oauth service is calibre-web's login page.

To Reproduce Steps to reproduce the behavior:

  1. Enter the url for calibre-web
  2. Log in via the proxy and it's configured oauth service.
  3. See calibre-web's login screen.

Logfile

calibre-web log ``` [2022-11-14 18:11:40,816] WARN {cps.config_sql:327} Log path None not valid, falling back to default [2022-11-14 18:11:40,859] WARN {cps.config_sql:358} invalidating configuration [2022-11-14 18:11:40,899] INFO {cps:143} *** "greenlet" version does not fit the requirements. Should: available, Found: Not available, please consider installing required version *** [2022-11-14 18:11:40,900] INFO {cps:152} Starting Calibre Web... [2022-11-14 18:11:41,728] INFO {apscheduler.scheduler:171} Scheduler started [2022-11-14 18:11:41,936] WARN {py.warnings:109} /usr/local/lib/python3.10/dist-packages/apscheduler/util.py:436: PytzUsageWarning: The localize method is no longer necessary, as this time zone supports the fold attribute (PEP 495). For more details on migrating to a PEP 495-compliant implementation, see https://pytz-deprecation-shim.readthedocs.io/en/latest/migration.html return tzinfo.localize(dt) [2022-11-14 18:11:41,937] INFO {apscheduler.scheduler:885} Added job "end scheduled task" to job store "default" [2022-11-14 18:11:42,057] INFO {cps.ub:890} github Blueprint Created [2022-11-14 18:11:42,086] INFO {cps.ub:890} google Blueprint Created [2022-11-14 18:11:42,818] INFO {cps.server:205} Starting Gevent server on [::]:8083 [2022-11-14 18:12:33,242] INFO {cps.server:275} webserver stop (restart=True) [2022-11-14 18:12:34,248] INFO {cps.server:263} Performing restart of Calibre-Web [2022-11-14 18:12:35,734] INFO {cps:143} *** "greenlet" version does not fit the requirements. Should: available, Found: Not available, please consider installing required version *** [2022-11-14 18:12:35,734] INFO {cps:152} Starting Calibre Web... [2022-11-14 18:12:36,442] INFO {apscheduler.scheduler:171} Scheduler started [2022-11-14 18:12:36,646] WARN {py.warnings:109} /usr/local/lib/python3.10/dist-packages/apscheduler/util.py:436: PytzUsageWarning: The localize method is no longer necessary, as this time zone supports the fold attribute (PEP 495). For more details on migrating to a PEP 495-compliant implementation, see https://pytz-deprecation-shim.readthedocs.io/en/latest/migration.html return tzinfo.localize(dt) [2022-11-14 18:12:36,647] INFO {apscheduler.scheduler:885} Added job "end scheduled task" to job store "default" [2022-11-14 18:12:37,436] INFO {cps.server:205} Starting Gevent server on [::]:8083 [2022-11-14 18:21:46,910] INFO {cps.server:275} webserver stop (restart=True) [2022-11-14 18:21:47,917] INFO {cps.server:263} Performing restart of Calibre-Web [2022-11-14 18:21:49,019] INFO {cps:143} *** "greenlet" version does not fit the requirements. Should: available, Found: Not available, please consider installing required version *** [2022-11-14 18:21:49,019] INFO {cps:152} Starting Calibre Web... [2022-11-14 18:21:49,796] INFO {apscheduler.scheduler:171} Scheduler started [2022-11-14 18:21:49,984] WARN {py.warnings:109} /usr/local/lib/python3.10/dist-packages/apscheduler/util.py:436: PytzUsageWarning: The localize method is no longer necessary, as this time zone supports the fold attribute (PEP 495). For more details on migrating to a PEP 495-compliant implementation, see https://pytz-deprecation-shim.readthedocs.io/en/latest/migration.html return tzinfo.localize(dt) [2022-11-14 18:21:49,984] INFO {apscheduler.scheduler:885} Added job "end scheduled task" to job store "default" [2022-11-14 18:21:50,832] INFO {cps.server:205} Starting Gevent server on [::]:8083 ```
access log ``` ::ffff:172.21.0.78 - - [2022-11-14 18:08:33] "GET /login/github/authorized?error=redirect_uri_mismatch&error_description=The+redirect_uri+MUST+match+the+registered+callback+URL+for+this+application.&error_uri=https%3A%2F%2Fdocs.github.com%2Fapps%2Fmanaging-oauth-apps%2Ftroubleshooting-authorization-request-errors%2F%23redirect-uri-mismatch&state=5xP4ggIo0dklV8MOe6RcMeqk04ZQ72 HTTP/1.1" 302 1286 0.008905 ::ffff:172.21.0.78 - - [2022-11-14 18:08:33] "GET /link/github HTTP/1.1" 302 1289 0.009295 ::ffff:172.21.0.78 - - [2022-11-14 18:08:33] "GET /login/github HTTP/1.1" 302 1867 0.008432 ::ffff:172.21.0.78 - - [2022-11-14 18:08:33] "GET /login/github/authorized?error=redirect_uri_mismatch&error_description=The+redirect_uri+MUST+match+the+registered+callback+URL+for+this+application.&error_uri=https%3A%2F%2Fdocs.github.com%2Fapps%2Fmanaging-oauth-apps%2Ftroubleshooting-authorization-request-errors%2F%23redirect-uri-mismatch&state=HnFDDafoztBHH2snlccQcyTHLUmugI HTTP/1.1" 302 1289 0.008597 ::ffff:172.21.0.78 - - [2022-11-14 18:08:33] "GET /link/github HTTP/1.1" 302 1292 0.008381 ::ffff:172.21.0.78 - - [2022-11-14 18:08:34] "GET /login/github HTTP/1.1" 302 1871 0.007950 ::ffff:172.21.0.78 - - [2022-11-14 18:08:34] "GET /login/github/authorized?error=redirect_uri_mismatch&error_description=The+redirect_uri+MUST+match+the+registered+callback+URL+for+this+application.&error_uri=https%3A%2F%2Fdocs.github.com%2Fapps%2Fmanaging-oauth-apps%2Ftroubleshooting-authorization-request-errors%2F%23redirect-uri-mismatch&state=hUDa7swFi4EfN76xjyMqNNvEkIHatb HTTP/1.1" 302 1294 0.009378 ::ffff:172.21.0.78 - - [2022-11-14 18:08:34] "GET /link/github HTTP/1.1" 302 1297 0.010458 ::ffff:172.21.0.78 - - [2022-11-14 18:08:34] "GET /login/github HTTP/1.1" 302 1875 0.008565 ::ffff:172.21.0.78 - - [2022-11-14 18:08:40] "GET /login/github/authorized?error=redirect_uri_mismatch&error_description=The+redirect_uri+MUST+match+the+registered+callback+URL+for+this+application.&error_uri=https%3A%2F%2Fdocs.github.com%2Fapps%2Fmanaging-oauth-apps%2Ftroubleshooting-authorization-request-errors%2F%23redirect-uri-mismatch&state=rYEwahxDbyA8xRwoOcZUDJ28uAXIq7 HTTP/1.1" 302 1297 0.008587 ::ffff:172.21.0.78 - - [2022-11-14 18:08:40] "GET /link/github HTTP/1.1" 302 1300 0.009946 ::ffff:10.1.1.30 - - [2022-11-14 18:08:49] "POST /admin/ajaxconfig HTTP/1.1" 200 935 0.046013 ::ffff:10.1.1.30 - - [2022-11-14 18:08:53] "GET /admin/alive HTTP/1.1" 200 706 0.010689 ::ffff:172.21.0.78 - - [2022-11-14 18:08:55] "GET /login?next=%2F HTTP/1.1" 200 10044 0.111359 ::ffff:172.21.0.78 - - [2022-11-14 18:08:55] "GET /static/js/libs/bootstrap.min.js HTTP/1.1" 200 40549 0.009020 ::ffff:172.21.0.78 - - [2022-11-14 18:08:55] "GET /static/css/upload.css HTTP/1.1" 200 1006 0.010103 ::ffff:172.21.0.78 - - [2022-11-14 18:08:55] "GET /static/js/libs/underscore-umd-min.js HTTP/1.1" 200 20403 0.009194 ::ffff:172.21.0.78 - - [2022-11-14 18:08:55] "GET /static/css/libs/bootstrap.min.css HTTP/1.1" 200 122305 0.010966 ::ffff:172.21.0.78 - - [2022-11-14 18:08:55] "GET /static/js/libs/context.min.js HTTP/1.1" 200 2399 0.010684 ::ffff:172.21.0.78 - - [2022-11-14 18:08:55] "GET /static/js/main.js HTTP/1.1" 200 30405 0.009758 ::ffff:172.21.0.78 - - [2022-11-14 18:08:55] "GET /static/js/uploadprogress.js HTTP/1.1" 200 8269 0.010633 ::ffff:172.21.0.78 - - [2022-11-14 18:08:55] "GET /static/js/libs/intention.min.js HTTP/1.1" 200 6732 0.010657 ::ffff:172.21.0.78 - - [2022-11-14 18:08:55] "GET /static/js/libs/jquery.min.js HTTP/1.1" 200 90366 0.010481 ::ffff:172.21.0.78 - - [2022-11-14 18:08:55] "GET /static/css/style.css HTTP/1.1" 200 9706 0.010360 ::ffff:172.21.0.78 - - [2022-11-14 18:08:55] "GET /static/js/libs/plugins.js HTTP/1.1" 200 80846 0.010252 ::ffff:172.21.0.78 - - [2022-11-14 18:08:55] "GET /static/js/libs/jquery.form.min.js HTTP/1.1" 200 17964 0.009088 ::ffff:172.21.0.78 - - [2022-11-14 18:08:55] "GET /static/css/fonts/GrandHotel-Regular.ttf HTTP/1.1" 200 45397 0.008195 ::ffff:172.21.0.78 - - [2022-11-14 18:09:02] "GET / HTTP/1.1" 302 1093 0.009083 ::ffff:172.21.0.78 - - [2022-11-14 18:09:02] "GET /login?next=%2F HTTP/1.1" 200 5413 0.013461 ::ffff:172.21.0.78 - - [2022-11-14 18:09:02] "GET /static/css/libs/bootstrap.min.css HTTP/1.1" 200 122305 0.014992 ::ffff:172.21.0.78 - - [2022-11-14 18:09:02] "GET /static/css/style.css HTTP/1.1" 200 9706 0.009387 ::ffff:172.21.0.78 - - [2022-11-14 18:09:02] "GET /static/js/main.js HTTP/1.1" 304 739 0.009160 ::ffff:172.21.0.78 - - [2022-11-14 18:09:02] "GET /static/js/libs/underscore-umd-min.js HTTP/1.1" 304 753 0.010191 ::ffff:172.21.0.78 - - [2022-11-14 18:09:02] "GET /static/js/libs/plugins.js HTTP/1.1" 304 742 0.009971 ::ffff:172.21.0.78 - - [2022-11-14 18:09:02] "GET /static/js/libs/jquery.form.min.js HTTP/1.1" 304 750 0.009328 ::ffff:172.21.0.78 - - [2022-11-14 18:09:02] "GET /static/js/uploadprogress.js HTTP/1.1" 304 749 0.008466 ::ffff:172.21.0.78 - - [2022-11-14 18:09:02] "GET /static/js/libs/intention.min.js HTTP/1.1" 304 748 0.008000 ::ffff:172.21.0.78 - - [2022-11-14 18:09:02] "GET /static/js/libs/bootstrap.min.js HTTP/1.1" 304 748 0.007437 ::ffff:172.21.0.78 - - [2022-11-14 18:09:02] "GET /static/js/libs/jquery.min.js HTTP/1.1" 304 745 0.007357 ::ffff:172.21.0.78 - - [2022-11-14 18:09:02] "GET /static/css/upload.css HTTP/1.1" 200 1006 0.008017 ::ffff:172.21.0.78 - - [2022-11-14 18:09:02] "GET /static/js/libs/context.min.js HTTP/1.1" 304 746 0.007368 ::ffff:172.21.0.78 - - [2022-11-14 18:09:03] "GET /static/css/fonts/GrandHotel-Regular.ttf HTTP/1.1" 304 754 0.008151 ::ffff:10.1.1.30 - - [2022-11-14 18:21:50] "GET /admin/alive HTTP/1.1" 200 705 0.012194 ::ffff:10.1.1.30 - - [2022-11-14 18:21:55] "GET /admin/logfile HTTP/1.1" 200 10297 0.115364 ::ffff:10.1.1.30 - - [2022-11-14 18:21:55] "GET /static/css/libs/bootstrap.min.css HTTP/1.1" 200 122294 0.007025 ::ffff:10.1.1.30 - - [2022-11-14 18:21:55] "GET /static/css/style.css HTTP/1.1" 200 9695 0.005388 ::ffff:10.1.1.30 - - [2022-11-14 18:21:55] "GET /static/css/upload.css HTTP/1.1" 200 995 0.005265 ::ffff:10.1.1.30 - - [2022-11-14 18:21:55] "GET /static/js/libs/bootstrap.min.js HTTP/1.1" 304 737 0.005997 ::ffff:10.1.1.30 - - [2022-11-14 18:21:55] "GET /static/js/libs/underscore-umd-min.js HTTP/1.1" 304 742 0.008168 ::ffff:10.1.1.30 - - [2022-11-14 18:21:55] "GET /static/css/caliBlur_override.css HTTP/1.1" 200 1251 0.009497 ::ffff:10.1.1.30 - - [2022-11-14 18:21:55] "GET /static/js/libs/jquery.min.js HTTP/1.1" 304 734 0.005032 ::ffff:10.1.1.30 - - [2022-11-14 18:21:55] "GET /static/js/libs/intention.min.js HTTP/1.1" 304 737 0.005078 ::ffff:10.1.1.30 - - [2022-11-14 18:21:55] "GET /static/js/libs/context.min.js HTTP/1.1" 304 735 0.004633 ::ffff:10.1.1.30 - - [2022-11-14 18:21:55] "GET /static/js/libs/plugins.js HTTP/1.1" 304 731 0.004703 ::ffff:10.1.1.30 - - [2022-11-14 18:21:55] "GET /static/css/caliBlur.css HTTP/1.1" 200 680401 0.055624 ::ffff:10.1.1.30 - - [2022-11-14 18:21:55] "GET /static/js/libs/jquery.form.min.js HTTP/1.1" 304 739 0.005512 ::ffff:10.1.1.30 - - [2022-11-14 18:21:55] "GET /static/js/main.js HTTP/1.1" 304 728 0.004619 ::ffff:10.1.1.30 - - [2022-11-14 18:21:55] "GET /static/js/uploadprogress.js HTTP/1.1" 304 738 0.004074 ::ffff:10.1.1.30 - - [2022-11-14 18:21:55] "GET /static/js/libs/jquery.visible.min.js HTTP/1.1" 304 742 0.004779 ::ffff:10.1.1.30 - - [2022-11-14 18:21:55] "GET /static/js/libs/compromise.min.js HTTP/1.1" 304 738 0.004112 ::ffff:10.1.1.30 - - [2022-11-14 18:21:55] "GET /static/js/libs/readmore.min.js HTTP/1.1" 304 736 0.004338 ::ffff:10.1.1.30 - - [2022-11-14 18:21:55] "GET /static/js/caliBlur.js HTTP/1.1" 304 732 0.005232 ::ffff:10.1.1.30 - - [2022-11-14 18:21:55] "GET /static/js/logviewer.js HTTP/1.1" 304 733 0.004992 ::ffff:10.1.1.30 - - [2022-11-14 18:21:55] "GET /static/css/images/caliblur/blur-noise.png HTTP/1.1" 304 735 0.005583 ::ffff:10.1.1.30 - - [2022-11-14 18:21:55] "GET /static/css/fonts/glyphicons-halflings-regular.woff2 HTTP/1.1" 304 755 0.004538 ::ffff:10.1.1.30 - - [2022-11-14 18:21:55] "GET /static/css/images/caliblur/blur-light.png HTTP/1.1" 304 735 0.004616 ::ffff:10.1.1.30 - - [2022-11-14 18:21:55] "GET /ajax/log/0?_=1668403323501 HTTP/1.1" 200 4285 0.006363 ::ffff:10.1.1.30 - - [2022-11-14 18:21:55] "GET /static/favicon.ico HTTP/1.1" 200 62493 0.006359 ::ffff:10.1.1.30 - - [2022-11-14 18:21:56] "GET /ajax/log/1?_=1668403323502 HTTP/1.1" 200 9112 0.006184 ::ffff:10.1.1.30 - - [2022-11-14 18:27:43] "GET /ajax/log/0?_=1668403323503 HTTP/1.1" 200 4285 0.006392 ```

Expected behavior To be logged in via the user header (X-Auth-Request-Preferred-Username in my case).

Screenshots image image image

Environment (please complete the following information):

Additional context Web Proxy Container: linuxserver/swag:latest oauth2-proxy Container: quay.io/oauth2-proxy/oauth2-proxy

Swag configuration for calibre-web ``` server { listen 443 ssl; server_name calibre-web.*; include /config/nginx/resolver.conf; set $upstream_service https://alteria_calibre_web_oauth_proxy; include /config/nginx/ssl.conf; client_max_body_size 0; location / { include /config/nginx/proxy.conf; include /config/nginx/ssl_headers.conf; #proxy_set_header X-Script-Name /calibre-web; proxy_pass $upstream_service; } } ```
Config file for oauth2-proxy(cleaned) ``` ## OAuth2 Proxy Config File ## https://github.com/oauth2-proxy/oauth2-proxy ## : to listen on for HTTP/HTTPS clients https_address = ":443" ## Are we running behind a reverse proxy? Will not accept headers like X-Real-Ip unless this is set. reverse_proxy = true ## TLS Settings tls_cert_file = "/le-ssl/live/alteria.xyz/cert.pem" tls_key_file = "/le-ssl/live/alteria.xyz/privkey.pem" ## the OAuth Redirect URL. # defaults to the "https://" + requested host header + "/oauth2/callback" redirect_url = "https://calibre-web.alteria.xyz/oauth2/callback" ## the http url(s) of the upstream endpoint. If multiple, routing is based on path upstreams = "http://atlantis_calibre_web:8083" ## pass HTTP Basic Auth, X-Forwarded-User and X-Forwarded-Email information to upstream pass_basic_auth = true pass_user_headers = true ## pass the request Host Header to upstream ## when disabled the upstream Host is used as the Host Header # pass_host_header = true set_xauthrequest = true ## Email Domains to allow authentication for (this authorizes any email on this domain) ## for more granular authorization use `authenticated_emails_file` ## To authorize any email addresses use "*" email_domains = [ "*" ] ## The OAuth Client ID, Secret provider = "keycloak-oidc" client_id = "calibre-web" client_secret = "******" oidc_issuer_url = "https://auth.alteria.xyz/auth/realms/alteria" allowed_roles = "******" ## Cookie Settings ## Name - the cookie name ## Secret - the seed string for secure cookies; should be 16, 24, or 32 bytes ## for use with an AES cipher when cookie_refresh or pass_access_token ## is set ## Domain - (optional) cookie domain to force cookies to (ie: .yourcompany.com) ## Expire - (duration) expire timeframe for cookie ## Refresh - (duration) refresh the cookie when duration has elapsed after cookie was initially set. ## Should be less than cookie_expire; set to 0 to disable. ## On refresh, OAuth token is re-validated. ## (ie: 1h means tokens are refreshed on request 1hr+ after it was set) ## Secure - secure cookies are only sent by the browser of a HTTPS connection (recommended) ## HttpOnly - httponly cookies are not readable by javascript (recommended) cookie_name = "_oauth2_proxy" cookie_secret = "******" cookie_domains = "" # cookie_path = "/" cookie_expire = "168h" # cookie_refresh = "" cookie_secure = true cookie_httponly = true ## Some services fail when the cookies are to large. This strips to oauth cookie down to the bare minimun session_cookie_minimal = true ```
robertmx commented 1 year ago

I have the same problem using the linuxserver docker image. Everything works as expected when using a local install. Seems to be a docker specific problem.

robertmx commented 1 year ago

I investigated a little further and found that the remote authentication does not work with the gevent server (used inside the docker image). The tornado server is fine. Thus non-docker installs are affected by this as well.

eleith commented 1 year ago

this feature stopped working with an upgrade to V0.6.20

juchong commented 1 year ago

I've definitely lost a few hours of my life dealing with this bug.

danieljkemp commented 7 months ago

I just tried to get this working, no no avail.

Supporting generic openid-connect clients (instead of just google/github) would be a huge help in most of the cases where people are attempting to use reverse proxy auth.

farfalleflickan commented 6 months ago

This works! Tested with keycloak, oauth2-proxy & nginx.

location /oauth2/ {
        proxy_pass       http://ip:port;
        proxy_set_header Host                    $host;
        proxy_set_header X-Real-IP               $remote_addr;
        proxy_set_header X-Auth-Request-Redirect $request_uri;
        # or, if you are handling multiple domains:
        # proxy_set_header X-Auth-Request-Redirect $scheme://$host$request_uri;
    }

    location = /oauth2/auth {
        proxy_pass       http://ip:port;
        proxy_set_header Host             $host;
        proxy_set_header X-Real-IP        $remote_addr;
        proxy_set_header X-Forwarded-Uri  $request_uri;
        # nginx auth_request includes headers but not body
        proxy_set_header Content-Length   "";
        proxy_pass_request_body           off;
    }
    location /calibre/ {
        auth_request /oauth2/auth;
        error_page 401 =403 /oauth2/sign_in;
        auth_request_set $name $upstream_http_x_auth_request_preferred_username;

        proxy_bind              $server_addr;
        proxy_pass              http://ip:port;
        proxy_set_header        Host            $http_host;
        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header        X-Scheme        $scheme;
        proxy_set_header        X-Script-Name   /calibre;  # IMPORTANT: path has NO trailing slash 
        proxy_set_header        X-Forwarded-User $name;
        proxy_pass_header       X-Forwarded-User;
    }

On the calibre-web side I simply set the header to "X-Forwarded-User" Do note that this is not a complete config, just the relevant bits...

Bujiraso commented 4 months ago

You can also leverage pass_user_headers=true. There's a bunch of headers which might work. See https://oauth2-proxy.github.io/oauth2-proxy/configuration/overview/

I noticed a small quirk where you need to have an exact match to an existing user on the field for the header which you're using. So for me, X-Forwarded-User doesn't work because my provider sends its own raw ID that isn't matched, and X-Forwarded-Email eventually worked, but X-Forwarded-Preferred-Username was easier for my first try. I'm not sure why email was stubborn at first, at all. it would be great to have any user created that's missing, but that's a feature request and implementation away.

robertmx commented 1 month ago

Did anybody get this to work with the docker image from linuxserver?

Bujiraso commented 1 month ago

Did anybody get this to work with the docker image from linuxserver?

Is that this?

    image: lscr.io/linuxserver/calibre-web:latest

Yes. See my above post.

robertmx commented 1 month ago

I think the docs should be amended with the following facts

  1. A remote-user header does not work with the docker deployment because it can not be populated by a header from the proxy.
  2. Recommend a header such as xRemoteUser without dashes to prevent header smuggling due to header normalization of underscores or dashes.
robertmx commented 1 month ago

The issue can then be closed because it works as documented, just there are some hiccups with respect to allowed header names. In my case I went with REMOTE_USER, which is ignored (rightfully so I conclude after reading the relevant docs).

echofire26 commented 1 month ago

@Bujiraso @robertmx @farfalleflickan Apologies for pinging y'all - but y'all appear to be the folks with the answers here.

So for the complete layman -- a dockized deployment will no longer work for reverse proxy access since 0.6.20? I tried to look over the OAuth2 documentation Bujiraso pointed out and the code farfalleflickan included - but it's literally flying over my head.

I've got my setup behind Authelia & Nginx. Since 0.6.20 (pretty sure since then) I can only access via local network. Cloudflare throws a 524 timeout error now when trying to access my reverse proxy address after trying to login in with my credentials on the Calibre-Web login page.

robertmx commented 1 month ago

So for the complete layman -- a dockized deployment will no longer work for reverse proxy access since 0.6.20? I tried to look over the OAuth2 documentation Bujiraso pointed out and the code farfalleflickan included - but it's literally flying over my head.

That is wrong, it will work. I have exactly that setup running at home. The only caveat is, that you can not use REMOTE_USER as a header name in calibre-web in a docker container. User something like xRemoteUser instead.**

** Explanation: REMOTE_USER is not a header but an environment variable, which can only be set from a local process. It will not propagate from the proxy header to the docker container. xRemoteUser is a good choice, because you should avoid any dashes (-) in the header because these might be susceptible to header smuggling attacks due to normalization.