Как я хотел просто поднять VPN для семьи и в итоге собрал свой сервис
Изначально задача была простой: родителям нужен был VPN, и стоял выбор между готовой Amnezia Premium и собственным сервером. Они в итоге купили Amnezia VPN, а мне стало интересно, насколько вообще сложно арендовать дешёвый VPS, поставить на него VPN и раздать несколько ключей своим.
До этого я уже смотрел ролики про VPS, WireGuard, VLESS и self-hosted VPN. Со стороны всё выглядело довольно понятно: покупаешь сервер, устанавливаешь нужный протокол, создаёшь конфиги и пользуешься. Поэтому я решил попробовать сделать свой вариант.
Сейчас это уже три сервера, около 12 маршрутов, AmneziaWG, Hysteria2, VLESS XHTTP, Telegram-бот, подписки для Happ и собственная админка. Но начиналось всё с одного дешёвого VPS и довольно неудачного знакомства с первым хостером.
Первый VPS и Xorek
Первый сервер я купил у Xorek. Закинул на баланс около 500 рублей и заказал VPS, насколько помню, в Нидерландах.
После выдачи сервера я попробовал подключиться по SSH и не смог. Поскольку это был один из моих первых нормальных опытов с VPS, сначала решил, что проблема у меня. Почти весь день проверял подключение, настройки, порты и пытался понять, что именно делаю неправильно.
В какой-то момент стало понятно, что дело, скорее всего, на стороне хостера. Я написал в поддержку и попытался вернуть деньги. Там мне агент поддержки сказал что для возврата средств мне прийдется отправлять письмо в лондон, где будет номер моей услуги подпись и т.д.
Мягко говоря, меня обули. Я закинул около 500 рублей, получил VPS, на котором не работал даже SSH, а нормального способа вернуть деньги на карту мне не предложили. Корчить из себя дипломата я не стал и на остаток баланса взял promo-сервер за 200 рублей. На нём я и начал экспериментировать с VPN.
От AmneziaWG к нескольким протоколам
Изначально основной идеей была AmneziaWG. Параллельно я попробовал обычный WireGuard. Один знакомый из России рассказывал, что у него он работает нормально, поэтому я решил проверить его у себя. У меня WireGuard нормально не заработал, поэтому основной вариант остался на AmneziaWG.
Я также пробовал стандартное автоматическое развёртывание через приложение Amnezia. Для личного использвоания и пары родстеников чтобы не заморачиваться - сойдет. Но для автоматизации и выхода за круг "пары родствеников" пришлось уже делать что то большее. Поэтому я перешел к ручной настройке и созданию самописной админки.
Позже начал экспериментировать с VLESS. На моём устройстве первая конфигурация работала, но после передачи тому же другу соединение уже не устанавливалось. На тот момент я не стал долго разбираться именно с этим вариантом и продолжил искать протокол, который будет проще использовать сразу у нескольких людей.
В какой-то момент на форуме я наткнулся на Hysteria2. Развернул её на сервере, создал ключи и отдал нескольким пользователям. В этот раз всё заработало заметно стабильнее, поэтому Hysteria2 постепенно стала одним из основных протоколов проекта.
Позже я всё-таки вернулся к VLESS, но уже к связке VLESS + XHTTP + TLS. Этот вариант у меня показал себя достаточно быстрым и стабильным, поэтому я оставил его как ещё один маршрут.
В процессе экспериментов изменилась и сама идея проекта. Сначала я искал один протокол, который можно поставить и дальше особо не трогать. На практике разные сети вели себя по-разному. То, что работало у одного человека, могло вообще не подключаться у другого.
Поэтому вместо поиска одного «идеального» протокола я пришёл к схеме с несколькими независимыми вариантами подключения. Сейчас AmneziaWG остаётся отдельным вариантом, а Hysteria2 и VLESS входят в общую систему маршрутов.
Смысл в том, чтобы пользователь не зависел от единственного подключения. Если конкретный маршрут у его оператора работает плохо или перестаёт работать совсем, должны оставаться другие.
От ручной выдачи к Telegram-боту
В первой версии проекта никакой автоматизации не было. Если кому-то нужен был доступ, я заходил на сервер, создавал конфигурацию и отправлял её вручную.
Когда пользователей несколько, это не проблема. Но каждый новый человек означает ещё одну конфигурацию, а потом возможное продление, перевыпуск ключа или изменение доступа. Чем больше появлялось пользователей и протоколов, тем меньше хотелось продолжать делать это руками.
Поэтому я решил автоматизировать выдачу через Telegram. Так появился бот, который со временем стал основной точкой входа в сервис.
Сейчас через него пользователь может получить доступ на определённый срок, активировать промокод или пройти сценарий оплаты. После активации система создаёт необходимые записи на серверной стороне и выдаёт подписку для подключения.
Вместе с ботом появилась уже обычная для такого сервиса логика: пользователи, сроки подписок, блокировки, типы клиентов, токены подписок и различные состояния доступа. И вот примерно здесь проект начал уходить от формата «на сервере лежит несколько VPN-конфигов».
Сам VPN при этом оставался важной частью, но вокруг него уже появлялась система, которая должна была понимать, кому и на какой срок можно подключаться, что делать после окончания подписки и какие конфигурации конкретному пользователю нужно отдавать.
Почему в итоге появилась одна подписка
Пока есть один протокол, пользователю можно просто отдать один конфиг. Когда серверов и вариантов подключения становится много, такая схема быстро становится неудобной.
Мне не хотелось объяснять каждому человеку, какой из нескольких Hysteria2 нужно выбрать, когда переключаться на VLESS и какой сервер стоит попробовать первым. Пользователь вообще не обязан знать, чем эти протоколы отличаются.
Поэтому в проекте появился Happ.
Идея была в том, чтобы вместо набора отдельных конфигураций выдавать одну ссылку подписки. На серверной стороне я могу менять список маршрутов, а пользователь после обновления получает актуальную конфигурацию в приложении.
На первый взгляд эта часть выглядит довольно простой. Сервер формирует список, клиент его получает. На практике именно вокруг подписок оказалось очень много мелких доработок.
Приходилось менять формат Hysteria2, исправлять генерацию URI, работу токенов и совместимость с Happ. Отдельно дорабатывалась авторизация: сервер должен понимать, существует ли пользователь, действует ли его подписка и можно ли ему сейчас подключаться.
Некоторые проблемы проявлялись не при первом запуске. Пользователь мог нормально добавить подписку, подключиться и какое-то время пользоваться VPN, а ошибка появлялась позже при обновлении или повторном подключении.
Из-за этого со временем пришлось изменить подход к тестированию. Теперь недостаточно проверить, что новая подписка один раз успешно открылась. Нужно проверить её обновление, окончание срока действия, блокировку и то, что уже существующие клиенты не ломаются после изменений на сервере.
От одного VPS к нескольким серверам
Первое время вся инфраструктура работала на одном сервере. Для небольшого количества пользователей этого вполне хватало, пока сам сервер был доступен.
Недавно возникла уже совсем другая проблема: произошла авария в дата-центре, где находился мой сервер в Германии. Дата-центр залило, сервер начал работать нестабильно, и пришлось довольно быстро поднимать новую машину в Нидерландах.
Некоторое время я ждал, пока на немецком сервере хотя бы восстановится нормальный доступ по SSH. Когда это произошло, забрал необходимые данные и развернул всё на новом узле.
Позже немецкий сервер полностью восстановился. Возвращаться после этого к схеме, где вся инфраструктура зависит от одной машины, мне уже не хотелось, поэтому я оставил его в работе. Ещё позже добавился сервер в Финляндии.
Сейчас инфраструктура распределена между Германией, Финляндией и Нидерландами. На этих серверах работает около 12 маршрутов, не считая логики автоматического выбора.
После появления нескольких серверов возникла и отдельная задача с их развёртыванием. Если каждый новый регион полностью собирать вручную, довольно быстро начнёшь повторять одни и те же действия.
Поэтому в проекте появилась идея edge-нод. Новый сервер можно подготовить под несколько экземпляров Hysteria2 и VLESS XHTTP, зарегистрировать в центральной системе и после этого добавить новые маршруты в уже существующие пользовательские подписки.
В итоге добавление нового сервера не должно означать, что всем пользователям нужно что-то заново настраивать. С их стороны остаётся та же подписка, меняется только то, что сервис отдаёт внутри неё.
Админка и центральное управление
Идея собственной админки появилась достаточно рано. Если выдавать пользовательские конфиги через терминал неудобно, то управлять всеми этими пользователями через тот же терминал со временем становится не менее неудобно.
Мне нужно было видеть в одном месте пользователей, их подписки, созданных клиентов и сроки доступа. Один знакомый советовал поставить 3x-ui. Я этот вариант рассматривал, но в итоге решил делать управление под собственную архитектуру.
Админка долго развивалась и пережила несколько переделок. Сейчас это отдельное приложение на FastAPI, которое работает с общей базой и используется для управления пользователями, VPN-клиентами, подписками и частью инфраструктуры.
Постепенно центральная часть проекта стала выполнять роль control plane. Telegram-бот отвечает за пользовательский сценарий, админка нужна для управления, а отдельные VPN-серверы уже непосредственно обслуживают соединения.
При изменениях в центральной системе нужные конфигурации синхронизируются с серверами. Это особенно важно для протоколов, где список разрешённых клиентов должен оставаться актуальным на разных узлах.
AmneziaWG в этой упрощённой схеме стоит немного отдельно, но общая идея именно такая: пользователь взаимодействует с одной системой, а сервера и маршруты внутри неё можно менять независимо.
Во что проект превратился сейчас
Если сравнить текущую систему с первой версией, от первоначальной идеи «один VPS и несколько конфигов» осталось довольно мало.
Сейчас есть три сервера, около 12 маршрутов, AmneziaWG, Hysteria2 и VLESS XHTTP. Пользователь получает доступ через Telegram-бота, маршруты приходят через подписку Happ, а управлять системой можно через собственную админку. Новые edge-узлы можно подключать к центральной части и добавлять в уже существующие подписки.
При этом проект пока остаётся небольшим. До этого он в основном тестировался на своём круге пользователей. Сценарий оплаты уже реализован, но как полноценный коммерческий сервис я его ещё не запускал.
Сейчас мне интересно попробовать вывести его из режима «для своих» и посмотреть, насколько вся эта схема будет работать уже на более широком круге пользователей.
Если интересно посмотреть, во что в итоге превратился этот эксперимент, оставлю здесь. телеграм бот @deyttbot
Дальше я хочу двигаться примерно в том же направлении: добавлять новые варианты подключения, улучшать автоматический выбор маршрутов и постепенно убирать технические детали из пользовательского сценария. Если всё работает нормально, человеку вообще не должно быть важно, на каком сервере он сейчас сидит и какой протокол используется внутри. Для него это должна оставаться одна подписка и обычная кнопка подключения.