6 октября 2026 года вышел OpenSSH 10.6, что в нём нового, я разбирал в отдельной заметке. А здесь про возможность, которая есть в OpenSSH много лет и до сих пор выручает каждый день: туннели. Через обычное SSH-подключение можно пробросить порт к внутренней базе, открыть доступ к своему локальному сервису с сервера, поднять SOCKS-прокси или даже простой IP-туннель. Ключи одинаковые в Linux, macOS и FreeBSD.
Как это работает
Трафик приложения идёт внутри уже зашифрованной SSH-сессии. Снаружи видно только соединение с портом SSH, что внутри, не видно. Это удобно, чтобы достучаться до сервисов, которые доступны только с сервера, работать через бастион и временно обойтись без отдельного VPN. Нужен только работающий sshd и доступ к нему.
Локальный проброс: -L
На вашей машине открывается порт, а соединения с него уходят через SSH-сервер к нужному адресу. Классика: база данных или админка, которые слушают только внутри сети сервера.
ssh -L [локальный_порт]:[хост]:[порт] user@ssh.example.com # PostgreSQL сервера на своём ноутбуке ssh -N -L 5432:127.0.0.1:5432 user@ssh.example.com # внутренняя веб-админка ssh -N -L 8080:internal.example.com:80 user@ssh.example.com
После этого база доступна на 127.0.0.1:5432, а админка на http://127.0.0.1:8080. Важно: адрес в середине команды ищется и открывается со стороны SSH-сервера, поэтому 127.0.0.1 там значит сам сервер, а не ваш ноутбук.
Обратный проброс: -R
Наоборот: порт открывается на SSH-сервере, а соединения с него приходят к вам. Так можно показать заказчику локальный сайт или дать серверу доступ к сервису на вашей машине.
# локальный сайт на 8080 станет доступен на сервере, порт 9000 ssh -N -R 9000:localhost:8080 user@ssh.example.com # обратный SOCKS: сервер ходит в сеть через вас ssh -N -R 1080 user@ssh.example.com
По умолчанию, как сказано в man sshd_config, сервер вешает такие порты только на loopback, и снаружи к ним не подключиться. Чтобы открыть их наружу, нужен GatewayPorts в sshd_config. Делайте это осознанно и только вместе с файрволом: иначе ваш локальный сервис увидит весь интернет.
SOCKS-прокси: -D
Локальный SOCKS-прокси: приложение само говорит, куда ему надо, а SSH ходит туда от имени сервера. Удобно, когда нужен доступ сразу к куче внутренних адресов или нужно временно выйти в сеть с IP сервера.
ssh -N -D 1080 user@ssh.example.com # проверка из консоли curl --socks5-hostname 127.0.0.1:1080 https://ifconfig.me
В браузере указывается SOCKS5, хост 127.0.0.1, порт 1080, лучше с опцией отправлять DNS-запросы через прокси. Для консольных утилит часто хватает переменной ALL_PROXY=socks5h://127.0.0.1:1080.
Полезные ключи и сценарии
-Nтолько туннель, без командной оболочки.-fуйти в фон после входа.-o ExitOnForwardFailure=yesзавершиться, если порт пробросить не удалось, а не висеть без туннеля.-Cсжатие, иногда помогает на медленном канале с текстом.- Для постоянного туннеля вместо забытого
-fлучшеautosshили юнит systemd с перезапуском.
Бастион: -J
Чтобы попасть на сервер через промежуточный хост, не нужно заходить по SSH дважды:
ssh -J user@bastion.example.com user@10.0.0.15
# в ~/.ssh/config
Host db
HostName 10.0.0.15
User user
ProxyJump user@bastion.example.com
Несколько прыжков пишутся через запятую. С настройкой в ~/.ssh/config пробросы тоже работают через бастион: ssh -N -L 5432:127.0.0.1:5432 db.
Графические приложения: -X
ssh -X user@ssh.example.com # или -Y, если с -X не работают нужные расширения
На сервере должно быть X11Forwarding yes, на клиенте X-сервер (в macOS это XQuartz). Для постоянной удалённой работы с графикой удобнее RDP, VNC или Waypipe.
IP-туннель: -w
Режим почти VPN: два устройства tun соединяются через SSH. На сервере нужен PermitTunnel (по умолчанию выключен), на обеих сторонах права root. Это запасной вариант, для постоянной сети удобнее WireGuard.
# /etc/ssh/sshd_config на сервере PermitTunnel point-to-point # перезапуск: в Debian и Ubuntu служба называется ssh sudo systemctl restart ssh # FreeBSD sudo service sshd restart
# клиент: поднять tun0 с обеих сторон sudo ssh -w 0:0 root@ssh.example.com # сервер (Linux) sudo ip addr add 10.0.0.1/30 dev tun0 && sudo ip link set tun0 up # клиент (Linux) sudo ip addr add 10.0.0.2/30 dev tun0 && sudo ip link set tun0 up # FreeBSD sudo ifconfig tun0 10.0.0.2 10.0.0.1 netmask 255.255.255.252 up
Чтобы клиент выходил в интернет через сервер, на сервере нужны включённая пересылка пакетов и NAT в nftables или iptables. Если меняете маршрут по умолчанию на клиенте, сначала добавьте отдельный маршрут до самого SSH-сервера через старый шлюз, иначе туннель оборвёт сам себя.
UDP через SSH
Пробросы в SSH работают только с TCP. UDP можно протащить через socat внутри туннеля, но это хрупко. Для DNS, голоса и игр надёжнее WireGuard.
Устойчивость и безопасность
- Вход по ключу:
ssh-keygen -t ed25519, пароли вsshd_configлучше выключить. - Ограничьте, кто может пробрасывать:
AllowTcpForwarding,PermitOpen,AllowUsers. - Защитите сам SSH от перебора, например через Fail2Ban.
- Чтобы NAT не рвал простаивающий туннель, в
~/.ssh/configдобавьтеServerAliveInterval 60иServerAliveCountMax 3. - Не открывайте
-Rна все адреса без файрвола.
Типичные проблемы
- Порт уже занят локально: смените левую часть
-Lили-D. -Rне виден снаружи:GatewayPortsи файрвол на сервере.- Проброс молча не работает: на сервере может стоять
AllowTcpForwarding no. - TUN: нет
tun0или device busy: другой номер в-w, права root,PermitTunnel.
В итоге три ключа закрывают почти все задачи: -L чтобы достать сервис с сервера к себе, -R чтобы отдать свой сервис серверу и -D чтобы пустить браузер или утилиты через сервер. Бастион делается через -J, а -w и UDP оставьте для редких случаев, постоянную сеть лучше строить на WireGuard.