logo
260722 |*| |a|

Comprehensive SSH Linux sysadmin guide

~296s

Overview: Generating and using SSH (Secure Shell) keypairs securely on Linux for host authentication purposes.

Motivation

SSH is the main tool used by sysadmins to remotely control servers in a secure way. Learning how to use and harden SSH is imperative for privsec enthusiasts.

Assumptions

  • you have root access to a VPS (Debian/-based) from a GNU/Linux machine
  • basic terminal and nano editor knowledge
  • ~30m time

0. Install OpenSSH on client

The openssh-client package should normally be installed by default on Debian 13 (your local machine, not the server).

Check with ssh. It should return a list of usage flags. If for some reason you don't have it just grab it from apt:

sudo apt update && sudo apt install openssh-client

1. Generate SSH keypair on client

To generate your SSH keypair run:

ssh-keygen -o -a 100 -t ed25519

Reply yes when asked if the keys should be stored as /home/$user/.ssh/id_ed25519.

Note: run the command with fewer key derivation function rounds (ie. -a 75) only if your machine can't handle the load (a higher value == higher privkey passphrase strength vs brute force attacks).

Note: 'ed25519' is the recommended key type by OpenSSH; do not use 'rsa' or 'ecdsa'.

2. Harden SSH configuration on client

The main SSH file is /etc/ssh/ssh_config and it includes all files in the /etc/ssh/ssh_config.d/ directory.

Check what file(s) are imported from that folder (if any):

ls /etc/ssh/ssh_config.d

You might see something like this on Debian 13:

20-systemd-ssh-proxy.conf

To overwrite the system-wide defaults we need to create a new file with a higher number prefix like 30-security.conf since SSH config files are read in filename order (settings in higher/later files are applied last when setting the same option):

sudoedit /etc/ssh/ssh_config.d/30-security.conf

Let's safely apply some of the best and most recommended cryptographic algorithms available today:

Host *
AddressFamily inet
StrictHostKeyChecking accept-new
VisualHostKey yes
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr
MACs umac-128-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
KexAlgorithms sntrup761x25519-sha512,sntrup761x25519-sha512@openssh.com,mlkem768x25519-sha256,curve25519-sha256,curve25519-sha256@libssh.org
HostKeyAlgorithms sk-ssh-ed25519@openssh.com,ssh-ed25519
PubkeyAcceptedAlgorithms sk-ssh-ed25519@openssh.com,ssh-ed25519

Press CTRL+X > Y > Enter to save and exit the editor (assuming the default is nano on Debian).

Note: only include 'AddressFamily inet' if you don't want to use IPv6.

Note: use 'StrictHostKeyChecking yes' if the host key is already in 'known_hosts'.

2.1 (optional) Check config on client

Use ssh -G to display the effective values after all SSH config files are processed:

ssh -G localhost | grep -Ei 'visualhostkey|ciphers|macs|kexalgorithms|hostkeyalgorithms|pubkeyacceptedalgorithms'

The output should be the options that we set in the 30-security.conf file. If some values differ, make sure you don't have another file in /etc/ssh/ssh_config.d/ with a higher prefix (31+).

3 Install OpenSSH on server

sudo apt update && sudo apt install openssh-server

3.1 Harden SSH configuration on server

Open two terminal tabs/windows and establish two separate SSH connections to the server, for backup purposes:

ssh root@[SERVER-IP]

Restart the sshd daemon:

systemctl restart sshd

If both connections are still alive, try opening a third terminal window and test new connections:

ssh root@[SERVER-IP]

Proceed if everything is still working as expected (no interruptions).

Similar to what we did on the client, let's create a file in /etc/sshd_config.d/:

sudoedit /etc/ssh/sshd_config.d/30-security.conf

And paste the following values:

Protocol 2
AddressFamily inet
MaxAuthTries 3
HostKey /etc/ssh/ssh_host_ed25519_key
HostKeyAlgorithms ssh-ed25519
PubkeyAcceptedAlgorithms ssh-ed25519,sk-ssh-ed25519@openssh.com
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com
MACs umac-128-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
KexAlgorithms sntrup761x25519-sha512,sntrup761x25519-sha512@openssh.com,mlkem768x25519-sha256,curve25519-sha256,curve25519-sha256@libssh.org
KbdInteractiveAuthentication no
UsePAM yes
AllowAgentForwarding no
AllowTcpForwarding no
X11Forwarding no
PrintMotd no
DebianBanner no

Note: only include 'AddressFamily inet' if you don't want to use IPv6.

4. Install SSH pubkey to server

You can either upload your user SSH key to the server or share root's key (if any) by copying it over to the newuser home. Choose one of the options below.

4.1 Option A: Upload user key

To copy the public SSH key to the server, run ssh-copy-id on the client:

ssh-copy-id -i ~/.ssh/id_ed25519.pub root@[SERVER-IP]

The output should be similar to this:

/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/user/.ssh/id_ed25519.pub"
The authenticity of host [SERVER-IP] can't be established.
ECDSA key fingerprint is SHA256:[SERVER-FINGERPRINT].
Are you sure you want to continue connecting (yes/no/[fingerprint])?

Note: replace '[SERVER-IP]' with the actual IP address of the server and 'root' with your provider default first time login user name.

4.2 Option B: Reuse root key (if any)

Switch to root if necessary:

su - root

Copy the key to $user home:

cp /root/.ssh/authorized_keys /home/$user/.ssh/authorized_keys

Now grant $user ownership over the folder:

chown $user /home/$user/.ssh/authorized_keys

Adjust permissions:

su $user && chmod 600 /home/$user/.ssh/authorized_keys

Note: replace '$user' with a privileged username on your server.

4.1 Server login

You should be able to connect with:

ssh root@[SERVER-IP]

You SSH pubkey should be located in authorized_keys.

Note: replace 'root' and '[SERVER-IP]' accordingly and check if the SSH server fingerprint matches the one from your provider if possible.

Observations

  • always use strong passphrases for SSH keys
  • never share your private key with anyone and store it safely
  • check permissions if you have any issues:
    • [Client] ~/.ssh/id_*.pub either 600 OR 644
    • [Client] ~/.ssh/config either 600 OR 644
    • [Client] ~/.ssh/known_hosts should be 644
    • [Server] /etc/ssh/ssh_config and /etc/ssh/ssh_config.d/*.conf owned by root:root and 644
    • [Server] /etc/ssh/ssh_host_*_key owned by root:root and 600
    • [Server] /etc/ssh/ssh_host_*_key.pub owned by root:root and 644
    • [Client/Server] ~/.ssh/ folder should be owned by $user:$user and 700
    • [Client/Server] ~/.ssh/authorized_keys should be 600

Consult the Linux server security essentials1 guide for tips on how to lock down SSH even more by restricting root access entirely, change the default port and more.