How to Configure iptables to Allow HTTP Traffic to a Single Domain (serverfault.com) Only


2 views


When attempting to restrict HTTP traffic to only serverfault.com using iptables rules, you encountered the error:
iptables v1.4.4: host/network serverfault.com' not found

This occurs because iptables operates at the network layer and requires IP addresses rather than domain names. The DNS resolution happens at a higher level in the network stack.

Here's a working configuration that handles both the web traffic and necessary DNS resolution:

# Flush existing rules
iptables -F
iptables -X

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

# Allow loopback interface
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

# Allow DNS resolution (UDP port 53)
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
iptables -A INPUT -p udp --sport 53 -j ACCEPT

# Get serverfault.com IP addresses (run this first)
# host serverfault.com | grep 'has address' | awk '{print $4}'

# Allow HTTP traffic to serverfault.com IPs (example IPs - replace with actual ones)
iptables -A OUTPUT -p tcp -d 151.101.1.69 --dport 80 -j ACCEPT
iptables -A OUTPUT -p tcp -d 151.101.65.69 --dport 80 -j ACCEPT
iptables -A OUTPUT -p tcp -d 151.101.129.69 --dport 80 -j ACCEPT
iptables -A OUTPUT -p tcp -d 151.101.193.69 --dport 80 -j ACCEPT

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

If serverfault.com changes its IP addresses frequently, consider these approaches:

1. IP Set Method (more efficient for multiple IPs):

# Create IP set
ipset create serverfault hash:ip

# Add IPs (run periodically via cron)
ipset flush serverfault
for ip in $(host serverfault.com | grep 'has address' | awk '{print $4}'); do
  ipset add serverfault $ip
done

# Use in iptables
iptables -A OUTPUT -p tcp -m set --match-set serverfault dst --dport 80 -j ACCEPT

2. DNS Proxy Solution:
You could run a local DNS proxy that only resolves allowed domains and block all other DNS traffic.

After applying these rules:

# Check if you can access serverfault.com
curl -v http://serverfault.com

# Verify other sites are blocked
curl -v http://google.com  # Should fail

# Check DNS resolution
dig serverfault.com  # Should work
dig google.com       # Should fail (except for initial DNS allow)

For more precise control, consider using an application-layer firewall like Squid:

acl allowed_sites dstdomain .serverfault.com
http_access allow allowed_sites
http_access deny all

This gives you better control over HTTPS traffic as well, though requires more setup.


When trying to restrict HTTP traffic to only serverfault.com using iptables, you'll immediately encounter a fundamental limitation: iptables operates at the network layer and doesn't natively resolve domain names. The error message host/network serverfault.com' not found clearly indicates this.

Before your rules can work, you need to handle DNS resolution. Even if you specify IP addresses directly, your system still needs to perform DNS lookups to establish the initial connection. Here's why DNS must be allowed:

# Allow DNS queries (UDP port 53)
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
iptables -A INPUT -p udp --sport 53 -j ACCEPT

Here's a working implementation that restricts HTTP traffic to serverfault.com while allowing necessary ancillary services:

# Flush existing rules
iptables -F
iptables -X

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

# Allow loopback interface
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

# Allow DNS resolution
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
iptables -A INPUT -p udp --sport 53 -j ACCEPT

# Allow HTTP to serverfault.com (using its IP addresses)
iptables -A OUTPUT -p tcp -d 151.101.1.69 --dport 80 -j ACCEPT
iptables -A OUTPUT -p tcp -d 151.101.65.69 --dport 80 -j ACCEPT
iptables -A OUTPUT -p tcp -d 151.101.129.69 --dport 80 -j ACCEPT
iptables -A OUTPUT -p tcp -d 151.101.193.69 --dport 80 -j ACCEPT

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

1. IP Address Stability: The IP addresses of serverfault.com might change. Consider implementing a script to periodically update these rules with current IPs.

2. HTTPS Support: If you need HTTPS access, add similar rules for port 443.

3. IPv6 Considerations: If your network uses IPv6, you'll need to add corresponding rules to ip6tables.

For more granular control, consider setting up a transparent proxy like Squid that can filter by domain name:

# Redirect HTTP traffic to proxy
iptables -t nat -A OUTPUT -p tcp --dport 80 -j DNAT --to 127.0.0.1:3128
iptables -t nat -A OUTPUT -p tcp --dport 443 -j DNAT --to 127.0.0.1:3129

Then configure the proxy to only allow access to serverfault.com.

After applying these rules, test with:

curl -v http://serverfault.com  # Should work
curl -v http://example.com     # Should fail
nslookup serverfault.com       # Should work
ping serverfault.com           # Should fail (ICMP blocked)