Best Practices for Hardening SSH Security on Linux Servers
Secure Shell (SSH) is the backbone of remote management for virtually every Linux server. While incredibly powerful and generally secure out of the box, SSH is also the primary target for malicious actors attempting to gain unauthorized access via brute-force attacks, dictionary attacks, and credential stuffing.
Hardening your SSH configuration is arguably the most critical step in securing a new Linux deployment. By implementing a few core best practices—moving beyond simple username and password authentication—you can drastically reduce your attack surface, minimize noise in your logs, and ensure that only authorized users using secure methods can access your system.
This guide outlines essential, actionable steps for securing the SSH service on any Linux distribution, focusing on the primary configuration file: /etc/ssh/sshd_config.
Prerequisite: Backing Up the Configuration
Before making any changes to the SSH daemon configuration (sshd_config), it is crucial to create a backup. An incorrect configuration can lock you out of your server. Always test changes thoroughly.
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak_$(date +%F)
After editing the file, check the syntax before restarting the service:
sudo sshd -t
If the test passes, you can safely restart the SSH service (command varies by distribution):
# For systems using systemd (most modern distros)
sudo systemctl restart sshd
1. Disable Root Login
Allowing direct login as the root user is one of the biggest security risks. If an attacker successfully brute-forces a password, they instantly have complete control of the system. Instead, non-root users should log in first and elevate privileges using sudo.
Configuration Step
Open /etc/ssh/sshd_config and locate the PermitRootLogin directive. Change its value to no.
# Before:
# PermitRootLogin yes
# After (Best Practice):
PermitRootLogin no
Important Note
Ensure you have created and configured at least one standard user with
sudoprivileges before disabling root login. Otherwise, you will be locked out of administrative access.
2. Implement Mandatory Key-Based Authentication
Password authentication is susceptible to brute-force attacks and dictionary attacks. SSH keys, consisting of a public key (on the server) and a private key (on the client), offer significantly stronger security due to their extreme complexity and length.
A. Generate and Install Keys
- Generate the Key Pair (on your local client machine):
bash ssh-keygen -t ed25519 -C "[email protected]" - Copy the Public Key (to the server):
bash ssh-copy-id -i ~/.ssh/id_ed25519 user@your_server_ip
B. Disable Password Authentication
Once you confirm that you can log in successfully using your SSH key, disable password authentication entirely.
# Disable passwords
PasswordAuthentication no
# Ensure keys are enabled
PubkeyAuthentication yes
Best Practice: Use strong key types like Ed25519 or RSA 4096-bit. Always protect the private key with a strong passphrase.
3. Change the Default SSH Port (Defense in Depth)
The default SSH port (TCP port 22) is constantly scanned by automated bots. Changing the port to a high, non-standard number (e.g., 2222, 22222, or 30000+) significantly reduces the amount of noise in your server logs and makes you invisible to casual scanners.
Configuration Step
In /etc/ssh/sshd_config, change the Port directive:
# Before:
# Port 22
# After (Example non-standard port):
Port 22222
Warning: Firewall Adjustment Required
If you change the port, you must update your firewall (e.g.,
iptables,firewalld, or AWS Security Groups) to allow traffic on the new port. Failure to do so will result in immediate connection loss.
Example using firewalld (CentOS/RHEL):
sudo firewall-cmd --permanent --add-port=22222/tcp
sudo firewall-cmd --reload
4. Limit Access to Specific Users and Groups
To enforce strict access control, you should explicitly define which users or groups are allowed to connect via SSH. This limits potential entry points even if an account is compromised or unused.
Configuration Directives
Use one or both of the following directives in sshd_config:
- Allow specific users:
config AllowUsers alice bob - Allow specific groups:
config AllowGroups sshaccess admins
If these directives are present, any user or group not explicitly listed will be denied access.
5. Enforce Stronger Protocol and Ciphers
Ensure that you are using the modern and secure SSH Protocol 2 and enforce the use of strong cryptographic ciphers and Message Authentication Codes (MACs).
Configuration Steps
Verify that older, vulnerable protocols are disabled:
Protocol 2
# Deny insecure legacy authentication methods
HostbasedAuthentication no
IgnoreRhosts yes
While modern SSH implementations are often well-configured by default, explicitly defining strong ciphers and MACs can prevent downgrading attacks. A recommended minimum set includes:
Ciphers [email protected],[email protected]
MACs hmac-sha2-512,hmac-sha2-256
6. Implement Rate Limiting and Intrusion Detection (Fail2Ban)
Even with key-based authentication, continuous probing by bots consumes resources and clutters logs. Fail2Ban is a critical tool that monitors logs for failed login attempts (or other suspicious activity) and dynamically adjusts the firewall to temporarily or permanently ban the originating IP address.
Installation and Configuration (General Steps)
-
Install Fail2Ban:
```bash
# Debian/Ubuntu
sudo apt update && sudo apt install fail2banRHEL/CentOS/Fedora
sudo dnf install fail2ban
`` 2. **Configure the SSH Jail:** Fail2Ban uses configurations called 'jails'. The defaultsshdjail is highly effective at monitoring/var/log/auth.log` (or equivalent) for repeated failures on the SSH service and automatically applying temporary bans. -
Ensure Service is Running:
bash sudo systemctl enable fail2ban sudo systemctl start fail2ban
Fail2Ban significantly mitigates automated brute-force attempts and is considered mandatory for internet-facing servers.
7. Other Essential SSH Hardening Directives
These minor adjustments help manage sessions and reduce the potential attack window:
| Directive | Recommended Value | Purpose |
|---|---|---|
ClientAliveInterval |
300 | Sends a null packet every 300 seconds (5 minutes) to keep session alive. |
ClientAliveCountMax |
3 | Maximum number of failed 'alive' checks before disconnection (15 minutes total idle time). |
UsePAM |
yes | Enables Pluggable Authentication Modules (PAM) for additional local system security policies. |
PermitEmptyPasswords |
no | Prohibits users with empty passwords from logging in (should be no by default). |
Hardening Checklist Summary
Use this checklist to ensure your server meets basic SSH hardening standards:
- [ ] Backup
sshd_configbefore making changes. - [ ] Set
PermitRootLogin no. - [ ] Set
PasswordAuthentication no(after key setup). - [ ] Change the
Portto a non-standard value. - [ ] Update the firewall to allow the new port.
- [ ] Use
AllowUsersorAllowGroupsto restrict access. - [ ] Set
Protocol 2. - [ ] Install and configure Fail2Ban.
- [ ] Check configuration with
sshd -tbefore restarting.
By implementing these best practices, you move SSH from a potential liability to a highly secure remote administration channel.