惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

The Last Watchdog
The Last Watchdog
博客园_首页
Martin Fowler
Martin Fowler
S
SegmentFault 最新的问题
美团技术团队
小众软件
小众软件
V
V2EX
博客园 - Franky
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
The GitHub Blog
The GitHub Blog
Microsoft Security Blog
Microsoft Security Blog
Attack and Defense Labs
Attack and Defense Labs
S
Security Affairs
Simon Willison's Weblog
Simon Willison's Weblog
I
Intezer
T
The Exploit Database - CXSecurity.com
有赞技术团队
有赞技术团队
S
Schneier on Security
人人都是产品经理
人人都是产品经理
Security Archives - TechRepublic
Security Archives - TechRepublic
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
K
Kaspersky official blog
PCI Perspectives
PCI Perspectives
AI
AI
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
罗磊的独立博客
O
OpenAI News
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
The Register - Security
The Register - Security
V
Vulnerabilities – Threatpost
GbyAI
GbyAI
博客园 - 【当耐特】
C
Cisco Blogs
大猫的无限游戏
大猫的无限游戏
Help Net Security
Help Net Security
Google DeepMind News
Google DeepMind News
S
Securelist
Application and Cybersecurity Blog
Application and Cybersecurity Blog
P
Proofpoint News Feed
博客园 - 三生石上(FineUI控件)
雷峰网
雷峰网
L
LangChain Blog
SecWiki News
SecWiki News
博客园 - 叶小钗
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
V2EX - 技术
V2EX - 技术
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
J
Java Code Geeks
L
LINUX DO - 热门话题
Cisco Talos Blog
Cisco Talos Blog

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
VPS-бастион: доступ к домашнему серверу без белого IP
AriaQA · 2026-05-22 · via Все публикации подряд на Хабре

Уровень сложностиПростой

Время на прочтение12 мин

Охват и читатели22K

Туториал

Что имеем и зачем всё это

У вас дома крутятся полезные сервисы: Home Assistant, code-server или Nextcloud. Или вы только собираетесь их запустить. Пока вы дома, всё открывается по локальному IP. Но стоит выйти за пределы квартиры, и сервисы пропадают. Причина: провайдер выдал серый IP-адрес, то есть применяет CGNAT. Белый адрес получить либо нельзя (примерно, как советский дефицит), либо он стоит дополнительных денег.

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

  • Российские одноплатники. Repka Pi или Элтай ЭсСи (Eltay SC) от новосибирской компании «Элрон» на базе процессора «Скиф». Прямые аналоги Raspberry Pi на отечественной элементной базе.

  • Китайские одноплатники. Orange Pi, Banana Pi, Radxa. Доступны, имеют активные русскоязычные сообщества, часто предлагают лучшие характеристики за меньшие деньги.

  • Старый ноутбук или ПК. Самый народный путь. Мощности даже 10–15-летнего устройства с избытком хватит для домашнего сервера. У меня старенький, 14-летний Acer, рука не поднялась выбросить, поцарапанный, со сколами, но старый конь борозды не портит.

Возникает резонный вопрос: почему бы просто не арендовать VPS и не перенести все сервисы туда? Формально можно. Но у домашнего сервера есть преимущества, которых нет у VPS за 300–500 рублей:

  • Дисковое пространство. На домашнем сервере у вас может быть терабайт фотографий, фильмов и музыки. VPS с таким объёмом диска стоит совсем других денег.

  • Локальный доступ без интернета. Home Assistant продолжит управлять умным домом, даже если интернет пропадет. А фильмы и музыка будут доступны по локальной сети без задержек и без расхода трафика.

  • Приватность. Данные лежат у вас дома, а не в дата-центре. Для кого-то это важно, в том числе для меня.

  • Производительность. Старый ноутбук с i5 может быть мощнее бюджетного VPS с одним vCPU.

Поэтому мы не заменяем домашний сервер, а даём ему публичный адрес через недорогой VPS-бастион. Сам VPS выступает только как прокси и не хранит данные.

