You are not logged in.

#1 2025-11-10 00:45:15

gabriel135
Member
Registered: 2024-03-29
Posts: 4

Migrating from iptables to nftables and firewalld

Hello, I'd like to switch from iptables (and ip6tables, ebtables) to nftables. When I installed archlinux, it was setup with iptables, as is the default. I'd like now to switch to iptables. So the question is what do I have to do for a clean setup. I don't want to preserve any configuration, as I want to leave everything default, that is wide open. Later I will setup firewalld to manage my firewall.

The issue is the following: I never used any kind of firewall on my arch, then I started working with docker which messed everything up - closed all ports and added it's own internal logic modifying the iptables. At first I didn't know it was docker issue (a known issue), and I installed ufw to open the ports I needed (unrelated to docker, I was testing a nodejs app). Of course, ufw didn't fix the issue, because it's unaware of the actual iptables config. Then I found out about docker issue, and the possible fixes. At that point I realized I didn't like ufw, since it doesn't read the iptables config file, it just adds it's own logic. I decided to switch to firewalld and nftables.

Important notes:
- I realize that firewalld can be used with iptables, but I still want a clean switch, since nftables is the future, and I just like it more. Also it's the default for firewalld, so I do want to stick with it.
- I did already remove the iptables, ip6tables, ebtables packages that are conflicting with nftables, and all config from '/etc/iptables'
- I don't want any default config with nft, just everything empty (default arch), and to configure the rules with firewalld
- Please don't reply generic recommendations, as "You don't have to switch, iptables is still supported". If I'm really wrong about switching, because it's not stable or too complicated, then ok
- Please don't start with the "Read the docs and come back" as I already tried everything, and I did read a lot of guides. I just want my system to be back to clean setup
- My last goal is to accomplish a firewall which I can configure via firewalld, or if that is also unacceptable, then pure nft

P.S. Sorry for the long post, I had to add all the details in order to be clear. I know I did wrong by mixing all different apps in, but I didn't know what to do anymore.

System info:

### uname -a

Linux arch 6.17.4-arch2-1 #1 SMP PREEMPT_DYNAMIC Sun, 19 Oct 2025 19:21:18 +0000 x86_64 GNU/Linux


### sudo nft list ruleset

