Architecture
VGate is a small distributed system with a clear control-plane / data-plane split.
Components at a glance
┌──────────────────┐ REST /api/v1 ┌──────────────────────────┐
│ Admin Console │ ───────────────────────────► │ │
│ (Vue 3, ops) │ │ Manager (Go) │
└──────────────────┘ │ ┌────────────────────┐ │
│ │ API / middleware │ │
┌──────────────────┐ REST /api/v1 │ │ Auth (JWT, roles) │ │
│ User Portal │ ───────────────────────────► │ │ Billing / orders │ │
│ (Vue 3, users) │ │ │ Plans / users │ │
└──────────────────┘ │ │ Traffic aggregator │ │
│ │ Nodes / system cfg │ │
┌──────────────────┐ REST /api/v1/server/* │ └─────────┬──────────┘ │
│ Server (VLESS) │ ◄───────────────────────────┤ GORM │ DB │
│ sync + report │ ───────────────────────────► │ ┌───────▼─────────────┐ │
│ │ per-user traffic reports │ │ SQLite / Postgres │ │
└────────┬─────────┘ │ └─────────────────────┘ │
│ VLESS inbound └──────────────────────────┘
▼
Internet clients (VLESS apps)Manager — the control plane
manager/ is a Go service (Gin + GORM). On startup (manager/main.go → cmd.Execute() → run()):
- Loads config (viper).
- Opens the DB (SQLite default, or Postgres).
AutoMigrates all GORM models.- Runs ordered, idempotent data migrations.
- Merges DB-backed system-config overrides on top of
config.yml. - Bootstraps the initial admin (from
admin.bootstrap; password printed once). - Builds the router via
api.NewRouter. - Starts background tickers: expired-order closer (5 min), hourly traffic aggregation, daily quota reset.
Layered structure (internal/)
api/— HTTP layer:router.go,handler/(one file per resource),dto/. Includes tests.middleware/—cors,jwt,node_auth,logger,ratelimit.service/— business logic: auth, user, node, plan, order/billing, traffic, stats, subscription, system_config, email/invite, announcement.model/— GORM models.util/,wire/,pkg/crypto/(VLESS credential helpers).
API surface (all under /api/v1)
- Public / user:
/user/login,/sub/:sub_token, profile / subscribe / plans / orders,/billing/alipay/notify. - Node data plane:
GET /server/config,GET /server/users,POST /server/traffic. - Admin: nodes, users, traffic, stats, system-config, orders, plans, admins.
GET /health.
Config split
Some keys are file/env-only; others are DB-backed and hot-reloadable:
| File / env only | DB-backed (hot-reloadable) |
|---|---|
server.port | jwt TTLs |
db.* | log.level / log.format |
jwt.secret | cors.allowed_origins |
admin.bootstrap.* | timeouts |
viper maps SERVER_PORT-style environment variables.
Server — the data plane (proxy node)
server/ is a Go binary (cobra CLI) that runs a VLESS inbound. Flow (server/main.go → cmd.Execute() → run()):
- Load local viper YAML config (
admin_api,node_id,node_token,sync_interval,log_level). - Create an
api.Clientpointed at<AdminAPI>/api/v1/server. - Start the VLESS inbound (
proxy/vless). - Run a ticker that calls
sync()everySyncIntervalseconds.
Sync loop
sync() pulls config + users with HTTP 304 short-circuiting (api/client.go uses If-None-Match; returns api.ErrNotModified), applies hot-reload via UpdateConfig / UpdateUsers, and reports accumulated per-user traffic (GetAndResetTraffic) back.
Transport abstraction
transport/transport.go defines a Transport interface + registry. The native tcp transport applies TLS/Reality via transport/security.Wrap. ws and xhttp adapters delegate to xray-core's websocket.ListenWS / splithttp.ListenXH, sharing helpers in transport/xraybridge (ChanListener, protojson decode, TLS/Reality protobuf builders). Transports register through anonymous imports in proxy/vless/bootstrap.go.
VLESS inbound internals (proxy/vless/)
- Handshake + TCP/UDP forwarder (
handler.go) - UDP-over-TCP relay (
udp.go) xtls-rprx-visionrelay (vision.go, xray-core leaf)- Mux handling — TCP / HTTP / WebSocket (
mux.go) - Protocol constants/helpers (
protocol.go) - User set + connection tracking (
user.go) - Per-user delta traffic counters (
traffic.go) - Lifecycle + hot-reload (
server.go)
Frontends — the human interface
frontend/admin— operator UI. Supportsnpmorpnpm.frontend/user— customer UI.npm installonly (nopnpmlockfile).
Both talk to the manager's REST API. Dev servers proxy /api → http://localhost:8081.
Data flow, end to end
- Operator creates a node and a user in the admin console → manager persists them.
- The server node's
sync()fetches the new config + user list (or gets a304). - A client connects to the server node with VLESS using the user's credential.
- The server node increments per-user traffic counters as bytes flow.
- On the next sync, the node posts deltas to
POST /server/traffic. - The manager aggregates and checks quotas; the admin console and user portal reflect usage.