У каждого, кто работает с удалёнными серверами, была такая сцена: перенос файлов идёт третий час, домашний канал моргнул, соединение оборвалось, и вместе с ним пропал терминал с ходом задания. tmux закрывает проблему целиком. Это терминальный мультиплексор, который держит сессии на самой машине, переживает разрывы соединений и возвращает всё на экран одной командой после повторного входа.

Сессии, окна и панели tmux и независимость задач от обрыва сети

tmux устроен по схеме клиент и сервер: серверный процесс хранит сессии и запущенные в них программы, терминал лишь подключается клиентом. Обрыв ssh для сервера tmux не событие: клиент исчез, процессы внутри панелей спокойно идут дальше и продолжают писать вывод. При следующем входе достаточно вернуться в прежнюю сессию, и экран окажется ровно там, где остановился, вплоть до позиции курсора в редакторе.

Сессия содержит окна, окно делится на панели: вкладки браузера и участки экрана с отдельными оболочками.

Новая именованная сессия создаётся командой:

tmux new -s deploy

Флаг -s задаёт имя, в примере deploy. Список сессий на сервере выводит tmux ls, а возврат в существующую сессию выполняется так:

tmux attach -t deploy

Отключение идёт сочетанием префикса и d, всё внутри продолжает работать без клиента. Принудительное завершение одной сессии делает команда tmux kill-session -t deploy, весь сервер останавливается командой tmux kill-server.

Файл .tmux.conf в домашнем каталоге и базовые параметры настройки

Все настройки tmux живут в файле .tmux.conf в домашнем каталоге пользователя. Конфигурация читается при старте сервера, команда tmux source-file ~/.tmux.conf перечитывает её на лету.

Базовый блок, с которого обычно начинается файл:

# терминал и цвета
set -g default-terminal "tmux-256color"
set -as terminal-overrides ",xterm-256color:Tc"

# скорость реакции
set -g escape-time 10
set -g repeat-time 600
set -g display-time 2000
set -g focus-events on

# глубина истории прокрутки
set -g history-limit 50000

# префикс Ctrl+a вместо Ctrl+b
unbind C-b
set -g prefix C-a
bind C-a send-prefix

# нумерация окон с нуля и сдвиг без дыр
set -g base-index 0
setw -g pane-base-index 0
set -g renumber-windows on

# мышь
set -g mouse on

Параметр escape-time задаёт ожидание после нажатия Esc, по умолчанию полсекунды, из-за чего переключение режимов в редакторах vi подтормаживает. repeat-time задаёт окно повтора для клавиш с флагом -r. history-limit держит по умолчанию две тысячи строк прокрутки на панель, для журналов мало, запас поднимают до десятков тысяч.

Стандартный префикс Ctrl+b неудобен, поэтому конфиги почти всегда ставят Ctrl+a, привычную по мультиплексору screen. Строка bind C-a send-prefix позволяет отправить сам Ctrl+a в приложение двойным нажатием. Нумерация окон с нуля нужна, чтобы порядок на экране совпадал с внутренними номерами, renumber-windows убирает дыры после закрытия среднего окна. Параметр mouse включает прокрутку колесом, выбор панели щелчком и растягивание границ.

Переназначение клавиш разделения панелей и переходов между окнами

Стандартные клавиши разделения окна это " и %, их мало кто удерживает в памяти. Рабочий конфиг переносит их на наглядные символы и добавляет быструю навигацию:

# разделение окна
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"
unbind '"'
unbind %

# новое окно наследует текущий каталог
bind c new-window -c "#{pane_current_path}"

# переходы по панелям в стиле vi
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R

# размеры панелей с повтором
bind -r H resize-pane -L 5
bind -r J resize-pane -D 5
bind -r K resize-pane -U 5
bind -r L resize-pane -R 5

# выбор окна одной клавишей без префикса
bind -n M-1 select-window -t 0
bind -n M-2 select-window -t 1
bind -n M-3 select-window -t 2
bind -n M-4 select-window -t 3
bind -n M-5 select-window -t 4

# перезагрузка конфигурации на лету
bind r source-file ~/.tmux.conf \; display-message "config reloaded"

