Aegis is a self-hosted control panel for multi-protocol VPN services. v0.8.1 ships the full admin surface end-to-end: sing-box on every node, BYO Node bootstrap with real
aegis-agent, user / host / plan CRUD, subscription render in sing-box / Clash / base64 / HTML formats, audit log, backups (with operator CLI), outgoing webhooks (HMAC-signed + DLQ), the Phase 2 multi-user sing-box render (per-(user, inbound) credentials, multi-userusers: [...]arrays, narrowed BatchedApplier fan-out, per-user sub URL), and the v0.8.1 auto-deploy bootstrap batch: sharedinternal/crypto/envelopepackage (X25519+ChaCha20-Poly1305, multi-recipient for key rotation), password-based first auth for the BYO Node flow with a persistent panel key that the panel generates on first install and re-uses on every re-provision (the operator never pastes a key after the first install). The CoreProvider abstraction lets a second provider (Xray) ship in v2.0+ without UI surgery. AGPL-3.0. Single-tenant.Stack: Go 1.26+ backend, Vue 3 + TypeScript frontend (Vite + shadcn-vue), PostgreSQL, Caddy, fail2ban, sops+age secrets. See
ARCHITECTURE.md(v9.5) for the full design anddocs/adr/0003-mvp-singbox-vertical-slice.mdfor the MVP strategy.
v0.8.1 — auto-deploy bootstrap batch — shipped.
v0.8.1 is the password-based first auth + persistent
panel key milestone: the operator clicks "+ Add node",
fills in name / region / SSH address / domain, pastes
the VPS root password, clicks submit — the panel
SSHes in once, installs the agent, and generates an
ed25519 keypair that the panel re-uses on every
subsequent re-provision. The operator never has to
paste a key. The 4-PR batch — the shared
internal/crypto/envelope package (#177, refactor),
the brace-expansion CVE bump (#178, security), the
backend password-XOR + persistent key (#179,
feature), and the matching three-way radio in the UI
(#180, feature) — also includes a frontend
dependency CVE fix (brace-expansion 5.0.8 → 5.0.9,
ReDoS in expand). The wire format gained one new
field: ssh_password on the NodeProvisionRequest
schema (mutually exclusive with ssh_private_key,
XOR enforced in
backend/internal/bootstrap/handler.go); the
OpenAPI spec is now at 0.8.1. The migration
landscape is 0001..0020 (was 0001..0019 in
v0.8.0; 0020 adds nodes.ssh_private_key_ciphertext).
v0.8.0 — Phase 2 multi-user sing-box render — shipped.
v0.8.0 is the end-to-end multi-user milestone: the
panel can issue per-(user, inbound) credentials via
internal/credentials Service + Store (data layer
- admin surface in v0.8.x follow-up), the sing-box
renderer emits multi-user
users: [...]arrays, the BatchedApplier fan-out is narrowed byuser.HostsAllowlist/Blocklist, and the per-user sub URL renders the user's own UUID/password (sing-box and Clash). The 9-PR batch — the four dep bumps (#159,#161,#163,#165), the audit batch (#166), and the Phase 2 chain (#167,#168,#169,#170) — also includes the audit-log call-site wiring into every mutating service and a frontend dependency batch (TS / CSS / axios / vue-tsconfig / postcss). v0.8.0 is purely infrastructure by API surface: the OpenAPI spec stays at0.7.0for v0.8.0,frontend/src/types/api.d.tsis regenerated only for thessh_passwordfield added in v0.8.1.
The release ladder:
| Milestone | Status | Notes |
|---|---|---|
v0.1.0-mvp-render |
shipped | Renderable MVP — admin UI + subscription endpoint + sing-box (no-op core in dev) |
v0.2.0-mvp-agent |
shipped | Per-sub_token rate limit, OpenAPI codegen, audit log, operator CLI, per-resource handler surfaces |
v0.3.0-mvp-byo-node |
shipped | BYO Node flow: SSH probe + agent install + state machine |
v0.4.0-mvp-batched |
shipped | BatchedApplier + real apply transport + install_singbox Ansible role + aegis-agent writes config to disk and reloads sing-box |
v0.4.0-d |
shipped | internal/users data layer (d.1) + Path C consolidation (d.r1–d.r4) |
v0.4.0 (tag) |
shipped | Aggregate of d.1 / d.r1 / d.r2 / d.r3 / d.r4 |
v0.4.0-post |
shipped | Release workflow fixes (#102 / #103 / #104 / #111) — no application code change |
v0.5.0 |
shipped | sops+age secrets, backup/restore (pkg + UI + CLI), pre-PR gate, GitHub-API sing-box SHA-256, container wiring for secrets, operator guide + SECURITY + quickstart |
v0.6.0 |
shipped | internal/plans — plan catalog promoted from the v0.3.0 table stub to a full CRUD surface |
v0.7.0 |
shipped | internal/webhooks — outgoing-webhook surface with HMAC signing, retry with exponential backoff, DLQ |
v0.7.1 |
shipped | Webhook call-site wiring, sops+age envelope on webhook_endpoints.secret, background retry worker, events multi-select, shared zod schema, plus the post-v0.7.0 Go+frontend dependency batch (#141–#144) and the docs sync (#145) |
v0.7.2 |
shipped | Audit batch closeout: God-object main.go extracted into internal/app.Build (#156); real BatchedApplier FlushFn + Enqueue from user/inbound services (#157); end-to-end integration test against a real Postgres (#158) |
v0.8.0 |
shipped | Phase 2 multi-user sing-box render end-to-end (#167 data model, #168 renderer, #169 builder + BatchedApplier narrow, #170 subscription per-user render); audit-log call-site wiring into every mutating service (#166); frontend dependency batch — TS / CSS / axios / vue-tsconfig / postcss (#159, #161, #163, #165) |
v0.8.1 |
shipped | Auto-deploy bootstrap batch: shared internal/crypto/envelope package (#177 refactor); brace-expansion 5.0.8 → 5.0.9 CVE (#178 chore); password-based first auth + persistent node SSH key (#179 feat); three-way radio in the provision UI (#180 feat). Migration 0020 (nodes.ssh_private_key_ciphertext BYTEA). OpenAPI spec bumped to 0.8.1. |
v0.8.2 |
planned | Server-side /me fix (auth.Store.GetByID + PgStore, closes the v0.8.0 auth.me === null 500 on pg backend); HTTP admin surface for user_inbound_credentials (/api/v1/credentials/ mount + ScopeCredentials + OpenAPI + Credentials tab in the user detail page) |
v0.8.x |
planned | BatchedApplier decrypt-and-use for the stored panel key; re-provision path for v0.3.0..v0.7.x nodes (CLI aegis admin node rotate-panel-key <id>); Host → node mapping in the Builder-side filter; inbound-templates work (per-tenant Params defaults); "show me the stored public key" debug surface; merged "Add node + Provision" dialog; shadcn-vue RadioGroup primitive; cosign re-signing on every release; JSON logs in production (AEGIS_ENV=production one-liner) |
v0.9.0 |
planned | Smoke test on fresh VM in CI (terraform + ansible + boot log artifact) |
v1.0.0-mvp-soft-launch |
planned | GA tag — minimum surface for the public release |
See docs/ROADMAP.md for the milestone ladder,
CHANGELOG.md for the per-PR release notes, and
KNOWN_LIMITATIONS.md for the current gap
list.
aegis/
├── ARCHITECTURE.md # the design document (v9.5)
├── CHANGELOG.md # per-version release notes (Keep a Changelog)
├── KNOWN_LIMITATIONS.md # current gap list (v0.8.0)
├── README.md # this file
├── LICENSE # AGPL-3.0
├── Makefile # top-level orchestration
├── .gitattributes # LF / CRLF policy (LF in repo, CRLF on .bat/.cmd/.ps1)
├── .markdownlint.json # docs lint config
├── backend/ # Go 1.26+ service
│ ├── cmd/
│ │ ├── aegis/ # the `aegis` panel binary
│ │ ├── aegis-agent/ # the per-node Go agent (writes sing-box config + reloads)
│ │ ├── aegis-pg-backup/ # operator-side backup CLI
│ │ └── aegis-pg-restore/ # operator-side restore CLI (separate binary, safety boundary)
│ ├── internal/ # 21 packages: app, audits, auth, backups, bootstrap, config, cores, credentials, db, hosts, inbounds, migrations, nodes, obs, panelcfg, plans, ratelimit, router, subscription, users, webhooks (+ 9 doc.go-only placeholders: cabinet, caddy, cascades, decoy, events, mcp, notifications, stats, subscriptions)
│ ├── migrations/ # 19 SQL files (0001..0019; 0019 adds user_inbound_credentials)
│ └── testutil/ # shared Postgres test fixtures
├── frontend/ # Vue 3 + TS admin UI (shadcn-vue)
│ ├── src/components/ui/ # 25 base shadcn-vue components
│ ├── src/components/ # Form / DataTable / FormField (typed wrapper around vee-validate + zod)
│ ├── src/api/services/ # typed API clients (auth / backups / nodes / inbounds / hosts / users / plans / panelcfg / audits / webhooks)
│ ├── src/schemas/ # zod schemas
│ ├── src/views/ # Dashboard / Nodes / Inbounds / Hosts / Plans / Subscription / Users / Webhooks / Backups / Settings / Audits / Profile / Login
│ ├── src/i18n/ # vue-i18n (en + ru)
│ ├── src/types/ # aegis.ts (hand mirror) + api.d.ts (codegen from openapi.yaml)
│ └── tools/scripts/ # check-raw-text.mjs (i18n lint) + check-codegen.mjs (openapi-typescript freshness)
├── deploy/
│ ├── ansible/ # bootstrap_node / configure_secrets / install_agent / install_caddy / install_fail2ban / install_singbox / install_panel / setup_decoy roles + playbooks
│ ├── secrets/ # sops+age encrypted secrets (secrets.example.yml is committed encrypted; secrets.yml is gitignored)
│ ├── docker/ # docker-compose.prod.yml.j2 template
│ └── caddy/ # Caddyfile templates
├── docs/
│ ├── adr/ # Architecture Decision Records (0001–0004)
│ ├── api/ # API reference (rendered from openapi.yaml)
│ ├── archive/ # superseded docs (e.g. ARCHITECTURE_ADDENDUM_1)
│ ├── developer/ # developer guide (module overview, testing, contributing)
│ ├── guide/ # rendered ARCHITECTURE.md + quickstart + getting-started
│ ├── operator-guide.md # the canonical "fresh VPS → panel" reference
│ ├── SECURITY.md # threat model + disclosure flow
│ ├── ROADMAP.md # the milestone ladder
│ ├── README.md # docs index
│ ├── KNOWN_LIMITATIONS.md # (root) gap list
│ └── openapi.yaml # OpenAPI 3.0 spec (codegen source of truth; v0.7.0 — v0.8.0 same API surface)
└── tools/scripts/ # pre-pr.sh, install-pre-push.sh, branch-start.sh, smoke-frontend.sh, release.sh, backup.sh, restore.sh
For the operator path (a single VPS behind a public domain, secrets on disk, real users, real backups) the operator guide is the canonical entry. The five-minute version is the quickstart.
For the development path (Postgres + Redis + NATS + panel + UI on a laptop) the getting started page is the right entry. The TL;DR:
# 1. Clone
git clone https://github.com/QAdversif/AegisPanel.git aegis
cd aegis
# 2. Install the pre-push gate (recommended)
make pre-pr-install # installs .git/hooks/pre-push delegating to tools/scripts/pre-pr.sh
# 3. Bring up the dev stack
make dev # Postgres + Redis + NATS + panel + UI on :5173 (UI) / :8080 (panel)
# 4. Smoke
./tools/scripts/smoke-frontend.shPrerequisites: Go 1.26+, Node.js 20+, npm (the project
is standardized on npm ci against the committed
package-lock.json; pnpm is no longer used — see PR #87), Docker
24+ and Docker Compose v2, Make.
- Architecture —
ARCHITECTURE.md(Russian, v9.5). Source of truth for the design. - Roadmap —
docs/ROADMAP.md. Milestone ladder with per-PR status. - Operator guide —
docs/operator-guide.md. The end-to-end "from a fresh VPS to a panel that serves real users" flow. - Quickstart —
docs/guide/quickstart.md. The five-minute operator path. - Security policy —
docs/SECURITY.md. Threat model, disclosure flow, supply-chain trust. - API reference —
docs/api/. Rendered fromdocs/openapi.yaml(currently 0.7.0; v0.7.1, v0.7.2, v0.8.0 did not change the API surface). - CHANGELOG —
CHANGELOG.md. Per-version release notes (Keep a Changelog format). - Known limitations —
KNOWN_LIMITATIONS.md. Open gaps and the milestone that closes each. - Developer guide —
docs/developer/. Module overview, testing, contributing.
- Branch naming:
feat/<scope>/<name>,fix/<scope>/<name>,chore/<scope>/<name>,refactor/<scope>/<name>,docs/<scope>/<name>. Branch offmain;mainis the integration branch (nodevelop). - Commits: Conventional Commits.
Avoid backticks in
-mstrings (PowerShell execution policy). Multi-line commits: write the message to a.git-commit-*.txtandgit commit --file <path>. Throwaway drafts are gitignored. - PRs: one PR per work unit.
gh pr create --body-file .github/pr-body-<name>.md. Merges usegh pr merge --admin --squash --delete-branch. - Pre-PR gate: run
tools/scripts/pre-pr.sh(or the installed pre-push hook) before pushing. The gate runs gofmt, golangci-lint v2, vue-tsc, eslint, markdownlint-cli2,go test -short, andnpm run codegen:check. It catches ~80% of the issues that would otherwise bounce in CI. - i18n: every user-facing string goes through
t('key'). Runnode frontend/tools/scripts/check-raw-text.mjslocally; the CI gate runs the same script. - License header in every source file:
// SPDX-License-Identifier: AGPL-3.0-or-later(Go / shell / SQL) or<!-- SPDX-License-Identifier: AGPL-3.0-or-later -->(Vue / TS).
AGPL-3.0-or-later. See LICENSE.
The Aegis project is single-tenant and AGPL-licensed: any operator who runs a modified version of the panel is required to publish the modifications. The operator's modifications and the upstream Aegis source are both governed by this license.