Table of Contents
Why SSH Security Matters
SSH (Secure Shell) is usually the primary way to remotely administer Linux systems. If SSH is compromised, an attacker effectively gets a shell on your machine with your privileges (or root, if they can escalate). This chapter focuses on practical, baseline measures to harden SSH on typical Linux servers.
You’ll use:
- The SSH server config:
/etc/ssh/sshd_config - The SSH client config:
/etc/ssh/ssh_configand~/.ssh/config - The
ssh,sshd, andsshd-keygentools - Systemd commands like
systemctl restart sshd(name may besshon some distros)
Assume SSH is already installed and working; here we focus on making it safer.
Understanding SSH Keys vs Passwords
SSH supports two common authentication methods:
- Password authentication
- You type a username and password.
- Vulnerable to brute-force guessing if SSH is exposed to the internet.
- Reuse of passwords across services is especially dangerous.
- Public key authentication
- You generate a key pair: private key (kept secret) and public key (shared).
- Server stores your public key in
~/.ssh/authorized_keys. - When you connect, the server challenges your client to prove it has the private key.
- More resistant to brute-force attacks, especially if keys are protected with a passphrase.
For most servers, public key authentication should be the default, and password logins should be disabled once keys are in place.
Generating and Using SSH Keys Securely
Creating a key pair
Run this on the client machine (your laptop/workstation):
ssh-keygen -t ed25519 -C "you@example.com"-t ed25519: uses a modern, strong key type.-Cis an arbitrary comment (e.g., email or purpose).- Default file is
~/.ssh/id_ed25519(private) and~/.ssh/id_ed25519.pub(public).
When prompted:
- Choose a strong passphrase. This encrypts your private key at rest.
- Don’t share the private key file with anyone.
To see your public key:
cat ~/.ssh/id_ed25519.pub
Never share the private key (id_ed25519); you may share the .pub file.
Installing your public key on the server
On the client, you can copy your key to a server:
ssh-copy-id user@server.example.comThis:
- Appends your public key to
~user/.ssh/authorized_keyson the server. - Sets basic permissions correctly.
If ssh-copy-id is unavailable, do it manually:
- On client:
cat ~/.ssh/id_ed25519.pub- On server (logged in as
useror viasudo su - user):
mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "ssh-ed25519 AAAA... your-comment" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keysNow test login from client:
ssh user@server.example.comIf it logs in without asking for the account’s password (but maybe asking for key passphrase), key auth is working.
Hardening `sshd_config`
The SSH daemon configuration file is usually /etc/ssh/sshd_config.
Before editing, backup it:
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bakAfter changes, test config for syntax errors:
sudo sshd -tIf there’s no output, configuration syntax is OK. Then restart:
sudo systemctl restart sshd
# or, on some systems:
sudo systemctl restart sshDisable root login
Logging in directly as root over SSH is risky. Use a regular user and sudo instead.
In /etc/ssh/sshd_config:
PermitRootLogin noOr, more permissive but still safer than full root logins:
PermitRootLogin prohibit-password
This allows only key-based root logins (not recommended for beginners; prefer no).
Enforce key-based authentication
Once keys are set up and tested, disable password auth:
In /etc/ssh/sshd_config:
PasswordAuthentication no
KbdInteractiveAuthentication no
UsePAM yesNotes:
- Only do this after confirming that your keys work, or you can lock yourself out.
- Keep console/physical access or out-of-band access (e.g., cloud provider console) for recovery.
Restrict SSH protocol and algorithms
Modern OpenSSH only supports protocol 2; ensure it:
Protocol 2Algorithms:
- Old/weak ciphers and MACs should be disabled, but default modern OpenSSH configs are generally sane.
- For most beginners, rely on the distro defaults; aggressive tuning belongs in more advanced chapters.
Limiting Who and How People Can Log In
Restrict which users can SSH
You can explicitly allow only certain users or groups:
In /etc/ssh/sshd_config:
AllowUsers alice backupuser
# or
AllowGroups sshusers
If you use AllowUsers or AllowGroups, only those listed will be allowed.
Alternatively, you can deny specific accounts:
DenyUsers test temp
DenyGroups nogroup
Don’t use both Allow and Deny in complex ways unless you understand the precedence rules; for simple setups, stick to one approach.
Use non-default port (with care)
Changing the SSH port from 22 to another (e.g., 2222) does not add real cryptographic security, but it:
- Reduces noise from automated bots scanning the internet.
- Makes logs less cluttered with generic brute-force attempts.
In /etc/ssh/sshd_config:
Port 2222Then update firewall rules and connect with:
ssh -p 2222 user@server.example.comThis is “security through obscurity” and should supplement, not replace, proper hardening.
Protecting SSH with Firewalls
Basic idea: only allow SSH from networks or IPs that should reach it.
Examples:
Using UFW (commonly on Ubuntu)
Allow SSH on the default port:
sudo ufw allow sshIf you changed the SSH port (e.g., to 2222):
sudo ufw allow 2222/tcpRestrict to a specific IP:
sudo ufw allow from 203.0.113.10 to any port 22 proto tcpCheck rules:
sudo ufw status verboseUsing firewalld (Fedora/RHEL family)
Allow SSH in the active zone:
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reloadIf using a custom port:
sudo firewall-cmd --permanent --add-port=2222/tcp
sudo firewall-cmd --reload
For tighter restrictions (e.g., only from a specific subnet), use --add-rich-rule or rich rules as appropriate for your environment.
Using Fail2ban (Brute-Force Protection)
Fail2ban monitors logs and bans IP addresses with repeated failed login attempts.
Install (example on Debian/Ubuntu):
sudo apt install fail2banBasic SSH protection is often enabled by default. To enable or tune it:
- Copy default config:
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local- Edit
/etc/fail2ban/jail.local, look for[sshd]:
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 5
bantime = 600maxretry: number of failed attempts before ban.bantime: ban duration in seconds.
- Restart Fail2ban:
sudo systemctl restart fail2banCheck banned IPs:
sudo fail2ban-client status sshdFail2ban configuration can be more advanced, but this baseline cuts down on brute-force noise.
Securing SSH Client-Side
Use `~/.ssh/config` for safer defaults
Create or edit ~/.ssh/config on your client:
Host server-example
HostName server.example.com
User alice
Port 2222
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yesNow connect with:
ssh server-exampleThis helps avoid mistakes like specifying the wrong port or user, and enforces use of your key.
Protect your private keys
- Set proper permissions:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519- Never email or upload private keys.
- Use an SSH agent so you don’t type your passphrase every connection:
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519Many desktop environments start an agent automatically.
Verifying Host Keys and Avoiding MITM
When you first connect to a host, SSH shows a message like:
The authenticity of host 'server.example.com (203.0.113.5)' can't be established.
ED25519 key fingerprint is SHA256:....
Are you sure you want to continue connecting (yes/no/[fingerprint])?- SSH stores the server’s host key fingerprint in
~/.ssh/known_hosts. - On later connections, it checks if the key changed; if it did, you’ll get a warning (possible man-in-the-middle attack or server reinstall).
Basic practices:
- For important servers, verify the fingerprint out-of-band (e.g., from your provider’s web console or documentation) before accepting.
- If you see a warning about a changed host key, don’t blindly accept it. Confirm why it changed (e.g., server rebuilt) before proceeding.
You can inspect a known host entry:
ssh-keygen -lf ~/.ssh/known_hostsOr from a host key file on the server:
sudo ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pubPractical Hardening Checklist
For a typical internet-facing server:
- Generate an
ed25519SSH key on your client; protect it with a passphrase. - Install your public key on the server (
ssh-copy-id). - Confirm you can log in using the key.
- On the server, edit
/etc/ssh/sshd_config: Protocol 2PermitRootLogin noPasswordAuthentication no(after confirming key works)- Optionally change
Portfrom22to a non-standard value. - Optionally add
AllowUsers yourusername. - Test SSH config:
sudo sshd -t. - Restart SSH service.
- Configure firewall (UFW or firewalld) to:
- Allow SSH only from networks that need it.
- Use the correct port.
- Install and enable Fail2ban (or equivalent) to limit brute-force attempts.
- Keep SSH server and system packages up to date with your distro’s package manager.
- Periodically review
/var/log/auth.logor equivalent for unusual SSH activity.
These steps provide a solid baseline of SSH security for most beginner-to-intermediate Linux administrators.