1. Blog
  2. Manuals

Port Knocking: How to Hide the SSH Port on a Linux Server

Port Knocking: How to Hide the SSH Port on a Linux Server

Port knocking is a way to hide a service from strangers. The SSH port is closed by the firewall for everyone, and a scanner sees a server with no management ports open. To connect, a client first “knocks” on several closed ports in a set order — after the correct sequence the firewall opens SSH for that client’s IP address only.

When it makes sense

Port knocking is an extra layer, not the foundation of your security. It is useful when:

  • you connect from changing addresses and cannot restrict SSH to a list of IPs;
  • you want the server to drop out of mass scan results;
  • you want to hide the very existence of the service.

The foundation of SSH security is still keys instead of passwords. The knock sequence travels in clear text, and anyone who can see your traffic can replay it.

How it works

The knockd service watches incoming packets on a network interface. When connection attempts to the configured ports arrive from one address in the right order within the allowed time, it runs a command — adding a firewall rule that lets that address reach SSH. When the time runs out, or after a closing sequence, the rule is removed.

Step 1. Installation

Ubuntu and Debian:

sudo apt update
sudo apt install knockd

AlmaLinux, Rocky Linux (the package is in EPEL):

sudo dnf install epel-release
sudo dnf install knock-server

Step 2. Prepare the firewall

The rules below allow established connections and close SSH for new ones. Thanks to the first rule your current session is not dropped.

sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 22 -j REJECT

Save the rules so they survive a reboot:

sudo apt install iptables-persistent
sudo netfilter-persistent save

If you use UFW or firewalld, do not mix them with raw iptables rules: put the corresponding commands of your firewall into the knockd settings instead, for example ufw allow from %IP% to any port 22.

Step 3. Configure knockd

Find the network interface name:

ip -br a

Open the settings file:

sudo nano /etc/knockd.conf
[options]
    UseSyslog
    Interface = eth0

[SSH]
    sequence      = 7341,8523,9417
    seq_timeout   = 10
    tcpflags      = syn
    start_command = /usr/sbin/iptables -I INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
    cmd_timeout   = 30
    stop_command  = /usr/sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
  • sequence — the port sequence. Make up your own and do not use values from examples on the internet. Protocols can be mixed: 7341:tcp,8523:udp,9417:tcp;
  • seq_timeout — how many seconds are allowed for the whole sequence;
  • start_command — the command run after a correct knock; %IP% is replaced with the client’s address;
  • cmd_timeout — after how many seconds stop_command runs.

In this setup the port opens for 30 seconds. That is enough to connect: an established connection keeps working thanks to the ESTABLISHED rule, while the port closes again for new connections. No separate closing sequence is needed.

On Debian and Ubuntu, also set the interface and enable start-up in /etc/default/knockd:

START_KNOCKD=1
KNOCKD_OPTS="-i eth0"

Step 4. Start

sudo systemctl enable --now knockd
sudo systemctl status knockd

Step 5. Connect

Install the client on your computer: on Linux it is the same knockd package (the knock utility), on macOS brew install knock.

knock -d 300 203.0.113.10 7341 8523 9417
ssh root@203.0.113.10

-d 300 adds a 300 ms pause between packets so they arrive in the right order.

Without the knock client, nmap will do:

for p in 7341 8523 9417; do nmap -Pn --max-retries 0 -p $p 203.0.113.10 > /dev/null; done

On Windows the sequence can be sent from PowerShell:

7341,8523,9417 | ForEach-Object { Test-NetConnection 203.0.113.10 -Port $_ -WarningAction SilentlyContinue | Out-Null }

Knock and connect in one command

Add to ~/.ssh/config:

Host myserver
    HostName 203.0.113.10
    User root
    ProxyCommand sh -c "knock -d 300 %h 7341 8523 9417; sleep 1; nc %h %p"

Now ssh myserver sends the sequence itself before connecting.

Test

From another computer, confirm the port is closed:

nc -vz 203.0.113.10 22

Then send the sequence and repeat the check — the port should open. The service log shows what happens:

sudo journalctl -u knockd -f

A correct knock produces the lines Stage 1, Stage 2, Stage 3 and OPEN SESAME.

If it does not work

  • The port does not open. Check the interface name in the settings and increase the pause between knocks. The packets may have arrived in a different order.
  • The knocks do not arrive. The sequence ports may be filtered by your ISP or the hosting provider’s network firewall.
  • The command does not run. Check the path to iptables: which iptables.
  • You locked yourself out. Log in through the console in the control panel and delete the blocking rule: iptables -D INPUT -p tcp --dport 22 -j REJECT.

Alternatives

  • VPN. The most reliable way to hide management access: SSH is reachable only inside a WireGuard tunnel.
  • Fail2Ban. Does not hide the port but blocks brute force: see the setup guide.
  • Single Packet Authorization. An evolution of port knocking with encryption: instead of a knock sequence, one signed packet is sent that cannot be captured and replayed. The implementation is the fwknop project.

On a VPS where the administrator has a static address, it is simpler and safer to allow SSH from that address only.