Block China IP by Iptables

Servers: Debian9

Install ipset

apt-get install ipset

Next, I wrote a small Bash script to do all the work, which you should be able to understand from the comments in it. Create a file:

nano /etc/

Here’s what you want to paste into it:

# Create the ipset list
ipset -N china hash:net

# remove any old list that might exist from previous runs of this script
rm -rf /root/

# Pull the latest IP set for China
wget -P /root

# Add each IP address from the downloaded list into the ipset 'china'
for i in $(cat /root/ ); do ipset -A china $i; done

# Restore iptables
/sbin/iptables-restore < /etc/iptables/rules.v4

Save the file. Make it executable:

chmod +x /etc/

This hasn’t done anything yet, but it will in a minute when we run the script. First, we need to add a rule into iptables that refers to this new ipset list the script above defines:

nano /etc/iptables/rules.v4

Add the following line:

-A INPUT -p tcp -m set --match-set china src -j DROP

Save the file. To be clear, my full iptables.firewall.rules now looks like this:


#  Allow all loopback (lo0) traffic and drop all traffic to 127/8 that doesn't use lo0
-A INPUT -i lo -j ACCEPT

#  Accept all established inbound connections

# Block anything from China
# These rules are pulled from ipset's china list
# The source file is at /root/ (which in turn is generated by a shell script at /root/ )
-A INPUT -p tcp -m set --match-set china src -j DROP
-A INPUT -p udp -m set --match-set china src -j DROP

#  Allow all outbound traffic - you can modify this to only allow certain traffic

#  Allow HTTP and HTTPS connections from anywhere (the normal ports for websites and SSL).
-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 443 -j ACCEPT

#  Allow SSH connections
#  The -dport number should be the same port number you set in sshd_config
-A INPUT -p tcp -m state --state NEW --dport 22 -j ACCEPT

#  Allow ping
-A INPUT -p icmp -j ACCEPT

#  Log iptables denied calls
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7

#  Drop all other inbound - default deny unless explicitly allowed policy


Right now, nothing has changed with the server because no new rules have been applied; to do so, run the script:


This should show some output as it pulls a fresh list of Chinese based IPs and then, after a few seconds or so, it will complete and drop you back to a command prompt.

To test if it worked, run:

iptables -L

You should now see a new rule blocking China – the output ought to look like this:

Chain INPUT (policy ACCEPT)
target     prot opt source               destination
ACCEPT     all  --  anywhere             anywhere
REJECT     all  --  anywhere             loopback/8           reject-with icmp-port-unreachable
ACCEPT     all  --  anywhere             anywhere             state RELATED,ESTABLISHED
DROP       tcp  --  anywhere             anywhere             match-set china src
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:http
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:https
ACCEPT     tcp  --  anywhere             anywhere             state NEW tcp dpt:ssh
ACCEPT     icmp --  anywhere             anywhere
LOG        all  --  anywhere             anywhere             limit: avg 5/min burst 5 LOG level debug prefix "iptables denied: "
DROP       all  --  anywhere             anywhere

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination
DROP       all  --  anywhere             anywhere

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
ACCEPT     all  --  anywhere             anywhere

Almost done! This works, and will continue to work on re-boots. But, IP addresses change and that list will grow stale over time. If you want to pull and apply an updated list of IPs you can just run the script again.

We can also set the machine to do that automatically via a cron job:

crontab -e

Add a line such as this:

* 5 * * * /root/

This will run /etc/ at 5am every day. The user running the script will need to be root or have root privileges.

Alternative (Free user can generate once per day)

Photo by wu yi on Unsplash