суббота, 14 мая 2011 г.

Переброс портов и интерфейса графических программ с помощью SSH

У вас есть учетная запись user1 на сервере example.net с IP-адресом 8.9.10.11, на котором запущен демон SSH. Вы находитесь в локальной сети, имеющей подключение к Интернету. Ваш IP-адрес в локальной сети 192.168.0.2. Все адреса взяты для примера, везде подставляйте свои значения.

Примеры задач, которые вам может понадобиться выполнить с использованием главного преимущества SSH - высокой степени защиты соединения:
  • (1) На вашем сервере установлен MySQL и соединения для пользователя root разрешены только с локальной машины (т.е. с самого сервера), вы же хотите подключиться к нему со своей домашней машины (к примеру, из MySQL Administrator или MySQL Workbench).
  • (2) В вашей локальной сети есть веб-сервис, недоступный извне, а вы хотите скачать с него файл прямо на сервер.
  • (3) Вы хотите запускать на сервере GUI-приложения (программы с графическим интерфейсом) таким образом, чтобы они отображались на вашем компьютере как обычные окна.
Сначала рассмотрим первые 2 случая, они предполагают переброс TCP-портов. Чтобы упростить понимание, немного поговорим о том, как происходят соединения TCP с точки зрения обывателя:
  1. Программа-сервер занимает определенный порт и ждет пока кто-нибудь подключится. Порт на этой машине считается занятым и другие программы уже не могут его использовать. В качестве аналогии, представьте себе розетку на стене, в которую, тем не менее, можно подключать очень много вилок.
  2. Программа-клиент соединяется с программой-сервером путем подключения к определенному адресу и порту в сети. Программа-клиент как раз втыкает свою вилку в розетку программы-сервера.
В данном случае переброс портов работает как "удлинитель", позволяя переносить розетку со стены, скажем, в другую комнату.

Теперь перейдем к практике. На практике нужно знать, что создавать "розетки" с номером порта 1024 и меньше (в том числе с помощью "удлинителя") могут только привилегированные пользователи. На "вилки" это ограничение не распространяется. И второй нюанс: "вилка удлинителя" включается в "розетку" программы-сервера только в тот момент, когда в "розетку удлинителя" включается "вилка" программы-клиента (это несколько отличается от работы обычного удлинителя). Короче говоря, вся цепочка соединений полностью создается только при появлении клиента. На самом деле, для вас это не будет иметь особой разницы в большинстве случаев, поэтому не забивайте голову.

Разберем задачу (1) в наших терминах:
  • На сервере example.net есть "розетка" на стандартном для MySQL порту 3306, причем доступна она только с самого сервера, т.е. висит на его адресе 127.0.0.1.
  • Нужно провести "удлинитель" к нам на домашний компьютер, опять же, сделав "розетку удлинителя" доступной только с локальной машины.
Для этого мы подключаемся к серверу по SSH используя следующую команду:
$ ssh user1@example.net -L localhost:3307:127.0.0.1:3306
Опция -L означает, что мы создаем локальную "розетку" с помощью "удлинителя" (L = local). Таких параметров вы можете указать несколько, таким образом проложив сразу несколько "удлинителей". Разбираем параметры:
  • localhost - IP-адрес или имя машины, где будет создана "розетка удлинителя". Здесь мы ограничиваем "розетку" подключениями только с локального компьютера. Для доступа к "розетке" со всей локальной сети можно указать здесь 192.168.0.2 (адрес для примера, см. начало статьи). Этот параметр можно не указывать (опустив и двоеточие после него, сразу начав с порта), по-умолчанию и так используется localhost. Для использования других значений придется править настройки SSH на сервере (параметр GatewayPorts, подробности в документации на sshd).
  • 3307 - номер порта, по которому будет создана "розетка удлинителя". Можно использовать здесь и стандартный порт MySQL 3306, но это вызовет проблемы, если у вас запущен и локальный MySQL.
  • 127.0.0.1 - IP-адрес или имя машины, куда будет подключаться "вилка удлинителя". Чтобы для сервера подключения казались локальными, используем 127.0.0.1, или localhost. Опять же, ничто не мешает указать произвольный адрес в сети интернет, в таком случае соединение будет установлено с указанным адресом. Может быть полезно, если нужно исключить прослушку в локальной сети, хотя есть более адекватные способы это сделать.
  • 3306 - номер порта, к которому будет подключена "вилка удлиннителя", здесь указан стандартный порт MySQL.
