img src https habrastorage org webt 1v ds rv 1vdsrvezwkf95vto5nk7 lkla

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
<img src="https://habrastorage.org/webt/1v/ds/rv/1vdsrvezwkf95vto5nk7lklaplq.png" />
Если ваша работа требует держать множество SSH-сессий к разным серверам, вы наверняка знаете, как они легко ломаются при переключении на другой Wi-Fi или при временной потере интернета. Но что, если я скажу вам, что все эти проблемы давно решены и можно забыть про сломанные сессии и постоянные переподключения?
Открывая крышку ноутбука, все мои десятки SSH-сессий сразу доступны и находятся в том же состоянии, в каком я их оставил. В статье описывается настройка терминального сервера для системного администратора. Использование такого сервера позволяет забыть о сломанных SSH-сессиях, постоянном переподключении и вводе паролей.
<cut>
<h2>Настройка сервера</h2>
Идея проста и наглядно проиллюстрирована на картинке в заголовке поста: все SSH-подключения мы будем держать на специальном терминальном сервере. Этот сервер будет нашей точкой входа для управления другими серверами. При этом на конечных серверах не потребуется настройки или установки дополнительного ПО.
Для терминального сервера подойдет почти любая конфигурация, но лучше иметь побольше оперативной памяти, чтобы хранить лог консоли внутри каждой сессии и иметь возможность в любой момент проскроллить историю вверх и посмотреть, что вы делали на сервере сессии месяц назад. Обычно 1-2ГБ памяти достаточно.
<h3>Выбор дистрибутива</h3>
В терминальном сервере самое главное — это uptime, ведь чем реже мы перезагружаемся, тем больше живут наши SSH-сессии. Поэтому выбираем максимально консервативный LTS (Long Term Support) дистрибутив, например стабильную ветку debian или ubuntu. Настраиваем автоматические обновления (unattended-upgrades) таким образом, чтобы внезапный перезапуск программ не стал неожиданностью.
<h3>Настройка SSH-сервера</h3>
Так как терминальный сервер будет открывать доступ ко всем нашим серверам разом, будет правильно его обезопасить. Для этого запретим аутентификацию с помощью паролей, оставив только доступ с помощью ключей, а так же запретим логиниться пользователем root.
Предварительно нужно создать нового пользователя в системе.
<b>/etc/ssh/sshd_config</b>
<source lang="bash">
.....
# Запрет логиниться пользователем root
PermitRootLogin no
# Запрет использования паролей, только ключи
ChallengeResponseAuthentication no
# Если паролей нет, то и PAM не нужен
UsePAM no
....
</source>
Такой конфигурации вполне достаточно, чтобы защититься от массового перебора паролей, так как SSH-сервер будет просто закрывать подключение при попытке авторизоваться с паролем. Даже при большом числе подключений, они будут закрываться достаточно быстро, не создавая существенной нагрузки на сервер. На мой взгляд, с такой конфигурацией нет необходимости устанавливать дополнительные средства защиты вроде fail2ban.
<blockquote>
Часто начинающие админы в своих руководствах советуют менять порт SSH и вместо <b>22</b> устанавливать какой-то нестандартный вроде <b>2222</b>. На мой взгляд это плохая практика, не добавляющая никакой безопасности.
<ul>
<li>Это не позволит защититься от перебора паролей, так как автоматические сканеры всё равно найдут SSH на любом порту и начнут долбиться.</li>
<li> Это вносит бардак, если систему администрирует несколько человек и каждый выдумывает свои порты. Когда таких систем десятки, приходится искать сканером на каком порту спрятан SSH на этот раз.</li>
<li>Это ломает встроенные ограничения безопасности в программах. Например, веб-браузеры не подключатся на порт 22, если явно указать его в HTTP, но при этом подключатся на другой нестандартный порт. Это можно использовать для срабатывания IDS/IPS систем DDoS. </li>
</ul>
</blockquote>
<h2>Tmux — одно окно чтобы править всеми</h2>
Tmux — это невероятно удобная программа для управления виртуальными терминалами, без которой я просто не представляю своей работы. Поначалу он кажется запутанным и сложным, но если пересилить себя и научиться им пользоваться, вы больше не сможете от него отказаться.
Для тех, кто не знает что такое tmux, представьте себе веб-браузер с вкладками, только вместо сайтов там консольные сессии. Можно открыть бесконечное количество вкладок и в каждой вкладке запустить свою программу. При этом он запущен на сервере, и от него в любой момент можно отключиться, при этом все запущенные вкладки и программы останутся на своём месте и к ним можно будет вернуться.
Устанавливаем tmux, если он еще не установлен:
<source lang="bash">
apt install tmux
</source>
В терминологии tmux, отдельный набор окон называется сессией. Мы будем использовать только одну сессию по умолчанию, поэтому не будем использовать названий сессий вообще. Но важно знать, что их может быть больше одной при необходимости.
Создаем новую сессию:
<source lang="bash">
tmux new
</source>
В этот момент мы создали новую сессию с одним окном и сразу подключились к ней. Можно видеть появившуюся внизу зелёную панель состояния. Это что-то вроде панели с вкладками в браузере. На ней будут отображаться текущая вкладка и соседние, а также служебные сообщения.
<img src="https://habrastorage.org/webt/ug/zp/wx/ugzpwxra7ztlaklf98cydfdltd0.png" />
<sup><font color="999999">На панели состояния tmux отображаются названия окон (вкладок)</font></sup>
В этот момент, даже если мы закроем SSH-подключение и заново подключимся к серверу, наша запущенная сессия tmux останется в прежнем состоянии, вместе со всеми запущенными программами так, будто мы ее свернули. Попробуем запустить программу <b>top</b> внутри сессии tmux и отключимся от неё. Для наглядности закроем полностью окно терминала и заново подключимся к серверу.
После переподключения к серверу подключимся к нашей запущенной ранее сессии:
<source lang="bash">
tmux attach
</source>
И убедимся, что запущенная программа top продолжает работать. На этом месте важно понять главный принцип: после запуска сессия tmux остается работать в фоне на сервере вне зависимости от того, подключены вы к ней или нет.
<blockquote>
Так как сессия tmux позволяет несколько одновременных подключений, это можно использовать для совместной работы нескольких человек на сервере, чтобы видеть в реальном времени одну и ту же консоль. Для этого все подключаются к одному серверу под одной учетной записью и вводят tmux attach. Там же можно и чатиться, прямо в командной строке. Мы часто это используем, чтобы не перекидывать друг другу лог консоли в мессенджере, а сразу работать за одним терминалом.
</blockquote>
Tmux умеет делить окно на несколько (каждое окно внутри вкладки называется pane), это удобно, когда нужно одновременно видеть две консоли. Например, в одном окне редактировать скрипт, а в другом смотреть лог.
<img src="https://habrastorage.org/webt/mn/sv/3j/mnsv3jc9jejmb9r2yppcmdsg7y0.gif" />
<sup><font color="999999">tmux позволяет создавать несколько окон внутри одного и изменять их размер</font></sup>
По умолчанию, для управления tmux-ом используется хоткей <b>Ctrl+b</b>. После нажатия этого управляющего хоткея tmux ожидает ввода основной команды из одной буквы.
Вот основные команды:
<b>Ctrl+b + c</b> — (create) Создать новое окно (вкладку)
<b>Ctrl+b + <цифра></b> — Переместиться на вкладку номер N, где цифра это клавиша от 0 до 9. Нумерация окон начинается с нуля.
<b>Ctrl+b + x</b> — закрыть текущее окно. Если будет закрыто последнее окно, сессия tmux завершится.
<b>Ctrl+b + w</b> — отобразить список всех окон, по которому можно перемещаться кнопками курсора вверх-вниз и выбрать нужное, нажав enter.
<b>Ctrl+b + "</b> — разделить окно пополам по горизонтали и создать новое
<b>Ctrl+b + %</b> — разделить окно по вертикали и создать новое
<b>Ctrl+b + ,</b> — переименовать текущее окно
<b>Ctrl+b + вниз/вверх/влево/вправо</b> — перемещаться по pane'ам внутри окна
<b>Ctrl+b + page up/page down</b> — прокрутить скролл вверх
<b>Ctrl+b + /</b> — искать по истории, как в vim или less
Это все хоткеи, которые мне потребовались за 10 лет использования tmux. На самом деле их намного больше, но для начала лучше остановиться на этих.
<h2>Конфиг Tmux</h2>
Я считаю хоткей <b>Ctrl+b</b> неудобным, так как прожимать три клавиши для любого действия выходит слишком много. Тема конфигов tmux это отдельная область вкусовщины, и у каждого бывалого пользователя есть свое видение как правильно и удобно. Есть даже целые авторские <a href="https://github.com/rothgar/awesome-tmux">подборки конфигов и тем</a> для tmux.
Для отправной точки я приведу пример своего конфига, который, как мне кажется, исправляет все сложности, мешающие быстрому освоению tmux. Конфиг располагается в домашней папке с именем <b>~/.tmux.conf</b>
<source lang="bash">
# Вместо 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
</source>
Данная конфигурация позволяет автоматически создавать несколько окон при запуске, в которых сразу запускаются SSH-сессии. При этом не требуется вручную создавать новую сессию командой <b>tmux new</b>, достаточно всегда вводить <b>tmux attach</b>. Если сессия до этого не существовала, она будет создана.
<h2>Автозапуск tmux</h2>
Мы хотим, чтобы при подключении к терминальному серверу мы сразу попадали в tmux, даже если сервер был перезагружен и сессия tmux была закрыта.
Для этого добавим в конец файла <b>~/.bashrc</b> запуск tmux. Важно помнить, что такая конструкция будет работать только с конфигом выше.
<source>
if [ ! "$TMUX" ]; then
tmux attach
fi
if [ "$TMUX" ]; then
export TERM=screen
fi
</source>
Это простое условие означает, что если мы не в tmux, то подключаемся к нему.
На этом конфигурация tmux на терминальном сервере закончена. Отныне для каждого нового SSH-подключения мы будем создавать отдельное окно в tmux. И даже если соединения с терминальным сервером будет потеряно, все SSH-подключения останутся активными.
<h2>Mosh — больше никаких разрывов</h2>
Теперь нам нужно обеспечить непрерывное соединение с терминальным сервером, которое будет всегда активно. Даже если мы на несколько дней закрыли ноутбук и открыли его в другой wifi-сети, соединение должно восстанавливаться само.
<a href="https://mosh.org">Mosh</a> — надстройка над обычным OpenSSH сервером, которая позволяет забыть о разрывах соединения. Mosh авторизуется по обычному SSH, после чего поднимается отдельный UDP-канал, который мгновенно восстанавливается после разрыва, даже если у вас сменился внешний IP-адрес.
Так как нам нужно держать постоянное подключение к терминальному серверу, мы установим mosh только на сервер и на наш рабочий компьютер. При этом на удалённые серверы ничего устанавливать не потребуется, так как подключения к ним и так уже живут вечно в tmux.
Устанавливаем tmux на сервер:
<source>
apt install mosh
</source>
Устанавливаем mosh на наш рабочий компьютер. Он доступен для всех основных операционных систем, но нативный клиент есть только для Unix-подобных операционных систем. Версия для Windows реализована с помощью Cygwin либо приложения Chrome.
Я использую macOS, и устанавливаю mosh через пакетный менеджер brew:
<source>
brew install mosh
</source>
В большинстве случаев mosh не требует дополнительной настройки и работает прямо из коробки. Достаточно вместо команды ssh написать mosh:
<source>
mosh user@my-server.com
</source>
Для нестандартных конфигураций команда выглядит чуть сложнее. Например, если нужно указать порт и путь к ключу:
<source>
mosh --ssh="ssh -p 2222 -i /path/to/ssh.key" user@my-server.com
</source>
Первичную аутентификацию mosh выполняет как обычный SSH-клиент, авторизуясь на стандартный порт 22. При этом mosh-сервер изначально не слушает никаких портов, и кроме оригинального демона OpenSSH наружу никаких портов на сервере не открыто. После подключения по TCP, mosh запускается на сервере в юзерспейсе и открывает дополнительный тоннель по UDP.
<img src="https://habrastorage.org/webt/oc/l4/vf/ocl4vfgwunbbtorsi_za-jc4_xq.png" />
<sup><font color="999999">Схема работы протокола Mosh</font></sup>
Теперь запущенная на клиенте сессия mosh будет всегда восстанавливаться при появлении интернета. На своем ноутбуке я держу открытой одну сессию mosh месяцами без перезапуска и мне не приходится постоянно заново логиниться на терминальный сервер, он просто всегда работает.
Чтобы каждый раз не вводить длинную команду подключения к терминальному серверу, я сделал алиас команды подключения из одной буквы:
<source>
alias t='mosh --ssh="ssh -p 443 -i /path/to/ssh.key" user@my-server.com'
</source>
<h2>Заключение</h2>
Эта простая схема позволяет значительно сэкономить время и нервы, не терять результат работы при обрыве SSH. Мне постоянно приходится видеть, как начинающие админы начинают каждый раз заново логиниться на свои сервера и убивать залипшие SSH-сессии.
Возможно, на первый взгляд это покажется слишком запутанным, но я уверяю вас, стоит себя один раз пересилить и привыкнуть, как вы начнете смотреть со снисходительным сожалением на тех, у кого до сих пор ломаются SSH-подключения.