Что делаем. Мы арендуем VPS с публичным IP ( можно найти конфигурации за 300–500 рублей в месяц). На самом деле проверяйте актуальные цены у провайдеров, так как рынок очень динамичный. Этот VPS будет точкой входа, или бастионом. Домашний сервер сам установит SSH-соединение с VPS и скажет: «Всё, что придёт на твой порт 8123, пересылай мне на локальный порт 8123». Получается зашифрованный туннель из дома наружу, которому не страшен NAT провайдера.

Моя цель — показать не просто работающий, а безопасный и отказоустойчивый метод. Я расскажу, почему для ключа мы выбираем ed25519 с дополнительными раундами KDF, зачем отключаем пароль для пользователя туннеля, как autossh и systemd вместе держат соединение даже при обрывах сети. Всё это сделано, чтобы туннель не падал каждую ночь и чтобы злоумышленник не мог подобрать пароль или ключ.

Такой подход выгоден по нескольким причинам:

  • Не нужно открывать порты на роутере.

  • Трафик между вами и домом шифруется.

  • Работает с любым провайдером, даже если используется CGNAT.

  • Мы не зависим от сторонних сервисов (будь то заблокированный Cloudflare или отечественные решения вроде DDoS-Guard или Qrator Labs) и полностью контролируем свои данные.

Как работает обратный SSH-туннель

Механизм простой. Выполняя команду

ssh -R 8123:localhost:8123 tunneluser@vps_ip

домашний сервер просит удалённую сторону (VPS) начать слушать порт 8123 и всё, что на него приходит, отправлять обратно через это же SSH-соединение на локальный порт 8123 домашней машины.

Когда кто-то из интернета стучится на <IP_VPS>:8123, трафик проходит такой путь:

Клиент → VPS:порт 8123 → SSH-туннель → Домашний сервер:порт 8123

Соединение всегда инициируется изнутри дома наружу, поэтому NAT на стороне провайдера не мешает. Чтобы пробросить несколько сервисов, просто добавляют несколько ключей -R. Чтобы туннель сам восстанавливался после обрывов связи, используют autossh. Аutossh это умная обёртка над обычным SSH.

Шаг 1. Подготовка VPS

Подключаемся к VPS по SSH.

Первым делом открываем конфигурационный файл SSH-сервера:

sudo nano /etc/ssh/sshd_config

Нам нужно явно разрешить проброс портов на все сетевые интерфейсы. По умолчанию SSH пробрасывает порты только на loopback (127.0.0.1), и подключиться к ним извне не получится. Ищем или добавляем две строки:

GatewayPorts yes
AllowTcpForwarding yes
Настройка sshd_config в редакторе nano
Настройка sshd_config: разрешаем проброс портов на все сетевые интерфейсы

Настройка sshd_config: разрешаем проброс портов на все сетевые интерфейсы

Сохраняем файл и перезагружаем sshd, чтобы настройки применились:

sudo systemctl restart sshd

Теперь создадим отдельного пользователя, от имени которого домашний сервер будет устанавливать туннель. Использовать для этого root или своего обычного пользователя небезопасно: если злоумышленник завладеет ключом, он не должен получить возможность выполнять команды на VPS. Пользователю tunneluser мы это запретим, но пока создадим его с обычной оболочкой, чтобы скопировать ключ.

Создаём пользователя и задаём ему временный пароль:

sudo adduser tunneluser --disabled-password
sudo passwd tunneluser

Теперь с домашнего сервера копируем публичный ключ. На домашнем сервере выполните:

ssh-copy-id -i ~/.ssh/id_ed25519.pub tunneluser@<IP_VPS>

После ввода временного пароля ключ будет добавлен. Проверим, что вход работает:

ssh tunneluser@<IP_VPS> hostname

Появится имя VPS и сразу соединение закроется. Если ошибка тогда проверьте права на ~/.ssh и authorized_keys на VPS у пользователя tunneluser.

Теперь, когда ключ скопирован, меняем оболочку на /usr/sbin/nologin, чтобы пользователь не мог выполнять команды. Проброс портов через -R продолжит работать, потому что для этого не нужен shell.

