Белого IP нет, роутер провайдерский, а домашний компьютер нужен прямо сейчас: забытый файл, зависшая сборка, открытая вкладка. Отдавать доступ стороннему сервису не хочется. Решение известное: пусть домашний компьютер сам подключается к VPS и держит туннель, через который мы попадём обратно.

В статье соберём такой туннель так, чтобы он переживал обрывы и перезагрузки (autossh + systemd), пустим через него полноценный рабочий стол (VNC) и сведём подключение к одной команде ssh home. Отдельно разберём грабли, из-за которых туннель «вроде работает», а на деле нет.

Вводная: что и зачем

Итак, у нас есть:

•     Домашний компьютер (Debian 13) за NAT провайдера, без белого IP. Хотим получить к нему доступ из любой точки мира — в том числе к графическому рабочему столу.

•     VPS (Debian 13) с публичным IP. Он будет «точкой встречи»: домашний компьютер сам к нему подключится, а мы будем заходить на VPS и через него попадать дальше.

Схема:

[Вы] ──ssh :443──▶ [VPS] ◀──ssh :443 (исходящее)── [Дом]

                   127.0.0.1:44443 ══ туннель ══▶ :22 дома

 

VNC: localhost:5900 у вас ══ внутри SSH ══▶ 127.0.0.1:5900 дома

Ключевая идея: домашний компьютер сам инициирует соединение с VPS. Поэтому:

•     не нужен белый IP и проброс портов у провайдера;

•     не нужно трогать настройки роутера;

•     фаервол провайдера не мешает — исходящие соединения обычно разрешены.

Конструкцию сделаем отказоустойчивой: если туннель оборвётся (сменился IP, упал провайдер, перезагрузился VPS), он поднимется сам. VNC при этом не будет торчать в интернет — он доступен только через SSH.

Что нам понадобится

На VPS (Debian 13):

•     публичный IP (в примерах — 203.0.113.10, адрес из документационного диапазона);

•     SSH-сервер на порту 443 — этот порт почти везде открыт на выход, даже в гостиничных и корпоративных сетях;

•     пользователь для подключения. Для простоты начнём с root, а в разделе о безопасности заменим его на отдельных пользователей.

На домашнем компьютере (Debian 13):

•     autossh — для автоматического переподключения туннеля;

•     x11vnc — для доступа к текущему рабочему столу;

•     SSH-клиент и SSH-сервер (клиент в Debian есть по умолчанию, сервер нужно поставить);

•     графический сеанс X11, а не Wayland. В Debian 13 GNOME по умолчанию запускается на Wayland, а x11vnc с ним не работает — будет чёрный экран. Выберите «GNOME on Xorg» на экране входа или пропишите WaylandEnable=false в /etc/gdm3/daemon.conf. Если хотите остаться на Wayland — смотрите в сторону встроенного в GNOME удалённого рабочего стола (RDP), wayvnc для wlroots-окружений или krfb для KDE; туннельная часть статьи от этого не меняется.

Устанавливаем пакеты:

# Домашний компьютер

sudo apt update

sudo apt install autossh x11vnc openssh-server

 

# VPS

sudo apt update

sudo apt install openssh-server

Шаг 0. Готовим SSH-сервер на VPS

Переносим SSH на порт 443 и сразу учим сервер быстро замечать мёртвые подключения. В /etc/ssh/sshd_config на VPS:

Port 443

ClientAliveInterval 30

ClientAliveCountMax 3

Зачем ClientAlive*: когда связь с домом рвётся, старый процесс sshd на VPS ещё долго не знает об этом и продолжает держать порт 44443. Новое подключение из дома не может занять порт, падает, перезапускается — и так несколько минут, пока старая сессия не умрёт по таймауту. С этими настройками VPS сам закроет мёртвую сессию примерно через полторы минуты.

Применяем, не закрывая текущую SSH-сессию, и проверяем вход на новый порт из второго окна:

sudo systemctl restart ssh
ssh -p 443 root@203.0.113.10

⚠ Если на VPS есть фаервол (ufw, nftables, панель хостера) — откройте в нём 443/tcp до перезапуска. Если на VPS включена сокет-активация SSH (ssh.socket), порт задаётся в ней, а не в sshd_config. И помните: 443 не «маскирует» SSH под HTTPS — DPI определяет протокол по рукопожатию, а не по номеру порта. Порт выбран просто потому, что он почти везде открыт.

Шаг 1. SSH-доступ с домашнего компьютера на VPS по ключу

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

Генерируем ключ на домашнем компьютере (если его ещё нет):

ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N ""

