Privacy Tools Guide

Every publicly accessible Linux server with SSH open on port 22 is scanned by automated bots within minutes of going online. These bots attempt thousands of common username/password combinations, looking for weak credentials. Hardening SSH closes the most common attack vectors and dramatically reduces your server’s exposure.

This guide covers the essential hardening steps for OpenSSH on a Linux server, ordered from highest to lowest impact.

Step 0: Back Up Working Access Before Starting

Before making any changes, ensure you have an alternative way to access the server (console access through your hosting provider, a second SSH session, etc.). Locking yourself out is a real risk when changing SSH configuration.

Step 1: Set Up SSH Key Authentication

Password authentication should be completely disabled. SSH key authentication is both more secure and more convenient.

Generate a key pair on your local machine

# Generate an Ed25519 key (preferred) with a comment
ssh-keygen -t ed25519 -C "your@email.com" -f ~/.ssh/id_ed25519

# Or RSA 4096 if Ed25519 isn't supported by your target
ssh-keygen -t rsa -b 4096 -C "your@email.com" -f ~/.ssh/id_rsa

Enter a strong passphrase. This protects the private key if your local machine is compromised.

Copy the public key to the server

ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server-ip

# Or manually:
cat ~/.ssh/id_ed25519.pub | ssh user@server-ip "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

Test key authentication before disabling passwords:

ssh -i ~/.ssh/id_ed25519 user@server-ip

Step 2: Harden sshd_config

Edit the main SSH server configuration file:

sudo nano /etc/ssh/sshd_config

Apply these settings:

# Disable password authentication entirely
PasswordAuthentication no
KbdInteractiveAuthentication no
UsePAM yes

# Disable root login
PermitRootLogin no

# Only allow specific users or groups to SSH (replace with your username)
AllowUsers yourusername

# Disable empty passwords
PermitEmptyPasswords no

# Use only modern key exchange algorithms
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512

# Restrict ciphers to strong options
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr

# Restrict MACs
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com

# Disable X11 forwarding (not needed on servers)
X11Forwarding no

# Disable TCP forwarding if not needed
AllowTcpForwarding no

# Disable agent forwarding
AllowAgentForwarding no

# Limit authentication attempts
MaxAuthTries 3

# Disconnect idle sessions after 10 minutes
ClientAliveInterval 600
ClientAliveCountMax 0

# Log level (INFO is appropriate for most; VERBOSE adds connection fingerprints)
LogLevel VERBOSE

# Disable host-based authentication
HostbasedAuthentication no
IgnoreRhosts yes

# Disable .rhosts files
RhostsRSAAuthentication no

# Only use SSH protocol 2
Protocol 2

Apply the changes:

# Test configuration before reloading
sudo sshd -t

# If no errors:
sudo systemctl reload sshd

Step 3: Change the Default SSH Port

Moving SSH off port 22 stops automated scans from the vast majority of bots (which only scan well-known ports). This is not a security control — a targeted attacker will port-scan and find your service — but it dramatically reduces noise in your logs and lowers the attack surface for opportunistic attacks.

In sshd_config:

Port 2222

Or use a port in the 49152-65535 range to avoid conflicts with other services.

Update your firewall:

# UFW
sudo ufw allow 2222/tcp
sudo ufw delete allow 22/tcp

# iptables
sudo iptables -A INPUT -p tcp --dport 2222 -j ACCEPT
sudo iptables -D INPUT -p tcp --dport 22 -j ACCEPT

Update your SSH client config to use the new port:

# ~/.ssh/config
Host myserver
    HostName server-ip
    Port 2222
    User yourusername
    IdentityFile ~/.ssh/id_ed25519

Step 4: Install and Configure fail2ban

fail2ban monitors SSH logs and bans IPs that have too many failed authentication attempts:

sudo apt install fail2ban

# Create a local jail configuration
sudo nano /etc/fail2ban/jail.local
[DEFAULT]
bantime  = 1h
findtime = 10m
maxretry = 3
banaction = iptables-multiport

[sshd]
enabled = true
port    = 2222    # Your SSH port
logpath = %(sshd_log)s
backend = %(sshd_backend)s
maxretry = 3
bantime  = 24h
sudo systemctl enable fail2ban
sudo systemctl start fail2ban

# Check ban status
sudo fail2ban-client status sshd

Step 5: Configure a Host-Based Firewall

Only allow SSH connections from trusted IP addresses where possible:

# UFW: allow SSH only from your home IP
sudo ufw allow from 203.0.113.10 to any port 2222 proto tcp

# Deny SSH from all other IPs
sudo ufw deny 2222/tcp

If you have a dynamic IP, this isn’t practical. In that case, rely on fail2ban and key-only auth.

Step 6: Audit Current SSH Sessions and Authorized Keys

Periodically check who is logged in and what keys have access:

# Check currently logged-in users
who
w

# Check active SSH sessions
ss -tnp | grep ssh
# or
sudo netstat -tnp | grep sshd

# Review all authorized keys
find /home -name "authorized_keys" -exec cat {} \;
sudo cat /root/.ssh/authorized_keys

# Check SSH login history
last | grep sshd | head -20

# Check failed login attempts
sudo grep "Failed password\|Invalid user" /var/log/auth.log | tail -30

# Check banned IPs from fail2ban
sudo fail2ban-client status sshd | grep "Banned IP"

Step 7: Enable SSH Certificates (Advanced)

For environments with multiple servers and users, SSH certificates are more manageable than distributing public keys:

# Create a Certificate Authority for your infrastructure
ssh-keygen -t ed25519 -f ssh_ca -C "Infrastructure CA"

# Sign a user's public key to create a certificate
ssh-keygen -s ssh_ca -I "username" -n "username" -V +52w ~/.ssh/id_ed25519.pub

# Configure sshd to trust the CA
echo "TrustedUserCAKeys /etc/ssh/ssh_ca.pub" | sudo tee -a /etc/ssh/sshd_config
sudo cp ssh_ca.pub /etc/ssh/ssh_ca.pub
sudo systemctl reload sshd

Now any key signed by your CA can authenticate without being individually added to authorized_keys on each server. Revocation is handled via a RevokedKeys file.

Verify the Hardening

# Test that password auth is disabled (should fail)
ssh -o PubkeyAuthentication=no user@server-ip -p 2222

# Run an SSH security audit
# Install ssh-audit
pip3 install ssh-audit
ssh-audit server-ip

# Or use the online tool at ssh-audit.com

A well-hardened server should score an “A” or “A+” on ssh-audit with no flagged algorithms.

Built by theluckystrike — More at zovo.one