How to use tmux for extra help when connecting to a server

So your development environment is all fine and dandy but every time you SSH into a machine you feel like your workflow is crippled and you’re trying to fight off a pit of tigers (read: production issues)? Well you should try out tmux.

Josh Bodah

Engineering

Obligatory tmux Background

tmux stands for “terminal multiplexer,” and it basically lets you run multiple shell instances. If you’re using tabs and splits in iTerm then it’s very similar to that. tmux has several advantages over iTerm though. You can also use it to run things in the background in case you need to switch to another task or are running a long script that you’re afraid might get cancelled if you lose your internet connection (or walk away from your computer). It supports multiple platforms and is 100% command line driven so you can use it when SSH’ed into boxes. It is also easily configurable and scriptable. It can even be used to support remote pairing.

Getting Started

The easiest way to install tmux is through your package manager:

OSX sh brew install tmux

Debian/Ubuntu sh sudo apt-get install tmux

Now lets create a session:

sh tmux new -s my-cool-sesh

Let’s run a little Ruby script to loop and print the time every few seconds:

sh ruby -e 'loop { puts Time.now; $stdout.flush; sleep 2 }'

Cool, now let’s detach from our session by hitting Ctrl+b then d. Ctrl+b is the default “prefix” chord, so hence forth we’ll refer to this as <prefix-d> (hint: think “detach”)

Once you’re out of the session you can list all of the running sessions:

sh tmux ls my-cool-sesh: 1 windows (created Fri Sep 23 15:15:16 2016) [178x49]

Then attach back to the session:

sh tmux attach -t my-cool-sesh

We can Ctrl+c to terminate our Ruby loop and then type exit to terminate our session. You can verify that our session is closed via tmux ls.

And there you go! You’ve now learned the most fundamental tmux workflow. Continue on if you’d like to get into more advanced features.

Terminology

Before we go further it will be useful to talk a little about how tmux is structured. tmux manages multiple sessions which you can attach to or detach from. Each session can have multiple windows (similar to tabs in iTerm). Each window can have multiple panes (similar to splits in iTerm).

tmux

Windows and Panes

Let’s make a new session:

sh tmux new -s wind-pane

Now let’s start our Ruby loop again. You can imagine this being some other blocking operation like starting a server or tailing a log.

sh ruby -e 'loop { puts Time.now; $stdout.flush; sleep 2 }'

Now we’ll create a new window with <prefix-c> (hint: think “create”).

Go check back on your last window with <prefix-p> (hint: “previous”). Nothing changed? Alright, go forward with <prefix-n> (hint: “next”)

For kicks let’s make a few panes. Make a horizontal cut with <prefix-"> then a vertical one with <prefix-%>. Navigate between them using <prefix-ARROW_KEY> (note: you can also switch to use vim bindings which will see shortly).

What if we don’t want to scroll through windows all the time? Notice the numbers on the windows at the bottom? You can hit <prefix-NUMBER> to go directly to that window.

THE BEST feature of tmux is the ability to zoom in on a pane with <prefix-z>. Go ahead and give it a try.

Ex-style Commands in tmux

We’ve been cheating a little bit so far by only using the keybinds, but you can also use the tmux command line. Enter a new session and type <prefix-:> then type create-window. We’ll explain how keybinds are mapped to these commands in two seconds. You can exit your session with the kill-session command.

Getting Help

Getting lost? Not sure how you’ll remember any of this? Fortunately there are two built-in sources that are very useful. man tmux lists all of the commands, their options, as well as their aliases (which work both on the bash command line following tmux or in tmux’s own command line <prefix-:>).

If you want to see which commands are mapped to which keys you can type <prefix-?>. This gives you a less-style prompt you can navigate with Ctrl+d to go down, Ctrl+u to go up, / to search forward, and ? to search backwards.

Remote Pairing with tmux

One of the cool things about tmux is that you can have multiple people attached to the same session as long as they can SSH into the same box. This can create a great pairing workflow as you can take turns sharing the keyboard even when remote. To make use of this feature simply have each user attach to the same session (e.g. tmux a -t my-cool-sesh) and presto! Two caveats to keep in mind: first the keyboard is shared, so only one person should type at a time, and second tmux will crop the window based on the smallest terminal window size of any user (so keep your terminal windows as large as possible and don’t change it!)

Synchronizing Panes

One of my favorite features of tmux is the ability to synchronize your panes. This allows you to type the same thing in multiple panes by controlling them all at the same time. I’ve found this useful for ad-hoc scripting when I need cheap multi-processing but still want an interactive shell.

Here’s a simple example (Note that a more practical example would be to do something like add keys to a Redis queue and have each shell act as a worker popping from that queue):

Create some splits

<prefix-"><prefix-%>

<prefix-b>:setw synchronize-panes on bundle exec rails c puts Time.now exit <prefix-b>:setw synchronize-panes off

Configuring tmux

By default tmux will look for a file at ~/.tmux.conf. You are able to configure a lot of things like modify your prefix key, change your colors, customize your status bar, enable copy/paste and clipboard support, adjust repeat rates, add logging, and much more. Feel free to check out an example here.

Some quick tips:

Add vim bindings for moving between panes Note: -r makes them chainable (see below)

sh bind -r h select-pane -L bind -r j select-pane -D bind -r k select-pane -U bind -r l select-pane -R

Increase tmux’s buffer size

sh set-option -g history-limit 10000

Change the prefix key (good if you want to use tmux on your host machine as well as a machine you’re SSH’ed into)

sh set -g prefix C-a unbind C-b

Configure the delay for which commands can be chained (e.g. <prefix-Up-Up-Left> instead of <prefix-Up><prefix-Up><prefix-Left>) sh set -g repeat-time 300

Scripting with tmux

If you’re really hardcore you can even script tmux. This is sweet if you want to be able to open up a custom environment lickity-split. For example, maybe you want typing dev to:

  1. Create a tmux session
  2. Create an “editor” window
  3. Split the “editor” window vertically
  4. Open vim in pane 1 and guard in pane 2
  5. Create a “server” window
  6. Start MySQL and Redis in the background
  7. Run foreman s in the server window

I won’t go into much detail here as this gets more complex.

Fun Facts

  • <prefix-s> will bring up a list of sessions so you can switch sessions
  • tmux will run tasks in the background if you detach from a session and kill an SSH connection. This is extremely useful for managing long-running tasks without fear of losing an internet/SSH connection (generally due to computer sleep).