This is sample configuration,

frontend fe_app

    bind name http
    acl has_auth_header req.fhdr(api-key) -m found

    acl mark_as_abuser       sc0_inc_gpc0(be_429_table_api) gt 10
    acl req_rate_api_abuse   sc0_http_req_rate(be_429_table_api) gt 10

    http-request set-header X-Concat %[req.fhdr(api-key)]_%[src] if has_auth_header
    http-request track-sc0 req.fhdr(X-Concat) table be_429_table_api if has_auth_header
    capture request header X-Concat len 100 

    use_backend be_429_slow_down if mark_as_abuser req_rate_api_abuse has_auth_header

    default_backend be_default

backend be_429_table_api
    stick-table type string size 100k expire 10s store http_req_rate(10s),http_req_cnt,gpc0,gpt0

backend be_429_slow_down
    timeout tarpit 10s
    http-request tarpit

And I tested with watch -n2 'echo "show table be_429_table_api" | socat stdio unix:/var/run/haproxy.sock'

The issue is upon receiving request gpc0 automatically starts increasing. Until table is expired. It doesn't seem to related to http_req_rate any way at all. What is the purpose of this counter then ?

I want a counter which only increases when http_req_rate >10. So when it goes over 3 ( i.e the offender repeats it for more than 3 time during 1 m) I can block. Something like following

1) 2:00:00 pm : http_req_rate > 10, abuae_counter =1

2) 2:00:07 pm: http_req_rate > 10, abuse_counter = 2

3) 2:00:17 pm : http_req_rate > 10 abuse_counter =3

4) 2:00:45 pm: http_req_rate > 10 abuse_counter =4 > Block

I can then simply use

use_backend be_429_slow_down if abuse_counter has_auth_header

How to achieve that ? I thought about using lua or set.var but nothing worked.


if you want a simple count with a big time slice, you can use

frontend website
    bind :80
    stick-table  type ip  size 100k  expire store http_req_rate(24h)
    http-request track-sc0 src
    http-request deny deny_status 429 if { sc_http_req_rate(0) gt 20 }
    default_backend servers

I removed the expires parameter from the stick table as from documentation:

A stick table record expires and is removed after a period of inactivity by the client, as set by the expire parameter. That’s just a way of freeing up space. Without an expire parameter, oldest records are evicted when the storage becomes full
  • Did you even read my question ? I don't want to do it for 24 hr, I want to do it per second. For the time being g let's say the time duration is 1m or 2m. I want to block if req rate is greater than the specified limit for more than 3 times. And even with your example it is still blocking the first time it crosses the rate limit ? So what's the point of 24 h or 10 h? Oct 16 '19 at 6:31
  • I got it :) the count of count, if you are a bad bot now you need to bad1, bad2, bad3 and now you a big bad boy :)
    – c4f4t0r
    Oct 16 '19 at 12:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.