Копируем публичный ключ на VPS и проверяем, что пускает без пароля:

ssh-copy-id -p 443 root@203.0.113.10

ssh -p 443 root@203.0.113.10

Заодно этот вход добавит ключ VPS в ~/.ssh/known_hosts — без этого сервис в шаге 4 не сможет подключиться.

Шаг 2. Проверяем reverse-туннель вручную

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

ssh -p 443 -R 44443:localhost:22 root@203.0.113.10

Оставляем окно открытым. На VPS в другом окне смотрим, слушается ли порт:

sudo ss -tlnp | grep 44443

Ожидаем что-то вроде:

LISTEN 0 128 127.0.0.1:44443 0.0.0.0:* users:(("sshd",pid=...,fd=...))

Порт появился — туннель работает. Теперь с VPS можно зайти на домашний компьютер (vasvs — ваш пользователь дома):

ssh -p 44443 vasvs@localhost

Важный нюанс. По умолчанию reverse-туннель слушает только 127.0.0.1 на VPS. Это правильно и безопасно: порт доступен только с самого VPS, а не из интернета. GatewayPorts yes не включаем.

Шаг 3. Держим туннель живым: autossh

Обычный SSH-туннель падает при первой же сетевой икоте. autossh запускает ssh и перезапускает его, если тот завершился:

autossh -M 0 -N \

    -o ServerAliveInterval=30 \

    -o ServerAliveCountMax=3 \

    -o ExitOnForwardFailure=yes \

    -p 443 \

    -R 44443:localhost:22 \

    root@203.0.113.10

Разберём флаги:

•     -M 0 — отключаем встроенный мониторинг autossh (он использует отдельные порты и часто упирается в фаерволы). Живость соединения проверяет сам ssh.

•     -N — не выполнять команды на удалённой стороне, только туннель.

•     ServerAliveInterval=30 — каждые 30 секунд ssh отправляет keepalive.

•     ServerAliveCountMax=3 — три keepalive подряд без ответа, и соединение считается мёртвым: ssh завершается, autossh поднимает новое.

•     ExitOnForwardFailure=yes — если ssh не смог занять порт 44443 на VPS, соединение сразу закрывается. Без этого флага можно получить «тихий» туннель: ssh подключён, а порта на VPS нет. Эта мелочь экономит пару вечеров отладки.

•    -p 443 — порт SSH на VPS.

•     -R 44443:localhost:22 — собственно reverse-туннель.

Честная оговорка: с -M 0 под systemd autossh почти ничего не добавляет — перезапуск умеет и сам systemd (Restart=always), а проверку живости делает ssh. Можно смело заменить /usr/bin/autossh -M 0 на /usr/bin/ssh в unit-файле ниже, всё будет работать так же. autossh удобен, когда туннель запускается руками или из cron, без systemd.

Шаг 4. Оформляем туннель как systemd-сервис

Создаём /etc/systemd/system/reverse-ssh.service:

[Unit]

Description=Reverse SSH Tunnel to VPS

After=network-online.target

Wants=network-online.target

 

[Service]

User=vasvs

Environment=AUTOSSH_GATETIME=0

ExecStart=/usr/bin/autossh -M 0 -N \

    -o ServerAliveInterval=30 \

    -o ServerAliveCountMax=3 \

    -o ExitOnForwardFailure=yes \

    -o BatchMode=yes \

    -p 443 \

    -R 44443:localhost:22 \

    root@203.0.113.10

Restart=always

RestartSec=10

 

[Install]

WantedBy=multi-user.target

Пояснения:

•     User=vasvs — сервис работает от вашего пользователя, потому что ключ и known_hosts лежат в его ~/.ssh. От root ключ не найдётся.

•     After= и Wants=network-online.target — стартуем, когда сеть действительно поднялась, а не только интерфейс.

•     AUTOSSH_GATETIME=0 — без этого autossh завершается, если самое первое подключение не удалось (например, VPS ещё недоступен при загрузке).

•     BatchMode=yes — ssh никогда не станет ждать пароль или подтверждение ключа хоста: либо подключился, либо ошибка в журнале.

•     Restart=always и RestartSec=10 — перезапуск в любом случае, с паузой 10 секунд.

Активируем и проверяем:

sudo systemctl daemon-reload

sudo systemctl enable --now reverse-ssh.service

sudo systemctl status reverse-ssh.service

Должно быть active (running). На VPS снова проверяем sudo ss -tlnp | grep 44443 — если порт слушается, туннель работает и переживёт перезагрузку.

