Guides

How to secure SSH access on a public server

Port 22 gets brute-forced within minutes. Key-only auth plus fail2ban and a firewall removes almost all the risk. The practical, in-order setup.

Published · Updated ~6 min read
On this page

Port 22 on a public IP starts getting brute-forced within minutes of going live. You do not need anything exotic to stop it: key-only authentication plus a rate limiter removes essentially the entire risk. Here is the practical, in-order setup.

1. Use keys, then turn passwords off

Generate a modern key on your local machine and copy it up:

on your laptop
ssh-keygen -t ed25519 -C "you@laptop"
ssh-copy-id user@your-server

Confirm key login works, then disable passwords entirely so brute force has nothing to aim at:

/etc/ssh/sshd_config
PasswordAuthentication no
PermitRootLogin no
KbdInteractiveAuthentication no
# apply
sudo sshd -t && sudo systemctl restart ssh

PermitRootLogin: no, prohibit-password or yes?

PermitRootLogin takes four values. The OpenSSH default is prohibit-password: root may log in, but only with a key, never with a password.without-password is the old, deprecated name for the same thing.

ValueRoot can log in withUse it when
nonothingYou log in as a normal user and use sudo. The safest choice
prohibit-passworda key only (password and keyboard-interactive are off for root)Automation needs root and runs with a key; this is the default
forced-commands-onlya key only, and only if that key has a command= option in authorized_keysA backup or deploy key that may run exactly one command as root
yesany method, including a passwordPractically never on a public IP

A value in sshd_config is not always the one sshd uses. For each keyword the first value it reads wins, and Debian and Ubuntu read the drop-in files in /etc/ssh/sshd_config.d/ first, so a cloud-init file there can quietly override your edit. Ask sshd for the setting it actually applies:

effective setting
sudo sshd -T | grep -i permitrootlogin
grep -ri permitrootlogin /etc/ssh/sshd_config /etc/ssh/sshd_config.d/

2. Add fail2ban

fail2ban watches the auth log and temporarily bans IPs that fail repeatedly. It neutralises the noise from bots even with passwords already off:

install
sudo apt install -y fail2ban python3-systemd

Create a minimal jail for SSH. backend = systemd makes it read sshd’s log from the journal: Debian 12 writes no /var/log/auth.log, and without that line fail2ban stops there with Have not found any log file for sshd jail. That is also why the service apt started fails on Debian 12 until this file is in place.

/etc/fail2ban/jail.local
[sshd]
enabled = true
backend = systemd
maxretry = 4
bantime = 1h
findtime = 10m
enable + restart + check
sudo systemctl enable fail2ban
sudo systemctl restart fail2ban
sudo fail2ban-client status sshd

Your own address in ignoreip, unbanning an IP, repeat offenders and jails for nginx are covered in the fail2ban guide for Ubuntu and Debian.

3. Should you change the port?

Moving SSH off 22 does not add real security (a scanner finds the new port in seconds), but it does cut log noise dramatically. It is cosmetic, not protective. If you do it, remember to open the new port in the firewall first. How to check which port sshd really listens on, and how ssh, scp and rsync connect to another one, is in SSH port 22: check it, connect on another.

4. Limit who can log in

Restrict SSH to the accounts that actually need it:

allow-list users
# in sshd_config
AllowUsers deploy admin

5. Firewall the rest

Everything except the ports you serve should be closed. See the UFW guide for the full setup; the SSH essentials are:

ufw
sudo ufw allow OpenSSH
sudo ufw enable

The short version

  • Keys only, passwords and root login off.
  • fail2ban on the SSH jail.
  • Firewall closed except for what you serve.
  • An allow-list of login accounts.

That combination stops the overwhelming majority of attacks against a new VMHeaven Linux VPS. Every VMHeaven VPS has a browser VNC console in the panel, which works without SSH, so you can apply it confidently without fear of being locked out.

Frequently asked

Does changing the SSH port improve security?

Not meaningfully: a scanner finds the new port in seconds. It cuts log noise, which is nice, but it is cosmetic, not protective. Key-only auth is what matters.

Is fail2ban still useful if passwords are disabled?

Yes. It bans noisy IPs and reduces log clutter and load from constant scanning, even when key-only auth already blocks them.

What is the minimum effective setup?

Keys only with passwords and root login off, fail2ban on the SSH jail, a firewall closed except for what you serve, and an AllowUsers list.

Related articles

All guides

xrdp on Ubuntu and Debian: install an RDP desktop (XFCE) on a VPS and fix the black screen

Install xrdp with XFCE on Ubuntu 24.04 or Debian 12/13, add xrdp to ssl-cert, open port 3389 to your IP only or tunnel it over SSH, and fix the black screen.

Set up your own WireGuard VPN server on a VPS (Debian and Ubuntu)

Install WireGuard on Debian 12/13 or Ubuntu 24.04, create keys, enable forwarding and NAT, open UDP 51820 and connect your laptop and phone, step by step.

Kali Linux on a VPS for pentesting: the setup that works

No Kali template? Run Kali's tools on a hardened Debian VPS in Docker, and stay inside your written scope and the host's rules while you test.

SSH tunnel explained: local, remote and dynamic (SOCKS) port forwarding

What an SSH tunnel is and how to build one: local forwarding with ssh -L, reverse tunnels with ssh -R, a SOCKS proxy with ssh -D, autossh and PuTTY.

How to exit vim: :wq, :q! and every other way out

Esc then :wq saves and quits; :q! quits without saving. Every exit command, why vim traps people in the first place, and how to change the default editor.

How to generate an SSH key (ssh-keygen) and use it to log in

ssh-keygen -t ed25519 creates a key pair in minutes. Why ed25519 over RSA, setting a passphrase, copying the key with ssh-copy-id, and loading it into ssh-agent.

tmux cheat sheet: sessions, windows, panes and the keys you actually use

The tmux keys and commands used every day: Ctrl-b bindings for windows and panes, detaching and reattaching a session, copy mode, and a minimal .tmux.conf.

How to enable SSH on Ubuntu

sudo apt install openssh-server, then systemctl enable --now ssh and ufw allow OpenSSH if a firewall is active. Ubuntu Server already has it; Ubuntu Desktop does not.

ClamAV on Linux: install it, update the signatures and scan safely

ClamAV Linux guide: install on Ubuntu, Debian or Rocky, keep signatures current with freshclam, scan with clamscan or clamd, and know its limits.