Tutorial 2024/06: HAProxy + Let's Encrypt Wildcard Certificates + 100% A+ Rating

Started by TheHellSite, May 31, 2021, 01:06:11 PM

Previous topic - Next topic
Ok. I changed OPNsene Port to 222 and SSH_frontend to 22.

Now I can access all my clients over haproxy with ssh,ipv4 and port 22.

Thanks for the Input.


Hello Guys!

Today its my first post here at this forum. At first @TheHellSite THANK YOU for your tutorial it helps my a lot! Before i used nginx proxy manager which was a lot easier than haproxy :)

I had one for my big problem and need the help from you all, please. I want to configure vaultwarden with websocket support in haproxy. The normal redirect to vaultwarden is no problem, but to add websocket support is still driven my crazy!

https://github.com/dani-garcia/vaultwarden/wiki/Proxy-examples
Here are some examples how the proxy setup should, but i dont understand were my problem is.

#
# Automatically generated configuration.
# Do not edit this file manually.
#

global
    uid                         80
    gid                         80
    chroot                      /var/haproxy
    daemon
    stats                       socket /var/run/haproxy.socket group proxy mode 775 level admin
    nbproc                      1
    nbthread                    4
    hard-stop-after             60s
    no strict-limits
    maxconn                     10000
    tune.ssl.default-dh-param   4096
    spread-checks               2
    tune.bufsize                16384
    tune.lua.maxmem             0
    log                         /var/run/log local0 info
    lua-prepend-path            /tmp/haproxy/lua/?.lua

defaults
    log     global
    option redispatch -1
    maxconn 5000
    timeout client 30s
    timeout connect 30s
    timeout server 30s
    retries 3
    default-server init-addr last,libc
    default-server maxconn 5000

# autogenerated entries for ACLs


# autogenerated entries for config in backends/frontends

# autogenerated entries for stats




# Frontend: 0_SNI_frontend (Listening on 0.0.0.0:80, 0.0.0.0:443)
frontend 0_SNI_frontend
    bind 0.0.0.0:443 name 0.0.0.0:443
    bind 0.0.0.0:80 name 0.0.0.0:80
    mode tcp
    default_backend SSL_backend
    # tuning options
    timeout client 30s

    # logging options

# Frontend: 1_HTTP_frontend (Listening on 127.0.0.1:80)
frontend 1_HTTP_frontend
    bind 127.0.0.1:80 name 127.0.0.1:80 accept-proxy
    mode http
    option http-keep-alive
    option forwardfor
    # tuning options
    timeout client 30s

    # logging options
    # ACL: NoSSL_condition
    acl acl_636976fd9d4d71.97561865 ssl_fc

    # ACTION: HTTPtoHTTPS_rule
    http-request redirect scheme https code 301 if !acl_636976fd9d4d71.97561865

# Frontend: 1_HTTPS_frontend (Listening on 127.0.0.1:443)
frontend 1_HTTPS_frontend
    http-response set-header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
    bind 127.0.0.1:443 name 127.0.0.1:443 accept-proxy ssl curves secp384r1  no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES256-GCM-SHA384 ciphersuites TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256 alpn h2,http/1.1 crt-list /tmp/haproxy/ssl/636aad8d3cbe18.58884679.certlist
    mode http
    option http-keep-alive
    option forwardfor
    # tuning options
    timeout client 30s

    # logging options
    # ACL: nc_carddav
    acl acl_636ba4e5b6aa82.28881573 path_end -i /.well-known/carddav
    # ACL: nc_caldav
    acl acl_636ba2d9f14933.27250118 path_end -i /.well-known/caldav
    # ACL: vw_ws_acl01_condition
    acl acl_636c2f2b5accd9.55827620 path_beg -i /notifications/hub
    # ACL: vw_ws_acl02_condition
    acl acl_636cc909734817.72974823 path_beg -i /notifications/hub/negotiate
    # ACL: vw_ws_acl03_condition
    acl acl_636ccac64fcd74.27409543 path_beg -i /notifications/hub
    # ACL: vw_ws_acl04_condition
    acl acl_636ccae443ca48.73072029 path_beg -i /notifications/hub/negotiate

    # ACTION: nc_carddav_rule
    http-request redirect code 301 location /remote.php/dav if acl_636ba4e5b6aa82.28881573
    # ACTION: nc_caldav_rule
    http-request redirect code 301 location /remote.php/dav if acl_636ba2d9f14933.27250118
    # ACTION: PUBLIC_SUBDOMAINS-map_rule
    # NOTE: actions with no ACLs/conditions will always match
    use_backend %[req.hdr(host),lower,map_dom(/tmp/haproxy/mapfiles/63653d33935cd3.47503593.txt)]
    # ACTION: vw_ws_acl01_rule
    use_backend vw_backend if !acl_636c2f2b5accd9.55827620
    # ACTION: vw_ws_acl02_rule
    use_backend vw_backend if acl_636cc909734817.72974823
    # ACTION: vw_ws_acl03_rule
    use_backend vw_ws_backend if acl_636ccac64fcd74.27409543
    # ACTION: vw_ws_acl04_rule
    use_backend vw_ws_backend if !acl_636ccae443ca48.73072029

