When working with iptables on CentOS/RHEL systems, many administrators encounter a frustrating scenario: they add a new rule to open a port, but the connection still gets blocked. The root cause lies in the rule ordering where new rules get appended after the default REJECT policy.
# Common mistake:
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
service iptables save
CentOS 6.x systems typically include a final REJECT rule in their default configuration:
*filter
:INPUT ACCEPT [0:0]
# ... other chains ...
-A INPUT -j REJECT --reject-with icmp-host-prohibited
COMMIT
This acts as an implicit "deny all" security measure, but causes problems when rules are added via -A
(append).
Method 1: Using INSERT Instead of APPEND
# Insert rule at specific position (before REJECT)
iptables -I INPUT 5 -p tcp --dport 80 -j ACCEPT
# Verify position
iptables -L INPUT --line-numbers
Method 2: Editing the Config File Directly
# /etc/sysconfig/iptables
-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
Method 3: Using a Custom Chain
# Create custom chain
iptables -N CUSTOM_RULES
iptables -A INPUT -j CUSTOM_RULES
iptables -A INPUT -j REJECT
# Add rules to custom chain
iptables -A CUSTOM_RULES -p tcp --dport 80 -j ACCEPT
- Always check rule order with
iptables -L --line-numbers
- Consider using
-I
(insert) instead of-A
(append) in scripts - For complex setups, implement chain organization early
- Test changes with
iptables-restore -t
before applying
For repeatable deployments, consider this bash function:
function safe_iptables_rule() {
local port=$1
local protocol=${2:-tcp}
local position=$(iptables -L INPUT --line-numbers |
grep "REJECT" | awk '{print $1-1}')
iptables -I INPUT $position -p $protocol --dport $port -j ACCEPT
}
# Usage:
safe_iptables_rule 80
When working with iptables on CentOS 6.4, many administrators encounter a common pitfall when trying to open new ports. The issue occurs because new rules added via iptables -A
get appended after the default REJECT policy, making them effectively useless.
Here's what a typical default iptables configuration looks like on CentOS 6.4:
*filter :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [88:9264] -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT -A INPUT -p icmp -j ACCEPT -A INPUT -i lo -j ACCEPT -A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT -A INPUT -j REJECT --reject-with icmp-host-prohibited COMMIT
When you execute:
/sbin/iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT service iptables save service iptables restart
The rule gets added AFTER the REJECT policy, resulting in this ineffective configuration:
-A INPUT -j REJECT --reject-with icmp-host-prohibited -A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
Method 1: Using INSERT instead of APPEND
The correct command should use -I
(insert) instead of -A
(append):
/sbin/iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
Method 2: Specifying Rule Position
You can specify exactly where to insert the rule by providing a rule number:
/sbin/iptables -I INPUT 5 -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
Method 3: Editing the Config File Directly
Alternatively, you can edit /etc/sysconfig/iptables
directly and place your rule before the REJECT line:
vim /etc/sysconfig/iptables # Add your rule manually before the REJECT line service iptables restart
Always check your rule order after making changes:
iptables -L -n --line-numbers
This will show you the rule numbers and their order in the chain.
- Always use
-I
when adding new ACCEPT rules to the INPUT chain - Consider numbering your rules explicitly for better control
- Document your iptables changes in a version-controlled file
- Test connectivity after every change
Here's how to properly open both HTTP and HTTPS ports:
iptables -I INPUT -p tcp --dport 80 -j ACCEPT iptables -I INPUT -p tcp --dport 443 -j ACCEPT service iptables save service iptables restart