Page Last Updated: 2024 March 06
Iptables
(N.B. You might be on a newer system that requires nftables, click on nftables on the left-hand menu to see how to handle this.)
iptables is used for packet filtering and NAT, and is a standard part of modern Linux firewalling. It is an alternative to UFW and PF, which do the same work in different ways. Let’s look at how to get started.
Installation
iptables comes in both ipv4 and ipv6 flavors. Let’s begin with ipv4.
The tools necessary to create a firewall with iptables are already installed on your Debian box. So, begin by creating a file to house your rules.
sudo touch /etc/iptables.rules
Using iptables
While iptables rules can be added and removed from the command line (more on that here), it’s often easier to keep your ruleset in a file that can be loaded as needed.
So, let’s open the file you just created:
sudo nano /etc/iptables.rules
Here’s mine for reference. Use the comments to decide what rules are useful to you. Your needs/ports may vary, but here’s some of what I use for speed and security.
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [86:13587]
:ICMP_IN - [0:0]
:TCP - [0:0]
:UDP - [0:0]
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -d 127.0.0.0/8 ! -i lo -j REJECT --reject-with icmp-port-unreachable
-A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j TCP
-A INPUT -p udp -m conntrack --ctstate NEW -j UDP
-A INPUT -p icmp -m conntrack --ctstate NEW -j ICMP_IN
-A INPUT -m limit --limit 50/min -j LOG --log-prefix "iptables denied: " --log-level 7
-A OUTPUT -o eth0 -p icmp -m icmp --icmp-type 8 -m conntrack --ctstate NEW -j ACCEPT
-A ICMP_IN -i eth0 -p icmp -m icmp --icmp-type 8 -j DROP
-A ICMP_IN -i eth0 -p icmp -m icmp --icmp-type 0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A ICMP_IN -i eth0 -p icmp -m icmp --icmp-type 3 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A ICMP_IN -i eth0 -p icmp -m icmp --icmp-type 11 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A ICMP_IN -p icmp -m limit --limit 6/sec --limit-burst 1 -j ACCEPT
-A ICMP_IN -p icmp -j LOG --log-prefix "ICMP denied: " --log-level 7
-A ICMP_IN -p icmp -j REJECT --reject-with icmp-proto-unreachable
-A TCP -p tcp --dport 22 -m comment --comment SSH -j ACCEPT
-A TCP -p tcp -m multiport --dports 80,443 -m comment --comment Web -j ACCEPT
-A TCP -p tcp -m multiport --dports 25,587,993 -m comment --comment Mail -j ACCEPT
-A TCP -p tcp -j LOG --log-prefix "TCP denied: " --log-level 7
-A TCP -p tcp -j REJECT --reject-with tcp-reset
-A UDP -p udp -j LOG --log-prefix "UDP denied: " --log-level 7
-A UDP -p udp -j REJECT --reject-with icmp-port-unreachable
COMMIT
*mangle
:PREROUTING ACCEPT [40:2858]
:INPUT ACCEPT [40:2858]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [86:13587]
:POSTROUTING ACCEPT [86:13587]
-A PREROUTING -i eth0 -p tcp -m tcp ! --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j DROP
-A PREROUTING -i eth0 -p tcp -m conntrack --ctstate NEW -m tcpmss ! --mss 536:65535 -j DROP
-A PREROUTING -i eth0 -m conntrack --ctstate INVALID -j DROP
-A PREROUTING -i eth0 -f -m comment --comment "Drop Fragments" -j DROP
-A PREROUTING -i eth0 -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j DROP
-A PREROUTING -i eth0 -p tcp -m tcp --tcp-flags FIN,SYN FIN,SYN -j DROP
-A PREROUTING -i eth0 -p tcp -m tcp --tcp-flags SYN,RST SYN,RST -j DROP
-A PREROUTING -i eth0 -p tcp -m tcp --tcp-flags FIN,RST FIN,RST -j DROP
-A PREROUTING -i eth0 -p tcp -m tcp --tcp-flags FIN,ACK FIN -j DROP
-A PREROUTING -i eth0 -p tcp -m tcp --tcp-flags ACK,URG URG -j DROP
-A PREROUTING -i eth0 -p tcp -m tcp --tcp-flags FIN,ACK FIN -j DROP
-A PREROUTING -i eth0 -p tcp -m tcp --tcp-flags PSH,ACK PSH -j DROP
-A PREROUTING -i eth0 -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,RST,PSH,ACK,URG -j DROP
-A PREROUTING -i eth0 -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j DROP
-A PREROUTING -i eth0 -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,PSH,URG -j DROP
-A PREROUTING -i eth0 -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,PSH,URG -j DROP
-A PREROUTING -i eth0 -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,RST,ACK,URG -j DROP
COMMIT
Once you’ve got your iptables.rules file the way you want it, go ahead and activate those rules:
sudo iptables-restore < /etc/iptables.rules
#If you're using fail2ban, you'll need to restart it here:
sudo /etc/init.d/fail2ban restart
#Then, to confirm that your rules are working:
sudo iptables -L -n
Final Steps
Of course, these rules aren’t very useful if they aren’t loaded when you reboot your server. Let’s make sure they are by adding a command to load them to your machine’s boot process:
su
apt-get install netfilter-persistent
Follow the prompts, and your firewall should reload when you reboot.
If this approach doesn’t work, you could try:
su
nano /etc/network/if-pre-up.d/firewall
Now, add these lines to your file and save:
#!/bin/sh
/sbin/iptables-restore < /etc/iptables.rules
That’s it!