SSH Server Hardening (Linux)
Disable password auth, lock down SSH to key-only access, change the default port, and restrict user logins. Works on Ubuntu, Debian, Fedora, and openSUSE.
bash# 1. Generate an SSH key pair on your LOCAL machine (skip if you have one)
# ssh-keygen -t ed25519 -C "your-email@example.com"
# 2. Copy your public key to the server (run from your LOCAL machine)
# ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server-ip
# 3. Run the rest ON THE SERVER after confirming key login works
# Back up original config
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
# Apply hardened settings
sudo tee /etc/ssh/sshd_config.d/99-hardened.conf > /dev/null <<'EOF'
# Disable password authentication — key-only
PasswordAuthentication no
PubkeyAuthentication yes
# Disable root login entirely
PermitRootLogin no
# Disable unused auth methods
ChallengeResponseAuthentication no
KbdInteractiveAuthentication no
UsePAM yes
# Limit login window
LoginGraceTime 30
MaxAuthTries 3
MaxSessions 5
# Disable forwarding unless needed
AllowTcpForwarding no
X11Forwarding no
AllowAgentForwarding no
# Only allow specific users (edit as needed)
# AllowUsers yourusername
# Use modern key exchange and ciphers only
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
EOF
# Validate config before restarting
sudo sshd -t && echo "Config OK — restarting SSH"
# Restart SSH (use the right service name for your distro)
sudo systemctl restart ssh 2>/dev/null || sudo systemctl restart sshd
What this does
Applies a drop-in config to /etc/ssh/sshd_config.d/99-hardened.conf that:
- Disables password authentication (prevents brute-force attacks)
- Disables root login
- Disables unused forwarding and agent features
- Restricts to modern cryptographic algorithms only
Why this approach
The default SSH configuration that ships with most Linux distributions is permissive in ways that matter for internet-facing or LAN-accessible servers. Password authentication is enabled, root login is allowed, and there’s no rate-limiting on authentication attempts. These defaults make sense during initial setup when you’re still configuring key access — they become liabilities the moment setup is complete.
Disabling password authentication is the highest-value single change. With only key authentication allowed, brute-force and credential-stuffing attacks simply don’t work — there’s no password to guess. The pre-requisite is having key-based access already working before you disable passwords; this playbook handles that by placing the change in a drop-in file (99-hardened.conf) and validating it with sshd -t before restarting the daemon.
Changing the default port from 22 has more limited security value — a port scan finds it immediately — but it effectively eliminates automated opportunistic attack traffic that exclusively targets port 22. In practice, moving to a high port number drops most auth-log noise from internet background scanning. This is most useful for internet-exposed servers; on a private LAN it matters less.
The AllowUsers directive (commented out in this playbook) is worth enabling as the vault grows: it creates an explicit allowlist of accounts that can authenticate over SSH, so a misconfigured service account or an old user that wasn’t deleted can’t become an unintended entry point.
Prerequisites
Critical: Copy your SSH public key to the server before disabling password auth, or you will lock yourself out.
# From your LOCAL machine:
ssh-keygen -t ed25519 -C "you@example.com" # if you don't have a key
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server-ip
Verify key login works in a separate terminal before proceeding.
Changing the default port (optional)
Add to 99-hardened.conf before restarting:
Port 2222
Then connect with ssh -p 2222 user@server and update any firewall rules.
Firewall (UFW — Ubuntu/Debian)
sudo ufw allow from trusted-ip to any port 22
sudo ufw deny 22
sudo ufw enable
Notes
- The
sshd -tcheck validates config before restart — if it fails, no changes are applied - Original config is backed up to
/etc/ssh/sshd_config.bak - On Fedora/RHEL the service is
sshd; on Debian/Ubuntu it’sssh AllowUsersdirective is commented out — uncomment and edit to whitelist specific accounts