[Guide] Geo Blocking With UFW / IPTables

Geo blocking are sometimes necessary for some web application to filtered out traffic from countries or simply to reduce cost by reduce the usage from non targeted countries.

This guide will show you how to setup geo blocking with firewall rules to block user based on their countries, we will be using the geoip module from Xtables-addons, and we will be merging multiple free database to get more comprehensive coverage.

In this tutorial my environment is Ubuntu 20.04 LTS, and the example of this tutorial will be blocking users from certain countries from accessing our web app hosted on this server.

Install Prerequisites

sudo apt update -y
sudo apt upgrade -y
sudo apt install curl perl unzip xtables-addons-common libtext-csv-xs-perl libmoosex-types-netaddr-ip-perl

Download Database

First, let’s make a directory:

sudo mkdir -p /usr/share/xt_geoip

Now we’ll setup a script to download and update database for the latest IP to countries list, this is a simple script that combine multiple source of IP2Country databases, for better coverage you can also pay for DP-IP commercial database, which will include more IPs.

sudo nano /usr/local/bin/update-geoip.sh

Then paste this into the script and save:

#!/bin/bash

# Create temporary directory
mkdir -p /usr/share/xt_geoip/tmp/
mkdir -p /usr/share/xt_geoip/tmp/ip2loc/

# Download latest from db-ip.com
cd /usr/share/xt_geoip/tmp/
/usr/lib/xtables-addons/xt_geoip_dl

# Download maxmind legacy csv and process
wget https://mailfud.org/geoip-legacy/GeoIP-legacy.csv.gz -O /usr/share/xt_geoip/tmp/GeoIP-legacy.csv.gz
gunzip /usr/share/xt_geoip/tmp/GeoIP-legacy.csv.gz
cat /usr/share/xt_geoip/tmp/GeoIP-legacy.csv | tr -d '"' | cut -d, -f1,2,5 > /usr/share/xt_geoip/tmp/GeoIP-legacy-processed.csv
rm /usr/share/xt_geoip/tmp/GeoIP-legacy.csv
rm /usr/share/xt_geoip/tmp/GeoIP-legacy.csv.gz

# Download latest from https://github.com/sapics/ip-location-db
wget -P /usr/share/xt_geoip/tmp/ https://cdn.jsdelivr.net/npm/@ip-location-db/geo-whois-asn-country/geo-whois-asn-country-ipv4.csv
wget -P /usr/share/xt_geoip/tmp/ https://cdn.jsdelivr.net/npm/@ip-location-db/geo-whois-asn-country/geo-whois-asn-country-ipv6.csv
wget -P /usr/share/xt_geoip/tmp/ https://cdn.jsdelivr.net/npm/@ip-location-db/iptoasn-country/iptoasn-country-ipv4.csv
wget -P /usr/share/xt_geoip/tmp/ https://cdn.jsdelivr.net/npm/@ip-location-db/iptoasn-country/iptoasn-country-ipv6.csv
wget -P /usr/share/xt_geoip/tmp/ https://cdn.jsdelivr.net/npm/@ip-location-db/dbip-country/dbip-country-ipv4.csv
wget -P /usr/share/xt_geoip/tmp/ https://cdn.jsdelivr.net/npm/@ip-location-db/dbip-country/dbip-country-ipv6.csv
wget -P /usr/share/xt_geoip/tmp/ https://cdn.jsdelivr.net/npm/@ip-location-db/geolite2-country/geolite2-country-ipv4.csv
wget -P /usr/share/xt_geoip/tmp/ https://cdn.jsdelivr.net/npm/@ip-location-db/geolite2-country/geolite2-country-ipv6.csv

# Combine all csv and remove duplicates
cd /usr/share/xt_geoip/tmp/
cat *.csv > geoip.csv
sort -u geoip.csv -o /usr/share/xt_geoip/dbip-country-lite.csv

# Remove temp directory and update geoip xtables
rm -r /usr/share/xt_geoip/tmp/
/usr/lib/xtables-addons/xt_geoip_build -D /usr/share/xt_geoip/ -S /usr/share/xt_geoip/
rm /usr/share/xt_geoip/dbip-country-lite.csv

# reload ufw
# ufw reload

Now make the script executable and run the script for the first time to download database

sudo chmod +x /usr/local/bin/update-geoip.sh
/usr/local/bin/update-geoip.sh

Once it’s completed you should see these database sorted by countries and IP type in /usr/share/xt_geoip, you should also setup a cronjob to update this database once a month.

Using GeoIP with UFW for Geo Blocking

Now we need to add custom firewall rules to use the geoip module blocking user from certain countries, first we need to modify this 2 file, the first is for ipv4 and the second is ipv6

  • /etc/ufw/before.rules
  • /etc/ufw/before6.rules

This is an example how to use them, just add the rules into the chain, for example to block known IPs from Russian and Ukraine accessing our web app which is listening on port 3000:

-A ufw-before-input -p tcp --dport 3000 -m geoip --src-cc RU,UA -j DROP

I have mine setup to only start geo blocking at certain hours and also keeping logs:

-A ufw-before-input -p tcp --dport 3000 -m time --timestart 05:00 --timestop 16:00 -m geoip --src-cc RU,UA,A1 -j LOG --log-prefix "[BLOCKED COUNTRIES] "
-A ufw-before-input -p tcp --dport 3000 -m time --timestart 05:00 --timestop 16:00 -m geoip --src-cc RU,UA,A1 -j DROP

The A1 are from maxmind, which is known IPs from anonymizing services such as proxies and VPN.

Want someone to set this up for you?

If your using our managed WordPress hosting we are happy to help you set this up for you!

Leave a Comment