Linux Iptables Just Block By Country

See all Firewall related FAQ
I admin ecom website and a lot of bogus traffic comes from countries that do not offer much in commercial value. How do I just configure Apache or iptables to just refuse connections to certain countries?

See all Apache Webserver related FAQ
You can block traffic at both Apache or iptables level. I recommend iptables command to save some resources. First, you need to get list of netblocks for each country. Simply visit this page and download IP block files are provided in CIDR format. Use the following shell script:
Tutorial details
Difficulty level Advanced
Root privileges Yes
Requirements Linux terminal
Category Firewall
Prerequisites iptables command
OS compatibility AlmaLinux Alpine Amazon Linux Arch CentOS Debian Fedora Linux Mint Mint openSUSE Pop!_OS RHEL Rocky Slackware Stream SUSE Ubuntu
Est. reading time 2 minutes
Advertisement

Linux Iptables Just Block By Country Shell Script

WARNING! People from other countries may use proxy server or think of spoofing their IP address. In such case, this may not work and it will only protect your box from automated scans or spam.
#!/bin/bash
# Purpose: Block all traffic from AFGHANISTAN (af) and CHINA (CN). Use ISO code. #
# See url for more info - http://www.cyberciti.biz/faq/?p=3402
# Author: nixCraft <www.cyberciti.biz> under GPL v.2.0+
# -------------------------------------------------------------------------------
ISO="af cn" 
 
### Set PATH ###
IPT=/usr/sbin/iptables
WGET=/usr/bin/wget
EGREP='/usr/bin/egrep -E'
 
### No editing below ###
SPAMLIST="countrydrop"
ZONEROOT="/root/iptables"
DLROOT="http://www.ipdeny.com/ipblocks/data/countries"
 
cleanOldRules(){
$IPT -F
$IPT -X
$IPT -t nat -F
$IPT -t nat -X
$IPT -t mangle -F
$IPT -t mangle -X
$IPT -P INPUT ACCEPT
$IPT -P OUTPUT ACCEPT
$IPT -P FORWARD ACCEPT
}
 
# create a dir
[ ! -d $ZONEROOT ] && /bin/mkdir -p $ZONEROOT
 
# clean old rules
cleanOldRules
 
# create a new iptables list
$IPT -N $SPAMLIST
 
for c  in $ISO
do 
	# local zone file
	tDB="$ZONEROOT/$c.zone"
 
	# get fresh zone file
	$WGET -O "$tDB" "$DLROOT/$c.zone"
 
	# country specific log message
	SPAMDROPMSG="$c Country Drop"
 
	# get 
	BADIPS=$($EGREP -v "^#|^$" "$tDB")
	for ipblock in $BADIPS
	do
	   $IPT -A "$SPAMLIST" -s "$ipblock" -j LOG --log-prefix "$SPAMDROPMSG"
	   $IPT -A "$SPAMLIST" -s "$ipblock" -j DROP
	done
done
 
# Drop everything 
$IPT -I INPUT -j "$SPAMLIST"
$IPT -I OUTPUT -j "$SPAMLIST"
$IPT -I FORWARD -j "$SPAMLIST"
 
# call your other iptable script
# /path/to/other/iptables.sh
 
exit 0

Save above script as root user and customize ISO variable to point out country name using ISO country names. Once done install the script as follows using cron job (crontab):
@weekly /path/to/country.block.iptables.sh
To start blocking immediately type:
# /path/to/country.block.iptables.sh
And you are done with blocking the whole country from your server.

Related
Also, check all our complete firewall tutorials for Alpine Linux Awall, CentOS 8, OpenSUSE, RHEL 8, Debian 12/11, Ubuntu Linux version 16.04 LTS/18.04 LTS/20.04 LTS, and 22.04 LTS.

iptables geoip patch

Another, alternative to above shell script is to use geoip iptables patch. This is not standard iptables modules. You need to download patch and compile Linux kernel.

  • Grab geoipt patch from the official website.
  • Download and install Linux kernel and iptables source code.
  • Grab and install tool called patch-o-matic (required for geoip modules).
  • Finally, grab GEO IP database from MaxMind.