Символ | открывает панель сбоку, символ - панель снизу. Ключ -c "#{pane_current_path}" открывает новую панель в каталоге активной, а не в домашнем, строка bind c распространяет правило на новые окна. Переходы h j k l повторяют навигацию редактора vi, заглавные H J K L меняют размер панели на пять шагов, флаг -r позволяет повторять нажатие без нового префикса.

Связки Alt и цифры перебрасывают в нужное окно без префикса. Цифра на клавише больше внутреннего номера на единицу, потому что нумерация начинается с нуля: Alt и 1 ведёт в окно с номером 0. Имя окна меняется сочетанием префикса и запятой, имя сессии сочетанием префикса и $. Клавиша r перечитывает конфиг после правок.

Режим копирования со своим набором клавиш в стиле vi

Вывод команды уходит за верх экрана и теряется. Режим копирования превращает окно в текстовый редактор: по истории можно подниматься, искать и выделять фрагменты. Вход делается сочетанием префикса и [:

setw -g mode-keys vi
set -g status-keys vi
bind Escape copy-mode
bind -n PageUp copy-mode -u

# клавиши внутри режима копирования
bind -T copy-mode-vi v send -X begin-selection
bind -T copy-mode-vi C-v send -X rectangle-toggle
bind -T copy-mode-vi y send -X copy-pipe-and-cancel
bind -T copy-mode-vi Escape send -X cancel

Первая пара строк включает раскладку vi. PageUp входит в режим и сразу отматывает страницу назад, самый частый сценарий при чтении длинного вывода.

Внутри работают привычные движения: h j k l двигают курсор, w и b прыгают по словам, g и G уходят в начало и конец буфера, клавиша / ищет вперёд, знак вопроса ищет назад. Клавиша v начинает выделение, C-v переключает прямоугольное выделение для колонок, y копирует фрагмент и закрывает режим.

Скопированное оседает в буферах tmux. Сочетание префикса и = открывает список, Enter вставляет выбранный фрагмент в активную панель. Из командной строки работают tmux show-buffer и tmux save-buffer /tmp/fragment.txt.

Системный буфер обмена и связка tmux с xclip и wl-copy

У tmux собственная память для скопированного, системный буфер обмена живёт отдельно, и между ними нужен мост из внешних утилит: для графической сессии X это xclip, для Wayland пара wl-copy и wl-paste, в macOS пара pbcopy и pbpaste. Клавиша y из предыдущего раздела получает аргумент с внешней командой, и выделение уходит сразу в два хранилища:

# копирование выделения в системный буфер
bind -T copy-mode-vi y send -X copy-pipe-and-cancel "xclip -selection clipboard"
bind -T copy-mode-vi MouseDragEnd1Pane send -X copy-pipe-and-cancel "xclip -selection clipboard"

# вставка из системного буфера
bind p run-shell "xclip -selection clipboard -o | tmux load-buffer - && tmux paste-buffer"

Первая строка заменяет базовый вариант y: текст попадает в буфер tmux и через xclip в системный буфер. Вторая ловит завершение выделения мышью. Третья организует обратный путь: xclip печатает содержимое системного буфера, tmux принимает поток и вставляет его в активную панель. Клавиша p по умолчанию переключает на предыдущее окно, после переназначения её забирает вставка. Для Wayland утилиты меняются местами: bind -T copy-mode-vi y send -X copy-pipe-and-cancel "wl-copy", а вставка читает wl-paste.

Откуда у сервера без монитора возьмётся системный буфер? На головной машине xclip не поможет, там нет ни X, ни Wayland, и копирование наружу организуется управляющей последовательностью OSC 52:

set -g set-clipboard on
set -as terminal-overrides ',xterm-256color:Ms=\E]52;c;%p2%s\7'

С включённым set-clipboard tmux при копировании печатает в поток терминала короткую последовательность, она проходит по ssh обратно в локальный эмулятор, и уже он кладёт текст в буфер рабочей станции. Поддержка зависит от эмулятора: многие популярные терминалы понимают последовательность без настроек, xterm требует строки Ms. Вставка идёт средствами терминала: чтобы tmux с включённой мышью не перехватывал выделение, текст выделяют с зажатым Shift, затем вставляют штатной комбинацией, например Ctrl+Shift+V.

Статусная строка с именами сессий, списком окон и часами

Статусная строка это полоса на краю окна, по умолчанию скромная. Рабочий вариант собирают из блоков с подстановками:

set -g status-position top
set -g status-interval 5
set -g status-style "fg=white,bg=black"
set -g status-left "#[fg=green,bold] #S "
set -g status-left-length 30
set -g status-right "#[fg=cyan]#H #[fg=yellow]%H:%M %d-%m #[fg=magenta]#(uptime)"
set -g status-right-length 80
set -g window-status-format " #I #W "
set -g window-status-current-format "#[fg=black,bg=cyan,bold] #I #W "
set -g pane-border-status top
set -g pane-border-format " #{pane_index} #{pane_current_command} "
set -g set-titles on
set -g set-titles-string "#S / #W"

Слева выводится имя активной сессии, его подставляет #S. Справа хост #H, часы в формате %H:%M, дата и вывод внешней команды uptime со средней загрузкой. Конструкция #(команда) выполняет оболочку при каждом обновлении, status-interval 5 задаёт обновление раз в пять секунд. Часы не украшение: в нескольких окнах легко потерять счёт времени.

Средняя часть перечисляет окна, #I подставляет номер, #W имя, активное окно выделяется инверсией цветов. Имена окнам дают сочетанием префикса и запятой. Параметры pane-border-status и pane-border-format подписывают каждую панель сверху: индекс и текущую команду, например tail или journalctl. Когда в окне три панели с журналами, подписи экономят минуты на поиск потока. set-titles выносит имя сессии и окна в заголовок терминала.

Сценарии на сервере от долгих заданий до параллельного наблюдения за журналом

Долгие задания это самый частый сценарий: развёртывание, перенос больших каталогов через rsync, обновление пакетов, резервное копирование. Под каждый проект заводится именованная сессия: api для службы приложений, web для веб-сервера, backup для заданий по расписанию, имена видны в tmux ls и в статусной строке.

Обрыв и восстановление идут следом. Ноутбук закрыли, поезд въехал в туннель, соединение может пропасть в любой момент. Сессия на сервере продолжает работать, процесс завершается штатно. Через час вход повторяется, tmux attach -t deploy возвращает экран, и задание либо ещё идёт, либо уже завершилось, журнал подскажет.

Журнал и командная строка рядом выручают при настройке служб. Слева панель с journalctl -u nginx -f, справа оболочка, поведение перезапущенной службы сразу видно в живом потоке. Для файлов журналов приложения годится tail -f /var/log/app.log. Панель наблюдения уменьшают заглавными H J K L, для чтения длинных строк разворачивают сочетанием префикса и z.

Несколько машин требуют одновременного контроля. В окне открываются панели, в каждой своя машина по ssh, и синхронизация ввода включается клавишей:

bind S set -w synchronize-panes \; display-message "synchronize-panes toggled"

После нажатия всё введённое уходит во все панели окна, для необратимых действий синхронизацию выключают тем же сочетанием.

Запись происходящего в файл остаётся последним штрихом: команда pipe-pane дублирует всё, что печатает панель.

tmux pipe-pane -t deploy.0 "cat >> /tmp/deploy.log"

Повторный вызов без команды останавливает запись.

Устойчивость соединения ssh поддерживается настройкой клиента, в ~/.ssh/config добавляется блок:

Host production
  ServerAliveInterval 30
  ServerAliveCountMax 3

Клиент отправляет контрольный пакет каждые полминуты, и промежуточные узлы не рвут простаивающую сессию. Даже при обрыве tmux продолжает держать работу.

Типовой порядок запуска долгого задания на сервере через tmux выглядит так:
1. подключиться к серверу по ssh и открыть именованную сессию командой tmux new -s deploy;
2. разделить окно на панели и запустить в одной из них слежение за журналом службы nginx командой journalctl -u nginx -f;
3. запустить в соседней панели само задание, например синхронизацию большого каталога утилитой rsync;
4. убедиться по журналу, что процесс стартовал, и отключиться от сессии сочетанием префикса и d;
5. после разрыва связи или закрытия терминала подключиться к серверу заново и вернуться в сессию командой tmux attach -t deploy;
6. завершив задание, закрыть сессию командой tmux kill-session -t deploy и проверить результат.

Готовый конфиг переезжает между серверами копированием одного файла, tmux ставится из репозитория командой apt install tmux или dnf install tmux. Привычка начинать серверную работу с именованной сессии закрепляется быстро: обрывы перестают быть событием, журналы всегда на виду, а руки запоминают клавиши.