Блог 7even

про ruby, rails, sinatra, git и всё на свете

Тонкая настройка SSH

Любой веб-разработчик пользуется ssh чуть ли не ежедневно - чтобы размещать код на удаленном сервере, конфигурировать этот сервер, производить какие-то операции с файлами итд. Но не все знают о возможностях тонкой настройки клиента OpenSSH - о них и пойдет речь в этой статье.

Общее соединение

Часто есть необходимость подключиться к одному и тому же серверу одновременно в нескольких окнах/вкладках консоли. ssh можно настроить так, чтобы вместо создания нового соединения к серверу использовалось уже созданное. Для этого нужно добавить следующие строчки в ~/.ssh/config (возможно, этот файл придется создать):

1
2
ControlMaster auto
ControlPath /tmp/ssh_mux_%h_%p_%r

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

Этот метод также работает со всеми утилитами, использующими ssh-соединения: scp, rsync, git итд - достаточно открыть соединение, и утилита будет его использовать. При вводе пути к файлу на удаленном сервере в scp даже будет работать tab-completion.

Постоянное соединение

Во время работы часто приходится устанавливать много следующих друг за другом соединений - подключаемся, отключаемся, опять подключаемся - и так по много раз в день. OpenSSH позволяет устанавливать постоянное соединение - после окончания сессии такое соединение будет висеть в “спящем режиме” в течение указанного в конфиге времени, и будет использовано, как только будет запрошено соединение с тем же сервером. Постоянные соединения включаются одной строчкой в конфиге (в дополнение к 2 строчкам для общего соединения):

1
ControlPersist 4h

Авторизация через публичный ключ

Это, пожалуй, самая известная возможность ssh - чтобы не было нужно вводить пароль при каждом соединении, достаточно создать на локальной машине пару ключей - публичный и приватный - и скопировать публичный на удаленную машину, к которой нужно подключаться по ssh. При этом будет запрашиваться pass phrase для ключа - но это будет происходить только при первом соединении после каждой перезагрузки локальной машины, а не при каждом соединении.

Для начала нужно сгенерировать пару ключей. Это делается командой

1
$ ssh-keygen

которая выдаст инструкции для дальнейших действий по генерации ключа. Нужно ввести pass phrase, чтобы приватный ключ хранился в зашифрованном виде. Потом нужно скопировать публичный ключ на удаленную машину. Во многих системах для этого есть команда ssh-copy-id, с ее помощью ключ копируется следующим образом:

1
ssh-copy-id smylers@compo.example.org

Если же команда ssh-copy-id отсутствует, можно проделать эти же действия вручную:

1) найти файл с публичным ключом - ssh-keygen должен сообщить путь к файлу, обычно это что-то вроде ~/.ssh/id_rsa.pub
2) на каждой из удаленных машин нужно поместить содержимое этого файла в ~/.ssh/authorized_keys
3) убедиться, что ~/.ssh и ~/.ssh/authorized_keys доступны для записи только для вашего пользователя

Например, такая команда должна выполнить эти действия:

1
$ < ~/.ssh/id_rsa.pub ssh clegg.example.org 'mkdir -p .ssh; cat >> .ssh/authorized_keys; chmod go-w .ssh .ssh/authorized_keys'

Алиасы для хостов

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

1
2
Host dev
  HostName dev.internal.example.com

Похожие доменные имена можно группировать, используя подстановку с помощью %h.

1
2
Host dev intranet backup
  HostName %h.internal.example.com

Данный пример создаст алиасы dev, intranet и backup для dev.internal.example.com, intranet.internal.example.com и backup.internal.example.com соответственно.

Также можно использовать обычную маску - * для любого кол-ва символов и ? для одного любого символа:

1
2
Host www* mail
  HostName %h.example.com

Если имя пользователя на локальной и удаленной машинах различаются, можно также указать его в описании хоста:

1
2
3
Host www* mail
  HostName %h.example.com
  User simon

Теперь, даже если локально нашего юзера зовут smylers, подключение через команду

1
$ ssh www2

будет использовать пользователя simon.

Соединение по цепочке

Часто доступ к определенному серверу открыт только для другой доверенной удаленной машины, в этом случае нужно сначала заходить на доверенную машину, а уже оттуда соединяться с итоговым сервером. Это также можно автоматизировать. Сначала нужно убедиться в наличии публичного ключа на всех серверах, чтобы можно было подключиться к промежуточной машине одной командой, а оттуда второй командой - к нужному серверу; так, чтобы ни одна из команд не запрашивала пароль:

1
2
$ ssh gateway
gateway$ ssh db

Теперь в локальном shh-конфиге указываем, что для подключения к конечному хосту нужно проксирование через ssh на промежуточном сервере:

1
2
3
Host db
  HostName db.internal.example.com
  ProxyCommand ssh -W %h:%p gateway

После этого для подключения к конечному серверу будет достаточно следующей команды:

1
$ ssh db

Проброс портов

Иногда на удаленном сервере работает какая-то служба - такая, как веб-сервер, или сервер БД - и есть необходимость настроить соединение с этой машиной так, чтобы можно было вести работу с сервисом на ней через локальный порт - как если бы сервис был запущен локально. Это бывает полезно, например, когда на удаленном сервере запущен сервер PostgreSQL, настроенный на работу только с локальными соединениями.

Это можно осуществить с помощью проброса портов. Например, для работы с PostgreSQL-сервером на удаленной машине через локальный порт 5433 нужно вписать в ~/.ssh/config следующее:

1
2
Host db
  LocalForward 5433 localhost:5432

Теперь когда мы подключаемся к хосту db, весь трафик на локальном порту 5433 перенаправляется на порт 5432 на удаленной машине - и последняя думает, что соединение приходит с localhost.

1
2
3
$ ssh db
# открываем новое окно консоли, чтобы снова выполнять команды локально
$ psql -h localhost -p 5443 orders

Или же, допустим, у нас есть бэк-энд веб-сервер, недоступный напрямую из сети - можно направить к нему весь трафик с локального порта:

1
2
Host api
  LocalForward 8080 localhost:80

Потом подключаемся к нему:

1
$ ssh api

И сервер отвечает на локальном порту 8080:

1
$ firefox http://localhost:8080/

Авторство

Эта статья является переводом, оригинал находится здесь. Я перевел не всю статью, а только части, показавшиеся мне наиболее интересными.

Комментарии