Install and Harden an OpenSSH Server

OpenSSH is a secure transport, not a complete identity or network policy. Install it only on a host that is reachable through an approved private management path, create a named administrator, enroll and test a public key, and then reduce the authentication and forwarding surface. The examples use Debian-family package names; consult the distribution’s supported package and service names before applying them.

Do not publish SSH while hardening it. Keep the server behind the site’s private management boundary. Before any reload, keep a working recovery session and a local console or alternate administrator path available.

Install the supported package

# Confirm the distribution and package source before changing packages.
cat /etc/os-release
sudo apt update
sudo apt install --no-install-recommends openssh-server

Use the vendor repository and supported release documentation; do not add an untrusted repository because it has a newer version number. Confirm the service name and configuration path on the host:

systemctl status ssh --no-pager
command -v sshd
ss -lntp | grep ':22 '

A listening socket is not permission to expose it to the WAN. A host firewall and the upstream network policy should allow TCP/22 only from the documented administration path, or not at all until key enrollment is complete.

Create a named administrator and enroll a key

Do not use direct root login for routine work. Create a named account through the distribution’s supported account-management procedure, grant only the required administrative capability, and record who owns it. On a system where the operator already has a trusted local session:

sudo adduser admin
sudo usermod -aG sudo admin

On distributions that do not use the sudo group, follow that distribution’s documented administrator mechanism. Verify the group change in a new login rather than assuming the current shell has it.

Generate the key on the administrator’s device, not on the server:

ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_admin
ssh-copy-id -i ~/.ssh/id_ed25519_admin.pub admin@192.168.60.10

Use an approved private management address and verify the host key before ssh-copy-id. If that utility is unavailable, append the public key to the administrator’s ~/.ssh/authorized_keys through a trusted console or existing session. Never transmit the private key. Keep the passphrase-protected private key on the administrator’s device.

Use a drop-in, not an improvised rewrite

Many distributions include /etc/ssh/sshd_config.d/*.conf from the primary configuration. Drop-ins make ownership and rollback easier, but the exact include order matters: OpenSSH uses the first value it obtains for a keyword. Inspect the active file and included files before choosing a filename. Avoid editing a vendor file or blindly adding a second contradictory setting.

sudo grep -nE '^[[:space:]]*(Include|Port|ListenAddress|PasswordAuthentication|KbdInteractiveAuthentication|PubkeyAuthentication|PermitRootLogin|AllowUsers|AllowGroups|AllowTcpForwarding|X11Forwarding)' /etc/ssh/sshd_config
sudo find /etc/ssh/sshd_config.d -maxdepth 1 -type f -name '*.conf' -print 2>/dev/null | sort

Create a site-owned file using sudoedit, after confirming the include order. A filename such as 60-site-hardening.conf is only a convention; do not assume it overrides an earlier value.

# /etc/ssh/sshd_config.d/60-site-hardening.conf
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no
X11Forwarding no
AllowTcpForwarding no
PermitTunnel no
UsePAM yes
LogLevel VERBOSE

Keep AllowTcpForwarding no unless a reviewed forwarding use case requires it. If a service needs forwarding, constrain it with PermitOpen or PermitListen and a matching client alias rather than enabling arbitrary tunnels. Do not copy this block without checking PAM, account policy, and the distribution’s defaults.

Validate before reloading

First check syntax, then inspect the effective server settings. These commands do not reload the daemon:

sudo sshd -t -f /etc/ssh/sshd_config
sudo sshd -T -f /etc/ssh/sshd_config | grep -E '^(pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication|permitrootlogin|allowtcpforwarding|x11forwarding|permittunnel|usepam) '
sudo systemctl status ssh --no-pager

sshd -t catches syntax and key-file errors; sshd -T prints the effective policy. If either check fails, do not reload. Fix the file or restore the last known-good site-owned drop-in through the console or an existing session.

Open a second terminal and authenticate as the named administrator with the intended key before disabling password authentication. Keep the first, known-good session untouched:

ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519_admin admin@192.168.60.10
id
sudo -v

Only after that test succeeds should the operator reload the service:

sudo systemctl reload ssh

Immediately test a fresh connection again. A reload is preferable to a restart for a configuration change because existing sessions can remain available, but it is not a substitute for a recovery plan. If the reload reports an error or the new session fails, retain the original session and correct the configuration from there; do not close every working session at once.

Define the administrative boundary

Use one or more of AllowUsers and AllowGroups only after deciding how service accounts and break-glass accounts are managed. These directives are global filters and can deny an account that a package or automation job needs.

# Example only: replace with the reviewed account and group policy.
AllowGroups ssh-admins
# Or, for a very small host:
# AllowUsers admin@192.168.50.20

Do not use a broad wildcard to compensate for a missing inventory. Root login, sudo authorization, file ownership, and SSH authentication are separate boundaries: disabling PermitRootLogin does not grant an administrator sudo, and membership in an administrative group does not make a key trustworthy.

Keep the management path private

  • Permit the SSH service only from the trusted management VLAN, a documented overlay interface, or a bastion. Do not add a WAN port forward or a firewall rule from “any” source.
  • Verify listeners with ss -lntp and confirm the host firewall and upstream policy agree with the intended source boundary.
  • Keep a console or tested alternate path for the host. Record how to restore the prior drop-in and how to undo an incorrect firewall change without guessing.
  • Review authentication logs, failed offers, account membership, key rotation, package updates, and effective sshd -T output after maintenance.

Continue with Manage SSH Users, authorized_keys, and sudo to delegate access without sharing an administrator credential.

Sequence navigation

Previous: Build a Reliable SSH Client Configuration · Next: Manage SSH Users, authorized_keys, and sudo

References