Пока будет установлено SSH-соединение, мы можем в локальных программах указывать сервер - localhost, порт - 3307 и таким образом соединяться с MySQL на сервере. "Розетка" на локальном компьютере, соединение пойдет через "удлинитель" и попадет в "розетку" на сервере.

Задача (2) является обратной:
  • На машине в локальной сети (для примера возьмем адрес 192.168.0.100) есть "розетка" с номером порта 80 (стандартный порт HTTP), доступная только для данной локальной сети.
  • Нужно провести "удлинитель" так, чтобы "розетка" оказалась на нашем сервере, а соединение происходило с "розеткой" на машине в локальной сети.
Чтобы ее решить, нужно подключиться по SSH со следующими параметрами:
$ ssh user1@example.net -R localhost:8080:192.168.0.100:80
Здесь опция -R означает, что мы создаем "розетку удлиннителя" на удаленном сервере (R = remote). Опять же, ничего не мешает указывать несколько таких опций и комбинировать их с опциями -L. Параметры:
  • localhost - IP или имя удаленной машины, на которой будет создана "розетка удлинителя". Можно не указывать (опустив двоеточие, начав сразу с порта), по-умолчанию и так localhost.
  • 8080 - номер порта для "розетки удлинителя". Повторюсь, порты до 1024 включительно могут использовать только привилегированные пользователи.
  • 192.168.0.100 - IP или имя машины на локальной стороне, в "розетку" которой мы подключим наш "удлинитель"
  • 80 - порт машины на локальной стороне, куда будет подключена "вилка удлинителя"
Пока будет установлено такое соединение, из консоли сервера мы сможем скачать какой-нибудь файл с веб-сервиса в локальной сети:
$ wget http://localhost:8080/some/path/file.zip
В самом простом случае всё заработает и так, в более сложном - вам придется на сервере дописать соответствие адреса веб-сервиса вашему локальному в файл /etc/hosts, но это оставим за пределами данной статьи.

Запоминать команды для переброса портов довольно просто:
  • Параметр (-L или -R) - это место создания "розетки удлинителя":
    L = local = "розетка" на стороне клиента
    R = remote = "розетка" на стороне сервера
  • Первая часть аргумента задает адрес и порт "розетки удлинителя", т.е. той "розетки", которую вы сами создаете с помощью SSH
  • Вторая часть аргумента - адрес и порт "розетки", куда будет подключена "вилка удлинителя", т.е. уже существующей "розетки"
Задача (3) решается уже не перебросом портов, а перебросом соединений с X-сервером. Неприятное предварительное условие - в настройках SSH-сервера должна быть включена опция X11Forwarding (должна иметь значение yes, по-умолчанию no). Далее вы просто соединяетесь с сервером следующей командой (буква X заглавная, это важно):
$ ssh user1@example.net -X
После этого, запуская графические приложения из данной консоли, вы увидите их на своем экране как обычные окна, но работать они будут на удаленном сервере.

На этом всё. Безопасных вам соединений.

6 комментариев:

Анонимный комментирует...

ужасное, путанное изложение. У новичка вызовет приступ паники

Dmitriy.Trt комментирует...

@Анонимный: новичкам обычно и не нужно порты перебрасывать, им и так хорошо

Анонимный комментирует...

А Ви таки на профессионалов ориентируетесь в своем опусе?

Dmitriy.Trt комментирует...

@Анонимный: написано в качестве напоминалки для себя, чтобы в манах SSH не копаться каждый раз.

virens комментирует...

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

Было бы интересно почитать про проброс портов через прокси. Автор не планирует случаем?

Ежели автор поставит на страничке виджет "сообщества Google" (это где можно нажать Follow и rss-фид будет сразу добавлен в гуглридер), обещаю таки подписаться :-)

Dmitriy.Trt комментирует...

@virens: Добавил виджет. Статью перетрясти возникли мысли еще после комментариев Анонимного, теперь точно наведу тут порядок. Картинок добавлю, тогда аналогия с розетками и удлинителями станет наглядной. Но вот когда это случится - понятия не имею.