No description
  • C# 44.6%
  • Go 28.9%
  • Vue 20.4%
  • TypeScript 4.3%
  • Shell 0.9%
  • Other 0.9%
Find a file
2026-06-23 18:04:44 +03:00
.forgejo/workflows CI: переход на cavicode/runner:dotnet, убраны setup-dotnet/node/go 2026-06-23 18:04:44 +03:00
backend Hotfix - исправлена валидация директорий для профилей 2026-06-21 19:44:26 +03:00
CaviCode-SSO-Client@fd7d9dfec5 sso fix 2026-06-21 15:56:07 +03:00
deploy ports fix 2026-06-21 15:41:01 +03:00
egress-go Улучшения безопасности и стабильности 2026-06-20 14:02:23 +03:00
frontend Ci Fix 2026-06-20 15:39:59 +03:00
runner-go SSO Fix 2026-06-21 15:18:28 +03:00
.dockerignore Ci Fix 2026-06-20 15:39:59 +03:00
.editorconfig Рефакторинг на новый бренд 2026-05-28 18:37:57 +03:00
.gitignore env example fix 2026-06-21 15:29:52 +03:00
.gitmodules SSO авторизация и клиент 2026-06-15 19:35:02 +03:00
Changelog.md EncryptPassword Tool 2026-06-21 16:14:53 +03:00
README.md SSO Fix 2026-06-21 15:18:28 +03:00

CaviCodeVPN Core

Ядро платформы CaviCodeVPN — управление пользователями, подписками, SOCKS5 прокси, панель администрирования и Plugin API.

Компоненты

Директория Назначение
backend/ C# .NET 8 — Controller API, Plugin API, фоновые сервисы, сбор метрик
frontend/ Vue 3 — панель управления (дашборд, пользователи, мониторинг, Runtime, плагины, настройки, вики)
egress-go/ Go — SOCKS5 прокси (RFC1928/1929, TrustTunnel extended_auth, CONNECT/UDP ASSOCIATE), валидация учётных данных, server-side policy/routing, учёт трафика
runner-go/ Go — внутренний Runner для Docker runtime: health/readiness/version, token auth, Docker daemon check, cavicodevpn-net, inventory/logs/stats/safe inspect, start/stop/restart контейнеров, audited exec, maintenance locks, cleanup orphans, self-update/Core-update helpers, stack summaries/actions, plugin lifecycle и reconciliation
deploy/ Docker Compose и примеры конфигурации

Репозиторий

git clone --recurse-submodules <repo-url> CaviCodeVPN-Core
cd CaviCodeVPN-Core

