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
  • firewalld running 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.