- 1 Overview
- 2 References
- 3 Debian packages
- 4 Server configuration
- 5 Client configuration
- 6 X11 Forwarding
- 7 Port Forwarding
- 8 Compression
- 9 Cipher selection
- 10 Running remote shell commands
- 11 SSH on the Mac
This page provides information about configuring and using SSH (or rather, the quasi-standard OpenSSH implementation).
- A very good introductory article about user identities.
- A very good introductory article about using ssh-agent
- Website of the excellent
- The first part of the article series "OpenSSH Key Management" by Gentoo creator Daniel Robbins. The second part also has details about using
keychain. The third part deals with SSH agent forwarding.
The following Debian package needs to be installed:
This is a meta package which resolves to
The SSH daemon's configuration is located in
The default configuration is sensible, so generally I don't fiddle with this.
One thing that you may wish to change is the log level. The default log level is INFO, which logs quite a lot. For instance it logs when the Nagios service check disconnects without an attempt to authenticate. If this inflates the log file too much, you could say
LogLevel = ERROR
Note that there is no log level WARNING in-between INFO and ERROR. At the moment I am staying on INFO because I don't want to interfere with fail2ban.
For future reference: The (unencrypted) private and public host keys are located in
/etc/ssh/ssh_host_dsa_key /etc/ssh/ssh_host_dsa_key.pub /etc/ssh/ssh_host_rsa_key /etc/ssh/ssh_host_rsa_key.pub
Per user configuration
To allow login by public/private key instead of password-based, those public keys that are allowed to login must be listed in
To quote from
man sshd: "The content of the file is not highly sensitive, but the recommended permissions are read/write for the user, and not accessible by others.". My personal file therefore looks like this:
patrick@pelargir:~$ l .ssh total 12 drwxr-xr-x 2 patrick patrick 4096 Jun 11 21:04 . drwxr-xr-x 8 patrick patrick 4096 Jul 13 20:00 .. -rw------- 1 patrick patrick 725 Nov 12 2009 authorized_keys patrick@pelargir:~$ cat .ssh/authorized_keys ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCuR259CxKjoSQd7cHy0IkXoUbmjqhTHkrSBX1NlZll0OluMVqZ/Pj6ntf4oqPL [...]
Note: See this HOWTO on the PGP page for a instructions on how to use GnuPG to generate an RSA key that is usable for SSH authentication.
Note: PuTTY generates public keys in PEM format. Use the following command to convert a public key from PEM format to OpenSSH format:
ssh-keygen -f foo.pem -i. Other input formats are also possible and can be specified using the
-m command line option.
Location of configuration files
The client's configuration is located in these files:
- /etc/ssh_config : Default configuration for all users on the machine
- ~/.ssh/config : User-specific configuration
Identity/Public key authentication
Instead of providing a password for authentication, it is also possible to identify using an RSA or DSA public/private keypair. Basically it works like this:
- You generate a keypair
- You copy the public key to the remote machine and add it to the file ~/.ssh/authorized_keys in the target user's home directory
- You keep the private key on the local machine in the file ~/.ssh/id_rsa (if it's an RSA key) in your home directory
- You initiate an SSH session
- SSH asks you for the private key's passphrase
- If the passphrase is correct, the login will be successful.
- If you don't want to enter the passphrase for each new SSH session, you have to either use an unencrypted private key (BAD idea), or use ssh-agent (see appropriate section further down)
- Note: When logging in, the private key is never transmitted from local to remote machine! Instead the two machines work out a challenge that can only be "solved" by the local machine when it has access to the decrypted private key. When the user supplies the correct passphrase, the local machine gains access to the decrypted private key, can "solve" the challenge and therefore prove to the remote machine that the local user is indeed who he claims to be. To see all the stuff that happens behind the scenes during a login, use the command line option -v.
To create an RSA public/private keypair (public key is stored in ~/.ssh/id_rsa.pub, private key is stored in ~/.ssh/id_rsa):
ssh-keygen -t rsa
To view the fingerprint of an RSA key (using the public part of the keypair):
ssh-keygen -lf id_rsa.pub
- If you want to allow multiple identities to login to a remote account, that account's authorized_keys file must contain a list of all those keys.
- If you want to have multiple identities on your local machine, each identity's private key must be placed in its own file. You then have to select the appropriate identity file using the
-icommand line option, or the identity file must be specified on a per-host basis in SSH's configuration file
~/.ssh/config. For instance, to use a different identity for each different user on a remote system, place the following snippet in
Host pelargir pelargir.herzbube.ch # %r expands to the remote user name IdentityFile ~/.ssh/%r.id_rsa
Multiple identities (roles) with which to connect to the same remote account
A real-life example that I use to distinguish between the administrator and user roles when working with Gitolite (see the GitServer page on this wiki):
Host gitolite-admin HostName git.herzbube.ch User gitolite3 IdentityFile ~/.ssh/admin.id_rsa IdentitiesOnly yes Host gitolite-user HostName git.herzbube.ch User gitolite3 IdentityFile ~/.ssh/patrick.id_rsa IdentitiesOnly yes
What does this mean?
- We have defined two host aliases: One is called "gitolite-admin", the other "gitolite-user"
- Whenever we refer to one of these aliases in the future, SSH will use the options below the alias to perform the connection to the server
- If we want to perform administrative duties, we use the alias "gitolite-admin" which will cause SSH to use the "admin" identity
- If we want to do normal developer work (which hopefully will be most of the time) we use the alias "gitolite-user", which will cause SSH to use the "patrick" identity
IdentitiesOnly yesoption is required to prevent
ssh-agentfrom offering the wrong key file to SSH. Instead,
ssh-agentis forced to only use the identity that is explicitly specified under the host alias. To understand the issue, let's have a look at the following scenario:
- You have done some work under the normal user identity, which means that
ssh-agenthas now cached that identity's key
- Now you want to perform admin work and try to clone the
gitolite-admin.gitrepository - BOOM, cloning does not work and you get a mysterious message "Repository read access denied"
- What happens here is this: Because
ssh-agenthas cached the normal user identity key, it offers that key to SSH every time a connection is about to be made. When SSH finds out that the key is allowed to login to the server's
gitolite3account, it happily accepts and uses the key. Once the connection has been established, SSH hands control over to the Gitolite software which finds out - too late - that the identity used does not have sufficient access rights to read the
- You have done some work under the normal user identity, which means that
- The problem here is conceptual: SSH only cares about authentication, not authorization - authorization is the domain of the application using SSH (Gitolite in this case). In other words: For SSH, every identity has the same "value": Either it is allowed to login (authenticate) to the remote side, or it is not. Gitolite, though, attaches an additional meaning to identities: Authorization, or access rights. The
IdentitiesOnlyoption must therefore be used to ensure that the proper identity is used on every connection attempt, regardless of the state of the
ssh-agentcache at connection time.
If you make repeated connections to the same remote user/host, it quickly becomes tiresome to enter the same passphrase for accessing the authenticating RSA key over and over again. One solution would be to store the private key unprotected, i.e. without a passphrase. For obvious reasons, this is not a very good solution.
An alternative is to use the Authentication Agent ssh-agent. ssh-agent will cache a private RSA key once it has been decrypted so that it can be used repeatedly for SSH connections. It works like this:
- Start ssh-agent, e.g. when you log in.
- This can be done automatically by adding the appropriate command to ~/.profile or some similar login-hook file.
- On some systems, automatic startup of ssh-agent might already be configured in a similar way.
- On Mac OS X, ssh-agent starts automatically when the first SSH connection is made.
- Use ssh-add to add the desired keys to ssh-agent
- ssh-agent will prompt you for the passphrase (is this true? or is it ssh-add which does the prompting?)
- On success, ssh-agent caches the decrypted key
- Make an SSH connection
- When ssh would normally require the private key for its operation, it will first query ssh-agent whether or not it has the required key
- ssh-agent never gives out the key itself. Instead, ssh tells ssh-agent to perform the required operation(s) on its behalf, and ssh-agent returns the operation's result back to ssh
- ssh-add -L lists all keys cached by ssh-agent
- ssh-add can also be used to remove keys from ssh-agent
Authenticating Agent Forwarding can be used to create an "authentication chain" that spans multiple systems. If you are logged in to a remote system A and from there would like to make another connection to remote system B, you can setup a forwarding mechanism so that ssh-agent on your local machine will be queried when you make the connection attempt to remote system B. In this way, the private authenticating RSA key never leaves your local machine. This forwarding mechanism is enabled like this:
ssh -A <host>
In the configuration file, the following enables forwarding:
The plain usage model of
ssh-agent has two disadvantages:
- On every login a new instance of
ssh-agentneeds to be started and
ssh-addneeds to be run. Therefore if you login multiple times on a machine, you have to enter a passphrase multiple times: Once per login.
- Programs that are run by
cronor otherwise run outside of a login shell do not have access to
ssh-agentand thus cannot benefit from passwordless remote logins.
keychain: This handy utility makes sure that a new instance of
ssh-agent is started only on the first login after a reboot. Subsequent login sessions then reuse the same instance of
ssh-agent. This means that you have to enter a passphrase only once. Because the single instance of
ssh-agent is running in the background, detached from any login shell, even
cron jobs can use that background instance of
On a Debian system, install the package
Then enable the utility by adding the following line to
eval `keychain --eval --agents ssh id_rsa`
--agentsoption specifies which agents should be started by
keychain. Currently only
gpg-agentare supported. If the option is omitted,
keychainruns those agents that it detects on the system.
id_rsais the name of the file that stores the private key that should be added to
ssh-agent. The file must be located in
~/.ssh. In the example above, the absolute path of the private key file is
~/.ssh/id_rsa. If more than one key should be added to
ssh-agent, the files can be listed as separate arguments.
keychainto print lines to
stdoutthat can be evaluated by the shell.
keychainemits code that is specific for the shell that is referenced in the
- Finally, the shell command
evalevaluates the lines that
keychainprints because of
man keychain for additional options and documentation (including shell script snippets),
keychain starts an instance of
ssh-agent, it stores information about the process in a file named:
This file is a shell script snippet that can be sourced by scripts that are run by
cron or inside other non-interactive shells. Example content:
pi@raspberrypi1:~$ cat .keychain/raspberrypi1-sh SSH_AUTH_SOCK=/tmp/ssh-GuyeaCeibai/agent.12345; export SSH_AUTH_SOCK; SSH_AGENT_PID=12345; export SSH_AGENT_PID;
The following shell script snippet can be added to any
cron script that wants to use
ssh-agent. The snippet also checks whether the private key
id_rsa is present.
[ -z "$HOSTNAME" ] && HOSTNAME=`uname -n` . $HOME/.keychain/$HOSTNAME-sh 2>/dev/null ssh-add -l 2>/dev/null | grep -q id_rsa || exit 1
A final warning: Because
ssh-agent keeps running even after you completely logout from the system, there is a certain additional risk in case someone gains unauthorized access to the system while the system is unattended: If an intruder manages to log in as
root or as the user on whose behalf
ssh-agent is running, the intruder at least can make use of the decrypted private keys that are cached by
ssh-agent by logging in to remote machines. If sufficiently skilled, the intruder might even be able to extract the private key itself from the
ssh-agent process. As a counter-measure you can add the
--clear option to the
keychain invocation in
~/.bash_profile. This causes
keychain to clear the currently cached private key(s) from
ssh-agent and ask again for the necessary passphrase(s). The idea is that
keychain should treat every new login as a potential security breach. Obviously this defeats the convenience of entering the passphrase(s) only once per machine reboot, so
--clear is really useful only on machines that are running unattended for long times.
Kudos: This excellent answer on the Unix StackExchange site pointed me towards
The following command logs into a remote system and forwards X11 traffic from that system to the local system (which acts as X server):
ssh -X <host>
Note: It appears that X11 forwarding circumvents access control set up with xhost (at least this is the case on my Mac OS X box). It becomes clearer why this is the case if we look at how ssh sets the DISPLAY variable on the remote system: localhost:10.0. This means that the X11 connection is not made through a normal X11 network connection (which would be protected by xhost), but the connection is made through the SSH connection. To the local X server it appears that a locally launched program (= ssh) wants to display stuff.
X11 forwarding may be enabled by default by adding the following to the local config file (either globally or for specific hosts only):
Port forwarding (tunneling) is similar to X11 forwarding, but more generalized. The following command establishes port forwarding:
ssh -L 9110:mail.example.net:110 shell.example.net
From now on, all connections to localhost:9110 are routed via shell.example.net to port 110 at the destination host mail.example.net. Notes:
- mail.example.net sees the connection as coming from shell.example.net
- Traffic between shell.example.net and mail.example.net is not encrypted!!!
- All locally logged in users can see and use port 9110; this can be either useful or dangerous...
- Users that are logged in via a remote connection cannot see or use port 9110, unless the user establishing the forwarding tunnel has specified the -g option
- Ports below 1024 are privileged and can be used for forwarding only with root privileges; this makes sense if you think of a multi-user system where it is not desirable that one user can change an important port such as 25 (SMTP) or 53 (DNS) into a forwarding tunnel, without the other users noticing
- On the server side, port forwarding can be disallowed by specifying AllowTcpForwarding no in the server config file /etc/ssh/sshd_config. I have read somewhere, though, that this may be circumvented if someone is really determined
Port forwarding may also be enabled through the local config file:
Hostname shell.example.com LocalForward 9110 mail.example.com:110
Note: Use RemoteForward to establish a "reverse-forwarding" connection, i.e. when you connect to a remote system, a port is forwarded from that remote system back to your local system.
Useful on a slow network connection: Data transferred over the SSH connection can be gzip compressed with the following command:
ssh -C <host>
Compression may also be enabled by adding the following to the local config file:
Compression yes CompressionLevel <lvl>
Possible compression levels are 1 (fast, worst compression) to 9 (slow, best compression). The default level is 4.
It is possible to select the Cipher that should be used for encrypting the SSH connection. Selecting a different cipher is probably most useful for SSH1 connections where the default cipher is the slow 3DES and it is desirable to select a faster cipher such as Blowfish.
The command to select a specific cipher is
ssh -c <cipher_spec> <host>
The cipher can be specified using one of the allowed keywords, or a comma-separated list of such keywords. The allowed keywords differ between SSH1 and SSH2. See the man page for details.
The cipher to use can also be specified in the configuration file (different options for SSH1 and SSH2):
Cipher <cipher> # SSH1 connections Ciphers cipher_spec> # SSH 2 connections
Running remote shell commands
Instead of running an interactive shell on the remote system, it is also possible to run a single command:
ssh <host> ls -l
It is possible to pipe data to the remote command:
tar cf - <srcdir> | ssh <host> 'cat >dest.tar'
(the remote command in this case is enclosed in single quotes to prevent the local shell from evaluating the ">" character)
SSH on the Mac
Before macOS 10.12 (Sierra)
When a user starts his first SSH session to a remote machine, launchd automatically starts an ssh-agent process in the background, which from then on captures all private keys that are used to login to remote machines. If a private key is protected with a passphrase, a GUI dialog pops up where you have to enter the passphrase (instead of a command line prompt in Terminal.app). Optionally, you can allow the passphrase to be stored in your personal Mac OS X keychain, in which case you will not have to enter the passphrase in the future (the entry into the keychain is made so that ssh-agent, ssh-add and ssh always have access to the passphrase).
Note: If you change or delete a private key file, ssh-agent continues to cache the old key (no doubt with surprising results) until you remove the cached key using ssh-add -d.
X11.app is launched automatically when an SSH connection is made with X11 Forwarding.
macOS 10.12 (Sierra) and later
As of macOS 10.12 (Sierra), ssh-agent no longer auto-loads previously loaded ssh keys when you log in to your account. The previous behaviour can be restored by adding the following two lines to
~/.ssh/config for every section that contains an
UseKeychain yes AddKeysToAgent yes
This solution comes from superuser.com.
To allow SSH login to a Macintosh machine, go to "Preferences > Sharing" and enable "remote login" ("Entfernte Anmeldung" on German systems). You must provide admin privileges to do so.