Guides for hardening and configuring Secure Shell (SSH) servers and clients.

Many systems automatically install OpenSSH. However, you should check the version (using ssh -V) and update if necessary (using sudo apt update && sudo apt upgrade openssh-server), as well as harden the default installation to avoid known vulnerabilities in the server’s implementation itself. You should also consider further restricting certain users, groups, and especially (possibly automated) clients who need access to a login shell, in accordance with the principle of least privilege.


Most operating system distributions provide the openssh-server package. Install it on a Debian-based GNU/Linux distribution by invoking:

sudo apt update && sudo apt install openssh-server


Configure SSH server


Configure SSH client

We strongly recommend that you configure your SSH client as soon as you have authentication credentials for logging in to an SSH server. Not only does this make your use of SSH simpler and faster, correct configurations help prevent operational security blunders such as attempting to log in using an unintended username, which may be logged on the remote system.


  • Let be the server to which you will be authenticating.
  • Let the_server be your personal alias for the server.
  • Let example_user be the remote username that you are intended to authenticate as.
  • Let ~/.ssh/example_com_rsa be the SSH private key file you are using for passwordless authentication.

Do this to configure the SSH client on your local system given the above assumptions:

  1. Log in to the (unprivileged) user account you normally use on your system.
  2. In your local system user’s ~/.ssh/config file, add the following Host block:
    Host the_server
        User example_user
        IdentityFile ~/.ssh/example_com_rsa
  3. Save the file.

This ensures that you can access the correct server with the correct username simply by invoking ssh the_server.


In order to use SSH most securely, you should consider performing the following procedures, derived from this "Secure Secure Shell" article, among other sources, such as the sshd manual page. In a nutshell, these instructions provide the following:

  • Network-based hardening through careful selection of permissible key exchange algorithms, ciphers, and other cryptographic implementations.
  • Host-based hardening through Operating System-level and application-level configuration options.
  • Deactivation of undocumented and risky features (i.e., security vulnerability CVE-2016-0777).

Harden SSH server

Do this to harden your OpenSSH installation:

  1. In the server’s /etc/ssh/sshd_config file, prepend the following lines, which will preempt the application of any similar configuration directives that appear later in the file. (See the sshd_config(5) manual page for more details and configuration options.)
    # Network security considerations.
    # Consider moving off a default port.
    #Port 22
    # Consider listening only on the local interface and setting up a Tor Onion service instead; this blocks LAN access.
    # Cryptographic selections.
    # Server authentication.
    Protocol 2
    HostKey /etc/ssh/ssh_host_ed25519_key
    HostKey /etc/ssh/ssh_host_rsa_key
    # Client authentication.
    PasswordAuthentication no
    ChallengeResponseAuthentication no
    PubkeyAuthentication yes
    # Host-based security considerations.
    UsePrivilegeSeparation sandbox
    AllowGroups ssh-users
    # Choose a `root` user login policy. This should probably either be `no` (to disable root login completely)
    # or `forced-commands-only` (to allow the root user access only to a whitelisted command).
    PermitRootLogin no
    #PermitRootLogin forced-commands-only
    # Don't tell clients our operating system, they don't care.
    DebianBanner no
    • If you chose to include the diffie-hellman-group-exchange-sha256 key exchange algorithm (in the list of acceptable KexAlgorithms), edit the /etc/ssh/moduli file (see moduli(5) for details) to remove small (i.e., weak) primes using the following (bash) commands:
      awk '$5 > 2000' /etc/ssh/moduli > "${HOME}/moduli" # print lines where the fifth column is greater than 2000
      wc -l "${HOME}/moduli" # make sure there is something left in the file; we should see a positive integer
      sudo cp "${HOME}/moduli" /etc/ssh/moduli # replace the original moduli file with the filtered one
      rm "${HOME}/moduli" # remove the temporary moduli file
    • If the /etc/ssh/moduli file doesn’t exist, then create it:
      sudo ssh-keygen -G /etc/ssh/moduli.all -b 4096
      sudo ssh-keygen -T /etc/ssh/ -f /etc/ssh/moduli.all
      sudo mv /etc/ssh/ /etc/ssh/moduli
      sudo rm /etc/ssh/moduli.all
  2. Remove any existing but unused SSH keys, and regenerate the remaining recommended ones with stronger parameters (longer key sizes):
    cd /etc/ssh
    sudo rm ssh_host_*key*
    sudo ssh-keygen -t ed25519 -f ssh_host_ed25519_key -N "" < /dev/null
    sudo ssh-keygen -t rsa -b 4096 -f ssh_host_rsa_key -N "" < /dev/null
  3. Create the special-purpose ssh-users group:
    sudo groupadd ssh-users
  4. Before a user will be permitted to log in over SSH, they must be added to the ssh-users group with sudo usermod -a -G ssh-users $THE_USERNAME (where $THE_USERNAME is the username of the user to be added to the group; you will probably want to add your own user account, at a minimum).
  5. Finally, test the configuration with sshd -t or sshd -T for an extended check. No errors indicates a reasonable configuration file.

