Secure iptables Configuration Guide: Optimizing Firewall Rules for HTTP/HTTPS & SSH Web Servers


3 views

When configuring a production web server, your iptables ruleset should implement these security principles:

# Basic structure for a secure web server
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]

Let's enhance the original rules with modern security practices:

# Loopback and local traffic
-A INPUT -i lo -j ACCEPT
-A INPUT ! -i lo -d 127.0.0.0/8 -j DROP  # More secure than REJECT

# Connection state handling
-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT  # Modern replacement for state module
-A INPUT -m conntrack --ctstate INVALID -j DROP

# Web traffic rules with rate limiting
-A INPUT -p tcp --dport 80 -m connlimit --connlimit-above 50 -j REJECT
-A INPUT -p tcp --dport 443 -m connlimit --connlimit-above 50 -j REJECT

Beyond basic brute force prevention, implement these measures:

# SSH protection with recent module
-A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -m recent --set --name SSH
-A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -m recent --update --seconds 60 --hitcount 3 --name SSH -j DROP
-A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT

# Alternative: Use ipset for more efficient blocking
ipset create SSH_blacklist hash:ip timeout 3600
-A INPUT -p tcp --dport 22 -m set --match-set SSH_blacklist src -j DROP

Modern best practices for ping handling:

# Rate-limited ICMP (ping) responses
-A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/second -j ACCEPT
-A INPUT -p icmp --icmp-type echo-request -j DROP

Effective logging setup:

# Targeted logging for dropped packets
-A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j LOG --log-prefix "SSH attempt: "
-A INPUT -j LOG --log-prefix "Dropped: " --log-level 4
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7

Complete with default policies and IPv6 considerations:

# Default policies
-P INPUT DROP
-P FORWARD DROP
-P OUTPUT ACCEPT

# IPv6 equivalent (ip6tables)
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# ... similar rules for IPv6

To make rules persistent across reboots:

# For Debian/Ubuntu
apt install iptables-persistent
netfilter-persistent save

# For CentOS/RHEL
yum install iptables-services
service iptables save

When securing a Linux webserver, iptables remains the first line of defense. A properly configured ruleset should balance accessibility with security, especially for standard web services. Here's an optimized version of the ruleset with security enhancements:

*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]

# Localhost traffic
-A INPUT -i lo -j ACCEPT
-A INPUT ! -i lo -d 127.0.0.0/8 -j REJECT

# Connection tracking
-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# HTTP/HTTPS with rate limiting
-A INPUT -p tcp --dport 80 -m connlimit --connlimit-above 50 -j REJECT
-A INPUT -p tcp --dport 443 -m connlimit --connlimit-above 50 -j REJECT
-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 443 -j ACCEPT

# SSH protection with modern techniques
-A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -m recent --set
-A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -m recent --update --seconds 60 --hitcount 4 -j DROP
-A INPUT -p tcp --dport 22 -j ACCEPT

# ICMP (ping)
-A INPUT -p icmp --icmp-type 8 -m limit --limit 1/second -j ACCEPT

# Logging and final policies
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables_dropped: "
-A INPUT -j REJECT --reject-with icmp-host-prohibited
COMMIT

The enhanced configuration includes several critical security measures:

  1. Default DROP policy for INPUT and FORWARD chains
  2. Connection rate limiting for web ports (prevents DDoS)
  3. Modern conntrack module instead of deprecated state module
  4. More aggressive SSH brute force protection (60 seconds instead of 180)
  5. ICMP rate limiting to prevent ping floods
  6. Proper ICMP rejection message for blocked packets

For production deployment, consider this bash script template:

#!/bin/bash
# Flush existing rules
iptables -F
iptables -X

# Set default policies
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# Allow localhost
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT ! -i lo -d 127.0.0.0/8 -j REJECT

# Allow established connections
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# Web server rules
iptables -A INPUT -p tcp --dport 80 -m connlimit --connlimit-above 50 -j REJECT
iptables -A INPUT -p tcp --dport 443 -m connlimit --connlimit-above 50 -j REJECT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# SSH protection
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -m recent --set --name SSH
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -m recent --update --seconds 60 --hitcount 4 --name SSH -j DROP
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# ICMP rules
iptables -A INPUT -p icmp --icmp-type 8 -m limit --limit 1/second -j ACCEPT

# Logging
iptables -A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables_dropped: " --log-level 7

# Save rules
iptables-save > /etc/iptables.rules

For long-term server security:

  • Regularly review iptables logs (/var/log/messages or /var/log/syslog)
  • Consider implementing ipset for managing large IP blacklists
  • Update the ruleset when adding new services
  • Combine with TCP wrappers (/etc/hosts.allow and /etc/hosts.deny) for defense in depth