Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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
share|improve this question

2 Answers 2

up vote 3 down vote accepted

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.

share|improve this answer
+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 at 12:06
Both great answers, I've learnt a lot! I tested @SkyDan answer and it works well! –  Steven Jun 10 at 11:36

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.

share|improve this answer
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. –  SkyDan Jun 9 at 11:35
@SkyDan You're right about what "established" means, but you are wrong about the first output packet being blocked if the connection is -p tcp and was created via an INPUT rule. Try it yourself (replace your output rule with an established, related rule). –  goldilocks Jun 9 at 12:05
@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 at 12:20
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! –  SkyDan Jun 9 at 12:24
@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 at 12:28

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

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