Перейти к содержанию

Осталось реализовать

Десять дней назад я завершил разбор схемы доставки конфигурации клиентам и поставил точку в характерном стиле: «схема зафиксирована в документации. Осталось дело за малым: реализовать». Такие фразы в дневнике проекта — опасный знак. Звучат оптимистично, будущее кажется близким — а через месяц смотришь на них с тихой укоризной.

На этот раз пронесло. Сегодня сервис запущен.

Мехинизм подписки #

Напомню суть проблемы — в том посте я объяснял, почему статичная VLESS-ссылка — это ахиллесова пята. Мы научились менять gRPC-пути между Entry- и Core-нодами автоматически, по расписанию. Но клиент об этом ничего не знает: у него на руках ссылка, скопированная при регистрации, и она рано или поздно устаревает.

Решение — механизм подписки. Вместо статичной ссылки пользователь получает один адрес:

https://<домен>/api/<UUID>

Клиентское приложение периодически обращается к нему и само забирает актуальную конфигурацию. Поменялся serviceName — следующий запрос вернет обновленную ссылку. Заменили Entry-ноду — перенаправили DNS, URL подписки остался тем же. Пользователю не нужно ничего делать — система сама обновляет конфигурацию, без лишних телодвижений.

Архитектура микросервиса #

Теперь об устройстве изнутри.

Микросервис небольшой — около 270 строк Python. FastAPI, четыре слоя с однонаправленными зависимостями, функциональный стиль. Никаких баз данных: данные берутся из локального клона репозитория с данными, который уже живет на Core-ноде и синхронизируется каждые 15 минут.

Логика одного запроса: UUID из пути → проверить устройство → проверить пользователя → найти активные маршруты для этой Core-ноды → для каждого маршрута подобрать домен Entry-ноды → собрать VLESS-ссылку → упаковать в base64 и вернуть. Один ответ может содержать несколько ссылок — если у пользователя есть доступ через несколько Entry-нод. Если устройство заблокировано, пользователь неактивен или маршрутов нет — просто 404, без подробностей.

Сервис упакован в Docker, запущен на Core-ноде. Nginx проксирует /api/ на localhost, снаружи сервис недоступен напрямую. CI/CD по знакомой схеме: пуш в main → GitHub Actions → SSH → git pull + docker compose up --build. Развернулось само, без единого ручного действия на сервере.

FastAPI #

Чуть раньше я писал о том, что этот микросервис — хороший повод наконец попробовать Go в деле. Язык уже присутствует в проекте повсюду: Hugo, тема, будущий etcd — всё Go. Было бы логично вписать в эту картину и сервис подписки.

Но в том же посте я честно оговорился: первый рабочий вариант — на FastAPI. Привычно, без сюрпризов, быстро до результата. Так и вышло. Прототип написан на Python, работает, задачу решает.

Go никуда не делся — просто это следующий шаг. Когда-нибудь перепишем.

Итоги #

Что это меняет на практике.

Раньше при любом изменении — смене ноды, обновлении пути, плановой ротации — каждому пользователю нужно было как-то доставить новую ссылку. Сейчас инфраструктура может меняться независимо: клиенты получат обновленную конфигурацию при следующей синхронизации сами.

«Осталось дело за малым: реализовать». Ну и вот. Реализовали.