Как я построил автоматический сервис защиты данных с нуля
Идея простая: человек регистрируется, оплачивает, получает ключ на почту и сразу подключается. Никакой ручной работы с моей стороны. Расскажу как это устроено под капотом.
Стек и почему именно он
Backend: FastAPI (Python)Выбрал за нативную async поддержку — платёжные вебхуки, запросы к VPN API и отправка писем должны работать параллельно без блокировок. SQLAlchemy async + PostgreSQL для хранения пользователей, подписок и платежей.
Frontend: React + Vite + TailwindSPA с несколькими страницами: лендинг, личный кабинет, оплата, помощь. Vite даёт быструю сборку, Tailwind — быструю вёрстку без написания CSS с нуля.
VPN-backend: Marzban Готовая панель управления XRay с REST API. Не стал писать управление XRay вручную — Marzban уже умеет создавать пользователей, выдавать ключи, считать трафик. Интегрируется через обычный HTTP.
Инфраструктура: Docker Compose + Nginx + CloudflareНесколько контейнеров за реверс-прокси. Cloudflare перед всем — скрывает реальный IP серверов.
Marzban интеграция
Самая интересная часть. После подтверждения оплаты backend автоматически создаёт пользователя в Marzban:
asyncdefcreate_user(self, username:str, months:int)->dict: expire_ts = _months_to_timestamp(months) payload ={"username": username,"proxies":{"vless":{"flow":"xtls-rprx-vision"}},"inbounds":{"vless":["VLESS Reality"]},"expire": expire_ts,"data_limit":0,} resp =await client.post(f"{MARZBAN_URL}/api/user", json=payload)return resp.json()
Marzban возвращает готовый vless://... ключ который пользователь вставляет в AmneziaVPN или Hiddify. Токен Marzban кешируется на 55 минут чтобы не делать лишних запросов.
Автоматическая доставка ключа
После активации платежа:
- Создаём пользователя в Marzban → получаем vless:// ключ
- Сохраняем подписку в PostgreSQL
- Отправляем письмо через Resend с ключом и пошаговой инструкцией
Письмо содержит три шага прямо в теле — скачать приложение, скопировать ключ, вставить. Конверсия выросла после того как добавили инструкцию прямо в email вместо просто ссылки на сайт.
Триал: 3 дня без карты
Хотел дать пробный период без привязки карты. Реализовал через верификацию email:
- Регистрация → письмо со ссылкой подтверждения
- Пользователь кликает → создаётся пробная подписка на 3 дня в Marzban
- Письмо с ключом приходит автоматически
Защита от злоупотреблений — поле trial_used в модели пользователя. Один email — один триал.
Подводные камни
Идемпотентность вебхуков — платёжные системы при таймауте повторяют запрос. Без проверки на дубли получал несколько одинаковых писем и задвоенные подписки. Решение: проверка статуса платежа перед активацией.
Cloudflare + IP-whitelist — после подключения Cloudflare вебхуки от платёжной системы перестали проходить проверку IP, потому что запросы приходят с IP Cloudflare. Перенёс проверку в backend через заголовок CF-Connecting-IP.
Сетевая связность в Docker — backend-контейнер не может достучаться до сервисов на localhost хоста. Решение: socat проксирует трафик через bridge-интерфейс Docker.
Итог
Полный путь от регистрации до работающего ключа занимает несколько секунд после оплаты. Ручной работы ноль.
Из неочевидного: самые сложные места — идемпотентность вебхуков и сетевая связность между контейнерами и внешними сервисами.
Здесь можете посмотреть что из этого получилось - https://data-shield.ru