IPTables: allow outgoing SSH

When you have an outgoing connection, the destination port will be 22 so this should be the rule:

$IPT -A OUTPUT -o eth0 -p tcp --dport 22 -j ACCEPT

Also, you should have one rule to cover ESTABLISHED and RELATED on top of the INPUT and OUTPUT chains:

$IPT -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPT -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

Hope this helps.


Your rule for outgoing SSH traffic doesn't include the NEW statement, required to initiate outgoing connections.


This is a classic error when you doesn't understand client-server architecture and "stateful firewalls"

In a client-server architecture, the only port that is known a priori is the destination port because the client choose a ephemeral ports1 , except some extremely rare exceptions like DHCP for example.

From the firewall point off view, every single packet expelled from it has state NEW especially in TCP connections.2

First let's see what we have

IPT=/sbin/iptables
$IPT -F
$IPT -X
$IPT -t nat -F
$IPT -t nat -X
$IPT -t mangle -F
$IPT -t mangle -X
$IPT -P INPUT DROP
$IPT -P FORWARD DROP
$IPT -P OUTPUT DROP

# Excellent!! because always we need to accept this kind of states because
# always are response packets, remember we can be client or server
$IPT -A INPUT -m state --STATE ESTABLISHED,RELATED -j ACCEPT
$IPT -A OUTPUT -m state --STATE ESTABLISHED,RELATED -j ACCEPT

# Allow All for SSH
# this accept ssh connections from outside, and the response for this input
# is a outgoing packet with the state ESTABLISHED. (four lines above)
$IPT -A INPUT -i eth0 -p tcp --dport 22 -j ACCEPT

# this rule are meaningless because you never start a ssh connection from
# source port 22, this because the source ports are choose randomly
$IPT -A OUTPUT -o eth0 -p tcp --sport 22 -j ACCEPT

# this one let start a ssh connection from within to the outside and the response
# enter in state ESTABLISHED, 13 lines above
$IPT -A OUTPUT -o eth0 -p tcp --dport 22 -j ACCEPT

# Allow all for HTTP / HTTPS
# http servers are very basic if we think on client-server, they only respond a
# client request, except if some web software try to establish a network connection
# to the outside, for this block the only rule with meaning is the first, the rest are
# meaningless
$IPT -A INPUT -i eth0 -p tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT
$IPT -A OUTPUT -o eth0 -p tcp --sport 80 -m state --state ESTABLISHED -j ACCEPT
$IPT -A OUTPUT -o eth0 -p tcp --dport 443 -m state --state NEW,ESTABLISHED -j ACCEPT
$IPT -A INPUT -i eth0 -p tcp --sport 443 -m state --state ESTABLISHED -j ACCEPT

# Allow loopback traffic
# this are obligatory rules avoiding the firewall block himself
$IPT -A INPUT -i lo -j ACCEPT
$IPT -A OUTPUT -o lo -j ACCEPT

# Allow to be pinged ( Outside => srv )
# always the interpretation depends from the point of view
# with this rules you can accept ping request from outside and despond the request
# but you cannot ping from inside to outside because in that scenario you send the request (OUTPUT)
# and receive a reply from outside (INPUT) 
$IPT -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
$IPT -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT


# Allow outgoing DNS connections
# this allow send dns queries to the DNS server that you have registered in the file
# /etc/resolv.conf
$IPT -A OUTPUT -p udp -o eth0 --dport 53 -j ACCEPT
# this one are meaningless because the response from the DNS server is ESTABLISHED and is 
# accepted in the very beginning in the firewall 
$IPT -A INPUT -p udp -i eth0 --sport 53 -j ACCEPT

# Apt-get
# AFAIK apt use http or ftp, they can use https but is less common
# the specification of a range on source port are meaningless
$IPT -A OUTPUT -p tcp --dport 80 --sport 32786:61000 -j ACCEPT
$IPT -A INPUT -p tcp --dport 80 --sport 32786:61000 -j ACCEPT
$IPT -A OUTPUT -p tcp --dport 32786:61000 --sport 80 -j ACCEPT
$IPT -A INPUT -p tcp --dport 32786:61000 --sport 80 -j ACCEPT

# SMTP Outgoing
# I don't known why you start adding more criteria without meaning 
# maybe you start surfing on the net and starting copy&paste code without see what you are doing
# always when yo need to learn something go to the root, or in this case to www.netfilter.org
$IPT -A OUTPUT -p tcp --sport 1024:65535 -d 0/0 --dport 25 -m state --state NEW,ESTABLISHED -j ACCEPT
$IPT -A INPUT -p tcp -s 0/0 --sport 25 --dport 1024:65535 -m state --state ESTABLISHED-j ACCEPT


# the rules below are.... copy&paste from somewhere

# Prevent DoS
#$IPT -A INPUT -p tcp --dport 80 -m limit --limit 60/minute --limit-burst 150 -j ACCEPT
$IPT -A INPUT -p tcp --dport 80 -m connlimit --connlimit-above 100 --connlimit-mask 32     -j REJECT --reject-with tcp-reset
#
# Log dropped packets
$IPT -N LOGGING
$IPT -A INPUT -j LOGGING
$IPT -A LOGGING -m limit --limit 2/min -j LOG --log-prefix "IPTables Packet Dropped: "     --log-level 7
$IPT -A LOGGING -j DROP

So, to me, you need this firewall

IPT=/sbin/iptables
$IPT -F
$IPT -X
$IPT -t nat -F
$IPT -t nat -X
$IPT -t mangle -F
$IPT -t mangle -X
$IPT -P INPUT DROP
$IPT -P FORWARD DROP
$IPT -P OUTPUT DROP

# accept a priori all the responses
$IPT -A INPUT -m state --STATE ESTABLISHED,RELATED -j ACCEPT
$IPT -A OUTPUT -m state --STATE ESTABLISHED,RELATED -j ACCEPT

# Allow All for SSH 
# allow ssh connections from outside to inside
$IPT -A INPUT -i eth0 -p tcp --dport 22 -j ACCEPT

# allow ssh connections from inside to outside
$IPT -A OUTPUT -o eth0 -p tcp --dport 22 -j ACCEPT

# Allow all for HTTP / HTTPS
$IPT -A INPUT -i eth0 -p tcp --dport 80 -j ACCEPT
$IPT -A INPUT -i eth0 -p tcp --dport 443 -j ACCEPT

# Allow loopback traffic
$IPT -A INPUT -i lo -j ACCEPT
$IPT -A OUTPUT -o lo -j ACCEPT

# Allow to be pinged ( Outside => srv )
$IPT -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
$IPT -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT
# from srv to outside
$IPT -A INPUT -p icmp --icmp-type echo-reply -j ACCEPT
$IPT -A OUTPUT -p icmp --icmp-type echo-request -j ACCEPT

# Allow outgoing DNS connections
$IPT -A OUTPUT -p udp -o eth0 --dport 53 -j ACCEPT

# Apt-get
$IPT -A OUTPUT -p tcp --dport 80 -j ACCEPT
$IPT -A OUTPUT -p tcp --dport 21 -j ACCEPT

# SMTP Outgoing
$IPT -A OUTPUT -p tcp --dport 25 -j ACCEPT

I hope it has been helpful. And sorry for my english, is not my mother tongue.


For the simplest rules (ignorgin state for now):

iptables -A INPUT -p tcp --sport 22 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 22 -j ACCEPT

This should do the trick. once it you try it and succeed, you can modify it to include state, source/destination IP addresses, different ports..