[GH-ISSUE #750] WebSockets through HaProxy not working ([WARN] Responding with 404 Not Found catcher.) #509

Closed
opened 2026-03-03 01:30:00 +03:00 by kerem · 4 comments
Owner

Originally created by @ElPistoler0 on GitHub (Nov 28, 2019).
Original GitHub issue: https://github.com/dani-garcia/vaultwarden/issues/750

Hi all,

Long time lurker, first-time poster. I'd like to begin by thanking the dev for this amazing work. Really appreciate it!

I enabled WebSockets on my Docker container running under Windows Server 2019. Here is my CREATE command:

`docker pull bitwardenrs/server:latest

docker create --name bitwarden_rs -p 88:80 -p 89:3012 -v SOMEDRIVE\bitwarden\data:/data -e WEBSOCKET_ENABLED=true -e DOMAIN=https://pw.blah -e SMTP_HOST=smtp.gmail.com -e SMTP_FROM=blah@gmail.com -e SMTP_PORT=465 -e SMTP_SSL=true -e SMTP_USERNAME=blah@gmail.com -e SMTP_PASSWORD=bleh -e SMTP_EXPLICIT_TLS=true -e LOG_FILE=/data/bitwarden.log -e LOG_LEVEL=warn -e EXTENDED_LOGGING=true -e ADMIN_TOKEN=********** --restart unless-stopped bitwardenrs/server:latest`

This setup is behind a pfSense firewall with HaProxy on it. I can browse to my vault, use browser extensions, and mobile apps. Everything seems to be working as expected, except for the WebSockets... Here is what I get on the BW log:

[2019-11-28 22:01:38][][WARN] Response was None.
[2019-11-28 22:01:38][
][WARN] Responding with 404 Not Found catcher.
[2019-11-28 22:01:38][][WARN] Response was None.
[2019-11-28 22:01:38][
][WARN] Responding with 404 Not Found catcher.
[2019-11-28 22:01:39][][WARN] Response was None.
[2019-11-28 22:01:39][
][WARN] Responding with 404 Not Found catcher.
[2019-11-28 22:01:39][][WARN] Response was None.
[2019-11-28 22:01:39][
][WARN] Responding with 404 Not Found catcher.
[2019-11-28 22:01:39][][WARN] Response was None.
[2019-11-28 22:01:39][
][WARN] Responding with 404 Not Found catcher.
[2019-11-28 22:01:39][][WARN] Response was None.
[2019-11-28 22:01:39][
][WARN] Responding with 404 Not Found catcher.
[2019-11-28 22:01:39][][WARN] Response was None.
[2019-11-28 22:01:39][
][WARN] Responding with 404 Not Found catcher.
[2019-11-28 22:01:39][_][WARN] Response was None.

And here's my HaProxy config:

    FE Config

acl			ACL_BW_88	hdr_beg(host) -i pw.blah
acl			ACL_BW_88_PATH	var(txn.txnpath) -m reg -i \/notifications.*\/hub\/n([^\/]+)
acl			ACL_BW_89	hdr_beg(host) -i pw.blah
acl			ACL_BW_3012_WS_PATH_b	var(txn.txnpath) -m beg -i /notifications
acl			ACL_BW_3012_WS_PATH_e	var(txn.txnpath) -m end -i /notifications/hub
acl			ACL_BW_3012_WS_HDR_UP	hdr(Connection) -i upgrade
acl			ACL_BW_3012_WS_HDR_WS	hdr(Upgrade) -i websocket
use_backend BE_HPM_BitWarden_88_ipvANY  if  ACL_BW_88 !ACL_BW_3012_WS_PATH_e 
use_backend BE_HPM_BitWarden_89_WebSockets_ipvANY  if  ACL_BW_89 ACL_BW_3012_WS_PATH_e ACL_BW_3012_WS_HDR_UP ACL_BW_3012_WS_HDR_WS 

   BE Config

backend BE_HPM_BitWarden_88_ipvANY
mode http
id 137
log global
option log-health-checks
http-response set-header Strict-Transport-Security max-age=900000;
timeout connect 600000
timeout server 600000
retries 5
server HPM_BW_88 x.x.x.x:88 id 112

backend BE_HPM_BitWarden_89_WebSockets_ipvANY
mode http
id 140
log global
option log-health-checks
http-response set-header Strict-Transport-Security max-age=900000;
timeout connect 600000
timeout server 600000
retries 5
reqrep ^([^\ :])\ /notifications/hub/(.) \1\ /\2
server HPM_BW_89_WS x.x.x.x:89 id 139

No matter what I try, I only manage to get this in the BW log:

[WARN] Responding with 404 Not Found catcher.

Could a charitable soul please help me to get this working? Also, could someone please explain what I am missing by WS being broken?

Thanks!

Pistoler0

Originally created by @ElPistoler0 on GitHub (Nov 28, 2019). Original GitHub issue: https://github.com/dani-garcia/vaultwarden/issues/750 Hi all, Long time lurker, first-time poster. I'd like to begin by thanking the dev for this amazing work. Really appreciate it! I enabled WebSockets on my Docker container running under Windows Server 2019. Here is my CREATE command: `docker pull bitwardenrs/server:latest docker create --name bitwarden_rs -p 88:80 -p 89:3012 -v SOMEDRIVE\bitwarden\data\:/data -e WEBSOCKET_ENABLED=true -e DOMAIN=https://pw.blah -e SMTP_HOST=smtp.gmail.com -e SMTP_FROM=blah@gmail.com -e SMTP_PORT=465 -e SMTP_SSL=true -e SMTP_USERNAME=blah@gmail.com -e SMTP_PASSWORD=bleh -e SMTP_EXPLICIT_TLS=true -e LOG_FILE=/data/bitwarden.log -e LOG_LEVEL=warn -e EXTENDED_LOGGING=true -e ADMIN_TOKEN=********** --restart unless-stopped bitwardenrs/server:latest` This setup is behind a pfSense firewall with HaProxy on it. I can browse to my vault, use browser extensions, and mobile apps. Everything seems to be working as expected, except for the WebSockets... Here is what I get on the BW log: [2019-11-28 22:01:38][_][WARN] Response was `None`. [2019-11-28 22:01:38][_][WARN] Responding with 404 Not Found catcher. [2019-11-28 22:01:38][_][WARN] Response was `None`. [2019-11-28 22:01:38][_][WARN] Responding with 404 Not Found catcher. [2019-11-28 22:01:39][_][WARN] Response was `None`. [2019-11-28 22:01:39][_][WARN] Responding with 404 Not Found catcher. [2019-11-28 22:01:39][_][WARN] Response was `None`. [2019-11-28 22:01:39][_][WARN] Responding with 404 Not Found catcher. [2019-11-28 22:01:39][_][WARN] Response was `None`. [2019-11-28 22:01:39][_][WARN] Responding with 404 Not Found catcher. [2019-11-28 22:01:39][_][WARN] Response was `None`. [2019-11-28 22:01:39][_][WARN] Responding with 404 Not Found catcher. [2019-11-28 22:01:39][_][WARN] Response was `None`. [2019-11-28 22:01:39][_][WARN] Responding with 404 Not Found catcher. [2019-11-28 22:01:39][_][WARN] Response was `None`. And here's my HaProxy config: FE Config acl ACL_BW_88 hdr_beg(host) -i pw.blah acl ACL_BW_88_PATH var(txn.txnpath) -m reg -i \/notifications.*\/hub\/n([^\/]+) acl ACL_BW_89 hdr_beg(host) -i pw.blah acl ACL_BW_3012_WS_PATH_b var(txn.txnpath) -m beg -i /notifications acl ACL_BW_3012_WS_PATH_e var(txn.txnpath) -m end -i /notifications/hub acl ACL_BW_3012_WS_HDR_UP hdr(Connection) -i upgrade acl ACL_BW_3012_WS_HDR_WS hdr(Upgrade) -i websocket use_backend BE_HPM_BitWarden_88_ipvANY if ACL_BW_88 !ACL_BW_3012_WS_PATH_e use_backend BE_HPM_BitWarden_89_WebSockets_ipvANY if ACL_BW_89 ACL_BW_3012_WS_PATH_e ACL_BW_3012_WS_HDR_UP ACL_BW_3012_WS_HDR_WS BE Config backend BE_HPM_BitWarden_88_ipvANY mode http id 137 log global option log-health-checks http-response set-header Strict-Transport-Security max-age=900000; timeout connect 600000 timeout server 600000 retries 5 server HPM_BW_88 x.x.x.x:88 id 112 backend BE_HPM_BitWarden_89_WebSockets_ipvANY mode http id 140 log global option log-health-checks http-response set-header Strict-Transport-Security max-age=900000; timeout connect 600000 timeout server 600000 retries 5 reqrep ^([^\ :])\ /notifications/hub/(.) \1\ /\2 server HPM_BW_89_WS x.x.x.x:89 id 139 No matter what I try, I only manage to get this in the BW log: [WARN] Responding with 404 Not Found catcher. Could a charitable soul please help me to get this working? Also, could someone please explain what I am missing by WS being broken? Thanks! Pistoler0
kerem closed this issue 2026-03-03 01:30:00 +03:00
Author
Owner

@meska commented on GitHub (Dec 5, 2019):

chunk of my haproxy.cfg , not very elegant but it's working
domains.map contains bw.xxxxxx.com bitwarden and many others

frontend htps-in
        option httplog
        bind *:443 ssl crt /etc/haproxy/certs/xxxxxxxxx.pem
        reqadd X-Forwarded-Proto:\ https
        acl is_websocket path -i -m beg /notifications/hub
        acl not_websocket path -i -m beg /notifications/hub/negotiate
        use_backend bitwarden if not_websocket
        use_backend bitwarden_ws if is_websocket
        use_backend %[req.hdr(host),lower,map_dom(/etc/haproxy/domains.map,nas)]

backend bitwarden
        http-request set-header X-Forwarded-Port %[dst_port]
        http-request add-header X-Forwarded-Proto https if { ssl_fc }
        http-request set-header X-Client-IP  %[req.hdr(CF-Connecting-IP)]
        http-request set-header X-Real-IP  %[req.hdr(CF-Connecting-IP)]
        acl restricted_page path_beg,url_dec -i /admin/
        http-request deny if restricted_page
        server bitwarden rancher:8007

backend bitwarden_ws
        http-request set-header X-Forwarded-Port %[dst_port]
        http-request add-header X-Forwarded-Proto https if { ssl_fc }
        http-request set-header X-Client-IP  %[req.hdr(CF-Connecting-IP)]
        http-request set-header X-Real-IP  %[req.hdr(CF-Connecting-IP)]
        server bitwarden_ws rancher:3012
<!-- gh-comment-id:562347829 --> @meska commented on GitHub (Dec 5, 2019): chunk of my haproxy.cfg , not very elegant but it's working domains.map contains `bw.xxxxxx.com bitwarden` and many others ``` frontend htps-in option httplog bind *:443 ssl crt /etc/haproxy/certs/xxxxxxxxx.pem reqadd X-Forwarded-Proto:\ https acl is_websocket path -i -m beg /notifications/hub acl not_websocket path -i -m beg /notifications/hub/negotiate use_backend bitwarden if not_websocket use_backend bitwarden_ws if is_websocket use_backend %[req.hdr(host),lower,map_dom(/etc/haproxy/domains.map,nas)] backend bitwarden http-request set-header X-Forwarded-Port %[dst_port] http-request add-header X-Forwarded-Proto https if { ssl_fc } http-request set-header X-Client-IP %[req.hdr(CF-Connecting-IP)] http-request set-header X-Real-IP %[req.hdr(CF-Connecting-IP)] acl restricted_page path_beg,url_dec -i /admin/ http-request deny if restricted_page server bitwarden rancher:8007 backend bitwarden_ws http-request set-header X-Forwarded-Port %[dst_port] http-request add-header X-Forwarded-Proto https if { ssl_fc } http-request set-header X-Client-IP %[req.hdr(CF-Connecting-IP)] http-request set-header X-Real-IP %[req.hdr(CF-Connecting-IP)] server bitwarden_ws rancher:3012 ```
Author
Owner

@ohkeenan commented on GitHub (Dec 7, 2019):

Just noticed mine may actually not work either? I can browse to https://warden.example.com/notifications/hub and see the JSON but still get this error in logs:

warden_app.1.idb4gm7xnmt1@ohwerk1    | [2019-12-07 23:06:37][error][ERROR] ###########################################################
warden_app.1.idb4gm7xnmt1@ohwerk1    |     '/notifications/hub' should be proxied to the websocket server or notifications won't work.
warden_app.1.idb4gm7xnmt1@ohwerk1    |     Go to the Wiki for more info, or disable WebSockets setting WEBSOCKET_ENABLED=false.
warden_app.1.idb4gm7xnmt1@ohwerk1    |     ###########################################################################################

edit: I think since it's only in the logs once maybe it's just because the service comes up and immediately checks for the existence but since haproxy isn't routing to that backend yet it can't see it?

Chunk of my frontends (in case it's of any use):

frontend http-to-https
    bind :::80 v4v6 
    mode http
    log global
    option http-keep-alive
    option forwardfor
    acl acme path_beg -i /.well-known/acme-challenge
    acl redirect var(txn.txnpath) -m sub -i /.well-known/acme-challenge
    http-request set-var(txn.txnpath) path
    http-request redirect scheme https code 301 if !redirect 
    use_backend acme if acme

frontend https-sni
    bind :::443 v4v6 alpn h2,http/1.1 ssl crt /etc/haproxy/ssl/private crt /etc/haproxy/ssl/ssl.d
    option forwardfor
    http-request set-var(txn.txnhost) hdr(host)
    http-request set-var(txn.txnpath) path

    http-request set-header X-Forwarded-Host %[req.hdr(Host)]
    http-request set-header X-Forwarded-For %[src]
    http-request set-header X-Forwarded-Proto https
    http-request set-header X-Forwarded-Port %[dst_port]
    http-response set-header X-Frame-Options sameorigin

    acl warden var(txn.txnhost) -m str -i warden.example.com
    use_backend warden if warden
    use_backend warden_websocket if { path -i /notifications/hub }
    use_backend warden if { path -i /notifications/hub/negotiate }

Could probably simplify the above once more:

    use_backend warden if { warden } { path -i /notifications/hub/negotiate }
    use_backend warden_websocket if { path -i /notifications/hub }

Backends:

backend warden
    server warden_app warden_app:80 check
backend warden_websocket
    http-request set-header X-Client-IP  %[req.hdr(CF-Connecting-IP)] #used this thanks to meska!
    http-request set-header X-Real-IP  %[req.hdr(CF-Connecting-IP)] #used this thanks to meska!
    server warden_socket warden_app:3012 check

Logs:

warden_app.1.7dqh2e27l20y@ohwerk8    | [2019-12-07 22:46:51][request][INFO] POST /api/ciphers
warden_app.1.7dqh2e27l20y@ohwerk8    | [2019-12-07 22:46:52][response][INFO] POST /api/ciphers (post_ciphers) => 200 OK
warden_app.1.7dqh2e27l20y@ohwerk8    | [2019-12-07 22:46:56][request][INFO] POST /notifications/hub/negotiate
warden_app.1.7dqh2e27l20y@ohwerk8    | [2019-12-07 22:46:56][auth][ERROR] Unauthorized Error: Invalid claim
warden_app.1.7dqh2e27l20y@ohwerk8    | [2019-12-07 22:46:56][response][INFO] POST /notifications/hub/negotiate (negotiate) => 401 Unauthorized
warden_app.1.7dqh2e27l20y@ohwerk8    | [2019-12-07 22:48:49][request][INFO] POST /notifications/hub/negotiate
warden_app.1.7dqh2e27l20y@ohwerk8    | [2019-12-07 22:48:49][response][INFO] POST /notifications/hub/negotiate (negotiate) => 200 OK
warden_app.1.7dqh2e27l20y@ohwerk8    | [2019-12-07 22:51:18][request][INFO] POST /notifications/hub/negotiate
warden_app.1.7dqh2e27l20y@ohwerk8    | [2019-12-07 22:51:18][response][INFO] POST /notifications/hub/negotiate (negotiate) => 200 OK
warden_app.1.7dqh2e27l20y@ohwerk8    | [2019-12-07 22:51:42][request][INFO] POST /identity/connect/token
warden_app.1.7dqh2e27l20y@ohwerk8    | [2019-12-07 22:51:42][response][INFO] POST /identity/connect/token (login) => 200 OK
warden_app.1.7dqh2e27l20y@ohwerk8    | [2019-12-07 22:51:43][request][INFO] POST /notifications/hub/negotiate
warden_app.1.7dqh2e27l20y@ohwerk8    | [2019-12-07 22:51:43][response][INFO] POST /notifications/hub/negotiate (negotiate) => 200 OK
<!-- gh-comment-id:562894318 --> @ohkeenan commented on GitHub (Dec 7, 2019): Just noticed mine may actually not work either? I can browse to https://warden.example.com/notifications/hub and see the JSON but still get this error in logs: warden_app.1.idb4gm7xnmt1@ohwerk1 | [2019-12-07 23:06:37][error][ERROR] ########################################################### warden_app.1.idb4gm7xnmt1@ohwerk1 | '/notifications/hub' should be proxied to the websocket server or notifications won't work. warden_app.1.idb4gm7xnmt1@ohwerk1 | Go to the Wiki for more info, or disable WebSockets setting WEBSOCKET_ENABLED=false. warden_app.1.idb4gm7xnmt1@ohwerk1 | ########################################################################################### edit: I think since it's only in the logs once maybe it's just because the service comes up and immediately checks for the existence but since haproxy isn't routing to that backend yet it can't see it? Chunk of my frontends (in case it's of any use): frontend http-to-https bind :::80 v4v6 mode http log global option http-keep-alive option forwardfor acl acme path_beg -i /.well-known/acme-challenge acl redirect var(txn.txnpath) -m sub -i /.well-known/acme-challenge http-request set-var(txn.txnpath) path http-request redirect scheme https code 301 if !redirect use_backend acme if acme frontend https-sni bind :::443 v4v6 alpn h2,http/1.1 ssl crt /etc/haproxy/ssl/private crt /etc/haproxy/ssl/ssl.d option forwardfor http-request set-var(txn.txnhost) hdr(host) http-request set-var(txn.txnpath) path http-request set-header X-Forwarded-Host %[req.hdr(Host)] http-request set-header X-Forwarded-For %[src] http-request set-header X-Forwarded-Proto https http-request set-header X-Forwarded-Port %[dst_port] http-response set-header X-Frame-Options sameorigin acl warden var(txn.txnhost) -m str -i warden.example.com use_backend warden if warden use_backend warden_websocket if { path -i /notifications/hub } use_backend warden if { path -i /notifications/hub/negotiate } Could probably simplify the above once more: use_backend warden if { warden } { path -i /notifications/hub/negotiate } use_backend warden_websocket if { path -i /notifications/hub } Backends: backend warden server warden_app warden_app:80 check backend warden_websocket http-request set-header X-Client-IP %[req.hdr(CF-Connecting-IP)] #used this thanks to meska! http-request set-header X-Real-IP %[req.hdr(CF-Connecting-IP)] #used this thanks to meska! server warden_socket warden_app:3012 check Logs: warden_app.1.7dqh2e27l20y@ohwerk8 | [2019-12-07 22:46:51][request][INFO] POST /api/ciphers warden_app.1.7dqh2e27l20y@ohwerk8 | [2019-12-07 22:46:52][response][INFO] POST /api/ciphers (post_ciphers) => 200 OK warden_app.1.7dqh2e27l20y@ohwerk8 | [2019-12-07 22:46:56][request][INFO] POST /notifications/hub/negotiate warden_app.1.7dqh2e27l20y@ohwerk8 | [2019-12-07 22:46:56][auth][ERROR] Unauthorized Error: Invalid claim warden_app.1.7dqh2e27l20y@ohwerk8 | [2019-12-07 22:46:56][response][INFO] POST /notifications/hub/negotiate (negotiate) => 401 Unauthorized warden_app.1.7dqh2e27l20y@ohwerk8 | [2019-12-07 22:48:49][request][INFO] POST /notifications/hub/negotiate warden_app.1.7dqh2e27l20y@ohwerk8 | [2019-12-07 22:48:49][response][INFO] POST /notifications/hub/negotiate (negotiate) => 200 OK warden_app.1.7dqh2e27l20y@ohwerk8 | [2019-12-07 22:51:18][request][INFO] POST /notifications/hub/negotiate warden_app.1.7dqh2e27l20y@ohwerk8 | [2019-12-07 22:51:18][response][INFO] POST /notifications/hub/negotiate (negotiate) => 200 OK warden_app.1.7dqh2e27l20y@ohwerk8 | [2019-12-07 22:51:42][request][INFO] POST /identity/connect/token warden_app.1.7dqh2e27l20y@ohwerk8 | [2019-12-07 22:51:42][response][INFO] POST /identity/connect/token (login) => 200 OK warden_app.1.7dqh2e27l20y@ohwerk8 | [2019-12-07 22:51:43][request][INFO] POST /notifications/hub/negotiate warden_app.1.7dqh2e27l20y@ohwerk8 | [2019-12-07 22:51:43][response][INFO] POST /notifications/hub/negotiate (negotiate) => 200 OK
Author
Owner

@ElPistoler0 commented on GitHub (Dec 10, 2019):

Thank you guys for the help! I'll check my config.

<!-- gh-comment-id:563876947 --> @ElPistoler0 commented on GitHub (Dec 10, 2019): Thank you guys for the help! I'll check my config.
Author
Owner

@dani-garcia commented on GitHub (May 13, 2020):

Closed due to inactivity.

<!-- gh-comment-id:628279638 --> @dani-garcia commented on GitHub (May 13, 2020): Closed due to inactivity.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/vaultwarden#509
No description provided.