OpenClaw SSH Hardening: Keys, Fail2ban, and Locking Down Remote Access
OpenClaw SSH Hardening: Keys, Fail2ban, and Locking Down Remote Access
SSH with password authentication is a liability on any public server. Automated bots scan the internet constantly looking for SSH servers, and they run credential lists against them continuously. Your server is getting probed right now — check your auth logs and you'll see it.
SSH keys eliminate the brute-force attack surface entirely. Fail2ban adds a second layer: 3 failed attempts from any IP = 24-hour ban, automated. Together, they make unauthorized SSH access nearly impossible.
This is the complete setup.
Why Password-Based SSH Is a Liability
Password authentication has one fundamental problem: passwords can be guessed. Automated tools run through millions of common passwords and credential combinations against any open SSH server. Given enough time or a weak password, they succeed.
The solution isn't "use a stronger password" — it's to remove passwords from the equation entirely. SSH key authentication uses asymmetric cryptography: a key pair where the private key never leaves your local machine and the public key sits on the server. There's nothing to brute-force. No password = no credential to guess.
Fail2ban complements this by monitoring the SSH log file and automatically blocking IPs that fail authentication repeatedly. Even against bots that cycle through IP addresses, it drastically reduces the attack bandwidth.
Part 1: SSH Key Setup
Step A: Generate an Ed25519 Key Pair (on your local machine)
ssh-keygen -t ed25519 -C "your-email@example.com"
Press Enter three times to accept the defaults (default file location, no passphrase). This creates two files:
~/.ssh/id_ed25519— your private key (never share this)~/.ssh/id_ed25519.pub— your public key (goes on the server)
ed25519 is the recommended key type in 2026. It's faster, more secure, and produces shorter keys than RSA.
Step B: Copy the Public Key to Your Server
ssh-copy-id openclaw@YOUR_SERVER_IP
This command:
- Reads your public key (
~/.ssh/id_ed25519.pub) - Connects to the server using your current password
- Appends the public key to
~/.ssh/authorized_keyson the server
You'll need to enter your SSH password once for this step. After this, the password isn't needed anymore.
If ssh-copy-id isn't available on your system:
# Manual alternative
cat ~/.ssh/id_ed25519.pub | ssh openclaw@YOUR_SERVER_IP "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
Step C: Test Key Authentication Before Disabling Passwords
# Open a NEW terminal and test
ssh openclaw@YOUR_SERVER_IP
If you connect without being prompted for a password, key auth is working. If it still asks for a password, something went wrong — troubleshoot before the next step.
⚠️ This test is critical. Do not proceed to disabling password auth until you've verified key auth works in a separate terminal. If you disable passwords and key auth is broken, you're locked out.
Part 2: Disable Password Authentication
With key auth confirmed working, edit the SSH daemon config on the server:
sudo nano /etc/ssh/sshd_config
Find and modify these lines (or add them if they're missing):
PasswordAuthentication no
PermitRootLogin no
Make sure there are no duplicate lines with conflicting values — search the file for both settings and ensure only the no version exists.
Save and exit: Ctrl+X → Y → Enter
Restart the SSH daemon:
sudo systemctl restart sshd
⚠️ Test again from your existing terminal session. Try SSHing in from the other terminal you left open. If it connects successfully (using your key), close the first session. If it fails, you can still fix things from the first session.
Part 3: Install and Configure Fail2ban
Even with key authentication, having Fail2ban running adds value. It:
- Blocks bots before they waste connection attempts
- Protects other services on the server (not just SSH)
- Reduces log noise from automated scanners
sudo apt update
sudo apt install fail2ban -y
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
Fail2ban's default SSH protection (jail.local) kicks in automatically on Debian/Ubuntu. By default it bans IPs after 5 failed attempts for 10 minutes. To tighten this to 3 attempts for 24 hours, create a custom jail:
sudo nano /etc/fail2ban/jail.local
Add:
[sshd]
enabled = true
maxretry = 3
bantime = 86400
findtime = 600
maxretry = 3— ban after 3 failed attemptsbantime = 86400— ban lasts 24 hours (86400 seconds)findtime = 600— counts failures within a 10-minute window
Restart Fail2ban to apply changes:
sudo systemctl restart fail2ban
Verifying Everything Works
Check SSH config is correct:
grep "PasswordAuthentication\|PermitRootLogin" /etc/ssh/sshd_config
# Should show:
# PasswordAuthentication no
# PermitRootLogin no
Check Fail2ban is running:
sudo systemctl is-active fail2ban
# Should show: active
Check Fail2ban SSH jail status:
sudo fail2ban-client status sshd
This shows: currently banned IPs, total bans, failed attempts. Once bots start probing, you'll see bans accumulating here.
Check banned IPs:
sudo fail2ban-client status sshd | grep "Banned IP"
After a day or two on a public server, you'll typically see dozens of bans from automated scanners. That's Fail2ban working.
Troubleshooting
Locked yourself out of SSH:
If you're locked out (disabled password auth before testing key auth), you'll need to use your VPS provider's console access (Hostinger, DigitalOcean, and Linode all have browser-based console access for this exact situation).
"Permission denied (publickey)" error:
# Check key permissions on local machine
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub
# Check authorized_keys on server
ls -la ~/.ssh/authorized_keys
# Should be 600
chmod 600 ~/.ssh/authorized_keys
Fail2ban doesn't seem to be banning:
# Check Fail2ban logs
sudo journalctl -u fail2ban -n 50
# Verify the SSH log it's monitoring
sudo fail2ban-client get sshd logpath
Can't find the sshd_config file:
sudo find /etc -name "sshd_config" 2>/dev/null
On some systems it's at /etc/ssh/sshd_config.d/*.conf.
The Verification Script for This Step
Run this to confirm SSH hardening is complete:
echo "=== SSH CONFIG ==="
grep "PasswordAuthentication\|PermitRootLogin" /etc/ssh/sshd_config
echo ""
echo "=== FAIL2BAN STATUS ==="
sudo systemctl is-active fail2ban
sudo fail2ban-client status sshd 2>/dev/null | head -10
echo ""
echo "=== AUTHORIZED KEYS ==="
ls -la ~/.ssh/authorized_keys 2>/dev/null || echo "No authorized_keys file found"
A healthy output shows:
PasswordAuthentication noPermitRootLogin nofail2ban: activeauthorized_keyswith600permissions
Key Takeaways
- SSH key authentication replaces password guessing with cryptographic authentication — there's nothing to brute-force
- Generate ed25519 keys (not RSA):
ssh-keygen -t ed25519 - Always test key auth in a new terminal before disabling password auth — this is how people lock themselves out
- Set
PasswordAuthentication noandPermitRootLogin noin/etc/ssh/sshd_config, thensystemctl restart sshd - Fail2ban defaults to 5 attempts/10 min ban; tighten to 3 attempts/24 hours with a
jail.localconfig - After a day on a public server, check
fail2ban-client status sshd— you'll see automated bots being blocked constantly
Learn alongside 1,000+ operators
Ask questions, share workflows, and get help from people running OpenClaw every day.
📚 Explore More
Rate Limits & Quota Management — Avoid Downtime
Getting HTTP 429 rate limit errors? Learn how to configure model fallbacks, rotate API keys, understand cooldown periods, and keep your agent running when quotas are exhausted.
How to Configure OpenClaw: Complete Settings Guide (2026)
Configure OpenClaw in ~/.openclaw/openclaw.json: API keys, model providers, channels (WhatsApp/Telegram/Discord), security, and multi-agent routing. Copy-paste examples included.
AI Assistant for Remote Workers
Stay productive from anywhere
1Password
Connect OpenClaw to 1Password for secure credential management. Inject secrets into skills, access vaults, and manage credentials programmatically.