SSH is a very powerful tool to have if you host your own server, but if you've ever opened up port 22 to the public internet you've probably been bombarded with login attempts. The following covers common hardening strategies for Debian-based systems, though most principles apply universally across distributions.
1. Disable Root Login
The root user is the most frequently targeted account in brute force attacks. Disabling root login over SSH means an attacker needs to know both a valid username and its password — a significant hurdle.
Edit /etc/ssh/sshd_config and change:
PermitRootLogin yes
to:
PermitRootLogin no
Then restart the SSH daemon:
sudo systemctl restart sshd.service
2. SSH Keys
SSH keys are computationally impractical to brute force, so disabling password authentication in favour of key-based auth essentially eliminates that entire attack surface.
Generate a key pair on your local machine:
ssh-keygen -t rsa
Copy the public key to your server:
ssh-copy-id user@server
Verify you can log in with the key, then disable password authentication in /etc/ssh/sshd_config:
PasswordAuthentication no
Restart the daemon:
sudo systemctl restart sshd.service
3. Fail2Ban
Fail2Ban monitors log files for repeated failed login attempts and automatically bans the offending IP address for a configurable period. It's a useful defence-in-depth layer even after keys-only auth is enabled.
Install it:
sudo apt update
sudo apt install fail2ban
sudo systemctl status fail2ban
Fail2Ban ships with a default SSH jail: after 3 failed login attempts the offending IP is banned for 30 minutes. The jail configuration lives in /etc/fail2ban/jail.conf — copy it to jail.local before making changes so package updates don't overwrite your settings:
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
4. OpenVPN
The most thorough option is to take SSH off the public internet entirely. Run OpenVPN on your server, then connect to the VPN before SSHing — port 22 never needs to be exposed publicly.
A minimal Docker Compose setup using the linuxserver/openvpn-as image:
version: '3'
services:
openvpn:
container_name: openvpn
image: linuxserver/openvpn-as
network_mode: bridge
cap_add:
- NET_ADMIN
environment:
- PUID=1008
- PGID=1008
- TZ=America/New_York
volumes:
- ./config:/config
ports:
- 943:943
- 9443:9443
- 1194:1194/udp
restart: always
After the container starts, access the admin panel at https://DOCKER-HOST-IP:943/admin to configure users and network settings. Port-forward 9443 and 1194 on your router. Users can then download their .ovpn profile from the VPN portal and connect before accessing SSH through the VPN gateway.