vgate-manager

command module
v0.0.0-...-2c9f6af Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 8, 2026 License: AGPL-3.0 Imports: 1 Imported by: 0

README

VGate Manager

Backend API server for VGate — admin/identity/billing management and the data plane that proxy nodes report into. Written in Go. This is the source of truth for the whole system: nodes, users, plans, orders, and traffic all live here, including per-user and per-node speed caps that the proxy nodes enforce.

Tech stack

Prerequisites

  • Go 1.26+

Build & run

# from this directory
go build -o vgate-manager .

# run with an explicit config file (defaults to ./config.yml)
./vgate-manager --config config.yml

# or just run the default:
./vgate-manager

On first start the database is auto-migrated and an initial admin is bootstrapped from admin.bootstrap in config.yml (default username admin; the bundled docker-compose.yml defaults the password to change-me, otherwise set admin.bootstrap.password / ADMIN_BOOTSTRAP_PASSWORD explicitly). The admin is created only once on first start; subsequent starts reuse the existing admin. GORM AutoMigrate runs automatically on startup (idempotent), and DB-backed system-config overrides are merged on top of config.yml.

Admin CLI

Create additional admin accounts from the command line:

./vgate-manager admin create --username alice --password s3cret --role super_admin

--role is one of admin (default) or super_admin. Super admins have access to the /admins and plan-management endpoints.

CLI flags
Flag Type Default Description
--config string ./config.yml Path to the config file.
--captcha-enabled bool false Enable Cloudflare Turnstile captcha on auth endpoints (/user/login, /user/register, /user/verify-email, /user/resend-verification, /admin/login).

The captcha toggle is normally a DB-backed, hot-reloadable setting (captcha.turnstile_enabled) that an admin flips from the admin console. The --captcha-enabled flag lets you force that switch at startup:

# turn captcha on at startup
./vgate-manager --captcha-enabled

# turn it off at startup
./vgate-manager --captcha-enabled=false

When the flag is omitted, the existing DB value is left untouched, so an admin can still toggle captcha live at runtime. When the flag is passed (either true or false), it overrides the DB value on each start. The flag only gates the Turnstile challenge — the widget's captcha.turnstile_site_key and captcha.turnstile_secret_key are still configured via system-config.

Configuration (config.yml)

Two kinds of settings exist:

File/env only — require a restart to change:

Key Default Notes
server.port 8081 HTTP listener port
db.dialect sqlite sqlite | postgres
db.dsn vgate_manager.db SQLite path or Postgres DSN
db.max_open_conns 20
db.max_idle_conns 5
jwt.secret change-me-in-production Set this in production
admin.bootstrap.username admin used only on first run
admin.bootstrap.password (unset) used only on first run; Docker Compose defaults to change-me

Managed in the database (hot-reloadable via PUT /api/v1/admin/system-config) — values for these in config.yml are ignored:

  • JWT: jwt.access_ttl_secs (7200), jwt.refresh_ttl_secs (604800)
  • Logging: log.level (info), log.format (text | json)
  • CORS: cors.allowed_origins (["*"])
  • Server timeouts: server.read_timeout_secs (30), server.write_timeout_secs (30)
  • Quota: quota.reset_day (day-of-month the monthly usage counters reset)
  • Password policy: password.min_length, password.require_complexity
  • Registration: user.register_enabled (open registration), user.register_require_invite, user.register_require_email_verify, user.register_email_suffix_whitelist
  • Trial accounts: user.trial_enabled, user.trial_quota_bytes, user.trial_duration_days
  • Invites: invite.default_user_quota
  • Site / subscription: site.name, site.base_url, sub.base_urls (per-node subscription base URLs), payment.product_name_template
  • Email: email.provider (smtp | resend), email.enabled, email.from, email.from_name, plus email.smtp_* / email.resend_* backend settings
  • Captcha: captcha.turnstile_enabled, captcha.turnstile_site_key, captcha.turnstile_secret_key
  • Telegram: telegram.enabled, telegram.bot_token, telegram.bot_username, telegram.user_bot_enabled, telegram.alert_ticket, telegram.alert_announcement, telegram.alert_order_paid, telegram.alert_new_registration, telegram.alert_node_up, telegram.alert_node_down, telegram.alert_traffic_exceeded
  • Payments: alipay.*, wechat.*, stripe.*, paypal.* (client id/secret, notify/webhook urls, currency, sandbox), and apple.* (issuer id, key id, bundle id, private key, environment, notify_url, product_map) gateway credentials — configured from the admin console System Config → Payment
  • Traffic reminders: reminder.enabled, reminder.pct_threshold (80), reminder.days_threshold (3), reminder.cooldown_days (1)

