UPDATE
This commit is contained in:
@@ -1,59 +1,212 @@
|
||||
# Core
|
||||
|
||||
REST API server — the control plane of Nexuma. Manages users, tariffs, subscriptions, nodes, traffic accounting, and generates subscription configs for VPN clients.
|
||||
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.
|
||||
|
||||
## Configuration
|
||||
This page is public operator documentation. It describes behavior, API, environment variables, and Docker deployment without requiring source-code access.
|
||||
|
||||
Edit the environment variables in [`docker-compose.base.yml`](./docker-compose.base.yml):
|
||||
## Capabilities
|
||||
|
||||
| Variable | Required | Description |
|
||||
|----------|----------|-------------|
|
||||
| `DB_HOST` | Yes | PostgreSQL host |
|
||||
| `DB_PORT` | Yes | PostgreSQL port |
|
||||
| `DB_USER` | Yes | Database user |
|
||||
| `DB_PASSWORD` | Yes | Database password |
|
||||
| `DB_NAME` | Yes | Database name |
|
||||
| `REDIS_HOST` | Yes | Redis host |
|
||||
| `REDIS_PORT` | Yes | Redis port |
|
||||
| `JWT_SECRET` | Yes | Access token secret |
|
||||
| `JWT_REFRESH_SECRET` | Yes | Refresh token secret |
|
||||
| `JWT_EXPIRES_IN` | No | Access token TTL (default: `15m`) |
|
||||
| `JWT_REFRESH_EXPIRES_IN` | No | Refresh token TTL (default: `7d`) |
|
||||
| `TELEGRAM_BOT_TOKEN` | No | Enables Telegram bot and OAuth login |
|
||||
| `CORS_ORIGINS` | No | Allowed CORS origins (default: `*`) |
|
||||
- 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.
|
||||
|
||||
## API Overview
|
||||
## Environment Variables
|
||||
|
||||
### Public
|
||||
| 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. |
|
||||
|
||||
- `POST /auth/register` — create account
|
||||
- `POST /auth/login` — login, get JWT tokens
|
||||
- `POST /auth/refresh` — refresh access token
|
||||
- `GET /sub/:uuid` — subscription config for VPN clients (base64 URI list)
|
||||
- `GET /sub/:uuid/info` — subscription info (JSON)
|
||||
- `GET /health`, `GET /metrics`
|
||||
## Docker Compose
|
||||
|
||||
### User
|
||||
Minimal Core deployment with Redis and an external database:
|
||||
|
||||
- `GET /me` — profile and balance
|
||||
- `GET /me/subscriptions` — subscriptions and links
|
||||
- `GET /me/balance/transactions` — transaction history
|
||||
```yaml
|
||||
version: '3.9'
|
||||
|
||||
### Admin
|
||||
services:
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: nexuma-redis
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
networks:
|
||||
- nexuma
|
||||
|
||||
- **Users** — CRUD, status approval (pending / active / rejected), balance management
|
||||
- **Tariffs** — CRUD
|
||||
- **Nodes** — CRUD, protocol management, xray/MTProto version install, GeoIP update, outbounds
|
||||
- **Subscriptions** — create, manage, auto-renewal toggle
|
||||
- **Routing rule sets** — xray-native rules and balancers
|
||||
- **External subscriptions** — aggregate external VPN share URLs
|
||||
- **Audit logs**
|
||||
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
|
||||
|
||||
## Tariff types
|
||||
volumes:
|
||||
redis_data:
|
||||
|
||||
| Type | Expiry | Auto-renews |
|
||||
|------|--------|-------------|
|
||||
| Timed paid | By date | If balance ≥ 0 |
|
||||
| Timed free | By date | Always |
|
||||
| Indefinite paid | When traffic exhausted | If balance ≥ 0 |
|
||||
| Indefinite free | When traffic exhausted | Always |
|
||||
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 <access_token>`.
|
||||
- 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.
|
||||
|
||||
Reference in New Issue
Block a user