The aim of this script is to only allow traffic over the VPN, except for localhost<->localhost and incoming SSH traffic. But when I run the script over SSH I am disconnected and forced to restart the vm. What is wrong with my script?

iptables -F

#Allow over VPN
iptables -A INPUT -i tun+ -j ACCEPT
iptables -A OUTPUT -o tun+ -j ACCEPT

iptables -A INPUT -s -j ACCEPT
iptables -A OUTPUT -d -j ACCEPT

iptables -A INPUT -s -j ACCEPT
iptables -A OUTPUT -d -j ACCEPT

iptables -A INPUT -p tcp --dport ssh -j ACCEPT

#Default Deny
iptables -A INPUT -j DROP
iptables -A OUTPUT -j DROP

Output chain is responsible for any packet going out.

Your script only allows outbound packets to tunnel interface, localhost and remote host at

If you are connecting to the server in a way that requires SSH daemon to send packets to the destination other than one of the above, the traffic will not be allowed to go out.

To allow outbound packets from your SSH daemon to the SSH client you need to add the following rule:

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

You might also want to add destination IP criteria to the above rule, if you are only connecting from a single location. This rule needs to come before the ultimate 'DROP anything else' rule for the output chain.

  • +1 This will work and is more specific than using an established, related rule (making it either more or less useful depending on context). – goldilocks Jun 9 '14 at 12:06
  • Both great answers, I've learnt a lot! I tested @SkyDan answer and it works well! – Steven Jun 10 '14 at 11:36
  • Nitpick: the output chain isn't responsible for forwarded packets. – Björn Lindqvist Nov 19 '18 at 18:55

Your #SSH rule implies ssh is a one way form of communication, which it is not. Data is being sent forth and back.

The normal way to deal with this, since you can't know the port number on the client side in advance, is to allow connections which are considered "established" or "related" to an established connection. To do this you need:


Before your DROP rules (and preferably at the top, since the rules are processed in order and these two will apply to most packets).

There's an explanation of how a TCP connection becomes ESTABLISHED here; essentially, the fact of the server replying to the packet allowed by your #SSH INPUT rule makes it so.

  • 1
    This will not work. Established means packets in both directions for a given TCP connection have been seen. If you only add this rule, the first outbound packet will still be blocked. – hellodanylo Jun 9 '14 at 11:35
  • 2
    @SkyDan Here's a reference for that. Notice on the diagram that when the server sends a syn/ack back to the client after receiving the opening syn, the connection is established meaning iptables will let that reply packet through: "Once it has seen one packet(the SYN), it considers the connection as NEW. Once it sees the return packet(SYN/ACK), it considers the connection as ESTABLISHED." -> again: iptables sees the return packet the server wants to send, sets the connection as established, and lets the reply through. – goldilocks Jun 9 '14 at 12:20
  • 1
    Okay, I see why it will work. It's a bit obscure, since the iptables man only talks about seeing packets in both directions, not a word about the TCP handshake packets being an exception. Thanks for the reference! – hellodanylo Jun 9 '14 at 12:24
  • 2
    @SkyDan In fact, the logic does not apply only to tcp -- I was wrong about -p tcp making any difference in this sense, and look at the subsequent explanation for UDP on that page (it's the same). The point is that the server replies without knowing whether iptables will allow it or not, and when iptables receives that reply from the server on the local system, it has now seen traffic in both directions (even though the client has not yet), considers the connection established, and lets the reply out. The "technicality" here hinges on the firewall being in the middle of the two parties. – goldilocks Jun 9 '14 at 12:28
  • 1
    You are correct there. Someone should probably include this information into the iptables man. – hellodanylo Jun 9 '14 at 13:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.