Top.Mail.Ru
OSEN-НИЙ SAAALEСкидка 50% на виртуальный хостинг и VDS
до 30.11.2025 Подробнее
Выберите продукт

SSH-туннели в Linux: local, remote и SOCKS на практике

Что такое SSH-туннели и как ими пользоваться: делаем local/remote/SOCKS-пробросы, работаем через бастион, проверяем фаервол и настраиваем автоподнятие. Внутри — безопасные примеры, диагностика и подсказки для продакшна.
SSH-туннели в Linux: local, remote и SOCKS на практике

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

  • LocalForward (-L): локальный порт → удалённая цель.
  • RemoteForward (-R): удалённый порт на сервере → локальная цель.
  • DynamicForward (-D): локальный SOCKS5-прокси, через который приложения выходят в сеть «через сервер».

Это не VPN: туннели точечные (порт/сервис), а не полноценный сетевой интерфейс.

Когда туннели реально нужны

  • Доступ к БД/админке, доступной только из внутренней сети (-L).
  • Показ локального dev-сервиса внешнему миру на короткое время (-R).
  • «Выйти в интернет как с сервера» для отладки/geo-кейсов (-D).
  • Обход NAT/CGNAT, работа через бастион, «не тянуть VPN ради одного порта».

Если SSH ещё не настроен — начните с базовой статьи: SSH в Linux.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Local port forward (-L): доступ к внутреннему ресурсу

Подключаемся к серверу, у себя получаем локальный порт, который «ходит» к внутреннему сервису через SSH.

Пример без бастиона:

ssh -L [LOCAL_ADDR:]LPORT:TARGET_HOST:TPORT user@SSH_HOST
# часто — так:
ssh -L 127.0.0.1:5432:db.internal:5432 user@bastion

Пояснения:

  • 127.0.0.1 — безопасный адрес привязки (binding-адрес), чтобы никто извне не подключился к туннелю.
  • TARGET_HOST:TPORT — реальная внутренняя цель, видимая с точки зрения SSH_HOST (например, db.internal:5432).
  • Добавьте -N (не запускать шелл) и -f (в фон):
    ssh -N -f -L 127.0.0.1:5432:db.internal:5432 user@bastion

Проверка:

psql -h 127.0.0.1 -p 5432 -U app dbname   # пример для PostgreSQL
# или
curl -v http://127.0.0.1:8080/health

Через бастион (-J):

ssh -J user@bastion user@internal -L 127.0.0.1:5432:db.internal:5432 -N -f

Чтобы не печатать длинные команды и управлять туннелем коротким алиасом, вынесите параметры в профиль ~/.ssh/config. Тогда туннель поднимается командой ssh -N -f bastion и закрывается ssh -O exit bastion.

Host bastion
  HostName bastion.example.com
  User user
  ServerAliveInterval 30
  ServerAliveCountMax 3
  ControlMaster auto
  ControlPersist 4h
  ExitOnForwardFailure yes
  LocalForward 127.0.0.1:5432 db.internal:5432

Что дальше: см. рецепты PostgreSQL через бастион и VNC через SSH (для RDP меняем порт на 3389).

Remote port forward (-R): показать локальный сервис наружу

Вы за NAT/фаерволом, но хотите временно показать свой локальный порт (например, dev-сайт на localhost:3000) через удалённый сервер (VPS).

Синтаксис (клиент):

ssh -R [RADDR:]RPORT:LOCAL_HOST:LPORT user@VPS
# пример: публикуем локальный 3000 на VPS:8080
ssh -R 127.0.0.1:8080:127.0.0.1:3000 user@vps.example.com

Важные детали.

  • По умолчанию (на большинстве конфигов) -R слушает только на loopback сервера.
  • Чтобы открыть порт на внешнем интерфейсе VPS, нужна серверная опция GatewayPorts:
    GatewayPorts clientspecified — доверять адресу из клиента (0.0.0.0 / ::).
    Или GatewayPorts yes — слушать на всех адресах.
  • Разрешите форвардинг на сервере: AllowTcpForwarding yes (или remote).

Пример: публичный 8080 на VPS

1. На VPS: проверьте sshd_config:

AllowTcpForwarding remote
GatewayPorts clientspecified

Примените: sudo sshd -t && sudo systemctl reload sshd

2. На клиенте:

ssh -R 0.0.0.0:8080:127.0.0.1:3000 user@vps.example.com -N -f

3. Откройте фаервол на VPS (если нужно):

# Debian-based (UFW):

sudo ufw allow 8080/tcp && sudo ufw reload


