MHOSTMHOST

Hardening SSH

In this article you'll set up key-based SSH login on your mHost VPS instead of a password, disable password and root SSH access in sshd_config, optionally change the SSH port, and safely restart sshd without losing access to the server.

What you'll need

  • An mHost VPS running Ubuntu 22.04/24.04, Debian 11/12, or AlmaLinux/Rocky Linux 8/9.
  • Working SSH access already — as root or a user with sudo (by password for now; we'll set up the key below). If you haven't connected to the server yet, start with "VNC console and first connection (SSH/RDP)" — it also covers the basics of ssh-keygen/ssh-copy-id; here we'll go deeper and further.
  • An SSH client on your own computer (not the server): built in on macOS and Linux, usually available out of the box on Windows 10/11 too — or use the graphical client PuTTY.
  • Access to the VMmanager 6 panel — as a fallback: if something goes wrong with SSH itself, you can still reach the server through the browser-based VNC console (see "How to log in to VMmanager 6").
Tip: all server-side commands below are given as root. If you're working as a regular user, prefix each command with sudo.

Step 1. Generate an SSH key pair

Keys are generated on your own computer (the client), not on the server:

bash
ssh-keygen -t ed25519 -C "you@example.com"

You can just press Enter at the path prompt — the key will be saved as ~/.ssh/id_ed25519 (private key) and ~/.ssh/id_ed25519.pub (public key). At the passphrase prompt, it's recommended to set a passphrase on the key itself: it isn't sent to the server and has nothing to do with your account password — it just protects the key file on your own disk.

Important: the id_ed25519 file (without .pub) is the private key. Never copy it to a server, publish it, or hand it to anyone. Only id_ed25519.pub goes to the server.
Tip: ed25519 is the modern, compact, currently recommended key type (in fact, if you omit -t altogether, ssh-keygen creates an Ed25519 key anyway — it's the default). If you need compatibility with old software or hardware that doesn't support Ed25519, use RSA instead: ssh-keygen -t rsa -b 4096 -C "you@example.com".

Step 2. Copy the public key to the server

bash
ssh-copy-id -i ~/.ssh/id_ed25519.pub root@185.246.66.12

Replace root@185.246.66.12 with your own username and server IP. The command appends your public key to ~/.ssh/authorized_keys on the server, asking for the password one last time.

If ssh-copy-id isn't available (for example, in Windows PowerShell without the OpenSSH utilities), do the same thing manually:

bash
cat ~/.ssh/id_ed25519.pub | ssh root@185.246.66.12 "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

Check that key-based login works — in a new terminal window, without closing your current session:

bash
ssh root@185.246.66.12

The connection should succeed without asking for the account password (a prompt for the key's own passphrase, if you set one in step 1, is a different thing, and expected).

Important: don't move on to step 3 until you've confirmed key-based login actually works. Once you disable PasswordAuthentication, passwords stop being accepted entirely — and if the key isn't set up, you'll lock yourself out of the server.

Step 3. Disable password login and restrict root in sshd_config

Open the SSH server configuration:

bash
sudo nano /etc/ssh/sshd_config

Find (or add, if missing) the following options and set them to:

bash
PasswordAuthentication no
PermitRootLogin prohibit-password
  • PasswordAuthentication no — disables password login entirely, for every user; from now on it's key-only.
  • PermitRootLogin prohibit-password — root can still log in over SSH, but only with a key, not a password. This is a safe default, especially if root is the only account on the server.
Tip: if you already have a separate sudo user set up and have confirmed key-based login works for it, you can tighten this further to PermitRootLogin no — root then can't log in over SSH at all, neither by password nor by key. Don't set no if root is your only way into the server over SSH — you would lock yourself out for certain.

Save the file, then check the syntax and, separately, which values will actually take effect:

bash
sudo sshd -t
sudo sshd -T | grep -i passwordauthentication
sudo sshd -T | grep -i permitrootlogin

sshd -t checks the file for syntax errors. sshd -T prints the resulting (effective) configuration — what will actually apply after a restart, accounting for every included file.

Important: on Ubuntu cloud images, cloud-init may create a file /etc/ssh/sshd_config.d/50-cloud-init.conf containing PasswordAuthentication yes. Files under sshd_config.d/ are pulled in by an Include directive right at the top of sshd_config, and for each option OpenSSH uses the first value it finds — so that line from cloud-init will win over whatever you set later in the main file, and sshd -T will show yes despite your edit.

Check whether anything is overriding your settings:

bash
sudo grep -rn "PasswordAuthentication" /etc/ssh/sshd_config /etc/ssh/sshd_config.d/*.conf

If the extra line turns up in one of the sshd_config.d/ files, fix or remove it right there, then re-check with sshd -T from the step above.

Don't restart sshd yet — you'll do that in step 5, together with the port change, if you're making one.

Step 4. Change the SSH port (optional)

Changing the port doesn't replace the key-based login and root restriction from step 3 — it just cuts down the background noise from automated scanners that probe port 22 across the internet around the clock. If that doesn't matter to you, skip this step and go straight to step 5.

Important: the order matters here — open the new port in the firewall first, and only then change Port in sshd_config. Do it the other way around, and the moment sshd restarts on the new port, the firewall will block it and you'll lose access to the server.

First, open the new port in the firewall. Port 22 is open by default on mHost, but that doesn't extend to a new port — you need to open it explicitly.

Ubuntu / Debian (ufw)

bash
sudo ufw status
sudo ufw allow 2222/tcp

AlmaLinux / Rocky (firewalld + SELinux)

bash
sudo firewall-cmd --permanent --add-port=2222/tcp
sudo firewall-cmd --reload
sudo semanage port -a -t ssh_port_t -p tcp 2222
Tip: if the semanage command isn't available, install the package: sudo dnf install -y policycoreutils-python-utils. If port 2222 is already labeled for another service under SELinux, -a will fail with an "already defined" error — use -m instead of -a in that case.
Important: for a detailed walkthrough of ufw commands and logic, see "Setting up the UFW firewall".

Then set the new port in sshd_config:

bash
sudo nano /etc/ssh/sshd_config
bash
Port 22
Port 2222

The Port directive can be given more than once — sshd will listen on both ports at the same time. Keep 22 around until you've confirmed port 2222 works (you'll drop the extra line in step 5) — that way you still have a way back if something goes wrong.

Step 5. Check the configuration and restart sshd without closing your session

bash
sudo sshd -t

Restart the service — the command depends on your distro.

Ubuntu / Debian

bash
sudo systemctl restart ssh

AlmaLinux / Rocky

bash
sudo systemctl restart sshd
Important: don't close your current SSH session right after restarting.

Open a new terminal window and connect again while the old session is still open:

bash
ssh -p 2222 root@185.246.66.12

The -p 2222 flag is only needed if you changed the port in step 4; otherwise just ssh root@185.246.66.12. Only close the old session once the new connection has succeeded. If the new connection fails, the old session is still open — go back to sshd_config, fix the setting, and restart again. As an extra safety net in case both sessions somehow drop, VMmanager 6's browser-based VNC console (see "How to log in to VMmanager 6") doesn't depend on SSH at all and opens right in the browser.

If you changed the port in step 4 and the new connection is confirmed, remove the temporary fallback: delete the Port 22 line from sshd_config, close the old firewall rule, and restart sshd once more, with the same discipline (a new terminal window before closing the old one).

bash
sudo ufw delete allow 22/tcp
bash
sudo firewall-cmd --permanent --remove-service=ssh
sudo firewall-cmd --reload
Done: SSH now accepts key-based login only, root is restricted (or fully disabled, if you chose that option in step 3), and optionally runs on a non-default port. You can check the current state at any time with sudo sshd -T | grep -iE "^(port|passwordauthentication|permitrootlogin)".

What's next

A key instead of a password and a non-default port cut down the background noise, but they don't protect against a targeted attack — for that, add automatic IP blocking after a few failed attempts, see "Fail2ban: blocking repeated failed logins". For a full walkthrough of firewall rules, see "Setting up the UFW firewall", and for a general server security checklist, see "Server security checklist".