# Backend: SSL_backend ()
backend SSL_backend
    # health checking is DISABLED
    mode tcp
    balance source
    # stickiness
    stick-table type ip size 50k expire 30m 
    stick on src
    # tuning options
    timeout connect 30s
    timeout server 30s
    server SSL_server 127.0.0.1 send-proxy-v2 check-send-proxy

# Backend: office_backend (Onlyoffice)
backend office_backend
    # health checking is DISABLED
    mode http
    balance source
    # stickiness
    stick-table type ip size 50k expire 30m 
    stick on src
    # tuning options
    timeout connect 30s
    timeout server 30s
    http-reuse safe
    server office_server 10.10.20.8:80

# Backend: vw_backend (Vaultwarden)
backend vw_backend
    # health checking is DISABLED
    mode http
    balance source
    # stickiness
    stick-table type ip size 50k expire 30m 
    stick on src
    # tuning options
    timeout connect 30s
    timeout server 30s
    http-reuse safe
    server vw_server 10.10.20.7:80

# Backend: mc_backend (Minecraft Server)
backend mc_backend
    # health checking is DISABLED
    mode http
    balance source
    # stickiness
    stick-table type ip size 50k expire 30m 
    stick on src
    # tuning options
    timeout connect 30s
    timeout server 30s
    http-reuse safe
    server mc_server 10.10.40.4:80

# Backend: cloud_backend (Nextcloud01)
backend cloud_backend
    # health checking is DISABLED
    mode http
    balance source
    # stickiness
    stick-table type ip size 50k expire 30m 
    stick on src
    # tuning options
    timeout connect 30s
    timeout server 30s
    http-reuse safe
    server cloud_server 10.10.20.5:80

# Backend: demo_backend (Nextcloud02)
backend demo_backend
    # health checking is DISABLED
    mode http
    balance source
    # stickiness
    stick-table type ip size 50k expire 30m 
    stick on src
    # tuning options
    timeout connect 30s
    timeout server 30s
    http-reuse safe
    server demo_server 10.10.20.6:80

# Backend: kunden_backend (Nextcloud03)
backend kunden_backend
    # health checking is DISABLED
    mode http
    balance source
    # stickiness
    stick-table type ip size 50k expire 30m 
    stick on src
    # tuning options
    timeout connect 30s
    timeout server 30s
    http-reuse safe
    server kunden_server 10.10.20.11:80

# Backend: vw_ws_backend (Vaultwarden Websocket)
backend vw_ws_backend
    # health checking is DISABLED
    mode http
    balance source
    # stickiness
    stick-table type ip size 50k expire 30m 
    stick on src
    # tuning options
    timeout connect 30s
    timeout server 30s
    http-reuse safe
    server vw_ws_server 10.10.20.7:3012



# statistics are DISABLED


