HAProxy Real IP + Cloudflare – Use src in firewal table

I searched the entire internet to find a solution to use the Real IP in the rules of a firewall and unfortunately I did not find anything concrete, all the resources were referring to something else but not my case.
I mean, most of them just wanted to find out the Real IP behind a CDN like Cloudflare and set it for backend servers use only!

In the end, I found myself a perfectly functional solution, that proved very useful for multiple configurations that I did later on many other servers.

Below you have the basic configuration for the front end and an example of debugging in the backend, in case you want to check the correct functioning of the settings/algorithm.

frontend:

...
    #~~~ Get real IP if CloudFlare is present
    acl cf_src  src -f /etc/haproxy/cf-ip.lst
    acl cf_real_ip req.hdr(CF-Connecting-IP) -m found
    http-request set-var(txn.realip) req.hdr(CF-Connecting-IP) if cf_src cf_real_ip
    http-request set-var(txn.realip) src if !cf_src
    http-request set-header X-Real-IP %[var(txn.realip)]
    http-request set-header X-Forwarded-For %[var(txn.realip)] if !cf_src

    #~~~ save src temporary, restore later
    http-request set-var(txn.realsrc) src
    http-request set-src var(txn.realip)
...
...
    #~~~ restore src original IP
    http-request set-src var(txn.realsrc)
    default_backend http_back

Explanation of the code:

acl cf_src src -f /etc/haproxy/cf-ip.lst  => check if the IP belongs to CloudFlare. The list of IPs with which cloudflare connects to our proxy server, you must download it from here: https://www.cloudflare.com/ips-v4
Save the file used above:
wget https://www.cloudflare.com/ips-v4 > /etc/haproxy/cf-ip.lst

acl cf_real_ip req.hdr(CF-Connecting-IP) -m found  => check if the CF-Connecting-IP field is in the header

http-request set-var(txn.realip) req.hdr(CF-Connecting-IP) if cf_src cf_real_ip  => save the real IP in variable txn.realip, if the above conditions are met, ie the source is CloudFlare and in the header I had CF-Connecting-IP

http-request set-var(txn.realip) src if !cf_src  => If the source does not come from CloudFlare, then in variable X we save the current IP src.

http-request set-header X-Real-IP %[var(txn.realip)]  => Now we set in the header the Real IP so that it can be used universally by any script in the backend server,  reading the X-Real-IP header and no matter the source, he will always be the real one.

http-request set-header X-Forwarded-For %[var(txn.realip)] if !cf_src  => If the source is not CloudFlare, then we set the real IP in the X-Forwarded-For header

http-request set-var(txn.realsrc) src  => The IP from the src is temporarily saved in the txn.realsrc variable

http-request set-src var(txn.realip)  => We set src with the IP previously saved in the variable txn.realip, and if the source is from CloudFlare, the value from src will be the IP of the client, the one who visits the website. This is the most important line, because from here we can use src as usual, as it contains the IP we need.

http-request set-src var(txn.realsrc)  => At the end of the configuration in the frontend, we restore the real value src, if we do not need it elsewhere.

The following line is useless to use if we use CloudFlare and do not have the above configuration, because we got blocked all the traffic from CloudFlare:

http-request track-sc1 url32+src table per_ip_and_url_rates unless static

backend:

...
    #~~~ for debug only	
    http-response set-header X-Client-IP %[var(txn.realip)]
...

Explanation of the code:

We configure the X-Client-IP header where we can view the IP with which we visit the website (txn.realip), when analyzing the server response in a web page!

That’s all it was, Happy Coding!

byrev Written by:

Be First to Comment

    Leave a Reply

    Your email address will not be published. Required fields are marked *