I'm working on local git project and I'm running separated SSH service on port 2222 with non-root user. Along that I'm using ufw firewall and opened port 2222 - I opened it just for testing if connection to it works as expected and it's OK.

Because default port for SSH is 22 and I wouldn't like for users to write additional ports in address for access to repositories I want to preroute it from 22 to 2222. Also I want that port 2222 wouldn't be accessible from outside when prerouting is effective.

Basically I already done the first part - I prerouted traffic from 22 to 2222 and it works without a problem if port 2222 is also opened, but when trying to close down port 2222 also the connection to 22 stops working (the rule for opened port is still there). This is somehow logical since iptables seeems to just convert port 22 to 2222 and forward it to ufw, which then recognizes this and deny connection because port 2222 is not opened.

Currently this is what I have in ufw's before.rules and it works if port 2222 is also opened:

-A PREROUTING -p tcp --dport 22 -j REDIRECT --to-port 2222

Is there a way to do this prerouting without a need to have port 2222 opened?

2 Answers 2


In principle, no. Using ufw here isn't important, since it only acts as a frontend, creating iptables rules. As you noticed, the NAT rules are handled before any filtering, so the filter sees the resulting packet after any NAT rules. (Wikipedia has a rather scary looking chart of the packet flow inside netfilter, which represents them as independent.)

I'm not sure if it's much of a problem that the server can be reached on the other port too.

However, if you actually want to drop packets going directly to port 2222, you can do it with some trickery, using connection marks, i.e. the CONNMARK target and connmark module:

In the nat table, set a mark on the connection, and redirect it to the target port.

iptables -t nat -A PREROUTING -p tcp --dport 22 -j CONNMARK --set-mark 1234
iptables -t nat -A PREROUTING -p tcp --dport 22 -j REDIRECT --to-port 2222

In the filter (default) table, reject the connection if it doesn't have the mark.

iptables -A INPUT -p tcp --dport 2222 -m connmark ! --mark 1234 -j REJECT

It doesn't matter what the mark number is, as long as it doesn't collide with your other rules.

(I'm not sure if it would be possible to create DROP rules in the NAT table, too. iptables v1.4.21 doesn't seem to allow it, but the complaint comes from iptables itself, not from the kernel, like it does for REJECT.)


I rather use config instead of batch or running directly iptables in any way. And I always set DROP the default action for INPUT and OUTPUT in the filter table. Therefore my solution is that follows.



-A INPUT -p tcp --dport 2222 -m connmark ! --mark 1234

-A PREROUTING -p tcp --dport 22 -j REDIRECT --to-port 2222



-p tcp --dport 2222 -m connmark --mark 1234 -j ACCEPT

  • And what is the purpose of the mark here? Where is it set?
    – RalfFriedl
    Commented Aug 14, 2019 at 6:20

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .