Chaining/Multiplexing an SSH Connection

Author:  MikeW Date: 2015-07-14T00:22:11+00:00

Ever want to run multiple SSH scripts but get annoyed by having to authenticate for each one? Well it turns out you can configure SSH to accept multiple commands over a period of time. The name I found on the net for this is SSH multiplexing. Command chaining would be a better name in my opinion. Anyway, this technique allows you to call several commands that use SSH but you only authenticate once! That's right, authentication happens on the first command, no long waits for each step.

For example, I need to execute 2 rsync commmands to copy files to different parts of my web site. Here are the two commands.

rsync -vaz --rsh="ssh -l username"  --exclude=bin/  --exclude=*.DS_Store /Users/username/www/blog/ example.com:~/blog
    rsync -vaz --rsh="ssh -l username" /Users/username/www/index.html example.com:~/index.html

For each command I would need to authenticate with SSH and each step would have to wait a few seconds for that to happen. So now I can replace this with a series of commands, but before I do that, a little configuration and explanation.

To get this to work, you need to create two things in your .ssh directory.

  1. An empty file named config
  2. An empty directory named sockets

For you config file, enter the following:

host *
    ControlMaster auto
    ControlPath ~/.ssh/sockets/%r@%h-%p
    ControlPersist 600

The first line tells SSH that any host can use this command chaining feature. If you want to limit it to certain hosts it can be changed to just example.com: *.example.com

The second line enables the multi command feature. It tells SSH that if an SSH socket alread exists for a host, it is ok to reuse it.

The third line tells SSH where to store the socket information. This is why we created a sockets directory. The string %r@%h-%p tells SSH to name the socket file username@hostname-port. If the username you log in with is different then your login username, then you will need to change the name so it matches the remote host. For example: remote-username@host-port

Finally, the fourth line tells SSH how long to leave the socket open if the open socket is not closed. In this case a value of 600 seconds (10m) is specified. You can also use minutes: 60m as a unit of measure for this option.

With everything setup, let's take a look at our rsync commands. This time, we will wrap them in special SSH commands.

ssh -l remote-username -Nf example.com
    rsync -vaz --rsh="ssh -l username"  --exclude=bin/  --exclude=*.DS_Store /Users/username/www/blog/ example.com:~/blog
    rsync -vaz --rsh="ssh -l username" /Users/username/www/index.html example.com:~/index.html
    ssh -O exit example.com

The first command sets up the shared socket. The -l option specifies the login name. The -N option tells SSH not execute a remote command. The -f option tell SSH to wait in the background.

The last command closes the open socket for that host. The -O option passes a command for SSH to execute on the open socket. In this case, exit tells SSH to close the connection.

Well that is the short version, though not very short. If you need more information on this topic please take a look at the resources linked below from which this post was built.

Resources

Rackspace Developer Blog - Speeding up SSH Creation
Stack Exchange: Executing Multiple Rsync Commands