You are currently viewing How to Secure SSH Access on a Linux Server

How to Secure SSH Access on a Linux Server

An internet-facing SSH server with password prompts enabled, direct root login allowed, and listeners on every network interface invites more automated login attempts and makes unusual access harder to spot. A safer setup uses a named administrative account, SSH keys, deliberate access rules, and a recovery plan before making changes that could lock you out.

These steps are for systems you own or administer with permission, such as a home lab, cloud virtual machine, development server, or a workplace host covered by an approved policy. Commands vary slightly by distribution, but the underlying OpenSSH concepts are consistent across most Linux systems.

Know the SSH components and configuration files

The OpenSSH server process on the remote machine is usually called sshd. Its main configuration file is commonly /etc/ssh/sshd_config. Current distributions may also load configuration snippets from /etc/ssh/sshd_config.d/. On your workstation, SSH client preferences are stored in ~/.ssh/config.

Confirm that the server package is installed and that the service is running. Debian and Ubuntu systems usually use the openssh-server package, as do Fedora, RHEL, and related distributions. Check the service with:

sudo systemctl status ssh
# or, on some distributions
sudo systemctl status sshd

Before editing configuration files, keep one authenticated SSH session open and start a second session for testing. If the new connection fails, the original session gives you a way to fix the problem without relying on physical console or cloud-rescue access.

Terminal session showing SSH service settings

Start with an account that can use sudo

Use an ordinary account with controlled administrative access through sudo for remote administration. This leaves a clearer audit trail and avoids working as root for an entire session.

Create an account if necessary, then set a strong local password as an emergency fallback while you set up keys:

sudo adduser adminuser
sudo usermod -aG sudo adminuser

On systems that use the wheel group rather than sudo, follow the local administrative convention:

sudo usermod -aG wheel adminuser

Sign in as this account and verify that sudo works before blocking root SSH access. Check permissions as well: unrelated users should not be able to write to the account’s home directory, and the .ssh directory must be private enough for OpenSSH to trust its contents.

Use modern SSH keys instead of reusable passwords

Password-based login exposes a public server to credential guessing and password reuse. With public-key authentication, the server holds only the public key while the private key remains on the client device. Protect that private key with a passphrase so a copied key file cannot be used immediately.

On the client computer, generate an Ed25519 key pair:

ssh-keygen -t ed25519 -a 64 -C "adminuser@laptop"

The -a 64 option increases the work required to protect the private key with its passphrase. Use the suggested storage location unless you follow a documented key-management layout. Never email a private key, paste it into a ticket, commit it to a repository, or upload it. Only the file ending in .pub belongs on the server.

While password login is still temporarily enabled, install the public key with:

ssh-copy-id adminuser@server-address

You can also create ~/.ssh/authorized_keys for the target account and add the public-key line once. File permissions matter:

chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

Test key authentication in a separate terminal. If the private key has a non-default filename, name it explicitly:

ssh -i ~/.ssh/id_ed25519 adminuser@server-address

A successful connection should use the key and ask for the key’s passphrase, rather than the server account password. An SSH agent on the workstation can keep an unlocked key available for the current session, reducing repeated prompts while retaining passphrase protection on the key file.

Make server-side authentication rules explicit

Edit the SSH daemon configuration with an approved administrative editor:

sudoedit /etc/ssh/sshd_config

When supported by the distribution, use a snippet in /etc/ssh/sshd_config.d/ so package upgrades are less likely to overwrite local settings. Avoid leaving conflicting versions of the same setting across several files. OpenSSH’s final behavior depends on parsing order and, for many directives, the first value it reads.

PermitRootLogin no
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitEmptyPasswords no
AllowUsers adminuser
MaxAuthTries 3
LoginGraceTime 30
X11Forwarding no
AllowTcpForwarding no

What these directives change

Directive Purpose Important consideration
PermitRootLogin no Blocks direct SSH login as root. Use a sudo-capable account for administration.
PasswordAuthentication no Requires a supported non-password method, usually a key. Confirm key login works first.
KbdInteractiveAuthentication no Disables interactive challenge-response prompts. Check whether your approved MFA setup relies on it.
AllowUsers Limits SSH access to named accounts. Update it deliberately when adding administrators.
AllowTcpForwarding no Prevents SSH port forwarding through this server. Leave enabled only where a documented workflow requires it.

