Advanced (open)SSH

Most Linux users have probably used SSH already in some way. As an admin, SSH to remote servers is daily business. Several administrative tools in fact rely on this piece of software.

Besides the well-known ssh user@host command, there are lots of options which can make your admin-life easier. This page lists the ones I use most often and serves as my personal cheat sheet.

WARNING: This is not a security-focused best practices guide! For hardening your servers w.r.t. SSH, have a look at this compilation.


Default paths where SSH looks for config and key files

~/.ssh, /etc/ssh

Simple (remote) login

ssh user@host

Simple (remote) copy (add -r for folders; recursive)

scp /local/path/to/src user@host:/remote/path/to/dest
scp user@host:/local/path/to/src /remote/path/to/dest

In the following I will restrict to the ssh command. Most configuration options are equally valid for scp (secure copy). For more advanced use cases you probably want to take a deeper look at rsync (my default: rsync -avzh --info=progress2 [--numeric-ids]).

Setup a secure SSH keypair


Some time ago, DSA or RSA with key sizes <2048 bits were common practice and considered sufficiently secure. Same for ECDSA (not to be confused with EdDSA), except that it’s “NSA-ware” (more precisely: NIST). In 2020+, you should generate new keys either using RSA with at least 2048 bits or, even better, use the new ED25519 signature algorithm, which is based on elliptic curves.

A nice overview of these terms is given for instance in the answers to ECDSA vs ECDH vs Ed25519 vs Curve25519.

Ok, so how to actually generate a new pair (with OpenSSH 6.5+)?

ssh-keygen -a 100 -t ed25519 -f ~/.ssh/id_ed25519 -C "user@host"

Options in detail:

  • -m not specified, so will use new openSSH format instead of PEM
  • -a number of KDF (Key Derivative Function) rounds (default: 16); can be thought of as a (linear, see e.g. this plot) way to secure against brute-force attacks at the expense of longer waiting time
  • -t specifies type of key
  • -f specifies output file, commonly id_ed25519 but can be more specific like hpc.admin.ed25519
  • -C comment to attach to the key, default is “user@host” but can be anything like “Name :: Affiliation/Position” or just an empty string “”

Choose a reasonably secure passphrase for your key!

You can display the fingerprint of your key with

# specific key
ssh-keygen -l ~/.ssh/id_ed25519
# choose from list
ssh-keygen -l
# also show ASCII art
ssh-keygen -lv


Now copy your newly generated public key to some remote host via

ssh-copy-id user@remote-host

This will create a new entry in ~/.ssh/authorized_keys on the remote host and allow you to SSH without typing in your remote user password.

ssh -i ~/.ssh/id_ed25519 user@remote-host

Instead, you now have to type the passphrase of your private key.

Benefit? Imagine you have 10 machines to connect to regularly, all with different users and passwords but all have your public key. You still need to remember only one passphrase.


Still too cumbersome if you need to type your SSH passphrase too often a day? No problem, ssh-agent is here to help. After booting your system, you type it once and the agent will take care of it as long as your session lasts.

Check if the agent is running


otherwise run

eval "$(ssh-agent -s)"

Add your key to the ssh-agent with

# add specific key
ssh-add ~/.ssh/id_ed25519
# add all keys in default path ~/.ssh/*

Config File

Have multiple keys or custom filenames and don’t want to always specify them with ssh -i filename? No problem. Just add matching entries in your config file in ~/.ssh/config:

Host <remote-host>
    HostName <IP-Address>
    User <username>
    IdentityFile ~/.ssh/id_ed25519
    IdentitiesOnly yes

BTW, ssh-agentwill automagically choose the right identity file for you, even if you do not specify it in the config or via -i option. However, it will try all available keys until one fits or all fail. This is prevented with IdentitiesOnly, letting SSH use only the specified one(s). You possibly want to put this option in the global section of your SSH config!

Restrict SSH access

There are certain situations where you want to limit access to a server. One way is to disable SSH entirely via

systemctl stop sshd.service

After submitting this command no user (including root) is able to SSH to this server. Mostly, this is not what you want. Instead, you probably want to limit SSH to certain users or groups.

NOTE: you have to restart sshd.service after each change in server-side configuration files.

Root User

Restrict access to the root user can be achieved by adapting /etc/ssh/sshd_config on the remote server and add the line

AllowUsers root

This of course only works if SSH root login is not disabled in the first place.

# entirely disable root ssh login
PermitRootLogin no
# enable password-based login (not recommended)
PermitRootLogin yes
# enable key-based login (arguable)
PermitRootLogin without-password
# the latter is synonymous to
PermitRootLogin prohibit-password

It is controversial if root SSH access via pubkey-only can be considered as “secure”. Instead, you should remote-login as normal user and then use sudo to elevate. See for example this discussion. Access can then be restricted using the sudoers file (see for instance this compilation).

Users, Groups and Locations

Of course, the latter config is not limited to the root user. In fact, you can select even entire groups and add network restrictions to each of these settings, e.g.

AllowUsers alice bob root@192.168.0.*
AllowGroups students staff admins@

In this case, users alice and bob as well as users with group students or staff may SSH from anywhere, whereas user root and users in group admin may only connect from the local network (which I assumed here to be 192.168.0/24) or a specific management node (

The same way, users and groups can be disallowed using DenyUsers and DenyGroups. It’s very much like white- and black-listing users and groups.

Precedence (from manpage)

“The allow/deny directives are processed in the following order: DenyUsers, AllowUsers, DenyGroups, and finally AllowGroups.”

Another handy config option is the Match block, which can be used for an even finer control:

Match Address 192.168..0.0/24
    PermitRootLogin yes

Match User alice, bob
    PasswordAuthentication yes

Match User charlie
    ForcedCommand echo "no ssh for you"

Restrictions via Authorized_Keys

SSH-key-access can be restricted also at the level of public keys. Say, for instance, you have a user on a server which should run a specific command at a certain time determined by some automated task running on a second server. Automated backups with rsync could be a possible scenario (see e.g. here).

One option would be to create a password-less SSH key and simply run something like

ssh -i /path/to/key user@server1 'touch filename'

Nice. But what if, by accident or after being compromised, this command is changed to

ssh -i /path/to/key testuser@server1 'rm *'

Not so nice. You could prevent this by limiting testuser to a certain command from the outset as shown above with user charlie in the sshd_config file. A more flexible option is to create a separeate key pair and use the first column of the authorized_keys file like so:

#change your key entry from 
ssh-rsa AAAAB3NzaC1ycEAAAA[....]
# to
command="touch filename" ssh-rsa AAAAB3[...]

This way, no matter what command is passed to SSH on the second server, testuser will always run the one given in authorized_keys, even if no specific command is passed at all. A generalization to multiple commands is easily set up using a script file.

Depending on your scenario, you probably want to supplement the first column with

command="touch filename",no-port-forwarding,no-X11-forwarding ,no-pty ssh-rsa AAAAB3[...] more details have a look at this nice tutorial or, as always, read the man pages.

Likewise, you can also restrict the network location using the from option:

from="" ssh-rsa AAAAB3[...]

NOTE: For ED25519 keys, key entries would of course start with ssh-ed25519.




  • proxy hopping
  • sshfs
  • security token / solo-key
  • from=, command=, authorized_keys file format

By continuing to use the site, you agree to the use of cookies. more information

The cookie settings on this website are set to "allow cookies" to give you the best browsing experience possible. If you continue to use this website without changing your cookie settings or you click "Accept" below then you are consenting to this. We only use session cookies!