sudo usermod -s /usr/sbin/nologin tunneluser

В некоторых дистрибутивах (включая Ubuntu) /usr/sbin/nologin отсутствует в файле /etc/shells. Тогда sshd при подключении с ключом может отказать, даже если выполняется только проброс. Добавим оболочку в список разрешённых:

echo /usr/sbin/nologin | sudo tee -a /etc/shells

Теперь от имени tunneluser создадим каталог .ssh и выставим правильные права. Временно переключимся в его окружение:

sudo su - tunneluser -s /bin/bash
mkdir -p ~/.ssh
chmod 700 ~/.ssh
exit
Создание каталога .ssh для пользователя tunneluser
Переключаемся в окружение tunneluser, создаём каталог .ssh и выставляем права 700

Переключаемся в окружение tunneluser, создаём каталог .ssh и выставляем права 700

Запретим вход по паролю для tunneluser. Снова откроем /etc/ssh/sshd_config и в конец добавим:

Match User tunneluser
    PasswordAuthentication no

Перезагружаем sshd:

sudo systemctl restart sshd

Теперь tunneluser сможет зайти только по ключу, пароль не сработает.

Также установим пакет psmisc, если его нет. В минимальных образах VPS утилита fuser может отсутствовать, а она понадобится скрипту для освобождения портов после обрыва туннеля.

sudo apt install -y psmisc
Установка пакета psmisc и управление паролем tunneluser
Устанавливаем psmisc (нужен для утилиты fuser) и задаём временный пароль

Устанавливаем psmisc (нужен для утилиты fuser) и задаём временный пароль

На этом подготовка VPS завершена.

Шаг 2. Настройка домашнего сервера

Все следующие команды выполняются на вашем домашнем устройстве: Raspberry Pi, Orange Pi, старом ноутбуке и так далее.

2.1. Генерируем SSH-ключ

Для аутентификации на VPS без пароля нам нужна пара ключей. Рекомендую использовать алгоритм ed25519: он быстрее и безопаснее, чем RSA, а ключи получаются короткими. Параметр -a 100 задаёт количество раундов KDF (функции формирования ключа). Если вы решите защитить приватный ключ паролем, это значительно замедлит попытки его подбора. В нашем случае ключ будет без пароля, чтобы autossh мог работать автоматически, но привычка указывать -a 100 полезна на будущее.

ssh-keygen -t ed25519 -a 100 -C "home-to-vps-tunnel"

На запрос пароля нажимаем Enter дважды оставляем пустым.

2.2. Устанавливаем autossh

Обычный SSH не умеет перезапускать туннель при обрыве. Если связь пропадёт, порты на VPS останутся «висеть» в занятом состоянии, и новый туннель не поднимется. autossh решает эту проблему: он мониторит состояние соединения и при необходимости перезапускает процесс.

sudo apt update
sudo apt install -y autossh

2.3. Список сервисов для проброса

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

sudo nano /etc/sshtunnels/services.conf

Пример содержимого:

# Home Assistant
8123:8123
# Jellyfin
8096:8096
# code-server
8443:8443
# SSH на домашний сервер (нестандартный порт, чтобы не мешать VPS)
2222:22

Формат: удалённый_порт_на_VPS:локальный_порт_домашнего_сервера. Строки, начинающиеся с #, игнорируются.

Обратите внимание на проброс SSH: домашний сервер станет доступен снаружи на порту 2222. Убедитесь, что на домашнем сервере также настроена аутентификация только по ключу, а вход по паролю отключён.

2.4. Пишем скрипт для запуска туннеля

Создадим скрипт, который будет читать services.conf и формировать команду для autossh.

sudo nano /usr/local/bin/tunnel-manager.sh

Скрипт выглядит так (замените REMOTE_HOST и путь к ключу на свои):

#!/bin/bash
REMOTE_USER="tunneluser"
REMOTE_HOST="123.123.123.123"         # ваш IP VPS
SSH_KEY="/home/pi/.ssh/id_ed25519"    # путь к приватному ключу
SSH_PORT="22"
CONFIG_FILE="/etc/sshtunnels/services.conf"