Test and apply the new configuration

Once configured as above, you can apply the new sshd_config on the server:

# Test the configuration again, just in case, and if the syntax check passes,
# send the main SSH server's process a hangup signal.
sudo sshd -t && sudo systemctl kill --kill-who=main --signal=SIGHUP sshd

Note that this might kill your connection, so be certain you can still access the server through some other means if the configuration does not take.

Harden SSH client

Do this to harden your SSH client:

  1. On your personal computer, in your user’s ~/.ssh/config file, prepend the following lines, which will preempt the application of any similar configuration directives that appear later in the file. (See the ssh_config(5) manual page for more details and configuration options.)
    # Make it easier to use Tor Onion services.
    Host *.onion
        ProxyCommand nc -x %h %p
        # If you prefer to use socat(1) instead of nc(1), use the following line instead:
        #ProxyCommand socat - SOCKS4A:localhost:%h:%p,socksport=9050
    # If you use GitHub, you will need a special KexAlgorithms line.
        KexAlgorithms diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1
    Host *
        # Don't send extraneous identity keys (which leaks metadata about who you are during the SSH connection).
        IdentitiesOnly yes
        ChallengeResponseAuthentication no
        PasswordAuthentication no
        PubkeyAuthentication yes
        KexAlgorithms diffie-hellman-group-exchange-sha256
        # The default macOS client prior to High Sierra 10.13.x only support a subset of the above HostKeyAlgorithms.
        # If you are using a macOS client, you may need to comment the above line and uncomment this one:
        # macOS clients only support a strict subset of the above Ciphers.
        # If you are using a macOS client, you may need to comment the above line and uncomment this one:
        #Ciphers aes256-ctr,aes192-ctr,aes128-ctr
        # macOS clients only support a strict subset of the above MACs.
        # If you are using a macOS client, you may need to comment the above line and uncomment this one:
        # Protect against CVE-2016-0777.
        UseRoaming no
        # macOS users may want to store public key passphrases in their macOS Keychain facility:
        #UseKeychain yes
        # Clients may also wish to automatically load public keys into `ssh-agent(1)` upon use:
        #AddKeysToAgent confirm
  2. Generate (or re-generate) your client’s identity keys with strong values:
    # Generate an RSA key with 4096 bits. Use the new SSH key format (`-o`), with 100 key derivation function rounds (-a).
    ssh-keygen -t rsa -b 4096 -o -a 100
    # ED25519 keys are always saved in the new SSH key format.
    ssh-keygen -t ed25519 -a 100
  3. Copy your newly generated SSH public key to your user’s ~/.ssh/authorized_keys file on the server, possibly using ssh-copy-id(1) (or any file transfer mechanism).
  4. Remove unhashed addresses from your known_hosts file(s):
    ssh-keygen -H
    # If everything looks okay, then...
    rm -i ~/.ssh/known_hosts.old        # ...delete the backup file created by `ssh-keygen`.

Apply application-level restrictions

Before you apply application-level restrictions, consider whether or not your use case requires access to a shell in the first place. If you can avoid creating an Operating System user account and providing a login shell entirely, you may be able to position yourself with a stronger security posture since you will never have exposed the possibility of gaining direct shell access to potential attackers in the first place. The rest of this section assumes you have already come to the conclusion that a shell provided by SSH is required.

Restrict allowed commands based on authorized SSH keys

TK-TODO: Use the command="…" option in the authorized_keys file to restrict logins made with specific public keys to a specific command invocation.