Step-by-Step Guide: Harden SSH with Security Best Practices
SSH (Secure Shell) is vital for remote Linux server administration, but default settings often lack sufficient security. Hardening SSH is essential to protect your system from unauthorised access, brute-force attacks, and other threats.
This guide outlines best practices for securing SSH, using a Linode server as an example. These steps apply universally across all server environments.
Overview of SSH Hardening Techniques #
Authentication and Access Control
- Disable root login
Prevent direct root access over SSH to reduce the impact of brute-force attacks. - Use key-based authentication
SSH keys are more secure than passwords and eliminate the risk of password-guessing attacks. - Disable password authentication
Forces all users to authenticate with SSH keys. - Enforce strong SSH key algorithms
Use secure key types likeed25519
for strong, efficient authentication. - Restrict user access
Explicitly define which users or groups are allowed to connect via SSH.
Network and Port Security
- Change the default SSH port
Using a non-standard SSH port reduces automated scanning and noise.
Protocol
- Set a short login grace time
Limit how long an unauthenticated user can log in to reduce brute-force risk.
Step 1: Create Key Pair #
Create SSH key pair with Ed25519
algorithm (on local machine):
ssh-keygen -t ed25519 -C "<[email protected]>" -f ~/.ssh/<key_name>
Key naming: Create a separate SSH key for each Linode. Use clear, descriptive names such as
linode-blog
orlinode-test
.Key algorithm: Use
Ed25519
. It offers strong security, high performance, and better long-term support thanRSA
orECDSA
.Key rotation: Regular rotation is good practice but not essential. If your private key is secured with a strong passphrase and stored safely, and there’s no sign of compromise, frequent changes are unnecessary.
Notes:
-t
: Specify key type (ecdsa
,ed25519
,rsa
).-C
: Add a comment (typically your email address).-f
: File name to save the key (default isid_ed25519
orid_rsa
).- Example
key_name
: linode-blog
Verify key creation:
ls -l ~/.ssh
Set private key permissions to 600
:
chmod 600 ~/.ssh/<key_name>
Step 2: Copy Public Key to Instance #
Copy public key:
ssh-copy-id -i ~/.ssh/<key_name>.pub <user>@<public_ipv4>
Log in:
ssh <user>@<public_ipv4>
Verify if public key is copied:
vim ~/.ssh/authorized_keys
Set permissions:
sudo chmod -R 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys
Step 3: Set Up SSH Config #
Backup current configuration:
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
Edit SSH configuration file:
sudo vim /etc/ssh/sshd_config
Modify:
Custom SSH port: select any TCP port number between 1024
and 49151
. This range includes unprivileged, user-defined ports not reserved by the system.
Port <custom_port> # Change default SSH port (22) to improve security through obscurity
LoginGraceTime 30s # Allow 30 seconds for users to authenticate before disconnecting
PermitRootLogin no # Disable root login to enhance security
AllowUsers <user1> <user2> # Restrict SSH access to specified user(s) only
PubkeyAuthentication yes # Enable public key authentication
PasswordAuthentication no # Disable password authentication to enforce key-based login
Restart SSH service to apply changes:
sudo systemctl restart ssh
Step 4: Update Firewall Settings #
- In the Linode dashboard, go to Network > Firewall.
- Under SSH port, select Custom.
- Enter your custom SSH port range in Custom port range (e.g.
<custom_port>
). - Click Save Changes.
- Navigate to Compute > Linodes.
- Select your Linode, right-click it, and choose Reboot.
- Confirm by clicking Reboot Linode.
Step 5: Create Custom Host #
Edit SSH config (on local machine):
vim ~/.ssh/config
Add:
Host <host>
HostName <public_ipv4_or_domain>
Port: <custom_port>
User <user>
IdentityFile ~/.ssh/<key_name>
Examples:
Host linode-blog
HostName xxx.xxx.xx.xxx
Port xxxxx
User jane
IdentityFile ~/.ssh/linode-blog
Host linode-test
HostName domain.com
Port xxxxx
User john
IdentityFile ~/.ssh/linode-test
Result
You can nog connect using:
ssh <host>
Instead of:
ssh -i ~/.ssh/<key_name> -p <custom_port> <user>@<public_ipv4>