Выберите продукт

Debian/Ubuntu: как исправить SSH remote port forwarding failed for listen port и GatewayPorts

Если reverse SSH tunnel через ssh -R не поднимается и клиент пишет remote port forwarding failed for listen port, причина обычно на стороне sshd: GatewayPorts, AllowTcpForwarding, PermitOpen, Match-блоки или занятый порт. Ниже — быстрая диагностика и рабочие примеры для Debian и Ubuntu.
Debian/Ubuntu: как исправить SSH remote port forwarding failed for listen port и GatewayPorts

Ошибка remote port forwarding failed for listen port в OpenSSH на Debian и Ubuntu почти всегда означает, что серверная сторона не разрешила открыть удалённый порт так, как вы ожидаете. Чаще всего проблема не в самой команде ssh -R, а в параметрах sshd_config: GatewayPorts, AllowTcpForwarding, PermitOpen, иногда в Match-блоках, занятом порте или серверных ограничениях.

Типичный сценарий такой: локальное приложение слушает 127.0.0.1:3000, а на удалённом сервере нужно открыть 8080 и направить трафик в этот локальный порт через reverse SSH tunnel. SSH-сессия устанавливается, но вместо рабочего туннеля вы получаете отказ на этапе создания удалённого listening socket.

Важно понимать механику reverse forwarding. В конструкции ssh -R remote_host:remote_port:local_host:local_port user@server порт открывается именно на удалённой машине, где работает sshd. Поэтому разрешение или запрет такого bind контролирует серверный демон, а не клиент.

Из-за этого многие начинают проверять только локальную машину, хотя в первую очередь нужно смотреть на /etc/ssh/sshd_config, include-файлы и серверные логи. Особенно если обычный вход по SSH работает нормально, а ломается только remote forwarding.

Ниже разберём, как быстро локализовать проблему, какие параметры реально влияют на ssh -R, чем отличаются режимы GatewayPorts, и как включить reverse tunnel без лишнего расширения поверхности атаки.

Что означает эта ошибка на практике

Сообщение remote port forwarding failed for listen port не всегда указывает на одну конкретную причину. По сути клиент сообщает, что сервер не смог создать сокет для удалённого прослушивания.

  • удалённый порт уже занят другим процессом;
  • sshd запрещает remote forwarding полностью или частично;
  • запрошенный адрес привязки не разрешён политикой GatewayPorts;
  • ограничения заданы через PermitOpen или Match User;
  • используется привилегированный порт и действуют дополнительные ограничения;
  • в команде ssh -R указан неверный синтаксис.

Ключевой момент: ошибка возникает именно на этапе создания listening socket на сервере. Это ещё не проверка доступности вашего приложения за туннелем. Даже если локальный сервис на 127.0.0.1:3000 не отвечает, ошибка bind на удалённой стороне появляется раньше и по другой причине.

Если команда ssh -R 8080:127.0.0.1:3000 user@server завершилась без ошибки, это ещё не гарантирует, что приложение доступно. Но если вы сразу видите remote port forwarding failed for listen port 8080, почти наверняка проблема в серверной политике или конфликте порта.

С чего начать диагностику

Первый шаг — запустить SSH с подробным выводом. Это помогает увидеть, на каком этапе рушится remote forwarding и как именно сервер отвечает на запрос клиента.

ssh -vvv -R 8080:127.0.0.1:3000 user@server

В отладочном выводе ищите строки про remote forward, listen, administratively prohibited и port forwarding failed. Если видно, что запрос на tcpip-forward отклонён, дальше нужно идти в серверную конфигурацию.

На сервере сразу проверьте, не занят ли нужный порт:

ss -ltnp | grep :8080
sudo lsof -iTCP:8080 -sTCP:LISTEN -n -P

Если порт уже занят Nginx, Docker-прокси, другим туннелем или приложением, ошибка будет воспроизводиться независимо от значений GatewayPorts и AllowTcpForwarding.

Дальше посмотрите итоговую конфигурацию OpenSSH. На Debian и Ubuntu это особенно полезно, потому что часть параметров может приехать из include-файлов и условий Match:

