# 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: 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/crypto/x25519` | Generate X25519 keys. | | `POST` | `/node/crypto/mldsa65` | Generate an ML-DSA-65 seed. | | `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 auto-issuance). | | `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.