Rate limit connections to your application using Varnish
Problem
Bots, bad users, bad actors can often use up PHP workers and CPU time by constantly making bad queries to your application.
This causes 502/503 errors for the end users as documented in https://docs.platform.sh/development/troubleshoot.html#http-responses-502-bad-gateway-or-503-service-unavailable
We can use some automation to block these IPs but it would be great if we could do it automatically.
https://community.platform.sh/t/diagnosing-and-resolving-issues-with-excessive-bot-access/792
Solution
Lets add Varnish to our environment, it can check the traffic coming into the application and forward it on if it is within the rate limits we set.
Follow the instructions below to implement Varnish on your environment.
In the source code of your project.
- Edit the
.platform/services.yaml
file and add a Varnish service.
varnish:
type: varnish:6.0
relationships:
main: 'app:http'
configuration:
vcl: !include
type: string
path: varnish.vcl
- Edit the
.platform/routes.yaml
file and edit the routes to point to the Varnish service.
Instead of
https://{default}/:
type: upstream
upstream: app:http
adjust your routes to
https://{default}/:
type: upstream
upstream: varnish:http
- Create a file in that directory
.platform/varnish.vcl
with the following contents
import vsthrottle;
sub vcl_recv {
# Varnish will set client.identity for you based on client IP.
if ( req.url !~ "^[^?]*\.(7z|avi|bmp|bz2|css|csv|doc|docx|eot|flac|flv|gif|gz|ico|jpeg|jpg|js|less|mka|mkv|mov|mp3|mp4|mpeg|mpg|odt|ogg|ogm|opus|otf|pdf|png|ppt|pptx|rar|rtf|svg|svgz|swf|tar|tbz|tgz|ttf|txt|txz|wav|webm|webp|woff|woff2|xls|xlsx|xml|xz|zip)(\?.*)?$" && vsthrottle.is_denied(req.http.X-Client-IP, 10, 15s, 123s)) {
# Client has exceeded 10 reqs per 15s.
# When this happens, block altogether for the next 123s.
return (synth(429, "Too Many Requests"));
}
# Only allow a few POST/PUTs per client.
if (req.method == "POST" || req.method == "PUT") {
if (vsthrottle.is_denied("rw" + req.http.X-Client-IP, 3, 10s, 123s)) {
return (synth(429, "Too Many Requests"));
}
}
set req.backend_hint = main.backend();
}
-
git add
the new file andgit commit
the changes and push them to your environment
Finally
Once implemented, any single IP trying to make more than 30 requests in a 15-second window, will be blocked for 127 seconds, and any IP making more than 3 POST or PUT requests to the endpoint within a 10-second window will be banned for 61 seconds.
These values can be adjusted as you need, and the key which is used by the vsthrottle module on can also be adjusted.
https://docs.varnish-software.com/varnish-cache-plus/vmods/vsthrottle/
The Platform.sh router will provide the real client IP as req.http.X-Client-IP
and not client.identity
.