An iptables firewall doesn’t actually secure your mail server; it just makes it harder for attackers to reach the services you want to expose.
Let’s get a basic, but reasonably secure, set of rules going. We’ll assume your mail server has a public IP address, say 192.0.2.10, and you’re running Postfix for SMTP, Dovecot for IMAP/POP3, and maybe a webmail interface.
First, we need to establish a baseline policy: deny everything by default. This is crucial.
sudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP
sudo iptables -P OUTPUT ACCEPT
We allow all outgoing traffic because our server will need to connect to other mail servers, DNS servers, etc. Dropping incoming and forwarded traffic means only explicitly allowed connections will get through.
Now, let’s allow established and related connections. This is how your server can receive replies to its outgoing requests.
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
This rule is the bedrock of stateful firewalls. Without it, your server couldn’t even receive a DNS response to a query it initiated.
Next, let’s allow loopback traffic. Your server’s services often talk to each other on 127.0.0.1.
sudo iptables -A INPUT -i lo -j ACCEPT
This is pretty straightforward: any traffic coming in on the loopback interface (lo) is allowed.
Now, the mail server specific ports.
For incoming SMTP (port 25):
sudo iptables -A INPUT -p tcp --dport 25 -j ACCEPT
This allows any machine on the internet to connect to your server’s SMTP port.
For SMTPS (port 465), if you use it:
sudo iptables -A INPUT -p tcp --dport 465 -j ACCEPT
For submission (port 587), used for authenticated sending:
sudo iptables -A INPUT -p tcp --dport 587 -j ACCEPT
For IMAP (port 143):
sudo iptables -A INPUT -p tcp --dport 143 -j ACCEPT
For IMAPS (port 993), the secure version:
sudo iptables -A INPUT -p tcp --dport 993 -j ACCEPT
For POP3 (port 110):
sudo iptables -A INPUT -p tcp --dport 110 -j ACCEPT
For POP3S (port 995), the secure version:
sudo iptables -A INPUT -p tcp --dport 995 -j ACCEPT
If you have a webmail interface (e.g., Roundcube on port 80 or 443):
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT
It’s generally a good idea to restrict access to these ports to only trusted IP addresses or networks if possible. For example, if you only manage your mail server from a specific IP 203.0.113.5:
sudo iptables -A INPUT -p tcp --dport 25 -s 203.0.113.5 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 587 -s 203.0.113.5 -j ACCEPT
# ... and so on for other ports and IPs
However, for public services like port 25, you usually can’t restrict by source IP.
If you want to allow ICMP (ping) requests:
sudo iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
This lets you ping your server to check if it’s online.
Finally, let’s save these rules so they persist after a reboot. The method varies by distribution, but for systems using iptables-persistent:
sudo netfilter-persistent save
Or on older Debian/Ubuntu systems:
sudo iptables-save | sudo tee /etc/iptables/rules.v4
And for IPv6:
sudo ip6tables -P INPUT DROP
sudo ip6tables -P FORWARD DROP
sudo ip6tables -P OUTPUT ACCEPT
sudo ip6tables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
sudo ip6tables -A INPUT -i lo -j ACCEPT
sudo ip6tables -A INPUT -p tcp --dport 25 -j ACCEPT
sudo ip6tables -A INPUT -p tcp --dport 465 -j ACCEPT
sudo ip6tables -A INPUT -p tcp --dport 587 -j ACCEPT
sudo ip6tables -A INPUT -p tcp --dport 993 -j ACCEPT
sudo ip6tables -A INPUT -p tcp --dport 995 -j ACCEPT
sudo ip6tables -A INPUT -p icmpv6 --icmpv6-type echo-request -j ACCEPT
sudo iptables-save -t nat | sudo tee /etc/iptables/rules.v6 # Check this path for your distro
The most common mistake people make here is forgetting the ESTABLISHED,RELATED rule, which breaks all return traffic.
After applying these rules, the next thing you’ll likely encounter is a need to protect against brute-force attacks on your mail submission (port 587) and IMAP/POP3 ports.