2022-11-10T13:33:48 Informational haproxy Connect from 10.10.10.239:54010 to PUBLICIP:443 (1_HTTPS_frontend/HTTP)
2022-11-10T13:33:48 Informational haproxy Connect from 10.10.10.239:54010 to PUBLICIP:443 (1_HTTPS_frontend/HTTP)
2022-11-10T13:33:48 Informational haproxy Connect from 10.10.10.239:54010 to PUBLICIP:443 (1_HTTPS_frontend/HTTP)
2022-11-10T13:33:48 Informational haproxy Connect from 10.10.10.239:54010 to PUBLICIP:443 (0_SNI_frontend/TCP)


With best regard,
techsolo12

Quote from: techsolo12 on November 10, 2022, 01:46:14 PM
Hello Guys!

Today its my first post here at this forum. At first @TheHellSite THANK YOU for your tutorial it helps my a lot! Before i used nginx proxy manager which was a lot easier than haproxy :)

I had one for my big problem and need the help from you all, please. I want to configure vaultwarden with websocket support in haproxy. The normal redirect to vaultwarden is no problem, but to add websocket support is still driven my crazy!

Sorry, but out of scope of this tutorial. Please ask in the official HAProxy forum.
All of my posts are submitted with the best of knowledge and belief.


My post was helpful to you?
Feel free to click [applaud] to the left underneath my profile.
Additionally you can consider donating: https://www.buymeacoffee.com/thehellsite

Alright! Im back with a clean baseline. Lets try this again... And apologies if anything below sounds dumb, im still faily new to understanding Certs, and how wildcard domains work. (although i had it working in NGINX with another domain of mine, i want to upgrade from a B score to A+ Score, and part of that was moving to HAProxy) - also i have no interest in utilizing 2nd-level-subdomains. I will only be using 1st-level-subdomains for all my services.

Heres where im getting stuck (Part 3, Step 6): Cert Validation - fails
Since i use Cloudflare, I tried my best to adapt your DynDNS setup to Cloudflare (DynDNS confirmed working)


Cloudflare account DNS Management



Dynamic DNS Settings


ACME Settings




What am i doing wrong?

Good Evening,

Thank you for the excellent tutorial! I have setup HAProxy + Wildcard Certificates following this tutorial, but am experiencing a 503 error when trying to access jellyfin.example.com using the setup here. I do not have any of these services accessible from outside my network (I.E. no WAN 443/80 ports open) and am only interested in being able to access "jellyfin.example.com" --> 192.168.5.88:8096 with a valid Let's Encrypt cert from inside my network. Right now when I access jellyfin.example.com, my browser shows a valid cert but throws a 503 error. Double and triple checking the tutorial has left me without any further options to explore.

Does anyone have any suggestions where I can look? Thank you very much in advance!

Unbound Host Override: *.example.com --> 192.168.5.1 (OpnSense LAN IP)


#
# Automatically generated configuration.
# Do not edit this file manually.
#

global
    uid                         80
    gid                         80
    chroot                      /var/haproxy
    daemon
    stats                       socket /var/run/haproxy.socket group proxy mode 775 level admin
    nbproc                      1
    nbthread                    4
    hard-stop-after             60s
    no strict-limits
    tune.ssl.default-dh-param   4096
    spread-checks               2
    tune.bufsize                16384
    tune.lua.maxmem             0
    log                         /var/run/log local0 info
    lua-prepend-path            /tmp/haproxy/lua/?.lua

defaults
    log     global
    option redispatch -1
    maxconn 5000
    timeout client 30s
    timeout connect 30s
    timeout server 30s
    retries 3
    default-server init-addr last,libc
    default-server maxconn 5000

# autogenerated entries for ACLs


# autogenerated entries for config in backends/frontends

# autogenerated entries for stats




# Frontend: HTTPS_Frontend (Listening on 127.4.4.3:443)
frontend HTTPS_Frontend
    http-response set-header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
    bind 127.4.4.3:443 name 127.4.4.3:443 accept-proxy ssl curves secp384r1  no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES256-GCM-SHA384 ciphersuites TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256 alpn h2,http/1.1 crt-list /tmp/haproxy/ssl/63687fb14df779.98297035.certlist
    mode http
    option http-keep-alive
    option forwardfor
    # tuning options
    timeout client 30s

    # logging options
    # ACL: Local_Only_Subnet
    acl acl_63687bc7cf9331.77802781 src 192.168.5.0/24

    # ACTION: Local_subdomain_map
    use_backend %[req.hdr(host),lower,map_dom(/tmp/haproxy/mapfiles/63687b6d92a544.19528694.txt)] if acl_63687bc7cf9331.77802781