Common defaults (set on first start, overridable via system-config): quota.reset_day = 1, password.min_length = 8, invite.default_user_quota = 5, user.trial_enabled = false, user.trial_quota_bytes = 1073741824 (1 GiB), user.trial_duration_days = 7.

Environment overrides

viper reads environment variables with ._ (uppercase), e.g. SERVER_PORT=9000, DB_DIALECT=postgres, JWT_SECRET=....

API overview

All endpoints are prefixed with /api/v1. Auth uses JWT. Admin login (POST /admin/login) returns an access token plus a refresh token, and POST /admin/refresh rotates the session; user login (POST /user/login) returns only an access token — users do not receive refresh tokens, so a 401 means re-login. Admin endpoints require Authorization: Bearer <token>. Node endpoints use a separate node token (node_auth middleware).

Public / user

  • POST /user/login
  • POST /user/register
  • POST /user/verify-email
  • GET /user/config, GET /user/dashboard — runtime config bundle / dashboard summary
  • GET /sub/:sub_token — subscription info (node side)
  • POST /user/resend-verification — resend the email-verification message (captcha-gated)
  • GET /user/profile, PUT /user/profile, GET /user/subscribe, GET /user/subscribe-url
  • GET /user/plans, GET /user/nodes
  • POST /user/regenerate-credential, POST /user/reset-sub-token
  • GET /user/traffic-packages
  • POST /user/orders, GET /user/orders, GET /user/orders/:id
  • POST /user/orders/:id/pay, POST /user/orders/:id/close
  • POST /user/orders/:id/apple-verify — verify an Apple App Store IAP receipt
  • GET /user/payment-methods — enabled payment channels for the current user
  • GET /user/balance, POST /user/change-plan, GET /user/change-plan/preview — wallet balance, prorated plan change, and proration preview
  • GET /user/traffic, GET /user/traffic/hourly
  • POST /user/change-password
  • GET/POST/DELETE /user/invites, GET /user/invites/status
  • GET /user/announcements
  • Support tickets — users open, reply to, and close their own tickets, and pick how they are notified of admin replies: GET/POST /user/tickets, GET /user/tickets/:id, POST /user/tickets/:id/messages, POST /user/tickets/:id/close
  • GET /user/tickets/unread — count of unread admin replies on your tickets.
  • Redemption codes — redeem an invite/redemption code and view your redemption history: POST /user/redemption-codes/redeem, GET /user/redemption-codes/records.
  • PUT /user/reminder-channel — choose the channel (none / email / telegram) for traffic-reminder alerts.
  • Telegram link (self-service) — bind/unbind a personal Telegram account and toggle announcement delivery: GET /user/telegram/status, POST /user/telegram/bind, POST /user/telegram/unbind, PUT /user/telegram/notify
  • POST /api/v1/billing/:platform/notify — async payment callback (public, POST) for alipay, wechat, stripe, paypal, or apple

Node (data plane)

  • GET /server/config, GET /server/users, POST /server/traffic

Admin (requires Authorization: Bearer <token>)

  • POST /admin/login, POST /admin/refresh
  • GET /admin/config (public, unauthenticated)
  • Nodes: GET/POST /admin/nodes, GET/PUT/DELETE /admin/nodes/:id, POST /admin/nodes/:id/regenerate-token, GET /admin/nodes/:id/users
  • Users: GET/POST /admin/users, GET/PUT/DELETE /admin/users/:id, POST /admin/users/:id/regenerate-sub-token, POST /admin/users/:id/regenerate-credential, PUT /admin/users/:id/password, GET /admin/users/:id/nodes, PUT /admin/users/:id/nodes, POST /admin/change-password
  • GET /admin/traffic, GET /admin/stats/overview
  • Zombie users (super-admin only): POST /admin/users/zombies/preview, POST /admin/users/zombies/cleanup
  • GET /admin/system-config, PUT /admin/system-config (super-admin only)
  • POST /admin/utils/generate-x25519
  • Invites: GET/POST/DELETE /admin/invites
  • Redemption codes: GET/POST /admin/redemption-codes, GET /admin/redemption-codes/:id/records, DELETE /admin/redemption-codes/:id
  • Announcements: GET/POST/PUT/DELETE /admin/announcements
  • Email: POST /admin/email/send, POST /admin/email/test
  • Orders: POST /admin/orders, GET /admin/orders, GET /admin/orders/:id, PUT /admin/orders/:id/status
  • Traffic packages: GET/POST/PUT/DELETE /admin/traffic-packages[/:id]
  • Tickets: GET/POST /admin/tickets, GET /admin/tickets/:id, POST /admin/tickets/:id/messages, PUT /admin/tickets/:id/status, GET /admin/tickets/unread
  • Telegram: POST /admin/telegram/broadcast (send to all linked users), and the admin self-link GET/POST /admin/me/telegram/{status,bind,unbind}
  • Reference data: GET /admin/reference — static lookup lists for admin dialogs.
  • Payment channels: GET /admin/payment-methods (super-admin) — enabled payment channels.
  • Wallet: GET/POST /admin/users/:id/balance — read / adjust a user's wallet balance.
  • Super-admin only: full admin CRUD GET/POST/PUT/DELETE /admin/admins[/:id], PUT /admin/admins/:id/password, and plan management CRUD (POST /admin/plans, PUT/DELETE /admin/plans/:id). Any admin may GET /admin/plans, GET /admin/plans/:id, and GET /admin/traffic-packages.