table inet filter {
	chain input {
		type filter hook input priority filter; policy drop;
		ct state invalid drop comment "early drop of invalid connections"
		ct state { established, related } accept comment "allow tracked connections"
		iif "lo" accept comment "allow from loopback"
		ip protocol icmp accept comment "allow icmp"
		meta l4proto ipv6-icmp accept comment "allow icmp v6"
		tcp dport 22 accept comment "allow sshd"
		meta pkttype host limit rate 5/second burst 5 packets counter packets 86 bytes 5444 reject with icmpx admin-prohibited
		counter packets 253 bytes 15180
	}

	chain forward {
		type filter hook forward priority filter; policy drop;
	}
}
table ip filter {
	chain INPUT {
		type filter hook input priority filter; policy accept;
		ip protocol icmp counter packets 0 bytes 0 accept
	}
}
table inet firewalld { # progname firewalld
	flags owner,persist

	chain mangle_PREROUTING {
		type filter hook prerouting priority mangle + 10; policy accept;
		jump mangle_PREROUTING_POLICIES
	}

	chain mangle_PREROUTING_POLICIES {
		iifname "wlp2s0" jump mangle_PRE_policy_allow-host-ipv6
		iifname "wlp2s0" jump mangle_PRE_trusted
		iifname "wlp2s0" return
		jump mangle_PRE_policy_allow-host-ipv6
		jump mangle_PRE_trusted
		return
	}

	chain nat_PREROUTING {
		type nat hook prerouting priority dstnat + 10; policy accept;
		jump nat_PREROUTING_POLICIES
	}

	chain nat_PREROUTING_POLICIES {
		iifname "wlp2s0" jump nat_PRE_policy_allow-host-ipv6
		iifname "wlp2s0" jump nat_PRE_trusted
		iifname "wlp2s0" return
		jump nat_PRE_policy_allow-host-ipv6
		jump nat_PRE_trusted
		return
	}

	chain nat_POSTROUTING {
		type nat hook postrouting priority srcnat + 10; policy accept;
		jump nat_POSTROUTING_POLICIES
	}

	chain nat_POSTROUTING_POLICIES {
		iifname "wlp2s0" oifname "wlp2s0" jump nat_POST_trusted
		iifname "wlp2s0" oifname "wlp2s0" return
		oifname "wlp2s0" jump nat_POST_trusted
		oifname "wlp2s0" return
		iifname "wlp2s0" jump nat_POST_trusted
		iifname "wlp2s0" return
		jump nat_POST_trusted
		return
	}

	chain nat_OUTPUT {
		type nat hook output priority dstnat + 10; policy accept;
		jump nat_OUTPUT_POLICIES
	}

	chain nat_OUTPUT_POLICIES {
		oifname "wlp2s0" jump nat_OUT_trusted
		oifname "wlp2s0" return
		jump nat_OUT_trusted
		return
	}

	chain filter_PREROUTING {
		type filter hook prerouting priority filter + 10; policy accept;
		icmpv6 type { nd-router-advert, nd-neighbor-solicit } accept
		meta nfproto ipv6 fib saddr . mark . iif check missing drop
	}

	chain filter_INPUT {
		type filter hook input priority filter + 10; policy accept;
		ct state { established, related } accept
		ct status dnat accept
		iifname "lo" accept
		ct state invalid drop
		jump filter_INPUT_POLICIES
		reject with icmpx admin-prohibited
	}

	chain filter_FORWARD {
		type filter hook forward priority filter + 10; policy accept;
		ct state { established, related } accept
		ct status dnat accept
		iifname "lo" accept
		ct state invalid drop
		ip6 daddr { ::/96, ::ffff:0.0.0.0/96, 2002::/24, 2002:a00::/24, 2002:7f00::/24, 2002:a9fe::/32, 2002:ac10::/28, 2002:c0a8::/32, 2002:e000::/19 } reject with icmpv6 addr-unreachable
		jump filter_FORWARD_POLICIES
		reject with icmpx admin-prohibited
	}

	chain filter_OUTPUT {
		type filter hook output priority filter + 10; policy accept;
		ct state { established, related } accept
		ct status dnat accept
		oifname "lo" accept
		ip6 daddr { ::/96, ::ffff:0.0.0.0/96, 2002::/24, 2002:a00::/24, 2002:7f00::/24, 2002:a9fe::/32, 2002:ac10::/28, 2002:c0a8::/32, 2002:e000::/19 } reject with icmpv6 addr-unreachable
		jump filter_OUTPUT_POLICIES
	}

	chain filter_INPUT_POLICIES {
		iifname "wlp2s0" jump filter_IN_policy_allow-host-ipv6
		iifname "wlp2s0" jump filter_IN_trusted
		iifname "wlp2s0" accept
		jump filter_IN_policy_allow-host-ipv6
		jump filter_IN_trusted
		accept
	}

	chain filter_FORWARD_POLICIES {
		iifname "wlp2s0" oifname "wlp2s0" jump filter_FWD_trusted
		iifname "wlp2s0" oifname "wlp2s0" accept
		iifname "wlp2s0" jump filter_FWD_trusted
		iifname "wlp2s0" accept
		oifname "wlp2s0" jump filter_FWD_trusted
		oifname "wlp2s0" accept
		jump filter_FWD_trusted
		accept
	}

	chain filter_OUTPUT_POLICIES {
		oifname "wlp2s0" jump filter_OUT_trusted
		oifname "wlp2s0" return
		jump filter_OUT_trusted
		return
	}

	chain filter_IN_trusted {
		jump filter_IN_trusted_pre
		jump filter_IN_trusted_log
		jump filter_IN_trusted_deny
		jump filter_IN_trusted_allow
		jump filter_IN_trusted_post
	}

	chain filter_IN_trusted_pre {
	}

	chain filter_IN_trusted_log {
	}

	chain filter_IN_trusted_deny {
	}

	chain filter_IN_trusted_allow {
	}

	chain filter_IN_trusted_post {
	}

	chain filter_OUT_trusted {
		jump filter_OUT_trusted_pre
		jump filter_OUT_trusted_log
		jump filter_OUT_trusted_deny
		jump filter_OUT_trusted_allow
		jump filter_OUT_trusted_post
	}

	chain filter_OUT_trusted_pre {
	}

	chain filter_OUT_trusted_log {
	}

	chain filter_OUT_trusted_deny {
	}

	chain filter_OUT_trusted_allow {
	}

	chain filter_OUT_trusted_post {
	}

	chain nat_OUT_trusted {
		jump nat_OUT_trusted_pre
		jump nat_OUT_trusted_log
		jump nat_OUT_trusted_deny
		jump nat_OUT_trusted_allow
		jump nat_OUT_trusted_post
	}

	chain nat_OUT_trusted_pre {
	}

	chain nat_OUT_trusted_log {
	}

	chain nat_OUT_trusted_deny {
	}

	chain nat_OUT_trusted_allow {
	}

	chain nat_OUT_trusted_post {
	}

	chain nat_POST_trusted {
		jump nat_POST_trusted_pre
		jump nat_POST_trusted_log
		jump nat_POST_trusted_deny
		jump nat_POST_trusted_allow
		jump nat_POST_trusted_post
	}

	chain nat_POST_trusted_pre {
	}

	chain nat_POST_trusted_log {
	}

	chain nat_POST_trusted_deny {
	}

	chain nat_POST_trusted_allow {
	}

	chain nat_POST_trusted_post {
	}

	chain filter_FWD_trusted {
		jump filter_FWD_trusted_pre
		jump filter_FWD_trusted_log
		jump filter_FWD_trusted_deny
		jump filter_FWD_trusted_allow
		jump filter_FWD_trusted_post
	}

	chain filter_FWD_trusted_pre {
	}

	chain filter_FWD_trusted_log {
	}

	chain filter_FWD_trusted_deny {
	}

	chain filter_FWD_trusted_allow {
		oifname "wlp2s0" accept
	}

	chain filter_FWD_trusted_post {
	}

	chain nat_PRE_trusted {
		jump nat_PRE_trusted_pre
		jump nat_PRE_trusted_log
		jump nat_PRE_trusted_deny
		jump nat_PRE_trusted_allow
		jump nat_PRE_trusted_post
	}

	chain nat_PRE_trusted_pre {
	}

	chain nat_PRE_trusted_log {
	}

	chain nat_PRE_trusted_deny {
	}

	chain nat_PRE_trusted_allow {
	}

	chain nat_PRE_trusted_post {
	}

	chain mangle_PRE_trusted {
		jump mangle_PRE_trusted_pre
		jump mangle_PRE_trusted_log
		jump mangle_PRE_trusted_deny
		jump mangle_PRE_trusted_allow
		jump mangle_PRE_trusted_post
	}

	chain mangle_PRE_trusted_pre {
	}

	chain mangle_PRE_trusted_log {
	}

	chain mangle_PRE_trusted_deny {
	}

	chain mangle_PRE_trusted_allow {
	}

	chain mangle_PRE_trusted_post {
	}

	chain filter_IN_policy_allow-host-ipv6 {
		jump filter_IN_policy_allow-host-ipv6_pre
		jump filter_IN_policy_allow-host-ipv6_log
		jump filter_IN_policy_allow-host-ipv6_deny
		jump filter_IN_policy_allow-host-ipv6_allow
		jump filter_IN_policy_allow-host-ipv6_post
	}

	chain filter_IN_policy_allow-host-ipv6_pre {
	}

	chain filter_IN_policy_allow-host-ipv6_log {
	}

	chain filter_IN_policy_allow-host-ipv6_deny {
	}

	chain filter_IN_policy_allow-host-ipv6_allow {
		icmpv6 type mld-listener-done accept
		icmpv6 type mld-listener-query accept
		icmpv6 type mld-listener-report accept
		icmpv6 type mld2-listener-report accept
		icmpv6 type nd-neighbor-advert icmpv6 code 0 accept
		icmpv6 type nd-neighbor-solicit icmpv6 code 0 accept
		icmpv6 type nd-redirect icmpv6 code 0 accept
		icmpv6 type nd-router-advert icmpv6 code 0 accept
	}

	chain filter_IN_policy_allow-host-ipv6_post {
	}

	chain nat_PRE_policy_allow-host-ipv6 {
		jump nat_PRE_policy_allow-host-ipv6_pre
		jump nat_PRE_policy_allow-host-ipv6_log
		jump nat_PRE_policy_allow-host-ipv6_deny
		jump nat_PRE_policy_allow-host-ipv6_allow
		jump nat_PRE_policy_allow-host-ipv6_post
	}

	chain nat_PRE_policy_allow-host-ipv6_pre {
	}

	chain nat_PRE_policy_allow-host-ipv6_log {
	}

	chain nat_PRE_policy_allow-host-ipv6_deny {
	}

	chain nat_PRE_policy_allow-host-ipv6_allow {
	}

	chain nat_PRE_policy_allow-host-ipv6_post {
	}

	chain mangle_PRE_policy_allow-host-ipv6 {
		jump mangle_PRE_policy_allow-host-ipv6_pre
		jump mangle_PRE_policy_allow-host-ipv6_log
		jump mangle_PRE_policy_allow-host-ipv6_deny
		jump mangle_PRE_policy_allow-host-ipv6_allow
		jump mangle_PRE_policy_allow-host-ipv6_post
	}

	chain mangle_PRE_policy_allow-host-ipv6_pre {
	}

	chain mangle_PRE_policy_allow-host-ipv6_log {
	}

	chain mangle_PRE_policy_allow-host-ipv6_deny {
	}

	chain mangle_PRE_policy_allow-host-ipv6_allow {
	}

	chain mangle_PRE_policy_allow-host-ipv6_post {
	}
}

