Skip to content
anysdaPublic

About

Self-hosted multi-node VPN platform: WG/OVPN/IKEv2 entry + Hysteria2 exits. Web panel, Telegram bot, auto-routing, smart failover, AdGuard DNS, monitoring.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

anysda-vpn2

Самостоятельный VPN-сервис с веб-панелью: одна entry-нода в России, одна или несколько exit-нод за рубежом, три протокола для клиентов (WireGuard, OpenVPN, IKEv2), маршрутизация по географии, DNS с фильтрацией рекламы и Telegram-бот. Ставится одной командой на чистые серверы.

🚀 Сразу деплоить → Quickstart

Обзор

Обзор: события панели, трафик за сутки, нагрузка на экзиты, DNS с долей блокировок. Ниже - карточки нод (CPU, iowait, RAM, статус), календарь активности клиентов, топ клиентов по трафику и счётчики онлайн/офлайн.

Клиенты

Клиенты и ключи: список с трафиком за сегодня, экзитом и сроком доступа, фильтры «истекают» и «заморожены», рассылка от бота. Справа - карточка клиента: срок, суммарный трафик, привязка к Telegram-боту, лимит устройств, предпочитаемый экзит. Снизу - устройства с трафиком и кнопками: WG (.conf/QR), OVPN (.ovpn), IKEv2 (сервер, Remote ID, логин, пароль и CA при работе без домена), перевыпуск ключей, удаление; заморозка и удаление клиента.

Возможности

  • Три протокола. WireGuard, OpenVPN и IKEv2/IPsec на одной entry-ноде. IKEv2 работает штатными клиентами iOS, macOS, Windows и Android без сторонних приложений.
  • Клиенты и устройства. Клиент - это человек, у него несколько устройств. У каждого устройства свои ключи WireGuard, сертификат OpenVPN и логин IKEv2. Лимит устройств, срок доступа, заморозка, перевыпуск ключей - из панели или из бота.
  • Маршрутизация по географии. Российский трафик уходит напрямую с entry-ноды, зарубежный - через Hysteria2 на лучший экзит. Экзит падает - сторож переключает на другой за 10-14 секунд, живые соединения не рвутся. Подробности: docs/routing.md, docs/failover.md.
  • Ручные правила. Домен, IP или подсеть на конкретный экзит, перетаскиванием в панели. Применяется на ходу, без перезапуска и без обрыва соединений.
  • Предпочитаемый экзит клиента. Весь зарубежный трафик клиента через выбранную страну. Экзит пропал - трафик временно идёт через общий выбор, вернулся - возвращается сам.
  • YouTube без рекламы (опционально). YouTube выводится с российского адреса entry-ноды, где реклама не показывается, а блокировка DPI обходится десинхронизацией TLS (zapret2). Видеопоток проверяется каждые пять минут; если обход сломался, YouTube уходит на экзиты. Подробности: docs/youtube.md.
  • Локальная сеть не ломается. Домашние адреса (RFC1918, CGNAT, multicast) не уезжают в туннель: роутер, NAS, принтер и Chromecast остаются доступны при поднятом VPN.
  • DNS с фильтрацией. AdGuard Home для клиентов с включённой фильтрацией, управление - во вкладке «DNS» панели. Подробности: docs/adguard.md.
  • Telegram-бот. Администратор управляет клиентами и получает алерты. Конечный клиент по ссылке-приглашению сам скачивает конфиги, добавляет устройства и видит уведомления.
  • Мониторинг. Нагрузка нод, трафик за сутки, задержка до экзитов, активность клиентов - в панели.
  • Резервные копии. Один зашифрованный архив со всем нужным для восстановления entry-ноды, по расписанию, локально или в S3. Подробности: docs/backup.md.
  • Вход в панель. Один администратор, по желанию TOTP или SSO через OIDC-провайдера (проверено на Authentik): docs/sso.md.

Как это устроено

клиент WireGuard · OpenVPN · IKEv2
   │
   ▼
