Если ваша работа требует держать множество SSH-сессий к разным серверам, вы наверняка знаете, как они легко ломаются при переключении на другой Wi-Fi или при временной потере интернета. Но что, если я скажу вам, что все эти проблемы давно решены и можно забыть про сломанные сессии и постоянные переподключения?
Открывая крышку ноутбука, все мои десятки SSH-сессий сразу доступны и находятся в том же состоянии, в каком я их оставил. В статье описывается настройка терминального сервера для системного администратора. Использование такого сервера позволяет забыть о сломанных SSH-сессиях, постоянном переподключении и вводе паролей.
Настройка сервера
Идея проста и наглядно проиллюстрирована на картинке в заголовке поста: все SSH-подключения мы будем держать на специальном терминальном сервере. Этот сервер будет нашей точкой входа для управления другими серверами. При этом на конечных серверах не потребуется настройки или установки дополнительного ПО.
Для терминального сервера подойдет почти любая конфигурация, но лучше иметь побольше оперативной памяти, чтобы хранить лог консоли внутри каждой сессии и иметь возможность в любой момент проскроллить историю вверх и посмотреть, что вы делали на сервере сессии месяц назад. Обычно 1-2ГБ памяти достаточно.
Выбор дистрибутива
В терминальном сервере самое главное — это uptime, ведь чем реже мы перезагружаемся, тем больше живут наши SSH-сессии. Поэтому выбираем максимально консервативный LTS (Long Term Support) дистрибутив, например стабильную ветку debian или ubuntu. Настраиваем автоматические обновления (unattended-upgrades) таким образом, чтобы внезапный перезапуск программ не стал неожиданностью.
Настройка SSH-сервера
Так как терминальный сервер будет открывать доступ ко всем нашим серверам разом, будет правильно его обезопасить. Для этого запретим аутентификацию с помощью паролей, оставив только доступ с помощью ключей, а так же запретим логиниться пользователем root.
Предварительно нужно создать нового пользователя в системе.
/etc/ssh/sshd_config
.....
# Запрет логиниться пользователем root
PermitRootLogin no
# Запрет использования паролей, только ключи
ChallengeResponseAuthentication no
# Если паролей нет, то и PAM не нужен
UsePAM no
....
Такой конфигурации вполне достаточно, чтобы защититься от массового перебора паролей, так как SSH-сервер будет просто закрывать подключение при попытке авторизоваться с паролем. Даже при большом числе подключений, они будут закрываться достаточно быстро, не создавая существенной нагрузки на сервер. На мой взгляд, с такой конфигурацией нет необходимости устанавливать дополнительные средства защиты вроде fail2ban.
Часто начинающие админы в своих руководствах советуют менять порт SSH и вместо 22 устанавливать какой-то нестандартный вроде 2222. На мой взгляд это плохая практика, не добавляющая никакой безопасности.
- Это не позволит защититься от перебора паролей, так как автоматические сканеры всё равно найдут SSH на любом порту и начнут долбиться.
- Это вносит бардак, если систему администрирует несколько человек и каждый выдумывает свои порты. Когда таких систем десятки, приходится искать сканером на каком порту спрятан SSH на этот раз.
- Это ломает встроенные ограничения безопасности в программах. Например, веб-браузеры не подключатся на порт 22, если явно указать его в HTTP, но при этом подключатся на другой нестандартный порт. Это можно использовать для срабатывания IDS/IPS систем DDoS.
Tmux — одно окно чтобы править всеми
Tmux — это невероятно удобная программа для управления виртуальными терминалами, без которой я просто не представляю своей работы. Поначалу он кажется запутанным и сложным, но если пересилить себя и научиться им пользоваться, вы больше не сможете от него отказаться.
Для тех, кто не знает что такое tmux, представьте себе веб-браузер с вкладками, только вместо сайтов там консольные сессии. Можно открыть бесконечное количество вкладок и в каждой вкладке запустить свою программу. При этом он запущен на сервере, и от него в любой момент можно отключиться, при этом все запущенные вкладки и программы останутся на своём месте и к ним можно будет вернуться.
Устанавливаем tmux, если он еще не установлен:
apt install tmux
В терминологии tmux, отдельный набор окон называется сессией. Мы будем использовать только одну сессию по умолчанию, поэтому не будем использовать названий сессий вообще. Но важно знать, что их может быть больше одной при необходимости.
Создаем новую сессию:
tmux new
В этот момент мы создали новую сессию с одним окном и сразу подключились к ней. Можно видеть появившуюся внизу зелёную панель состояния. Это что-то вроде панели с вкладками в браузере. На ней будут отображаться текущая вкладка и соседние, а также служебные сообщения.
На панели состояния tmux отображаются названия окон (вкладок)
В этот момент, даже если мы закроем SSH-подключение и заново подключимся к серверу, наша запущенная сессия tmux останется в прежнем состоянии, вместе со всеми запущенными программами так, будто мы ее свернули. Попробуем запустить программу top внутри сессии tmux и отключимся от неё. Для наглядности закроем полностью окно терминала и заново подключимся к серверу.
После переподключения к серверу подключимся к нашей запущенной ранее сессии:
tmux attach
И убедимся, что запущенная программа top продолжает работать. На этом месте важно понять главный принцип: после запуска сессия tmux остается работать в фоне на сервере вне зависимости от того, подключены вы к ней или нет.
Так как сессия tmux позволяет несколько одновременных подключений, это можно использовать для совместной работы нескольких человек на сервере, чтобы видеть в реальном времени одну и ту же консоль. Для этого все подключаются к одному серверу под одной учетной записью и вводят tmux attach. Там же можно и чатиться, прямо в командной строке. Мы часто это используем, чтобы не перекидывать друг другу лог консоли в мессенджере, а сразу работать за одним терминалом.
Tmux умеет делить окно на несколько (каждое окно внутри вкладки называется pane), это удобно, когда нужно одновременно видеть две консоли. Например, в одном окне редактировать скрипт, а в другом смотреть лог.
tmux позволяет создавать несколько окон внутри одного и изменять их размер
По умолчанию, для управления tmux-ом используется хоткей Ctrl+b. После нажатия этого управляющего хоткея tmux ожидает ввода основной команды из одной буквы.
Вот основные команды:
Ctrl+b + c — (create) Создать новое окно (вкладку)
Ctrl+b + <цифра> — Переместиться на вкладку номер N, где цифра это клавиша от 0 до 9. Нумерация окон начинается с нуля.
Ctrl+b + x — закрыть текущее окно. Если будет закрыто последнее окно, сессия tmux завершится.
Ctrl+b + w — отобразить список всех окон, по которому можно перемещаться кнопками курсора вверх-вниз и выбрать нужное, нажав enter.
Ctrl+b + " — разделить окно пополам по горизонтали и создать новое
Ctrl+b + % — разделить окно по вертикали и создать новое
Ctrl+b + , — переименовать текущее окно
Ctrl+b + вниз/вверх/влево/вправо — перемещаться по pane'ам внутри окна
Ctrl+b + page up/page down — прокрутить скролл вверх
Ctrl+b + / — искать по истории, как в vim или less
Это все хоткеи, которые мне потребовались за 10 лет использования tmux. На самом деле их намного больше, но для начала лучше остановиться на этих.
Конфиг Tmux
Я считаю хоткей Ctrl+b неудобным, так как прожимать три клавиши для любого действия выходит слишком много. Тема конфигов tmux это отдельная область вкусовщины, и у каждого бывалого пользователя есть свое видение как правильно и удобно. Есть даже целые авторские подборки конфигов и тем для tmux.
Для отправной точки я приведу пример своего конфига, который, как мне кажется, исправляет все сложности, мешающие быстрому освоению tmux. Конфиг располагается в домашней папке с именем ~/.tmux.conf
# Вместо ctrl+b будет использовать одну кнопку. Нам моем macbook это самая правая клавиша в цифровом ряду
set-option -g prefix `
# Когда нужно послать символ <`> нажимаем `+a
bind-key a send-prefix
# Нумерация окон с единицы вместо ноля
set -g base-index 1
set-option -g base-index 1
setw -g pane-base-index 1
# Lowers the delay time between the prefix key and other keys - fixes pausing in vim
set-option -sg escape-time 1
# Лимит истории консоли в 1000 строк. Столько строк можно отскроллить вверх
set -g history-limit 1000
# Цвета статус бара
# default statusbar colors
set-option -g status-fg white
set-option -g status-bg default
# default window title colors
set-window-option -g window-status-fg default
set-window-option -g window-status-bg default
# Автозапуск окон с командами при первом запуске
#------------------
# Respawn windows when PANE IS DEAD
bind-key R respawn-window
# Создать сессию default с окном local
new -d -s default -n local
# Создать окно с именем irc и командой irssi
neww -d -n irc irssi
# Создать окно с именем superserver и командой ssh root@superserver.com
neww -d -n superserver ssh root@superserver.com
# Создать окно с именем anotherserver и командой ssh root@123.123.123.123
neww -d -n superserver anotherserver root@123.123.123.123
Данная конфигурация позволяет автоматически создавать несколько окон при запуске, в которых сразу запускаются SSH-сессии. При этом не требуется вручную создавать новую сессию командой tmux new, достаточно всегда вводить tmux attach. Если сессия до этого не существовала, она будет создана.
Автозапуск tmux
Мы хотим, чтобы при подключении к терминальному серверу мы сразу попадали в tmux, даже если сервер был перезагружен и сессия tmux была закрыта.
Для этого добавим в конец файла ~/.bashrc запуск tmux. Важно помнить, что такая конструкция будет работать только с конфигом выше.
if [ ! "$TMUX" ]; then
tmux attach
fi
if [ "$TMUX" ]; then
export TERM=screen
fi
Это простое условие означает, что если мы не в tmux, то подключаемся к нему.
На этом конфигурация tmux на терминальном сервере закончена. Отныне для каждого нового SSH-подключения мы будем создавать отдельное окно в tmux. И даже если соединения с терминальным сервером будет потеряно, все SSH-подключения останутся активными.
Mosh — больше никаких разрывов
Теперь нам нужно обеспечить непрерывное соединение с терминальным сервером, которое будет всегда активно. Даже если мы на несколько дней закрыли ноутбук и открыли его в другой wifi-сети, соединение должно восстанавливаться само.
Mosh — надстройка над обычным OpenSSH сервером, которая позволяет забыть о разрывах соединения. Mosh авторизуется по обычному SSH, после чего поднимается отдельный UDP-канал, который мгновенно восстанавливается после разрыва, даже если у вас сменился внешний IP-адрес.
Так как нам нужно держать постоянное подключение к терминальному серверу, мы установим mosh только на сервер и на наш рабочий компьютер. При этом на удалённые серверы ничего устанавливать не потребуется, так как подключения к ним и так уже живут вечно в tmux.
Устанавливаем tmux на сервер:
apt install mosh
Устанавливаем mosh на наш рабочий компьютер. Он доступен для всех основных операционных систем, но нативный клиент есть только для Unix-подобных операционных систем. Версия для Windows реализована с помощью Cygwin либо приложения Chrome.
Я использую macOS, и устанавливаю mosh через пакетный менеджер brew:
brew install mosh
В большинстве случаев mosh не требует дополнительной настройки и работает прямо из коробки. Достаточно вместо команды ssh написать mosh:
mosh user@my-server.com
Для нестандартных конфигураций команда выглядит чуть сложнее. Например, если нужно указать порт и путь к ключу:
mosh --ssh="ssh -p 2222 -i /path/to/ssh.key" user@my-server.com
Первичную аутентификацию mosh выполняет как обычный SSH-клиент, авторизуясь на стандартный порт 22. При этом mosh-сервер изначально не слушает никаких портов, и кроме оригинального демона OpenSSH наружу никаких портов на сервере не открыто. После подключения по TCP, mosh запускается на сервере в юзерспейсе и открывает дополнительный тоннель по UDP.
Схема работы протокола Mosh
Теперь запущенная на клиенте сессия mosh будет всегда восстанавливаться при появлении интернета. На своем ноутбуке я держу открытой одну сессию mosh месяцами без перезапуска и мне не приходится постоянно заново логиниться на терминальный сервер, он просто всегда работает.
Чтобы каждый раз не вводить длинную команду подключения к терминальному серверу, я сделал алиас команды подключения из одной буквы:
alias t='mosh --ssh="ssh -p 443 -i /path/to/ssh.key" user@my-server.com'
Заключение
Эта простая схема позволяет значительно сэкономить время и нервы, не терять результат работы при обрыве SSH. Мне постоянно приходится видеть, как начинающие админы начинают каждый раз заново логиниться на свои сервера и убивать залипшие SSH-сессии.
Возможно, на первый взгляд это покажется слишком запутанным, но я уверяю вас, стоит себя один раз пересилить и привыкнуть, как вы начнете смотреть со снисходительным сожалением на тех, у кого до сих пор ломаются SSH-подключения.
Автор: owlnagi