### sudo firewall-cmd --list-all

trusted (default, active)
  target: ACCEPT
  ingress-priority: 0
  egress-priority: 0
  icmp-block-inversion: no
  interfaces: wlp2s0
  sources: 
  services: 
  ports: 
  protocols: 
  forward: yes
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

If something else can be useful, ask me to provide output.
Thanks

Offline

#2 2025-11-10 03:17:01

dagorret
Member
From: Argentina
Registered: 2017-12-29
Posts: 11

Re: Migrating from iptables to nftables and firewalld

Quick summary

- Stop Docker and UFW.

- Disable nftables.service.

- Flush all rules (nft flush ruleset).

- Enable firewalld (zone trusted).

- Configure Docker (iptables:false or reinstall iptables-nft).

References (Arch Linux)

Nftables: https://wiki.archlinux.org/title/Nftables

Firewalld: https://wiki.archlinux.org/title/Firewalld

Docker (Networking): https://wiki.archlinux.org/title/Docker#Networking

Docker: Disable iptables rules creation: https://wiki.archlinux.org/title/Docker … s_creation

UFW (Uncomplicated Firewall): https://wiki.archlinux.org/title/Uncomplicated_Firewall

Network configuration: https://wiki.archlinux.org/title/Network_configuration

Offline

#3 2025-11-10 14:36:34