# Frontend: SNI_Frontend (Listening to 0.0.0.0:80; 0.0.0.0:443)
frontend SNI_Frontend
    bind 0.0.0.0:80 name 0.0.0.0:80
    bind 0.0.0.0:443 name 0.0.0.0:443
    mode tcp
    default_backend SSL_Backend
    # tuning options
    timeout client 30s

    # logging options

# Frontend: HTTP_Frontend (Listening on 127.4.4.3:80)
frontend HTTP_Frontend
    bind 127.4.4.3:80 name 127.4.4.3:80 accept-proxy
    mode http
    option http-keep-alive
    option forwardfor
    # tuning options
    timeout client 30s

    # logging options
    # ACL: NoSSL_Condition
    acl acl_63687974def2f4.69235454 ssl_fc

    # ACTION: HTTPtoHTTPS
    http-request redirect scheme https code 301 if !acl_63687974def2f4.69235454

# Backend: SSL_Backend ()
backend SSL_Backend
    # health checking is DISABLED
    mode tcp
    balance source
    # stickiness
    stick-table type ip size 50k expire 30m 
    stick on src
    # tuning options
    timeout connect 30s
    timeout server 30s
    server SSL_Server 127.4.4.3 send-proxy-v2 check-send-proxy

# Backend: Jellyfin_Backend ()
backend Jellyfin_Backend
    # health checking is DISABLED
    mode http
    balance source
    # stickiness
    stick-table type ip size 50k expire 30m 
    stick on src
    # tuning options
    timeout connect 30s
    timeout server 30s
    http-reuse safe
    server Jellyfin 192.168.5.88:8096 ssl verify none

# Backend: TPLink_Backend ()
backend TPLink_Backend
    # health checking is DISABLED
    mode http
    balance source
    # stickiness
    stick-table type ip size 50k expire 30m 
    stick on src
    # tuning options
    timeout connect 30s
    timeout server 30s
    http-reuse safe
    server TPLinkSwitch 192.168.5.5:80

# Backend: Opnsense_Backend ()
backend Opnsense_Backend
    # health checking is DISABLED
    mode http
    balance source
    # stickiness
    stick-table type ip size 50k expire 30m 
    stick on src
    # tuning options
    timeout connect 30s
    timeout server 30s
    http-reuse safe
    server Opnsense 192.168.5.1:8100 ssl verify none

# Backend: Proxmox_Backend ()
backend Proxmox_Backend
    # health checking is DISABLED
    mode http
    balance source
    # stickiness
    stick-table type ip size 50k expire 30m 
    stick on src
    # tuning options
    timeout connect 30s
    timeout server 30s
    http-reuse safe
    server Proxmox 192.168.5.201:8006 ssl verify none



# statistics are DISABLED


Map File:

jellyfin Jellyfin_Backend
tplink TPLink_Backend
opnsense Opnsense_Backend
proxmox Proxmox_Backend


Quote from: meelokun on November 11, 2022, 02:52:45 AM
Alright! Im back with a clean baseline. Lets try this again... And apologies if anything below sounds dumb, im still faily new to understanding Certs, and how wildcard domains work. (although i had it working in NGINX with another domain of mine, i want to upgrade from a B score to A+ Score, and part of that was moving to HAProxy) - also i have no interest in utilizing 2nd-level-subdomains. I will only be using 1st-level-subdomains for all my services.

Heres where im getting stuck (Part 3, Step 6): Cert Validation - fails
Since i use Cloudflare, I tried my best to adapt your DynDNS setup to Cloudflare (DynDNS confirmed working)

Out of scope of this tutorial!
As a hint: Your certificate configuration looks fine. Probably wrong DNS-01 settings. Please search on Google for OPNsense Cloudflare ACME guide.
All of my posts are submitted with the best of knowledge and belief.


