How to Configure iptables Firewall Rules on RHEL 7
RHEL 7 ships with firewalld as the default firewall management layer, but many system administrators prefer to work directly with iptables, the underlying Linux netfilter framework. iptables provides precise, stateful packet filtering through a chain-based rule system and is the right choice when you need fine-grained control, scripted rule sets, or compatibility with legacy tooling. This guide covers everything you need to configure iptables on RHEL 7: understanding chains, writing rules, persisting them across reboots, replacing firewalld, and using stateful connection tracking for efficient, secure filtering.
Prerequisites
- RHEL 7 system with root access
- Basic understanding of TCP/IP networking (ports, protocols, IP addresses)
- Existing SSH session — be careful not to lock yourself out when modifying firewall rules
Step 1: Disable firewalld and Enable iptables Services
Before using iptables directly, stop and disable firewalld to prevent conflicts. Then enable the iptables and ip6tables services that manage persistent rule loading:
systemctl stop firewalld
systemctl disable firewalld
systemctl mask firewalld
yum install iptables-services -y
systemctl enable iptables
systemctl enable ip6tables
systemctl start iptables
systemctl start ip6tables
Masking firewalld prevents other services from accidentally re-enabling it as a dependency.
Step 2: View the Current Ruleset
Display the active iptables rules with line numbers and packet/byte counters:
iptables -L -n -v --line-numbers
The default output shows three built-in chains:
- INPUT — packets destined for the local system
- FORWARD — packets routed through the system (relevant for gateways)
- OUTPUT — packets originating from the local system
Each chain has a default policy: ACCEPT or DROP. After a fresh install, all chains default to ACCEPT, meaning all traffic is allowed until you add restrictive rules.
Step 3: Understanding Rule Syntax
The general structure of an iptables rule is:
iptables -A CHAIN -p PROTOCOL --dport PORT -j TARGET
-Aappends the rule to the end of the chain;-Iinserts at a specific position (default: top);-Ddeletes a rule-p tcpor-p udpspecifies the protocol--dportspecifies the destination port-j ACCEPTallows the packet;-j DROPsilently discards it;-j REJECTdiscards and sends an error reply to the sender-smatches source IP;-dmatches destination IP-imatches incoming interface;-omatches outgoing interface
Step 4: Build a Practical Ruleset
The following sequence creates a solid baseline ruleset for a server. Execute these commands in order:
# Flush all existing rules
iptables -F
iptables -X
# Set default policies: drop all inbound and forwarded traffic
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
# Allow loopback interface (required for many local services)
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
# Allow established and related connections (stateful tracking)
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
# Allow ICMP (ping) — useful for diagnostics
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
# Allow SSH (port 22) from any source
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# Allow HTTP and HTTPS
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
# Allow DNS responses (UDP port 53) for outbound queries
iptables -A INPUT -p udp --sport 53 -j ACCEPT
Step 5: Using Stateful Connection Tracking
The -m state --state RELATED,ESTABLISHED rule is the cornerstone of a stateful firewall. Instead of writing separate rules for every return packet, this single rule allows all traffic that belongs to connections already permitted by earlier rules. The supported states are:
NEW— the first packet of a new connectionESTABLISHED— packets belonging to an ongoing connectionRELATED— packets related to an existing connection (e.g., FTP data channel, ICMP errors)INVALID— packets that do not match any known connection; these should be dropped
Drop invalid packets explicitly to prevent certain network scans and malformed packet attacks:
iptables -A INPUT -m state --state INVALID -j DROP
This rule should appear before the RELATED,ESTABLISHED rule in a production setup. To insert it at position 1:
iptables -I INPUT 1 -m state --state INVALID -j DROP
Step 6: Restrict SSH to a Specific Source Network
Limiting SSH access to a known management network drastically reduces brute-force exposure:
# Remove the unrestricted SSH rule
iptables -D INPUT -p tcp --dport 22 -j ACCEPT
# Add a restricted SSH rule allowing only 10.0.0.0/8
iptables -A INPUT -p tcp -s 10.0.0.0/8 --dport 22 -j ACCEPT
Step 7: Insert and Delete Rules by Line Number
To view rules with line numbers:
iptables -L INPUT -n --line-numbers
To insert a rule at line 3 (pushing existing rules down):
iptables -I INPUT 3 -p tcp --dport 8080 -j ACCEPT
To delete the rule currently at line 5:
iptables -D INPUT 5
Step 8: Save and Restore Rules
iptables rules are held in memory and lost on reboot unless saved. Save the current ruleset to the file that iptables-services reads at boot:
iptables-save > /etc/sysconfig/iptables
Verify the file content:
cat /etc/sysconfig/iptables
To restore rules from the file at any time (e.g., after testing temporary changes):
iptables-restore < /etc/sysconfig/iptables
With iptables-services enabled, the saved ruleset is automatically loaded when the system boots via systemctl start iptables.
Step 9: Log Dropped Packets for Troubleshooting
Add a logging rule just before the final DROP policy to capture dropped packets in /var/log/messages:
iptables -A INPUT -j LOG --log-prefix "iptables-dropped: " --log-level 4
Monitor the log in real time:
tail -f /var/log/messages | grep iptables-dropped
Remove the logging rule in high-traffic environments once troubleshooting is complete, as it can generate significant log volume.
Conclusion
iptables remains one of the most powerful and flexible packet filtering tools available on Linux. By replacing firewalld with the iptables-services package on RHEL 7, you gain direct access to netfilter’s chain-based rule system with predictable, scriptable behavior. The combination of a DROP-by-default INPUT policy, stateful connection tracking with -m state, and targeted ACCEPT rules for only the services you run provides a robust security boundary. Always test new rules in a safe environment or with a parallel SSH session open, save your working ruleset with iptables-save, and keep the ruleset commented and version-controlled so that future administrators understand the intent behind every rule.