Skip to content

Agent Control Protocol

Status: Current

Last reviewed: 2026-05-30

The agent control protocol is defined in common/proto/agent.proto in both nexus-backend and nexus-agent.

Service

SecureAgentService is the service registered by nexus-backend/src/main.rs.

protobuf
service SecureAgentService {
  rpc OpenSession(OpenSessionRequest) returns (OpenSessionResponse);
  rpc Control(stream SecureFrame) returns (stream SecureFrame);
}

The protobuf still contains the older AgentService RPCs (Register, Heartbeat, StreamConfig, and ReportMetrics) for compatibility. They are not the production service wired in the backend entry point.

Secure Session

Agents connect with h2c gRPC, then open a Nexus secure control session. The agent environment uses:

  • NEXUS_AGENT_ID
  • NEXUS_CONTROL_ENDPOINT
  • NEXUS_CONTROL_PSK
  • NEXUS_CONTROL_REKEY_INTERVAL_SECS (optional; default 6 hours)

OpenSession authenticates the agent with the per-node PSK verifier and an ephemeral key exchange. The backend stores a verifier and fingerprint, not the plaintext PSK. After the session opens, control messages are carried as AEAD-protected SecureFrame payloads.

The agent proactively reconnects secure control sessions after the configured rekey interval so that new session keys are derived even when the stream stays healthy for a long time.

Agent Hello

The first encrypted payload carries:

  • node_id
  • public_ipv4
  • public_ipv6
  • agent_version
  • multiplex
  • multiplex_port
  • detected_addresses

Heartbeat

HeartbeatRequest and HeartbeatResponse are encrypted payloads inside the secure control stream.

Agent sends:

  • node_id
  • sequence
  • timestamp
  • CPU and memory usage.
  • uptime.
  • repeated peer link metrics.
  • runtime listener and route tables.

Backend responds with:

  • ok
  • ack_sequence
  • optional commands.

Current command enum includes:

  • RELOAD_CONFIG
  • RESTART_PINGORA
  • RUN_DIAGNOSTICS

Config Streaming

ConfigRequest and ConfigUpdate are encrypted payloads inside the secure control stream.

The production secure-control path sends an authoritative RuntimeConfigSnapshot inside ConfigUpdate. The snapshot carries one generation for the node and is applied as one runtime target:

  • PingoraConfig
  • L3TunnelConfig
  • NodeConfig

Legacy ConfigUpdate payloads can still carry split updates for compatibility:

  • PingoraConfig
  • NodeConfig
  • L3TunnelConfig

Agents ignore stale snapshot generations and report each snapshot apply result with ConfigApplyReport.

See Runtime Config Hot Reload for the full generation, replay, rollback, and port conflict design.

NodeConfig carries connectivity settings:

  • multiplex
  • multiplex_port

PingoraConfig is the current L4 gateway config envelope. It carries:

  • upstream clusters.
  • TCP proxy rules.
  • HTTP proxy rules.
  • TLS config.
  • QUIC rules.
  • UDP rules.
  • listener policies for compatibility conflict handling.

UpstreamCluster in the protobuf is broader than the console-facing L4 upstream CRUD object. The control envelope still carries a legacy health_check submessage for runtime compatibility, while the console API now exposes server_names and health_check_interval_ms directly and rejects health_check_path.

Listener policy protobuf:

protobuf
message ListenerPolicy {
  string transport = 1;      // "tcp" or "udp"; QUIC uses UDP namespace
  string listen_addr = 2;
  int32 listen_port = 3;
  repeated string priority_order = 4; // reality,tls,noise,raw
}

The agent uses listener_policies only for compatibility cases that cannot be merged into a same-port route table. TCP REALITY/TLS/SSLPREREAD plus one RAW fallback can share one TCP SNI-family listener. UDP Noise, one UDP RAW fallback, and embedded QUIC REALITY routes can share one UDP socket when their early packet signals are unambiguous.

Runtime listener heartbeat protobuf:

protobuf
message HeartbeatRequest {
  string node_id = 1;
  uint64 sequence = 2;
  google.protobuf.Timestamp timestamp = 3;
  double cpu_usage = 4;
  double memory_usage = 5;
  uint64 uptime_seconds = 6;
  repeated LinkMetric link_metrics = 7;
  repeated RuntimeListener runtime_listeners = 8;
}

message RuntimeListener {
  string transport = 1;
  string listen_addr = 2;
  int32 listen_port = 3;
  string state = 4;
  repeated RuntimeRoute routes = 5;
  uint64 bytes_in = 6;
  uint64 bytes_out = 7;
  uint64 active_sessions = 8;
  uint64 total_sessions = 9;
  uint64 error_sessions = 10;
}

message RuntimeRoute {
  string service = 1;
  string payload = 2;
  string outer = 3;
  string security = 4;
  string match_kind = 5;
  string match_value = 6;
  string next_hop = 7;
}

Transport Profiles

Transport profiles separate payload protocol, outer transport, and security layer.

Current protobuf enums:

text
PayloadProtocol:
  TCP
  UDP
  IP

OuterTransport:
  TCP
  UDP
  QUIC
  FAKE_TCP

SecurityLayer:
  RAW
  TLS
  REALITY
  NOISE

Generic IP/TUN transport payloads use payload=IP, outer=QUIC, and security=REALITY when carried by QUIC REALITY. L4 UDP over FAKE_TCP uses payload=UDP, outer=FAKE_TCP, and security=RAW.

See FAKE_TCP Packet Format and FAKE_TCP Dataplane Modes for packet format and dataplane behavior.

Rule Types

TcpProxyRule

Supports:

  • RAW/TLS/REALITY mode.
  • inbound REALITY private key and metadata.
  • outbound/upstream REALITY.
  • outbound/upstream QUIC REALITY.
  • upstream TLS SPKI SHA-256 pins via upstream_tls_spki_pins_sha256.
  • transport profile.

When upstream TLS is enabled, the agent requires at least one SPKI pin and verifies SHA-256 over the leaf certificate's SubjectPublicKeyInfo DER. Business upstream TLS does not use ordinary no-verify.

UdpRule

Supports:

  • RAW/ENC mode.
  • UDP Noise key material.
  • outbound/upstream QUIC REALITY DATAGRAM.
  • transport profile.

QuicRule

Supports:

  • Quinn-based QUIC REALITY listener.
  • REALITY server names, short IDs, target host, and target port.
  • max streams per connection.
  • transport profile.

L3TunnelRule

Carries:

  • network id, network name, and enabled flag.
  • local endpoint and peer endpoint.
  • routes and allowed-source prefixes.
  • TUN configuration such as interface name, address family, prefixes, MTU, and feature flags.
  • REALITY transport material and camouflage target metadata.
  • DATAGRAM context id.
  • local runtime role: listener or connector.

Metrics

MetricsReport contains:

  • connection metrics.
  • bandwidth metrics.
  • Pingora metrics.

DATAGRAM-specific performance counters currently live in the agent implementation and test logs; formal control-plane reporting for those counters is still a roadmap item.

Config Replay And Restart Behavior

The agent does not persist local L4/L3 config cache files. It no longer reads or writes agent-state.nxc, agent-state.previous.nxc, or agent-state.json.

Runtime behavior:

  • When the control plane disconnects after config has been applied, existing listeners and tunnels keep running from in-process state.
  • When the agent process restarts, it sends ConfigRequest with config_version = 0 and waits for authoritative replay from the control plane. Replay is a full RuntimeConfigSnapshot, including L4, L3, and NodeConfig.
  • If the backend is unavailable at startup, no local last-known-good config is applied.
  • If the backend detects config broadcast lag on a connected stream, it replays the current authoritative snapshot instead of relying on missed deltas.

See Security Hardening for the current pinning, replay, rekey, and REALITY rotation security model.

NexusNet documentation