Skip to main content

Command Palette

Search for a command to run...

SSH Port Knocking: Knock Knock. Who's There? Not the Bots.

Updated
8 min read
SSH Port Knocking: Knock Knock. Who's There? Not the Bots.

I was casually checking one of my server logs one evening(around 9:30 PM😁) and saw something annoying. Hundreds of failed SSH login attempts. From Nepal, China, Russia, Brazil, everywhere. Bots were hammering my SSH door (port 22), as it owed them money.

$ tail -f /var/log/auth.log
Jan 18 10:23:45 server sshd: Failed password for invalid user admin from 185.234.x.x
Jan 18 10:23:47 server sshd: Failed password for root from 103.45.x.x
Jan 18 10:23:48 server sshd: Failed password for invalid user test from 45.227.x.x

Now, I use key-based authentication, so these bots weren't getting in. But still, watching strangers knock on your door all day is not fun. So I went down a rabbit hole and found this old-school technique called port knocking.

Honestly, it felt like something from a spy movie. And it really works.


So What is Port Knocking?

Imagine your server is like a hidden bar during prohibition. The door looks just like a regular wall with no signs or handles. But if you knock in a secret pattern - three knocks, pause, two knocks - the door suddenly appears and lets you in.

That's port knocking.

Your SSH port stays closed. Completely invisible to anyone scanning. But when you knock on a secret sequence of ports in the right order, the firewall opens SSH just for your IP.

1. You knock on port 7777
2. You knock on port 8888  
3. You knock on port 9999
4. Server goes "ah, it's you!" and opens SSH
5. You connect normally
6. When done, knock the reverse sequence to close it again

A little daemon called knockd listens for these patterns. When it sees the right sequence from your IP, it runs an iptables command to let you through. Everyone else just sees a closed port.


Let's Set It Up

I'm on Ubuntu, but this works on most Linux distributions with iptables. You'll need sudo access and ideally a cup of tea/coffee/lemon-tea (not any other beverage😁) because we're doing this step by step.

Prerequisites

Before we dive in, make sure you have:

  • A Linux server (Ubuntu/Debian preferred, but any distro with iptables works)

  • Sudo or root access

  • SSH access to your server (obviously)

  • A second terminal is ready (trust me on this one)

  • Console access from your cloud provider as backup ( AWS, DigitalOcean, GCP, Vultr - they all have it)

That last point is important. If something goes wrong and you lock yourself out, console access is your "break glass in case of emergency" option. Don't skip setting this up.

Alright, let's do this.

Step 1: Move SSH to a Different Port

First things first. Let's get SSH off port 22. Every bot and their grandfather scans port 22. And here we're gonna be moving to a non-standard port.

sudo vim /etc/ssh/sshd_config

Find the Port line and change it:

# Change this
#Port 22

# To this
Port 13022

Why 13022? The 13th is my birthday date, unlucky for attackers, and 022 reminds me it's SSH. Pick whatever you like, just avoid obvious ones like 2222, 22222, etc.

Restart SSH:

sudo systemctl restart sshd

Now here's the important part. Don't close your current session. Open a new terminal and test:

ssh -p 13022 user@your-server-ip

If you can connect, great. If not, you still have your old session to fix things. Don't skip this step, or you might lock yourself out. Ask me how I know😞.

Step 2: Install knockd

sudo apt update
sudo apt install knockd -y

Step 3: Configure the Knock Sequence

Open the config:

sudo vim /etc/knockd.conf

Replace everything with:

[options]
    UseSyslog
    LogFile = /var/log/knockd.log

[openSSH]
    sequence    = 7777,8888,9999
    seq_timeout = 10
    command     = /sbin/iptables -I INPUT -s %IP% -p tcp --dport 13022 -j ACCEPT
    tcpflags    = syn

[closeSSH]
    sequence    = 9999,8888,7777
    seq_timeout = 10
    command     = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 13022 -j ACCEPT
    tcpflags    = syn

Quick breakdown:

  • sequence - your secret knock pattern

  • seq_timeout - you have 10 seconds to complete the knock

  • command - the iptables magic that runs when you knock correctly

  • %IP% - automatically replaced with your IP

  • tcpflags = syn - only listens for connection attempts

I'm using 7777, 8888, 9999 for this tutorial. For your actual server, pick something less obvious. Maybe your lucky numbers or a birthday. Just don't use 1234, 5678 - you get the idea.

Step 4: Tell knockd to Actually Start

By default, knockd is installed but disabled. Let's fix that:

sudo vim /etc/default/knockd

Change these:

START_KNOCKD=1
KNOCKD_OPTS="-i eth0"

For the interface name, check yours:

ip addr show

Look for the one with your public IP. Usually eth0 or ens3 or something similar.

Fire it up:

sudo systemctl start knockd
sudo systemctl enable knockd

Step 5: Lock the Door

Now the fun part. We block SSH by default, so only the knock can open it.

If you're using UFW, disable it first:

sudo ufw disable

We're using raw iptables here. You can also use the UFW command as explained here - Link.

# This keeps your current session alive - very important!
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# Allow localhost
sudo iptables -A INPUT -i lo -j ACCEPT

