Новинка Виртуальный VDS сервер в Нидерландах от 390р
Выберите продукт

SSH Port Forwarding: Local, Remote и Dynamic (SOCKS) туннели на практике

Разбираем SSH port forwarding на практических кейсах: local forward для доступа к приватным сервисам, remote forward для входящих соединений через сервер и dynamic SOCKS как универсальный прокси. Плюс ProxyCommand/ProxyJump, GatewayPorts, PermitOpen и базовые меры контроля на sshd.
SSH Port Forwarding: Local, Remote и Dynamic (SOCKS) туннели на практике

Зачем вообще нужен SSH port forwarding

SSH часто воспринимают как «зайти на сервер по SSH». Но для админов и девопсов куда полезнее другая часть протокола: туннелирование (port forwarding). Оно позволяет безопасно протащить TCP-трафик через SSH-сессию, даже если прямой доступ к сервису закрыт фаерволом, NAT или сетевой политикой.

Терминология обычно путает, потому что «локальный/удалённый/динамический» описывает не то, где запущен SSH, а то, где создаётся порт, в который вы подключаетесь. Разберём три режима:

  • Local forward (локальная переадресация, -L) — порт открывается на вашей машине.
  • Remote forward (удалённая переадресация, -R) — порт открывается на удалённом SSH-сервере.
  • Dynamic SOCKS (-D) — на вашей машине поднимается SOCKS-прокси, а SSH сам устанавливает соединения к целям.

Шпаргалка по синтаксису

Минимальные формы команд (ниже будет практика и типовые ошибки):

ssh -L [bind_addr:]LPORT:DEST_HOST:DEST_PORT user@ssh_host
ssh -R [bind_addr:]RPORT:DEST_HOST:DEST_PORT user@ssh_host
ssh -D [bind_addr:]DPORT user@ssh_host

Что означают параметры:

  • LPORT, RPORT, DPORT — локальный/удалённый/локальный(SOCKS) порт, который будет «слушать».
  • DEST_HOST:DEST_PORT — куда SSH подключится с той стороны туннеля (на стороне сервера при -L, на стороне клиента при -R).
  • bind_addr — адрес привязки слушающего порта (например, 127.0.0.1 или 0.0.0.0).

Важно: OpenSSH port forwarding по умолчанию переносит TCP. UDP напрямую не поддерживается — это отдельная тема с другими инструментами и компромиссами.

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

Local forward (-L): доступ к приватным сервисам «как будто они локальные»

Local forward — самый частый сценарий: сервис доступен только изнутри сервера (или вообще только на 127.0.0.1), а вам нужно подключиться со своей машины. Мы открываем порт на локальной машине и «прокидываем» его к нужному сервису через SSH.

Пример: подключиться к PostgreSQL/MySQL, которые слушают только localhost

Допустим, на сервере база слушает 127.0.0.1:5432 (PostgreSQL), а SSH доступен извне. Поднимаем локальный порт 15432:

ssh -L 15432:127.0.0.1:5432 user@server

Теперь на вашей машине можно подключаться к 127.0.0.1:15432, а трафик уйдёт на server и попадёт в PostgreSQL на 127.0.0.1:5432.

Чтобы SSH не открывал интерактивную оболочку (только туннель), используйте -N. Чтобы отправить процесс в фон — -f (обычно вместе):

ssh -N -f -L 15432:127.0.0.1:5432 user@server

Пример: доступ к админке/внутреннему HTTP-сервису

Частый кейс: внутренняя панель мониторинга/админка доступна только на 127.0.0.1:3000 сервера. Поднимаем локальный порт:

ssh -N -L 13000:127.0.0.1:3000 user@server

Дальше вы открываете сервис на локальном 127.0.0.1:13000 и работаете с ним как с «локальным», не публикуя его наружу.

Типичные ошибки и полезные флаги

  • Порт занят локально — выберите другой LPORT.
  • Туннель поднят, но соединения нет — проверьте, куда SSH должен подключаться на стороне сервера: часто это 127.0.0.1, а не внешний IP.
  • Нужна диагностика — добавьте -v, -vv или -vvv.
  • Не хотите слушать на всех интерфейсах — явно привяжитесь к 127.0.0.1:
ssh -N -L 127.0.0.1:13000:127.0.0.1:3000 user@server

Когда туннели используются регулярно, удобно хранить их в ~/.ssh/config, а не в истории терминала: меньше ошибок, проще масштабировать, легче ревьюить доступы.

Схема: как работает локальный (-L) и удалённый (-R) SSH port forwarding

Remote forward (-R): «вход» к вам через сервер (обход NAT)

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

