OneLinersCommand workbench
Guides
Security / System Administration

Harden SSH and require key-based login

Introduce per-user keys, validate a drop-in, test a second session, and only then disable password and root login.

35 min8 stepsChanges system stateRevision 2
Save or explore
Save to collectionCreate a collection in the sidebar first.
0 of 8 steps completed
Goal

Reduce remote-login attack surface without locking administrators out.

Supported environments
  • Ubuntu Server 22.04 LTS, 24.04 LTS
  • OpenSSH 8.9+, 9.x
Prerequisites
  • Recovery path Keep console access and the working SSH session open.
  • Client key Create an Ed25519 key with a passphrase on the client.
  • Administrator inventory Know every account that must retain access.
Operating boundary

OneLiners never runs these steps or stores secrets. Review placeholders, versions, current state, and change-control requirements before using a command.

Full guide

What you will build

System
  • A passphrase-protected Ed25519 administrator key that remains on the client and a matching public key installed for one named server account.
  • An Ubuntu OpenSSH drop-in that requires public-key authentication, denies direct root login and disables interactive password paths.
  • A lockout-resistant validation sequence using sshd syntax checks, a retained session, a second positive login and an explicit negative password test.
Observable outcome
  • A new SSH session authenticates with the intended key while the original administration session remains available for recovery.
  • sshd -T reports public-key authentication enabled and password, keyboard-interactive and root login disabled.
  • A client that deliberately disables public-key authentication receives Permission denied (publickey).

Architecture

How the parts fit together

The client proves possession of a private key; sshd matches its public half in the target account's authorized_keys file and applies the effective server policy assembled from the main configuration plus ordered drop-ins.

Administrator clientStores the encrypted private key and invokes ssh or ssh-agent.
Target accountOwns ~/.ssh/authorized_keys and receives an interactive session after authentication.
sshd configurationDefines allowed authentication methods, root-login policy and connection limits.
Recovery channelProvides console or retained-session access if a new connection fails.
  1. The client and server establish an encrypted SSH transport and negotiate a host key.
  2. The client offers a public key; the server checks account ownership, permissions and authorized_keys.
  3. The client signs the exchange with the private key and sshd applies the effective authentication policy.
  4. Only after a separate key-authenticated session works is password authentication considered safely disabled.