These settings are not universal. A managed MFA service may depend on keyboard-interactive authentication, and developers may need port forwarding to access a database in a private environment. Enable a feature only when an approved task requires it, then restrict who can use it.

Changing the SSH port may reduce random log noise, but it does not replace keys, access controls, updates, or a firewall. Services can still be discovered, and authorized users have another setting to remember. Treat a non-default port as an operational choice, not a security boundary.

Validate before restarting the daemon

A typo or unsupported directive can prevent SSH from accepting new connections. Check the configuration before applying it:

sudo sshd -t

No output usually means the syntax check passed. To inspect the effective configuration, including loaded snippets, run:

sudo sshd -T | grep -E 'permitrootlogin|passwordauthentication|pubkeyauthentication|allowusers'

After validation, reload the service:

sudo systemctl reload ssh
# or
sudo systemctl reload sshd

A reload is generally preferable to a restart because it applies valid settings without needlessly ending active sessions. Use the second terminal for a fresh login, then verify that the permitted account can use its key, root is rejected, and password-only authentication fails.

Key-based remote login protected by access rules

Limit network exposure with a firewall and trusted paths

Make SSH reachable only from networks that need it. For a private server, the best practical option may be no public SSH exposure at all, with access provided through a VPN, managed bastion host, or provider console. If direct access is required, allow SSH through the host firewall and limit source addresses where they are stable.

For example, a host managed with UFW can allow SSH only from a known office range:

sudo ufw allow from 203.0.113.0/24 to any port 22 proto tcp

Replace that documentation-only range with one owned by your authorized network. Do not apply remote firewall rules without a recovery route, especially through the same SSH connection affected by those rules. Firewall design, rule order, and cloud security groups need separate review; the existing guide on Pagination Security: How a Simple Page Number Can Leak Your Entire Database is unrelated to SSH administration, so it should not be used as a firewall reference.

For temporary contractor or support access, create a separate account, add a dedicated public key, and define how access will expire. Do not share an administrator’s private key or use a shared password. Remove the key entry and account access as soon as the approved work is complete.

Protect keys and use a client configuration

A private SSH key is an authentication credential. Keep it only on devices you control, use full-disk encryption and screen locking, and revoke or replace keys that may have been exposed. In higher-value environments, hardware-backed security keys can prevent private key material from being exported while still supporting SSH authentication.

A client configuration file makes repeat connections less error-prone. On the client, create or edit ~/.ssh/config and set its permissions to 600:

Host project-server
    HostName server.example.internal
    User adminuser
    IdentityFile ~/.ssh/id_ed25519_project
    IdentitiesOnly yes
    ServerAliveInterval 30
    ServerAliveCountMax 3

IdentitiesOnly yes stops the client from offering every key loaded in an agent, which can prevent confusing failures and unnecessary identity disclosure. You can then connect with ssh project-server. Before accepting a new server host key, confirm its fingerprint through a trusted administrative channel or console. A changed fingerprint may mean the server was rebuilt, but it can also indicate a routing or impersonation issue.

Logs, updates, and recovery planning

Authentication records can help separate a configuration error from an attempted intrusion. Debian-family systems often write SSH events to /var/log/auth.log. On systems using the systemd journal, use:

sudo journalctl -u ssh --since "24 hours ago"
# or
sudo journalctl -u sshd --since "24 hours ago"

Review the logs after configuration changes and at regular intervals. Repeated failures for unknown accounts, unexpected successful logins, and access from unfamiliar networks warrant investigation. Logs do not prevent access attempts, but they can reduce the time between an event and a response.

Keep OpenSSH and the operating system patched through the distribution’s supported update process. Back up relevant configuration files, record the server’s verified host-key fingerprint, and maintain console or rescue access for critical systems. If a key is lost, use that recovery path to add a replacement public key and remove the old entry from authorized_keys. Do not turn password authentication back on as a permanent shortcut.

For a final diagnostic check, open a new connection with verbose client output: ssh -vvv project-server. The output shows the offered key, selected authentication method, and the stage at which a connection fails without revealing the private key. Run it only against hosts you are authorized to administer, then compare the result with the server logs to identify the setting that needs correction.