# Core Core is the Nexuma control API. It stores platform state, authenticates users, coordinates nodes, builds node configuration revisions, records traffic, and serves public subscription exports. This page is public operator documentation. It describes behavior, API, environment variables, and Docker deployment without requiring source-code access. ## Capabilities - User registration, login, Telegram OAuth, account approval, profile updates, and role-based access. - Tariff management with price, duration, traffic limit, protocol permissions, node permissions, and external subscription sources. - Subscription lifecycle with activation, cancellation, expiry, auto-renewal, traffic accounting, and public links. - Balance management with deposit, withdrawal, refund, history, and auto-renewal charging rules. - Node registration through one-time codes. - Node heartbeat, status, sync state, revision tracking, config delivery, and error reporting. - Per-node protocol configuration, routing configuration, masking sites, runtime operations, and outbounds. - Routing rule sets with rules, balancers, and blocking options. - External subscription source ingestion and testing. - Public subscription exports for VPN clients. - Audit logs, usage queries, metrics, and health checks. ## Environment Variables | Variable | Required | Default | Description | | --- | --- | --- | --- | | `PORT` | No | `3000` | HTTP port. | | `NODE_ENV` | No | `development` | Runtime mode. | | `DB_HOST` | Yes | `localhost` | Database host. | | `DB_PORT` | No | `5432` | Database port. | | `DB_USER` | Yes | `postgres` | Database user. | | `DB_PASSWORD` | Yes | empty | Database password. | | `DB_NAME` | Yes | `nexuma` | Database name. | | `REDIS_HOST` | Yes | `localhost` | Redis host. | | `REDIS_PORT` | No | `6379` | Redis port. | | `REDIS_PASSWORD` | No | empty | Redis password. | | `REDIS_DB` | No | `0` | Redis database index. | | `JWT_SECRET` | Yes | insecure dev value | Access token secret. Use a long random value. | | `JWT_EXPIRES_IN` | No | `15m` | Access token lifetime. | | `JWT_REFRESH_SECRET` | Yes | insecure dev value | Refresh token secret. Use a different long random value. | | `JWT_REFRESH_EXPIRES_IN` | No | `7d` | Refresh token lifetime. | | `TELEGRAM_BOT_TOKEN` | No | empty | Enables Telegram login and notifications. | | `CORS_ORIGINS` | No | `*` | Comma-separated allowed origins. | ## Docker Compose Minimal Core deployment with Redis and an external database: ```yaml version: '3.9' services: redis: image: redis:7-alpine container_name: nexuma-redis restart: unless-stopped volumes: - redis_data:/data networks: - nexuma core: image: nexuma/core:latest container_name: nexuma-core restart: unless-stopped environment: PORT: 3000 DB_HOST: your-postgres-host DB_PORT: 5432 DB_USER: postgres DB_PASSWORD: change-me DB_NAME: nexuma REDIS_HOST: redis REDIS_PORT: 6379 JWT_SECRET: replace-with-long-random-secret JWT_REFRESH_SECRET: replace-with-another-long-random-secret JWT_EXPIRES_IN: 15m JWT_REFRESH_EXPIRES_IN: 7d CORS_ORIGINS: https://panel.example.com ports: - "3000:3000" depends_on: - redis networks: - nexuma healthcheck: test: ["CMD-SHELL", "wget -qO- http://localhost:3000/health || exit 1"] interval: 30s timeout: 10s retries: 3 start_period: 30s volumes: redis_data: networks: nexuma: driver: bridge ``` Run: ```bash docker compose up -d ``` Health check: ```bash curl http://localhost:3000/health ``` ## API Conventions - JSON request and response bodies are used unless a route explicitly returns text, YAML, or metrics. - User and admin routes use `Authorization: Bearer `. - Admin routes require an admin account. - Node-private routes use `x-node-auth-key`. - Public subscription content is served by UUID and does not require login. - Validation errors return HTTP error responses with an error message. ## Public API | Method | Route | Purpose | | --- | --- | --- | | `GET` | `/health` | Health status. | | `GET` | `/metrics` | Metrics text output. | | `POST` | `/auth/register` | Register with email and password. | | `POST` | `/auth/login` | Login with email and password. | | `POST` | `/auth/refresh` | Refresh tokens. | | `POST` | `/auth/telegram` | Login or register through Telegram OAuth. | | `GET` | `/auth/telegram/bot-id` | Return configured Telegram bot ID. | | `GET` | `/sub/:uuid/info` | Return public subscription metadata. | | `GET` | `/sub/:uuid` | Return generated VPN subscription content. | `GET /sub/:uuid` supports: - `?format=v2ray` - `?format=clash` - `?format=singbox` Missing or unknown `format` falls back to `v2ray`. ## User API | Method | Route | Purpose | | --- | --- | --- | | `GET` | `/me` | Current user profile. | | `PATCH` | `/me/profile` | Update name, email, or password. | | `GET` | `/me/stats` | User summary statistics. | | `GET` | `/me/traffic` | Traffic series by period. | | `GET` | `/me/traffic/daily` | Daily traffic series. | | `GET` | `/me/traffic/hourly-dist` | Hour-of-day traffic distribution. | | `GET` | `/me/balance` | Current balance. | | `GET` | `/me/balance/transactions` | User balance history. | | `GET` | `/me/subscriptions` | User subscriptions. | | `GET` | `/me/links` | User subscription links. | | `GET` | `/me/configs` | Available configs for the user. | | `POST` | `/me/links` | Create a public link. | | `PATCH` | `/me/subscriptions/links/:id` | Rename, enable, disable, or reconfigure a link. | | `DELETE` | `/me/subscriptions/links/:id` | Delete a link. | | `POST` | `/me/subscriptions/:id/reset` | Reset a link UUID. | | `PATCH` | `/me/subscriptions/:id/auto-renew` | Toggle auto-renew. | ## Admin API Groups - `/admin/users` - users, approval status, block flag, profile fields, stats. - `/admin/tariffs` - tariff CRUD. - `/admin/subscriptions` - subscriptions and subscription links. - `/admin/nodes` - nodes, protocols, sync, runtime operations, masking sites, outbounds. - `/admin/routing-rule-sets` - reusable routing templates. - `/admin/external-subscriptions` - external source CRUD and URL testing. - `/admin/logs` - audit log viewer data. - `/admin/usage` - traffic usage rows. - `/admin/xray/parse-link` - parse a proxy share link into outbound settings. See [Core API routes](./core-routes.md) for the detailed route table. ## Node-Private API Node agents consume the private `/node/*` API: - `POST /node/register` - `POST /node/heartbeat` - `GET /node/config/latest` - `POST /node/config/applied` - `POST /node/usage` - `POST /node/outbound-usage` - `POST /node/session-events` - `POST /node/error` See [Core private node routes](./core-private-routes.md) for the payload contract. ## Data Behavior - Users can be `active`, `pending`, or `rejected`. - Nodes can be `active`, `disabled`, `maintenance`, or `error`. - Effective node status is computed from stored status and last heartbeat. - Subscriptions can be `active`, `expired`, or `cancelled`. - A tariff with `durationMonths = null` is indefinite and expires only by traffic limit or cancellation. - A subscription link UUID is the credential used in generated client configs. - Disabling or resetting a link affects generated configs on the next node sync. - Node config revisions increment when node-facing configuration changes. - Active nodes receive only active subscription clients. ## Operational Notes - Run Core behind HTTPS in production. - Keep database and Redis private. - Use unique long secrets for access and refresh tokens. - Restrict CORS to the panel domain. - Back up the database before upgrades. - Rotate node auth keys if a node host is compromised. - Do not expose node-private endpoints directly to the internet.