Introduction
Many firewall guides are either too permissive (ACCEPT everything) or too strict to operate safely in production. A good iptables policy should be strict by default, explicit about allowed traffic, and maintainable over time.
This guide shows how to build a least-privilege iptables policy without breaking SSH access or application traffic.
What “Strict” Should Mean
A strict firewall is not random denial. It means:
- Default deny (
DROP) for inbound and forwarded packets. - Explicit allow rules for required services.
- Established/related traffic allowed for return paths.
- Logging for denied packets at controlled rate.
- Minimal, documented outbound allowances.
Baseline Policy Design
Chain defaults
Recommended baseline:
INPUT:DROPFORWARD:DROPOUTPUT:ACCEPTinitially, then tighten if your environment needs egress control.
Why OUTPUT is often left open first
In many production systems, over-restricting OUTPUT breaks package managers, DNS, telemetry, object storage, backup agents, and time sync. Tightening egress should be deliberate and inventory-driven.
Safe Baseline Rules
# Flush current rules carefully in controlled maintenance window
iptables -F
iptables -X
# Set policies
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
# Allow loopback
iptables -A INPUT -i lo -j ACCEPT
# Allow established and related return traffic
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# SSH from admin network
iptables -A INPUT -p tcp --dport 22 -s 203.0.113.0/24 -m conntrack --ctstate NEW -j ACCEPT
# Web traffic
iptables -A INPUT -p tcp --dport 80 -m conntrack --ctstate NEW -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -m conntrack --ctstate NEW -j ACCEPT
# ICMP (recommended for diagnostics and MTU behavior)
iptables -A INPUT -p icmp -j ACCEPT
Service-Specific Examples
DNS server role
iptables -A INPUT -p udp --dport 53 -j ACCEPT
iptables -A INPUT -p tcp --dport 53 -j ACCEPT
Database exposed only to app subnet
iptables -A INPUT -p tcp --dport 5432 -s 10.10.0.0/16 -m conntrack --ctstate NEW -j ACCEPT
Internal metrics endpoint
iptables -A INPUT -p tcp --dport 9100 -s 10.20.30.0/24 -m conntrack --ctstate NEW -j ACCEPT
Controlled Logging for Denied Traffic
Logging every dropped packet can overload disks. Use rate limiting:
iptables -A INPUT -m limit --limit 5/min --limit-burst 10 -j LOG --log-prefix "iptables-drop: " --log-level 4
iptables -A INPUT -j DROP
Put LOG before final DROP in chain order.
About state vs conntrack
Older examples use -m state --state .... Modern kernels prefer -m conntrack --ctstate ....
Both can work, but use conntrack in new rules for clarity and consistency.
Should You Lock Down OUTPUT?
For high-security environments, yes. For general web servers, maybe later.
If you do lock down OUTPUT, allow at least:
- DNS (
53UDP/TCP) to trusted resolvers. - NTP (
123UDP) to time sources. - Package repository traffic.
- Required API endpoints.
Example:
iptables -P OUTPUT DROP
iptables -A OUTPUT -o lo -j ACCEPT
iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -p udp --dport 53 -d 10.0.0.2 -j ACCEPT
iptables -A OUTPUT -p udp --dport 123 -d 169.254.169.123 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 443 -j ACCEPT
Rule Persistence
Always save known-good state.
iptables-save > /root/iptables.known-good.rules
On Debian/Ubuntu with iptables-persistent:
apt-get install -y iptables-persistent
iptables-save > /etc/iptables/rules.v4
Validation and Troubleshooting
Useful commands:
iptables -S
iptables -L -n -v
ss -tulpen
journalctl -k | grep iptables-drop
If traffic fails unexpectedly:
- Check chain order.
- Check source IP assumptions.
- Check whether packet belongs to ESTABLISHED flow.
- Check NAT/filter table interactions.
Common Mistakes
- Typo in chain name (
OUTUTinstead ofOUTPUT). - Forgetting loopback allow rule.
- Using default drop before adding SSH allowlist.
- Relying on broad
ACCEPT allrules in production. - Not documenting why a port is open.
Practical Policy for Most Web Servers
A pragmatic strict policy for internet-facing web hosts:
- INPUT DROP.
- FORWARD DROP.
- OUTPUT ACCEPT initially.
- Allow
lo, ESTABLISHED/RELATED, SSH from admin CIDR, and80/443. - Add controlled ICMP.
- Add rate-limited logging before final drop.
This keeps attack surface small while preserving operability.
Conclusion
“More strict” should mean intentional, testable, and maintainable firewall design. Start with a clear baseline, open only required services, and keep rule changes documented and reversible.
A strict firewall that your team cannot operate safely is not secure. A strict firewall with safe rollout and clear ownership is.
Comments