Пример: временно отдать доступ к локальному веб-сервису

Допустим, на вашем ноутбуке поднят сервис на 127.0.0.1:8080, а у вас есть сервер server с публичным IP. Команда:

ssh -N -R 18080:127.0.0.1:8080 user@server

На server появится слушающий порт 127.0.0.1:18080 (по умолчанию именно localhost). Любой запрос, пришедший на этот порт на сервере, пойдёт по SSH обратно на ваш 127.0.0.1:8080.

FastFox VDS
Облачный VDS-сервер
Виртуальные серверы с быстрым запуском и гибкой конфигурацией от 390₽ / мес
Доступные локации
Россия Нидерланды

GatewayPorts: когда удалённый порт должен слушать не только localhost

Частый вопрос: «Я сделал -R, но снаружи к порту не подключиться». По умолчанию это нормально: OpenSSH привязывает удалённый порт к 127.0.0.1. Чтобы порт стал доступен извне, есть два механизма — оба требуют осознанности, потому что это фактическая публикация порта.

  1. Явно указать адрес привязки в -R:
ssh -N -R 0.0.0.0:18080:127.0.0.1:8080 user@server
  1. Разрешить это на SSH-сервере настройкой GatewayPorts в sshd_config.

Режимы GatewayPorts (как обычно, «по умолчанию безопаснее»):

  • GatewayPorts no — удалённые форварды только на localhost.
  • GatewayPorts yes — клиент может открывать порт на всех интерфейсах.
  • GatewayPorts clientspecified — сервер уважает bind_addr, который вы указали в -R.

Если нет чёткого сценария «публикуем порт наружу», держите GatewayPorts в режиме no или clientspecified и всегда задавайте bind_addr явно.

PermitOpen: ограничить, куда вообще можно форвардить

Если вы даёте SSH-доступ коллегам/подрядчикам и хотите контролировать направления туннелей, используйте ограничения на стороне сервера. В OpenSSH есть параметр PermitOpen: он задаёт allowlist «куда разрешено подключаться через форвардинг».

Практическая логика такая: даже если пользователь попробует сделать форвард на произвольный хост/порт, сервер запретит неразрешённые направления. Это особенно важно для bastion-хостов, где один лишний туннель может превратить «точку входа» в обход всей сетевой сегментации.

Dynamic SOCKS (-D): универсальный туннель для множества хостов

Dynamic SOCKS — это локальный SOCKS-прокси поверх SSH. В отличие от -L, где вы заранее фиксируете DEST_HOST:DEST_PORT, режим -D позволяет клиентам выбирать адрес назначения на лету.

Запуск SOCKS-прокси через SSH

ssh -N -D 127.0.0.1:1080 user@server

Дальше приложения, которые умеют SOCKS5, можно настроить на 127.0.0.1:1080.

SOCKS5 и DNS: чтобы резолв имён тоже шёл через туннель

Тонкость: некоторые клиенты при SOCKS-прокси продолжают резолвить DNS локально, а не «на той стороне». В сетях с ограничениями это либо ломает доступ к внутренним доменам, либо создаёт лишние утечки.

Ищите в настройках клиента режим «proxy DNS» / «remote DNS» / «SOCKS5 hostname». Принцип один: передавать доменное имя через SOCKS, чтобы резолв происходил там, где у вас есть доступ. Если вы часто отлаживаете DNS-поведение и политики резолвинга, пригодится материал про split-horizon DNS (views) в BIND.

Запуск dynamic SOCKS (-D) через SSH и использование прокси в приложениях

ProxyCommand и ProxyJump: доступ через бастион и цепочки

ProxyCommand — механизм OpenSSH, который определяет, как устанавливать TCP-соединение до конечного SSH-сервера. Самый частый кейс — доступ к внутренним хостам через bastion/jump host (когда внутренний сервер недоступен напрямую).

Сегодня чаще используют ProxyJump (ключ -J), но ProxyCommand всё ещё часто встречается в старых конфигурациях, CI-скриптах и inventory-файлах.

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

Пример записи в ~/.ssh/config:

Host internal-app
  HostName 10.10.0.10
  User deploy
  ProxyCommand ssh -W %h:%p bastion

Смысл: вы подключаетесь к internal-app, но фактически SSH сначала идёт на bastion, а дальше пробрасывает TCP до 10.10.0.10:22 через ssh -W.

Совмещение bastion-доступа и port forwarding

Самое полезное начинается, когда вы совмещаете bastion и туннели. Например, база доступна только во внутренней сети, SSH к внутреннему хосту — только из bastion, а вам нужен -L на ноутбук. Подход такой: сначала добейтесь стабильного ssh internal-app, и только потом добавляйте -L (или -D). Так проще локализовать проблему.

