Port knocking is a stealthy technique that keeps SSH’s port 22 invisible to network scanners until a client sends a precise sequence of connection attempts to predetermined ports. On RHEL 8, combining knockd with firewalld creates a powerful two-layer defense: the firewall silently drops all traffic on port 22 by default, and only the knock daemon can open it temporarily. This approach dramatically reduces your SSH attack surface without changing how authorized users connect. In this tutorial you will install and configure knockd from EPEL 8, set the default firewall policy to DROP for SSH, and test the full knock-open-connect-close cycle.
Prerequisites
- RHEL 8 server with a non-root sudo user
- Active internet connection or local EPEL 8 mirror
firewalldrunning and managing the default zone- A second machine (or the same machine via loopback) to test knocking
- Existing SSH access established before locking down port 22
Step 1 — Enable EPEL 8 and Install knockd
The knock-server package provides the knockd daemon and is available in the Extra Packages for Enterprise Linux (EPEL) repository. Install EPEL first, then install the server and the client-side knock utility.
dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
dnf install -y knock-server
Verify the installed files:
rpm -ql knock-server
You should see /usr/sbin/knockd, the unit file at /usr/lib/systemd/system/knockd.service, and the default configuration at /etc/knockd.conf.
Step 2 — Configure the Knock Sequence
Edit /etc/knockd.conf to define the opening sequence (7000 → 8000 → 9000) and the closing sequence (9000 → 8000 → 7000). The openSSH block runs a firewall-cmd command to allow port 22 for 30 seconds; the closeSSH block removes that rule.
cat > /etc/knockd.conf << 'EOF'
[options]
UseSyslog
Interface = eth0
[openSSH]
sequence = 7000,8000,9000
seq_timeout = 10
tcpflags = syn
command = /usr/bin/firewall-cmd --add-rich-rule='rule family="ipv4" source address="%IP%" port port=22 protocol=tcp accept' --timeout=30
[closeSSH]
sequence = 9000,8000,7000
seq_timeout = 10
tcpflags = syn
command = /usr/bin/firewall-cmd --remove-rich-rule='rule family="ipv4" source address="%IP%" port port=22 protocol=tcp accept'
EOF
Replace eth0 with your actual network interface name (check with ip -o link show | awk '{print $2}' | tr -d ':'). The %IP% placeholder is automatically substituted with the knocking client’s IP address by knockd, restricting the SSH window to that source only.
Step 3 — Drop Port 22 by Default in firewalld
With knockd configured, remove the permanent SSH service rule from the default zone so that port 22 is silently dropped unless a valid knock sequence has been received.
# Find your active zone
firewall-cmd --get-active-zones
# Remove the ssh service from the public zone permanently
firewall-cmd --permanent --zone=public --remove-service=ssh
# Reload to apply
firewall-cmd --reload
# Verify port 22 is no longer listed
firewall-cmd --list-all
Important: Do this from an active SSH session that you can keep open; the existing established connection will not be dropped. Have a recovery plan (console access or cloud provider serial console) in case something goes wrong.
Step 4 — Enable and Start knockd
Enable the knockd service so it starts on boot, then start it and verify it is listening on all three knock ports.
systemctl enable --now knockd
systemctl status knockd
# Confirm knockd is capturing packets on the interface
journalctl -u knockd -n 20
The journal should show lines such as Starting Port Knock Daemon and confirm the interface and sequences loaded without errors.
Step 5 — Install the knock Client and Test
On RHEL 8, the client utility is included in the knock package. Install it on your workstation or on the server itself for a loopback test.
# On the client machine (also RHEL 8)
dnf install -y knock
# Send the opening knock sequence to the server
knock -v SERVER_IP 7000 8000 9000
# Immediately attempt SSH; you have 30 seconds
ssh user@SERVER_IP
# After your session, send the closing sequence
knock -v SERVER_IP 9000 8000 7000
Watch journalctl -u knockd -f on the server in a separate terminal. You should see entries like openSSH: Stage 1, Stage 2, Stage 3, and finally OPEN SESAME followed by the firewall command executing.
Step 6 — Security Considerations and Hardening
Port knocking inspects TCP SYN packets at the network layer — the secret lives in the sequence of port numbers, not in any payload data, so it is not detectable by payload inspection. Keep these additional hardening points in mind:
# Protect knockd.conf (contains your secret sequence)
chmod 600 /etc/knockd.conf
chown root:root /etc/knockd.conf
# Optionally obfuscate the sequence further with UDP knock ports
# Change tcpflags = syn to protocol = udp in knockd.conf
# Rotate your knock sequence periodically; update both server and clients
# Consider using one-time sequences (OTP) with a custom script for high-security environments
# Log all failed knock attempts for intrusion detection
grep "Door Knock" /var/log/messages | tail -20
Never store the knock sequence in plain text on the client. Use a shell alias or a small wrapper script in your home directory with restricted permissions (chmod 700). Pair port knocking with other hardening measures such as fail2ban, key-based SSH authentication only, and SELinux in enforcing mode for a layered defense posture.
Conclusion
You have successfully installed knockd from EPEL 8, configured a three-port knock sequence that grants a 30-second SSH window to the knocking client’s IP, set firewalld to drop port 22 by default, and verified the full open-connect-close cycle. Port knocking will eliminate the constant background noise of automated SSH brute-force scanners from your logs and reduce your exposure to zero-day vulnerabilities in the SSH daemon.
Next steps: How to Configure fail2ban on RHEL 8, How to Harden SSH with Key-Based Authentication on RHEL 8, and How to Set Up Suricata IDS/IPS on RHEL 8.