sudo sshd -T | grep -Ei 'allowtcpforwarding|gatewayports|permitopen|passwordauthentication|pubkeyauthentication'
sudo sshd -T -C user=user,host=$(hostname -f),addr=127.0.0.1 | grep -Ei 'allowtcpforwarding|gatewayports|permitopen'

Команда sshd -T показывает эффективные настройки. Это намного надёжнее, чем читать только /etc/ssh/sshd_config глазами и пытаться угадать, какой именно Match реально сработал.

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

Как влияет GatewayPorts

Параметр GatewayPorts — самая частая причина, по которой reverse tunnel либо не создаётся так, как ожидается, либо создаётся только на localhost вместо внешнего интерфейса.

Во многих конфигурациях поведение эквивалентно GatewayPorts no. Это значит, что удалённые порты для ssh -R будут слушаться только на loopback-интерфейсе сервера, то есть на 127.0.0.1 и, в зависимости от стека, на ::1. Из внешней сети такой порт недоступен, даже если туннель формально поднялся.

Отсюда и типичная путаница: администратор ожидает публикацию сервиса наружу, запускает ssh -R 0.0.0.0:8080:127.0.0.1:3000 user@server, а сервер либо игнорирует желаемый bind-адрес, либо отказывает в нём. В результате либо появляется ошибка, либо порт слушает только localhost.

  • GatewayPorts no — удалённый порт доступен только с localhost на сервере;
  • GatewayPorts yes — сервер разрешает слушать на wildcard-адресах;
  • GatewayPorts clientspecified — клиент сам задаёт адрес привязки в ssh -R.

Если вам нужно явно указывать 0.0.0.0, конкретный внешний IP или 127.0.0.1, самый предсказуемый вариант — GatewayPorts clientspecified.

Пример настройки:

sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
sudo editor /etc/ssh/sshd_config
AllowTcpForwarding yes
GatewayPorts clientspecified

После изменения проверьте конфиг и перезапустите сервис:

sudo sshd -t
sudo systemctl restart ssh

На Debian и Ubuntu сервис чаще всего называется ssh, хотя на некоторых системах можно встретить и sshd.

После этого можно явно задать адрес bind:

ssh -N -R 0.0.0.0:8080:127.0.0.1:3000 user@server

Если публикация наружу не нужна, безопаснее оставить привязку только к localhost:

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

Такой режим особенно удобен, когда дальше вы отдаёте сервис через локальный Nginx на сервере или поднимаете дополнительный reverse proxy. Если туннель нужен на постоянной основе на отдельной машине, обычно удобнее использовать VDS, где вы полностью контролируете sshd_config, firewall и сетевые привязки.

Проверка параметров sshd_config и GatewayPorts в терминале Linux

AllowTcpForwarding: общий рубильник для форвардинга

Параметр AllowTcpForwarding определяет, разрешён ли TCP forwarding вообще. Если он выключен, ssh -R работать не будет, а вы увидите либо прямой отказ, либо то же сообщение про невозможность открыть удалённый порт.

  • AllowTcpForwarding yes — разрешены local и remote forwarding;
  • AllowTcpForwarding no — всё запрещено;
  • AllowTcpForwarding local — только ssh -L;
  • AllowTcpForwarding remote — только ssh -R.

Если нужен именно reverse SSH tunnel, разумно использовать AllowTcpForwarding remote. Это лучше, чем глобальное yes, особенно на серверах, где есть несколько технических пользователей.

AllowTcpForwarding remote

Обязательно проверьте, не переопределяется ли параметр ниже по файлу через Match User, Match Group или файлы в /etc/ssh/sshd_config.d/.

PermitOpen и почему он ломает даже корректный ssh -R

Параметр PermitOpen часто недооценивают. Он ограничивает, к каким хостам и портам можно подключаться через форвардинг. Если когда-то политику ужесточили, а потом забыли об этом, reverse tunnel начинает выглядеть «странно»: авторизация проходит, но нужное направление не разрешается.