My post was helpful to you?
Feel free to click [applaud] to the left underneath my profile.
Additionally you can consider donating: https://www.buymeacoffee.com/thehellsite

Quote from: robbie11r1 on November 11, 2022, 04:33:04 AM
Good Evening,

Thank you for the excellent tutorial! I have setup HAProxy + Wildcard Certificates following this tutorial, but am experiencing a 503 error when trying to access jellyfin.example.com using the setup here. I do not have any of these services accessible from outside my network (I.E. no WAN 443/80 ports open) and am only interested in being able to access "jellyfin.example.com" --> 192.168.5.88:8096 with a valid Let's Encrypt cert from inside my network. Right now when I access jellyfin.example.com, my browser shows a valid cert but throws a 503 error. Double and triple checking the tutorial has left me without any further options to explore.

Does anyone have any suggestions where I can look? Thank you very much in advance!

Unbound Host Override: *.example.com --> 192.168.5.1 (OpnSense LAN IP)

Map File:

jellyfin Jellyfin_Backend
tplink TPLink_Backend
opnsense Opnsense_Backend
proxmox Proxmox_Backend



Since you get a 503 with the right certificate your overall setups seems to be working.

Is only Jellyfin not working or does it affect all services mentioned in the map file?
If it only affects Jellyfin: You might want to check the server settings for it in regards of SSL (yes or no). By default Jellyfin comes WITHOUT a self-signed SSL certificate so you will want to disable SSL for this server in HAProxy. Also from what I know the Jellyfin port 8096 is HTTP so no SSL. But you have SSL enabled in the server settings.
All of my posts are submitted with the best of knowledge and belief.


My post was helpful to you?
Feel free to click [applaud] to the left underneath my profile.
Additionally you can consider donating: https://www.buymeacoffee.com/thehellsite

@TheHellSite, I saw some other posts over thr last year with similar problems to me (503 error) and solved it by de-selecting SSL in the Real Server section. I tried that with Jellyfin and nothing changed for me (still same 503 with valid cert).

I get the same error for every service, no matter if SSL is selected or not. Is there anything else I should be changing aside from just de-selecting SSL?

Thanj you again!

EDIT: As of this morning (and changing nothing), everything started to work. Not sure what did it, but awesome tutorial and thanks for the feedback/troubleshooting with everyone, helped immensely.

Im up and running (Everything works!) I Figured out my Cloudflare DNS challenge issue (you have to make sure to get the Token that is displayed AFTER you create a Cloudflare API Token for the Zone.DNS read and Zone.DNS Edit... I mistakenly thought it was the Global ID Key..)

Now the only thing i cant get to work is the Unbound DNS Override.

You stated
QuoteIf you are running all of your services on your 1st level subdomain "your_subdomain.dedyn.io" than you will just need to override this one.

Since im utilizing a wildcard, i figured it should work this way, so that any subdomain i enter, will be redirected to HAProxy's SNI_Frontend. And since its listening on 0.0.0.0, i figured the virtual IP should work - i also tried the Firewalls IP address with no luck.



And yes - the virtual ip is set to loopback.

Also - the Unbound DNS Overrides section looks different, now theres 2 tabs (Host Overrides), a main entry and an aliases entry,

then a (Domain Overrides) tab.

Quote from: meelokun on November 12, 2022, 11:19:38 AM

You stated
QuoteIf you are running all of your services on your 1st level subdomain "your_subdomain.dedyn.io" than you will just need to override this one.

Since im utilizing a wildcard, i figured it should work this way, so that any subdomain i enter, will be redirected to HAProxy's SNI_Frontend. And since its listening on 0.0.0.0, i figured the virtual IP should work - i also tried the Firewalls IP address with no luck.



My tutorial clearly states that you have to use the OPNsense LAN IP in the DNS override.

How on earth would the lan devices be able to talk to a virtual IP created on the loopback device of the OPNsense. You should Google what the localhost is.
All of my posts are submitted with the best of knowledge and belief.


