Deployment
A production VGate deployment is: one manager (with a database), one or more server nodes, and the two frontends served as static assets — typically all behind a single reverse proxy for TLS.
Want to skip building from source? Every component ships pre-built artifacts (binaries, Docker images, and the built frontends) in its GitHub release — see Releases (Pre-built) to download and run directly.
Topology
┌──────────── Reverse proxy (nginx/Caddy, TLS) ────────────┐
Operators ────┤ /admin → Admin Console (static) │
Customers ────┤ / → User Portal (static) │
API clients ──┤ /api/v1 → Manager (backend) │
└──────────────────────────────────────────────────────────┘
│
┌───────▼────────┐ ┌────────────────┐
│ Manager │◄──DB──►│ SQLite/Postgres│
└───────┬────────┘ └────────────────┘
REST /api/v1/server/* (node token)
┌───────▼────────┐
│ Server node(s) │ → VLESS clients (internet)
└────────────────┘1. Manager
cd vgate-manager
go build -o vgate-manager .
./vgate-manager --config /etc/vgate/manager.ymlPre-built? Download vgate-manager-<os>-<arch>.tar.gz (or .zip) from the vgate-manager releases, or pull the image ghcr.io/vgate-project/vgate-manager — see Releases (Pre-built).
- Use Postgres in production (
db.dialect: postgres,db.dsn: "..."). - Set a strong
jwt.secret. - Put it behind the reverse proxy; do not expose the manager port directly to the internet except for the paths the proxy forwards.
- Persist the bootstrap admin password somewhere safe — set it via
admin.bootstrap.password(the bundleddocker-compose.ymldefaults it tochange-me).
2. Server nodes
On each proxy host:
cd vgate-server
go build -o vgate .
./vgate --config /etc/vgate/server.ymlPre-built? Download vgate-server-<os>-<arch>.tar.gz (or .zip) from the vgate-server releases, or pull the image ghcr.io/vgate-project/vgate-server — see Releases (Pre-built).
server.yml contains only admin_api, node_id, node_token, sync_interval, log_level. Firewall the VLESS listen port (assigned by the manager) for client access; the manager connection is outbound from the node.
For many nodes, run vgate as a systemd service:
# /etc/systemd/system/vgate.service
[Unit]
Description=VGate proxy node
After=network.target
[Service]
ExecStart=/usr/local/bin/vgate --config /etc/vgate/server.yml
Restart=on-failure
User=vgate
[Install]
WantedBy=multi-user.target3. Frontends
Pre-built (recommended): download the built SPA archive (dist.tar.gz / dist.zip) from the vgate-admin and vgate-user releases, extract it into a dist/ directory, then edit dist/env.js to point at your manager (see Releases (Pre-built) for the full steps). No npm install / npm run build needed.
To build from source instead:
git clone https://github.com/vgate-project/vgate-admin.git
cd vgate-admin && npm install && npm run build
git clone https://github.com/vgate-project/vgate-user.git
cd vgate-user && npm install && npm run buildAfter building (or after extracting the pre-built archive), edit each dist/env.js to set window.__ENV__.API_BASE_URL:
- Same-origin (proxy serves
/api): leave empty''. - Separate manager host: set the full URL and allow the frontend origin in the manager's CORS
allowed_origins(DB-backed system config).
4. Reverse proxy example (Caddy)
example.com {
reverse_proxy /api/* localhost:8081
file_server /admin/* /srv/vgate/admin/dist
file_server /srv/vgate/user/dist
}(Adapt to your own path layout; the manager, admin, and user apps can live on one host.)
Background jobs
The manager runs these automatically — no external scheduler needed:
- Expired-order closer: every 5 minutes (flips unpaid orders to closed).
- Hourly stats pruning: once at startup, then every 24 hours (deletes
traffic_hourly_statsrows older than 48h). Hourly traffic is aggregated as nodes report it, not on a schedule. - Quota reset: once at startup, then every 24 hours (resets usage counters on the configured
quota.reset_day).
Upgrades
- The manager runs GORM
AutoMigrateon startup (idempotent). - Update server nodes and restart them (or let the sync re-pull config). Rolling restarts are safe because nodes are stateless workers.
- Rebuild frontends and redeploy
dist/.