Если домашний сервер находится за NAT или CGNAT, не имеет белого IP-адреса, а проброс портов на роутере невозможен или нежелателен, сервисы всё равно можно опубликовать безопасно. Один из практичных вариантов — использовать как публичную точку входа, а домашний сервер подключать к нему через обратный SSH-туннель.
В такой схеме домашний сервер сам инициирует исходящее SSH-соединение к VPS. На стороне VPS создаётся локальный TCP endpoint, который через SSH-туннель ведёт к сервису на домашнем сервере. Внешний HTTPS-трафик принимает Caddy, после чего проксирует запросы на локальный адрес туннеля.
Базовая схема:
Пользователь
│
│ HTTPS :443
▼
VPS с публичным IP
│
│ Caddy reverse proxy / TLS termination
▼
127.0.0.1:11000 на VPS
│
│ Reverse SSH tunnel
▼
Домашний сервер
│
▼
Nextcloud / Home Assistant / Jellyfin / code-server / другой сервис
Главный принцип безопасности: backend-сервисы не публикуются в интернет прямыми портами. Наружу доступны только 80/tcp, 443/tcp и, при необходимости, SSH-порт для администрирования VPS. Все прикладные сервисы остаются доступными только через loopback на VPS и reverse proxy.
Примеры ориентированы на Ubuntu/Debian-подобные системы. На других дистрибутивах логика та же, но могут отличаться имена пакетов, пути и команды управления службами.
-R 127.0.0.1:11000:127.0.0.1:8080
│ │ │ │
│ │ │ └─ порт сервиса на домашнем сервере
│ │ └────────── адрес сервиса на домашнем сервере
│ └──────────────── порт, создаваемый на VPS
└────────────────────────── адрес прослушивания на VPS
Важно указывать именно 127.0.0.1 на стороне VPS. Тогда порт туннеля не становится публичным сетевым интерфейсом и не принимает входящие соединения напрямую из интернета. Внешний трафик должен идти только через Caddy.
Этот пользователь не предназначен для обычного входа в систему. Его задача — аутентификация по ключу и создание разрешённых remote forwarding endpoints.
8. Генерация SSH-ключа на домашнем сервере
На домашнем сервере создаём отдельную ключевую пару только для туннеля:
Для автоматического запуска через systemd passphrase обычно оставляют пустым. Более строгая схема с passphrase, ssh-agent или аппаратным ключом возможна, но усложняет unattended-запуск после перезагрузки.
# The tunnel account is permitted to create remote port forwards only.
# Interactive access and unrelated forwarding mechanisms are disabled.
Match User tunneluser
AllowTcpForwarding remote
GatewayPorts no
PermitTTY no
X11Forwarding no
AllowAgentForwarding no
PermitTunnel no
PasswordAuthentication no
PubkeyAuthentication yes
Указание параметров:
AllowTcpForwarding remote — разрешает только remote forwarding (ssh -R), без local forwarding;
GatewayPorts no — удерживает remote forwarding на loopback-интерфейсах и не позволяет открыть проброшенный порт на внешних интерфейсах VPS;
PermitTTY no — запрещает интерактивный терминал;
X11Forwarding no — отключает X11 forwarding;
AllowAgentForwarding no — запрещает проброс SSH-agent;
PermitTunnel no — запрещает TUN/TAP-туннели;
PasswordAuthentication no — запрещает парольную аутентификацию для этого пользователя;
PubkeyAuthentication yes — оставляет аутентификацию по публичному ключу.
Проверяем конфиг:
sshd -t
Если ошибок нет, перезапускаем SSH:
systemctl restart ssh
На некоторых системах:
systemctl restart sshd
Проверяем статус:
systemctl status ssh --no-pager
Практическое правило: **никогда не перезапускайте SSH после изменения конфигурации без предварительного **sshd -t.
11. Первичная проверка туннеля вручную
На домашнем сервере добавляем host key VPS в known_hosts:
ssh-keyscan -H 203.0.113.10 >> ~/.ssh/known_hosts
В production-сценарии fingerprint ключа желательно сверить с данными из консоли VPS-провайдера или с выводом на самом сервере. ssh-keyscan удобен для автоматизации, но сам по себе не доказывает, что ключ получен именно от нужного сервера.
До тех пор пока домен не указывает на VPS, автоматическая выдача TLS-сертификата Caddy может не сработывать
Если домен проксируется через Cloudflare, на время первичной проверки можно использовать “DNS-only”. После выпуска сертификата следует отдельно проверить режим SSL/TLS: обычно это Full или Full Strict, в зависимости от схемы сертификатов.
Для сложных приложений, особенно Nextcloud, заголовки следует подбирать осторожно. Чрезмерно жёсткая политика может нарушить WebDAV, загрузки файлов, предпросмотр, интеграции или мобильные клиенты.
Отдельно стоит относиться к директиве preload в HSTS. Директиву не следует включать механически: сначала нужно убедиться, что домен и все необходимые поддомены стабильно работают по HTTPS. Для учебного стенда или временного домена лучше использовать HSTS без preload либо временно не задавать HSTS вовсе.
20. Публикация нескольких сервисов
Допустим, на домашнем сервере работают:
Nextcloud 127.0.0.1:8080
Home Assistant 127.0.0.1:8123
Jellyfin 127.0.0.1:8096
В unit-файле можно объявить несколько remote forwards:
В более сложных конфигурациях дополнительно проверяются trusted_proxies, overwritehost, overwrite.cli.url, X-Forwarded-For, X-Forwarded-Proto и WebDAV.
22. Ограничение ключа в authorized_keys
Дополнительно можно наложить ограничения прямо на строку ключа в authorized_keys.
Открываем:
nano /home/tunneluser/.ssh/authorized_keys
Для remote forwarding полезен параметр permitlisten, если версия OpenSSH его поддерживает:
Публичная публикация требует дополнительных решений
frp/rathole
Много reverse endpoints за NAT
Инструменты специально для reverse proxy/tunneling
Нужны отдельные server/client-компоненты
Reverse SSH tunnel уместен, когда нужна минимальная зависимость от внешних платформ и понятная эксплуатационная модель на стандартных компонентах Linux.
28. Рекомендуемая production-схема
Итоговая модель:
Internet
│
│ HTTPS
▼
VPS: Caddy :443
│
│ reverse_proxy to loopback
▼
VPS: 127.0.0.1:11000
│
│ reverse SSH tunnel
▼
Home Server: 127.0.0.1:8080
Match User tunneluser
AllowTcpForwarding remote
GatewayPorts no
PermitTTY no
X11Forwarding no
AllowAgentForwarding no
PermitTunnel no
PasswordAuthentication no
PubkeyAuthentication yes
Критерий корректности: внешний пользователь видит только HTTPS-домен, а прикладные backend-порты недостижимы из интернета напрямую.
Заключение
Обратный SSH-туннель через VPS — простой и управляемый способ публикации домашних сервисов без белого IP-адреса и без входящего проброса портов на домашнем маршрутизаторе.
Сильная сторона подхода — использование стандартных компонентов: OpenSSH, systemd, autossh, Caddy и firewall. Слабая сторона — необходимость аккуратно удерживать границы доверия. Ошибочная публикация backend-портов, глобальное включение GatewayPorts yes, отключение проверки host key или использование привилегированного пользователя для туннеля могут превратить простую схему в рискованную.
Практически корректная модель:
Домашний сервер инициирует исходящее SSH-соединение.
VPS предоставляет только локальный tunnel endpoint.
Caddy принимает внешний HTTPS-трафик.
Firewall не публикует backend-порты.
SSH-пользователь ограничен задачей remote forwarding.
Для домашней лаборатории, Nextcloud, Home Assistant, Jellyfin, code-server, документационного портала или личного self-hosted-сервиса такая схема даёт разумный баланс между контролем, воспроизводимостью и эксплуатационной безопасностью.