To prevent my server IP from being blocked by the GFW (Great Firewall), I wanted to ensure that my server is only accessible from outside mainland China. The most effective way to achieve this is by adding firewall rules to block all inbound traffic from Chinese IP addresses.
While iptables with xt_geoip has been a popular choice for years, nftables is the modern replacement in the Linux ecosystem. However, nftables lacks built-in support for GeoIP or MMDB (MaxMind Database) lookups out of the box. To bridge this gap, we need a way to generate nftables-compatible IP sets from a GeoIP database.
In this post, I’ll share a tool I built to automate this process: Auto Update MMDB. It automatically fetches the latest GeoLite2 data, extracts Chinese network ranges, and generates the necessary nftables configuration files.
The Solution: Auto Update MMDB
I created a simple Go utility called auto-update-mmdb. It performs the following tasks:
- Downloads the latest
GeoLite2-Country.mmdb. - Parses the database to find all IPv4 and IPv6 ranges associated with China (CN).
- Generates
nftablesset files (cn4.nftandcn6.nft). - Reloads
nftablesto apply the changes.
You can find the source code on GitHub: missuo/auto-update-mmdb.
Installation and Setup
First, we need to install the tool. You can build it from source using Go:
git clone https://github.com/missuo/auto-update-mmdb.git
cd auto-update-mmdb
go build -o /usr/local/bin/auto-update-mmdb
Once installed, you can run it manually to generate the initial IP sets:
sudo /usr/local/bin/auto-update-mmdb
This will create the following files:
/usr/share/GeoIP/GeoLite2-Country.mmdb/etc/nftables.d/cn4.nft/etc/nftables.d/cn6.nft
Automating Updates
IP addresses change over time, so it’s important to keep the database updated. We can use a systemd timer to run the update daily.
Create a service file /etc/systemd/system/auto-update-mmdb.service:
[Unit]
Description=Auto Update GeoLite2 MMDB
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/auto-update-mmdb
And a timer file /etc/systemd/system/auto-update-mmdb.timer:
[Unit]
Description=Auto Update GeoLite2 MMDB Daily
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target
Enable and start the timer:
sudo systemctl daemon-reload
sudo systemctl enable --now auto-update-mmdb.timer
Configuring nftables
Now that we have the IP sets ready, we can use them in our nftables configuration.
Edit your /etc/nftables.conf. You need to include the generated files and then reference the sets (@cn4 and @cn6) in your rules.
Here is a complete example that blocks traffic from China on a specific port (e.g., 2333), while allowing other traffic:
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
# Import the generated IP sets
include "/etc/nftables.d/cn4.nft"
include "/etc/nftables.d/cn6.nft"
chain input {
type filter hook input priority 0;
# Allow loopback and established connections
iifname "lo" accept
ct state established,related accept
# Block SSH (port 22) from China
tcp dport 22 ip saddr @cn4 drop
tcp dport 22 ip6 saddr @cn6 drop
# Block China IPs on port 2333 (TCP & UDP)
tcp dport 2333 ip saddr @cn4 drop
udp dport 2333 ip saddr @cn4 drop
tcp dport 2333 ip6 saddr @cn6 drop
udp dport 2333 ip6 saddr @cn6 drop
# Allow everything else by default
accept
}
}
Blocking All Traffic
If you want to block all inbound traffic from China, you can simplify the rules:
# Drop all traffic from China
ip saddr @cn4 drop
ip6 saddr @cn6 drop
After modifying the configuration, restart nftables to apply the rules:
sudo systemctl restart nftables
Conclusion
By combining nftables with a simple automation tool, we can effectively manage geolocation-based firewall rules without relying on legacy tools or complex dependencies. This setup ensures your server remains inaccessible from specific regions while keeping the IP database up-to-date automatically.