# Block SSH by default
sudo iptables -A INPUT -p tcp --dport 13022 -j REJECT

# Save the rules so they survive reboot
sudo apt install iptables-persistent -y
sudo netfilter-persistent save

That first rule is crucial. It tells iptables "don't kill existing connections." Without it, running the block rule would kick you out immediately. Not fun, SED LIFE!.

Do not close your current SSH session yet. Keep it open as a safety net while you test.


Testing Time

On your local machine, install the knock client:

# Ubuntu/Debian
sudo apt install knockd

# macOS
brew install knock

First, let's confirm the port is actually blocked:

ssh -p 13022 user@your-server-ip

You should get "Connection refused." Good. The door is locked.

Now perform the secret knock:

knock -v your-server-ip 7777 8888 9999

You'll see:

hitting tcp your-server-ip:7777
hitting tcp your-server-ip:8888
hitting tcp your-server-ip:9999

Quickly connect:

ssh -p 13022 user@your-server-ip

And you're in.

When you're done, close the door behind you:

knock -v your-server-ip 9999 8888 7777

Notice the reverse order. 9999, 8888, 7777. That's your "close" sequence.

No knock client? Telnet works too

telnet your-server-ip 7777
# Ctrl+C
telnet your-server-ip 8888
# Ctrl+C
telnet your-server-ip 9999
# Ctrl+C

You'll see "Connection refused" each time, but that's fine. The knock packets still get sent.


Making Life Easier with a Script

Typing the knock command every time gets old fast. Here's a simple script:

#!/bin/bash
# knock-ssh.sh

SERVER="your-server-ip"
SSH_PORT="13022"
USER="your-username"

echo "Performing secret knock..."
knock $SERVER 7777 8888 9999

sleep 1

echo "Opening the door..."
ssh -p $SSH_PORT $USER@$SERVER

echo "Closing the door..."
knock $SERVER 9999 8888 7777

Save it, make it executable:

chmod +x knock-ssh.sh
./knock-ssh.sh

One command to rule them all.


Watching the Magic Happen

Want to see Knockd in action? Check the logs:

sudo tail -f /var/log/knockd.log

When you knock correctly:

[2025-01-18 10:45:23] 203.0.113.50: openSSH: Stage 1
[2025-01-18 10:45:23] 203.0.113.50: openSSH: Stage 2
[2025-01-18 10:45:24] 203.0.113.50: openSSH: Stage 3
[2025-01-18 10:45:24] 203.0.113.50: openSSH: OPEN SESAME
[2025-01-18 10:45:24] openSSH: running command: /sbin/iptables -I INPUT -s 203.0.113.50 -p tcp --dport 13022 -j ACCEPT

"OPEN SESAME" - I didn't make that up, knockd actually says that. Whoever wrote this daemon had a sense of humor like mine!


A Few Things to Keep in Mind

Port knocking is clever, but it's not magic. Some limitations:

  • If someone is watching your network traffic, they can see the knock sequence.

  • Doesn't play well with CI/CD or automated deployments

  • If Knockd crashes, you might lock yourself out😔

This is perfect for personal servers, homelabs, and dev boxes. For production with a team, you probably want a VPN or something like Teleport.

Some tips from experience:

  • Always have console access as backup. Cloud providers have web-based consoles. Use them if you lock yourself out.

  • Don't use sequential ports like 1000, 2000, 3000. Too easy to guess.

  • Keep your knock sequence to yourself.

  • Still use key-based SSH authentication. Port knocking is an extra layer, not a replacement.


Quick Reference

# Install
sudo apt install knockd

# Config file
/etc/knockd.conf

# Enable on boot
sudo vim /etc/default/knockd  # Set START_KNOCKD=1

# Start the service
sudo systemctl enable --now knockd

# Knock from client
knock -v server-ip port1 port2 port3

# Check logs
sudo tail -f /var/log/knockd.log

That's it. Your SSH server is now basically invisible. Port scanners see nothing. Bots find nothing to attack. Only you with the secret knock can get in.

My auth.log has been so much quieter since I set this up. No more watching random IPs fail to guess "admin" as a username fifty times a minute.

Hope this saves you some headaches, too.

#devops #security #linux #ssh #networking

Thanks! JADAU!

But Wait... There's More! (Bonus)

Port knocking works at the firewall level. You can use it for any port:

  • PostgreSQL (5432)

  • MySQL (3306)

  • Redis (6379)

  • Admin panels

  • Internal APIs

  • Literally anything

You just add more blocks in /etc/knockd.conf:

[openPostgres]
    sequence    = 5555,6666,7777
    seq_timeout = 10
    command     = /sbin/iptables -I INPUT -s %IP% -p tcp --dport 5432 -j ACCEPT
    tcpflags    = syn

[closePostgres]
    sequence    = 7777,6666,5555
    seq_timeout = 10
    command     = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 5432 -j ACCEPT
    tcpflags    = syn

Different knock sequences for each service.

More from this blog

S

Sagar Budhathoki

17 posts

A Python/DevOps Engineer with hands-on experience in cloud computing, automating and optimizing mission-critical deployments in AWS, leveraging configuration management, CI/CD, etc. AI/ML enthusiast.