Looking for HAProxy behind Cloudflare tutorial / example

Hi,
I used the search before opening this thread and realized that there are several similar threads, but no one with a solution …
First of all, I am a tech enthusiast with a home lab and don’t manage a data center. However, I have a 10g internet connection that wants to be used, run several servers, and like to learn new things.
Almost two years ago I got in touch with L7 forwarding and cloudflare via this youtube video that describes exactly what I am looking for: Use cloudflare wild card certificates with a free KEMP loadbalancer to do L7 forwarding via subdomains and port 443 to different servers on my network.

However, the free KEMP loadbalancer is limited to 20Mbit/s, so I was looking for a free alternative and started playing around with HAproxy, but never really got it to work and at some point gave up and fell back to KEMP. Now I moved countries, upgraded my home lab, have an even faster internet connection and would like to give it another try.

I found a step-by-step tutorial for HAProxy that describes what I want to accomplish: How to add Cloudflare in front of HAProxy
However, the tutorial is for a GUI version of HAProxy and therefore for people who can afford paying big money / companies. I am looking for something similar that describes how to configure something like that with the free (GUI-less) version.

I also found the free HAProxy-wi and Roxy-Wi, whereof the installation instructions of the former one are not working because of missing files and the latter one requires a donation before it can be tested (I am happy to donate, but I don’t want to donate in the first place and then realize afterwards that it also doesn’t work).

There are also tutorials for pfSense/HAProxy, but I don’t have pfSense.

Is anyone aware of a working tutorial to set something like that up?
If anyone has an example configuration that he/she would be willing to share, I also would be grateful!

Thank you!

I have done a write up on this.

Awesome!
Thank you! I will try to set it up tomorrow!

Hi,
I am really sorry, but I can’t get it to work with your instructions. I might not get how to do the forwarding to subdomains correctly.

I set up the certificate and private key file as described in your description and saved it in domain.com.pem.
To incorporated the forwarding, I modified the service lines … but what I did doesn’t look correct to me …

I have a domain at cloudflare, let’s call it dummy.com. I generated an origin certificate and private key for dummy.com and *.dummy.com as described on your website.
On cloudflare, I set up a CNAME record for
nextcloud.dummy.com that is proxied and
grafana.dummy.com that is also proxied.
I set the SSL/TLS encryption mode on Cloudflare to Full strict.
Then I copied your config file and edited the parts for the frontend and backend according to what I thought it might look like.
Then I restarted the service and of course it failed.

According to this tutorial: HAProxy For Load Balancing and Subdomain-Port Redirection — Steemit
I need something like
acl sub1 hdr_sub(host) -i nextcloud.dummy.com
and
acl sub2 hdr_sub(host) -i grafana.dummy.com
with a bind to port 80 in the frontend and mode http (not https ?!?) in the backend.
… but I don’t want to forward stuff on port 80, but from 443 to 443, just based on which subdomain was used. I guess this must be a super simple case and I apologize for not getting it, but I don’t get it.

That’s what I have so far:

global
    log /dev/log local0
    log /dev/log local1 notice
    chroot /var/lib/haproxy
    stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd liste>
    user haproxy
    group haproxy
    daemon
    maxconn 40000
    ulimit-n 81000
    crt-base /etc/haproxy/certificates/

defaults
    mode http
    option httplog
    option dontlognull
    option forwardfor
    log global
    timeout client 30s
    timeout server 30s
    timeout connect 5s

# HTTP Frontend
frontend fe_http
    bind *:80
    http-request redirect scheme https code 301

# HTTPS Frontend
frontend fe_https
    bind *:443 ssl crt domain.com.pem

    acl service1 ssl_fc_sni nextcloud.dummy.com
    use_backend be_service1 if service1

    acl service2 ssl_fc_sni grafana.dummy.com
    use_backend be_service2 if service2


    # This redirects to a failure page
    default_backend be_no-match

backend be_no-match
    http-request deny deny_status 403

backend be_service1
    #option forwardfor
    server service1 172.16.52.10:443 check

backend be_service2
    #option forwardfor
    server service2 172.16.52.31:3000 check

Thank you!

