SSH туннели и проброс портов

4 min read

При администрировании серверов часто возникают следующие задачи:

  1. Получить доступ к локальному порту на сервере с рабочей машины
  2. Обеспечить доступ к локальному порту рабочей машины с сервера

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

Доступ к внутреннему порту сервера

Попробуем подключиться к порту, к которому нет доступа снаружи, но есть доступ с сервера (например, MongoDB, которая слушает порт 27017 на интерфейсе localhost сервера). Для этого используется параметр -L.

ssh -L 9999:localhost:27017 root@serverIP

После аутентификации, у нас на рабочей машине появляется порт 9999, который перенаправлен на порт 27017 локального интерфейса сервера.

Теперь можно подключиться к MongoDB напрямую, как будто она запущена у вас на компьютере. 

mongo localhost:9999 -u user -p password

Туннель прервётся, если вы закроете SSH соединение. Кстати, если оно вам не требуется, а нужен только туннель – можно добавить параметр -N.

ssh -L 9999:localhost:27017 root@serverIP -N

Можно также открывать доступ не к локальному порту сервера, а к удаленному порту другой машины, которая доступна с сервера.

ssh -L 9999:anotherIP:80 root@serverIP -N

В данном примере, вы можете делать запросы на порт 9999, связанный с 80 портом машины anotherIP.

Доступ с сервера на локальный порт

Теперь представим ситуацию, что нужно с сервера обратиться к какому-нибудь сервису, запущенному на локальном компьютере. Например, вам регулярно присылают HTTP запросы по 80 порту на сервер. Вы можете прокинуть локальный веб-сервер со своей рабочей машины (скажем с 3000 порта) на сервер так, что запросы будут идти напрямую к вам. За это отвечает параметр -R.

ssh -R 80:localhost:3000 root@serverIP

После этой команды на сервере откроется 80 порт, запросы на который будут прокидываться вам на 3000.

По умолчанию 80 порт откроется на всех интерфейсах. Если вы желаете выбрать конкретный (скажем 192.168.0.1), его можно указать следующим образом

ssh -R 192.168.0.1:80:localhost:3000 root@serverIP

Цепочка туннелей через несколько узлов

Если нужно пробросить на свою машину локальный порт с сервера №2, доступ к которому по SSH есть только с сервера №1, можно построить цепочку из SSH туннелей

server1# ssh -L 9999:localhost:27017 root@server2 client# ssh -L 9999:localhost:9999 root@server1

Можно воспользоваться однострочной командой. 

ssh -L 9999:localhost:9999 root@server1 ssh -L 9999:localhost:27017 -N root@server2

А в случае, если у вас есть SSH ключи для доступа к серверу №2, вы можете построить защищенный туннель так, что ваш трафик не будет виден на сервере №1.

ssh -L 9998:server2:22 -N root@server1 ssh -L 9999:localhost:27017 -N -p 9998 root@localhost

В данном примере вы пробрасываете себе на порт 9998 порт с сервера №2, обращаясь к нему через сервер №1. А затем пробрасываете порт 27017 с сервера №2 на локальный 9999. В данной конфигурации вам уже не нужен сервер №1, так как порт SSH уже у вас на локальном 9998

SOCKS прокси

С помощью параметра -D можно создать на локальной машине сокет для прослушивания динамического порта.

ssh -D localhost:8123 root@serverIP

Теперь достаточно добавить хост localhost и порт 8123 в браузер для использования в качестве прокси.

Пример использования SOCKS5 прокси в Firefox

Заключение

Мы научились пробрасывать локальный порт на сервер и серверный порт на локальную машину с помощью SSH. И хотя это не слишком production ready решение, но на этапе разработки часто оказывается практичным и работает стабильно.