# RHEL-based (firewalld):

sudo firewall-cmd --permanent --add-port=8080/tcp
sudo firewall-cmd --reload


# Arch: UFW или firewalld — по аналогии.

Проверяйте доступ извне (например, нашим онлайн-сканером портов или curl http://VPS:8080 с внешнего хоста).

Безопасность: если публикуете наружу, используйте временные учётки, ограничение Match User и по возможности оставляйте RADDR = 127.0.0.1 + делайте доступ через реверс-прокси/VPN. Публичный 0.0.0.0 нужен только осознанно и ненадолго.

Что дальше: см. рецепт Показ локального dev на VPS (-R).

Dynamic SOCKS (-D): гибкий прокси через SSH

Поднимаем локальный SOCKS5-порт, через который приложения выходят «как с сервера».

Команда:

ssh -D 1080 -N user@server

Проверка в CLI:

curl --socks5-hostname 127.0.0.1:1080 https://ifconfig.me

Браузер/приложения. Укажите SOCKS-прокси 127.0.0.1:1080. Используйте режим socks5-hostname, чтобы DNS-запросы шли через прокси, а не локально. Помните, что не все программы умеют SOCKS.

Что дальше: см. рецепт SOCKS/прокси через SSH.

Через бастион и мульти-хопы

Совмещайте -L/-R/-D с бастионом:

# local forward через бастион
ssh -J user@bastion user@internal -L 127.0.0.1:5432:db.internal:5432 -N -f
# SOCKS через бастион
ssh -J user@bastion -D 1080 -N user@internal

Альтернатива старой школы — ProxyCommand -W %h:%p, но -J проще.

Полезные опции клиента и конфиг

В ~/.ssh/config удобно держать всё, что нужно ежедневно:

Host vps
  HostName vps.example.com
  User user
  ServerAliveInterval 30
  ServerAliveCountMax 3
  ExitOnForwardFailure yes
  ControlMaster auto
  ControlPersist 4h
  # Примеры пробросов:
  # LocalForward 127.0.0.1:5432 db.internal:5432
  # RemoteForward 127.0.0.1:8080 127.0.0.1:3000
  # DynamicForward 1080
  • ExitOnForwardFailure yes — упасть, если форвард не встал.
  • ServerAlive* — держать соединение живым; помогает autossh/systemd.
  • ControlMaster/ControlPersist — мультиплексирование, меньше RTT при множестве команд.

Политика безопасности на сервере (sshd_config)

Ограничивайте возможности туннелей на стороне сервера — глобально или выборочно (через Match):

# Разрешить только нужное
AllowTcpForwarding local|remote|yes|no
# Управлять доступностью удалённых адресов/портов (для -L и, в новых версиях, -R)
# PermitOpen host:port
# (в свежих OpenSSH также есть PermitListen для -R — проверьте `sshd -T`)

# Публикация удалённого порта наружу
GatewayPorts no|clientspecified|yes

# Блокируем лишнее
X11Forwarding no
AllowAgentForwarding no

# Ограничения по пользователям/группам
Match User dev
    AllowTcpForwarding remote
    PermitOpen 127.0.0.1:3000

Перед применением — sudo sshd -t. Если директивы не поддерживаются вашей версией OpenSSH, они засветятся ошибкой; посмотрите, что реально активно: sudo sshd -T | grep -i forward.

Диагностика и типичные ошибки

  • channel 0: open failed: administratively prohibited — сервер запрещает форвардинг (AllowTcpForwarding no) или не разрешён нужный хост/порт (PermitOpen).
  • bind: Address already in use — порт уже занят (проверьте ss -lntp).
  • connect to 127.0.0.1 port N: Connection refused — целевой сервис не слушает или неверная цель (TARGET_HOST:TPORT).
  • Broken pipe / обрывы — добавьте ServerAliveInterval/CountMax, посмотрите сеть/фаервол.
  • Снаружи «не видно» при -R — откройте порт на VPS-фаерволе; при необходимости используйте наш онлайн-сканер портов.
  • Смотрите логи:
ssh -vvv user@host                  # подробности с клиента
sudo journalctl -u sshd -b          # серверные логи
ss -lntp; lsof -i -nP               # кто слушает/куда подключаемся

Автоподнятие и восстановление туннеля

Вариант A — autossh (просто и надёжно):

# Local forward
autossh -M 0 -N -f -L 127.0.0.1:5432:db.internal:5432 user@bastion \
  -o ServerAliveInterval=30 -o ServerAliveCountMax=3 -o ExitOnForwardFailure=yes

# Remote forward
autossh -M 0 -N -f -R 0.0.0.0:8080:127.0.0.1:3000 user@vps \
  -o ServerAliveInterval=30 -o ServerAliveCountMax=3 -o ExitOnForwardFailure=yes

Вариант B — systemd-юнит (без autossh): /etc/systemd/system/ssh-tunnel.service

[Unit]
Description=Persistent SSH tunnel (-R 8080 -> localhost:3000)
After=network-online.target
Wants=network-online.target

[Service]
User=tunnel               # выделенный пользователь
ExecStart=/usr/bin/ssh -N -o ServerAliveInterval=30 -o ServerAliveCountMax=3 \
  -o ExitOnForwardFailure=yes -R 0.0.0.0:8080:127.0.0.1:3000 user@vps.example.com
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now ssh-tunnel

Рекомендуется выделить отдельного пользователя/ключ, ограничить права Match-блоком и PermitOpen/GatewayPorts.

Unix-сокеты и нестандартные кейсы

SSH поддерживает проброс UNIX-сокетов (StreamLocalForward):

# Локально создаём сокет .pg.sock, который идёт к /var/run/postgresql/.s.PGSQL.5432 на сервере
ssh -L ~/pg.sock:/var/run/postgresql/.s.PGSQL.5432 user@db-host -N

Следите за правами на сокеты и учитывайте, что некоторые менеджеры (Docker) не любят такой проброс в проде.

Готовые рецепты (скопируй и пользуйся)

VNC через SSH

Задача A. Подключиться к удалённому VNC-серверу, не открывая 5900 наружу

1. Убедитесь, что на удалённой машине VNC действительно слушает (часто только на loopback):

# на удалённом хосте
ss -lntp | grep 59
# примеры запуска:
tigervncserver :1 -localhost yes       # порт 5901
# или для :0 будет 5900

2. Поднимите локальный туннель SSH (без шелла):

ssh -N -f -L 5901:127.0.0.1:5901 user@REMOTE

3. Откройте свой VNC-клиент и подключитесь к localhost:5901

  • macOS: open vnc://localhost:5901
  • Linux: vncviewer localhost:5901 (TigerVNC / Remmina и т. п.)
  • Windows (PuTTY): Connection → SSH → Tunnels → Source port: 5901, Destination: 127.0.0.1:5901 → Add → Open; затем в VNC-клиенте — localhost:5901.

Почему безопасно: VNC по умолчанию не шифрует трафик; -L шифрует соединение и держит сам VNC слушающим только на 127.0.0.1.

Задача B. Показать локальный VNC наружу через свой VPS (редко, осознанно)

1. На VPS в sshd_config разрешите публикацию порта:

AllowTcpForwarding remote
GatewayPorts clientspecified
sudo sshd -t && sudo systemctl reload sshd

2. На своей машине поднимите обратный туннель:

ssh -N -f -R 0.0.0.0:5901:127.0.0.1:5901 user@VPS

Теперь к вашему локальному VNC можно подключаться на VPS:5901 (лучше ограничить IP на уровне фаервола VPS).

Этот вариант потенциально опаснее: включайте его временно, с ограничениями (firewalld/UFW, Match User, возможен реверс-прокси с ACL).

Полезно знать

  • Порты VNC: :0 → 5900, :1 → 5901, :2 → 5902 ...
  • Завершить туннель: если используете ControlMaster-профиль — ssh -O exit <alias>; иначе pkill -f 'ssh -N -f -L 5901'.
# Примечание про RDP (Windows):
# тот же приём -L, только порт 3389
ssh -N -f -L 127.0.0.1:3389:WIN_HOST:3389 user@bastion
# через ProxyJump:
ssh -J user@bastion user@internal -N -f -L 127.0.0.1:3389:WIN_HOST:3389
# затем подключайтесь RDP-клиентом к localhost:3389 (MSTSC/Remmina/MRD)

PostgreSQL через бастион (-L + -J)

Задача. Получить доступ к БД db.internal:5432, которая видна только из внутренней сети сервера.

1. Проверка с бастиона (доступ к цели):

# на бастионе
nc -vz db.internal 5432 || ss -n 'dport = :5432'   # есть ли коннект
# (если есть psql)
psql -h db.internal -p 5432 -U app -c 'select 1;' || true

2. Поднять туннель с ноутбука:

ssh -J user@bastion.example.com user@internal.example.com \
  -N -f -o ExitOnForwardFailure=yes \
  -L 127.0.0.1:5432:db.internal:5432

3. Подключиться локально:

psql -h 127.0.0.1 -p 5432 -U app dbname

Зачем 127.0.0.1? Чтобы локальный порт был доступен только вам.
IPv6: цель можно писать в скобках: -L 127.0.0.1:5432:[2001:db8::10]:5432.

Удобно вынести в ~/.ssh/config:

Host db-tunnel
  HostName bastion.example.com
  User user
  ProxyJump user@bastion.example.com
  ExitOnForwardFailure yes
  ServerAliveInterval 30
  ServerAliveCountMax 3
  LocalForward 127.0.0.1:5432 db.internal:5432

Зачем это нужно: чтобы не печатать длинные команды. С профилем достаточно ssh -N -f db-tunnel (поднять) и ssh -O exit db-tunnel (закрыть).


Показ локального dev на VPS (-R):

Задача. Вы за NAT, хотите показать http://localhost:3000 наружу как http://VPS:8080.

1. На VPS в /etc/ssh/sshd_config:

AllowTcpForwarding remote
GatewayPorts clientspecified   # или yes (шире)

Применить:

sudo sshd -t && sudo systemctl reload sshd

2. С ноутбука поднять обратный туннель:

ssh -N -f -o ExitOnForwardFailure=yes \
  -R 0.0.0.0:8080:127.0.0.1:3000 user@vps.example.com

3. Открыть фаервол на VPS:

# UFW (Debian/Ubuntu):

sudo ufw allow 8080/tcp && sudo ufw reload

# firewalld (RHEL/Alma/Rocky/Fedora):

sudo firewall-cmd --permanent --add-port=8080/tcp
sudo firewall-cmd --reload

4. Проверка снаружи:

curl -I http://vps.example.com:8080/

Безопаснее вариант. Слушать только на loopback VPS:

ssh -N -f -R 127.0.0.1:8080:127.0.0.1:3000 user@vps

И отдать наружу через Nginx (ACL/базовая auth/HTTPS).
Ограничения: сделайте отдельного юзера и Match-политику:

Match User devpub
    AllowTcpForwarding remote
    PermitOpen 127.0.0.1:3000

Локальный браузер «через сервер» (-D SOCKS)

Задача. Отправлять трафик приложений через сервер (гео/отладка).

1. Поднять SOCKS-прокси:

ssh -D 1080 -N -f user@server.example.com

2. Проверка DNS и выхода:

curl --socks5-hostname 127.0.0.1:1080 https://ifconfig.me

Используйте именно --socks5-hostname, чтобы DNS-запросы шли через прокси.

3. Браузер: укажите SOCKS5 127.0.0.1:1080.
CLI: можно выставить переменные:

export ALL_PROXY=socks5h://127.0.0.1:1080
export NO_PROXY=localhost,127.0.0.1

Через бастион:

ssh -J user@bastion user@internal -D 1080 -N -f

Закрыть:

pkill -f 'ssh -D 1080'
# или, если запускали алиасом:
ssh -O exit socks-tunnel

Чек-лист перед продакшеном

  • Вход по ключам + (по ситуации) 2FA включены.
  • Фаервол/ACL согласованы (нужные порты на нужных узлах).
  • В sshd_config настроены AllowTcpForwarding, GatewayPorts, PermitOpen/PermitListen (если поддерживается).
  • Туннель стартует с ExitOnForwardFailure, живёт с ServerAlive*.
  • Логи на контроле, алиасы в ~/.ssh/config работают.
FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Заключение

Мы разобрали, как использовать SSH для создания защищённых туннелей — локальных, обратных и динамического SOCKS — и как настраивать их безопасно и стабильно. Надеемся, материал поможет организовать надёжную связь в Интернете.

Поделиться статьей

Вам будет интересно

Настройка двухфакторной аутентификации (2FA) для SSH в Linux

Настройка двухфакторной аутентификации (2FA) для SSH в Linux

Добавляем 2FA в SSH: к ключу или паролю требуем одноразовый код (TOTP) через PAM. Пошаговые команды для Debian-based, RHEL-based и ...
SSH в Linux: установка, подключение, ключи и безопасная настройка

SSH в Linux: установка, подключение, ключи и безопасная настройка

SSH в Linux на практике: ставим и запускаем, подключаемся, включаем ключевую аутентификацию и приводим sshd_config к безопасной ба ...
Порты в Linux: как проверить, открыть и закрыть (UFW, firewalld, nftables)

Порты в Linux: как проверить, открыть и закрыть (UFW, firewalld, nftables)

Пошаговый разбор портов в Linux: как увидеть, кто и где слушает, проверить доступ из сети и корректно открыть/закрыть через UFW, f ...