Health

  • GET /health

Email

Outbound mail (registration verification, admin broadcasts) is configured entirely via DB-backed system config — no restart required. Two backends are supported:

  • smtp (default) — a traditional SMTP server (email.smtp_host / email.smtp_port / email.smtp_security / email.smtp_user / email.smtp_pass).
  • resend — the Resend API (email.resend_api_key).

Shared settings (both backends): email.enabled (master switch), email.from (the sender address; for Resend it must be a verified domain), and an optional email.from_name (display name, e.g. VGate"VGate" <noreply@vgate.io>).

Verify connectivity from the admin console (System Config → Email → General → Test Email) or call the endpoint directly:

  • POST /admin/email/test — body { "to": "you@example.com", "subject?": "...", "body?": "..." }. Uses the currently saved configuration (save first if you just edited settings) and returns { "ok": true } on success or { "ok": false, "error": "..." } on delivery failure.

Registration & email verification

Registration (POST /user/register) is open when user.register_enabled is true. When user.register_require_email_verify is also true, the account is held pending and a verification email is sent; otherwise it is active immediately.

Either way the API returns a session token and the client auto-logs-in:

  • 201 — account active (verified, or verification not required).
  • 202 — pending verification, but the user is already logged in.

Email verification gates purchases and traffic only — an unverified user can log in and browse, but cannot place orders and the proxy nodes will not serve their traffic until email_verified is true. Completing verification (clicking the emailed link, or using the in-app resend) flips that flag and the restriction lifts on the next node sync.

Traffic quota

A user's traffic cap is stored as quota_bytes with this sentinel convention:

  • -1 — unlimited.
  • 0 — no quota (access blocked; the user cannot consume traffic until granted a plan).
  • >0 — capped at that many bytes.

The manager filters the authorized users it pushes to proxy nodes accordingly, so a node never serves traffic for a blocked or over-quota user.

Telegram integration

The manager can run a Telegram bot that delivers alerts and announcements and lets users and admins bind their personal accounts for ticket notifications. It is enabled and configured via DB-backed system config (TelegramConfig):

Key Default Meaning
telegram.enabled false Master switch for the bot.
telegram.bot_token "" BotFather token (secret).
telegram.bot_username "" Bot @username, used to build /start deep links.
telegram.user_bot_enabled false Allow users to self-bind via deep link.
telegram.alert_ticket false Notify linked admins on new tickets / user replies.
telegram.alert_announcement false Forward announcements to linked users.
telegram.alert_order_paid false Notify on paid orders.
telegram.alert_new_registration false Notify on new user registrations.
telegram.alert_node_up false Notify when a node comes online.
telegram.alert_node_down false Notify when a node goes offline.
telegram.alert_traffic_exceeded false Notify when a user exceeds their traffic quota.

Binding uses a /start <code> deep link. The code carries a u_ (user) or a_ (admin) prefix so the bot routes the bind to the right account: admins link from Settings → Telegram in the admin console, users from Settings in the portal.

When an admin replies to a ticket, the owner is notified on the channel they chose when opening it (none / email / telegram). Every admin with a linked Telegram account also receives an alert on each new ticket and user reply.

Support tickets

Tickets are a lightweight support channel between users and admins.

  • Users open tickets (POST /user/tickets), reply, and can close their own ticket (POST /user/tickets/:id/close). When opening one they pick a notification method (notify_method: none | email | telegram); if omitted it defaults to telegram when their account is Telegram-linked, else none.
  • Admins list/view all tickets, reply (POST /admin/tickets/:id/messages), and move them through a status machine open → in_progress → resolved → closed (PUT /admin/tickets/:id/status). A later user reply reopens a closed ticket.

