When securing a Linux server, implementing IP whitelisting through iptables is one of the most effective ways to control network access. The basic principle is simple: explicitly allow connections from/to specific IP ranges while dropping everything else by default.
If you're starting fresh or want to clear existing rules, begin with:
iptables -F iptables -X iptables -t nat -F iptables -t nat -X iptables -t mangle -F iptables -t mangle -X
The foundation of whitelisting is setting DROP policies:
iptables -P INPUT DROP iptables -P OUTPUT DROP iptables -P FORWARD DROP
Always permit local traffic:
iptables -A INPUT -i lo -j ACCEPT iptables -A OUTPUT -o lo -j ACCEPT
For inbound connections (users connecting to your server):
# Allow single IP iptables -A INPUT -p tcp -s 192.168.1.100 --dport 22 -j ACCEPT # Allow IP range (CIDR notation) iptables -A INPUT -p tcp -s 203.0.113.0/24 --dport 80 -j ACCEPT # Allow multiple services from specific IP iptables -A INPUT -p tcp -s 198.51.100.55 -m multiport --dports 22,80,443 -j ACCEPT
For outbound connections (server connecting to other services):
# Allow server to connect to specific IPs iptables -A OUTPUT -p tcp -d 93.184.216.34 --dport 443 -j ACCEPT # Allow DNS resolution iptables -A OUTPUT -p udp --dport 53 -j ACCEPT # Allow NTP time synchronization iptables -A OUTPUT -p udp --dport 123 -j ACCEPT
To maintain existing connections:
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT iptables -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
On Debian-based systems, persist your rules:
iptables-save > /etc/iptables.rules apt install iptables-persistent # If not already installed netfilter-persistent save
Check your configuration with:
iptables -L -nv --line-numbers iptables -L -nv --line-numbers -t nat
Here's how to allow AWS EC2 metadata service while blocking other external access:
# AWS metadata service iptables -A OUTPUT -d 169.254.169.254 -j ACCEPT # Allow SSH only from office IP iptables -A INPUT -p tcp -s 203.0.113.42 --dport 22 -j ACCEPT # Block everything else iptables -A INPUT -j DROP iptables -A OUTPUT -j DROP
When hardening a Debian-based server, implementing proper network segmentation through IP whitelisting is crucial. The goal is to restrict both inbound (INPUT chain) and outbound (OUTPUT chain) connections to specific trusted IP ranges while dropping all other traffic.
Here's a foundational implementation that handles both directions:
# Flush existing rules
iptables -F
iptables -X
# Set default policies to DROP
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP
# Allow localhost traffic
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
# Whitelist inbound connections (example: 192.168.1.0/24 and 203.0.113.15/32)
iptables -A INPUT -s 192.168.1.0/24 -j ACCEPT
iptables -A INPUT -s 203.0.113.15/32 -j ACCEPT
# Whitelist outbound connections (example: allowed destinations)
iptables -A OUTPUT -d 91.198.174.192/32 -j ACCEPT # example.org
iptables -A OUTPUT -d 151.101.0.0/16 -j ACCEPT # common CDN range
# Allow established/related connections
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
For production environments, consider these enhancements:
# Rate limiting for SSH (allow 3 new connections per minute from whitelisted IPs)
iptables -A INPUT -p tcp --dport 22 -m connlimit --connlimit-above 3 -j DROP
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --set
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 -j DROP
# Log dropped packets for debugging
iptables -N LOGGING
iptables -A INPUT -j LOGGING
iptables -A OUTPUT -j LOGGING
iptables -A LOGGING -m limit --limit 2/min -j LOG --log-prefix "IPTables-Dropped: " --log-level 4
iptables -A LOGGING -j DROP
# Allow ICMP only from specific monitoring hosts
iptables -A INPUT -s 198.51.100.42 -p icmp -j ACCEPT
For complex whitelists, use ipset for better performance:
# Install ipset if needed
apt-get install ipset
# Create and populate ipset
ipset create allowed_ips hash:net
ipset add allowed_ips 192.168.1.0/24
ipset add allowed_ips 203.0.113.0/28
# Reference ipset in iptables rules
iptables -A INPUT -m set --match-set allowed_ips src -j ACCEPT
iptables -A OUTPUT -m set --match-set allowed_ips dst -j ACCEPT
On Debian systems, save and restore rules:
# Save current rules
iptables-save > /etc/iptables.rules
# Install persistence package
apt-get install iptables-persistent
# For manual saving after changes
netfilter-persistent save
- Check effective rules with:
iptables -L -n -v
- Test connectivity from whitelisted IPs before production deployment
- Consider implementing a backup SSH access method during testing
- Monitor system logs (/var/log/syslog) for dropped packets