Assumptions

  • The server runs Ubuntu 22.04 or 24.04 with OpenSSH and includes /etc/ssh/sshd_config.d/*.conf from the main file.
  • You have console access or an existing privileged SSH session that will remain open throughout validation.
  • Every administrator who must retain access has a separately attributable public key installed before passwords are disabled.
  • Host-key verification is already trusted. This guide does not tell users to bypass a changed-host-key warning.

Key concepts

Private key
The client-side credential used to create authentication signatures. It is never copied to the server.
authorized_keys
The account-owned file listing public keys that may authenticate as that account, optionally with per-key restrictions.
Effective configuration
The values sshd will actually use after includes, ordering, Match blocks and defaults are resolved; sshd -T displays it.
Reload
A configuration refresh that preserves existing sessions, unlike a disruptive service restart.

Before you copy

Values used in this guide

{{identity}}

Comment that identifies the key owner and purpose.

Example: alice@ops-laptop-2026
{{user}}

Named non-root administrator account on the server.

Example: alice
{{host}}

Verified DNS name or address of the SSH server.

Example: admin01.example.com

Security and production boundaries

  • A key without a passphrase becomes immediately usable if the client file is stolen. Use a passphrase and a trusted agent or hardware-backed key where appropriate.
  • Disabling passwords reduces online guessing but does not protect a stolen private key. Keep per-person keys, remove departed users promptly and review authorized_keys.
  • Do not disable host-key checking. An unexpected host-key change is a separate security incident to investigate.

Stop before continuing if

  • Stop if no console or retained privileged session is available.
  • Stop if sudo sshd -t emits any error or sshd -T does not show the intended effective values.
  • Stop if the new key-authenticated session fails; do not close the original session or disable another authentication path.
  • Stop and investigate any unexpected SSH host-key warning instead of accepting it automatically.
01

command

Inspect effective settings

read-only

Record current port, authentication, include, and root-login policy.

Why this step matters

Capture the effective policy before changing it so you can distinguish an existing setting from the effect of the new drop-in and preserve a rollback reference.

What to understand

sshd -T resolves compiled defaults and included configuration instead of merely printing text found in one file.

The anchored grep keeps the review focused on the listener, root policy, public-key and password paths, and any explicit user allowlist.

System changes

  • No persistent state changes; the command reads the effective daemon configuration.

Syntax explained

sshd -T
Tests and prints the effective OpenSSH server configuration.
grep -E
Uses an extended regular expression to select the named directives.
^
Anchors each alternative at the start of a configuration line.
Command
sudo sshd -T | grep -E '^(port|permitrootlogin|passwordauthentication|pubkeyauthentication|allowusers)'
Example output / evidence
port 22
permitrootlogin prohibit-password
passwordauthentication yes

Checkpoint: Save the baseline

sudo sshd -T | grep -E '^(port|permitrootlogin|passwordauthentication|pubkeyauthentication|kbdinteractiveauthentication|allowusers)'

Continue whenThe output records the current effective values and exits without an sshd error.

Stop whensshd cannot parse the existing configuration or the expected administrative port is unknown.

Security notes

  • Effective policy can vary inside Match blocks; later validate the actual user and source context when such blocks exist.

Alternatives

  • Use sshd -T -C with user, host and address when context-specific Match rules are present.

Stop conditions

  • Repair an already invalid configuration before adding a hardening drop-in.
02

command

Generate a client key

caution

Keep the private key on the client and protect it with a passphrase.

Why this step matters

Create a modern, attributable client credential before disabling passwords; without a proven replacement authentication path the server can be locked out.

What to understand

Ed25519 provides a compact modern key type. The key comment identifies owner and device but is not an authorization control.

The KDF rounds make offline passphrase guessing more expensive. Enter a strong unique passphrase when ssh-keygen prompts; the command intentionally does not place one on the command line.

System changes

  • Creates a private key and .pub public key in the client user's ~/.ssh directory.

Syntax explained

-t ed25519
Selects the Ed25519 key type.
-a 64
Uses 64 KDF rounds when protecting the private-key file with its passphrase.
-C
Stores an operator-readable identity comment in the public key.
Command
Fill variables0/1 ready

Values stay on this page and are never sent or saved.

ssh-keygen -t ed25519 -a 64 -C "{{identity}}"
Example output / evidence
Your public key has been saved in ~/.ssh/id_ed25519.pub

Checkpoint: Confirm the public half and private permissions

ssh-keygen -lf ~/.ssh/id_ed25519.pub && stat -c '%a %n' ~/.ssh/id_ed25519

Continue whenA SHA256 fingerprint is shown and the private key has mode 600 or stricter.

Stop whenThe private key was created without the intended passphrase, exposed, or has broad permissions.

If this step fails

ssh-keygen reports that id_ed25519 already exists.

Likely causeThe client already has a key using the default filename.

Safe checks
  • ssh-keygen -lf ~/.ssh/id_ed25519.pub
  • ls -l ~/.ssh/id_ed25519*

ResolutionDo not overwrite it blindly. Reuse it only if policy permits, or choose a distinct filename and configure that identity explicitly.

Security notes

  • The private key never belongs on the server or in a browser form.

Alternatives

  • Use a hardware-backed ed25519-sk key where supported and operationally recoverable.

Stop conditions

  • Rotate the pair if private material is printed or copied outside the trusted client.
03

command

Install only the public key

caution

Append the public key and verify ownership and permissions.

Why this step matters

Install only the public half for the exact named account, then let ssh-copy-id preserve the account-specific authorized_keys layout.

What to understand

The client authenticates using the currently available method and appends the selected .pub line remotely.

The operation is additive. Review the complete authorized_keys file afterward so an unexpected pre-existing key is not silently ignored.

System changes

  • Creates or appends to the target account's ~/.ssh/authorized_keys file on the server.

Syntax explained

ssh-copy-id
Authenticates to the target and installs selected public keys in authorized_keys.
-i ~/.ssh/id_ed25519.pub
Limits installation to the explicitly named public key file.
user@host
Selects the exact remote account and verified server endpoint.
Command
Fill variables0/2 ready

Values stay on this page and are never sent or saved.

ssh-copy-id -i ~/.ssh/id_ed25519.pub {{user}}@{{host}}
Example output / evidence
Number of key(s) added: 1

Checkpoint: Test the specific identity before hardening

ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 {{user}}@{{host}} true

Continue whenThe remote command exits 0 using the new key.

Stop whenThe client still requires the account password for authentication or reports a host-key change.

If this step fails

ssh-copy-id reports success but the explicit-key test fails.

Likely causeWrong target account, unsafe ownership, a restricted key option, or sshd reading another authorized-keys path.

Safe checks
  • ssh -vvv -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 user@host
  • sudo journalctl -u ssh -n 50 --no-pager

ResolutionCorrect account ownership and the configured AuthorizedKeysFile path from the retained access session, then re-test.

Security notes

  • Verify the server host key out of band before sending credentials to a new hostname.

Alternatives

  • Provision public keys through approved configuration management for fleets.

Stop conditions

  • Do not disable passwords until the explicit key-only command succeeds.
04

config

Create a hardening drop-in

caution

Keep package defaults visible and limit authentication methods deliberately.

Why this step matters

A dedicated drop-in keeps local policy separate from package defaults and makes rollback a single-file operation while clearly removing interactive password paths.

What to understand

Ubuntu includes sshd_config.d near the beginning of its main configuration. OpenSSH generally uses the first obtained value, so review all earlier drop-ins and Match blocks.

PasswordAuthentication and KbdInteractiveAuthentication cover different prompts. Disabling both avoids leaving keyboard-interactive password authentication available.

System changes

  • Creates /etc/ssh/sshd_config.d/50-oneliners-hardening.conf and changes authentication policy after reload.

Syntax explained

PubkeyAuthentication yes
Allows public-key user authentication.
PasswordAuthentication no
Disables the SSH password authentication method.
KbdInteractiveAuthentication no
Disables keyboard-interactive challenges, including many password or OTP PAM prompts.
PermitRootLogin no
Rejects all direct SSH logins as root.
MaxAuthTries 4
Limits authentication attempts permitted for one connection.
LoginGraceTime 30
Allows 30 seconds to authenticate before disconnecting.
X11Forwarding no
Disables forwarding of X11 display connections.
File /etc/ssh/sshd_config.d/50-oneliners-hardening.conf
Configuration
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no
MaxAuthTries 4
LoginGraceTime 30
X11Forwarding no
Example output / evidence
Hardening drop-in saved

Checkpoint: Review the file and include order

sudo grep -RnsE '^(Include|PasswordAuthentication|KbdInteractiveAuthentication|PermitRootLogin|PubkeyAuthentication)' /etc/ssh/sshd_config /etc/ssh/sshd_config.d

Continue whenThe intended drop-in is visible and no earlier unexpected directive overrides the planned value.

Stop whenThe main file does not include the drop-in directory or a Match block changes the target account unexpectedly.

Security notes

  • Disabling keyboard-interactive authentication also disables OTP flows that depend on it; choose AuthenticationMethods deliberately if MFA is required.

Alternatives

  • Use an account-scoped Match block for a staged migration, with explicit tests for every affected account.

Stop conditions

  • Do not reload until every administrator has a working key and recovery access is present.
05

verification

Validate syntax and effective values

read-only

Never reload sshd after a failed configuration test.

Why this step matters

A syntax check must precede every reload, and the effective-value check proves that include ordering produced the intended policy rather than merely accepting valid text.

What to understand

sshd -t is silent on success and non-zero on failure. Chaining with && prevents the second command from masking a parse error.

sshd -T prints normalized lowercase directives, which is why the grep pattern uses lowercase names.

System changes

  • No persistent changes; both commands parse and resolve configuration.

Syntax explained

sshd -t
Checks server configuration syntax and required key files without starting a listener.
&&
Runs the effective-value inspection only if validation exits successfully.
sshd -T
Prints the effective normalized configuration.
Command
sudo sshd -t && sudo sshd -T | grep -E '^(permitrootlogin|passwordauthentication|pubkeyauthentication)'
Example output / evidence
permitrootlogin no
passwordauthentication no
pubkeyauthentication yes

Checkpoint: Require exact effective values

sudo sshd -t && sudo sshd -T | grep -E '^(permitrootlogin|passwordauthentication|kbdinteractiveauthentication|pubkeyauthentication)'

Continue whenNo validation error; root and interactive password paths are no while public-key authentication is yes.

Stop whenAny error appears or any effective value differs.

Security notes

  • Syntax validity does not prove account access; the second-session test remains mandatory.

Alternatives

  • Add -C context values when Match rules make the generic output insufficient.

Stop conditions

  • Never reload ssh after a failed or ambiguous validation.
06

command

Reload without dropping sessions

caution

Reload rather than restart during a remote-only change.

Why this step matters

Reload applies the validated policy to new connections while preserving the original session that can perform rollback.

What to understand

Ubuntu names the OpenSSH server unit ssh. A reload asks the existing daemon to re-read configuration without terminating established sessions.

The chained service-state check gives immediate evidence that the daemon remains active, but it is not a substitute for a new login.

System changes

  • Reloads the ssh service so subsequent connections use the new authentication policy.

Syntax explained

systemctl reload ssh
Requests a configuration reload without a full service stop/start.
systemctl is-active ssh
Returns active only when systemd sees the service running.
Command
sudo systemctl reload ssh && systemctl is-active ssh
Example output / evidence
active

Checkpoint: Keep recovery open

systemctl is-active ssh && sudo journalctl -u ssh -n 20 --no-pager

Continue whenThe service is active and recent logs show no configuration or listener error.

Stop whenThe service is failed, logs show an error, or the original session is lost.

Security notes

  • Do not restart remotely when a reload can apply the policy with less disruption.

Alternatives

  • Use console access to restart only when the installed service explicitly cannot reload.

Stop conditions

  • Keep the original privileged session open until both positive and negative tests pass.
07

decision

Open a second key-authenticated session

read-only

If it fails, keep the first session open, restore the drop-in, and inspect logs.

Why this step matters

A truly separate connection proves the server accepts a fresh key authentication under the new policy; the retained session alone proves nothing about new logins.

What to understand

PreferredAuthentications asks the client to try publickey first. For strict diagnosis also specify IdentitiesOnly and the intended key path.

Run the test from the real administration network so source-address Match rules, firewall policy and DNS are represented.

System changes

  • No persistent server changes; opens a new authenticated session.

Syntax explained

-o PreferredAuthentications=publickey
Prioritizes the public-key method for this client invocation.
user@host
Tests the exact named account on the intended server.
Command
Fill variables0/2 ready

Values stay on this page and are never sent or saved.

ssh -o PreferredAuthentications=publickey {{user}}@{{host}}
Example output / evidence
Welcome to Ubuntu 24.04 LTS

Checkpoint: Prove key-only administration

ssh -o PasswordAuthentication=no -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 {{user}}@{{host}} 'id && sudo -n true'

Continue whenThe session authenticates by key, prints the intended account, and confirms the expected sudo policy.

Stop whenAuthentication fails, the wrong account opens, or expected privilege escalation is unavailable.

If this step fails

The new session returns Permission denied (publickey).

Likely causeThe key, account, permissions or effective Match context differs from the tested baseline.

Safe checks
  • Keep the first session open
  • Run ssh -vvv with IdentitiesOnly
  • Tail sudo journalctl -fu ssh from the retained session

ResolutionRestore interactive authentication if needed, correct the key path or context, validate and reload before repeating.

Security notes

  • A successful login should still verify the expected username and privilege path.

Alternatives

  • Use a second trusted administrator client if the primary client environment may hide agent behavior.

Stop conditions

  • Do not close the original session until this independent login works repeatedly.
08

verification

Confirm passwords are refused

read-only

Explicitly request password authentication from a trusted client.

Why this step matters

Positive key login does not prove passwords were disabled, so deliberately remove public keys from one test connection and require the server to refuse it.

What to understand

PubkeyAuthentication=no prevents the client from succeeding with an agent key. PreferredAuthentications=password asks only for the method that should now be unavailable.

Permission denied (publickey) indicates the server advertises only the allowed public-key path. A password prompt or successful login is a failed hardening result.

System changes

  • No persistent changes; performs a deliberately unsuccessful authentication attempt.

Syntax explained

-o PubkeyAuthentication=no
Disables client use of public keys for this one test.
-o PreferredAuthentications=password
Requests password authentication, which the server should refuse.
Command
Fill variables0/2 ready

Values stay on this page and are never sent or saved.

ssh -o PubkeyAuthentication=no -o PreferredAuthentications=password {{user}}@{{host}}
Example output / evidence
Permission denied (publickey).

Checkpoint: Require a controlled refusal

ssh -o PubkeyAuthentication=no -o PreferredAuthentications=password {{user}}@{{host}}

Continue whenThe connection ends with Permission denied (publickey) and never offers a password prompt.

Stop whenA password prompt appears or authentication succeeds.

Security notes

  • Run only a small number of controlled attempts so monitoring and lockout systems are not flooded.

Alternatives

  • Inspect sshd -T -C as supporting evidence, but keep the network-level negative test.

Stop conditions

  • Do not declare hardening complete while any unintended interactive method is still offered.

Finish line

Verification checklist

Configurationsudo sshd -tNo output and exit code 0.
Key loginssh -o PasswordAuthentication=no user@host trueExit code 0.
Servicesystemctl is-active sshReturns active.

Recovery guidance

Common problems and safe checks

The server still asks for a password after the public key was copied.

Likely causeThe client offered another key, authorized_keys ownership or modes are unsafe, or the account is reading a different home directory.

Safe checks
  • ssh -vvv -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 user@host
  • namei -l ~user/.ssh/authorized_keys
  • sudo journalctl -u ssh -n 50 --no-pager

ResolutionSelect the intended identity explicitly, correct owner-only write permissions and re-run the positive login before changing server policy.

sshd -t reports a bad configuration option or syntax error.

Likely causeA directive is misspelled, unavailable in the installed version, or placed incorrectly in the drop-in.

Safe checks
  • sudo sshd -t
  • sudo sshd -T
  • sshd -V 2>&1 | head -n 1

ResolutionRestore or correct the drop-in from the retained session. Reload only after sshd -t exits successfully.

A second key login works but password login still succeeds.

Likely causeAn earlier drop-in sets the first effective value, a Match block changes the account, or keyboard-interactive authentication remains enabled.

Safe checks
  • sudo sshd -T | grep -E '^(passwordauthentication|kbdinteractiveauthentication|authenticationmethods)'
  • sudo sshd -T -C user=user,host=host,addr=client_ip

ResolutionCorrect drop-in ordering and applicable Match rules, validate the context-specific effective configuration, then reload and repeat the negative test.

New sessions fail after reload while the original session remains connected.

Likely causeThe account key was not installed correctly, the policy is more restrictive than intended, or a network control changed at the same time.

Safe checks
  • Keep the original session open
  • sudo journalctl -fu ssh
  • sudo sshd -T

ResolutionRestore or rename the hardening drop-in, validate, reload, and prove recovery login before investigating a new hardening attempt.

After the procedure

Alternatives and next steps

Consider these alternatives

  • Use FIDO2-backed OpenSSH keys for phishing-resistant hardware possession when client and server versions support the selected key type.
  • Add centrally managed certificates or an identity-aware access gateway for larger fleets instead of manually copying long-lived keys.
  • Keep passwords temporarily enabled for accounts not yet migrated, but narrow access and set a dated removal plan rather than applying a partial untracked policy.

Operate it safely

  • Inventory authorized keys by owner, device, creation date and planned rotation date.
  • Add connection-rate controls, centralized authentication logs and alerts for repeated failures without exposing key material.
  • Evaluate per-key restrictions, AllowUsers or Match blocks only after testing the exact account and source-address context.
  • Move high-value administrator identities to hardware-backed keys and maintain a separately controlled recovery procedure.

Reference

Frequently asked questions

Why keep the original session open after reload?

Existing SSH sessions normally survive a reload and provide the safest immediate path to inspect logs or restore the drop-in if new authentication fails.

Is PermitRootLogin prohibit-password enough?

It still permits direct root login by public key. This baseline uses PermitRootLogin no and expects administrators to log in as named accounts and elevate through sudo.

Should I delete all passwords?

Not as part of this change. First prove key-only SSH, preserve console recovery and manage local or emergency credentials under a separate reviewed account policy.

Recovery

Rollback

Restore authentication from the open session or console.

  1. Remove or rename the hardening drop-in.
  2. Run sudo sshd -t.
  3. Reload ssh only after validation passes.
  4. Confirm recovery login before closing the original session.

Evidence

Sources and review

Verified 2026-07-24Review due 2026-10-22
Ubuntu OpenSSH server documentationofficialOpenSSH sshd_config manualofficial