Sorry, I need to update that. It is better to use hdr(host) -i

I have a better version in my complete haproxy configuration.

The port 80 config is simply telling the client to use 443 instead.

If your backend has TLS enabled, you might need to have ssl verify none on the server backend after check. This is required if you are using a self-signed certificate and HAProxy does not have the root certificate installed. It is perfectly safe to do this because HAProxy is doing TLS offloading.

1 Like

Oh yeah!!! :slight_smile:
It’s working!!
I wasn’t able to rebuild your fancy setup, although I’d like to!
I installed crowdsec, but things with the bouncer didn’t work. However, it would be nice to see the original IPs of the visitor. I set my firewall up do allow access only from certain countries and having them hidden behind cloudflare is not ideal.
The frontend for internal IPs is also neat! But I wasn’t sure what to do with the wildcard certificate. Up to my knowledge it is not possible to download it from cloudflare. I will look into generating my own with the certbot cloudflare plugin/API (Welcome to certbot-dns-cloudflare’s documentation! — certbot-dns-cloudflare 0 documentation, other DNS services here: User Guide — Certbot 2.4.0 documentation)
Thanks for your help! Highly appreciated!

For everyone else looking for a simple working example, see below (it is simplexion’s config, just skimmed + the ssl verify none in the end):

global
    log /dev/log local0
    log /dev/log local1 notice
    chroot /var/lib/haproxy
    stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
    user haproxy
    group haproxy
    daemon
    maxconn 40000
    ulimit-n 81000
    crt-base /etc/haproxy/certificates/

    ## Crowdsec bouncer
    #lua-prepend-path /usr/lib/crowdsec/lua/haproxy/?.lua
    #lua-load /usr/lib/crowdsec/lua/haproxy/crowdsec.lua
    #setenv CROWDSEC_CONFIG /etc/crowdsec/bouncers/crowdsec-haproxy-bouncer.conf

defaults
    mode http
    option httplog
    option forwardfor
    option dontlognull
    log global
    timeout client 30s
    timeout server 30s
    timeout connect 5s
    errorfile 400 /etc/haproxy/errors/400.http
    errorfile 403 /etc/haproxy/errors/403.http
    errorfile 408 /etc/haproxy/errors/408.http
    errorfile 500 /etc/haproxy/errors/500.http
    errorfile 502 /etc/haproxy/errors/502.http
    errorfile 503 /etc/haproxy/errors/503.http
    errorfile 504 /etc/haproxy/errors/504.http

#listen stats
#    bind *:8404
#    stats enable
#    stats hide-version
#    stats realm Haproxy\ Statistics
#    stats uri /haproxy_stats
#    stats auth HAProxy:Password

# Frontend to redirect HTTP to HTTPS with code 301
frontend http-redirect
    bind *:80
    http-request redirect scheme https code 301

# Frontend for redirecting traffic to the required frontend
frontend https-redirect
    bind *:443
    mode tcp
    option tcplog
    tcp-request inspect-delay 5s
    tcp-request content accept if { req_ssl_hello_type 1 }
    #acl internal src 192.168.210.0/24
    #IPs from here: https://www.cloudflare.com/ips-v4
    acl cloudflare src -f /etc/haproxy/CF_ips.lst
    use_backend cloudflare if cloudflare
    #use_backend internal if internal

# Frontend for external users that a connecting through Cloudflare
frontend cloudflare
    bind *:7000 accept-proxy ssl crt domain.com.pem

    # SNI ACLs
    acl nextcloud hdr(host) -i nextcloud.domain.com
    acl grafana hdr(host) -i grafana.domain.com

    # Send to backend based on SNI ACL
    use_backend nextcloud if nextcloud
    use_backend grafana if grafana

    # This redirects to a failure page
    default_backend no-match

# Redirect to frontend based on internal or external connections
backend cloudflare
    mode tcp
    server loopback-for-tls 127.0.0.1:7000 send-proxy-v2

# Normal Backends
backend no-match
    http-request deny deny_status 403

backend nextcloud
    server nextcloud 172.16.3.2:443 check ssl verify none

backend grafana
    server grafana 172.168.3.3:443 check ssl verify none

1 Like