Магия ssh
Разве что ленивый не писал про ssh и несмотря на это, данный протокол и его возможности не перестают меня восхищать. Здесь я хочу поделиться исключительно своим опытом использования сего замечательного инструмента в своих задачах (При этом активно применяю его даже при разработке на Windows).
Поскольку я программист, то инструментарий ssh часто нужен мне в разработке и для личных нужд. Самые частые задачи, которые я выполняю с его помощью (по частоте использования):
- Удалённый доступ — логично, ведь для этого он и предназначался.
- Монтирование папок по сети — очень удобно для работы с кодом на удалённой машине.
- Удалённое выполнение команд — нечастая, но используемая мной операция. Удобно получать выхлоп команды в канал другой команды на текущей машине.
- Запуск графических приложений на удалённой машине.
- Проксирование трафика — способ перенаправления трафика. Этакий быстрый и простой аналог VPN.
- Обратный ssh — использую для проброса портов к системам, находящимися за NAT, когда лень настраивать firewall.
Далее вкратце разберу каждый пункт, и особенно пути эффективного и простого использования под Windows.
Конфигурирование рабочей машины
Забавно, что в различных примерах использования ssh, этот важнейший момент обходят стороной, хотя, как по мне — он ключевой. Приведу вполне живой пример, того, как я делаю первичную настройку сервера под себя.
После того как я выбрал и заказал себе сервер VPS, у меня в панели создания сервера появляется логин и пароль, и как это не удивительно — логин root
.
Результат создания сервера
Первое, что нужно сделать прямо сразу после создания сервера: отключить логин по руту, настроить фаервол и проковырять в нём дырочку для корректной работы ssh. В идеале отключить логин по паролю и оставить только логин по ключу.
Когда-то я уже делал хороший гайд в наш Справочник о первичной настройке Ubuntu 18.04. Вся информация актуальна и применима к Ubuntu 20.04. Подробно расписывать, что я делаю — не буду, но дам небольшие пояснения.
ssh remotehost #заранее прописал ip сервера в /etc/hosts
adduser dlinyj #добавляем нового пользователя
usermod -aG sudo dlinyj #добавляем пользователя в группу sudo
Обращаю внимание, что я создаю пользователя такого же, как и на локальной машине, и поэтому — далее по тексту его не указываю. Если у вас пользователь отличается от того, что на сервере, то логиниться нужно через user@remotehost
.
Далее необходимо отключить логин пользователя root
. Это очень важно, потому что, в конце концов, методом перебора сервер рано или поздно будет взломан.
nano /etc/ssh/sshd_config
Находим строчку, содержащую PermitRootLogin
, и меняем её на состояние no
.
PermitRootLogin no
После этого перезапускаем ssh-сервис.
service sshd reload
Обязательно рекомендую проверить, что вы больше не можете зайти под рутом с тем же паролем, и эти изменения успешно применились.
После чего проверяю успешность подключения от своего аккаунта dlinyj
, и затем копирую ключи. Логин по ключам имеет две цели: не вводить пароль каждый раз вручную, и просто отключить логин по паролю. Ключи перебрать значительно сложнее, чем пароль по словарям. Главное — не забыть сгенерировать пару ключей командой ssh-keygen
. Можно сделать сложные ключи, а можно более простые. Тут уж дело вкуса, а я особо не заморачиваюсь и просто запускаю данную команду.
ssh-keygen
После успешной генерации пары ключей: публичного и приватного, копируем публичный ключ с помощью следующей команды:
ssh-copy-id remotehost
Проверяем логин. Введя ssh remotehost — мы должны сразу зайти на удалённый сервер с текущим логином.
После чего можно и вовсе отключить логин по паролю. Если вы единолично используете сервер, то это лучший вариант. Меня пугает ситуация, что если я потеряю приватный ключ, то попасть на сервер будет проблематично, но не сказать об этом нельзя.
Снова редактируем файл:
sudo nano /etc/ssh/sshd_config
Находим строку PasswordAuthentication
, раскомментируем её и ставим no
. Всё, перезапускаем ssh сервис командой sudo service sshd reload и наслаждаемся жизнью. Также настоятельно рекомендую настроить фаервол, согласно мануалу.
В заключении главы хочу порекомендовать внимательно посмотреть на все возможные настройки sshd
, которые кроются в конфигурационном файле. Можно ограничить время сессии, количество подключений и многое другое.
Мои основные применения ssh
Итак, пробегусь по основным применениям ssh, кроме банального удалённого доступа.
▍ Удалённое выполнение команд
Простейший пример — это выполнить и записать команду сразу после адреса удалённого хоста.
Например:
ssh remotehost cat /etc/passwd | grep dlinyj
Вернётся следующая строка:
dlinyj:x:1000:1000:,,,:/home/dlinyj:/bin/bash
Обратите внимание, что grep выполнился уже на стороне машины, с которой мы делали запрос. Это можно увидеть, если добавить вывод, например, ip-адреса:
ssh remotehost cat /etc/passwd | grep dlinyj;ip a
dlinyj:x:1000:1000:,,,:/home/dlinyj:/bin/bash
...
2: enp6s0: mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:**:**:**:**:** brd ff:ff:ff:ff:ff:ff
inet 192.168.**.**/24 brd 192.168.**.** scope global dynamic noprefixroute enp6s0
valid_lft 378sec preferred_lft 378sec
...
Если мы хотим, чтобы цепочка команд была выполнена на стороне хоста, то следует брать команды в кавычки.
ssh remotehost "cat /etc/passwd | grep dlinyj;ip a"
dlinyj:x:1000:1000:,,,:/home/dlinyj:/bin/bash
...
2: eth0: mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:**:**:**:**:** brd ff:ff:ff:ff:ff:ff
inet ***.***.***.***/** scope global eth0
valid_lft forever preferred_lft forever
При этом бывает удобно использовать как первый, так и второй вариант. При первом варианте удобно получать выхлоп в свои скрипты, а при втором — делать что-то большое на удалённом сервере.
▍ Копирование файлов «на» и «с» удалённого хоста
В линуксе достаточно банальная операция копирования по протоколу scp, которая осуществляется с помощью команды scp. Данная программа используется точно так же, как и команда cp, с той особенностью, что надо указывать адрес удалённого сервера. Пример использования:
$ touch testfile
$ scp testfile remotehost:~/
testfile 100% 0 0.0KB/s 00:00
$ ssh remotehost ls testfile
testfile
Здесь я создал файл, затем скопировал его на удалённый хост (в домашнюю папку), и после, проверил его существование. Аналогично можно копировать и в обратном направлении.
▍ Монтирование удалённых папок
Для меня это является чуть ли не самой часто используемой функцией. Даже научился через тернии использовать её в Windows. Монтирование папок с удалённого хоста чаще всего использую для разработки на удалённом сервере, особенно если он какой-то отличный от x86 архитектуры. Да, Visual Studio Code
умеет работать по ssh
, но мне этот функционал не понравился. Плюс, не на каждый удалённый хост можно поставить дополнительные пакеты, чтобы работало всё гладко и там был поиск по файлам внутри студии. Когда программа большая (например, исходники Android) — поиск по файлам бывает очень нужен.
Очень удобно работать с удалённой папкой локально, будто бы она находится здесь и сейчас. Единственное, чего мне не хватает в этом функционале — это корректная работа inotify для отслеживания изменений файлов на удалённой машине. С такими примонтированными папками можно творить потрясающие штуки. Например, я организовывал взаимодействие двух сервисов, данные которых обменивались через примонтированные по ssh каталоги. Единственное, что не удалось — отслеживать изменения файлов, выполненные удалённой машиной. Тут пришлось изобретать другие схемы синхронизации.
Для того чтобы монтировать удалённые папки, нужно установить приложение sshfs.
sudo apt install sshfs
Теперь можно сделать монтирование удалённой папки. Для этого нужно указать локальную точку монтирования и путь к удалённой папке. Например, смонтируем папку home удалённого сервера — в папку ~/home локальной машины:
mkdir ~/home
sshfs remotehost:/home/dlinyj/ ~/home
В том, что монтирование прошло успешно, можно убедиться командой mount
:
mount
....
remotehost:/home/dlinyj/ on /home/dlinyj/home type fuse.sshfs (rw,nosuid,nodev,relatime,user_id=1000,group_id=1000)
Убедимся, что папка не пуста:
ls -la ~/home/
итого 40
drwxr-xr-x 1 dlinyj dlinyj 4096 июл 11 23:49 .
drwxr-xr-x 28 dlinyj dlinyj 4096 июл 12 00:01 ..
-rw------- 1 dlinyj dlinyj 983 июл 11 23:46 .bash_history
-rw-r--r-- 1 dlinyj dlinyj 220 июл 10 21:40 .bash_logout
-rw-r--r-- 1 dlinyj dlinyj 3771 июл 10 21:40 .bashrc
drwx------ 1 dlinyj dlinyj 4096 июл 10 21:44 .cache
drwxrwxr-x 1 dlinyj dlinyj 4096 июл 10 22:39 .local
-rw-r--r-- 1 dlinyj dlinyj 807 июл 10 21:40 .profile
drwx------ 1 dlinyj dlinyj 4096 июл 10 23:25 .ssh
-rw-r--r-- 1 dlinyj dlinyj 0 июл 10 21:41 .sudo_as_admin_successful
-rw------- 1 dlinyj dlinyj 57 июл 11 23:49 .Xauthority
Это самый крутой инструмент ssh, который приводит меня в полнейший восторг. Если бы можно было монтировать под Windows удалённые папки из Linux-машин, то было бы просто великолепно. Хотя и это тоже возможно сделать без особых проблем.
▍ Запуск удалённых графических приложений
Это называется X11 Forwarding, и для того чтобы продемонстрировать данный функционал, необходимо настроить ssh-демон. Снова на удалённом сервере редактируем файл sshd_config:
nano /etc/ssh/sshd_config
Находим там строку X11Forwarding
, раскомментируем её и ставим значение yes:
X11Forwarding yes
И после — не забываем перезапустить сервис sshd
.
service sshd reload
Чтобы показать работу «проброски окошек» — нужно на чистый сервер без «иксов», установить хоть какие-нибудь X-приложения. Для этого я выполнил:
sudo apt install x11-apps
Это легковесный пример графических приложений, который для своей установки не требует много места. Отключаемся от удалённого сервера комбинацией клавиш ctrl-d (deattach) и подключаемся уже с опцией -X
:
Глазки удалённого сервера следят за вашей мышкой
Как видно, графические приложения удалённого сервера прекрасно взаимодействуют с мышью.
Но к сожалению — не всё так радужно. Конечно, можно весь оконный менеджер так запустить, и оно будет работать, но будет дико тормозить. Обычно подобный запуск я использую исключительно для того, чтобы посмотреть какие-то графики, картинки, или глянуть последнюю вкладку в браузере на удалённом сервере. Последний раз, когда пробовал пробрасывать окошко логического анализатора — пользоваться этим было практически невозможно. Для полноценной работы всё же лучше использовать RDP.
▍ Проксирование трафика
Не могу сказать, что часто использую данный функционал, но несколько раз он меня выручал. Он особенно полезен, если нужно пропустить трафик через удалённый сервер, а морочиться с настройкой нормального VPN нет времени или желания. Этакий туннель для бедных.
Если посмотреть все мануалы про то, как проксировать трафик, то там приводится просто команда ssh, но совершенно не рассказывается о том, как настроить демона. При этом команда выполнится, но фокуса не произойдёт. Поэтому начну с главного — как разрешить проксирование. Для этого снова редактируем наш многострадальный файл конфигурирования демона ssh.
Находим там следующую строку, раскомментируем её и приводим к виду:
AllowTcpForwarding yes
Сохраняем файл и перезапускаем демон. После этого можно создать канал прокси к нашему серверу следующей командой:
ssh -D 8888 remoteserver
Где 8888
— локальный порт для прокси. Всё, теперь с данным прокси можно настроить и браузер. Пример настройки для firefox:
С хромом — ещё проще. Достаточно запустить его из командной строки:
google-chrome --proxy-server="socks5://localhost:8888
Если теперь перейти на сайт myip.ru, то там будет отображаться адрес вашего сервера:
Тут адрес вашего сервера
Таким образом, проксирование успешно работает. Отмечу, что это не такой уж и экзотический способ. Для смартфонов есть даже всякие приложения, которые умеют проксировать весь трафик мобильного устройства.
▍ Обратный ssh
Эта опция прям редко-редко мной использовалась, но были случаи, когда реально выручала. Суть такова — ваш домашний компьютер, либо какое другое устройство под управлением *nix находится за NAT и у вас нет выделенного IP. Есть множество решений этой проблемы, но, как по мне, идеальным решением будет обратный ssh. Со мной многие не согласятся и будут даже правы, но для меня это простой и понятный путь. Не агитирую.
Создаётся ssh соединение, по которому с удалённого сервера можно будет подключиться к вашему домашнему ПК. Итак, с домашнего ПК необходимо выполнить следующую инструкцию:
ssh -R 5544:localhost:22 remotehost
Опция R говорит перенаправлять порт удалённого хоста на указанный порт локального компьютера. Выполняем её и у нас будет поднято ssh-соединение до удалённого сервера. Если теперь подключиться к удалённому серверу, например, с работы, то можно получить доступ к домашней машине следующей командой:
ssh localhost -p 5544
Вжух, и вы на своей домашней машине, вне зависимости от того, где она находится.
Особенность в том, что на домашнем компе надо держать активную сессию и плюс — данные не сжимаются. Поэтому немного модифицируем инструкцию, чтобы всё работало быстрее.
ssh -fCNR 5544:localhost:22 remotehost
-f
выполняет команду ssh в фоновом режиме, однако, если закрыть окно терминала — сессия прервётся (используйте nohup),-C
сжатие данных,-N
не выполнять удалённые инструкции.
Если хочется, чтобы можно было подключиться извне, то нужно на удалённом хосте тоже сделать перенаправление портов. Делается следующей командой и выполняется на хосте:
ssh -fCNL *: 1234: localhost: 8888 localhost
-f
Фон.-C
Сжатие.-N
Не выполнять инструкции.-L
Перенаправляет порт на локальной машине (клиенте) на указанный порт, указанной удалённой машины.
Всё. Проковыриваете дырку в фаерволе для порта 1234
и из внешнего мира можно подключиться к вашему домашнему компьютеру, просто подключившись к remotehost
по порту 1234
.
Из недостатков способа можно отметить то, что сессия рвётся по таймауту, и если вдруг произошло отключение (плохой интернет), то связи больше не будет. Но специально для нас придумали autossh. Параметры такие же, как и у ssh, только он восстанавливает соединение после разрыва. Подробнее можно прочитать тут.
А как же Windows?
Ох, ОС Windows — это моя личная боль, при использовании ssh. Всем хороша операционная система, но плохо совместима с linux. На одной работе локальные компьютеры были под Windows, а разработка велась на удалённом сервере под Linux. При этом установить linux локально запрещала политика компании, как и ставить какой-либо иной софт, кроме разрешённого скромного списка. И эта личная боль (и опыт), решение которой я хочу изложить в этой части статьи.
Из широко распространённых инструментов можно отметить консольный клиент putty, который я использую для удалённого администрирования и WinSCP — для копирования файлов. С программой копирования по протоколу SCP всё более-менее понятно — это обычный командер. Единственное, что мне в ней не нравится, что если сессия рвётся по таймауту, то приходится заново создавать подключение, а это долго и раздражает. Да и в целом — я не нахожу её особо удобной, поэтому следует рассказать об альтернативных путях.
Копирование прошивки на малину.
Вот putty не так прост, как кажется на первый взгляд. Для меня эта программа — эталон удобства, и порой даже думаю поставить её под linux, хотя это и оверкилл. Программа позволяет делать практически все операции, описанные выше, кроме монтирования папок и копирования файлов: проксирование, проброс иксов, обратный ssh. Расскажу то, чем пользуюсь я (кроме банального удалённого доступа) — это проброс X11 на локальную машину.
▍ Проброс X11 в Windows
Поскольку Windows не имеет собственного Windows X-сервера, его следует предварительно установить. Есть несколько программ для этого. В своих решениях я использую VcXsrv Windows X Server. После установки запускаем и не забываем установить номер дисплея равный нулю:
Далее всё по умолчанию, разве что стоит отключить opengl:
Щёлкаем далее и готово.
В putty необходимо разрешить перенаправление иксов. В сессии, которую вы создали и сохранили для вашего удалённого сервера необходимо пойти в настройки, и найти вкладку X11, и там включить X11-перенаправление. В моём случае это выглядит так:
Всё, теперь можно посмотреть на глазки, следящие за курсором, но уже в Windows.
Глазки следят за курсором в Windows.
▍ Когда хочется POSIX в Windows
Конечно, всё это хорошо, но когда привыкаешь к магии и простоте консольных команд копирования, удалённого выполнения и прочего, то в Windows всего этого не хватает. Поэтому я долго искал какие-то более-менее вменяемые альтернативы. Главное — отказаться от WinSCP. Простейшей, и вполне удобной альтернативой оказался Cygwin. По сути, это коллекция инструментов GNU, которые обеспечивают функциональность, аналогично дистрибутиву Linux для Windows. Пока нормально не допилили wsl (Windows Subsystem for Linux) — долгое время я пользовался им. В сути, всё то же самое, что я выше описал для Linux, разве что это обычные exe-файлы, и работают под Windows: ssh
, scp
, ssh-keygen
, ssh-copy-id
. Работает всё, кроме удалённого монтирования папок, как я не пытался разрешить эту проблему и как не искал пакеты — так и не понял, как это можно сделать.
Как по мне, это самое простое и быстрое решение, потому что разворачивать wsl немного сложнее, чем просто скачать и запустить инсталлятор Cygwin.
▍ Путь настоящего джедая — Windows Subsystem for Linux
Если исключить установку linux на виртуальную машину, и шаринг папок по сети, то один из немногих известных мне (вменяемых) способов монтирования папок по ssh — использование подсистемы линукс для виндоус. Можно посмотреть следующий мануал и ужаснуться того, как же сложно это делается.
Но на самом деле, на Windows 11 wsl уже совсем хорошо и просто работает, без особых танцев с бубном и перенаправлением видео на программу X Server. На Windows 10 я ставил Ubuntu из магазина приложений, потом запускал какую-то команду в PowerShell
, чтобы активировать wsl и получал готовый linux.
Это решение хорошо тем, что оно мгновенно запускается. Консоль linux запускается также быстро, как PowerShell
или cmd
. Также оно имеет доступ ко всем данным на жёстких дисках из коробки. Единственный нюанс — нельзя по сети монтировать папки в папки, принадлежащие ОС Windows.
Поэтому я монтирую папки в wsl, и там уже запускаю Visual Studio Code
, скармливаю ей локальную папку и работаю в ней. Студия ругается на то, что я запускаю её под wsl. Для работы X11 в Windows 10 (в Windows 11 починили), точно также как для удалённого сервера надо устанавливать программу VcXsrv
. Для того чтобы окна корректно открывались, нужно в машине wsl прописать адрес удалённого сервера X Windows (можно её сразу добавить в .bashrc
):
export DISPLAY=$(awk '/nameserver / {print $2; exit}' /etc/resolv.conf 2>/dev/null):0
Понимаю, что это может показаться очень сложным, но я так привык к удобству удалённых папок, что один раз в этом разобраться — точно стоит того. На данный момент при работе не возникает никаких проблем, когда понимаешь: что, почему и зачем нужно.
Вот, для примера точно так же монтирую удалённую папку home
в wsl, и затем открываю её в Visual Studio Code
:
Монтирование удалённой папки и перенаправление дисплея
После чего можно успешно всё открыть в VS Code
.
Успешно открытая Visual Studio Code с удалённой папкой
Заключение
Ssh — это основной инструмент системного разработчика, администратора и даже продвинутого пользователя. Очень классный, простой, а главное — эффективный инструмент, который может решать массу задач.
Для меня самой большой болью было подружить Windows и ssh. Дружба эта — плохая, как воды и масла, но всё же, мне удаётся достаточно комфортно работать по ssh и под операционной системой Windows.
Ссылки
- Прекрасная статья использования ssh в примерах. И её русский перевод на хабре. Единственное на что хочу обратить внимание, что там опущено то, как конфигурировать демона, и без корректной настройки на стороне сервера это работать не будет.
- Пример создания обратного ssh-тунеля, в картинках, как почему, зачем.
- Достаточно объёмный, и в той же мере бесполезный мануал по разворачиванию wsl. Но есть несколько полезных моментов, которые оттуда для себя почерпнул.