MarkMaunder dot com

How to limit website visitor bandwidth by country

This technique is great if you have no customers from countryX but are being targeted by a DoS, unwanted crawlers, bots, scrapers and other baddies. Please don’t use this to discriminate against less profitable countries. The web should be open for all. Thanks.

If you’re not already using Nginx, you should get it even if you already have a great web server. Put it in front and get it to act as a reverse proxy.

First grab this perl script which you will use to convert Maxmind’s geo IP database into a format usable by Nginx.

Then download Maxmind’s latest GeoLite country database in CSV format on this page.

Then run:

geo2nginx.pl < maxmind.csv > nginxGeo.txt

Copy nginxGeo.txt into your nginx config directory.

Then add the following text in the ‘http’ section of your nginx.conf file:

geo $country {
default no;
include nginxGeo.txt;
}

Then add the following in the ‘server’ section of your nginx.conf file:

if ($country ~ ^(?:US|CA|ES)$ ){
set $limit_rate 10k;
}
if ($country ~ ^(?:BR|ZA)$ ){
set $limit_rate 20k;
}

This limits anyone from the USA, Canada and Spain to a maximum of 10 kilobits per second of bandwidth. It gives anyone from Brazil and South Africa 20 Kbps of bandwidth. Every other country gets the maximum.

You could use a exclamation character before the tilde (!~) to do the opposite. In other words, if you’re NOT from US, Canada or Spain, you get 10 Kbps, although I strongly advise against this policy.

Remember that $limit_rate only limits per connection, so the amount of bandwidth each visitor has is $limit_rate X number_of_connections. See below to limit connections.

Another interesting variable is limit_rate_after. The documentation on this is very very sparse, but from what I’ve gathered it is time based. So the first 1 minute of a connection will get full bandwidth, and then after that the limiting starts. Great for streaming sites I would think.

There are two other great modules in Nginx but neither of them work inside ‘if’ directives which means you can’t use them to limit by country. They are the Limit Zone module which lets you limit the number of concurrent connections and the Limit Requests module which lets you limit the number of requests over a period of time. The Limit Requests module also has a burst variable which is very useful. Once again the documentation is sparse, but this comment from Igor (Nginx author) sheds some light on how bursting works.

I’ve enabled all three features on our site. Bandwidth limiting by country, limiting concurrent connections and limiting requests over a time period. I serve around 20 to 40 million requests a day on a single nginx box and I haven’t noticed much performance degradation with the new config. It has quadrupled the size of each nginx process though to about 46M per process, but that’s still a lot smaller than most web server processes.

One Comment

    Si14

    Hi,
    I am receiving huge amount of traffic (from few IP addresses, and I assume they are hacker) to my website, which might cause my website to shut down.
    1- Do you have any advise on this?
    2- Is it possible to limit the Bandwidth for every visitor IP, so no IP can consume a lot bandwidth?

    Thanks.

    Commented on March 6, 2013 at 11:02 am

Leave a Comment

Your email address will not be published. Required fields are marked *

My name is Mark Maunder. I've been blogging since around 2003 when I started on Movable Type and ended up on WordPress which is what I use to publish today. With my wife Kerry, I'm the co-founder of Wordfence which protects over 5 million WordPress sites from hackers and is run by a talented team of 36 people. I'm an instrument rated pilot and I fly a Cessna 206 along with a 1964 Cessna 172 in the Pacific Northwest and Colorado. I'm originally from Cape Town, South Africa but live in the US these days. I code in a bunch of languages and am quite excited about our emerging AI overlords and how they're going to be putting us to work for them.