Skip to content

feat(xray): embedded REALITY data-plane runtime on the node#14

Merged
bodaay merged 2 commits into
mainfrom
feat/xray-reality-runtime
Jun 6, 2026
Merged

feat(xray): embedded REALITY data-plane runtime on the node#14
bodaay merged 2 commits into
mainfrom
feat/xray-reality-runtime

Conversation

@bodaay

@bodaay bodaay commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

The node gains a second data plane alongside AmneziaWG: an embedded xray-core VLESS+REALITY server, managed in-process so the node stays a single static binary.

What

  • internal/xray/identity.go — the node's REALITY identity, a Curve25519 keypair generated once and persisted (xray-node.json), mirroring the AmneziaWG identity. coxswain caches the base64url public key to build a matching REALITY client; the private key never leaves the node.
  • internal/xray/runtime.go — embeds xray-core, renders the VLESS+REALITY server config from the identity + pushed policy, and swaps in a fresh instance on every change (validating the new config before disturbing the running one). Apply (full replace, revision-guarded), AddClient/RemoveClient (live reload), Status, Restart, Stop.
  • controlPushConfig/AddPeer/RemovePeer/ListPeers branch on protocol and handle PROTOCOL_XRAY_REALITY (XRayRealityConfig: VLESS clients + REALITY camouflage policy). GetStatus reports the REALITY identity + service health. RestartService is now implemented for both protocols (AmneziaWG re-applies its conf; XRay swaps a fresh instance).
  • cli/run.go loads the XRay identity and wires the runtime into the NodeControl server. The service starts down until coxswain provisions a REALITY device.

Why this is safe to embed

The user's mandate is a single statically-linked binary. The node with xray-core embedded builds clean:

$ file node-xray
ELF 64-bit LSB executable, x86-64, statically linked, stripped
$ ldd node-xray
        not a dynamic executable

(CGO_ENABLED=0, -tags netgo,osusergo, amd64, 33MB — built on the native builder.)

Tests

internal/xray/xray_test.go is the in-repo form of the embedding de-risk probe: it boots a real in-process REALITY server, confirms it binds a TCP port, exercises live client add/remove, and tears it down (port 0). Identity persist/reload is also covered. Full go test ./... green; go vet clean.

Pairs with the proto contract already on main (node #13 / helm #49: XRayRealityConfig, XRayRealityInfo, Peer.flow).

🤖 Generated with Claude Code

The node now owns a second data plane alongside AmneziaWG: an embedded
xray-core VLESS+REALITY server, managed entirely in-process so the node
stays a single static binary (CGO_ENABLED=0; verified `not a dynamic
executable`).

- internal/xray/identity.go: the node's REALITY identity — a Curve25519
  keypair generated once and persisted (xray-node.json), mirroring the
  AmneziaWG identity. coxswain caches the base64url public key to build a
  matching REALITY client; the private key never leaves the node.
- internal/xray/runtime.go: the runtime embeds xray-core, renders the
  VLESS+REALITY server config from the identity + pushed policy, and swaps
  in a fresh instance on every change (validating the new config before
  disturbing the running one). Apply (full replace, revision-guarded),
  AddClient/RemoveClient (live reload), Status, Restart, Stop.
- control: PushConfig/AddPeer/RemovePeer/ListPeers now branch on protocol
  and handle PROTOCOL_XRAY_REALITY (XRayRealityConfig: VLESS clients +
  REALITY camouflage policy); GetStatus reports the REALITY identity +
  service health; RestartService is implemented for both protocols
  (AmneziaWG re-applies its conf, XRay swaps a fresh instance).
- cli/run.go loads the XRay identity and wires the runtime into the
  NodeControl server; the service starts down until coxswain provisions a
  REALITY device with PushConfig.

xray-core (v1.260327.0) embedding is covered by an in-process test that
binds a real REALITY server, exercises live client add/remove, and tears
it down — the in-repo form of the embedding de-risk probe.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Khalefa <khalefa@alahmad.org>
…er row id

The node's xrayClientID read peer.id first, but coxswain carries the VLESS UUID
in peer.public_key (peers.public_key = the UUID for XRay; the WireGuard key for
AmneziaWG) — peer.id is coxswain's row id. So the REALITY server registered the
client under the row id while the client presented its real UUID: REALITY auth
succeeded, then VLESS rejected the unknown UUID and the connection EOF'd
(observed live: Mac/clean-net -> node-1 REALITY relayed to the decoy, then drop).

Reading the UUID from public_key (id as fallback) fixes it. Verified live on the
fleet: client -> node-1 VLESS+REALITY -> egress at node-1.

Also gofmt internal/netpolicy/netpolicy_test.go under go 1.26 (CI uses `stable`
= 1.26, whose gofmt reformats it; unrelated to XRay).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Khalefa <khalefa@alahmad.org>
@bodaay bodaay merged commit 11ba7d3 into main Jun 6, 2026
2 checks passed
@bodaay bodaay deleted the feat/xray-reality-runtime branch June 6, 2026 19:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant