The OUTPUT chain in iptables is where you control packets originating from your own machine.

Let’s see it in action. Imagine you want to prevent your server from initiating SSH connections to anywhere except a specific management IP.

# Allow established SSH connections (important!)
iptables -A OUTPUT -p tcp --dport 22 -m state --state ESTABLISHED,RELATED -j ACCEPT

# Block all other outbound SSH traffic
iptables -A OUTPUT -p tcp --dport 22 -j REJECT --reject-with tcp-reset

# Allow outbound traffic to our management IP on any port
iptables -A OUTPUT -d 192.168.1.100 -j ACCEPT

# Drop everything else by default (if you want a strict policy)
# iptables -P OUTPUT DROP

This example shows a common pattern: allow specific outbound traffic, then block or restrict the rest. The REJECT target sends an ICMP "port unreachable" or TCP RST packet back to the sender, letting them know the connection was actively refused. DROP silently discards the packet, which can be useful for hiding your internal network but can also make debugging harder.

The OUTPUT chain is distinct from the INPUT and FORWARD chains. INPUT handles traffic destined for your machine, and FORWARD handles traffic passing through your machine to another destination. OUTPUT is purely about packets your server is sending.

The key components you’ll manipulate are:

  • Protocols (-p): tcp, udp, icmp, all.
  • Destination (-d): The IP address or network the packet is going to.
  • Source (-s): The IP address or network the packet is coming from (less common for OUTPUT unless you have multiple interfaces/IPs).
  • Destination Port (--dport): The port the packet is trying to reach on the destination.
  • State (-m state --state): Crucial for allowing return traffic for established connections. ESTABLISHED means the packet is part of an existing connection, and RELATED means it’s a new connection that’s related to an existing one (like FTP data connections).

The default policy for the OUTPUT chain is usually ACCEPT. This means if no rule matches, the packet is allowed through. If you want to implement a strict outbound firewall, you’d set the default policy to DROP and then explicitly ACCEPT only the traffic you want to allow.

Consider a scenario where you want to restrict your server to only performing DNS lookups to a specific internal DNS server.

# Allow established/related UDP traffic (e.g., for DNS responses)
iptables -A OUTPUT -p udp -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -p tcp -m state --state ESTABLISHED,RELATED -j ACCEPT

# Allow DNS (UDP port 53) to our internal DNS server
iptables -A OUTPUT -p udp -d 192.168.1.53 --dport 53 -j ACCEPT

# Allow DNS (TCP port 53) to our internal DNS server (for zone transfers, etc.)
iptables -A OUTPUT -p tcp -d 192.168.1.53 --dport 53 -j ACCEPT

# Drop all other outbound DNS traffic
iptables -A OUTPUT -p udp --dport 53 -j REJECT --reject-with icmp-port-unreachable
iptables -A OUTPUT -p tcp --dport 53 -j REJECT --reject-with tcp-reset

# Now, you'd typically add rules for other essential outbound traffic
# e.g., NTP, package updates, etc.

A common pitfall is forgetting the ESTABLISHED,RELATED rule. Without it, your server won’t be able to receive responses to its own outbound requests, effectively breaking outbound communication for most applications. The REJECT target is generally preferred over DROP for outbound rules when you want to provide feedback to the initiating application that the connection was blocked, facilitating faster troubleshooting.

If you’re applying a restrictive OUTPUT policy, you must explicitly allow outbound traffic for package management tools (like apt, yum) if you intend to use them, and also for NTP if time synchronization is critical. Without these, your system’s clock could drift, and you won’t be able to update your software.

The next hurdle you’ll likely face is managing the order of rules. iptables processes rules sequentially within a chain, and the first matching rule determines the packet’s fate. This means more specific rules (e.g., a particular destination IP and port) should often appear before more general rules (e.g., dropping all traffic to a certain port).

Want structured learning?

Take the full Iptables course →