My (current) favorite SSH tricks

Posted: 04 Jul 2012

Tagged: trick ssh


As tools go, ssh is easily one of the most useful in my computer toolbox. There are a lot of tricks up its sleeve, and a lot of little gripes with it as well. These are some of my favorite ways to get it to do really cool things, and diminish problems at the same time.

The configuration

This is a very stripped down version of my configuration file, and the primary way I mitigate the aforementioned little problems.

Host charon
    hostname <alternate hostname>

Host ice5
    Protocol 2
    HostName ice5
    ProxyCommand ssh charon nc -q 0 ice5 22

Host ice6
    Protocol 2
    HostName ice6
    ProxyCommand ssh charon nc -q 0 ice6 22

Host armor2
    Protocol 2
    HostName armor2
    #forward local port 5902 to the VNC port on armor2
    LocalForward 5902 localhost:5900
    ProxyCommand ssh charon nc -q 0 armor2 22

Host *
    #use my local keys on remote machines
    ForwardAgent yes
    #keep the connection alive for finnecky servers, and kill it when the
    #connection has died
    ServerAliveInterval 15
    ServerAliveCountMax 3
    #allow local and proxy commands
    PermitLocalCommand yes
    #Set up control sockets so multiple ssh/scp/sftp sessions can share one
    ControlPath ~/.ssh/master-%r@%h:%p
    ControlMaster auto

The first section is important, it applies to all hosts, unless the settings are overridden by a specific host section later on. Each item in this version either fixes an issue or makes life easier in some way. ForwardAgent for example allows my local ssh-agent to be used from any target computer. In that way, all of my keys are stored on machines I control, but they can still be used from others so long as I am connecting originally from the machine they are on. Aside from that, there are a couple of settings to allow proxying, and keep finicky servers from causing disconnects, or connections from living too long after they are actually dead.

The last one of importance is the Control{Path,Mater} pair. These create a local socket whenever an ssh connection is made, and allow all simultaneous connections to that destination to use that socket. This has several consequences, the first is that one does not need to type their password again until the first connection is closed and a new one must be established. Additionally, it avoids connection setup, which can save a great deal of time on systems which insist on reverse DNS.

Trick 1: Forwarding ports

Frequently I find that services are only listed as available on local networks, or only on a local machine for that matter. My own machines have local-only screen sharing, or VNC, enabled for example. On the face, that sounds rather useless, why would one want to connect to that locally? The reason is that I want to connect to these services with encryption, and they frequently do not support that option. The solution? SSH port forwarding. For example, when I want to connect to a local VNC server on armor2 I might use the following.

ssh -L 5901:localhost:5900 armor2

Now, it’s important to see what this does. The -L flag specifies that this is a local port forward command, 5901 is the local port to use, 5900 is the port to connect to on armor2, and localhost is the host to connect to. Armor2 is the target host for the ssh connection. After establishing that connection vncviewer localhost:1 would connect to the VNC server on armor2 over an ssh encrypted pipe. Alternatively, since armor2 is behind another machine charon, it could be written as follows.

ssh -L 5901:armor2:5900 charon

This version assumes that VNC connections are allowed from charon to armor2, but skips the extra hop of the proxy. It works by connecting the local port, over a tunnel to charon, to armor2 without the need to be able to directly ssh to armor2. Used this way, one can connect to any port on a target machine from any (non-restricted) local port through any machine they can ssh to. It is an extremely flexible option, and one I am constantly finding new uses for.

Trick 2: Connecting to a machine behind a firewall

It is a relatively common issue to need to connect to one machine through another, both through SSH. Normally, that means that one must explicitly conenct to the first, then ssh to the second from there, while not a huge issue, it is a definite annoyance. Using another great multitasker, netcat, we can fix this problem, as in this excerpt from the above configuration.

Host ice5
    Protocol 2
    HostName ice5
    ProxyCommand ssh charon nc -q 0 ice5 22 OR

Host ice5
    Protocol 2
    HostName ice5
    ProxyCommand ssh charon -W ice5:22

This rule allows one to ssh directly to ice5 from outside, even though it must be accessed by first sshing to charon. The ProxyCommand is the key, when one types ssh ice5 the system automatically runs the proxycommand, which opens an ssh connection to charon, and connects the pipe from that connection to a netcat process on charon which points to the ssh port on ice5. That connection is then used to communicate with ice5, completely skipping the need to explicitly log in to charon, and if ones ssh keys and forwarding are set up, it’s all automatic.


Thanks to Lorenzofh for pointing out that ssh offers the -W <host>:<port> option to accomplish this as well. It is always nice to save a process, not to mention not requiring that netcat be installed.

Trick 3: Transferring files without scp/sftp

As much as scp and sftp are well thought out, and work well much of the time, sometimes one wants an alternative. The most common reason for this is when I have a large number of small files to transfer, and would prefer to use one persistent connection to transfer them all rather than restarting for each file. Another would be using a different compression algorithm than that built into scp. With ssh and tar, it’s quite easy to set up. For example, lets say I want to transfer a mailder format directory called email on charon to my local machine.

ssh charon tar c emails/ | tar xv

That’s all it takes. Lets break that down for a moment. It connects to charon over ssh, opening a non-interactive terminal with the tar command to create an archive of the email directory on standard output. The | breaks the command in the local shell, in that way the output pipe from ssh is fed into a tar extraction command, which extracts the folder verbosely in the current directory.

Ok, so that gets us to having all the files in one pipe, which is a pretty big win on connection setup and teardown, but there is no compression. One could certainly add a compression option to tar, say ‘j’ for bzip2, but since this is a pipe, so we can use whatever we want. This version is even better.

ssh charon sh -c 'tar c emails/ | xz -9 --stdout --compress' | xz --decompress --stdout | tar xv

Now we have all of the files packed into a single tar stream, compressed to the maximum with lzma in xz, piped back to the local machine, decompressed, and untarred. Of course, if you want to archive the remote machine instead of recreating the original, the pipe from ssh can simply be directed to a file, which is a great way to create archives of systems which do not have enough local space to hold the archive.

Trick 4: Full SOCKS proxy courtesy of ssh

Need a proxy to connect outside of your firewall? My most recent use for this was to make connections out of China to various sites in the US. The command is deceptively simple.

ssh -D <port> charon

Where charon is the hostname. With that, ssh creates a SOCKS4/5 proxy on the specified port, setting your browser or operating system to use that proxy can forward essentially any kind of traffic through, which will appear to have come from the target machine. Simple, but extremely useful in the right situation.


Thanks to these, ssh is in my top-tier of command line tools, right up there with vim, zsh and the members of coreutils. It never seems to run out of tricks, if you know of any other cool ones, drop me a line, I’d love to hear about them.

blog comments powered by Disqus