How to Implement IP Geoblocking on Your Server
IP geoblocking restricts access to your Breeze instance based on the geographic origin of incoming connections. This is a practical defense against attacks originating from regions where you have no legitimate users, significantly reducing your attack surface.
Understanding Geoblocking Approaches
There are several ways to implement geoblocking on your server:
- iptables with GeoIP — kernel-level blocking using MaxMind GeoIP databases
- Nginx GeoIP2 module — application-level blocking within your web server
- nftables with GeoIP sets — modern kernel-level blocking with efficient set matching
- fail2ban with GeoIP — combining intrusion prevention with geographic filtering
Method 1: iptables with xtables-addons GeoIP
Install xtables-addons for GeoIP support:
sudo apt install -y xtables-addons-common libtext-csv-xs-perl
sudo mkdir -p /usr/share/xt_geoip
# Download and build the GeoIP database
cd /tmp
/usr/lib/xtables-addons/xt_geoip_dl
/usr/lib/xtables-addons/xt_geoip_build -D /usr/share/xt_geoip *.csv
Create firewall rules to block specific countries:
# Block traffic from specific country codes
sudo iptables -A INPUT -m geoip --src-cc CN,RU,KP -j DROP
# Or allow only specific countries
sudo iptables -A INPUT -m geoip ! --src-cc US,CA,GB -p tcp --dport 443 -j DROP
Method 2: Nginx GeoIP2 Module
Install the GeoIP2 module for Nginx:
sudo apt install -y libnginx-mod-http-geoip2 geoipupdate
Configure Nginx to use the GeoIP2 database:
# In the http block of nginx.conf
geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
auto_reload 60m;
$geoip2_country_code default=US source=$remote_addr country iso_code;
}
map $geoip2_country_code $allowed_country {
default no;
US yes;
CA yes;
GB yes;
DE yes;
AU yes;
}
server {
listen 443 ssl;
server_name yourdomain.com;
if ($allowed_country = no) {
return 403;
}
# ... rest of server config
}
Method 3: nftables with GeoIP Sets
For modern Linux kernels, nftables offers efficient set-based geoblocking:
# Create a set for blocked country IPs
sudo nft add table inet filter
sudo nft add set inet filter blocked_countries { type ipv4_addr \; flags interval \; }
# Populate the set with IP ranges from a GeoIP database
# Use a script to convert GeoIP data to nftables format
for range in $(cat /tmp/blocked_ranges.txt); do
sudo nft add element inet filter blocked_countries { $range }
done
# Create a rule to drop traffic from the set
sudo nft add chain inet filter input { type filter hook input priority 0 \; }
sudo nft add rule inet filter input ip saddr @blocked_countries drop
Automating GeoIP Database Updates
GeoIP databases require regular updates. Create a cron job:
# Create update script
cat <<'SCRIPT' | sudo tee /usr/local/bin/update-geoip.sh
#!/bin/bash
cd /tmp
/usr/lib/xtables-addons/xt_geoip_dl
/usr/lib/xtables-addons/xt_geoip_build -D /usr/share/xt_geoip *.csv
rm -f *.csv
SCRIPT
sudo chmod +x /usr/local/bin/update-geoip.sh
# Schedule weekly updates
echo "0 2 * * 0 root /usr/local/bin/update-geoip.sh" | sudo tee /etc/cron.d/geoip-update
Logging Blocked Requests
Log blocked connections for monitoring and analysis:
# Log before dropping with iptables
sudo iptables -A INPUT -m geoip --src-cc CN,RU -j LOG --log-prefix "GEOBLOCK: " --log-level 4
sudo iptables -A INPUT -m geoip --src-cc CN,RU -j DROP
Best Practices
- Whitelist before blacklisting — if you serve a limited audience, allow specific countries and block everything else
- Do not rely solely on geoblocking — attackers can use VPNs and proxies to bypass geographic restrictions
- Update GeoIP databases regularly — IP allocations change frequently; stale data causes false positives
- Monitor blocked traffic — review logs to ensure legitimate users are not being blocked
- Combine with rate limiting — use geoblocking alongside fail2ban and rate limiting for layered defense
IP geoblocking is a simple but effective way to reduce the attack surface of your Breeze instance by filtering traffic from regions that should not be accessing your services.