- Vrealmatic
- Ubuntu Server
- SSH keys
SSH keys and SSH server hardening
Key-only login, no password and no root, on Ubuntu Server and Desktop.
You create a passphrase-protected key, upload it to the server and write the SSH settings into a separate file: passwords and root off, optionally another port. The commands are filled in from your details and for your system (Windows, Mac, Linux).
Contents
01 · Start
Before you start
The result of this guide is a server you log in to over SSH with a key only: password login and direct root login are disabled. The server settings live in a separate file; the main configuration stays untouched.
Fill in your details and the commands throughout the guide are filled in. The Copy button copies them with your values. Empty values stay as placeholders (<ADMIN_USER>, <SERVER_IP>…), the same as in the other guides.
The SSH server is running on the server. which sshd checks it (prints a path); empty output = sudo apt install openssh-server. Details in the Installing the SSH server step of the Securing access chapter.
The procedure in short
- Key on your computer: you create a key pair protected by a passphrase.
- Key to the server: you upload the public part.
- Key login: only the key passphrase instead of the server password.
- Hardening the SSH server: passwords and root off, optionally another port.
- Verification: the key gets in, the password does not.
02 · Your computer
Key on your computer
The key is created on the computer you will connect from. It has two files: the private part stays with you, the public part goes to the server.
Step 1: Generate an ed25519 key
In a terminal (PowerShell on Windows) run:
ssh-keygen -t ed25519 -a 100 -f ~/.ssh/<KEY_NAME> -C "<PC_NAME>"ssh-keygen -t ed25519 -a 100 -f $env:USERPROFILE\.ssh\<KEY_NAME> -C "<PC_NAME>"Enter a passphrase. It protects the key if the file ends up in the wrong hands; a forgotten passphrase cannot be recovered, you then create a new key.
| Option | What it does |
|---|---|
-t ed25519 | the Ed25519 key type: short, fast and secure |
-a 100 | key derivation rounds for the passphrase; slows down guessing it if someone steals the file |
-f | your own file name, one key per server (or group of servers) is easy to find and revoke |
-C | key comment (who and from which computer); stored on the server in authorized_keys too |
ssh-agent remembers the key after the first passphrase until you log out. It runs by itself on Mac and Linux; on Windows enable the OpenSSH Authentication Agent service.
Step 2: Show the public key
cat ~/.ssh/<KEY_NAME>.pubGet-Content $env:USERPROFILE\.ssh\<KEY_NAME>.pubA single line starting with ssh-ed25519 AAAAC… and ending with the key comment. Never share the private key (the file without .pub).
Protecting the key on your computer
This is about the computer you connect from. The key replaced the password: whoever has the private key file and knows its passphrase gets into the server.
- Key passphrase: without it a stolen key is usable right away.
- Encrypted disk: BitLocker (Windows), FileVault (Mac), LUKS (Linux). A stolen laptop then does not reveal the key.
- Updated system and screen lock. Do not use the key on other people's or shared computers.
- One key per computer. Do not copy the private key between devices. Create a new one with its own comment on another computer.
- Phone with 2FA codes: protect it with a lock just like the computer.
Lost or retired computer
On the server, open ~/.ssh/authorized_keys and delete the line that ends with the lost computer's comment. Save with ctrl+x.
nano ~/.ssh/authorized_keysThe change applies to new logins immediately; the stolen key no longer gets in.
03 · Server
Key to the server
The public key belongs on the server in your user's ~/.ssh/authorized_keys. The Ubuntu Server installer can import it from GitHub (Import SSH key). If you did that, skip to the key login.
Step 3: Upload the key over a password login
The computer and the server must be in the same network. The command asks for the user's password on the server:
ssh-copy-id -i ~/.ssh/<KEY_NAME>.pub -o IdentitiesOnly=yes -o PreferredAuthentications=password -p 22 <ADMIN_USER>@<SERVER_IP>Get-Content $env:USERPROFILE\.ssh\<KEY_NAME>.pub | ssh -o IdentitiesOnly=yes -o PreferredAuthentications=password -p 22 <ADMIN_USER>@<SERVER_IP> "umask 077; mkdir -p ~/.ssh; cat >> ~/.ssh/authorized_keys"-o IdentitiesOnly=yes -o PreferredAuthentications=password forces a password login. Without them SSH first tries every key on your computer and the server may close the connection with Too many authentication failures. Windows has no ssh-copy-id; the PowerShell command does the same.
04 · Login
Key login
Step 4: Log in with the key
ssh -i ~/.ssh/<KEY_NAME> -o IdentitiesOnly=yes -p 22 <ADMIN_USER>@<SERVER_IP>ssh -i $env:USERPROFILE\.ssh\<KEY_NAME> -o IdentitiesOnly=yes -p 22 <ADMIN_USER>@<SERVER_IP>SSH asks for the key passphrase, the one you entered when creating it. If it asks for the user's password on the server, the key was not accepted, see permissions below.
Asks for the user's password? Fix the permissions
The server rejected the key, most often because ~/.ssh or authorized_keys is readable by other users.ssh-copy-id sets the permissions only for a newly created folder. Log in with the password (it still works) and run on the server:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
ls -ld ~/.ssh ~/.ssh/authorized_keysdrwx------ 2 <ADMIN_USER> <ADMIN_USER> 4096 … /home/<ADMIN_USER>/.ssh
-rw------- 1 <ADMIN_USER> <ADMIN_USER> 98 … /home/<ADMIN_USER>/.ssh/authorized_keysThen log in with the key again. If it still fails, the detailed output helps.
Optional: a server shortcut instead of the full command
To avoid typing the address, port and key every time, add the server to the SSH configuration on your computer. When you change the port, update the Port line too.
Host <SERVER_ALIAS>
HostName <SERVER_IP>
Port 22
User <ADMIN_USER>
IdentityFile ~/.ssh/<KEY_NAME>
IdentitiesOnly yesHost <SERVER_ALIAS>
HostName <SERVER_IP>
Port 22
User <ADMIN_USER>
IdentityFile ~/.ssh/<KEY_NAME>
IdentitiesOnly yesConnecting is then just:
ssh <SERVER_ALIAS>05 · Server
Hardening the SSH server
Continue only once the key login works. Keep two SSH windows open: the changes do not drop existing connections, so if a new login fails, you can revert everything from the other window.
Step 5: Write the settings into a separate file
Into /etc/ssh/sshd_config.d/; the main /etc/ssh/sshd_config stays untouched:
sudo tee /etc/ssh/sshd_config.d/00-hardening.conf <<'EOF'
# Port <SSH_PORT> (optional: uncomment and set your own port)
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no
AuthenticationMethods publickey
EOF| Line | What it does |
|---|---|
PasswordAuthentication no | no password login over SSH (locally at the server the password still works as your way back if you lose the key) |
KbdInteractiveAuthentication no | disables interactive password entry too |
PermitRootLogin no | root cannot log in over SSH at all; administration only through your own user and sudo |
AuthenticationMethods publickey | explicitly key only; when you add 2FA, change this line as described in the 2FA guide |
Port | stays commented out (port 22) until you enter one in your details, see chapter 06 |
Why a separate file and why 00-
- The first value found wins.
sshd_configincludes the files fromsshd_config.d/right at the top, in alphabetical order. The00-prefix makes your settings win even over50-cloud-init.conf, which enables passwords on some installations. - The main file stays original, so
openssh-serverpackage updates do not ask about a configuration conflict and do not overwrite your settings. - All settings in one place: easy to review, copy to another server or remove.
Step 6: Apply the settings
Syntax check first (on an error nothing restarts), then reload. On Ubuntu 24.04 and newer SSH is started by ssh.socket, which reads the port from the configuration only after daemon-reload:
sudo sshd -t && sudo systemctl daemon-reload && sudo systemctl restart ssh.socket sshsudo sshd -t && sudo systemctl restart ssh06 · Optional
Changing the port
Optional. Automated scanners try port 22 first; another port (1024 to 49151) reduces log noise. Real protection comes from key login and the firewall. With SSH only over Tailscale a different port adds almost nothing.
Step 1: Enter the port in your details and check it is free
Enter the port in your details above; the commands below use it. First check that it is free:
sudo ss -tulpn | grep ':<SSH_PORT>' # empty output = the port is freeStep 2: Allow the port in the firewall first
Only if UFW is active. Otherwise you will not get in after the restart:
sudo ufw status # active? then allow the new port first
sudo ufw allow <SSH_PORT>/tcp comment 'SSH'Step 3: Write the port into 00-hardening.conf
The command removes any old Port line and inserts the new one on the first line. The rest of the file stays unchanged:
sudo sed -i -E '/^#? *Port /d' /etc/ssh/sshd_config.d/00-hardening.conf
sudo sed -i '1i Port <SSH_PORT>' /etc/ssh/sshd_config.d/00-hardening.conf
head -n 1 /etc/ssh/sshd_config.d/00-hardening.confStep 4: Apply the settings and log in on the new port
In a new window; keep the old one open. If you use the shortcut, update its Port line.
sudo sshd -t && sudo systemctl daemon-reload && sudo systemctl restart ssh.socket sshsudo sshd -t && sudo systemctl restart sshssh -i ~/.ssh/<KEY_NAME> -o IdentitiesOnly=yes -p 22 <ADMIN_USER>@<SERVER_IP>ssh -i $env:USERPROFILE\.ssh\<KEY_NAME> -o IdentitiesOnly=yes -p 22 <ADMIN_USER>@<SERVER_IP>Step 5: Remove the old rule for port 22
sudo ufw delete allow 22/tcpPort (and ListenAddress) do not follow "the first value wins", every Port line adds another port SSH listens on. The default sshd_config has #Port 22 commented out.
07 · Check
Verification
Step 1: Effective server settings
The output should match the second block (the order of lines may differ):
sudo sshd -T | grep -E '^(port|pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication|permitrootlogin|authenticationmethods) 'port 22
pubkeyauthentication yes
passwordauthentication no
kbdinteractiveauthentication no
permitrootlogin no
authenticationmethods publickeyStep 2: What SSH actually listens on
Only your port:
sudo ss -tlnp | grep -E 'ssh|systemd'
cat /run/systemd/generator/ssh.socket.d/addresses.conf # Ubuntu 24.04+: port taken from the configurationStep 3: In a new window: the key gets in, the password does not
The key login works (first command). An attempt to log in with a password must be rejected:
ssh -i ~/.ssh/<KEY_NAME> -o IdentitiesOnly=yes -p 22 <ADMIN_USER>@<SERVER_IP>ssh -i $env:USERPROFILE\.ssh\<KEY_NAME> -o IdentitiesOnly=yes -p 22 <ADMIN_USER>@<SERVER_IP>ssh -o PubkeyAuthentication=no -o PreferredAuthentications=password -p 22 <ADMIN_USER>@<SERVER_IP><ADMIN_USER>@<SERVER_IP>: Permission denied (publickey).08 · Other users
A user without a key: password instead of a key
For users who will not use a key, for example a less technical client whose server runs at home. Instead of the key they enter a password, but always together with a code from their phone (2FA). They get no sudo.
Step 1: Create the user in the ssh-password group
sudo groupadd -f ssh-password
sudo adduser <USER>
sudo usermod -aG ssh-password <USER>Step 2: Allow the group to log in without a key
SSH asks group members for no key, only for answers through PAM. Everyone else keeps logging in with a key:
sudo tee /etc/ssh/sshd_config.d/10-ssh-password.conf <<'EOF'
Match Group ssh-password
AuthenticationMethods keyboard-interactive
EOF
sudo sshd -t && sudo systemctl restart sshStep 3: Check that the password alone does not get in
Until you turn on 2FA, interactive login is off and the user cannot log in at all:
sudo sshd -T -C user=<USER>,host=localhost,addr=127.0.0.1 | grep -E '^(kbdinteractiveauthentication|authenticationmethods) 'kbdinteractiveauthentication no
authenticationmethods keyboard-interactiveThey can log in only after 2FA is on (the next step), with the password and the code. You create the secret key for their phone there, in the Other users step.
09 · Problems
Troubleshooting
Watch the SSH server log (in the second window or on the server console) and log in from your computer with a detailed output:
sudo journalctl -u ssh -f # on the server: watch the log while you try to log inssh -v -i ~/.ssh/<KEY_NAME> -o IdentitiesOnly=yes -p 22 <ADMIN_USER>@<SERVER_IP> # detailed course of the loginssh -v -i $env:USERPROFILE\.ssh\<KEY_NAME> -o IdentitiesOnly=yes -p 22 <ADMIN_USER>@<SERVER_IP> # detailed course of the login| Message / state | Cause and fix |
|---|---|
| Authentication refused: bad ownership or modes | permissions too loose, see permissions |
| Too many authentication failures | the client tries every key; use -o IdentitiesOnly=yes (it is in the guide's commands and in the shortcut) |
| Asks for the user's password, not the key's | the key is missing on the server or has wrong permissions, see step 3 and permissions |
| Connection refused / timeout after changing the port | the port is not allowed in UFW, or on 24.04 the daemon-reload and ssh.socket restart are missing |
| Password login still works | check sudo sshd -T; the file with the alphabetically lower name in sshd_config.d/ takes precedence |
Sources
Official documentation and further reading
The guide is based on the OpenSSH and Ubuntu documentation (verified on 29 Oct 2026):
- sshd_config(5)All SSH server settings, Include, Match, first value wins.
- ssh-keygen(1)Key types, -a, -f, -C.
- ssh_config(5)Server shortcuts in ~/.ssh/config.
- Ubuntu Server: OpenSSH serverInstalling and configuring SSH on Ubuntu.
- Socket-based activation of sshdWhy a port change on Ubuntu 24.04 needs daemon-reload and ssh.socket.
Related
- Securing access step by stepThe chapter this guide is part of.
- Two-factor authentication (2FA)A one-time code on top of the key.
- Fail2BanBlocking repeated login attempts.
- Tailscale on Ubuntu Server (in Czech)SSH only over a private network.
How to cite this publication (APA 7)Nepor, V. (2026, October 2). SSH Keys and SSH Server Hardening on Ubuntu. Vrealmatic. https://vrealmatic.com/ubuntu/ssh-keys
Need a secure server setup?
We design, secure and document networks and servers.