Если вы видите что-то необычное, просто сообщите мне. Skip to main content

Проброс портов в туннеле ssh

Создаем постоянное подключение к удаленном серверу.

Требования: 

  1. Удаленный доступ должен иметь настроенный ssh сервер
  2. Локально должен быть доступен ключ id_rsa
  3. Публичная часть ключа должна быть на удаленном сервере

Настройки:

    Создаем файл /etc/systemd/system/SERVICENAME.service с содержанием вида

    [Unit]
    Description=SSH tunnel
    
    [Service]
    ExecStart=bash -c "ssh -i /PATH/TO/id_rsa -L 0.0.0.0:9999:localhost:8010 USER@REMOTE.HOST -N"
    Restart=on-failure
    EnvironmentFile=/etc/environment
    
    [Install]
    WantedBy=multi-user.target
    

    Мы говорим, что на хосте REMOTE.HOST по адресу localhost:8010 доступно приложение, и его мы мапируем на локальный компьютер на порт 9999. 

    Теперь удаленно приложение висящее на порту 8010, досупно локально, но на порту 9999. Любое подключение идущее на localhost:9999 компьютера на котором запускается сервис будет уходить на REMOTE.HOST через ssh тунель.

    0.0.0.0:9999 -  подключение будет доступно не только на localhost но и еще в локальной сети компьютера на котором запущен текущий сервис. 0.0.0.0 можно не писать.

      Запускаем/останалвливаем сервис:

      systemctl start/stop SERVICENAME.service
      

      start/stop - выберите что-то одно, или запускаем или останавливаем

      Если demon просит перезагрузить конфиги - перезагружаем

        Включаем сервис при загружке:

        systemctl enable SERVICENAME.service
        

          Проверяем состояние сервиса на наличие ошибок:

          systemctl status SERVICENAME.service
          

          или

          journalctl -u SERVICENAME
          

          Немного теории

          Описываю реальную ситуацию: есть удаленный сервер (назовем его remoteserver), на нем крутятся несколько контейнеров, один из них база данных (пусть будет docker_mysql_1). Разработчику (его комп пусть будет developer), находящемуся в одной локалке с девопсом (его хост - devops) понадобился доступ к порту mysql на том удаленном сервере. Из них двоих только у девопса есть доступ до сервера (remoteserver) - по ssh.

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

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

          Ответ - последняя команда этой страницы.

          Теперь по порядку: ssh может создавать туннели, пробрасывая внутренние порты сервера на машину, с которой была запущена команда.

          Например, следующая команда, если ее выполнит девопс, открыла бы на его машине (devops) порт 9999, который был бы связан с портом 3306 (mysql) на сервере remoteserver. Этот порт был бы доступен только ему, так как открылся бы на интерфейсе localhost.

          ssh -L 9999:localhost:3306 user@remoteserver
          

          Если для подключения используется нестандартный порт, то не нужно забывать это указывать:

          ssh -p 32323 -L 9999:localhost:3306 user@remoteserver
          

          Но мне кажется, что хорошей практикой было бы включить такие настройки в .ssh/config.

          Далее, если нам не нужен сам ssh-туннель, а только доступ к порту, то мы можем не запускать интерпретатор:

          ssh -p 32323 -L 9999:localhost:3306 user@remoteserver -N
          

          Тут мы вспомнили, что ломиться нужно не на localhost, а на определенный хост, доступный ему по сети (виртуальной или реальной - не важно). Смотрим ip-адрес нужного нам контейнера через 

          docker inspect docker_mysql_1
          

          и затем указываем полученный ip-адрес в команде.

          ssh -p 32323 -L 9999:172.31.0.2:3306 user@remoteserver -N
          

          Теперь у нас все получилось и девопс выполняя команду mysql -h localhost --port 9999 он попадает на порт mysql'а, который работает в контейнере docker_mysql_1, запущенном на remoteserver. 

          Осталось дать доступ разработчику. Следующая команда разрешает пользоваться данным портом через все интерфейсы, а значит он доступен не только девопсу, но и разрабу (команда уже будет mysql -h devops --port 9999):

          ssh -p 32323 -L 0.0.0.0:9999:172.31.0.2:3306 user@remoteserver -N