I've been trying to implement rate limiting for some HTTP POST requests on my website. It works great, except for one detail: the expiration of my entry in my stick-table is always reset to 30 seconds, which means that if the client mistakenly makes a request 29 seconds after being blocked, it will be blocked, again, for 30 seconds.
Here's my config, stripped down to the bare minimal for ease of reading:
frontend http-in mode http bind *:80 ### Request limiting # Declare stick table stick-table type string size 100k expire 30s store gpc0 # Inspect layer 7 tcp-request inspect-delay 15s # Declare ACLs acl source_is_abuser sc0_get_gpc0 gt 0 tcp-request content track-sc0 req.cook(frontend) if !source_is_abuser ### End Request limiting use_backend rate-limit if source_is_abuser default_backend mybackend backend mybackend mode http stick-table type string size 100k expire 30s store http_req_rate(30s) tcp-request content track-sc1 req.cook(frontend) if METH_POST acl post_req_rate_abuse sc1_http_req_rate gt 30 acl mark_as_abuser sc0_inc_gpc0 gt 0 tcp-request content accept if post_req_rate_abuse mark_as_abuser server myLocalhost 127.0.0.1:8081 backend rate-limit mode http errorfile 503 /usr/local/etc/haproxy/rate-limit.http
With this config, as soon as a client makes more than 1 request per second over 30 seconds, this client is marked as an abuser by
mybackend. The following request are then, as expected, blocked by the
However, every time the currently marked
source_is_abuser client sends a request, the expiration counter of
http-in 's stick-table is reset to 30 seconds. I would expect the expiration counter to keep going down, since the connection is supposedly only tracked when
Any insight into what I am doing wrong?