OIDC BFF — submodule CaviCode-SSO-Client/ (https://git.cavicode.tech/CaviCode/CaviCode-SSO-Client.git).

Быстрый старт

cd deploy
cp .env.example .env
docker compose up -d

Compose создаёт общую сеть cavicodevpn-net как dual-stack bridge: контейнеры получают IPv4 и IPv6 из CaviCodeVPN_DOCKER_IPV6_SUBNET. Runner cavicodevpn-runner запускается в этой же сети без публичных портов, использует CaviCodeVPN_RUNNER_TOKEN или CaviCodeVPN_RUNNER_TOKEN_FILE для внутреннего API и на старте проверяет доступность Docker daemon и параметры cavicodevpn-net. В production installer включает mTLS Core -> Runner: backend ходит на https://cavicodevpn-runner:3010 с client certificate, Runner проверяет CA и дополнительно rate-limit-ит опасные операции. Backend ходит к Runner по CaviCodeVPN_RUNNER_URL и проксирует runtime API в панель: список контейнеров Core/Runner/плагинов, безопасный inspect, logs tail, stats, историю snapshots, действия start/stop/restart для разрешённых контейнеров, Owner-only audited exec-сессии с short-lived token и режим Stacks для plugin stack detail, whole-stack start/stop/restart/recreate/pull, logs по контейнерам stack, orphan preview, cleanup orphan-контейнеров, maintenance locks, Core update и operation history. Protected-контейнеры требуют роль Owner и ввод точного имени контейнера; Core stack управляется через защищённые container actions. Runner self-update запускается через защищённый maintenance flow: Core получает 202 Accepted, Runner создаёт одноразовый updater-контейнер, а Core пишет результат health-check в историю операций. Core update запускается только Owner-ом из Runtime: Runner поднимает одноразовый helper, выполняет docker compose pull, docker compose down --remove-orphans и docker compose up -d для смонтированной директории deploy, затем пишет итог в RuntimeOperation. Helper использует CaviCodeVPN_CORE_UPDATE_URL через host gateway и не подключается к cavicodevpn-net, чтобы не мешать compose down пересоздать сеть. Core также отдаёт Runner внутренний desired-state и вызывает hooks /api/runner/core/started / /api/runner/core/stopping: после старта backend Runner перезапускает активные plugin stacks, при остановке backend пытается их остановить, а reconcile loop восстанавливает вручную остановленные или неполные active stacks. Для IPv6 outbound у cavicodevpn-core-egress на хосте должен быть рабочий IPv6 default route, а Docker должен создать IPv6 forwarding/masquerade rules. Проверка:

docker compose exec cavicodevpn-core-egress ip -6 route
docker compose exec cavicodevpn-core-egress curl -6 https://api64.ipify.org

Если сеть уже была создана как IPv4-only, остановите Core и плагины, удалите старую cavicodevpn-net, затем поднимите стек заново. Docker не меняет IPv6 параметры существующей bridge-сети.

При первом запуске откроется мастер настройки:

  1. Шаг 1 — создание учётной записи администратора
  2. Шаг 2 — настройка сервера (пароль БД, JWT, Egress, метрики). Можно пропустить.

После создания первого администратора маршрут /setup закрывается и перенаправляет в обычный вход.

Панель управления

  • Дашборд — метрики CPU/RAM/сеть/диск с графиками, статистика Egress, активные соединения
  • Пользователи — создание пользователей, управление подписками и логинами вида ИмяПользователя-ИмяПодписки, журналы запросов и соединений по выбранному пользователю
  • Клиентские фильтры — Include/Exclude профили TrustTunnel/SOCKS5 правил, импорт GeoIP/GeoSite из .dat файлов с предпросмотром и генерация конфигураций подписок через traffic-плагины
  • Мониторинг — сводка ошибок контейнеров, соединений без marker/subscription и переходов в маскировочный сайт; отдельный список ошибок/предупреждений Gateway и контейнеров с фильтрами, без debug-шума Egress splice и штатных переподключений Runner к Docker events
  • Runtime — контейнеры и plugin stacks Core/Runner/плагинов, статусы, start/stop/restart, audited exec, maintenance locks, Runner self-update, Core update, whole-stack actions, полноэкранные logs, stats history, orphan cleanup и безопасный inspect через Runner
  • Диагностика — выдача 24-часового токена для Desktop, сохранённые отчёты клиента и server snapshot за окно теста
  • Плагины — установка из Git URL, настройка через iframe UI, обновление из Git/Docker registry, перезапуск, логи контейнеров
  • Настройки — параметры сервера (JWT, Egress, метрики, пароль БД) через web-интерфейс
  • Админы — управление администраторами (Owner/Admin/Viewer) и 2FA через TOTP-приложения
  • API Ключи — ключи для внешних интеграций (Telegram-боты и т.д.)
  • Вики — встроенная документация (API, развёртывание, плагины)

Плагины

Core работает самостоятельно как SOCKS5-прокси с биллингом. Плагины устанавливаются через панель управления (Плагины → Установка) указав Git URL репозитория. Core хранит бизнес-состояние плагина и выдаёт токен, а Runner клонирует репозиторий, пишет .env и запускает Docker Compose. Compose-плагины могут использовать готовые образы из registry через CaviCodeVPN_PLUGIN_IMAGE_PREFIX.

Если в репозитории плагина есть plugin.json, панель показывает логотип, название, краткое описание, автора и версию плагина. Полное Markdown-описание открывается отдельным окном. Инструкция установки из manifest-а отображается после git clone / git pull, но до запуска Docker Compose; администратор должен подтвердить продолжение установки.

SOCKS5 Egress реализован в egress-go как отдельный Go-сервис. Он сохраняет внешний контракт старого контейнера cavicodevpn-core-egress: порт SOCKS5 1080, health API 1081, env-переменные CaviCodeVPN_* и Core endpoints /api/plugin-api/egress/*. Для TCP CONNECT на IP-адрес Egress подсматривает TLS ClientHello и, если находит SNI, пишет этот домен в request logs без расшифровки TLS. Существующие Desktop/TrustTunnel-профили не нужно пересоздавать при замене контейнера, если login/password подписок не менялись.

Traffic-плагины workspace:

  • CaviCodeVPN-Plugin-TT — TrustTunnel Gateway + cover-сайт.
  • CaviCodeVPN-Plugin-VLESS — Xray VLESS over TCP + REALITY; server-side Xray outbound идёт через Core SOCKS5 Egress, без прямого freedom.
  • CaviCodeVPN-Plugin-Relay — TrustTunnel connector sidecar для server-side RelayPeer маршрута между ingress и foreign node.

Установленные плагины настраиваются через Плагины → карточка плагина → Настройки. При сохранении настроек Core сохраняет JSON в БД и просит Runner синхронизировать .env файл плагина. Кнопка обновления запускает Runner operation: git pull --ff-only, docker compose pull для compose-плагинов, затем docker compose down --remove-orphans, очистка конфликтующих контейнеров плагина по Docker label/имени и docker compose up -d --build --remove-orphans. При перезапуске Runner пересоздаёт plugin stack с обновлёнными переменными окружения. Runtime → Stacks даёт отдельное управление plugin stack: start/stop/restart/recreate/pull, logs каждого контейнера stack, maintenance locks, orphan cleanup и историю RuntimeOperation. Reconcile loop пропускает плагины с активной ручной operation или maintenance lock, но вне неё приводит Docker-состояние к desired-state Core.

Server-side страховка Egress

При генерации клиентской конфигурации Core сохраняет выбранный профиль клиентских фильтров на подписке. В UI действие списка показывается как Exclude или Include: General/Exclude генерирует TrustTunnel bypass-список и server-side deny-list, а Selective/Include генерирует список назначения для TrustTunnel и server-side allow-list. SOCKS5 Egress получает вместе с credentials egressPolicy и до исходящего TCP CONNECT или UDP datagram применяет домены и CIDR из профиля. Это не заменяет клиентский bypass в TOML, а страхует от устаревшего или вручную изменённого клиентского конфига: запрещённый destination не выходит наружу с IP VPN-сервера.

GeoIP/GeoSite импортируются в панели из локального geoip.dat/geosite.dat: Core показывает категории, preview развёрнутых адресов, а при импорте сохраняет плоские CIDR в IP/CIDR правила и домены в domain rules. Сами .dat файлы на сервере не сохраняются.

При блокировке Egress возвращает SOCKS5 reply 0x02 (connection not allowed by ruleset) и пишет событие в application logs контейнера. Расширение UI request logs отдельными полями решения и причины блока пока не включено в схему БД.

Server-side routing Egress

Глобальная маршрутизация Egress хранится в system_settings ключом egress_routing_config и отдаётся контейнеру через GET /api/plugin-api/egress/routing-config. Админский API GET/PUT /api/egress-routing/config принимает JSON с активным профилем, relay peers и правилами по доменам, CIDR, портам и протоколам.

Минимальный профиль для Relay:

{
  "activeProfileId": "main",
  "relayPeers": [
    {
      "id": "foreign-1",
      "name": "Foreign exit",
      "connectorHost": "cavicodevpn-plugin-relay-connector-foreign-1",
      "connectorSocksPort": 11080,
      "enabled": true
    }
  ],
  "profiles": [
    {
      "id": "main",
      "name": "Main",
      "defaultTarget": "RelayPeer",
      "defaultRelayPeerId": "foreign-1",
      "rules": [
        {
          "id": "ru-local",
          "name": "RU local",
          "target": "Local",
          "relayPeerId": null,
          "domainPatterns": ["*.ru"],
          "cidrs": [],
          "ports": [],
          "protocols": ["tcp", "udp"]
        }
      ]
    }
  ]
}

TCP RelayPeer открывается через SOCKS5 connector без локального DNS для доменных destination: Egress передаёт SOCKS5 address type DOMAINNAME в connector. Если connector/peer недоступен, Egress возвращает отказ и не делает fallback в Local. UDP RelayPeer пока не реализован: если профиль выбирает RelayPeer для UDP, datagram блокируется fail-closed в Egress.

Request logs получили поля routeTarget, relayPeerId и routeReason, чтобы видеть, какое решение принял Egress. Для TLS-запросов, где TT endpoint передал в SOCKS5 IP-адрес вместо домена, Egress заполняет destinationHost из SNI ClientHello.

Если клиентский TrustTunnel уже дошёл до VPN_SS_CONNECTED, но затем падает с Authorization Required (5) или HTTP/2 407, проблема находится в авторизации на SOCKS5 Egress, а не в WinTun/Gateway-маркере. Смотрите application logs контейнера Egress: он пишет причину отказа (CacheEmpty, UnknownLogin, InvalidPassword, отсутствующий пароль, неактивный статус, лимит трафика или истечение подписки) и размер credential cache без вывода пароля.

В карточке пользователя доступен экспорт ссылок активных подписок в текстовом формате:

Имя подписки
tt://...

Другая подписка
tt://...

Core хранит пароли подписок как зашифрованную строку, ключ берётся из .env переменной CaviCodeVPN_SUBSCRIPTION_PASSWORD_ENCRYPTION_KEY. Массовый экспорт использует сохранённые пароли и не перевыпускает активные подписки. После миграции со старых версий прежние password_hash удаляются без восстановления plain password: для таких подписок нужно один раз сбросить пароль перед генерацией профиля. Для TrustTunnel панель показывает markerHex/TLS Prefix, который вернул traffic-плагин при генерации; это значение должно совпадать с активным TLS Prefix в настройках плагина и client_random в импортируемом TOML.

Связанные репозитории

Репозиторий Назначение
CaviCodeVPN-Plugin-TT Плагин маскировки через TrustTunnel (Gateway + TT endpoint + сайт прикрытия + ACME)
CaviCodeVPN-Plugin-UserSync Плагин P2P синхронизации пользователей между нодами
CaviCodeVPN-Desktop Avalonia VPN-клиент для Linux/Windows

Стек

  • Backend: C# .NET 8, ASP.NET Core Minimal API, EF Core + Npgsql, JWT/ApiKey/PluginToken аутентификация, AES-GCM для паролей подписок, BCrypt для админов, TOTP 2FA, TimescaleDB
  • Frontend: Vue 3, TypeScript, Vite, Pinia, Canvas-графики, терминальные логи через xterm.js
  • Egress: Go, RFC1928+RFC1929 SOCKS5, TrustTunnel extended_auth, CONNECT/UDP ASSOCIATE, pull-кеш учётных данных, policy и routing profiles
  • Runner: Go, внутренний HTTP/mTLS API, token/token-file auth, Docker Engine API через unix socket, network ensure, container inventory/logs/stats/safe inspect, start/stop/restart, audited exec, maintenance locks, orphan cleanup, self-update/Core-update helpers, stack summaries/actions, plugin lifecycle через Git/Compose, Core restart/shutdown hooks и reconciliation loop
  • БД: PostgreSQL 16 + TimescaleDB
  • Инфра: Docker Compose, Docker socket смонтирован только в Runner; backend работает через thin Runner client для setup/diagnostics/logs/runtime, Let's Encrypt ACME (в плагинах)

Развёртывание в продакшн

cd deploy
cp .env.example .env
# Отредактируйте .env (пароль БД) или настройте через мастер в браузере
docker compose up -d

По умолчанию Core images берутся из git.cavicode.tech/cavicode/*. Для локальной сборки используйте deploy/scripts/dev-up.sh.

Пароль PostgreSQL можно задать:

  • В .env файле перед запуском
  • Через мастер настройки в браузере (автоматически обновит .env и перезапустит контейнер)

Подробнее — в Wiki панели управления (раздел «Развёртывание»).