Tested on Debian 9 / Varnish 5.0
Module vmod_vsthrottle is a varnish module to limit requests by unit time. It can be useful for APIs or as protection against an attack.
Varnish has grouped all official modules in a all-in-one package, so to compile vmod_vsthrottle is necessary compile all modules.
First install packages and libraries needed, of course you need varnish itslef:
~ $ apt-get install varnish libvarnishapi1 libvarnishapi-dev libtool python-docutils make pkg-config
Download varnish-modules from https://download.varnish-software.com/varnish-modules:
~ $ cd /usr/local/src/ ~ $ wget https://download.varnish-software.com/varnish-modules/varnish-modules-0.15.0.tar.gz ~ $ tar xvzf varnish-modules-0.15.0.tar.gz ~ $ cd varnish-modules-0.15.0
Compile and install:
~ $ ./configure ~ $ make ~ $ make install
Check new modules were installed, included vmod_vsthrottle:
~ $ ls -l /usr/lib/x86_64-linux-gnu/varnish/vmods/ total 596 -rwxr-xr-x 1 root root 1019 Apr 22 13:15 libvmod_bodyaccess.la -rwxr-xr-x 1 root root 51896 Apr 22 13:15 libvmod_bodyaccess.so -rwxr-xr-x 1 root root 995 Apr 22 13:15 libvmod_cookie.la -rwxr-xr-x 1 root root 56480 Apr 22 13:15 libvmod_cookie.so -rw-r--r-- 1 root root 55208 Nov 9 2017 libvmod_directors.so -rwxr-xr-x 1 root root 995 Apr 22 13:15 libvmod_header.la -rwxr-xr-x 1 root root 52576 Apr 22 13:15 libvmod_header.so -rwxr-xr-x 1 root root 1013 Apr 22 13:15 libvmod_saintmode.la -rwxr-xr-x 1 root root 66048 Apr 22 13:15 libvmod_saintmode.so -rw-r--r-- 1 root root 26560 Nov 9 2017 libvmod_std.so -rwxr-xr-x 1 root root 977 Apr 22 13:15 libvmod_tcp.la -rwxr-xr-x 1 root root 41912 Apr 22 13:15 libvmod_tcp.so -rwxr-xr-x 1 root root 977 Apr 22 13:15 libvmod_var.la -rwxr-xr-x 1 root root 63240 Apr 22 13:15 libvmod_var.so -rwxr-xr-x 1 root root 1019 Apr 22 13:15 libvmod_vsthrottle.la -rwxr-xr-x 1 root root 61328 Apr 22 13:15 libvmod_vsthrottle.so -rwxr-xr-x 1 root root 983 Apr 22 13:15 libvmod_xkey.la -rwxr-xr-x 1 root root 86000 Apr 22 13:15 libvmod_xkey.so
Now import module in /etc/varnish/default.vcl at the top of file:
import vsthrottle;
And add this to vcl_recv sub;
if (vsthrottle.is_denied(req.http.host, 15, 10s, 30s)) { return (synth(429, "Too Many Requests")); }
Here we are using key “req.http.host”, it means will ban request by HTTP header host. More than 15 request in 10 seconds will be banned for 30 seconds.
You can use another key, for example X-Country-Code (using vmod_geoip), X-Forwarded-For, req.url, or several, for example:
if (vsthrottle.is_denied(req.http.host + X-Country-Code, 15, 10s, 10s)) { return (synth(429, "Too Many Requests")); }
Bans requests for 10 seconds if ratio is more than 15 requests in 10 seconds when http header host and country code were the same.
Finally reload varnish:
~ $ /etc/init.d/varnish reload
Test it trying reach the limit:
~ $ curl -I -X GET http://domain.com
Use varnishncsa to see requests and code status:
~ $ varnishncsa -F '(Status:%s) %{X-Country-Code}i [%{Varnish:handling}x] %{X-Real-IP}i %m %{Host}i %U' (Status:200) XX [pass] 10.10.10.2 GET domain.com / (Status:200) XX [pass] 10.10.10.2 GET domain.com / (Status:200) XX [pass] 10.10.10.2 GET domain.com / (Status:200) XX [pass] 10.10.10.2 GET domain.com / (Status:200) XX [pass] 10.10.10.2 GET domain.com / (Status:429) XX [synth] 10.10.10.2 GET domain.com / (Status:200) XY [pass] 10.10.10.3 GET domain.com / (Status:200) XZ [pass] 10.10.10.4 GET domain.com / (Status:429) XX [synth] 10.10.10.2 GET domain.com / (Status:429) XX [synth] 10.10.10.2 GET domain.com /