On this page
Two changes do most of the work: sign in with a key instead of a password, and stop root signing in with a password. Everything else on this page is smaller than those two, and every one of them can lock you out of your own server if you apply it before you test it.
Get key sign-in working first
Nothing below is safe until a key works. Do this part on its own and confirm it, then come back for the config.
On your own machine, create a key if you do not have one:
ssh-keygen -t ed25519 -C "you@example.com"Copy the public half to the server:
ssh-copy-id -i ~/.ssh/id_ed25519.pub root@203.0.113.10If ssh-copy-id is not available, append the public key by hand on the server
and fix the permissions, which SSH refuses to work around:
mkdir -p ~/.ssh
chmod 700 ~/.ssh
printf '%s\n' 'ssh-ed25519 AAAA...your key... you@example.com' >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keysOn RHEL, Alma, and Rocky, restore the SELinux labels afterwards or the daemon will ignore the file:
restorecon -R -v ~/.sshNow open a second terminal and prove the key works on its own, with passwords ruled out:
ssh -o PubkeyAuthentication=yes -o PasswordAuthentication=no root@203.0.113.10If that gets you a shell, continue. If it asks for a password or is refused, fix that before changing anything on the server.
Create a user to sign in as
You need this only if you intend to stop root signing in entirely. Creating the
account and granting it sudo is covered in
Users, groups and sudo on Linux; the SSH half is
giving that user the same key, with ownership and permissions preserved:
rsync --archive --chown=deploy:deploy ~/.ssh /home/deploy/Test the new account in a second terminal before you go further, including
sudo, because a user who cannot escalate cannot undo what you are about to do:
ssh deploy@203.0.113.10
sudo -vFind out where your settings actually live
Current OpenSSH reads /etc/ssh/sshd_config and, from an Include line near the
top of it, everything in /etc/ssh/sshd_config.d/. For most keywords the first
value wins, so a drop-in file included at the top of the config beats anything
you type further down the main file. Cloud images frequently ship a drop-in that
sets PasswordAuthentication yes, and it is the usual reason a careful edit
appears to do nothing.
Check whether the include exists, and what is in there:
grep -i '^include' /etc/ssh/sshd_config
ls -l /etc/ssh/sshd_config.d/Then ask the daemon what it has actually resolved, as root. This is the only answer that counts:
sshd -T | grep -Ei 'permitrootlogin|passwordauthentication|pubkeyauthentication|kbdinteractive'Put your changes in the file that wins. Either edit the drop-in that already sets
the keyword, or add your own file in /etc/ssh/sshd_config.d/ with a name that
sorts before it, then run sshd -T again to confirm the value changed.
The settings that matter
| Setting | Value | What it does |
|---|---|---|
PubkeyAuthentication | yes | Allows key sign-in. Confirm it before turning passwords off. |
PasswordAuthentication | no | Stops password sign-in outright. This is the change that matters most. |
KbdInteractiveAuthentication | no | Closes the other route to a password prompt. Older builds call this ChallengeResponseAuthentication. Leaving it on can hand sign-in back to PAM and prompt for a password anyway. |
PermitRootLogin | prohibit-password | Root can still sign in with a key but never with a password. Use no instead once another user with sudo is tested. |
PermitEmptyPasswords | no | Refuses accounts with no password set. |
MaxAuthTries | 3 | Drops the connection after three failed attempts, cutting the cost of a guessing run. |
LoginGraceTime | 20 | Seconds an unauthenticated connection may sit open. |
AllowUsers or AllowGroups | your users | Anyone not listed cannot sign in at all, whatever their credentials. Adding yourself wrongly here locks you out. |
X11Forwarding | no | Turns off a feature a server almost never needs. |
Leave UsePAM yes alone. Turning it off changes account and session handling well
beyond SSH.
Apply the change without losing the server
Keep your current session open
Do not close the terminal you edited from. An existing session survives a reload, so it stays usable even if the new config is wrong.
Check the syntax
sshd -tSilence means the config parses. An error prints the file and line. Fix it before going any further.
Reload the daemon
On Debian and Ubuntu the unit is
ssh:systemctl reload sshOn RHEL, Alma, and Rocky it is
sshd:systemctl reload sshdReload re-reads the config without dropping connections.
Open a new session in a second terminal
ssh deploy@203.0.113.10This is the test. Until a fresh connection succeeds, assume the server is unreachable and do not close anything.
Only now close the first session
If the new session failed, the old one is still root on the machine: put the previous configuration back, reload, and test again before you go anywhere.
A timed rollback, for the changes you are least sure about
Schedule the old config to come back on its own, so a mistake repairs itself while you are still trying to reconnect:
cp /etc/ssh/sshd_config /root/sshd_config.bak
systemd-run --on-active=10min --timer-property=AccuracySec=1s \
/bin/sh -c 'cp /root/sshd_config.bak /etc/ssh/sshd_config; systemctl reload ssh'It prints the unit it created, something like run-r4f1a.timer. If the new
session works, cancel the rollback:
systemctl stop run-r4f1a.timerBack up and restore the drop-in file instead if that is where you made the change.
Changing the SSH port
Moving SSH off port 22 stops the constant background scanning from reaching it, which makes your logs readable. Be clear about what that is worth: it is noise reduction, not security. Anyone scanning your address for open ports finds the new one in seconds, and a service that would have fallen to a weak password on port 22 falls to the same password on port 2222. Key-only sign-in is the control that stops the attack; the port is housekeeping.
If you still want it, four things have to agree, and the order they are done in matters.
Find out whether systemd owns the port
systemctl is-enabled ssh.socketIf that prints
enabled, the socket accepts connections and starts the daemon, andPortinsshd_configis ignored. Set the port in a socket drop-in instead. Create/etc/systemd/system/ssh.socket.d/port.conf:[Socket] ListenStream= ListenStream=2222The empty
ListenStream=clears the inherited value. Without that line you get both ports. Then:systemctl daemon-reload systemctl restart ssh.socketIf the command reports the socket is disabled or does not exist, which is the usual case on RHEL, Alma, and Rocky, set
Port 2222in the SSH config in the file that wins, as above.Tell SELinux about the port, on the RHEL family
dnf install -y policycoreutils-python-utils semanage port -a -t ssh_port_t -p tcp 2222Skip this and the daemon fails to bind.
systemctl status sshdshows the error.Open the port in the host firewall
Add the new port before you remove the old one. See Using a firewall on your Linux server.
Add a port rule in the panel
Give the new port its own inbound rule for TCP, so the port's rate limits and protocol checks apply to it. If Default for unlisted ports is set to
Deny all, the connection never arrives without one. See Port rules. Keep the rule for port 22 until the new port is proven, then remove it.Connect on the new port from a second terminal
ssh -p 2222 deploy@203.0.113.10
If you run fail2ban, its sshd jail resolves port = ssh through /etc/services
and will keep watching port 22. Set port = 2222 in the jail. See
Setting up fail2ban.
If you do lock yourself out
Open Console access in the panel. The console is
attached to the machine rather than to the network stack inside it, so it works
when SSH does not. Sign in there, undo the change, run sshd -t, reload the
daemon, and test from a normal terminal again.
Related
ufw and firewalld, and how a host firewall relates to the panel's rules.
Setting up fail2banBanning addresses that fail sign-in repeatedly, and what that does not cover.
Console accessThe way back in when SSH stops answering.
SSH keysAdding keys in the panel, and when they are injected.
Users, groups and sudoCreating the account you will sign in as once root is locked down.