A 2 AM Phone Call and a Screen Full of Red Logs
At 2 AM, my phone wouldn’t stop buzzing on the desk. The monitoring system was screaming as the server CPU spiked to 95%. For a VPS running WordPress and an API serving Vietnamese users, this was a bad sign. The moment I SSH’d in and opened access.log, my stomach dropped — tens of thousands of requests were hammering the server every minute. Unknown IP ranges were relentlessly pounding /wp-login.php and /xmlrpc.php.
tail -f /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -nr | head -n 20
A quick lookup on a few IPs revealed they were coming from countries this project had never done business with. It was a large-scale brute-force attack from an international botnet. Instead of manually blocking IPs one by one — a task that would never end — I decided to deploy GeoIP Blocking immediately. The goal was simple: drop all traffic from countries outside my user base.
Three Common IP-Blocking Approaches
Before typing a single command, I weighed three familiar approaches used by sysadmins:
1. Firewall-Based Blocking (UFW/IPTables)
This approach blocks at the network layer, making it extremely lightweight for the server. However, managing tens of thousands of IP ranges per country using IPTables is a nightmare. Every time you update the database, the script runs forever and can easily lock up the system.
2. Cloudflare GeoIP
If you’re already using Cloudflare as a proxy, this is dead simple — just head to the Security tab, create a Rule, and you’re done. But in practice, not every project should be routed through Cloudflare. Some systems need low latency optimization or strict internal security requirements.
3. Nginx with the GeoIP2 Module
This is the most balanced option between performance and flexibility. Nginx reads MaxMind’s binary database (.mmdb) directly to identify a country in just a few milliseconds. You can block at the http or server block level and fully customize the response returned to users.
Why MaxMind GeoLite2 Is Good Enough
MaxMind offers GeoLite2 for free with approximately 99% accuracy at the country level. While the paid version is more precise, for the purpose of blocking botnets and reducing server load, the Lite edition is more than sufficient.
A quick tip: beyond IP blocking, make sure you set a seriously strong admin password. I often use the password generator at toolcraft.app/en/tools/security/password-generator. It runs 100% in the browser, so your password never travels over the network.
Step-by-Step Deployment
Step 1: Install the GeoIP2 Module
On Ubuntu 22.04, a single command is all you need to install the module:
sudo apt update && sudo apt install libnginx-mod-http-geoip2 -y
Once installed, run this command to confirm the module is loaded into Nginx:
nginx -V 2>&1 | grep --color geoip2
Step 2: Download the Database from MaxMind
MaxMind now requires a registered account to download the database. After signing up, create a “License Key”. I recommend using the geoipupdate tool to automatically refresh the data weekly — it saves a lot of manual effort:
sudo apt install geoipupdate -y
Configure /etc/GeoIP.conf with your license key, then run geoipupdate. The database file will appear at /usr/share/GeoIP/GeoLite2-Country.mmdb.
Step 3: Teach Nginx to Identify Countries
Open /etc/nginx/nginx.conf and add the following inside the http { ... } block:
http {
geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
auto_reload 5m;
$geoip2_data_country_code default=XX source=$remote_addr country iso_code;
}
map $geoip2_data_country_code $allowed_country {
default yes;
CN no; # Block China
RU no; # Block Russia
BR no; # Block Brazil
}
}
The $allowed_country variable acts as a filter. If a request comes in from Russia (RU) or China (CN), it gets immediately flagged as no.
Step 4: Set Up the Checkpoint
Now apply the filter to your site’s server block configuration:
server {
listen 80;
server_name itfromzero.com;
if ($allowed_country = no) {
return 403;
}
location / {
# Your web application code here
}
}
Finally, validate the config syntax and reload Nginx to apply the changes:
sudo nginx -t && sudo systemctl reload nginx
The Sweet Results
Immediately after reloading Nginx, junk requests in the log dropped from 10,000 req/min to under 100. Server CPU cooled down from 95% to a stable 10%.
That said, don’t forget these three critical caveats:
- Don’t block Googlebot: If you care about SEO, always allow
US— Google’s crawlers primarily originate from the United States. - VPNs can still get through: GeoIP Blocking won’t stop users with a VPN exit node in an allowed country. It’s an industrial-grade filter against international botnets, not a silver bullet.
- Schedule regular updates: Country IP ranges change frequently. Set up a weekly cronjob to run
geoipupdateautomatically.
Server security is a long game. GeoIP Blocking is like closing your windows to keep out the dust — but the front door still needs a solid lock. Here’s to sleeping soundly at night, without a botnet waking you up!

