NginX / Apache Reverse Proxy Settings To HAProxy

Hi Everyone,

TL/DR: Need help with NginX/Apache Reverse Proxy Settings to HAProxy.

I’m really hoping someone can help with this - I’ve spent the last 4 days googling, reading, and “experimenting” but I just cannot get this to work. Please, I really need some help.

The Situation

  • All of the following is running on Rocky Linux 8.6 (for those that don’t know, that’s a RHEL-clone replacement for CentOS)
  • We have a Node.js application (Electron-based) running on a local dedicated server (all details shown below).
  • The internal DNS name of app is app.localdomain.local
  • The internal IP Address of the app is 192.168.1.100 on Port 30000
  • We have a local dedicated HAProxy box
  • We have a local dedicated web-server (192.168.1.99) sitting behind the HAProxy box running multiple web-sites
  • We can connect to all three local boxes (& the app & the web-sites) using the local IP Address and local DNS name of each respective box
  • We can connect to each web-site from the public Internet ie the HAProxy box is doing its job correctly (as far as the web-sites are concerned)
  • When we attempt to connect to the app from an external source (ie when using the public DNS name app.ourdomain.com) we’re receiving a 503 Error (I know what that means)
  • According to the HAProxy Logs, HAProxy is routing the external GET request (for the app) to the correct backend.
  • When we use a curl app.localdomain.local -v command (&/or a curl 192.168.1.100 -v command) from the HAProxy box we receive the expected results from the app

So it seems to me (in my less-than-expert-knowledge ignorance) that our issue lies somewhere in the proxy configuration for the app.

The app publisher has provided information and sample configs on using both NginX and Apache as reverse proxies for their app, but nothing for HAProxy. So we’ve “had a go” at taking each of those relevant configs (see below) and attempting to convert them to HAProxy - but with no luck.

So could someone please, please, please point me in the right direction so as to get this working properly — I know (think?) I’m close, but as I’m not an expert in HAProxy, NginX, nor Apache I also know that I’m missing something, so any help anyone can give would be greatly appreciated.

Sample NginX Reverse-Proxy Settings (with our relevant settings included)

location / {
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_pass http://192.168.1.100:30000;
    }

Sample Apache Reverse-Proxy Settings (with our relevant settings included)

ProxyPreserveHost  On
ProxyPass          "/socket.io/" "ws://192.168.1.100:30000/socket.io/"
ProxyPass /        http://192.168.1.100:30000/
ProxyPassReverse / http://192.168.1.100:30000/

Our haproxy.cnf File (the relevant bits)

(I know the timings can be tightened up, & that’s something I’m going to get too, once I’ve got this sorted.)

defaults
        mode http
        log global
        option httplog
        option http-server-close
        option httpchk HEAD /
        timeout connect 10s
        timeout client 1m
        timeout server 1m
        timeout http-keep-alive 10s

frontend websites_frontend
        bind *:80
        bind *:443 ssl crt /etc/haproxy/ssl/ ecdhe secp384r1 alpn h2,http/1.1
        http-request redirect scheme https code 301 unless { ssl_fc }
        http-request redirect prefix https://www.ourdomain.com code 301 if { req.hdr(host) -i ourdomain.com }
        http-response add-header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload;"
        use_backend %[req.hdr(host),lower,map(/etc/haproxy/maps/hosts.map)]
        default_backend websites_backend

backend app_backend
        http-request set-header X-Forwarded-Port %[dst_port]
        http-request add-header X-Forwarded-Proto https
        option forwardfor
        server app 192.168.1.100:30000

backend websites_backend
        cookie SERVERUSED insert indirect nocache
        http-request set-header X-Forwarded-Port %[dst_port]
        http-request add-header X-Forwarded-Proto https
        server www 192.168.1.99:80 cookie www check

Our HAProxy host.map File

#DOMAIN NAME             BACKEND NAME
#----------------------------------------
webmail.ourdomain.com    websites_backend
www.ourdomain.com        websites_backend
www1.ourdomain.com       websites_backend
www2.ourdomain.com       websites_backend
www3.ourdomain.com       websites_backend
www4.ourdomain.com       websites_backend

app.ourdomain.com        app_backend

Thank you

Dulux-Oz

503 means Service Unavailable

have you checked Websockets Load Balancing with HAProxy - HAProxy Technologies

in the app_backend you are setting

http-request add-header X-Forwarded-Proto https

is this correct? you are saying that the client was using https when connecting to haproxy. in this case you have to check curl with https and not with http?

Hi Markus, thanks for helping out.

OK, a couple of things:

I turned off all references to https and now the system is running purely on http - still getting a 503.

However (and I don’t know if this is relevant or not - but I suspect it is) I just noticed that when we do a curl 192.168.1.100:3000 -v the haproxy box is actually receiving a 302 from the app redirecting to the app’s \auth subfolder (which makes sense that you’d want to authenticate to the app). When I do a curl 192.168.1.100:3000/auth -v the haproxy box actually receives the “auth” html code.

And sorry for the (apparently/possibly) misleading info in the first post. <sheepish grin>

Now, I was under the impression that when the haproxy box received the 302 response it would forward that to the client, and then the client (browser) would resubmit the initial request with /auth tacked on the back. If this isn’t the case then do we need to somehow tell haproxy to “automatically follow” the 302 and sent that response thru to the client - or am I completely off my rocker? :slight_smile:

Oh, also, when we enter app.ourdomain.com/auth into the browser we’re still getting a 503

Also also, you’ve given me a whole bunch more to read (ie HAProxy with SSL Websockets, etc) so it looks like I’m going to be spending an… “interesting”… weekend - thanks(?) for that.

I’ll be back on Monday after I digest my weekend reading diet. :grin:

no, redirects (302 or 301) work pretty well through haproxy.
it should be not the problem. can have you checked logfiles on your app server? does the requests reach your appserver? maybe they were blocked?

Just a quick update: The HAProxy log is as follows:

Jun 25 16:49:27 localhost haproxy[34880]: 192.168.1.200:1292 [25/Jun/2022:16:49:27.337] website_frontend app_backend/app 0/0/-1/-1/1 503 212 - - SC-- 1/1/0/0/3 0/0 "GET / HTTP/1.1"

This tells me that the appserver is actively refusing the tcp connection (the “SC” in the log). However, the firewall allows port 30000/tcp, and the curl ... returns with the 302 redirect (from the app), so unless the haproxy server needs those ports open as well (do they? I didn’t think they did.) then I really don’t know why the tcp connection is being refused - anyone have any idea?

OK, so after lots & lots (& lots & lots & lots) of reading, troubleshooting, and log-reviewing, I’m seriously suspecting that the issues isn’t within haproxy or its config, but in the backend app. I’m testing for that now (actually tomorrow) so I’m going to close this off because I don’t think its useful to have open anythinger.

Thanks everyone

Cheers

Dulux-Oz