Good iptables starting rules for a webserver?

Your IPTables rules seem to be mostly appropriate for your server. But I would suggest a couple of possible changes:

  • Unless you need to allow SSH, MySQL, and FTP access from the entire Internet, it would be much more secure to use the '--source' option to restrict access on those ports from certain approved IP addresses, only. For instance, to only allow SSH access from the IP address 71.82.93.101, you'd change the 5th rule to 'iptables -A INPUT -p tcp --dport ssh --source 71.82.93.101 -i eth0 -j ACCEPT'. You'll probably need to add a separate rule for each individual IP address that you want to allow, see this question for more info on that: iptables multiple source IPs.

  • Unless this machine is running a DNS server, you'll probably want to block access to the 'domain' (53) port. To do this, just remove the line 'iptables -A INPUT -p tcp --dport domain -i eth0 -j ACCEPT'. (This should also answer your final question, BTW.) If you are actually running a DNS server, though, leave this rule in place.

  • If you need to allow remote MySQL client access over the network, you'll need to add the line 'iptables -A INPUT -p tcp --dport 3306 -i eth0 -j ACCEPT' to open up external access to the standard MySQL port. But DON'T do this unless it's really necessary--if you only need local MySQL access (for a PHP app running under Apache, say), you don't need to provide remote MySQL access. And unless you want to risk getting hacked, if you do open port 3306 to the network, make sure that you require strong passwords for all of the MySQL user accounts, and that your MySQL server packages are up-to-date.

  • One of your comments ('Allow ssh, dns, ldap, ftp and web services') mentions LDAP services, but there is no such rule in your configuration. This happens to me a lot when I copy an example configuration and modify it. It won't affect the function, but I would fix the comment, since misleading comments can cause indirectly by confusing you or another admin in the future.

In my experience, it's hard to come up with a perfect set of IPTables rules, but I think you're definitely on the right track. Also, good luck with learning more about IPTables--these rules can seem complex at first, but it's a very helpful skill for any Linux sysadmin to have.


Definitely look to restrict your outbound traffic too.

I've seen plenty of cases where PHP exploits result in someone using 'curl' or 'wget' to fetch malicious code from elsewhere, then execute it on your server to join to a botnet.

If you do not expect Apache (as an example) to need to talk to other websites itself, restrict the traffic and save yourself a little pain down the line!


These rules are ready to be imported via "iptables-restore":

*filter
:INPUT DROP [20:2036]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [93:16260]
-A INPUT -p icmp -m icmp --icmp-type 0 -j ACCEPT -m comment --comment "allow ICMP: echo-reply"
-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT -m comment --comment "allow ICMP: echo-request"
-A INPUT -p icmp -m icmp --icmp-type 3 -j ACCEPT -m comment --comment "allow ICMP: destination-unreachable"
-A INPUT -p icmp -m icmp --icmp-type 4 -j ACCEPT -m comment --comment "allow ICMP: source-quench"
-A INPUT -p icmp -m icmp --icmp-type 11 -j ACCEPT  -m comment --comment "allow ICMP: time-exceeded"
-A INPUT -i lo -j ACCEPT -m comment --comment "allow input from the loop-back adapter"
-A INPUT -i eth0 -p tcp -m tcp --dport 22 -j ACCEPT -m comment --comment "allow SSH: ssh"
-A INPUT -i eth0 -p tcp -m tcp --dport 53 -j ACCEPT -m comment --comment "allow DNS: domain"
-A INPUT -i eth0 -p tcp -m udp --dport 53 -j ACCEPT -m comment --comment "allow DNS: domain"
-A INPUT -i eth0 -p tcp -m tcp --dport 21 -j ACCEPT -m comment --comment "allow FTP: ftp"
-A INPUT -i eth0 -p udp -m udp --dport 21 -j ACCEPT -m comment --comment "allow FTP: ftp"
-A INPUT -i eth0 -p tcp -m tcp --dport 20 -j ACCEPT -m comment --comment "allow FTP: ftp-data"
-A INPUT -i eth0 -p udp -m udp --dport 20 -j ACCEPT -m comment --comment "allow FTP: ftp-data"
-A INPUT -i eth0 -p tcp -m tcp --dport 3306 -j ACCEPT -m comment --comment "allow MariaDB/MySQL: mysql"
-A INPUT -i eth0 -p tcp -m tcp --dport 80 -j ACCEPT -m comment --comment "allow HTTP (apache/nxing/lighttpd)"
-A INPUT -i eth0 -p tcp -m tcp --dport 443 -j ACCEPT -m comment --comment "allow HTTPS (apache/nxing/lighttpd)"
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT  -m comment --comment "allow already established connections"
COMMIT

And just for the record...these default policies should be set too, IF the above iptables-restore is not used:

iptables -P INPUT DROP
iptables -P OUTPUT ACCEPT
iptables -P FORWARD DROP