Например, вы хотите пробросить локальный сервис на 127.0.0.1:3000, а в конфиге или параметрах ключа разрешён только другой endpoint. В этом случае запрос на новое направление будет отклонён, даже если с GatewayPorts и AllowTcpForwarding всё в порядке.

Смотреть нужно в двух местах:

  • в глобальном sshd_config;
  • в параметрах ключа в ~/.ssh/authorized_keys.

Пример ограничения в authorized_keys:

permitopen="127.0.0.1:3000" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA...

Если используется такой подход, разрешённый адрес и порт должны совпадать с реальным направлением туннеля. Иначе можно долго искать проблему в GatewayPorts, хотя причина на самом деле в ограничении ключа.

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

Типовые рабочие сценарии с ssh -R

Сервис должен быть доступен только на самом сервере

Это самый безопасный вариант. Туннель поднимается, а доступ к нему есть только у процессов на удалённой машине.

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

Такой режим подходит для временного админского доступа, локального проксирования через Nginx или отладки веб-приложения без публикации в сеть.

Сервис должен слушать на всех интерфейсах сервера

Здесь нужен либо GatewayPorts yes, либо лучше GatewayPorts clientspecified.

ssh -N -R 0.0.0.0:8080:127.0.0.1:3000 user@server

После запуска туннеля проверьте, где реально слушается порт:

ss -ltnp | grep :8080

Если видите только 127.0.0.1:8080, сервер не разрешил bind на внешний интерфейс. Это почти прямое указание на проблему с GatewayPorts.

Нужна привязка к конкретному внешнему IP

На сервере с несколькими адресами это часто удобнее и безопаснее, чем wildcard-bind.

ssh -N -R 203.0.113.10:8080:127.0.0.1:3000 user@server

Такой сценарий тоже требует GatewayPorts clientspecified или совместимого поведения демона.

Если вы переносите приложение с общего тарифа на отдельный сервер ради таких сценариев, может пригодиться материал про миграцию с виртуального хостинга на VDS.

Что проверить в логах Debian/Ubuntu

На современных Debian и Ubuntu логи OpenSSH чаще всего удобнее смотреть через journald:

sudo journalctl -u ssh -n 100 --no-pager
sudo journalctl -u ssh -f

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

sudo grep sshd /var/log/auth.log | tail -n 50

Полезные маркеры в сообщениях:

  • refused port forward;
  • administratively prohibited;
  • bind: Address already in use;
  • cannot listen to port;
  • port forwarding disabled.

Логи часто сразу показывают, что проблема не в сети и не в приложении, а именно в серверной политике. Это экономит много времени.

Match-блоки: частая ловушка в production

Очень распространённая ситуация: глобально в sshd_config всё разрешено, но для конкретного пользователя, группы, подсети или отдельного bastion-сценария задан Match-блок с более жёсткими ограничениями.

Например:

Match User tunnel
    AllowTcpForwarding remote
    GatewayPorts clientspecified

Match Group sftp-only
    AllowTcpForwarding no

Если пользователь попадает под другой Match, итоговое поведение будет совсем не тем, что видно в верхней части файла. Поэтому команда sshd -T -C ... здесь особенно полезна.

Просмотр логов SSH и открытых портов на сервере Linux

Когда проблема не в GatewayPorts

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

Порт ниже 1024

Открытие привилегированных портов на удалённой стороне может быть ограничено. Если вы пытаетесь поднять ssh -R 80:127.0.0.1:3000 под обычным пользователем, для диагностики лучше сразу перейти на непривилегированный порт, например 8080 или 10080.

IPv4 и IPv6

На dual-stack-хостах поведение может отличаться для 0.0.0.0, :: и localhost. Если клиент ожидает IPv4-socket, а сервер поднял только IPv6-listener, внешняя проверка может запутать. Всегда смотрите вывод ss -ltnp, а не только тест из браузера.

Firewall уже после bind

