Firewall the SSH port
# ufw — Debian, Ubuntusudo ufw allow from 203.0.113.10 to any port 22 proto tcpsudo ufw deny 22/tcp
# firewalld — RHEL, Rocky, Almasudo firewall-cmd --permanent --new-zone=sshadminsudo firewall-cmd --permanent --zone=sshadmin --add-source=203.0.113.10sudo firewall-cmd --permanent --zone=sshadmin --add-service=sshsudo firewall-cmd --permanent --zone=public --remove-service=sshsudo firewall-cmd --reloadReplace 203.0.113.10 with the address you administer from.
Why it matters
Section titled “Why it matters”Every other control on this list hardens a daemon that attackers can still reach. A firewall rule means they never get to it. Authentication bugs, a misconfigured directive, a bad upgrade — none of it is reachable from an address that can’t open the socket.
This is the highest-leverage SSH control available when you have a fixed administrative address or a bastion. It closes the exposure rather than narrowing it.
Changing the port is not this control
Section titled “Changing the port is not this control”Moving SSH to port 2222 is commonly presented as hardening. It isn’t, and it’s worth being precise about why:
- It does cut log noise substantially. Broad internet scans hammer port 22 and mostly don’t follow to high ports, so your auth log gets quieter.
- It does not stop a targeted attacker. A full port scan finds the daemon in seconds, and the banner identifies it immediately.
Quieter logs have real operational value — it’s easier to see a genuine attack when the noise is gone. Just don’t count it as an access control. If you want the noise gone and the exposure closed, the firewall rule does both, and the port change does one.
If you do change the port, note the ordering trap: add the new rule and verify the new port works before removing the old one.
On Ubuntu 22.10 and newer, the port lives in two places
Section titled “On Ubuntu 22.10 and newer, the port lives in two places”Ubuntu moved SSH to systemd socket activation in 22.10, which means ssh.socket
owns the listener and Port in sshd_config is not the whole story. Check
which model you’re on:
systemctl is-enabled ssh.socketIf that returns enabled, a port change needs the socket restarted, not the
service reloaded:
sudo systemctl daemon-reloadsudo systemctl restart ssh.socketAnd to stop it listening on both the old and new port, override the socket
explicitly — the empty ListenStream= clears the inherited value first:
[Socket]ListenStream=ListenStream=2222Related
Section titled “Related”- Restrict which users can log in over SSH — narrow who, once you’ve narrowed where from.
- SSH exposed to the internet — what you’re actually closing here.