gabriel135
Member
Registered: 2024-03-29
Posts: 4

Re: Migrating from iptables to nftables and firewalld

Thank you Dagorret. I followed the steps you provided. I didn't know the nftables.service had to be disabled in order to manage the tables with firewalld. Then I understood this was an issue with nodejs, rather than firewalld. I reinstalled iptables-nft, enabled back docker service and started up a container. It seems that everything works. Then I tried some of my node, vite etc. projects. Turns out that using vite or nuxt (which uses vite) as a dev or preview server is working. But then express nodejs didn't work. I realized it was my fault, I was testing with an express (nodejs) server that was listening on localhost. It never occured to me that localhost is not bound to the external ip address of the machine. So listening to localhost doesn't expose the server to the LAN. After removing the host from

app.listen()

I managed to get it working. So after all it was my fault, not the machine's:)

# .env
SERVER_PORT=3000
SERVER_HOST=localhost
# end .env


# server.js
// app.listen(process.env.SERVER_PORT, process.env.SERVER_HOST, () => {
//         console.log(`Express server created at ${server} serving only ${client}`);
// });
app.listen(process.env.SERVER_PORT, () => {
        console.log(`Express server created at ${server} serving only ${client}`);
});
# end server.js

Thank you for your help, I can finally continue development that was interrupted for 3 horrible days

Offline

#4 2025-11-10 22:10:04

dagorret
Member
From: Argentina
Registered: 2017-12-29
Posts: 11

Re: Migrating from iptables to nftables and firewalld

I have the same problem working with Docker. Sometimes we don't know where the network is pointing. You have to read the Docker Composer documentation carefully. I'm glad it worked for you.

Offline

Board footer

Powered by FluxBB