Skip to content

Instantly share code, notes, and snippets.

@haproxytechblog
Last active November 28, 2022 16:27
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save haproxytechblog/af7f4678e0457b147ec487c52ed01be6 to your computer and use it in GitHub Desktop.
Save haproxytechblog/af7f4678e0457b147ec487c52ed01be6 to your computer and use it in GitHub Desktop.
Introduction to HAProxy Stick Tables
backend webfarm
stick-table type ip size 1m expire 10s store http_req_rate(10s)
# other configuration...
backend st_src_global
stick-table type ip size 1m expire 10s store http_req_rate(10s)
frontend fe_main
bind *:80
http-request track-sc0 src table st_src_global
backend st_src_global
stick-table type ip size 1m expire 10m store http_req_rate(10m)
backend st_src_login
stick-table type ip size 1m expire 10m store http_req_rate(10m)
backend st_src_api
stick-table type ip size 1m expire 10m store http_req_rate(10m)
frontend fe_main
bind *:80
http-request track-sc0 src table st_src_global
http-request track-sc1 src table st_src_login if { path_beg /login }
http-request track-sc1 src table st_src_api if { path_beg /api }
$ echo "show table st_src_global" | socat stdio UNIX-CONNECT:/var/run/hapee-1.8/hapee-lb.sock
# table: st_src_global, type: ip, size:1048576, used:1
0x18f907c: key=127.0.0.1 use=0 exp=3583771 http_req_rate(86400000)=3
$ echo "show table st_src_api" | socat stdio UNIX-CONNECT:/var/run/hapee-1.8/hapee-lb.sock
# table: st_src_api, type: ip, size:1048576, used:1
0x18f919c: key=127.0.0.1 use=0 exp=3572396 http_req_rate(86400000)=2
$ echo "show table st_src_login" | socat stdio UNIX-CONNECT:/var/run/hapee-1.8/hapee-lb.sock
# table: st_src_login, type: ip, size:1048576, used:1
0x18f989c: key=127.0.0.1 use=0 exp=3563780 http_req_rate(86400000)=1
stick-table type ip size 1m expire 10s store http_req_rate(10s)
tcp-request inspect-delay 10s
tcp-request content track-sc0 src
http-request deny if { sc_http_req_rate(0) gt 10 }
stick-table type ip size 1m expire 10s store conn_cur
tcp-request content track-sc0 src
tcp-request content reject if { sc_conn_cur(0) gt 10 }
stick-table type string len 128 size 2k expire 1d store http_err_rate(1d)
tcp-request content track-sc0 path
# table: fe_main, type: string, size:2048, used:2
0xbc929c: key=/ use=0 exp=86387441 http_err_rate(86400000)=0
0xbc99ac: key=/foobar use=0 exp=86390564 http_err_rate(86400000)=1
stick-table type string len 32 size 100k expire 30m
stick on req.cook(sessionid)
backend mysql
mode tcp
stick-table type integer size 1 expire 1d
stick on int(1)
server primary 192.168.122.60:3306 check on-marked-down shutdown-sessions
server backup 192.168.122.61:3306 check backup on-marked-down shutdown-sessions
backend st_ssl_stats
stick-table type string len 32 size 200 expire 24d store http_req_rate(24d)
frontend fe_main
tcp-request inspect-delay 10s
tcp-request content track-sc0 ssl_fc_protocol table st_ssl_stats
$ echo "show table st_ssl_stats" | socat stdio UNIX-CONNECT:/var/run/hapee-1.8/hapee-lb.sock
# table: st_ssl_stats, type: string, size:200, used:2
0xe4c62c: key=TLSv1 use=0 exp=2073596788 http_req_rate(2073600000)=1
0xe5a18c: key=TLSv1.2 use=0 exp=2073586582 http_req_rate(2073600000)=2
backend st_ssl_stats
stick-table type ip size 200 expire 1h store http_req_rate(1d)
frontend fe_main
tcp-request inspect-delay 10s
tcp-request content track-sc0 src table st_ssl_stats if { ssl_fc_protocol TLSv1.1 }
http-request deny if { sc_http_req_rate(0) gt 100 }
http-request deny if { src,table_http_req_rate(st_src_global) gt 100 }
tcp-request inspect-delay 10s
listen fe_main
bind *:443 ssl crt /path/to/cert.pem
bind *:80
server local unix:/var/run/hapee-1.8/ssl_handoff.sock send-proxy-v2
frontend fe_secondary
bind unix:/var/run/hapee-1.8/ssl_handoff.sock accept-proxy process 1
# Stick tables, use backend, default backend, etc goes here.
peers mypeers
peer centos7vert 192.168.122.64:10000
peer shorepoint 192.168.122.1:10000
stick-table type string len 32 size 100k expire 30m peers mypeers
@CharlesRDavis
Copy link