My post was helpful to you?
Feel free to click [applaud] to the left underneath my profile.
Additionally you can consider donating: https://www.buymeacoffee.com/thehellsite

Quote from: TheHellSite on November 10, 2022, 02:36:49 PM
Quote from: techsolo12 on November 10, 2022, 01:46:14 PM
Hello Guys!

Today its my first post here at this forum. At first @TheHellSite THANK YOU for your tutorial it helps my a lot! Before i used nginx proxy manager which was a lot easier than haproxy :)

I had one for my big problem and need the help from you all, please. I want to configure vaultwarden with websocket support in haproxy. The normal redirect to vaultwarden is no problem, but to add websocket support is still driven my crazy!

Sorry, but out of scope of this tutorial. Please ask in the official HAProxy forum.

Hello Guys!

Unfortunally nobody in the other forums can help me with this situation. Anybody in vaultwarden or haproxy forum. Is here nobody who had vaultwarden getting worked? :(

With best regards;
techsolo12

Quote from: techsolo12 on November 13, 2022, 04:08:24 PM
Hello Guys!

Unfortunally nobody in the other forums can help me with this situation. Anybody in vaultwarden or haproxy forum. Is here nobody who had vaultwarden getting worked? :(

With best regards;
techsolo12

As I already explained a dozen times: This tutorial is about getting HAProxy up and running with a LE cert. I won't be helping here with service specific settings, issues and what not!

That beeing said... I am also running Vaultwarden and it is working fine. However I don't use its websockets as I simply have no need for the additional features.

So please find this one out by yourself and feel free to post the solution here. :)
All of my posts are submitted with the best of knowledge and belief.


My post was helpful to you?
Feel free to click [applaud] to the left underneath my profile.
Additionally you can consider donating: https://www.buymeacoffee.com/thehellsite

apologies, my tired eyes at 4am missed this part

Quote from: TheHellSite on May 31, 2021, 01:06:11 PM

  • But if you would like to do it my way then you will need to create a virtual IP that is in a different subnet than any of your other networks. Preferably you would chose an IP that belongs to the localhost subnet in order to avoid IP conflicts in your local network.

i also misunderstand that setting a virtual IP that has a "loopback" does not automatically mean that it serves to "Loopback" to the firewall. that one was on me.

I updated the virtual ip to be 127.4.4.3 (mirroring your setup)

and updated SSL_Server to 127.4.4.3

HTTPS and HTTP Front Ends to listen on 127.4.4.3.

Updated unbound overide IP value to 10.0.1.1 (Firewall/OPNSense IP)

Restarted HAProxy - and its still not working. i wonder what i did wrong...

Update: Rebooted the firewall and that fixed it...

Okay, I've been through the instructions at least 3 times and cannot find why it's not working. Can someone please take a look? Other than it being currently disabled, obviously.

Firewall rule is:
IPv4 TCP Src* Port* Dest WAN address Port AliasforHTTP/HTTPS Gateway* Schedule*

#
# Automatically generated configuration.
# Do not edit this file manually.
#

#
# NOTE: HAProxy is currently DISABLED
#
global
    uid                         80
    gid                         80
    chroot                      /var/haproxy
    daemon
    stats                       socket /var/run/haproxy.socket group proxy mode 775 level admin
    nbproc                      1
    nbthread                    2
    hard-stop-after             60s
    no strict-limits
    maxconn                     10000
    tune.ssl.default-dh-param   4096
    spread-checks               2
    tune.bufsize                16384
    tune.lua.maxmem             0
    log                         /var/run/log local0 info
    lua-prepend-path            /tmp/haproxy/lua/?.lua

defaults
    log     global
    option redispatch 1
    maxconn 5000
    timeout client 30s
    timeout connect 30s
    timeout server 30s
    retries 3
    default-server init-addr last,libc

# autogenerated entries for ACLs


# autogenerated entries for config in backends/frontends

# autogenerated entries for stats




# Frontend: 0_SNI_Frontend ()
frontend 0_SNI_Frontend
    bind 0.0.0.0:443 name 0.0.0.0:443 accept-proxy
    bind 0.0.0.0:80 name 0.0.0.0:80 accept-proxy
    mode tcp
    default_backend SSL_backend
    # tuning options
    timeout client 15m

    # logging options

# Frontend: 1_HTTP_frontend ()
frontend 1_HTTP_frontend
    bind 127.4.4.3:80 name 127.4.4.3:80 accept-proxy
    mode http
    option http-keep-alive
    option forwardfor
    # tuning options
    timeout client 30s

    # logging options
    # ACL: NoSSL_condition
    acl acl_63859d8c6a7b81.10799804 ssl_fc

    # ACTION: HTTP_to_HTTPS
    http-request redirect scheme https code 301 if !acl_63859d8c6a7b81.10799804

# Frontend: 1_HTTPS_frontend ()
frontend 1_HTTPS_frontend
    http-response set-header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
    bind 127.4.4.3:443 name 127.4.4.3:443 accept-proxy ssl curves secp384r1  no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES256-GCM-SHA384 ciphersuites TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256 alpn h2,http/1.1 crt-list /tmp/haproxy/ssl/6385a4c7e68d06.81674833.certlist
    mode http
    option http-keep-alive
    option forwardfor
    # tuning options
    timeout client 30s

    # logging options

    # ACTION: PUBLIC_SUBDOMAINS_map-rule
    # NOTE: actions with no ACLs/conditions will always match
    use_backend %[req.hdr(host),lower,map_dom(/tmp/haproxy/mapfiles/63859df5259306.89264162.txt)]

# Backend: acme_challenge_backend (Added by ACME Client plugin)
backend acme_challenge_backend
    # health checking is DISABLED
    mode http
    balance source
    # stickiness
    stick-table type ip size 50k expire 30m 
    stick on src
    # tuning options
    timeout connect 30s
    timeout server 30s
    http-reuse safe
    server acme_challenge_host 127.0.0.1:43580

# Backend: homeassistant_backend ()
backend homeassistant_backend
    # health checking is DISABLED
    mode http
    balance source
    # stickiness
    stick-table type ip size 50k expire 30m 
    stick on src
    # tuning options
    timeout connect 30s
    timeout server 30s
    http-reuse safe
    server HomeAssistant 192.168.0.3:8123 check inter 30s port 8123

# Backend: web_backend ()
backend web_backend
    # health checking is DISABLED
    mode http
    balance source

    # tuning options
    timeout connect 30s
    timeout server 30s
    http-reuse safe
    server web 192.168.0.4:80

# Backend: SSL_backend ()
backend SSL_backend
    # health checking is DISABLED
    mode tcp
    balance source
    # stickiness
    stick-table type ip size 50k expire 30m 
    stick on src
    # tuning options
    timeout connect 30s
    timeout server 30s
    server SSL_Server 127.4.4.3 send-proxy-v2 check-send-proxy

# Backend: factorio_backend ()
backend factorio_backend
    # health checking is DISABLED
    mode http
    balance source

    # tuning options
    timeout connect 30s
    timeout server 30s
    http-reuse safe
    server factorio 192.168.0.17:80

# Backend: jira_backend ()
backend jira_backend
    # health checking is DISABLED
    mode http
    balance source

    # tuning options
    timeout connect 30s
    timeout server 30s
    http-reuse safe
    server jira 192.168.0.20:80

# Backend: meshcentral_backend ()
backend meshcentral_backend
    # health checking is DISABLED
    mode http
    balance source

    # tuning options
    timeout connect 30s
    timeout server 30s
    http-reuse safe
    server meshcentral 192.168.0.41:443

# Backend: nextcloud_backend ()
backend nextcloud_backend
    # health checking is DISABLED
    mode http
    balance source

    # tuning options
    timeout connect 30s
    timeout server 30s
    http-reuse safe
    server nextcloud 192.168.0.38:443 ssl alpn h2,http/1.1 verify none


# statistics are DISABLED


And the mapping file, which I have tried with the full FQDN and without the periods as well.
# public access subdomains
hass. homeassistant_backend
factorio. factorio_backend
jira. jira_backend
mesh. meshcentral_backend
nextcloud. nextcloud_backend
web_backend