nftables, iptables или внешний сетевой экран не мешают самому факту прослушивания сокета, но могут блокировать входящий трафик. В этом случае SSH-туннель формально поднят, а подключиться к нему снаружи нельзя. Сообщение remote port forwarding failed for listen port здесь обычно не появляется, но визуально ситуация часто кажется похожей.

Автоподнятие через systemd или autossh

Если туннель стартует не вручную, а сервисом, старая команда в unit-файле может содержать другой порт, неверный bind-адрес или устаревший синтаксис. Сначала всегда воспроизводите сценарий вручную в интерактивной сессии, а уже потом возвращайте его в automation.

Минимально безопасная конфигурация для reverse SSH tunnel

Не стоит бездумно включать все виды форвардинга глобально для всех пользователей. Если задача — дать одному техническому пользователю право поднимать только удалённые туннели, лучше сделать это адресно.

Пример умеренно ограниченного подхода:

Match User tunnel
    AllowTcpForwarding remote
    GatewayPorts clientspecified
    X11Forwarding no
    AllowAgentForwarding no
    PermitTTY no

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

Если reverse tunnel публикует внутренний HTTP-сервис наружу, не забывайте про защиту уже на уровне самого приложения или reverse proxy. Для внешнего веб-доступа также полезны корректно настроенные SSL-сертификаты, чтобы не оставлять сервис без шифрования там, где это критично.

Пошаговый чек-лист, если ssh -R не работает

  1. Запустите команду с -vvv и зафиксируйте точный текст ошибки.
  2. Проверьте, не занят ли удалённый порт через ss или lsof.
  3. Посмотрите итоговые значения AllowTcpForwarding, GatewayPorts и PermitOpen через sshd -T.
  4. Проверьте Match-блоки и файлы в /etc/ssh/sshd_config.d/.
  5. Изучите серверные логи через journalctl -u ssh или /var/log/auth.log.
  6. Для внешней публикации включите GatewayPorts clientspecified и укажите bind-адрес явно.
  7. Для тестов используйте непривилегированный порт, например 8080.
  8. После успешного bind отдельно проверьте firewall и доступность локального приложения за туннелем.

Итог

В Debian и Ubuntu ошибка remote port forwarding failed for listen port почти всегда решается системно, а не подбором случайных клиентских флагов. Нужно проверить четыре вещи: не занят ли порт, разрешён ли remote forwarding через AllowTcpForwarding, допускает ли сервер нужный bind-адрес через GatewayPorts, и нет ли ограничений через PermitOpen или Match.

Если нужен публичный reverse SSH tunnel, рабочая схема обычно такая: на сервере AllowTcpForwarding remote и GatewayPorts clientspecified, на клиенте — явный вызов ssh -N -R 0.0.0.0:PORT:127.0.0.1:LOCALPORT. Если публикация наружу не нужна, держите bind на 127.0.0.1 — это и проще, и безопаснее.

И главное: не редактируйте sshd_config вслепую. Сначала проверяйте эффективную конфигурацию через sshd -T и валидируйте изменения командой sshd -t. В админской практике именно такие короткие проверки чаще всего экономят больше времени, чем серия перезапусков наугад.

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

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

Debian/Ubuntu: apt update зависает на Waiting for headers — IPv6, MTU, proxy и timeout зеркал OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: apt update зависает на Waiting for headers — IPv6, MTU, proxy и timeout зеркал

Если в Debian или Ubuntu команда apt update подвисает на стадии Waiting for headers, причина обычно не в самом APT, а в сети: слом ...
Debian/Ubuntu: netfilter-persistent save failed — как исправить и сохранить правила nftables/iptables OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: netfilter-persistent save failed — как исправить и сохранить правила nftables/iptables

Ошибка netfilter-persistent save failed в Debian и Ubuntu обычно связана с путаницей между nftables и iptables, неверным backend, ...
Debian/Ubuntu: как исправить sudo: no space left on device из-за /tmp, /var/tmp и journald OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: как исправить sudo: no space left on device из-за /tmp, /var/tmp и journald

Ошибка sudo: no space left on device в Debian и Ubuntu не всегда означает, что переполнен весь диск. Часто проблема в /tmp, /var/t ...