β SSH plus tmux automatically
β’ 628 words β’ 3 min β’ updated
One of the most classic sysadmin/DevOps tasks is to use secure shell to connect to remote machines.
To persist those connections, a terminal multiplexer is often used, tmux and screen being the two most popular ones.
In this post I will cover a few different client-side and server-side ways to have ssh automatically spawn tmux upon connection.
Option #1: Use command-line ssh flags (client-side, recommended) #
Start tmux, forcing unicode, attaching to and/or creating a session named main:
$ ssh user@host -t -- tmux -u new -A -s main-u is not strictly necessary, however I experienced occasional weirdness when connecting to some machines and omitting it. Some unicode characters wouldn’t be properly rendered, like the horizontal and vertical lines used to render tmux pane splits. Even though most machines should work just fine these days by supporting UTF-8 out-of-the-box, it’s safer to always include -u just in case.
Tip: If it’s annoying to remember to type the full command above, consider adding an alias in your shell config. Alternatively, use a ssh client that remembers your flags preferences such as the chrome secure shell extension.
Option #2: Use ~/.ssh/config (client-side)
#
This option is very similar to the previous one, but the flags live in the ssh config rather then being specified at the command line:
Host *
RequestTTY yes
RemoteCommand tmux -u new -A -s mainYou don’t need to match all hosts (Host *), if you’d rather match one or more specific hosts, refer to the ssh config syntax ssh_config(5) to add them. A simple example would be Host mymachine.example.org.
Caveat: I’ve found this method interferes with git + ssh authentication. More specifically:
$ git remote -v
origin git@github.com:thiagowfx/.dotfiles.git (fetch)
origin git@github.com:thiagowfx/.dotfiles.git (push)
$ git push
Cannot execute command-line and remote command.
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.Therefore I discourage it, unless you only use it with specific hosts i.e. don’t use it with Host *.
Option #3: Use ~/.bash_profile or similar (server-side, recommended)
#
This method leverages your login shell startup config file (~/.bash_profile, ~/.zprofile, etc) to automatically spawn tmux.
# This file is invoked as part of my ~/.bash_profile.
# Automatically spawn tmux within ssh sessions for interactive terminals.
# https://stackoverflow.com/a/43819740/1745064
#
# The session is called `main`.
# Create a session with PREFIX :new, rename with PREFIX $, toggle with PREFIX s.
#
# Escape hatch:
# ssh <host> -t -- NOTMUX=1 <shell>
if [ -z "$NOTMUX" ] && [ -z "$TMUX" ] && [ -n "$SSH_TTY" ] && [[ $- =~ i ]]; then
tmux -u new -A -s main
exit
fiThe if basically checks:
- whether we’re not already inside a tmux session (we shouldn’t be), so that we don’t nest
tmux - whether we’re accessing the shell via
ssh(we should be) - whether we’re accessing an interactive shell (we should be), so that it doesn’t interfere with oneshot
sshcommands
There’s also a escape hatch. If you want to get an interactive shell but bypass tmux for some reason1, just set NOTMUX=1:
$ ssh user@host -t -- NOTMUX=1 bashFinal remarks #
My favorite methods are #1 and #3, and whether I use one or the other depends whether I want to unconditionally spawn tmux server-side, or selectively spawn tmux client-side.
When using chrome secure shell (hterm) I find #1 convenient because hterm remembers your ssh host settings. That said, in scenarios where I fully control a host and it’s not solely used for production, #3 is my favorite as it works unconditionally regardless of the client terminal emulator I am using.
-
For example, maybe if
tmuxbroke due to a recent upgrade, or if the~/.tmux.confis invalid. ↩︎