Безопасность: как не превратить туннели в «универсальный обход»

SSH port forwarding — мощный инструмент, но в среде с несколькими пользователями он может стать дырой в политике доступа, если оставить всё «как есть». На стороне sshd обычно контролируют три вещи: можно ли форвардить вообще, куда можно форвардить и не публикуются ли порты наружу.

AllowTcpForwarding: кто вообще может форвардить

Базовая настройка — разрешён ли TCP forwarding. Обычно это параметр AllowTcpForwarding. Его можно задавать глобально и в секциях Match (например, по пользователю/группе). Для сервисных учёток часто разумно отключать форвардинг, если он не нужен.

PermitOpen: allowlist направлений

PermitOpen помогает ограничить destination-направления. Это особенно актуально для bastion-хостов: вы можете разрешить туннели только к нескольким административным сервисам, а не ко всей сети.

GatewayPorts: не публикуйте лишнее

GatewayPorts влияет на то, будет ли remote forward доступен извне. Если у вас нет чёткого сценария публикации порта наружу, избегайте GatewayPorts yes.

Логи и наблюдаемость

Если бастион — контролируемая точка входа, важно видеть попытки и факты форвардинга. В зависимости от настроек логирования sshd можно получить записи о запросах на открытие каналов. Это полезно для расследований «почему сервис стал доступен» и «кто прокидывал туннели».

FastFox SSL
Надежные SSL-сертификаты
Мы предлагаем широкий спектр SSL-сертификатов от GlobalSign по самым низким ценам. Поможем с покупкой и установкой SSL бесплатно!

Практические рецепты

1) Открыть туннель и не держать лишнюю сессию

ssh -N -f -L 127.0.0.1:18000:127.0.0.1:8000 user@server

2) Поднять SOCKS как универсальный выход «в сеть сервера»

ssh -N -D 127.0.0.1:1080 user@server

3) Remote forward для доступа к вашему локальному сервису через сервер

ssh -N -R 127.0.0.1:19000:127.0.0.1:9000 user@server

Этот вариант безопаснее, потому что порт слушает только localhost на сервере. Дальше вы решаете, кто на сервере может к нему подключаться (локально, через другой туннель, через reverse proxy и т.д.).

4) Проверить, куда реально «слушает» порт

На локальной машине:

ss -lntp

На сервере (для remote forward):

ss -lntp

Как выбирать режим: краткая логика

  • Нужно с ноутбука попасть в приватный сервис на сервере или в его сети — используйте local forward (-L).
  • Нужно, чтобы кто-то на сервере мог подключаться к сервису у вас за NAT — используйте remote forward (-R) и аккуратно настройте GatewayPorts.
  • Нужно много направлений через один туннель (браузер/CLI) — используйте dynamic SOCKS (-D).
  • Есть bastion и внутренние хосты — добавляйте ProxyCommand или -J, а уже поверх делайте -L/-R/-D.

Итог

SSH port forwarding — «швейцарский нож» для админа: доступ к закрытым панелям, базам и внутренним API без публикации сервисов наружу, плюс удобные маршруты через bastion. Держите в голове два вопроса: где именно открывается порт (local/remote), и что разрешено политиками на sshd (AllowTcpForwarding, PermitOpen, GatewayPorts). Тогда туннели останутся управляемым инструментом, а не обходом инфраструктурных ограничений.

Если захотите продолжение, логичное углубление — «боевой» ~/.ssh/config: мультиплексирование ControlMaster, устойчивые туннели в стиле autossh и шаблоны для dev/stage/prod.

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

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

Debian/Ubuntu: mount: wrong fs type, bad option, bad superblock — как быстро найти и исправить причину OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: mount: wrong fs type, bad option, bad superblock — как быстро найти и исправить причину

Ошибка mount: wrong fs type, bad option, bad superblock в Debian/Ubuntu может означать и простую опечатку в имени раздела, и пробл ...
Debian/Ubuntu: XFS metadata corruption и emergency read-only — пошаговое восстановление OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: XFS metadata corruption и emergency read-only — пошаговое восстановление

Если XFS-раздел внезапно стал доступен только для чтения, а сервер ушёл в emergency mode, главное — не спешить. Разберём безопасны ...
Debian/Ubuntu: как исправить Failed to fetch при apt update OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: как исправить Failed to fetch при apt update

Ошибка Failed to fetch при apt update в Debian и Ubuntu обычно связана не с самим APT, а с DNS, сетью, зеркалом, прокси, временем ...