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
Simple (remote) login
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:
-mnot specified, so will use new openSSH format instead of PEM
-anumber 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
-tspecifies type of key
-fspecifies output file, commonly
id_ed25519but can be more specific like
-Ccomment 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
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
echo $SSH_AGENT_PID $SSH_AUTH_SOCK
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/* ssh-add
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
Host <remote-host> HostName <IP-Address> User <username> IdentityFile ~/.ssh/id_ed25519 IdentitiesOnly yes
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.
Restrict access to the root user can be achieved by adapting
/etc/ssh/sshd_config on the remote server and add the line
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 firstname.lastname@example.org.* AllowGroups students staff email@example.com
In this case, users
bob as well as users with group
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 (192.168.0.2).
The same way, users and groups can be disallowed using
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:
DenyGroups, and finally
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[...]
Likewise, you can also restrict the network location using the
from="192.168.1.0/24" ssh-rsa AAAAB3[...]
NOTE: For ED25519 keys, key entries would of course start with
- proxy hopping
- security token / solo-key
- from=, command=, authorized_keys file format