Port knocking keeps a port, usually SSH, closed in the firewall until a client “knocks” by sending connection attempts to a secret sequence of other ports. A daemon watching the traffic sees the correct sequence and briefly opens SSH for that client’s IP. To scanners, the server shows no SSH port at all.
It’s a neat trick that removes nearly all brute-force noise. It’s also obscurity, not real authentication, so it’s worth knowing the trade-offs before you rely on it.
How it works
- The firewall drops all traffic to port 22.
knockdwatches incoming packets (via libpcap), even dropped ones.- The client sends packets to, say, TCP 7000, 8000, 9000, in that order and within a short time.
- knockd runs a command that allows port 22 from the client’s IP.
- You connect with SSH normally. Later, the rule is removed again.
Before you start: don’t lock yourself out
Have the provider’s VNC console ready and test carefully. If knockd isn’t running or the firewall rule is wrong, SSH is unreachable. See Linux rescue mode.
Install knockd
sudo apt install knockd
Find your interface name with ip -br link (for example eth0 or ens3).
Configure knockd
/etc/knockd.conf:
[options]
UseSyslog
Interface = eth0
[openSSH]
sequence = 7113:tcp,8522:tcp,9431:udp
seq_timeout = 10
tcpflags = syn
start_command = /usr/sbin/ufw insert 1 allow from %IP% to any port 22 proto tcp
cmd_timeout = 30
stop_command = /usr/sbin/ufw delete allow from %IP% to any port 22 proto tcp
- Pick random, high, non-sequential ports, and mix TCP and UDP.
start_commandopens SSH only for the knocking IP (%IP%).- After
cmd_timeoutseconds,stop_commandremoves the rule. Your established SSH session stays connected, because UFW allows established traffic. Only new connections need a new knock.
With plain iptables instead of UFW:
start_command = /sbin/iptables -I INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
stop_command = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
Enable the daemon. On Debian/Ubuntu, set START_KNOCKD=1 and KNOCKD_OPTS="-i eth0" in /etc/default/knockd, then:
sudo systemctl enable --now knockd
Close SSH in the firewall
Only after knockd is running, and with a console session ready:
sudo ufw delete allow OpenSSH # or: sudo ufw delete allow 22/tcp
sudo ufw status
Knock from the client
sudo apt install knockd # provides the 'knock' client (also available for macOS via Homebrew)
knock -v 203.0.113.10 7113:tcp 8522:tcp 9431:udp && ssh [email protected]
Without the client, use nmap or nc to hit each port in order. Wrap it in your ~/.ssh/config:
Host web1
HostName 203.0.113.10
ProxyCommand sh -c 'knock %h 7113:tcp 8522:tcp 9431:udp; sleep 1; nc %h %p'
Check the server log for knock events: journalctl -u knockd or grep knockd /var/log/syslog.
Limitations
- Replayable: anyone who can observe your traffic (shared Wi-Fi, an ISP, a compromised network) can see and replay the sequence. Variants with one-time sequences exist, but they’re more complex.
- NAT: if you’re behind carrier-grade NAT, the opened rule applies to a shared public IP.
- Packet loss or reordering can break the knock, especially with UDP.
- Another component to fail: if knockd crashes, you’re locked out until you use the console.
- Not authentication: SSH still needs strong authentication behind it.
Better modern alternatives
| Approach | Why |
|---|---|
| Key-only SSH + Fail2Ban | Brute force becomes pointless, with bans for noise. See key-only SSH |
| Firewall SSH to your IPs | Simple and strong if your IPs are stable |
| VPN or mesh VPN (WireGuard, Tailscale) | SSH not exposed to the internet at all. See WireGuard |
| Single Packet Authorization (fwknop) | Like port knocking, but with an encrypted, authenticated, non-replayable packet |
| Bastion host | One hardened entry point. See ProxyJump |
Port knocking can still be a fun extra layer on a personal server. For production, a VPN, IP allow-listing or SPA give similar invisibility with real cryptographic protection.
Quick reference
| Task | Command |
|---|---|
| Install | apt install knockd |
| Config | /etc/knockd.conf |
| Start | systemctl enable --now knockd |
| Knock | knock host p1:tcp p2:tcp p3:udp |
| Logs | journalctl -u knockd |
Related: UFW firewall and change SSH port.