Iptables
iptables is the classic command-line tool for managing the Linux firewall. It controls netfilter, the packet filtering framework inside the Linux kernel, and decides which incoming, outgoing and forwarded packets are accepted or dropped.
All commands in this guide need root rights. Run them as root or add sudo. The examples use IPv4; for IPv6 use the same rules with ip6tables. The IP addresses 203.0.113.0/24 and 198.51.100.0/24 are documentation examples, so replace them with your own.
How iptables Works
Rules are grouped into tables, and each table has chains:
- filter (the default table) decides whether a packet is allowed. Its chains are INPUT (traffic to the server), OUTPUT (traffic from the server) and FORWARD (traffic passing through the server).
- nat changes addresses and ports, for example for port forwarding or sharing an internet connection.
- mangle changes packet headers for advanced routing.
Each rule ends with a target: ACCEPT lets the packet through, DROP silently discards it, REJECT discards it and replies with an error, LOG writes it to the kernel log. Rules are checked from top to bottom, and the first matching rule wins. If no rule matches, the chain policy applies.
View the Current Rules
iptables -L -n -v
iptables -L INPUT -n -v --line-numbers
iptables -S
iptables -t nat -L -n -v-L lists the rules, -n shows IP addresses and ports as numbers (faster, no DNS lookups), -v adds packet counters and interfaces, --line-numbers shows rule numbers, and -S prints the rules in the same format you would type them.
A Basic Firewall for a Web Server
The following rules allow SSH, HTTP and HTTPS, keep established connections working and drop everything else that comes in:
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPTAlways add the rule for SSH before you set the INPUT policy to DROP, otherwise you will lose access to the server. If that happens on a BlueVPS server, open the VNC console in your client area and fix the rules from there.
Add, Insert and Delete Rules
# Add a rule to the end of the chain
iptables -A INPUT -p tcp --dport 8080 -j ACCEPT
# Insert a rule at position 1 (top of the chain)
iptables -I INPUT 1 -s 203.0.113.10 -j DROP
# Delete a rule by its number
iptables -L INPUT -n --line-numbers
iptables -D INPUT 3
# Delete a rule by its exact definition
iptables -D INPUT -s 203.0.113.10 -j DROP
# Replace rule number 2
iptables -R INPUT 2 -p tcp --dport 2222 -j ACCEPTBlock or Allow IP Addresses
# Block one IP address
iptables -I INPUT -s 203.0.113.10 -j DROP
# Block a whole subnet
iptables -I INPUT -s 198.51.100.0/24 -j DROP
# Allow SSH only from your office IP
iptables -A INPUT -p tcp --dport 22 -s 203.0.113.50 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j DROP
# Block outgoing connections to an IP range
iptables -A OUTPUT -d 198.51.100.0/24 -j DROPUse -I (insert) for blocking rules so they are checked before the rules that allow traffic.
Open and Close Ports
# Open TCP ports
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
# Open a UDP port (for example, DNS)
iptables -A INPUT -p udp --dport 53 -j ACCEPT
# Open a range of ports
iptables -A INPUT -p tcp --dport 6000:6010 -j ACCEPT
# Allow MySQL only from a private network
iptables -A INPUT -p tcp --dport 3306 -s 10.0.0.0/8 -j ACCEPT
# Close a port by deleting the rule that opened it
iptables -D INPUT -p tcp --dport 8080 -j ACCEPTNever open database ports such as 3306 (MySQL) or 5432 (PostgreSQL) to the whole internet. Allow them only from the addresses that need them.
Limit Connections
Limit new SSH connections from one IP address to 5 per minute to slow down password guessing:
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -m recent --set
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -m recent --update --seconds 60 --hitcount 5 -j DROPLimit the number of simultaneous HTTP connections from one IP address to 50:
iptables -A INPUT -p tcp --syn --dport 80 -m connlimit --connlimit-above 50 --connlimit-mask 32 -j REJECTPut these rules before the rules that accept SSH and HTTP traffic.
Log Dropped Packets
Add a LOG rule just before the final DROP rule or policy. The limit module keeps the log from growing too fast:
iptables -A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables-dropped: " --log-level 4This logs up to 5 packets per minute. To read the log, run journalctl -k | grep iptables-dropped or check /var/log/kern.log on Ubuntu and Debian.
ICMP and Ping
Blocking all ICMP traffic breaks network diagnostics and path MTU discovery, so it is better to allow the important types and decide only about ping:
iptables -A INPUT -p icmp --icmp-type destination-unreachable -j ACCEPT
iptables -A INPUT -p icmp --icmp-type time-exceeded -j ACCEPT
# Allow ping
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
# Or block ping from everyone except your network
iptables -A INPUT -p icmp --icmp-type echo-request -s 203.0.113.0/24 -j ACCEPT
iptables -A INPUT -p icmp --icmp-type echo-request -j DROPNAT and Port Forwarding
To share the internet connection of the server with a private network, enable packet forwarding and masquerading:
sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -s 10.0.0.0/24 -j ACCEPTTo forward port 8080 on the server to port 80 on an internal host:
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 8080 -j DNAT --to-destination 10.0.0.2:80
iptables -A FORWARD -p tcp -d 10.0.0.2 --dport 80 -j ACCEPTTo keep forwarding on after a reboot, add net.ipv4.ip_forward = 1 to /etc/sysctl.conf.
Save Rules Permanently
iptables rules live in memory and disappear after a reboot unless you save them.
Ubuntu and Debian
apt install iptables-persistent
netfilter-persistent saveThe rules are saved to /etc/iptables/rules.v4 and loaded at boot.
AlmaLinux and Rocky Linux
dnf install iptables-services
systemctl disable --now firewalld
service iptables save
systemctl enable --now iptablesThe rules are saved to /etc/sysconfig/iptables. Do not run firewalld and the iptables service at the same time.
Manual backup and restore
iptables-save > /root/iptables.rules
iptables-restore < /root/iptables.rulesReset All Rules
Set the policies to ACCEPT first, so you do not lock yourself out, then remove all rules and custom chains:
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -Xiptables, nftables, UFW and firewalld
Current Linux distributions use nftables in the kernel. The iptables command still works through a compatibility layer: iptables -V shows (nf_tables) in this case. UFW on Ubuntu and firewalld on AlmaLinux and Rocky Linux are simpler front ends that create the rules for you. Use one tool to manage the firewall, because rules from different tools can conflict.
Conclusion
A few well-ordered iptables rules are enough to protect a typical server: allow the services you need, keep established connections working and drop the rest. On a BlueVPS VPS you get full root access to set up any firewall rules, and the VNC console in the client area helps if a rule blocks your SSH access.
Blog