SSH Cheatsheet

Hardening the Server

Use this SSH reference while you build software engineering projects, review code, or refresh the syntax you reach for most.

Configuration File

All settings go in /etc/ssh/sshd_config. After every change:

# Test config syntax before reloading
sudo sshd -t

# Reload (keep existing sessions alive)
sudo systemctl reload sshd

# Full restart (drops existing sessions)
sudo systemctl restart sshd

Essential Hardening Settings

# /etc/ssh/sshd_config

# Disable password auth — key-only
PasswordAuthentication no
ChallengeResponseAuthentication no
KbdInteractiveAuthentication no   # OpenSSH 8.7+

# Disable root login
PermitRootLogin no
# (or: PermitRootLogin prohibit-password  — allows root with key only)

# Disable empty passwords
PermitEmptyPasswords no

# Move off port 22 (reduces noise, not real security)
Port 2222

# Restrict to specific users or groups
AllowUsers alice bob
AllowGroups sshusers

# Limit authentication attempts
MaxAuthTries 3
MaxSessions 5
MaxStartups 10:30:60    # start:rate:max half-open connections

# Set an auth timeout
LoginGraceTime 30       # seconds before unauthenticated connection dropped

# Disable X11 and agent forwarding if not needed
X11Forwarding no
AllowAgentForwarding no
AllowTcpForwarding no

# Disable tunneled plaintext passwords in PAM
UsePAM yes              # keep yes; the above PasswordAuthentication no is what locks it

# Banner (shown before auth — legal notice)
Banner /etc/ssh/banner.txt

# Log level
LogLevel VERBOSE        # or INFO; avoid QUIET in prod

Restrict to Modern Algorithms

# /etc/ssh/sshd_config — strong crypto only (OpenSSH 8.x+)
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512
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
HostKeyAlgorithms ssh-ed25519,rsa-sha2-512,rsa-sha2-256

Run ssh -Q kex, ssh -Q cipher, ssh -Q mac to see what your client supports.

Host-Based Access Control

/etc/ssh/sshd_config Match blocks

# Allow password auth only from the internal network
Match Address 10.0.0.0/8
    PasswordAuthentication yes

# Lock down a specific user further
Match User deploy
    ForceCommand /usr/local/bin/deploy.sh
    PermitTTY no
    AllowTcpForwarding no

/etc/hosts.allow and /etc/hosts.deny (TCP Wrappers)

# /etc/hosts.allow
sshd: 192.168.1.0/24

# /etc/hosts.deny
sshd: ALL

Fail2ban (Rate-Limit Brute Force)

apt install fail2ban    # Debian/Ubuntu

# /etc/fail2ban/jail.local
[sshd]
enabled  = true
port     = 2222         # match your Port directive
maxretry = 5
bantime  = 3600
findtime = 600
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd     # check bans
sudo fail2ban-client set sshd unbanip 1.2.3.4

Firewall (ufw / iptables)

# ufw — allow SSH on custom port, deny others
ufw allow 2222/tcp
ufw enable

# iptables — rate-limit SSH connections
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --set
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 -j DROP

Two-Factor Authentication (TOTP)

# Install
apt install libpam-google-authenticator

# Run per user
google-authenticator

# /etc/pam.d/sshd — add at the top
auth required pam_google_authenticator.so

# /etc/ssh/sshd_config
KbdInteractiveAuthentication yes
AuthenticationMethods publickey,keyboard-interactive

Key Rotation Checklist

  1. Generate a new key pair (ssh-keygen -t ed25519)
  2. Add new public key to authorized_keys
  3. Test login with the new key
  4. Remove the old key from authorized_keys
  5. Delete or archive the old private key

Audit: Who Can Log In

# Check authorized keys for all users
find /home -name authorized_keys -exec echo "=== {} ===" \; -exec cat {} \;
cat /root/.ssh/authorized_keys 2>/dev/null

# Check active SSH sessions
who
ss -tnp | grep :22
last | head -20

# Recent auth failures
grep "Failed password\|Invalid user" /var/log/auth.log | tail -20
journalctl -u sshd --since "1 hour ago" | grep -i fail