SSH escape commands for fun and profit

We can never say it enough, but OpenSSH is an amazing tool. Lately, I have been playing with VMs and a friend of mine showed me some really cool tricks with SSH. The SSH escape ~ commands!

What are SSH escape commands?

The ~ is a special escape command that is only recognized immediately after a newline. You can display the help with ~ ? from any SSH session. Note that because the command is interpreted by SSH it won't be displayed in your terminal.

daimrod@omecha:~$
Supported escape sequences:
 ~.   - terminate connection (and any multiplexed sessions)
 ~B   - send a BREAK to the remote system
 ~C   - open a command line
 ~R   - request rekey
 ~V/v - decrease/increase verbosity (LogLevel)
 ~^Z  - suspend ssh

 ~#   - list forwarded connections
 ~&   - background ssh (when waiting for connections to terminate)
 ~?   - this message
 ~~   - send the escape character by typing it twice
(Note that escapes are only recognized immediately after newline.)

The first command that I find somewhat useful is ~.. It is used to terminate the connection, which is useful when you want to kill your SSH session, for example because you've switched between networks and you need to make a new connection but you don't want to wait for the timeout. Just enter ~. and boom, your session is closed!

Behold the ~C command

But the command that I found really cool is ~C. When you enter the ~C command from an SSH session, a new prompt appears. You can list the available commands by entering ? or help.

daimrod@omecha:~$
ssh> ?
Commands:
      -L[bind_address:]port:host:hostport    Request local forward
      -R[bind_address:]port:host:hostport    Request remote forward
      -D[bind_address:]port                  Request dynamic forward
      -KL[bind_address:]port                 Cancel local forward
      -KR[bind_address:]port                 Cancel remote forward
      -KD[bind_address:]port                 Cancel dynamic forward

This commands allow you to forward (and to cancel) ports from your current SSH session.

I find this very useful when I'm working with VMs and I have to forward ports to access the VNC or SSH ports of the VMs. Here is an example of me, connecting to my hypervisor, starting some VMs and forwarding the VNC ports to my localhost. Note that, though the command vncdisplay indicates that the VNC is listening on 127.0.0.1:N, the real port it is listening to is 5900 + N.

$ ssh root@hypervisor
# virsh
Welcome to virsh, the virtualization interactive terminal.

virsh # create domains/vm1.xml
Domain vm1 created from domains/vm1.xml

virsh # vncdisplay vm1
127.0.0.1:0

virsh #
ssh> -L 5900:localhost:5900
Forwarding port.

# In another terminal
$ vncviewer  localhost:5900

virsh # create domains/vm2.xml 
Domain vm2 created from domains/vm2.xml

virsh # vncdisplay vm2
127.0.0.1:1

virsh #
ssh> -L 9 5901:localhost:5901
Forwarding port.

# In another terminal
$ vncviewer localhost:5901

Pretty neat, isn't it? The only drawback, is that we still need another terminal to launch vncviewer. But I've found a way around.

One terminal to rule them all

  1. Forward the port from SSH with ~C -L 5900:localhost:5900
  2. Suspend SSH with ~^Z
  3. Launch vncviewer localhost:5900, it doesn't start because SSH is suspended and thus is unable to forward the connection.
  4. Suspend the vncviewer command and resume it in background with bg
  5. Resume SSH in the foreground with fg.

Here is a sample of the session :

$ ssh root@hypervisor
# virsh

virsh # create domains/vm1.xml
Domain vm1 created from domains/vm1.xml

virsh # vncdisplay vm1
127.0.0.1:0

virsh # ~C
ssh> -L 5900:localhost:5900
Forwarding port.

~^Z[1] + Suspended            ssh root@hypervisor

$ vncviewer localhost:5900
^Z[2] + Suspended            vncviewer localhost:5900
$ bg
[2] vncviewer localhost:5900

$ fg
virsh # 

Final note and conclusion

One last thing, if you nest your SSH sessions (an SSH session within another SSH session), you need to escape the ~ character if you want to send command to the SSH session within the first one.

$ ssh host1               # first SSH session
host1$ ssh host2          # second SSH session
host2$ ~?
[help from the first SSH session]
host2$ ~~?
[help from the second SSH session]

Once again, OpenSSH is awesome, big thanks to all the folks working on it!