Когда полезен SSH туннель

20 июля 2025 г.

Чаще всего я использую SSH туннель для подключения к домашнему серверу без выделенного ip-адреса через интернет. Через такой же туннель я перенаправяю на него запросы с определенных доменов. И по той же методике я иногда расшариваю доступ через домен к порту на ноутбуке во время разработки.

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

Как работает SSH туннель

SSH туннель — это подключение одного комьютера к другому через SSH, которое позволяет перенаправлять трафик с одного порта на другой.

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

Для этого используется команда, которую можно запустить в терминале:

ssh -NT -R 0.0.0.0:10022:localhost:22 -p 22 root@44.55.66.44

Или такое же подключение, но без проверки отпечатков ключей. Актуально, если вы часто переустанавливаете систему и не хотите каждый раз очищать ключи в файле :

ssh -NT -o ServerAliveInterval=60 -o ExitOnForwardFailure=yes -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -R 0.0.0.0:10022:localhost:22 -p 22 root@44.55.66.44

Эти команды создают туннель, который перенаправляет все запросы к порту удаленного сервера на порт домашнего сервера. То есть, когда вы подключаетесь к , вы фактически подключаетесь к .

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

Создание системного сервиса

Создаем файл с содержимым.

[Unit]
Description=SSH Tunnel
After=network.target

[Service]
User=root
ExecStart=/usr/bin/ssh -NT -o ServerAliveInterval=60 -o ExitOnForwardFailure=yes -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -R 0.0.0.0:10022:localhost:22 -p 22 root@44.55.66.44
RestartSec=5
Restart=always

[Install]
WantedBy=multi-user.target

Порт и IP-адрес замените на ваши от VPS. Порт — это порт на домашнем сервере, который вы хотите расшарить.

Загрузите сервис в systemd и запустите его:

sudo systemctl daemon-reload
sudo systemctl start ssh-tunnel

И добавьте его в автозагрузку:

sudo systemctl enable ssh-tunnel

Подключение к туннелю

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

ssh -J root@44.55.66.44 -p 10022 root@localhost

Почему не просто ?

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

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

ssh -NT -R 0.0.0.0:10022:0.0.0.0:22 -p 22 root@44.55.66.44

Ansible файлы для настройки туннеля

  • ssh-tunnel
    • tasks
      • main.yml
    • templates
      • ssh-tunnel.service.j2

— файл с задачами Ansible для настройки SSH туннеля. Он создает системный сервис, который будет автоматически запускаться при загрузке системы.

- name: Create SSH "{{ tunnel_name }}" systemd service using template
  template:
    src: ssh-tunnel.service.j2
    dest: /etc/systemd/system/{{ tunnel_name }}.service

- name: Reload systemd daemon
  systemd:
    daemon_reload: yes

- name: Ensure SSH "{{ tunnel_name }}" systemd service is started and enabled
  systemd:
    name: '{{ tunnel_name }}'
    state: started
    enabled: yes

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

[Unit]
Description=SSH {{ tunnel_name }} to target server
After=network.target

[Service]
User=root
ExecStart=/usr/bin/ssh -NT -o ServerAliveInterval=60 -o ExitOnForwardFailure=yes -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -R 0.0.0.0:{{ remote_port }}:localhost:{{ host_port }} -p {{ vps_port }} root@{{ vps_ip }}
RestartSec=5
Restart=always

[Install]
WantedBy=multi-user.target

Теперь, чтобы настроить SSH туннель, достаточно указать роль с переменными в Ansible. Например, туннели для SSH и HTTP запросов:

- name: Configure SSH Tunnel
  import_role:
    name: ssh-tunnel
  vars:
    tunnel_name: ssh-tunnel
    host_port: 22
    remote_port: 10022
    # vps_ip: 44.55.66.44
    # vps_port: 22

- name: Configure Web Tunnel
  import_role:
    name: ssh-tunnel
  vars:
    tunnel_name: web-tunnel
    host_port: 80
    remote_port: 10080
    # vps_ip: 44.55.66.44
    # vps_port: 22

У меня параметры и прописаны в общих переменных инвентаря, чтобы не дублировать их в каждом плейбуке.

И останется только убедиться, что на сервере есть публичный ключ от машины, которая будет устанавливать туннель.

Показать заметки по похожей теме
Подпишитесь на мой Бусти, чтобы комментировать записи и получать уведомления о новых заметках.Подписаться на Бусти