Шаг 5. VNC: полный рабочий стол

SSH-доступ есть, теперь графика. Задаём пароль VNC на домашнем компьютере:

x11vnc -storepasswd

Пароль сохранится в ~/.vnc/passwd. Это пароль именно на VNC, не путайте с паролем пользователя. Учтите, что VNC использует только первые 8 символов — основная защита здесь всё равно SSH.

Проверяем вручную, находясь в графическом сеансе:

x11vnc -forever -shared -localhost -rfbauth ~/.vnc/passwd -display :0

Флаги:

•     -forever — не выходить после отключения клиента;

•     -shared — разрешить нескольким клиентам подключаться одновременно;

•     -localhost — принимать соединения только с localhost. Критично для безопасности: VNC не должен быть доступен снаружи, ходим к нему только через SSH;

•     -rfbauth — файл с паролем;

•     -display :0 — какой X-дисплей показывать. Номер может отличаться: проверьте echo $DISPLAY в терминале графического сеанса.

Во втором терминале убеждаемся, что VNC слушает только localhost:

ss -tlnp | grep 5900

Должно быть 127.0.0.1:5900. Это то, что нужно.

Шаг 6. Автозапуск x11vnc

Создаём /etc/systemd/system/x11vnc.service :

[Unit]

Description=x11vnc server for reverse SSH access

After=display-manager.service

Wants=display-manager.service

 

[Service]

Type=simple

User=vasvs

ExecStart=/usr/bin/x11vnc -forever -shared -localhost \

    -rfbauth /home/vasvs/.vnc/passwd -find

Restart=always

RestartSec=5

 

[Install]

WantedBy=graphical.target

Вместо жёсткого -display :0 здесь -find: x11vnc сам найдёт X-дисплей пользователя и нужный файл авторизации, а если сеанса ещё нет — подождёт. Это важно, потому что GDM после входа часто поднимает сеанс пользователя не на :0, а на :1.

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

sudo systemctl daemon-reload

sudo systemctl enable --now x11vnc.service

sudo systemctl status x11vnc.service

Теперь и туннель, и VNC поднимаются автоматически.

Шаг 7. Подключаемся из любой точки

Вариант А: одна команда через ProxyJump

ssh умеет сам «прыгать» через промежуточный сервер. На компьютере, с которого подключаетесь:

ssh -J root@203.0.113.10:443 -p 44443 -L 5900:localhost:5900 vasvs@localhost

ssh зайдёт на VPS и уже оттуда подключится к localhost:44443 — то есть в reverse-туннель. localhost здесь относится к VPS, а не к вашей машине. Одна команда — два прыжка.

Чтобы не набирать это каждый раз, добавим в ~/.ssh/config:

Host vps

    HostName 203.0.113.10

    Port 443

    User root

 

Host home

    HostName localhost

    Port 44443

    User vasvs

    ProxyJump vps

    HostKeyAlias home-desktop

    LocalForward 5900 localhost:5900

HostKeyAlias нужен, чтобы ключ домашнего компьютера не записался в known_hosts под безликим [localhost]:44443 и не конфликтовал с другими туннелями.

Теперь подключение выглядит так:

ssh home                    # терминал домашнего компьютера + проброс VNC

vncviewer localhost:5900    # во втором окне — рабочий стол

Если локально порт 5900 занят, возьмите другой: LocalForward 5901 localhost:5900 и vncviewer localhost:5901.

Вариант Б: два прыжка вручную (чтобы понять, как это работает)

На своём компьютере заходим на VPS и пробрасываем локальный 5900 на 5900 VPS:

ssh -p 443 -L 5900:localhost:5900 root@203.0.113.10

В этом же сеансе, уже на VPS, заходим домой и пробрасываем 5900 VPS на 5900 домашнего компьютера:

ssh -p 44443 -L 5900:localhost:5900 vasvs@localhost

Получилась цепочка: ваш localhost:5900 → VPS:5900дом:5900. Во втором терминале запускаем vncviewer localhost:5900, вводим пароль VNC — и видим рабочий стол. Вариант А делает то же самое, но короче и без открытого порта 5900 на VPS.

Шаг 8. Безопасность

Схема рабочая, но root на VPS мы использовали только для простоты. Приведём её в порядок. Делайте изменения по одному и держите открытой рабочую SSH-сессию, пока не проверите новый вход.

1. Отдельный пользователь для туннеля. На VPS:

sudo adduser --disabled-password --gecos "" tunnel

sudo install -d -m 700 -o tunnel -g tunnel /home/tunnel/.ssh