The details of kernel compile and iptables patching are beyond the scope of this FAQ. This is left as an exercise to readers.

Further Enhancements (ready to use scripts)

See discussion below in the comments:

🥺 Was this helpful? Please add a comment to show your appreciation or feedback.

nixCrat Tux Pixel Penguin
Hi! 🤠
I'm Vivek Gite, and I write about Linux, macOS, Unix, IT, programming, infosec, and open source. Subscribe to my RSS feed or email newsletter for updates.

181 comments… add one
  • tlhackque Dec 22, 2015 @ 12:19

    Just a reminder that the BlockCountries perl script is maintained on
    https://github.com/tlhackque/BlockCountries and has been for over 2 years.

    The old versions posted here have known issues, including the inability to deal with some
    database format changes made at the registries. (I wish I could delete the code posted here.)

    The current version supports IPv6 and has no known issues. It’s also better documented.

    Also, I don’t look for issues or post release announcements here. Report issues at
    https://github.com/tlhackque/BlockCountries/issues Watch the repository for release
    announcements.

    I encourage everyone visiting this site who is interested in BlockCountries to switch to github.
    That’s where you’ll get prompt support and current releases.

    Note that I appreciate this (cybersiti.biz) blog’s contribution to IP address blocking. The shell
    scripts produced by Vivek and Dave inspired creation of the Perl script. The blog provided
    valuable feedback, and allowed initial distribution.

    However, a blog is not a good vehicle for software distribution, maintenance or issue tracking.
    That’s why I moved to github.

  • Dumb_Dumber Mar 14, 2016 @ 1:01

    just reinstalled debian 7 did the update and the whole shabang so i would say its ok to setup the script from github ?

    but i get this ??
    Carp v1.20 *OUTDATED Must upgrade to v1.3301 or higher
    File::Temp v0.22 *OUTDATED Must upgrade to v0.2304 or higher
    IO::Compress::Zip v2.033 *OUTDATED Must upgrade to v2.069 or higher
    IO::Uncompress::Gunzip v2.033 *OUTDATED Must upgrade to v2.064 or higher
    LWP::Simple *NOT INSTALLED Must install v6.00 or higher
    Locale::Country v3.16 *OUTDATED Must upgrade to v3.37 or higher
    Net::Domain v2.20 *OUTDATED Must upgrade to v2.23 or higher
    NetAddr::IP *NOT INSTALLED Must install v4.044 or higher
    Regexp::IPv6 *NOT INSTALLED Must install v0.03 or higher
    Socket v1.94 *OUTDATED Must upgrade to v2.006 or higher
    Storable v2.27 *OUTDATED Must upgrade to v2.30 or higher
    Sys::Syslog v0.27 *OUTDATED Must upgrade to v0.29 or higher

    i must say the install could have some extra’s like a automated install that also fixes the missing or upgrades
    i love this script and always used the original script above that worked perfect for me but now i want to try the github script

    how can i fix these errors ?

  • Richard Homes Jul 31, 2016 @ 5:26

    Really useful! Can I block this IP’s from Squid ?

  • john Mar 28, 2017 @ 19:27

    that was good script – blocking by countries is good thing.
    block by ports not always be as close as good, because, i every day see many and many attempts to log in to administration account in my CMS , and i have had my wordpress site hacked some months ago ( i thing via some query injection or so, as so – 80 port also is unsafe).

  • T Apr 16, 2017 @ 19:22

    this is awesome. saved me some time.

  • SitiSchu May 15, 2017 @ 21:12

    Thanks. Needed a script after I saw 200k+ attempts of chinese ip’s trying to ssh into my server

  • N. May 19, 2024 @ 0:27

    Still working in 2024, though I need to remove the lines with spamdropmsg just to make the process faster. Thank you.

Leave a Reply

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

Use HTML <pre>...</pre> for code samples. Your comment will appear only after approval by the site admin.