These are most helpful. Many thanks. However, is there some secret archive of stick-table info I cant find? The Haproxy doc and site explanation raise more questions than answers. And I cannot figure out where some of the material on this page came from. For instance, I cannot find any explanation of why this syntax is OK "src,table_http_req_rate(st_src_global)" or even what it is supposed to do exactly. If a full explanation is available, no matter how arcane or convoluted, I would be more than happy to produce a readable paper on the topic.

@NickMRamirez
Copy link

NickMRamirez commented Dec 20, 2019

@CharlesRDavis these code snippets are used in this blog post https://www.haproxy.com/blog/introduction-to-haproxy-stick-tables/.

I think I can add some more context and hopefully clear up the confusion with the "table_" syntax. Each of the "table_" directives is a "converter", and all converters receive an input and return an output. You can use the "table_" converters to look up an entry in a stick table. The entry that you look up does not need to be, for example, the current connection that is being tracked with an "http-request track-sc0 src" line. You can pass in any string and it will be looked up in the stick table.

I have not tested this, but I think it would be:

# returns request rate for IP 1.2.3.4
str("1.2.3.4"),table_http_req_rate(mytable)

or maybe:

ipv4(1.2.3.4),table_http_req_rate(mytable)

Or, you could pass in the IP address of the current connection, as:

# returns request rate for current connection, looked up by its source IP
src,table_http_req_rate(mytable)

But that should be equivalent to using sc_http_req_rate(0,mytable) since you will already be tracking the current connection with http-request track-sc0 src.

@CharlesRDavis
Copy link

Thanks Nick,
That helps and I really appreciate the explanation. However, my lack of comprehension is at a more basic level. For example, I am imagining a stick-table to be an array of "structs" of some sort, storing the ip, some counters, and other stuff. Currently, I am using stick-tables and counters for various security purposes without the fundamental understanding of what I am doing. For instance, consider this description for the manual:
- sc-inc-gpc0():
This action increments the GPC0 counter according with the sticky counter
designated by . If an error occurs, this action silently fails and
the actions evaluation continues.

How is this to be interpreted? There are two different counters mentioned here, a gpc0 counter and a sticky counter. Are these the same, or different. And if different, what is their relationship.
Are sticky counters and/or GPC0 counters stick-table elements, or are they independent, but somehow associated with or assigned to a stick table? And if so, how is that association determined?
The argument , what does it mean? Does it mean sc-inc-gpc0(2) is the same as sc2-inc-gpc0()
Without the fundamental knowledge, I am proceeding largely by trial and error. Makes me nervous.
So basically, what I am looking for is the explicit relationship between sticky counters, general purpose counters, and the stick-tables.
Clarification here would be greatly appreciated.
Charles Davis

@NickMRamirez
Copy link

Hi Charles.

OK, so I am going to give you what I think is a correct interpretation.

"sticky counters" are what let you track a client across requests. They, for lack of a better word, stick to the client in that whenever that client returns, HAProxy knows because it has stored a key, such as their IP address, in the stick table. The sticky counter, I think, is a slot into which the key and all counters are stored.

A "general purpose counter" is a custom counter. It is just a number you can increment based on an ACL. Use it for your own custom logic. It is stored among the other counters in the "slot".

These things are only relevant to stick tables.

"sc-inc-gpc0(2)" is equivalent to "sc2-inc-gpc0", but the latter is deprecated.

@jbrkeith
Copy link

Hi, I'm trying to implement the:

backend mysql
mode tcp
stick-table type integer size 1 expire 1d
stick on int(1)
server primary 192.168.122.60:3306 check on-marked-down shutdown-sessions
server backup 192.168.122.61:3306 check backup on-marked-down shutdown-sessions

example above and am getting this error in /var/log/messages:

Mar 29 04:34:18 nyitsdes201 systemd: Started HAProxy Load Balancer.
Mar 29 04:34:18 nyitsdes201 systemd: Starting HAProxy Load Balancer...
Mar 29 04:34:18 nyitsdes201 haproxy-systemd-wrapper: [ALERT] 087/043418 (32002) : parsing [/etc/haproxy/haproxy.cfg:87] : 'stick': unknown fetch method 'int'
Mar 29 04:34:18 nyitsdes201 haproxy-systemd-wrapper: [ALERT] 087/043418 (32002) : Error(s) found in configuration file : /etc/haproxy/haproxy.cfg

Is this because my haproxy version (1.5.18) is too old and doesn't support this feature?

@NickMRamirez
Copy link

@jbrkeith Yes, it looks like the int method was added in version 1.6.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment