183 lines
6.9 KiB
Markdown
183 lines
6.9 KiB
Markdown
# Node
|
|
|
|
Node is the agent installed on each VPN/proxy server. It registers with Core, receives configuration revisions, applies local services, reports usage, and exposes authenticated runtime actions.
|
|
|
|
This page is public operator documentation. It describes setup, behavior, environment variables, Docker deployment, and the node HTTP API without requiring source-code access.
|
|
|
|
## Capabilities
|
|
|
|
- One-time registration with Core.
|
|
- Persistent auth key storage.
|
|
- Config sync by revision.
|
|
- Xray install, restart, validation, GeoIP update, key generation, and outbound probing.
|
|
- TLS-ECH, X25519, ML-DSA-65, and VLESS encryption key generation.
|
|
- MTProto install and restart.
|
|
- Nginx masking site management.
|
|
- System status reporting with CPU, RAM, disk, network, and process state.
|
|
- Heartbeat reporting.
|
|
- Per-user and per-subscription traffic reporting.
|
|
- Outbound traffic reporting for proxy chains.
|
|
- Cloudflare WARP outbound config generation.
|
|
- Session event reporting.
|
|
- Runtime error reporting.
|
|
- Crash watchdog for local services.
|
|
|
|
## Environment Variables
|
|
|
|
| Variable | Required | Default | Description |
|
|
| --- | --- | --- | --- |
|
|
| `PORT` | No | `3001` | Local node agent HTTP port. |
|
|
| `NODE_ENV` | No | `development` | Runtime mode. |
|
|
| `CORE_URL` | Yes | `http://localhost:3000` | Core HTTP API URL reachable from the node server. Used for registration. |
|
|
| `CORE_GRPC_URL` | Yes | `localhost:3002` | Core gRPC address (`host:port`). Used for heartbeat, usage reporting, and config sync. |
|
|
| `CORE_INSECURE` | No | `false` | Set to `true` to use plaintext gRPC instead of TLS (for internal/private networks). |
|
|
| `REGISTRATION_CODE` | First start only | empty | One-time node registration code generated in the panel. |
|
|
| `NODE_AUTH_KEY` | No | empty | Optional fallback auth key when no key file exists. |
|
|
| `HEARTBEAT_INTERVAL_SEC` | No | `30` | Heartbeat interval in seconds. |
|
|
|
|
Persistent state is stored under `/var/lib/vpnnode`.
|
|
|
|
Keep this directory on a persistent Docker volume. It contains the auth key, generated configs, binaries, stats state, and masking-site files.
|
|
|
|
## Docker Compose
|
|
|
|
Create a `docker-compose.yml` on the VPN/proxy server:
|
|
|
|
```yaml
|
|
version: '3.9'
|
|
|
|
services:
|
|
node:
|
|
image: git.kiow.ru/nexuma/node:latest
|
|
container_name: nexuma-node
|
|
restart: unless-stopped
|
|
environment:
|
|
PORT: 3001
|
|
CORE_URL: https://core.example.com
|
|
CORE_GRPC_URL: core.example.com:3002
|
|
CORE_INSECURE: "false"
|
|
REGISTRATION_CODE: paste-one-time-code-here
|
|
HEARTBEAT_INTERVAL_SEC: 30
|
|
volumes:
|
|
- node_data:/var/lib/vpnnode
|
|
ports:
|
|
- "3001:3001"
|
|
# Add protocol ports here, for example:
|
|
# - "443:443"
|
|
# - "443:443/udp"
|
|
cap_add:
|
|
- NET_ADMIN
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "wget -qO- http://localhost:3001/health || exit 1"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 15s
|
|
|
|
volumes:
|
|
node_data:
|
|
```
|
|
|
|
Run:
|
|
|
|
```bash
|
|
docker compose up -d
|
|
```
|
|
|
|
After successful registration, remove `REGISTRATION_CODE` and redeploy:
|
|
|
|
```bash
|
|
docker compose up -d
|
|
```
|
|
|
|
## Registration
|
|
|
|
1. In the panel, open `Nodes`.
|
|
2. Generate a registration code.
|
|
3. Set `CORE_URL` and `REGISTRATION_CODE` on the node server.
|
|
4. Start the node container.
|
|
5. Wait until the node appears as registered.
|
|
6. Remove `REGISTRATION_CODE`.
|
|
7. Keep the `node_data` volume for future restarts.
|
|
|
|
If the persistent volume is deleted, the node loses its auth key and must be registered again or started with `NODE_AUTH_KEY`.
|
|
|
|
## Local HTTP API
|
|
|
|
Public:
|
|
|
|
| Method | Route | Purpose |
|
|
| --- | --- | --- |
|
|
| `GET` | `/health` | Health check. |
|
|
|
|
All other routes require `x-node-auth-key`.
|
|
|
|
| Method | Route | Purpose |
|
|
| --- | --- | --- |
|
|
| `GET` | `/node/status` | Runtime status and resource usage. |
|
|
| `POST` | `/node/apply-config` | Trigger config pull and apply. |
|
|
| `POST` | `/node/xray/restart` | Restart Xray. |
|
|
| `POST` | `/node/xray/install` | Install an Xray version. |
|
|
| `POST` | `/node/geoip/update` | Update GeoIP/geosite files. |
|
|
| `POST` | `/node/xray/probe-outbound` | Test an outbound connection and return latency. |
|
|
| `POST` | `/node/xray/tls-ping` | Run `xray tls ping <domain>`; vet a REALITY target (incl. ML-DSA-65 readiness). |
|
|
| `POST` | `/node/crypto/x25519` | Generate X25519 keys. |
|
|
| `POST` | `/node/crypto/mldsa65` | Generate an ML-DSA-65 seed/verify pair. |
|
|
| `POST` | `/node/crypto/tls-ech` | Generate TLS-ECH keys. |
|
|
| `POST` | `/node/crypto/vlessenc` | Generate VLESS encryption material. |
|
|
| `POST` | `/node/mtproto/restart` | Restart MTProto processes. |
|
|
| `POST` | `/node/mtproto/install` | Install an MTProto version. |
|
|
| `GET` | `/node/nginx/sites` | List masking sites. |
|
|
| `GET` | `/node/nginx/sites/:domain` | Get one masking site. |
|
|
| `GET` | `/node/nginx/sites/:domain/certificate` | Get certificate and domain validity info. |
|
|
| `PUT` | `/node/nginx/sites` | Upsert one domain masking site (TLS upload or ACME auto-issuance; `keyType=ecdsa`\|`rsa`, RSA-4096 for ML-DSA-65 self-mask). |
|
|
| `PUT` | `/node/nginx/site` | Upsert legacy default masking site. |
|
|
| `GET` | `/node/nginx/site` | Get current masking site status. |
|
|
| `DELETE` | `/node/nginx/sites/:domain` | Delete one masking site. |
|
|
| `DELETE` | `/node/nginx/site` | Delete current masking site. |
|
|
| `POST` | `/node/nginx/restart` | Restart nginx. |
|
|
| `POST` | `/node/warp/generate` | Register an anonymous Cloudflare WARP account and return a WireGuard outbound config. |
|
|
|
|
These endpoints are intended to be called by Core. Protect the agent port with firewall rules or private networking.
|
|
|
|
## Config Sync
|
|
|
|
- The node keeps the latest applied revision locally.
|
|
- The node sends heartbeats to Core over gRPC (`CORE_GRPC_URL`). If Core's revision is ahead, the heartbeat response sets `needSync: true` and the node pulls the latest config immediately via gRPC.
|
|
- Core can also push a sync trigger to the node over HTTP (`POST /node/apply-config`).
|
|
- The node fetches the config from Core and applies it. On success it confirms the applied revision; on failure it reports an error and keeps the previous valid config where possible.
|
|
|
|
## Traffic and Events
|
|
|
|
The node reports:
|
|
|
|
- user traffic
|
|
- subscription traffic attribution
|
|
- per-protocol usage
|
|
- outbound usage
|
|
- online/offline session events
|
|
- service crash and config errors
|
|
|
|
Traffic is flushed periodically. If reporting fails temporarily, the node keeps pending stats for the next flush where possible.
|
|
|
|
## Status Output
|
|
|
|
`GET /node/status` returns operational status including:
|
|
|
|
- system uptime
|
|
- CPU usage and core count
|
|
- RAM usage
|
|
- disk usage
|
|
- network transfer rates and totals
|
|
- Xray running state and uptime
|
|
- MTProto process state and connection counts
|
|
|
|
## Operations
|
|
|
|
- Use node sync from the panel after changing protocols, routing, or outbounds.
|
|
- Open every configured inbound port in Docker and the server firewall.
|
|
- Keep `/var/lib/vpnnode` persistent.
|
|
- Keep the node agent API private.
|
|
- Remove one-time registration codes after registration.
|
|
- Rotate auth keys when moving or rebuilding a server.
|