This article outlines how to get started with tmux (v2.1), and if needed how to do some custom configuration and boot-time automated setup.

Why I Needed tmux

I’ve had a headless Linux server for about four years. It’s configured so that I can connect to it from my laptop via VNC (gui) or SSH (cli). With Xfce running, VNC is a pretty nice way to work with the server when I’m at home on my laptop and I’m doing mostly GUI stuff. Whenever I disconnect my laptop, the server stays intact ready for my next connection. However, when I’m on my iPhone, at work, or even doing text-heavy command line stuff from home, the VNC setup is sub-optimal compared to a local terminal on my laptop. SSH allows me to connect using a terminal application on my laptop, but for any sort of non-linear workflows it quickly becomes a tedious mess of multiple connections that need to be setup on a per-use basis. If only there was a way to merge the two. tmux!

This article documents my weekend journey to increased happiness with the introduction of tmux into my life.

What’s tmux?

Straight from the man page:

tmux is a terminal multiplexer: it enables a number of terminals to be created, accessed, and controlled from a single screen. tmux may be detached from a screen and continue running in the background, then later reattached.

The man page goes on to define three key terms: session, window, and pane. While the man page offers more technically correct definitions, I find it simpler to use the common multi-workspace desktop GUI as an analog.

tmux equivalents

Envisioning a GUI desktop is a quick way to grasp the tmux concepts of Sessions, Windows, and Panes.

In short, every terminal window you open is like a pane, all the terminals you can see at one time is a window, and the different workspaces you can toggle between are the windows in a single session.

tmux let’s you easily get around between all those sessions, windows, and panes. And best of all, if you disconnect from the server and reconnect later, they’re all waiting for you as if you’d never left, which means you get all that command line goodness with the permanence of a VNC connection to a remote desktop.

Install tmux

Obviously this will vary depending on your OS. I’m running Fedora 23, so:

sudo dnf install tmux

Setup a Session from the Command Line

Most of the other tmux articles you’ll find would have you jump into tmux and start setting things up from within tmux. I think it’s useful to set up a trivial session before jumping in as it puts things in a better context.

First, let’s check that tmux isn’t running.

tmux ls
error connecting to /tmp/tmux-1000/default (No such file or directory)

Great. Let’s set up an arbitrary session to demonstrate a tmux.

# Setup a session called "stuff" that has 2 windows.
# The first window we'll call "text-to-file"
# We want it putting dates into a text file
tmux new-session -d -s stuff -n text-to-file -c /tmp 'watch -n1 "date >> date_file"'

# Vertically split the window in step 1 into 2 panes.
# The second pane tails the dates file.
tmux split-window -d -t stuff:text-to-file -c /tmp -v 'watch -n1 tail -n10 date_file'

# Create second window called "monitor" running top.
tmux new-window -d -a -t stuff:text-to-file -n monitor 'top'

# Horizontally split the window in step 3 into 2 panes.
# The second pane is watching the /tmp folder for changes.
tmux split-window -d -t stuff:monitor -c /tmp -h 'watch -n3 ls -la'

Now let’s check again for an active session:

tmux ls
stuff: 2 windows (created Mon May 23 22:07:33 2016) [140x40]

Looks good. Let’s see if our windows are there:

tmux lsw
0: text-to-file* (2 panes) [140x40] [layout dbca,140x40,0,0[140x20,0,0,0,140x19,0,21,1]] @0 (active)
1: monitor (2 panes) [140x40] [layout 7e37,140x40,0,0{70x40,0,0,2,69x40,71,0,3}] @1

Attach to an Active Session

Everything above seems to be in order. Let’s attach to the session and see what it looks like:

tmux a -t stuff

Upon running that command, our full terminal is replaced by the following:

In the bottom left we see that we’re in the “stuff” session with the “text-to-file” window active. In the top pane we see our “date_file” getting a date added to it every second, and in the bottom pane we see the last 10 lines of that file changing. Let’s check our other window.

Jump to the next window by pressing Ctrl-b, n (That’s pressing control+b, releasing, and then pressing the n key.)

Success! We see the “monitor” window with top running on the left and an active view of the directory on the right, complete with our date_file.

Detach: Ctrl-b, d

That will detach us from our session and bring us back to the plain old terminal. You can reattach to it if you like, or when you’re ready, kill it. (In a normal situation, it’s advisable to first terminate any running commands before killing the session.)

[detached (from session stuff)]
tmux kill-session -t stuff
tmux ls
no server running on /tmp/tmux-1000/default

I recommend checking out the tmux shortcuts & cheatsheet to get started with the default keyboard shortcuts. Some of the more critical are below. For all of them, you must press the prefix key and then the key shown. By default, the prefix key is Ctrl-b (just like in the example above).

Sessions

  • s list/select sessions

Windows

  • c create window
  • w list/select windows
  • n next window
  • p previous window
  • & kill window

Panes (splits)

  • % vertical split
  • ” horizontal split
  • x kill pane
  • arrow keys move between panes

Configuring with ~/.tmux.conf

When you’re ready, check out the tmux man page and customize tmux to your liking. My config is below. Of note, check out the first three lines. I really don’t like the Ctrl-b prefix, so I bound the backtick key to be my prefix, which is much more ergonomic in my opinion. (And if you really need to type a backtick, you just press it twice.)

# set prefix to '`', but keep 'b' too
set -g prefix '`'
bind-key '`' send-prefix
set-option -g prefix2 C-b

# reload ~/.tmux.conf
bind r source-file ~/.tmux.conf

# easy split pane commands
bind | split-window -h
bind - split-window -v

# Don't rename windows
set-window-option -g automatic-rename off
set-window-option -g allow-rename off

# set window and pane index to 1 (0 by default)
set-option -g base-index 1
setw -g pane-base-index 1

# select panes with meta
bind -n M-H select-pane -L
bind -n M-J select-pane -D
bind -n M-K select-pane -U
bind -n M-L select-pane -R

# move between windows and sessions with meta
bind -n M-h previous-window
bind -n M-j switch-client -p
bind -n M-k switch-client -n
bind -n M-l next-window

# resize pane
set -g repeat-time 1500
bind -r h resize-pane -L
bind -r j resize-pane -D
bind -r k resize-pane -U
bind -r l resize-pane -R

# Enable mouse support
set-option -g mouse on
bind m set-option -g mouse on
bind M set-option -g mouse off

# Start copy mode when scrolling up
bind -n WheelUpPane copy-mode -e

# Window style adjustments
set -g window-style 'fg=colour240'
set -g window-active-style 'fg=colour254'

# Status Bar Adjustments
set-option -g status-bg colour235 #base02
set-option -g status-fg yellow #yellow
set-option -g status-attr dim 

set-window-option -g window-status-fg brightyellow #base0
set-window-option -g window-status-bg colour236 
set-window-option -g window-status-attr dim

set-window-option -g window-status-current-fg brightgreen
set-window-option -g window-status-current-bg colour236 
set-window-option -g window-status-current-attr bright

set -g status-left "#[fg=white]#S "
set -g status-right "#[fg=white] %d %b %Y %H:%M"

Credit: I borrowed heavily from Mark H. Nichols when first getting setup.

Have tmux Start at Login

Once you’re feeling comfortable with everything, you may want to make tmux attach to your sessions when you login. If so, add this to your .bashrc (assuming you’re using bash of course):

# check that tmux is installed
if command -v tmux > /dev/null; then
  # check that we're not already in screen or tmux; only via SSH connection (remote)
  if [[ ! $TERM =~ screen ]] && [ -z $TMUX ] && [ -n "$SSH_CLIENT" ]; then
     # if a session called admin exist, attach to it; else create it
     if tmux ls | grep -q admin; then
        exec tmux attach -t admin
     else
        exec tmux new -s admin -n main
     fi
  fi
fi

Important note: I don’t recommend doing this unless you really know what you’re doing and have a separate user you can log in as or have physical access to your machine. If you botch the details, you could end up with a situation where you can’t log in.

Set Up Sessions at Boot Time

Lastly, once you figure out what your normal workflow is and have a common set of sessions, windows, and panes, put them in a script file and add a cron task to have them setup at boot time.

Create ~/tmux_boot_setup and make it executable. Let’s populate it with our ridiculous example from before:

#!/bin/bash

tmux new-session -d -s stuff -n text-to-file -c /tmp 'watch -n1 "date >> date_file"'
tmux split-window -d -t stuff:text-to-file -c /tmp -v 'watch -n1 tail -n10 date_file'
tmux new-window -d -a -t stuff:text-to-file -n monitor 'top'
tmux split-window -d -t stuff:monitor -c /tmp -h 'watch -n3 ls -la'

Then edit your crontab (crontab -e) and add one line:

@reboot /home/markmcb/tmux_reboot_setup

That’s it. Happy tmux’ing!