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
  • -A appends the rule to the end of the chain; -I inserts at a specific position (default: top); -D deletes a rule
  • -p tcp or -p udp specifies the protocol
  • --dport specifies the destination port
  • -j ACCEPT allows the packet; -j DROP silently discards it; -j REJECT discards and sends an error reply to the sender
  • -s matches source IP; -d matches destination IP
  • -i matches incoming interface; -o matches 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 connection
  • ESTABLISHED — packets belonging to an ongoing connection
  • RELATED — 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.