- C# 44.6%
- Go 28.9%
- Vue 20.4%
- TypeScript 4.3%
- Shell 0.9%
- Other 0.9%
|
|
||
|---|---|---|
| .forgejo/workflows | ||
| backend | ||
| CaviCode-SSO-Client@fd7d9dfec5 | ||
| deploy | ||
| egress-go | ||
| frontend | ||
| runner-go | ||
| .dockerignore | ||
| .editorconfig | ||
| .gitignore | ||
| .gitmodules | ||
| Changelog.md | ||
| README.md | ||
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
- Панель управления: http://localhost:8080
- API: http://localhost:3005
- SOCKS5 прокси: localhost:1080
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 — создание учётной записи администратора
- Шаг 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-sideRelayPeerмаршрута между 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 панели управления (раздел «Развёртывание»).