entry-нода (Россия)
 ├─ WireGuard / OpenVPN / strongSwan  →  sing-box (TPROXY)
 ├─ sing-box: ручные правила → YouTube → РФ напрямую → остальное на экзит
 ├─ сторож экзитов: пробы, переключение, балансировка
 ├─ zapret2: обход DPI для YouTube
 ├─ панель (Caddy, Let's Encrypt), AdGuard Home, VictoriaMetrics, бот
 │
 └─ Hysteria2 ──► exit-нода nl / fi / us / … ──► интернет

Exit-ноды связаны с entry-нодой туннелями Hysteria2 и служебной mgmt-сетью. У каждого экзита два пути: прямой и через Cloudflare WARP. Полная схема правил - docs/routing.md.

Стек. Nuxt 4 (Vue 3, TypeScript) · Nuxt UI 4 · Drizzle ORM + SQLite · better-auth · sing-box · WireGuard · OpenVPN · strongSwan · AdGuard Home · VictoriaMetrics + node_exporter · Caddy · Python (python-telegram-bot).

Структура репозитория.

app/            панель (Nuxt 4)
infra/          деплой: стадии, шаблоны конфигов, сторож экзитов, тесты
telegram/       бот
deploy.sh       точка входа деплоя
setup.sh        интерактивный мастер config.yaml
config.example.yaml
docs/           инструкции и скриншоты

Документация.

Файл О чём
docs/routing.md порядок правил sing-box, ручные маршруты, сплит-туннель, IPv6, почему не ходит ping, QUIC
docs/failover.md сторож экзитов: пороги, дорожки и балансировка, выход бота, ручное выключение экзита
docs/youtube.md YouTube мимо экзитов: отбор трафика, стратегия десинка, A/B-проверка, видеопроба
docs/backup.md состав архива, хранение, ротация, восстановление entry-ноды с нуля
docs/adguard.md AdGuard Home: прямой вход, учётка, лимиты
docs/sso.md вход в панель через OIDC (Authentik)
docs/speedtest.md BBR и Brutal на Hysteria2, замер скорости через туннель на стенде

🚀 Quickstart — развернуть с нуля

Нужны: одна entry-нода в России и N exit-нод (минимум одна, лучше две-три для отказоустойчивости). Чистая Ubuntu 24.04 или 26.04, root по SSH-паролю. Деплой запускается с entry-ноды, она же оркестратор.

Нода Минимум Рекомендуется
entry 1 vCPU, 2 ГБ RAM, 10 ГБ 2 vCPU, 2 ГБ RAM, 20 ГБ
exit 1 vCPU, 1 ГБ RAM, 5 ГБ 1 vCPU, 2 ГБ RAM, 10 ГБ

Entry-нода упирается в процессор: один vCPU занят полностью уже на ~120 Мбит/с суммарно. Swap не нужен, лимиты служб подбираются по памяти.

0. Домен (если нужен HTTPS). Направьте A-запись vpn.example.com → <entry-ip> заранее: DNS расходится до четырёх часов, иначе Caddy не получит сертификат при первом запуске. Только A-запись, без AAAA.

1. Зайти на entry-ноду.

ssh root@<entry-ip>

Если до этого сделать ssh-copy-id root@<entry-ip>, деплой подхватит ваш ключ и разложит его на все exit-ноды. Без этого оркестратор сгенерирует свой.

2. Склонировать репозиторий.

git clone https://github.com/anysda/vpn2 /opt/anysda-vpn2
cd /opt/anysda-vpn2

3. Заполнить конфиг мастером. Ответы попадут в config.yaml.

./setup.sh

4. Запустить деплой.

./deploy.sh

Деплой ставит зависимости, проверяет SSH ко всем нодам, поднимает mgmt-сеть и Hysteria2 на exit-нодах, а на entry-ноде - VPN-серверы, роутер, сторож, AdGuard, мониторинг, панель и бота. Повторный запуск безопасен: стадии идемпотентны.

5. Создать первого клиента. В панели «Новый клиент» → имя → в карточке клиента «+ девайс» → имя. Дальше кнопки WG (.conf или QR), OVPN, IKEv2.

Пароль администратора, если не задан в конфиге, генерируется при первом деплое и лежит в /etc/anysda/admin-password.txt на entry-ноде.


Настройка

Всё задаётся в config.yaml, образец с комментариями - config.example.yaml. После правки конфига перезапустите ./deploy.sh целиком или нужную стадию.

Порты и параметры клиентских VPN

ports:
  wireguard: 51820      # UDP
  openvpn: 1194         # UDP или TCP
openvpn:
  proto: udp            # udp | tcp, с суффиксами 4/6
wireguard:
  mtu: 1420             # 1280..9000, MTU клиента и MSS сервера
  split_local: true     # обход локальных сетей клиента (WG и OpenVPN)

Применить: ./deploy.sh 28-wireguard ru, ./deploy.sh 29-openvpn ru, ./deploy.sh 30-frontend ru. После смены порта, протокола, MTU или обхода локальных сетей клиентам нужно скачать конфиги заново, ключи перевыпускать не нужно. Порт должен быть открыт во внешнем firewall хостера.

Домен и IKEv2

Укажите panel.domain, направьте A-запись и запустите ./deploy.sh. Caddy получит сертификат Let's Encrypt, панель перейдёт на HTTPS. IKEv2 до этого работает по IP со своим CA, после - автоматически переключается на домен и доверие к Let's Encrypt. Профили IKEv2, выданные до подключения домена, нужно скачать заново: меняются сервер и Remote ID, логин и пароль остаются. Диагностика: journalctl -u anysda-ikev2-cert-sync -u caddy.

YouTube мимо экзитов

youtube:
  route: zapret         # off | zapret | direct
  quic: block           # QUIC режется намеренно, десинк проверен на TCP

Проверка - только A/B, статус юнита ничего не доказывает:

ssh root@<entry> anysda-yt-check                    # 0 = обход живой
ssh root@<entry> 'journalctl -u anysda-yt-failover'  # журнал видеопробы

Если обход не проходит: youtube.offload: off, подобрать стратегию через /opt/zapret2/blockcheck2.sh и записать в youtube.strategy, либо youtube.route: off. Как это работает и что проверяет видеопроба - docs/youtube.md.

Сторож экзитов

Раз в две секунды сторож пробует каждый экзит. Три промаха подряд - экзит считается мёртвым, новые соединения идут на другой, живые дорабатывают на старом. Устройства разложены по 32 дорожкам, сторож держит каждую на быстром экзите и выравнивает нагрузку. Экзит можно выключить вручную в карточке экзита в панели. Пороги, балансировка и выход бота - docs/failover.md.

Стадии 20 (роутер) и 21 (сторож) обновляйте вместе:

./deploy.sh 20-ru-router ru && ./deploy.sh 21-failover-watchdog ru

Отдельные стадии

./deploy.sh 30-frontend ru       # пересобрать панель
./deploy.sh 35-telegram ru       # перезапустить бота
./deploy.sh 10-foreign foreign   # все exit-ноды
./deploy.sh 19-yt-zapret ru      # обход DPI для YouTube
./deploy.sh 99-verify all        # проверка после деплоя

Полный список стадий - infra/scripts/.

Резервные копии

./deploy.sh backup снимает один зашифрованный архив со всем, что нужно для восстановления entry-ноды: база панели, секреты /etc/anysda, серверный ключ WireGuard, CA и PKI OpenVPN, сертификаты IKEv2, хранилище Caddy. Архив шифруется age до записи на диск.

./deploy.sh backup                    # снять архив сейчас
./deploy.sh backup-list               # список архивов
./deploy.sh restore                   # восстановить последний
./deploy.sh restore <archive> --force # перетереть непустую базу

По умолчанию архивы снимаются раз в сутки в 02:00 и хранятся в /var/backups/anysda-vpn2/ (последние 10). Для настоящего disaster recovery архивы должны жить вне entry-ноды: S3 у другого провайдера или синхронизация на удалённое хранилище.

config.yaml - мастер-секрет. В нём пароли всех нод, пароль панели, токен бота, ключ оркестратора и passphrase архивов. Без passphrase архивы нечитаемы. Храните копию вне entry-ноды, chmod 600, не коммитьте.

Состав архива, хранение в S3, ротация и пошаговое восстановление entry-ноды с нуля - docs/backup.md.

Telegram-бот

Опционален. Включается, если заданы telegram.bot_token и telegram.chat_id (в setup.sh или в настройках панели). Админский чат - личка с ботом или приватная группа с выключенным Group Privacy.

Команда Что делает
/clients список клиентов, создание, карточка с действиями
/status состояние нод и задержка до экзитов
/nodes список exit-нод с RTT

В карточке клиента: заморозить, лимит устройств, срок, приглашение, удалить. «Отправить приглашение» даёт ссылку t.me/<bot>?start=… для пересылки клиенту: по ней бот привязывает его чат, и дальше клиент сам скачивает конфиги, добавляет устройства и получает уведомления об изменениях. «Отозвать доступ к боту» в панели отвязывает Telegram и делает старую ссылку недействительной.

Бот не перевыпускает ключи, не трогает маршруты и не меняет свои настройки - это только в панели.

Лицензия

MIT.

About

Self-hosted multi-node VPN platform: WG/OVPN/IKEv2 entry + Hysteria2 exits. Web panel, Telegram bot, auto-routing, smart failover, AdGuard DNS, monitoring.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages