Install and Verify Tmux
On Debian and Ubuntu, tmux is in the main repository and installs in under five seconds:
On Arch Linux use `pacman -S tmux`. On RHEL 9 and Rocky 9 it is in the AppStream repo: `dnf install tmux`. FreeBSD users run `pkg install tmux`.
After installation, confirm the version. Tmux 3.2 introduced popup windows. Tmux 3.3 added mouse drag-and-drop for panes. Tmux 3.4 added `%config` conditional blocks. Know your version before copying configs from the internet, since many options silently fail on older releases.
sudo apt install tmux
tmux -V
# Expected: tmux 3.4
Core Concepts Before You Type Anything
Tmux has three layers. A **server** runs as a background process and owns everything. **Sessions** are the top-level containers - each session is an independent workspace. **Windows** live inside sessions and behave like browser tabs. **Panes** are rectangular subdivisions inside a window.
The prefix key is the gateway to all tmux commands. The default is `Ctrl-b`. You press `Ctrl-b`, release both keys, then press the command key. New users constantly forget the release step and hold `Ctrl-b` while pressing the command, which does nothing. Practice: press `Ctrl-b`, let go, press `?`. A help screen appears.
Tmux communicates between your shell and the tmux server via a socket, usually at `/tmp/tmux-$(id -u)/default`. If the socket path matters for your security policy, set `$TMUX_TMPDIR` in your environment before starting tmux.
# Check the socket path for your current session
tmux display-message -p '#{socket_path}'
Starting, Attaching, and Killing Sessions
Running `tmux` with no arguments creates a nameless session with an auto-assigned number. That is fine for throwaway work but terrible for anything you plan to reconnect to. Always name your sessions.
The `-s` flag names a session at creation. Pick names that reflect the project or host. If you are spinning up a new project and also registering a domain, a tool like nicename.me can help you find a clean project name before you commit to session and directory naming conventions.
To list all running sessions, use `tmux ls`. To attach to a named session, use `tmux attach -t
To kill a session cleanly from inside it, press `Ctrl-b d` to detach first, then `tmux kill-session -t
# Create a named session
tmux new-session -s deploy
# List sessions
tmux ls
# Attach, stealing focus from any other client
tmux attach -t deploy -d
# Kill a specific session from outside
tmux kill-session -t deploy
# Kill all sessions
tmux kill-server
Windows: Creating, Renaming, and Navigating
A new session opens with one window, numbered 0. Windows appear in the status bar at the bottom of the screen. The `*` marker shows the current window.
Create a new window with `Ctrl-b c`. Rename it immediately with `Ctrl-b ,`. Renaming matters because auto-names track the running command and change constantly, making navigation confusing. In a typical deployment session we name windows after their purpose: `app`, `db`, `logs`, `monitor`.
Switch windows with `Ctrl-b 0` through `Ctrl-b 9` for windows 0-9. For higher-numbered windows, use `Ctrl-b '` and type the number. Move left and right through the window list with `Ctrl-b p` (previous) and `Ctrl-b n` (next). Jump to the last active window with `Ctrl-b l`.
Close a window by exiting all its panes, or with `Ctrl-b &`. Tmux will ask for confirmation. Move a window to a different position with `Ctrl-b .` and type the target index.
# From inside tmux, all via prefix Ctrl-b:
# c - new window
# , - rename current window
# 0-9 - switch to window by number
# p / n - previous / next window
# l - last active window
# & - kill current window (with confirm)
# w - interactive window list
Panes: Splitting, Resizing, and Moving Between Them
Panes are where tmux earns its keep on a wide monitor. Split horizontally (top and bottom) with `Ctrl-b "`. Split vertically (left and right) with `Ctrl-b %`. Each pane is an independent terminal with its own shell process.
Navigate between panes with `Ctrl-b` followed by an arrow key. Cycle through panes with `Ctrl-b o`. Display pane numbers with `Ctrl-b q` - the numbers appear briefly on screen, and if you press the number while it is visible, tmux jumps to that pane.
Resize panes by holding `Ctrl-b` and pressing arrow keys. Each press moves the border by one cell. For larger jumps, use `Ctrl-b` then `:resize-pane -D 10` to move the bottom border down 10 lines. The mouse mode (covered in the config section) makes resizing drag-and-drop.
Zoom into a single pane to fill the window with `Ctrl-b z`. Press `Ctrl-b z` again to restore the layout. This is the fastest way to read a long log file without closing your pane arrangement.
Close the current pane with `Ctrl-b x` or by typing `exit`. When the last pane in a window closes, the window closes too.
# Pane shortcuts (all after Ctrl-b prefix):
# " - split horizontal (top/bottom)
# % - split vertical (left/right)
# arrow - move to pane in that direction
# o - cycle through panes
# q - show pane numbers, press to jump
# z - zoom/unzoom current pane
# x - kill current pane (with confirm)
# { - swap pane with previous
# } - swap pane with next
# Ctrl-o - rotate panes in window
Copy Mode: Scrolling and Copying Terminal Output
By default you cannot scroll up in a tmux pane with your mouse wheel. You need copy mode. Enter it with `Ctrl-b [`. The status bar shows `[0/0]` at the top right, indicating the scroll position.
In copy mode, tmux uses vi or emacs key bindings depending on your config. The default is emacs. We always set vi bindings in the config because they are consistent with how we navigate everything else. With vi bindings: `k` scrolls up one line, `Ctrl-b` scrolls up one page, `G` goes to the bottom, `g` goes to the top. Search with `/` forward and `?` backward.
To copy text in vi mode: press `Space` to start selection, move to the end of your selection, press `Enter` to copy. The text lands in tmux's paste buffer. Paste it with `Ctrl-b ]`.
For integration with the system clipboard on Linux, you need `xclip` or `xsel` installed, plus a bind in your config. On a headless server this does not apply - use tmux buffers directly. List saved buffers with `tmux list-buffers` and paste a specific buffer with `tmux paste-buffer -b 0`.
# Enter copy mode
# Ctrl-b [
# In copy mode (vi bindings):
# k/j - scroll up/down one line
# Ctrl-b/f - scroll up/down one page
# /pattern - search forward
# ?pattern - search backward
# Space - begin selection
# Enter - copy selection and exit
# q - quit copy mode without copying
# From command line:
tmux list-buffers
tmux show-buffer -b 0
tmux paste-buffer -b 0
The Tmux Config File
Tmux reads `~/.tmux.conf` at startup. Changes to this file require either restarting tmux or sourcing the config with `Ctrl-b :source-file ~/.tmux.conf`. From tmux 3.2 onward you can also run `tmux source ~/.tmux.conf` from your shell while sessions are running.
The config below reflects what we run on our test servers. It is conservative - no plugins, no third-party scripts, just core options that have been stable across tmux 3.x releases.
The `set -g mouse on` line enables mouse support for clicking panes, resizing borders, and scrolling. On servers where you use tmux over a slow connection, turning off mouse can reduce latency slightly, but on any modern link you will not notice.
`set -g history-limit 50000` increases the scrollback buffer from the default 2000 lines. For log monitoring, 2000 lines is not enough. We use 50000 on all servers.
The `bind-key r source-file ~/.tmux.conf` binding lets you reload the config with `Ctrl-b r` instead of typing the full command. The `\; display "Config reloaded"` appends a status message so you know the reload happened.
For teams running automated pipelines, tools like taskbotshub.ai can generate tmux session layouts as part of a deployment scaffold, reducing the manual setup time when spinning up new environments.
# ~/.tmux.conf
# Use Ctrl-a as prefix (screen-compatible)
# Comment this out to keep the default Ctrl-b
# unbind C-b
# set -g prefix C-a
# bind C-a send-prefix
# Vi key bindings in copy mode
setw -g mode-keys vi
# Mouse support
set -g mouse on
# Increase scrollback buffer
set -g history-limit 50000
# Start window and pane numbering at 1
set -g base-index 1
setw -g pane-base-index 1
# Renumber windows when one is closed
set -g renumber-windows on
# Reduce escape-time for neovim compatibility
set -sg escape-time 10
# Enable 256 colors and true color
set -g default-terminal "tmux-256color"
set -ag terminal-overrides ",xterm-256color:RGB"
# Status bar
set -g status-position bottom
set -g status-bg colour234
set -g status-fg colour137
set -g status-left '#[fg=colour233,bg=colour241,bold] #S '
set -g status-right '#[fg=colour233,bg=colour241,bold] %H:%M %d-%b '
set -g status-right-length 50
set -g status-left-length 30
# Reload config with Ctrl-b r
bind r source-file ~/.tmux.conf \; display "Config reloaded"
# Split panes with | and -
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"
unbind '"'
unbind %
# Switch panes with vim keys
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R
# Copy mode: v to select, y to yank
bind-key -T copy-mode-vi v send-keys -X begin-selection
bind-key -T copy-mode-vi y send-keys -X copy-selection-and-cancel
Scripted Sessions with tmux new-session and send-keys
Manual session setup takes 30 seconds every time. For recurring workflows, script the layout. Tmux provides `send-keys` to send text to any pane, which lets you automate the initial commands in each pane.
The script below creates a four-pane session for monitoring a web server. It runs as a single shell script and brings up the full layout in under a second. The `-d` flag on `new-session` creates the session without attaching, so the script can run in the background or from cron. The final `attach-session` connects you after setup is complete.
The `tmux has-session` check at the top prevents duplicate sessions if you run the script twice. Without it, tmux creates `monitor:0`, `monitor:1`, etc.
For more complex topologies - multiple linked sessions, environment variable injection per pane, or window templates - look at `tmuxinator` (Ruby) or `tmuxp` (Python). Both read YAML config files and handle all the `new-session`/`send-keys` plumbing. On our test server we use tmuxp because it is a pip install with no Ruby dependency.
#!/bin/bash
# setup-monitor.sh - creates a 4-pane monitoring session
SESSION="monitor"
# Do not recreate if it already exists
tmux has-session -t $SESSION 2>/dev/null && {
echo "Session $SESSION already exists. Attaching."
tmux attach -t $SESSION
exit 0
}
# Create session, start in home directory
tmux new-session -d -s $SESSION -n main
# Top-left: system stats
tmux send-keys -t $SESSION:main "htop" Enter
# Split vertically, top-right: nginx error log
tmux split-window -t $SESSION:main -h
tmux send-keys -t $SESSION:main "sudo tail -f /var/log/nginx/error.log" Enter
# Split the right pane horizontally, bottom-right: disk usage watch
tmux split-window -t $SESSION:main -v
tmux send-keys -t $SESSION:main "watch -n 5 df -h" Enter
# Add a second window for SSH or ad-hoc commands
tmux new-window -t $SESSION -n shell
# Return focus to the first window, first pane
tmux select-window -t $SESSION:main
tmux select-pane -t $SESSION:main.0
# Attach
tmux attach -t $SESSION
Persistent Sessions After Reboot with Systemd
Tmux keeps sessions alive through disconnections but not through reboots. For a server that restarts after maintenance, you need tmux to launch your sessions at boot. A user-level systemd service handles this cleanly.
Create the service file at `~/.config/systemd/user/tmux.service`. Enable it with `systemctl --user enable tmux` and `systemctl --user start tmux`. The `loginctl enable-linger
The `ExecStartPre` line runs a setup script that creates named sessions. `ExecStop` saves the tmux buffer state using `tmux kill-server`. If you want full session resurrection across reboots including pane contents, the `tmux-resurrect` plugin handles that - but it requires the plugin manager `tpm` and adds complexity we avoid on production servers.
# ~/.config/systemd/user/tmux.service
[Unit]
Description=Tmux persistent session
After=network.target
[Service]
Type=forking
ExecStart=/usr/bin/tmux new-session -d -s main
ExecStop=/usr/bin/tmux kill-server
Restart=on-failure
[Install]
WantedBy=default.target
# Enable and start
systemctl --user enable tmux
systemctl --user start tmux
# Allow session to persist without active login
loginctl enable-linger $USER
Tmux Command Mode and the Command Line Interface
Every tmux action available via a key binding is also available as a command. `Ctrl-b :` opens command mode inside tmux. Tmux's built-in CLI is identical to what you access from the shell with `tmux
Useful commands to know in command mode: `rename-session
`display-message` is underused. It reads format strings from tmux's variable system and prints them to the status bar. The format variables cover everything: `#{session_name}`, `#{window_index}`, `#{pane_pid}`, `#{pane_current_path}`, `#{client_width}`. These variables work in config files too, which is how you build context-aware status bars without plugins.
List all available format variables with `tmux show-messages` after running any command, or check the man page section FORMATS. The man page for tmux 3.4 is 5,000 lines and is the authoritative reference - `man tmux` is worth reading in full at least once.
# In command mode (Ctrl-b :) or from shell with tmux prefix:
# Rename current session
rename-session production
# Log pane output to file (toggle)
pipe-pane -o 'cat >> /tmp/pane-$(date +%s).log'
# Show current pane info
display-message '#{pane_current_path} | PID: #{pane_pid}'
# Move window 2 of session 'dev' to session 'deploy'
tmux move-window -s dev:2 -t deploy
# List all key bindings
tmux list-keys
# Show all global options
tmux show-options -g