FORWARD_OPTS=""
while IFS=: read -r remote_port local_port; do
    # Пропускаем пустые строки и комментарии
    [[ -z "$remote_port" || "$remote_port" =~ ^# ]] && continue
    # Убиваем старые процессы на удалённом порту, если туннель упал и порт остался занят
    ssh -p "$SSH_PORT" -i "$SSH_KEY" "$REMOTE_USER@$REMOTE_HOST" \
        "command -v fuser && fuser -k ${remote_port}/tcp 2>/dev/null || true"
    FORWARD_OPTS="$FORWARD_OPTS -R ${remote_port}:localhost:${local_port}"
done < "$CONFIG_FILE"

echo "Запускаем туннели к $REMOTE_HOST с параметрами: $FORWARD_OPTS"

exec autossh -M 0 \
    -o "ServerAliveInterval=30" \
    -o "ServerAliveCountMax=3" \
    -o "ExitOnForwardFailure=yes" \
    -o "StrictHostKeyChecking=no" \
    -o "GatewayPorts=yes" \
    -N -T \
    -i "$SSH_KEY" \
    -p "$SSH_PORT" \
    $FORWARD_OPTS \
    "$REMOTE_USER@$REMOTE_HOST"
Скрипт запуска туннеля tunnel-manager.sh
Полный код скрипта tunnel-manager.sh. В строках REMOTE_HOST и SSH_KEY замените значения на свои.

Полный код скрипта tunnel-manager.sh. В строках REMOTE_HOST и SSH_KEY замените значения на свои.

Поясню ключевые моменты.

  • command -v fuser && fuser -k ... || true — сначала проверяем, есть ли fuser на VPS. Если нет, ничего не делаем, и код возврата всегда нулевой. Иначе скрипт мог бы упасть при отсутствии fuser.

  • ExitOnForwardFailure=yes — если по какой-то причине не удалось пробросить хотя бы один порт, SSH немедленно завершится. Тогда systemd зафиксирует падение и перезапустит скрипт.

  • StrictHostKeyChecking=no — отключает проверку отпечатка ключа хоста. Мы доверяем своему VPS, иначе при первом подключении система спросила бы подтверждение и скрипт завис. Если хотите усилить безопасность, выполните на домашнем сервере ssh-keyscan -H <IP_VPS> >> ~/.ssh/known_hosts и замените StrictHostKeyChecking=no на StrictHostKeyChecking=accept-new. В этом случае туннель примет только сохранённый отпечаток.

  • GatewayPorts=yes — на всякий случай дублирует глобальную настройку, гарантируя, что проброшенные порты будут слушать все интерфейсы.

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

  • -T — не выделять псевдотерминал, что уменьшает накладные расходы.

  • ServerAliveInterval=30 и ServerAliveCountMax=3 — каждые 30 секунд SSH отправляет keepalive-пакет. Если три пакета подряд не получат ответа, соединение считается разорванным, и autossh инициирует переподключение.

  • -M 0 — отключает встроенный мониторинговый порт autossh. Мы полагаемся на механизмы keepalive самого SSH и перезапуск через systemd.

Делаем скрипт исполняемым:

sudo chmod +x /usr/local/bin/tunnel-manager.sh

2.5. Создаём systemd-сервис

Чтобы туннель автоматически стартовал при загрузке системы, оформим его как службу systemd.

Пользователям Windows (WSL): стандартная установка WSL не использует systemd. Чтобы команды ниже работали, включите systemd: добавьте в /etc/wsl.conf строки:

[boot]
systemd=true

Затем перезапустите WSL командой wsl --shutdown в PowerShell и снова откройте терминал Ubuntu. Если systemd не нужен, просто запускайте туннель вручную через nohup, но тогда он не будет стартовать автоматически при загрузке.

Создаём файл службы:

sudo nano /etc/systemd/system/autossh-tunnel.service

Содержимое:

[Unit]
Description=Persistent SSH Reverse Tunnel to VPS
After=network-online.target
Wants=network-online.target

[Service]
Type=exec
ExecStart=/usr/local/bin/tunnel-manager.sh
Restart=always
RestartSec=20
StartLimitIntervalSec=0
Environment="AUTOSSH_GATETIME=0"
Environment="AUTOSSH_POLL=60"

[Install]
WantedBy=multi-user.target
Файл службы
Содержимое unit-файла для автоматического запуска и перезапуска туннеля

Содержимое unit-файла для автоматического запуска и перезапуска туннеля

Параметры:

  • After=network-online.target — служба стартует только после полной инициализации сети.

  • Restart=always — перезапускать при любом завершении, кроме явной остановки через systemctl stop.

  • RestartSec=20 — ждать 20 секунд перед повторной попыткой. Небольшая пауза полезна, чтобы не заддосить VPS при быстро повторяющихся ошибках.

  • AUTOSSH_GATETIME=0 — считать первое соединение успешным сразу, без задержки.

  • AUTOSSH_POLL=60 — интервал, с которым autossh опрашивает состояние соединения (в дополнение к ServerAliveInterval).

Шаг 3. Запуск и проверка

Перед запуском туннеля на VPS нужно открыть порты, которые мы будем пробрасывать. Иначе туннель установится, но подключиться извне не получится. Выполните на VPS:

sudo ufw allow 8123/tcp
sudo ufw allow 8096/tcp
sudo ufw allow 8443/tcp
sudo ufw allow 2222/tcp
sudo ufw enable

Если вы пробрасываете дополнительные порты, откройте и их, например sudo ufw allow 8080/tcp.

Теперь на домашнем сервере активируем и запускаем службу:

sudo systemctl daemon-reload
sudo systemctl enable autossh-tunnel
sudo systemctl start autossh-tunnel

Проверяем статус:

sudo systemctl status autossh-tunnel

Теперь возьмите телефон, отключите Wi-Fi (чтобы трафик шёл через мобильную сеть) и откройте браузер. В адресной строке введите http://<IP\_VPS>:8123. Должен открыться интерфейс Home Assistant. Аналогично проверьте Jellyfin на порту 8096 и другие сервисы.

Доступ к домашнему серверу через мобильную сеть
Доступ с телефона через мобильную сеть

Доступ с телефона через мобильную сеть

Для контроля можно проверить проброс на VPS:

ss -tulpn | grep 8123

Если не работает:

  • Убедитесь, что на домашнем сервере сервис действительно слушает нужный порт: ss -tulpn | grep 8123. Если ss отсутствует, используйте netstat -tulpn | grep 8123 или lsof -i :8123.

  • Проверьте, не занят ли этот порт на самом VPS каким-то процессом: ss -tulpn | grep 8123.

  • Возможно, на VPS включен файрвол ufw, и порты закрыты. Разрешите их, как описано выше.

  • Если на VPS не найдена утилита fuser, установите её: sudo apt install -y psmisc. Она нужна скрипту для очистки портов после обрыва туннеля.

Типичная ситуация: если VPS перезагрузился в тот момент, когда туннель был активен, порты на VPS могут на короткое время остаться в состоянии TIME_WAIT. autossh с настройками выше переподнимет соединение, но возможна задержка до минуты. Если порт долго не освобождается, зайдите на VPS и проверьте ss -tulpn | grep <порт>. При необходимости завершите зависший процесс вручную.

Шаг 4. Базовая безопасность

4.1. Файрвол на VPS

Мы уже открыли нужные порты в ufw. Если вы всегда подключаетесь с одного IP (например, с работы), можно дополнительно ограничить доступ к чувствительным сервисам:

sudo ufw allow from <ваш_статический_IP> to any port 8123

После настройки Caddy и переноса сервисов на HTTPS прямые порты рекомендуется закрыть (см. раздел 4.3).

4.2. Регулярная замена ключей

Раз в полгода генерируйте новую пару ключей на домашнем сервере и заменяйте публичный ключ на VPS в /home/tunneluser/.ssh/authorized_keys. Так вы перестрахуетесь на случай, если старый ключ скомпрометируют, то есть попросту угонят.

4.3. HTTPS для сервисов

Пока мы ходим по HTTP, трафик не зашифрован между клиентом и VPS. Чтобы это исправить, нужен обратный прокси с SSL. Самый простой вариант — Caddy, потому что он автоматически получает сертификаты Let’s Encrypt и требует минимум настроек.

Установка на VPS:

sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy

Конфигурация (/etc/caddy/Caddyfile):

hass.my-domain.ru {
    reverse_proxy localhost:8123
}

jellyfin.my-domain.ru {
    reverse_proxy localhost:8096
}

code.my-domain.ru {
    reverse_proxy localhost:8443
}
Конфигурация Caddy для HTTPS и обратного прокси
Пример Caddyfile с поддоменами для Home Assistant, Jellyfin и code-server

Пример Caddyfile с поддоменами для Home Assistant, Jellyfin и code-server

Примечание: для автоматического HTTPS нужен реальный домен, направленный A-записью на IP вашего VPS. Если домена пока нет, Caddy можно использовать как обычный обратный прокси. Минимальная конфигурация для теста:

:80 {
    reverse_proxy localhost:8080
}

После привязки домена замените :80 на ваш поддомен (например, hass.my-domain.ru) — Caddy сам запросит сертификат и настроит HTTPS.

Перезапуск:

sudo systemctl restart caddy

Проверим локально, что Caddy проксирует запросы:

curl -I http://localhost:80
Проверка работы Caddy
Ответ curl -I http://localhost:80 подтверждает, что Caddy проксирует запросы (HTTP 200 OK)

Ответ curl -I http://localhost:80 подтверждает, что Caddy проксирует запросы (HTTP 200 OK)

Caddy сам запросит сертификаты, и через минуту ваши сервисы будут доступны по HTTPS с человеческими адресами. После того как Caddy заработал, прямые порты можно закрыть, чтобы сервисы не светились по HTTP:

sudo ufw delete allow 8123/tcp
sudo ufw delete allow 8096/tcp
sudo ufw delete allow 8443/tcp

Теперь трафик будет ходить только через зашифрованные соединения на 443 порт.

При желании можно добавить запрос пароля на уровне Caddy:

sudo apt install apache2-utils
htpasswd -c /etc/caddy/.htpasswd username

И в блок сервиса добавить:

hass.my-domain.ru {
    basicauth {
        username $2a$14$...
    }
    reverse_proxy localhost:8123
}

Хэш пароля берётся из созданного файла.

Примечание: при использовании обратного прокси все сервисы будут видеть запросы как пришедшие с 127.0.0.1, что может мешать анализу логов. В продвинутых сценариях это исправляется добавлением в конфигурацию Caddy директивы trusted_proxies и пробросом реального IP клиента. Для базовой установки такое поведение обычно не критично.

Шаг 5. Задержка

Добавление VPS в цепочку неизбежно увеличивает пинг, но SSH-туннель вносит минимальный оверхед. Если VPS находится в том же регионе, что и вы, задержка вырастает на 2–8 миллисекунд. Это практически незаметно при работе с веб-интерфейсами и передаче команд.

Альтернативы

Если autossh и ручная настройка кажутся громоздкими, можно посмотреть на утилиты вроде rathole, frp или bore. Они тоже делают проброс портов, но требуют установки своего ПО как на домашний сервер, так и на VPS. Наш метод хорош тем, что на VPS не нужно ставить ничего, кроме штатного SSH-сервера, который уже есть в любой Ubuntu.

Итог

Теперь у вас есть полноценный доступ к домашним сервисам из любой точки мира. Всё, что для этого потребовалось: VPS за 300–500 рублей в месяц и полчаса на настройку. Туннель работает прозрачно и шифрует трафик по пути. Самое важное: мы сделали его устойчивым к обрывам и защищённым от самых очевидных атак. Надеюсь, этот туториал поможет вам наладить свою инфраструктуру без лишней головной боли. Если что-то пошло не так, заглядывайте в логи journalctl -u autossh-tunnel и пишите в комментариях, разберёмся вместе.