Admins can also broadcast a message to every linked Telegram user via POST /admin/telegram/broadcast (optionally also published as an announcement).

CORS

Cross-origin requests are controlled by the DB-backed cors.allowed_origins system config (default ["*"]). When the admin or user frontend is deployed on a separate origin, add that origin (e.g. https://admin.example.com) via the system-config endpoint so the browser will allow credentialed requests.

Database

Defaults to a local SQLite file vgate_manager.db. To use PostgreSQL set db.dialect: postgres and db.dsn to a Postgres DSN. Tables are auto-migrated on startup (admins, nodes, users, user_nodes, user_node_traffic, traffic hourly stats, refresh tokens, system config, invite codes, email verifications, redemption codes and records, announcements, plans — plan prices are stored as a JSON column on the plan, so there is no separate plan_prices write path (the legacy plan_prices table is read only as a fallback for historical order reads and is not provisioned on a fresh install) — traffic packages, traffic grants, balance transactions, orders, tickets, ticket messages, and ticket read states, …).

Background tasks

Several jobs run automatically (started in cmd/root.go):

  • Expired-order closer — every 5 minutes (orderSvc.CloseExpired).
  • Hourly-stats pruning — once at startup, then every 24 hours (deletes traffic_hourly_stats rows older than 48h).
  • Quota reset — once at startup, then every 24 hours (resets usage counters on quota.reset_day).
  • Traffic-reminder scanner — every hour (reminderSvc.CheckAndSend): sends threshold/days-left reminders on each user's chosen channel (none / email / telegram).

The Telegram bot (when enabled) additionally reconciles its long-poll loop every 15s and runs its own node-up/down (1 min) and traffic-exceeded (15 min) monitors inside internal/service/telegram.go. Hourly traffic is aggregated as nodes report it (event-driven), not by a scheduled job.

Testing

go test ./...
go vet ./... && gofmt -l .

Documentation

The Go Gopher

There is no documentation for this package.

Directories

Path Synopsis
Package cmd provides the cobra CLI for the vgate manager.
Package cmd provides the cobra CLI for the vgate manager.
Package config loads the manager's runtime configuration via viper.
Package config loads the manager's runtime configuration via viper.
internal
api
Package api wires the gin engine: middleware, route groups, and handler registration.
Package api wires the gin engine: middleware, route groups, and handler registration.
api/handler
Package handler contains the gin HTTP handlers, organized by feature.
Package handler contains the gin HTTP handlers, organized by feature.
payment
Package payment defines a provider abstraction over payment gateways so the order service is not hardcoded to alipay.
Package payment defines a provider abstraction over payment gateways so the order service is not hardcoded to alipay.
payment/alipay
Package alipay implements payment.Provider for Alipay's offline QR pre-creation (alipay.trade.precreate, 统一收单线下交易预创建) and async notification verification, using github.com/go-pay/gopay/alipay (classic RSA2 public-key gateway).
Package alipay implements payment.Provider for Alipay's offline QR pre-creation (alipay.trade.precreate, 统一收单线下交易预创建) and async notification verification, using github.com/go-pay/gopay/alipay (classic RSA2 public-key gateway).
payment/apple
Package apple implements payment.Provider for Apple App Store In-App Purchases (IAP), using github.com/go-pay/gopay/apple (App Store Server API v2).
Package apple implements payment.Provider for Apple App Store In-App Purchases (IAP), using github.com/go-pay/gopay/apple (App Store Server API v2).
payment/paypal
Package paypal implements payment.Provider for PayPal Checkout (Orders v2, intent=CAPTURE).
Package paypal implements payment.Provider for PayPal Checkout (Orders v2, intent=CAPTURE).
payment/stripe
Package stripe implements payment.Provider for Stripe Checkout (one-time payment mode).
Package stripe implements payment.Provider for Stripe Checkout (one-time payment mode).
payment/wechat
Package wechat implements payment.Provider for WeChat Pay v3 NATIVE.
Package wechat implements payment.Provider for WeChat Pay v3 NATIVE.
service
Package service contains the manager's business logic.
Package service contains the manager's business logic.
util
Package util provides small ID and secret-generation helpers.
Package util provides small ID and secret-generation helpers.
wire
Package wire holds the wire-format DTOs exchanged with the vgate server (node).
Package wire holds the wire-format DTOs exchanged with the vgate server (node).
pkg
crypto
Package crypto provides small X25519 helpers for Reality / v2 key handling.
Package crypto provides small X25519 helpers for Reality / v2 key handling.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL