Files
docs/core-private-routes.md
T
2026-06-01 02:48:06 +03:00

5.5 KiB

Core Private Node Routes

These routes are consumed only by the node agent and require the x-node-auth-key header.

Transport

The node uses two transports to communicate with Core:

  • HTTP — registration only (POST /node/register).
  • gRPC — all other node-to-core calls: heartbeat, usage reporting, config sync, and stats. Core listens on GRPC_PORT (default 3002). The node connects via CORE_GRPC_URL. Set CORE_INSECURE=true on the node to use plaintext instead of TLS.

The HTTP routes for heartbeat, usage, config, and error remain available as a fallback but the node agent uses gRPC by default.

Authentication

  • POST /node/register is the only public route in this group.
  • All other HTTP routes require the x-node-auth-key header.
  • gRPC calls pass the auth key as the x-node-auth-key metadata header (or in the authKey request field as fallback).
  • The auth key is issued by Core during registration and persisted on the node side.

Route table

Method Route Input Output / Notes
POST /node/register RegisterNodeDto Returns { authKey, nodeId }
POST /node/heartbeat NodeHeartbeatDto Returns { ok: true, needSync }
POST /node/usage NodeUsageDto Returns { ok: true }
POST /node/outbound-usage NodeOutboundUsageDto Returns { ok: true }
POST /node/session-events SessionEventsDto Returns { ok: true }
GET /node/config/latest none Returns NodeConfig
POST /node/config/applied NodeConfigAppliedDto Returns { ok: true }
POST /node/error NodeErrorDto Returns { ok: true }

Request payloads

RegisterNodeDto

  • code: string
  • name: string
  • host: string
  • ip: string
  • region: string

NodeHeartbeatDto

  • ip?: string
  • revision?: number

The node sends its current revision in heartbeats. Core uses it to decide whether a sync is needed.

NodeUsageDto

  • entries: UsageEntryDto[]

UsageEntryDto fields:

  • userId: number
  • subscriptionId?: number | null
  • nodeProtocolId: number
  • bytesUp: number
  • bytesDown: number
  • recordedAt: string

NodeOutboundUsageDto

  • items: OutboundUsageItem[]

OutboundUsageItem fields:

  • tag: string
  • bytesUp: number
  • bytesDown: number

SessionEventsDto

  • events: SessionEventEntryDto[]

SessionEventEntryDto fields:

  • userId: number
  • protocol: VpnProtocol
  • eventType: SessionEventType
  • occurredAt: string
  • ipAddress?: string

NodeConfigAppliedDto

  • revision: number

NodeErrorDto

  • message: string
  • code?: string
  • details?: Record<string, unknown>

NodeConfig

The config returned by GET /node/config/latest has this structure:

{
  revision: number
  clientMap: Record<string, { userId: number; subscriptionId: number | null }>
  mtprotoClientMap: Record<string, { userId: number; subscriptionId: number | null }>
  services: {
    xray?: XrayServiceConfig
    mtproto?: MtProtoServiceConfig
  }
}

Important notes:

  • clientMap maps subscription link UUIDs to the user and subscription — used for xray traffic attribution.
  • mtprotoClientMap maps MTProto link UUIDs to the user and subscription — used for telemt traffic attribution.
  • services.xray contains the Xray inbounds, routing, and outbounds for the node.
  • services.mtproto contains MTProto inbounds for telemt.
  • The node stores the current revision and client maps locally after a successful apply.

Route semantics

  • POST /node/heartbeat updates lastSeenAt and can request a sync when the node revision is behind.
  • POST /node/usage stores per-minute usage rows and increments subscription traffic counters.
  • POST /node/outbound-usage increments node_outbounds.traffic_bytes_up/down.
  • POST /node/session-events stores online/offline events in session_events.
  • POST /node/config/applied marks the node sync status as synced.
  • POST /node/error marks the node as error and the sync status as failed.

gRPC interface (NodeService)

Core exposes a gRPC service that the node agent uses for all real-time communication. The service name is nodeservice.NodeService and is defined in proto/node-service.proto.

Authentication: pass x-node-auth-key as gRPC metadata (or in the authKey field of the request as fallback).

Method Request fields Response fields Notes
Heartbeat authKey, revision?, ip? ok, needSync Equivalent to POST /node/heartbeat
ReportUsage authKey, entries[] ok Equivalent to POST /node/usage
ReportOutboundUsage authKey, items[] ok Equivalent to POST /node/outbound-usage
GetLatestConfig authKey revision, clientMapJson, mtprotoClientMapJson, servicesJson Config fields are JSON-encoded strings
ConfirmConfigApplied authKey, revision ok Equivalent to POST /node/config/applied
ReportNodeStats authKey, system metrics fields ok Reports CPU/RAM/disk/network/xray/mtproto snapshot; stored in Redis; drives GET /admin/nodes/:id/runtime-status and stats history

ReportNodeStats fields: uptimeSeconds, cpuPercent, cpuCores, ramUsed, ramTotal, diskUsed, diskTotal, netRxPerSec, netTxPerSec, netRxTotal, netTxTotal, xrayRunning, xrayUptimeSeconds?, mtprotoJson.

The node sends ReportNodeStats on every heartbeat cycle. GET /admin/nodes/:id/runtime-status returns the latest stored snapshot without polling the node; ?fromNode=true forces a live HTTP fetch instead.