Why This Matters
SSH with Passwords Is a Bad Idea
The moment a Linux server is reachable on the public internet, bots start hammering port 22. Within minutes of a fresh VPS coming online you will find thousands of failed login attempts in /var/log/secure (Fedora) or /var/log/auth.log (Debian/Ubuntu) — all trying common usernames and passwords around the clock. Password authentication is the attack surface that makes this viable.
SSH keys are a completely different threat model. An ed25519 private key is 256 bits of entropy — brute forcing it is computationally infeasible. There is no password to guess, phish, or find in a credential dump from another breach. When password authentication is disabled, every one of those automated attacks fails at the protocol level before any credentials are even checked.
Root SSH Login Is Flat-Out Wrong
Allowing direct SSH login as root compounds the problem. Root is a known, predictable username on every Linux system — it is always the first target. More importantly, root sessions have no audit trail. When five admins can all SSH in as root, there is no way to determine who ran a destructive command or made a configuration change. Named accounts with sudo give you accountability, traceability, and least-privilege access.
Even with key-only authentication, allowing root login is still wrong. If that key is ever compromised — stolen laptop, leaked.ssh directory, malicious insider — the attacker lands directly in a root shell with no barriers. With PermitRootLogin no, a compromised user key still requires a working sudo escalation to reach root, which is a meaningful additional checkpoint.
Before you proceed: You must have a named, non-root user account with a working SSH key and sudo privileges already configured on this server. Disabling password authentication and root login without a working key will lock you out completely. If you have not done this yet, see the Adding a New User on Fedora 44+ guide first.
All commands in this guide are run as your named user account using sudo — not as root.
How the Drop-In Works
Fedora's default /etc/ssh/sshd_config includes this directive near the top:
Include /etc/ssh/sshd_config.d/*.confAny .conf file placed in /etc/ssh/sshd_config.d/ is loaded in alphabetical order. OpenSSH uses a first-match-wins rule — the first time a directive appears, that value sticks. A file prefixed with 00- loads before any other drop-in, so its directives cannot be overridden by anything that loads after it — including cloud-init's 50-cloud-init.conf on Ubuntu, which would otherwise re-enable password authentication.
This approach is preferred over editing /etc/ssh/sshd_config directly. Drop-in files survive package updates cleanly and make your local changes explicit and easy to audit.
Step 1 — Verify Your Fallback
Before making any changes, confirm that you can log in as your named user with your SSH key right now. Open a second terminal and connect without closing your current session:
ssh youruser@your-server-ipIf the connection succeeds without prompting for a password, your key is working. Keep both sessions open throughout this guide.
Keep your current session open the entire time. If something goes wrong — a typo in the config, reloading the wrong service — your existing session stays alive and you can fix it. Closing it before you have verified the changes work is how people lock themselves out of servers.
Step 2 — Create the Hardening Drop-In
Create /etc/ssh/sshd_config.d/00-Meikaku_SSHD_Hardening.conf with the following content:
sudo tee /etc/ssh/sshd_config.d/00-Meikaku_SSHD_Hardening.conf << 'EOF' > /dev/null
# Meikaku SSH hardening overrides
# Never allow root to log in over SSH
PermitRootLogin no
# Key-based login only
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
# Extra safety
PermitEmptyPasswords no
EOFWhat each directive does and why it is here:
- PermitRootLogin no — Blocks any SSH login as the
rootuser. Root is always the first account attackers target, and direct root sessions produce no audit trail. Admins should always log in as a named user and escalate withsudo. - PubkeyAuthentication yes — Explicitly enables public-key (SSH key) authentication. This is on by default, but stating it explicitly makes the intent of this file unambiguous — it is not trying to disable all authentication, it is replacing passwords with keys.
- PasswordAuthentication no — Disables username/password login entirely. This is the most impactful single change you can make to an SSH server. Every automated brute force attack on the internet targets password authentication; with this off, those attacks become completely pointless.
- KbdInteractiveAuthentication no — Disables keyboard-interactive authentication, which is a separate protocol path that some PAM modules (and older SSH clients) use to present a password prompt. On modern OpenSSH and Fedora, leaving this enabled while disabling
PasswordAuthenticationcan still allow PAM-based password prompts to appear. Turning it off closes that gap. - PermitEmptyPasswords no — Prevents login to any account that has no password set. This is a sane baseline that closes an edge case: a newly created account with an empty password field would otherwise be reachable with a blank password if password authentication were somehow re-enabled.
Set ownership and permissions so only root can read or modify it:
sudo chown root:root /etc/ssh/sshd_config.d/00-Meikaku_SSHD_Hardening.conf
sudo chmod 600 /etc/ssh/sshd_config.d/00-Meikaku_SSHD_Hardening.confConfirm the contents look correct:
sudo cat /etc/ssh/sshd_config.d/00-Meikaku_SSHD_Hardening.confStep 3 — Validate the Configuration
Before reloading SSHD, use its built-in config test to catch any syntax errors:
sudo sshd -tNo output means the configuration is valid. Any errors will be printed to the terminal — fix them before proceeding.
You can also dump the effective configuration after all drop-ins are merged and confirm every directive is set as expected:
sudo sshd -T | grep -i 'passwordauth|pubkeyauth|kbdinteractive|permitempty|permitroot'pubkeyauthentication yes
passwordauthentication no
kbdinteractiveauthentication no
permitemptypasswords no
permitrootlogin noStep 4 — Reload SSHD
Reload the daemon to apply the new configuration. A reload re-reads the config without dropping existing connections — your open sessions stay alive.
sudo systemctl reload sshdreload is preferred over restart here. A restart drops all active SSH sessions including yours. A reload applies the new config to future connections only, leaving existing sessions undisturbed.
Step 5 — Verify the Changes Work
Confirm Password Auth Is Rejected
From a third terminal (not your open sessions), attempt to connect with the -o PasswordAuthentication=yes flag to force a password prompt:
ssh -o PasswordAuthentication=yes -o PubkeyAuthentication=no youruser@your-server-ipYou should see Permission denied (publickey). — the server refused to offer a password prompt at all.
Confirm Root Login Is Rejected
Attempt to connect directly as root using your key:
ssh root@your-server-ipYou should see Permission denied (publickey). — root login is blocked regardless of whether a valid key exists.
Confirm Normal Key Login Still Works
Open one more session as your named user to confirm nothing broke:
ssh youruser@your-server-ipOnce you have confirmed all three, you can close your original fallback sessions. The server is now hardened.
Debian and Ubuntu Differences
The configuration file paths are identical on Debian and Ubuntu — /etc/ssh/sshd_config and /etc/ssh/sshd_config.d/ work the same way. The drop-in approach described in this guide applies without modification.
The one meaningful difference is the service name. On Fedora the SSH daemon is managed as sshd. On Debian and Ubuntu it is managed as ssh:
| Distribution | Reload command | Config test |
|---|---|---|
| Fedora 43+ | sudo systemctl reload sshd | sudo sshd -t |
| Debian / Ubuntu | sudo systemctl reload ssh | sudo sshd -t |
Ubuntu cloud images often ship with a /etc/ssh/sshd_config.d/50-cloud-init.conf that sets PasswordAuthentication yes. Because OpenSSH uses first-match-wins, the 00- prefix on the hardening file means it loads before cloud-init's drop-in and its settings stick. Always verify with sudo sshd -T | grep passwordauth before reloading.
Troubleshooting
"Permission denied (publickey)" when you should have access
If your own key login stops working after the reload, the problem is almost certainly the key itself — not the hardening config. Check that your authorized_keys file has the right permissions and is owned by the correct user:
sudo stat /home/youruser/.ssh
sudo stat /home/youruser/.ssh/authorized_keysThe .ssh directory must be 700 and authorized_keys must be 600, both owned by the user — not root. See the Fedora New User guide for the exact commands to fix ownership and permissions.
Reverting the Changes
If you need to undo the hardening — for example, on a managed host that requires password access — simply remove the drop-in and reload:
sudo rm /etc/ssh/sshd_config.d/00-Meikaku_SSHD_Hardening.conf
sudo systemctl reload sshdChecking What Is Active
To see every effective SSHD setting after all drop-ins are merged:
sudo sshd -T