• Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Search
  • Register
  • Login
Netgate Discussion Forum
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Search
  • Register
  • Login

HAProxy Websockets - Frigate

Scheduled Pinned Locked Moved Cache/Proxy
11 Posts 4 Posters 667 Views
Loading More Posts
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • P
    phipac
    last edited by Jul 29, 2024, 8:46 PM

    Good day, all. I have spent days looking at the posts regarding websockets on HAProxy, but I cannot seem to get it to work at all. I know my HAProxy is working, because I have 8 other web sites that are working just fine. I'm trying to set up a reverse proxy to Frigate, which is a security camera monitoring package. It is accessible via web browser at ip:5000. According to the Frigate documentation, if I were using Apache as a reverse proxy, I would need the following parameters:

        RewriteEngine on
        RewriteCond %{HTTP:Upgrade} =websocket [NC]
        RewriteRule /(.*)  ws://frigatepi.local:5000/$1 [P,L]
        RewriteCond %{HTTP:Upgrade} !=websocket [NC]
        RewriteRule /(.*)  http://frigatepi.local:5000/$1 [P,L]
    

    For whatever reason, I cannot seem to translate the documentation I have seen on websocket setup into something that works for me. I'm not sure if I'm trying to put the values in the wrong place (frontend vs. backend) or what. I would be very grateful if anyone can help shed some light. Thank you very much in advance!

    For reference: pfsense+ 24.03 and haproxy 0.63_4

    1 Reply Last reply Reply Quote 0
    • P
      phipac
      last edited by Jul 30, 2024, 9:09 PM

      Or, if you speak nginx, here is the suggested setup:

        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $http_connection;
        proxy_http_version 1.1;
      
        access_log /data/logs/proxy-host-40_access.log proxy;
        error_log /data/logs/proxy-host-40_error.log warn;
      
        location / {
          proxy_set_header Upgrade $http_upgrade;
          proxy_set_header Connection $http_connection;
          proxy_http_version 1.1;
        }
      
      D 1 Reply Last reply Aug 29, 2024, 8:54 AM Reply Quote 0
      • D
        davecummins @phipac
        last edited by Aug 29, 2024, 8:54 AM

        @phipac
        I use websockets quite a bit.
        Put your websocket servers into their own backend, websocket_servers
        Ensure that the correct parameters are met in order to upgrade to websocket by placing these rules
        a0bcc144-44d4-47c3-ace1-9f5e557e4186-image.png

        For health checks I use GET and this URL:
        HTTP/1.1\r\nHost:\ yourdomain.com\r\nConnection:\ Upgrade\r\nUpgrade:\ websocket\r\nSec-WebSocket-Key:\ haproxy\r\nSec-WebSocket-Version:\ 13\r\nSec-WebSocket-Protocol:\ echo-protocol

        Also on the backend add these rules to 'Backend pass thru'
        timeout tunnel 1h
        http-check expect status 101
        timeout http-request 10s
        timeout http-keep-alive 2s
        timeout queue 5s
        timeout server-fin 1s

        On your frontend dedicated https offloading set these 2 rules for the connection upgrading to websocket.
        17dbd3db-b9e5-4e2b-b250-d70277aeebc8-image.png

        with ACTION:
        hdr_connection_upgrade hdr_upgrade_websocket
        USE backend websocket_servers.

        R 1 Reply Last reply Oct 23, 2024, 5:21 AM Reply Quote 0
        • R
          rpm5099 @davecummins
          last edited by Oct 23, 2024, 5:21 AM

          @davecummins Dave this is great information, but I can't see the full config value of the ACL's. Could you post the haproxy config with all of it included, I'm not familiar with some of these haproxy commands. Thanks in advance

          D 1 Reply Last reply Oct 23, 2024, 12:38 PM Reply Quote 0
          • D
            davecummins @rpm5099
            last edited by Oct 23, 2024, 12:38 PM

            @rpm5099 my config contains a lot of frontends and backends and sensitive information but here is the backend websocket info which you can't see from the screen shots. Hope this helps.

            backend webapp_websockets_app_ipvANY
            mode http
            id 119
            log global
            http-response replace-header Set-Cookie "^((?:(?!; [Ss]ecure\b).)*)$" "\1; secure" if { ssl_fc }
            http-check send meth GET uri /wssapp ver HTTP/1.1\r\nHost:\ mydomain.com\r\nConnection:\ Upgrade\r\nUpgrade:\ websocket\r\nSec-WebSocket-Key:\ haproxy\r\nSec-WebSocket-Version:\ 13\r\nSec-WebSocket-Protocol:\ echo-protocol
            balance roundrobin
            timeout connect 5000
            timeout server 50000
            retries 1
            load-server-state-from-file global
            option httpchk
            timeout tunnel 1h
            http-check expect status 101
            timeout http-request 10s
            timeout http-keep-alive 2s
            timeout queue 5s
            timeout server-fin 1s
            acl hdr_websocket_key hdr_cnt(Sec-WebSocket-Key) eq 1
            acl hdr_websocket_version hdr_cnt(Sec-WebSocket-Version) eq 1
            acl hdr_connection_upgrade hdr(Connection) -i upgrade
            acl hdr_upgrade_websocket hdr(Upgrade) -i websocket
            acl ws_valid_protocol hdr(Sec-WebSocket-Protocol) echo-protocol
            http-request deny deny_status 503 if !hdr_connection_upgrade !hdr_upgrade_websocket !hdr_websocket_version !hdr_websocket_key
            server websocketServer-37 172.18.80.237:443 id 112 ssl check inter 5000 weight 10 verify none
            server websocketServer-36 172.18.80.236:443 id 120 ssl check inter 5000 weight 10 verify none

            S 1 Reply Last reply 18 days ago Reply Quote 0
            • S
              sensewolf @davecummins
              last edited by 18 days ago

              @davecummins

              This is very helpful.

              Since you seem very knowlegeable, may I please ask for your advice as well:

              My situation is that I have a substantial number of applications hosted in my home lab that are proxied through pfSense's integrated HAProxy.

              All of a sudden, some two or three of them require websocket support.

              Now I'm wondering how to implement that. Is it possible to upgrade more than one backend connection to websocket or can that be done only for one?

              You seem to be suggesting to put more than one server in one backend. That way, it would seem possible to overcome a potential websocket backend limitation. But how would I distinguish between the individual apps within one backend?

              Thank you very much in advance.

              R 1 Reply Last reply 18 days ago Reply Quote 0
              • R
                rpm5099 @sensewolf
                last edited by rpm5099 18 days ago 18 days ago

                @sensewolf
                If you really have a LOT of domains you probably need to do some custom HAProxy scripting or other configuration that you'd want to contact the HAProxy developers for help with. For a reasonable amount, i.e. <30, this is what I do:

                Name                    Expression              Value
                -------------------------------------------------------------------------------
                is_websocket	        Host starts with:	ws.
                is_websocket	        Custom acl:		hdr(Connection) -i upgrade
                is_websocket	        Custom acl:		hdr(Upgrade) -i websocket
                domainA_acl		Host matches:		domainA.yourdomain.tld
                domainB_acl		Host matches:		domainB.yourdomain.tld
                domainC_acl		Host matches:		domainC.yourdomain.tld
                
                
                Action                                  Parameters                      Condition Acl Name
                --------------------------------------------------------------------------------------------------
                Use Backend:domainA_backend		See below			is_websocket domainA_acl
                Use Backend:domainB_backend		See below			is_websocket domainB_acl
                Use Backend:domainC_backend		See below			is_websocket domainC_acl
                
                S 1 Reply Last reply 18 days ago Reply Quote 0
                • S
                  sensewolf @rpm5099
                  last edited by 18 days ago

                  @rpm5099

                  Thank you.

                  I'm still very new to the concept, so please excuse my asking naive (aka stupid) questions:

                  This looks to me like we look for three conditions to be fulfilled (plus the host match) and if they are fulfilled, we forward to the backend that matches the host. And if requirements are not met, we don't forward (because the Action part implies an AND operator). In other words, some backends can only be reached, if a websocket upgrade is requested.

                  My situation is that I have a number of hosts and some require the websocket upgrade and others don't.

                  Can't I just forward the connection request as is to a backend that matches the host (say, app1.example.com) and let the host deal with it, i.e. if the connection request contains a websocket upgrade request, either upgrade or not and if the connection request doesn't contain an upgrade request, don't upgrade.

                  Why would I filter out certain requests to certain hosts?

                  Sorry, if the answer is obvious... (to me it isn't).

                  Thank you.

                  D 1 Reply Last reply 18 days ago Reply Quote 0
                  • D
                    davecummins @sensewolf
                    last edited by 18 days ago

                    @sensewolf if your backend server upgrades to websocket, then it will open a new tcp port for that connection. So you need to add a new backend, call it ws_servers, add the same server again but with the websocket tcp port, call it ws_version for example. This is then the backend server you reference for websocket upgrade requests coming in your front end.

                    S 1 Reply Last reply 17 days ago Reply Quote 0
                    • S
                      sensewolf @davecummins
                      last edited by 17 days ago

                      @davecummins

                      Thank you.

                      So, for each of my apps that may want to upgrade a connection to websocket, I should create a second backend with the same app but a different port number, right?

                      And from the frontend I should forward traffic that does not request an upgrade to the normal backend and traffic that does request an upgrade to the websocket backend for the same app, right?

                      Okay, so far I get it (I'm hoping). That explains why I should filter the traffic for upgrade requests.

                      But how do I know the port number to use for the websocket backend? The docs of those apps that (may) need an upgrade do not mention another port number. In fact, I almost exclusively host docker apps and they only require one port to be forwarded into the container (for traffic; maybe another one for metrics). This suggests to me that they don't use another port.

                      And I do have (so far only) one app that does require websocket and for which I have set up HAProxy (with the help of some forum thread from the internet) in a way that makes it work that does not use a separate backend (or port number) but the same one. So, I believe that this one app does not open another port but uses the normal http port.

                      If the apps open another port, it all seems so straight forward. But what do I do, if the apps don't open another port but use the same port for websocket as they use for normal http(s)?

                      Sorry for all the questions and thank you!

                      R 1 Reply Last reply 17 days ago Reply Quote 0
                      • R
                        rpm5099 @sensewolf
                        last edited by 17 days ago

                        @sensewolf All of the applications I have that run websockets use the same port, so I do not create separate backends for them and it works fine. If your application does use separate ports then you will need to create a separate backend. I'm not sure how common this is, but I have I think 5 domains with websockets and none of them use a separate port.

                        1 Reply Last reply Reply Quote 0
                        • First post
                          Last post
                        Copyright 2025 Rubicon Communications LLC (Netgate). All rights reserved.
                          [[user:consent.lead]]
                          [[user:consent.not_received]]