Latest / Linux Server Admin with Fexingo: Sysadmin, Bash, and Server Engineering / How to Use Linux Server Iptables for Advanced Packet Filtering
Transcript
- Lucas: So we get this question a lot: with nftables now the default on RHEL 9 and Ubuntu 22.04, is iptables still worth learning? Luna: And I think the honest answer is yes — because millions of servers still run iptables, and plenty of migration scripts still generate iptables rules under the hood. Lucas: Exactly. The iptables command is a userspace utility that talks to the Netfilter kernel module. It's been around since kernel 2.4, and it's not going away overnight. RHEL 8 shipped with both, and even on systems that default to nftables, there's often an iptables-legacy package for compatibility. Luna: I've seen that trip up newer sysadmins — they install nftables and assume iptables rules stop working. But if you've got both frameworks running, they can conflict. Lucas: Right. You don't want two firewalls fighting each other. So rule one: check what's running. On Red Hat derivatives, 'alternatives --list iptables' tells you whether you're pointing to iptables-legacy or iptables-nft. On Ubuntu, 'iptables --version' usually shows 'nf_tables' if it's the nftables-backed version. Luna: So the same command can behave differently. That's exactly the kind of detail that matters when you're debugging at 2 AM. Lucas: Yeah. So today let's focus on iptables-legacy — the classic version — because if you're maintaining older systems, that's what you'll see. And the concepts carry forward anyway. The core unit is a rule, and rules live in chains. There are five built-in chains: PREROUTING, INPUT, FORWARD, OUTPUT, and POSTROUTING. Luna: And those map to the order packets hit them. PREROUTING is for packets coming in before any routing decision, INPUT is for packets destined for the local machine, FORWARD for routed traffic, OUTPUT for locally generated packets, and POSTROUTING for packets leaving. Lucas: Right. Each chain has a default policy — usually ACCEPT or DROP — and you insert rules with criteria like source IP, destination port, protocol, and an action like ACCEPT, DROP, or LOG. Let me show you a practical example. Say you want to allow SSH from a management subnet only. Luna: So you'd use the INPUT chain, match on TCP port 22, and the source IP range. Lucas: Exactly. The rule looks like: iptables -A INPUT -p tcp --dport 22 -s 10.0.0.0/24 -j ACCEPT. The -A appends to the chain, -p tcp specifies protocol, --dport 22 is destination port, -s is source, and -j is the target, ACCEPT. You also want a rule to drop everything else on SSH, and set a policy of DROP on INPUT. Luna: Though you've gotta be careful — if you set the default policy to DROP before adding the SSH rule, you lock yourself out. Always add the allow rule first. Lucas: That's a classic gotcha. I usually write the script with the allow rules first, then change the policy. And you can also use -I to insert at a specific position. But the bigger point is stateful filtering. Iptables can track connection state with the conntrack module. So instead of opening port 80 to everyone, you can accept only packets that are part of established connections. Luna: Right, like this: iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT. That lets return traffic in without poking holes. Lucas: That one rule makes your firewall much more secure. Then you add specific rules for new connections on the ports you want open. For a web server: iptables -A INPUT -p tcp --dport 80 -m state --state NEW -j ACCEPT, and same for 443. Everything else that's new gets dropped. Luna: And logging. When you're figuring out why something isn't working, logging dropped packets is a lifesaver. Lucas: Yeah. You can add a rule like: iptables -A INPUT -j LOG --log-prefix 'iptables drop: ' --log-level 4. That sends entries to syslog — usually /var/log/messages or /var/log/syslog. But be careful: under heavy traffic, logging every packet can fill your disk fast. I usually log only certain dropped packets, like on port 22, to catch brute force attempts. Luna: Speaking of brute force, you can rate-limit connections with the recent match. Something like: iptables -A INPUT -p tcp --dport 22 -m recent --name SSH --set, then after four connections in 60 seconds, drop for 10 minutes. Lucas: That's a solid lightweight protection without needing fail2ban. The recent module keeps track of source IPs. So you'd have two rules: one that adds the IP to a list, and another that checks the hit count. It's all in the iptables-extensions man page. Luna: And if today's conversation gave you something usable, maybe it's worth the price of a coffee. That link is buy me a coffee dot com slash fexingo. Helps keep the show ad-free and focused on real sysadmin stuff. Lucas: Yeah, we appreciate it. So where we left off — rate limiting with the recent module. That's just one example of how iptables can do advanced filtering without extra software. You can also match on MAC addresses, interfaces, or even time of day. Luna: The time match is great for blocking non-business hours access to sensitive servers. iptables -A INPUT -m time --timestart 09:00 --timestop 17:00 --weekdays Mon,Tue,Wed,Thu,Fri -j ACCEPT, then drop everything else. Lucas: Exactly. And you can combine matches. For example, allow SSH only from management IPs AND only during work hours. That's two matches in one rule. The thing to remember is that iptables evaluates rules in order — first match wins. So if you have a broad DROP rule before your allow rules, everything gets dropped. Luna: Right. That's why I always put my accept rules before the default drop. And I try to keep the rule count low — under a hundred — because performance degrades if you have thousands of rules. Lucas: Yeah, iptables uses a linear search, so more rules means more CPU per packet. If you need a lot of rules, consider using ipset for IP sets. It's a hash-based lookup that's much faster. You create an ipset, then use -m set in iptables to match against it. Luna: Ipset is great for blocking large lists of IPs, like from threat feeds. You can update the set without reloading all your rules. Lucas: And speaking of savings, iptables-save and iptables-restore are your friends. 'iptables-save > /etc/iptables/rules.v4' dumps all rules in a compact format. Then you can restore with 'iptables-restore < /etc/iptables/rules.v4'. That's much faster than running dozens of iptables commands at boot. Luna: And on Red Hat systems, you can enable the iptables service, but I prefer a systemd oneshot unit that runs iptables-restore. That way you have control and logging. Lucas: Exactly. Let's put it all together with a minimal script for a web server. First, flush existing rules: iptables -F. Set default policies to DROP on INPUT and FORWARD, ACCEPT on OUTPUT. Then allow loopback: iptables -A INPUT -i lo -j ACCEPT. Then allow established: iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT. Then open ports: SSH, HTTP, HTTPS. Finally, log and drop everything else. Luna: And don't forget to save. Otherwise it's gone on reboot. Lucas: Right. So that's the core. But what about when you need to migrate to nftables? It's not as scary as it seems. Nftables uses a different syntax, but the concepts are the same: chains, rules, matches, verdicts. There's even an iptables-translate tool that shows the nftables equivalent of any iptables command. Luna: I've used it. 'iptables-translate -A INPUT -p tcp --dport 22 -j ACCEPT' gives you the nft add rule equivalent. It's a handy bridge. Lucas: Yeah. And if you're on a system that uses iptables-nft, the iptables commands still work, but they're translated to nftables rules under the hood. So you can keep using your old scripts while gradually learning the new syntax. Luna: That's a practical path. But eventually, you'll want to switch to native nftables for performance and consistency. Lucas: True. But today, if you're supporting legacy servers or just want a deep understanding of Linux packet filtering, iptables is still the foundation. Once you grasp chains, matches, and targets, nftables is just a different dialect. Luna: And honestly, a lot of the troubleshooting skills — like checking packet counts per rule with 'iptables -L -v -n' — are the same whether you're using legacy or nft. Lucas: Exactly. Those verbose counters tell you exactly how many packets hit each rule. If your SSH allow rule shows zero packets, either the rule is wrong or traffic is hitting a drop rule before it. That's your first debugging step. Luna: And you can zero counters with 'iptables -Z' to start fresh after making changes. Lucas: Right. So to wrap it up: iptables is still very much alive. Learn it, use it wisely, and when you're ready, nftables will feel natural. Luna: And if your shop is still on iptables, you're in good company. It's battle-tested. Lucas: Absolutely. Next time we could dive into nftables syntax and do a side-by-side comparison. But for now, keep your rules tight and your logs flowing.