Affiliate disclosure — This article contains Contabo affiliate links. If you order a VPS via our links, we earn a commission at no extra cost to you. Every command is tested on our own production VPS.
You self-host WireGuard on Contabo. Everything works. Except your UDP port 51820 has been in Shodan for 3 days, your VPS gets thousands of scan packets per hour, and you see WireGuard handshakes rejected from botnets in journalctl. If your WireGuard is properly configured (strong public key, no shared PSK), you have nothing to fear cryptographically — but the noise pollutes logs, wastes CPU, and one day someone may find a vulnerability.
Port knocking is an old but effective technique to fix this: your WireGuard endpoint stays closed by default (UFW drop), and only opens after a "knock sequence" (a series of TCP connection attempts on specific ports in a specific order). The client taps the sequence, the firewall temporarily opens the WireGuard port, the session is established, the port closes. To Shodan, your VPS exposes no UDP/51820 port — you're invisible.
This guide covers knockd install on a Contabo VPS, the secure sequence, fail2ban integration, and an automated deployment script to reproduce the setup on multiple VPS.
The principle: three doors, one combination
Port knocking works like a coded doorbell. You define a port sequence (e.g. 7001 → 8002 → 9003) and an order. The client sends a simple TCP/SYN attempt to each port in order. No service listens on those ports — the firewall LOGs the packets and moves on.
When the knockd daemon sees the valid sequence from a single IP in under 30 seconds, it runs a command: typically iptables -A INPUT -s <ip> -p udp --dport 51820 -j ACCEPT. The client IP is temporarily allowed. A few seconds later, knockd closes: iptables -D INPUT ....
Advantage: to an external scanner (Shodan, Censys, masscan), your port 51820 NEVER responds. It's not listed. Limit: this is not cryptography. Someone sniffing your traffic can see the knocks and replay them. That's why we combine with WireGuard (which provides the strong cryptographic auth).
Install on a Contabo VPS
Contabo VPS S (€4.99/month, see deal) on Ubuntu 24.04 LTS, WireGuard already installed and working (if not yet: see our WireGuard self-host guide).
Step 1 — Install knockd
apt update && apt install -y knockd
Step 2 — Close WireGuard by default
First, check your current firewall:
ufw status verbose
If UFW allows 51820/udp wide open, we'll replace it with "closed by default + opened by knockd". Edit /etc/default/ufw or directly iptables:
ufw delete allow 51820/udp
# WireGuard is now DROP by default
Verify: from outside, nmap -sU -p 51820 your-ip should return filtered or closed.
Step 3 — Configure knockd
/etc/knockd.conf:
[options]
UseSyslog
Interface = eth0
[openWireGuard]
sequence = 7203,4581,6217
seq_timeout = 15
command = /usr/sbin/iptables -I INPUT -s %IP% -p udp --dport 51820 -j ACCEPT
tcpflags = syn
[closeWireGuard]
sequence = 6217,4581,7203
seq_timeout = 15
command = /usr/sbin/iptables -D INPUT -s %IP% -p udp --dport 51820 -j ACCEPT
tcpflags = syn
Key fields:
sequence: your knock ports. Not sequential (not 1234,1235,1236), pick them at random between 1024 and 65000.seq_timeout: 15 seconds to complete the sequence from the same IP. Too short, mobile latency issues. Too long, brute-force attack window widens.command: what's run when the sequence is valid.%IP%is replaced with the source IP of the knock.tcpflags:synto match only the initial connection packet (avoids false positives).
For auto-close after 60 seconds instead of a manual knock, use cmd_timeout:
[openWireGuard]
sequence = 7203,4581,6217
seq_timeout = 15
command = /usr/sbin/iptables -I INPUT -s %IP% -p udp --dport 51820 -j ACCEPT
tcpflags = syn
cmd_timeout = 60
stop_command = /usr/sbin/iptables -D INPUT -s %IP% -p udp --dport 51820 -j ACCEPT
This is cleaner: no need for the client to send a "close knock", knockd closes by itself after 60s. WireGuard has established its UDP session in the meantime, which stays active.
Step 4 — Enable knockd
/etc/default/knockd:
START_KNOCKD=1
KNOCKD_OPTS="-i eth0"
systemctl enable --now knockd
journalctl -u knockd -f
Client-side knocker
Linux / macOS: install the knockd package (it also ships the knock client):
apt install knockd # Ubuntu/Debian
brew install knock # macOS via Homebrew
Usage:
knock your-vps-ip 7203 4581 6217
Wait 1–2 seconds, then bring WireGuard up normally:
wg-quick up wg0
You have 60 seconds for WireGuard to complete its UDP handshake. Once the session is active, knockd can close the firewall: the existing connection is not affected by new INPUT rules.
Windows: no officially maintained knock.exe port. Pragmatic workaround: a PowerShell script doing 3 fast Test-NetConnections:
$ip = "your-vps-ip"
$ports = 7203, 4581, 6217
foreach ($p in $ports) {
Test-NetConnection -ComputerName $ip -Port $p -InformationLevel Quiet
Start-Sleep -Milliseconds 200
}
Start-Sleep -Seconds 1
# Launch the WireGuard app here
Android: app KnockOnD on the Play Store (free). Configure IP + sequence, tap the button, knocks are sent. Combine with WireGuard Android: after the knock, bring the tunnel up manually.
iOS: PortKnock on the AppStore (free). Same principle.
Hardening: avoiding knock-replay
A plain knock has a weakness: if someone sniffs your traffic (public Wi-Fi, hostile ISP, etc.), they can replay the sequence from their IP and get the firewall opened. Three mitigations:
1. fail2ban on invalid knocks
Ban IPs that perform 5+ invalid knocks (not completing the sequence). Create /etc/fail2ban/filter.d/knockd.conf:
[Definition]
failregex = ^.*knockd.*<HOST>:.*: Stage \d failed.*$
ignoreregex =
And /etc/fail2ban/jail.d/knockd.conf:
[knockd]
enabled = true
filter = knockd
logpath = /var/log/syslog
maxretry = 5
findtime = 60
bantime = 3600
Reload: systemctl reload fail2ban.
2. one-time knock sequences (knockd 0.8+)
Use single-use sequences via one_time_sequences:
[openWireGuard]
one_time_sequences = /etc/knockd/sequences.list
seq_timeout = 15
command = /usr/sbin/iptables -I INPUT -s %IP% -p udp --dport 51820 -j ACCEPT
tcpflags = syn
cmd_timeout = 60
stop_command = /usr/sbin/iptables -D INPUT -s %IP% -p udp --dport 51820 -j ACCEPT
The /etc/knockd/sequences.list file holds one sequence per line. Once used, it's removed. You pre-generate 100 sequences, distribute them to the client (encrypted file), and each connection burns one.
This is significantly more secure against replay, at the cost of trickier management.
3. Combine with a bootstrap VPN
Elegant approach: your VPS exposes only a Shadowsocks or V2Ray on 443 (camouflage mode). The WireGuard knocks are sent through this first SS/V2Ray tunnel. External sniff only sees TLS toward your domain, not the knocks.
This is the "belt-and-suspenders" setup for ultra-sensitive travel.
Automated deployment script
To reproduce this setup on multiple Contabo VPS, here's a script we use. Drop it in /usr/local/bin/setup-knock-wg.sh:
#!/bin/bash
set -euo pipefail
if [[ $EUID -ne 0 ]]; then
echo "Run this script as root"
exit 1
fi
# Generate 3 random ports between 5000 and 60000
PORT1=$(( ( RANDOM % 55000 ) + 5000 ))
PORT2=$(( ( RANDOM % 55000 ) + 5000 ))
PORT3=$(( ( RANDOM % 55000 ) + 5000 ))
echo "Generated sequence: $PORT1 -> $PORT2 -> $PORT3"
apt update && apt install -y knockd fail2ban
cat > /etc/knockd.conf <<EOF
[options]
UseSyslog
Interface = eth0
[openWireGuard]
sequence = ${PORT1},${PORT2},${PORT3}
seq_timeout = 15
command = /usr/sbin/iptables -I INPUT -s %IP% -p udp --dport 51820 -j ACCEPT
tcpflags = syn
cmd_timeout = 60
stop_command = /usr/sbin/iptables -D INPUT -s %IP% -p udp --dport 51820 -j ACCEPT
EOF
sed -i 's/START_KNOCKD=0/START_KNOCKD=1/' /etc/default/knockd
# Close WireGuard by default
ufw delete allow 51820/udp 2>/dev/null || true
# fail2ban config
cat > /etc/fail2ban/filter.d/knockd.conf <<EOF
[Definition]
failregex = ^.*knockd.*<HOST>:.*: Stage \d failed.*\$
ignoreregex =
EOF
cat > /etc/fail2ban/jail.d/knockd.conf <<EOF
[knockd]
enabled = true
filter = knockd
logpath = /var/log/syslog
maxretry = 5
findtime = 60
bantime = 3600
EOF
systemctl enable --now knockd
systemctl reload fail2ban
echo ""
echo "Setup complete!"
echo "Client: knock $(curl -s ifconfig.me) ${PORT1} ${PORT2} ${PORT3}"
echo "Keep this sequence safe — password manager recommended."
Make executable and run:
chmod +x /usr/local/bin/setup-knock-wg.sh
/usr/local/bin/setup-knock-wg.sh
You get the client-side sequence as output. Save it in Bitwarden / 1Password / KeePass — it's a secret just like your SSH key.
Validation: test that it works
1. From outside (your laptop, not the VPS) — confirm 51820 is closed:
nmap -sU -p 51820 your-vps-ip
# PORT STATE SERVICE
# 51820/udp filtered (or closed) — no response
2. Still from outside — knock + WireGuard attempt:
knock your-vps-ip 7203 4581 6217
sleep 2
wg-quick up wg0
wg show wg0 # should show a handshake
3. Server side — check the log:
journalctl -u knockd | tail -20
# Should show: openWireGuard: Stage 3 OK
# openWireGuard: OPEN SESAME
# openWireGuard: running command
4. Confirm the firewall closes after cmd_timeout:
# On the server, wait 60s then:
iptables -L INPUT -n | grep 51820
# No rule for your IP. WireGuard session stays active thanks to conntrack.
Typical use cases
1. Self-hosting for yourself, annoyed by Shodan noise. Perfect setup: 5 minutes of config, you're no longer in Shodan, your logs are clean. No client-side change for mobile WireGuard (just a knock before each connection).
2. Self-hosting for a few advanced users. Distribute a one-time sequence per user. Each user has their individual sequence. If one leaks, you revoke that sequence without affecting the others.
3. Resilient multi-VPS setup. Each Contabo VPS has its own random sequence. The client has a fallback list: if VPS1 doesn't respond (failed knock or IP down), it knocks VPS2, etc.
4. Inverted honeypot. Combined with psad or crowdsec, IPs that scan your knock ports invalidly end up in a community blacklist. You become a threat-intel sensor.
Limits and alternatives
Port knocking isn't magic:
- If someone has passive access to your LAN traffic (enterprise proxy MITMing TLS), they can see the knocks and replay them.
- If your mobile client is on a cell network where the operator logs everything, same.
- If your VPS is a bit slow,
seq_timeout = 15smay be too short on edge-of-coverage 3G.
Alternatives to consider:
| Need | Solution |
|---|---|
| Hide VPN endpoint from scans | Port knocking (this guide) |
| Hide AND resist sniffing | Cloak (see our guide) |
| Bypass national DPI (GFW, etc.) | V2Ray + REALITY (see our guide) |
| Strong cryptographic auth only | Plain WireGuard, peering OK |
| Pro multi-user setup | Xray-core + x-ui dashboards |
Port knocking is complementary, not a substitute. You can stack: port knocking + Cloak + WireGuard, giving you a near-invisible setup. At the cost of increased operational complexity.
When a commercial VPN is simpler
If you don't want to manage knockd + fail2ban + UFW + WireGuard, a commercial VPN spares you all that. NordVPN doesn't give you low-level control, but its servers are shared (so natural scan dilution). You aren't the identifiable target.
Many of our readers combine: self-host with port knocking for daily use (peak perf, fixed IP), commercial VPN as travel backup (no maintenance).
Further reading
- Self-host VPN on Contabo: complete WireGuard guide 2026
- Cloak: TLS obfuscation for self-host VPN
- V2Ray VMess/VLess: complete setup 2026
- VPN killswitch Linux: iptables + systemd
Technical sources:
- knockd official documentation
- Original port knocking paper — M. Krzywinski, 2003
- fail2ban GitHub
- WireGuard whitepaper — Jason A. Donenfeld
Published 2026-06-03. Setup tested on a Contabo VPS S Nuremberg + residential clients in Europe, March–April 2026. Port knocking is a complementary defense layer, not a silver bullet — always combine with strong WireGuard auth and fail2ban.
Legal reminder: port knocking and WireGuard self-host are perfectly legal in the EU, US, Canada. Check local regulations before deploying in sensitive jurisdictions. VPNSmith publishes this guide for educational purposes.
★ Datacenter Nuremberg GDPR · ✓ IPv4 dédiée incluse · 200+ Mbps garantis
Get Contabo30 jours satisfait ou remboursé→