Persistence and Migration from ufw to iptables-persistent
Hello, I'm incompetent.
Until now, I had been using ufw, which allows for easy FW configuration, but I wanted to manage it at the config level, like pf.conf, to make migration easier, so I installed iptables-persistent.
Apparently, there's a kernel patch that enables pf, but forcing myself to use it that much isn't right, and it would also mean avoiding iptables, so I decided to adopt it.
Installation
iptables should already be mostly installed, so I will only install iptables-persistent.
By the way, ufw will be automatically removed because of conflicts, so make sure to check your existing rules beforehand.
sudo apt install iptables-persistent
Minimum Usage of netfilter-persistent
To save current rules under /etc/iptables/
sudo netfilter-persistent save
To reload using the current settings in /etc/iptables/
sudo netfilter-persistent reload
By the way, if you save without having reloaded, it will treat the current rules as the ones to save, and the settings you've written will be blown away, so be careful.
Configuration
This is what the configuration looks like.
It's quite tough that iptables blows away all comments and line breaks when you save...
# cat rules.v4
# Generated by iptables-save v1.8.9 (nf_tables) on Sat Oct 11 16:27:52 2025
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [18:1900]
:TCP - [0:0]
:UDP - [0:0]
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -i 127.0.0.1/32 -j ACCEPT
-A INPUT -s 192.168.1.0/24 -j ACCEPT
-A INPUT -i wg0 -j ACCEPT
-A INPUT -m conntrack --ctstate INVALID -j DROP
-A INPUT -p icmp -m icmp --icmp-type 8 -m conntrack --ctstate NEW -j ACCEPT
-A INPUT -p udp -m conntrack --ctstate NEW -j UDP
-A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j TCP
-A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
-A INPUT -p tcp -j REJECT --reject-with tcp-reset
-A INPUT -j REJECT --reject-with icmp-proto-unreachable
COMMIT
# Completed on Sat Oct 11 16:27:52 2025
Regarding the allow rules, they basically permit traffic for local connections and each WireGuard interface.
I basically copied them from Arch Wiki.
Simple Stateful Firewall - ArchWiki
The reason is that if you don't add-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT, for example, the response from a curl command won't be able to return, so it seems necessary to explicitly assign established connections to a separate rule. I realized anew that pf's power comes from its excellent handling of this kind of state management, and it made me want to pat pf-chan on the head again.
See you next time.
By the way, no IPv6.
# cat rules.v6
# Generated by ip6tables-save v1.8.9 (nf_tables) on Sat Oct 11 17:37:50 2025
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
COMMIT
# Completed on Sat Oct 11 17:37:50 2025
Best regards.