Skip to content

SSH Configuration

After SSH Key Authentication, a single connection can already require a long command like ssh -i ~/.ssh/id_work [email protected], especially once several servers and several keys are in play. There's also a second, still-open question: which authentication methods the server itself allows, and whether root can log in directly at all. These are two separate concerns — convenience on the client side, and policy on the server side — and they're controlled by two entirely different configuration files.

Two Independent Configuration Files

SSH has two completely separate levels of configuration:

File Scope Controls
Client ~/.ssh/config per user which server to connect to, with which parameters
Server /etc/ssh/sshd_config system-wide (root) who can log in to this server, and how

Keeping these two apart matters: a change in the client configuration only affects how ssh behaves on your own machine; a change in the server configuration applies to everyone connecting to that server.

Client Configuration: ~/.ssh/config

If the file doesn't exist yet, create it:

touch ~/.ssh/config
chmod 600 ~/.ssh/config

Each server gets its own Host block:

Host prod-web
    HostName 192.168.1.50
    User alice
    Port 2222
    IdentityFile ~/.ssh/id_ed25519

Host staging-db
    HostName 10.20.0.15
    User deploy
    IdentityFile ~/.ssh/id_work

Now a short alias replaces the full command:

ssh prod-web

This is functionally identical to running ssh -p 2222 -i ~/.ssh/id_ed25519 [email protected].

The Most Common Directives

  • Host — defines which alias(es) the block applies to; multiple patterns are allowed (for example, Host *.internal);
  • HostName — the real address or domain name;
  • User — the remote username;
  • Port — a port other than the default 22;
  • IdentityFile — which private key file to use;
  • ProxyJump — connect through an intermediate (bastion/jump) server, for example:
Host internal-app
    HostName 10.20.0.30
    User deploy
    ProxyJump bastion-server

This is a common pattern in architectures where an internal network is only reachable through a single, tightly controlled bastion server: running ssh internal-app automatically connects first to bastion-server, then to the internal 10.20.0.30, without doing that two-step manually.

Settings Shared by Every Host

A Host * block applies settings to every server:

Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3
  • ServerAliveInterval 60 — the client sends a keep-alive request to the server every 60 seconds; this prevents a long-idle connection from being silently dropped by NAT or a firewall;
  • ServerAliveCountMax 3 — how many missed replies are tolerated before the connection is considered dead.

Note

Put the Host * block at the end of the file. OpenSSH reads the configuration top to bottom and takes the first value it finds for each parameter — so if Host * comes earlier, values in more specific blocks that follow it get ignored.

Server Configuration: /etc/ssh/sshd_config

This file controls the behavior of the sshd service and can only be edited with root privileges.

Key Directives

Port 22
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AllowUsers alice deploy
  • Port — which port the service listens on; choosing a non-default value is covered in more depth in SSH Hardening;
  • PermitRootLogin no — prevents the root user from logging in directly over SSH; the administrator has to log in as a regular user first and then use sudo — a direct application of the least-privilege principle from Root and sudo;
  • PasswordAuthentication no — allows key-based login only, disabling password attempts entirely;
  • PubkeyAuthentication yes — confirms key authentication is enabled (usually already the default);
  • AllowUsers — only the listed users are allowed to log in over SSH; every other system account — even one with a correct password or key — is rejected outright.

Danger

Always confirm that key authentication genuinely works before turning on PasswordAuthentication no. Getting this wrong risks being locked out of the server entirely — especially on a remote machine, where the only recovery path might be a hosting provider's console or rescue mode.

Warning

On Ubuntu 22.04+ (and most current distributions) the very top of /etc/ssh/sshd_config contains an Include /etc/ssh/sshd_config.d/*.conf line, and cloud images ship a drop-in there such as 50-cloud-init.conf. Because sshd_config takes the first value it finds for each setting and the include sits at the top, a directive in a drop-in file overrides the same directive you edit lower down in the main file. This is the frequent "I set PasswordAuthentication no but passwords still work" trap. Always confirm the effective value with sudo sshd -T | grep -i <directive> (used in the scenario below) rather than trusting the main file alone — and put lasting changes in their own drop-in, e.g. /etc/ssh/sshd_config.d/99-hardening.conf.

Safely Changing the Configuration

After any change to sshd_config, the syntax must be validated before reloading the service:

sudo sshd -t

No output means success. If there's an error, it's reported with the exact line number. Only then reload the service:

sudo systemctl reload ssh

reload is preferred over restart — it re-reads the new configuration without dropping existing connections. This matters especially for remote changes: if the new configuration turns out to be broken and the service is fully restarted, you could cut yourself off from the server; reload keeps the current session alive.

Warning

When changing sshd_config on a remote server, test a new connection in a separate terminal, without closing the current SSH session. If the new connection fails, the existing session is still there to undo the change. Editing, closing the terminal, and only then testing is the most common way to lock yourself out of a server.

Practical Scenario: Verifying an Access Plan Before Disabling Root Login

Problem: a new server currently only allows login as root; this needs to move to a safer setup.

Step 1 — check the current effective values:

sudo sshd -T | grep -iE 'permitrootlogin|passwordauthentication'

sshd -T prints all effective settings — both defaults and anything read from the file — which is more reliable than reading the file directly, since some values already differ from their documented defaults on a given install.

Step 2 — set up a regular user and key authentication first: following SSH Key Authentication, authorized_keys is prepared for alice, and login is verified with ssh alice@server in a new terminal.

Step 3 — confirm sudo access:

ssh alice@server "sudo -l"

Step 4 — change the configuration:

sudo sed -i 's/^#*PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
sudo sshd -t

Step 5 — reload while keeping the old session open, then test in a new terminal:

sudo systemctl reload ssh

In a new terminal:

ssh root@server
root@server: Permission denied (publickey,password).

Login as alice@server continues to work.

Step 6 — result and documentation: confirm root can no longer log in directly, and that alice can still log in with a key and run administrative tasks through sudo. Record the date and reason for the change (for instance, aligning with a security policy).

Common Mistakes

Running restart Directly, Without sshd -t First

Restarting the service with a syntax error in the configuration can leave it unable to start at all — in which case SSH access to the server is gone entirely.

Relying on a Single Open Session for a Risky Change

As noted above, closing the current session before testing a change removes any way to correct a broken configuration.

Writing the Wrong IdentityFile Path in ~/.ssh/config

If the path doesn't exist, or points to the wrong file (a .pub file, for example), ssh silently falls back to trying other default keys — which can be confusing to debug. Use the -v flag to see which key is actually being used.

Forgetting an Existing User When Updating AllowUsers

Replacing the whole AllowUsers value when adding a new user, instead of appending to it, can lock out users who were previously allowed.

Exercises

  1. Create a Host block in ~/.ssh/config for your lab server (alias, HostName, User, IdentityFile) and connect using ssh <alias>.
  2. From the output of sudo sshd -T | less, find the values of PermitRootLogin, PasswordAuthentication, and X11Forwarding, and write down the practical meaning of each.
  3. Repeat the scenario above: set up key authentication for a regular user, and only then enable PermitRootLogin no.
  4. Deliberately introduce a syntax error into sshd_config (for example, Port abc), observe how sudo sshd -t reports it, then fix it.

Verification criterion: for exercise 3, a direct ssh root@server attempt must return Permission denied, while ssh alice@server must still succeed and sudo -l must list available commands — if either check fails, the change was not applied correctly.

References