A tiny command‑line tool to keep a persistent IP blocklist in a SQLite database and to generate a ready‑to‑use nftables set file. It is deliberately minimal: one Python script, no external services, and everything is stored locally.
Typical workflow:
- Add single or many IP addresses (optionally with metadata).
- Remove single or many IP addresses.
- Export the whole list to a nftables‑compatible file (
20‑blocklist‑ipv4.nft).
That file can be dropped into /etc/nftables.d/ and automatically included by the global nftables configuration.
git clone https://github.com/viczem/nftables-ipset.git
cd nftables-ipset
uv run nftables-ipset| Variable | Default | Example |
|---|---|---|
DIR |
directory where the script resides | export DIR=/var/lib/nftables-ipset |
- The directory must be writable by the user that runs the script (or by the systemd service, if you use it).
- The database file is always named
nftables-ipset.db.
/etc/nftables.d/
├── 10-blocklist.nft # static table / chain definition (never overwritten)
├── 20-blocklist-ipv4.nft # generated by `nftables-ipset --export`
└── 20-blocklist-ipv6.nft
10‑blocklist.nft (provided with the README, copy it to the host)
table inet blocklists {
set blocklist_ipv4 {
type ipv4_addr
flags interval
}
set blocklist_ipv6 {
type ipv6_addr
flags interval
}
chain earlydrop {
type filter hook prerouting priority -300;
policy accept;
ip saddr @blocklist_ipv4 drop
ip6 saddr @blocklist_ipv6 drop
}
}
20‑blocklist‑ipv4.nft (generated)
add element inet blocklists blocklist_ipv4 {
1.1.1.1,
2.2.2.2,
…
}
20‑blocklist‑ipv4.nft (generated)
add element inet blocklists blocklist_ipv6 {
2001:db8::/32,
2606:4700:4700::1111,
…
}
/etc/nftables.conf (the master file, also provided by most distros)
#!/usr/sbin/nft -f
flush ruleset
#...
include "/etc/nftables.d/*.nft"The include line automatically picks up both 10‑blocklist.nft and 20‑blocklist‑ipv4.nft (20‑blocklist‑ipv6.nft).
When you run nftables-ipset --export, the generated file is overwritten in place, so the next nft -f /etc/nftables.conf reload picks up the new list.
uv run nftables-ipset -husage: nftables-ipset [-h] [-a IP | -A | -r IP | -R] [-c COMMENT] [-e]
Manage an IP blocklist (IPv4 & IPv6) stored in a SQLite database. The DB location can be overridden with the DIR environment variable.
options:
-h, --help show this help message and exit
-a, --add IP Add a single IP address or network.
-A, --batch-add Add many IPs/networks from stdin.
-r, --remove IP Remove a single IP address (hosts only).
-R, --batch-remove Remove many IPs from stdin.
-c, --comment COMMENT
Comment stored for every added host IP.
-e, --export Export blocklists to nftables files.
uv run nftables-ipset --add 203.0.113.45
# with comments (e.g., source of the block)
uv run nftables-ipset --add 203.0.113.45 --comment "spam‑source:spamhaus"# From a file
cat bad_ips.txt | uv run nftables-ipset --batch-add
# From another command
curl -s https://example.com/blocked.txt | uv run nftables-ipset --batch-addBatch mode reads one IP per line. An empty line or Ctrl‑D ends the input.
If the input file contains comments (anything after a #), they are stripped automatically.
If you want the same comments for every line, pass -c "your‑note"; it overrides per‑line comments.
uv run nftables-ipset --remove 203.0.113.45cat to_remove.txt | uv run nftables-ipset --batch-removeuv run nftables-ipset --exportThe command:
- Reads all rows from the database.
- Writes them into
20-blocklist-ipv4.nft(or/and20-blocklist-ipv6.nft) in the same directory as the script (orDIRif set).
After export copy the file to /etc/nftables.d/20-blocklist-ipv4.nft (requires root permissions) and reload nftables:
sudo nft -f /etc/nftables.conf
# or, if you have a systemd service:
sudo systemctl reload nftables