В /home/tunnel/.ssh/authorized_keys кладём публичный ключ домашнего компьютера (~/.ssh/id_ed25519.pub) с ограничениями:

restrict,port-forwarding,permitlisten="44443" ssh-ed25519 AAAA... home

Этот ключ сможет только открыть reverse-туннель на порт 44443: ни shell, ни команд, ни других портов. Не забудьте sudo chown tunnel:tunnel и chmod 600 на файл. В reverse-ssh.service меняем root@... на tunnel@....

2. Отдельный пользователь для себя. Туннельный пользователь не умеет ничего, кроме туннеля, поэтому для входа на VPS заведите обычного пользователя с ключом вашего ноутбука и замените им root в блоке Host vps в ~/.ssh/config.

3. Закрываем root и пароли. Когда вход под своим пользователем проверен, в /etc/ssh/sshd_config на VPS:

PermitRootLogin no

PasswordAuthentication no

И sudo systemctl restart ssh.

4. fail2ban. Ставим sudo apt install fail2ban, но учтите две вещи: стандартный jail банит на порту 22, а в Debian нет /var/log/auth.log по умолчанию. Создаём /etc/fail2ban/jail.local:

[sshd]

enabled = true

port    = 443

backend = systemd

и перезапускаем: sudo systemctl restart fail2ban.

5. VNC — только через SSH. Флаг -localhost у x11vnc гарантирует, что VNC недоступен напрямую. Не убирайте его.

6. Обновления. И на VPS, и дома: sudo apt update && sudo apt upgrade. На VPS удобно включить unattended-upgrades.

Диагностика: что может пойти не так

Порт 44443 на VPS не слушается. Смотрим сервис на домашнем компьютере:

sudo systemctl status reverse-ssh

sudo journalctl -u reverse-ssh -f

В журнале будет точная причина. Частые варианты:

•     ключ не скопирован на VPS или лежит не у того пользователя — с BatchMode=yes будет Permission denied;

•     ключ VPS не в known_hosts пользователя vasvs — Host key verification failed, зайдите на VPS руками один раз;

•     порт 44443 на VPS занят — remote port forwarding failed;

•     фаервол на VPS не пропускает 443/tcp;

•     в команде не тот порт SSH (-p 443 против -p 22).

Туннель после обрыва несколько минут не поднимается, в журнале remote port forwarding failed. Порт держит старая «мёртвая» сессия на VPS. Проверьте ClientAliveInterval и ClientAliveCountMax из шага 0.

VNC показывает чёрный экран. Почти всегда это Wayland — проверьте echo $XDG_SESSION_TYPE в графическом сеансе, там должно быть x11. Второй вариант — x11vnc подключился не к тому дисплею: посмотрите who и echo $DISPLAY и journalctl -u x11vnc.

VNC-клиент не подключается к localhost:5900. Проверьте, что:

•     SSH-сессия с -L (или ssh home) открыта;

•     порядок аргументов именно такой: -L локальный_порт:хост:удалённый_порт;

•     на домашнем компьютере x11vnc действительно слушает 127.0.0.1:5900 (ss -tlnp | grep 5900).

Туннель живёт, но отваливается через несколько минут простоя. Где-то по пути есть idle-timeout. ServerAliveInterval=30 обычно решает проблему; если нет — уменьшите до 15 секунд.

Итог

Что мы получили:

•     домашний Debian 13 сам поднимает reverse SSH-туннель на VPS и держит его живым благодаря autossh и systemd;

•     VPS быстро закрывает мёртвые сессии, так что туннель восстанавливается за секунды, а не за минуты;

•     x11vnc показывает рабочий стол, но слушает только localhost — снаружи он недоступен;

•     из любой точки мира ssh home открывает терминал домашнего компьютера и проброс к его рабочему столу;

•     всё переживает перезагрузки, смену IP и кратковременные обрывы сети.

Схема не претендует на корпоративный уровень, но для личного использования подходит отлично. Все компоненты стандартные, из репозиториев Debian.

Если хочется совсем без ручной возни — посмотрите в сторону Tailscale или ZeroTier. Но если хочется понимать, что происходит под капотом, и не зависеть от сторонних сервисов, reverse SSH и systemd остаются классикой, которая работает годами.

P.S. Если дома не Debian 13, отличия минимальны: замените apt на свой пакетный менеджер, пути к systemd-юнитам останутся прежними. x11vnc есть в большинстве репозиториев.

Комментарии (1)


  1. naim
    21.09.2026 08:52

    Посмотрите в сторону frps на сервере и на клиенте или rustdeak