English · Русский
A client core based on sing-box for the desktop launcher, LxBox and routers. Compatibility with current Xray and AmneziaWG servers, a daemon and observability for the apps.
- Compatibility with today's servers and networks. REALITY with the hybrid post-quantum
ML-KEM key exchange (X25519MLKEM768) that current Xray requires, XHTTP, VLESS
encryption, AmneziaWG 3.x, ClientHello fragmentation, WARP over MASQUE. - A core built to be operated by demanding consumers — the desktop launcher, the LxBox Android app, routers: daemon mode, observability over gRPC, energy saving with sleep for idle tunnels, router builds.
- Extra capabilities. Multi-hop
chain, load balancing, DNS server groups, protocol sniffers. - Bugs closed where they were found — in real use, each with a test and a condition for retiring the patch.
Details of every item — Features.
- Why the fork exists
- About sing-box
- Features
- Build
- Configuration — a quick tour
- The
lxddaemon - How the fork is maintained
- Repository map
- Links
- License
The servers people connect to often run Xray and AmneziaWG and move faster than sing-box;
examples of the lag: REALITY, the post-quantum key exchange, XHTTP, VLESS encryption,
AmneziaWG 3.x. sing-box-lx closes that gap on its own side without forking away: every
upstream/stable release is merged within days, our code lives in its own files behind build
tags, and a build without them is upstream byte for byte — see
How the fork is maintained.
The Go module and the binary keep upstream's name; the -lx suffix lives in the version string
only. The rules every feature here lives by — CONSTITUTION.
sing-box by SagerNet is the universal proxy platform this
core is built on: the protocols, the routing engine, the TUN stack and the libbox binding for
mobile all come from there. Its documentation — sing-box.sagernet.org,
its README — on GitHub.
| Feature | Config surface | What you get | Build tag | Status |
|---|---|---|---|---|
| XHTTP — 002 | transport.type: xhttp |
Xray-compatible "splithttp": modes auto / packet-up / stream-up / stream-one over TLS, REALITY or h2c; xmux connection reuse; obfuscation options |
with_xhttp |
live-validated against Xray servers; stream-one (the auto+REALITY path) device-verified |
| AmneziaWG 2.0 / 3.x — 003 | wireguard endpoint fields jc/jmin/jmax, s1–s4, h1–h4, i1–i5, AWG 3.x header_protection_key, padding, trailers, ranged timings |
The full obfuscation set of amneziawg-go v3.1, plus WireSock-style masquerade sugar id/ip/ib that builds the I1 decoy for you |
with_awg |
verified against live AWG 2.0 and 3.1 servers; ip=quic decoy device-proven against an LTE/WARP DPI |
| MASQUE / Cloudflare WARP — 009 | type: masque outbound |
CONNECT-IP (RFC 9484) over HTTP/3 or HTTP/2 through a userspace network stack; profile: cloudflare for WARP; standard tls block; idle-suspend and self-healing reconnect |
— | device-verified on Wi-Fi and LTE, h3 and h2 |
| REALITY against current Xray — 017 | tls.reality + tls.utls.fingerprint, tls.reality.key_share, tls.fragment / record_fragment |
The hybrid post-quantum key share X25519MLKEM768 that Xray ≥ v26.9.8 requires, on chrome, firefox, safari (the latter two via the utls fork submodule); per-node key_share: classical | hybrid; ClientHello fragmentation now applies to REALITY |
— (inside with_utls) |
stand-verified against Xray v26.9.9 and older; firefox/safari field-confirmed; key_share and fragmentation await a field run |
VLESS encryption — 012 |
encryption field on a vless outbound |
Post-quantum mlkem768x25519plus layer inside VLESS, beneath the transport and independent of TLS/REALITY |
— | device-verified: previously dead subscription nodes came alive |
| Feature | Config surface | What you get | Build tag | Status |
|---|---|---|---|---|
chain outbound — 015 |
type: chain |
A virtual multi-hop path assembled at runtime from groups and nodes; groups are never copied, hops are runtime links; transparent direct, automatic MTU for tunnel links, strip / rewrite |
with_lx_chain |
live stand on real hops; WireGuard links on device pending |
| DNS server group — 013 | dns.servers[].type: group |
One DNS server over several: stable / fastest / parallel on a TTL model, fan-out with a budget, survival visibility |
— | shipped; field run pending |
| Load balancing and failover — 007 | urltest with mode: round_robin, balancer{…}; least_test reacts to live dial errors |
Round-robin pool with lazy health checks and sticky slots; dead-path errors penalise a node and retry through the best candidate | with_lx_command (only GetPool) |
device-verified on a real multi-node pool |
| Protocol sniffers — 016 | sniff action names wireguard, openvpn, ike, tailscale, sip |
Recognise other devices' VPN tunnels and calls behind a router by the shape of the first packet; sits ahead of upstream's uTP sniffer that mislabelled WireGuard as bittorrent | — | shipped; router run pending |
| Feature | Config surface | What you get | Build tag | Status |
|---|---|---|---|---|
| Observability — 006 | libbox CommandClient extensions |
URLTestOutbound, GetRules, GetGroups, GetOutbounds, GetPool, GetDNSGroups, GetRunningConfig, GetChains, SubscribeDNSQueries, Connection.detourList — what the Android client lives on |
with_lx_command |
shipped, consumed by LxBox |
| Idle-suspend (energy) — 008 | route.lx_idle_suspend / lx_idle_suspend_reachable / lx_idle_teardown, urltest.passive_check |
Three sleep levels for idle WireGuard/AWG endpoints: battery, heat and RAM on multi-node mobile profiles | with_lx_idle_suspend (baked into the AAR) |
device-verified: RSS −31 % |
lxd daemon — 014 |
sing-box lxd subcommand |
The core in-process behind a management channel that outlives every config change: gRPC + admin-REST on one port, apply with automatic rollback, mTLS with enrolment, service install, host telemetry |
with_lxd |
device-verified on macOS; OpenWrt installer scripts field-tested |
Not supported, by design: server halves of the above; Xray's post-quantum REALITY signatures (
pqv/ ML-DSA-65) andspiderX— a different mechanism from the key exchange, absent from sing-box; theedge,ios,android,360,
Builds go through Makefile.lx; the upstream Makefile is untouched.
git clone --recurse-submodules https://github.com/Leadaxe/sing-box-lx
make -f Makefile.lx lx-build # → ./sing-box, version like vX.Y.Z-lx.N
make -f Makefile.lx lx-check # validate the sample configs in lx-test/config/-
--recurse-submodulesis required for every build. Four dependencies are swapped for fork submodules throughreplaceingo.mod:sing-tun,gvisorandutlsunconditionally,wireguard-go(the AmneziaWG runtime) behindwith_awg. A clone without them does not compile. -
The tag set (
make -f Makefile.lx lx-print-tagsis the single source of truth):with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_clash_api,with_naive_outbound,with_purego,badlinkname,tfogo_checklinkname0,with_xhttp,with_awg,with_lx_command,with_lxd,with_openvpn,with_openconnect,with_lx_chain,with_tailscaleThat is upstream's client feature set minus the server-only tags (
with_acme,with_ccm/with_ocm), pluswith_purego(CGO-free cross-compile, sowith_naive_outboundbuilds atCGO=0) and our own tags.with_lx_command(libbox command-protocol extensions) andwith_lxd(the daemon) are independent by design. -
Toolchain. The Go version is pinned in
go.versionand read by every CIsetup-gostep; the upstream version the fork is based on lives inupstream.version. Notgo-version-file: go.mod— that would resolve to a language floor, not a toolchain, and a Go 1.24 AAR kills every quic-go outbound on Android. -
Android (
libbox.aar).make lib_install && make lib_androidbuildslibbox.aar(SDK 23) andlibbox-legacy.aar(SDK 21) withwith_xhttp/with_awg/with_lx_command/with_lx_idle_suspend/with_lx_chain/with_tailscalebaked in.clash_apiis dropped from the AAR only — the Android client manages the core over the nativeCommandClient. -
Release matrix (
lx-release.ymlon av*-lx.*tag): desktop binaries for linux / darwin / windows incl. a Windows 7 (32-bit) legacy build (without naive andlxd), linux-musl and mips/mipsle softfloat for routers, both AARs,SHA256SUMS. Release notes come fromdocs-lx/releases/.
One snippet per feature. Field tables, defaults and every option — docs-lx/lx-config.md (RU); wire-level detail for XHTTP, AmneziaWG and MASQUE — docs-lx/lx-protocols-transports.md (RU).
{
"type": "wireguard", // … standard wireguard fields …
"jc": 10, "jmin": 50, "jmax": 100,
"s1": 20, "s2": 20, "s3": 60, "s4": 60,
"h1": 1, "h2": 2, "h3": "1000-2000", "h4": 4, // single value or "N-M" range
"i1": "<b 0x...><r 12>", // I1–I5: must match the server, case-sensitive
"id": "www.google.com", "ip": "quic", "ib": "chrome" // or: masquerade sugar instead of a hand-written i1
}id/ip/ib and an explicit i1 are mutually exclusive. ip=quic sends two out-of-order fragmented QUIC Initials and is the profile proven against a live DPI; dns/stun/sip are correct requests kept for providers whose DPI only checks well-formedness. Reference — lx-protocols-transports.md §2 (RU) · masquerade examples.
{
"type": "masque", "tag": "warp",
"server": "162.159.198.2", "server_port": 443,
"profile": "cloudflare", // cloudflare (WARP) | standard (RFC 9484)
"vhttp": "h3", // h3 (QUIC) | h2 (HTTP/2, for networks that filter UDP:443)
"tls": { "server_name": "www.microsoft.com" }, // fronting SNI; auth is public-key pinning
"private_key": "<base64 DER EC>", "public_key": "<base64 DER PKIX>",
"ip": "172.16.0.2/32", "ipv6": "2606:4700:110:...::/128"
}Key material comes from the WARP device registration done by the client. Not to be confused with the AWG masquerade sugar above — same word, different feature. Reference — lx-protocols-transports.md §3 (RU).
"tls": {
"enabled": true, "server_name": "www.apple.com",
"utls": { "enabled": true, "fingerprint": "chrome" }, // chrome | firefox | safari carry the hybrid share
"reality": {
"enabled": true, "public_key": "<base64url>", "short_id": "0123abcd",
"key_share": "" // "" = as the fingerprint carries it · "classical" = strip X25519MLKEM768 (Xray < v26.9.8 only, one TCP segment) · "hybrid" = require it
}
}classical exists for networks that drop the two-segment hybrid ClientHello; on a newer server the remaining levers are record_fragment (now effective on REALITY) and a detour. Reference — lx-config.md §7 (RU).
{ "type": "vless", "uuid": "…", "encryption": "mlkem768x25519plus.native.0rtt.<ML-KEM-768 key>" } // absent or "none" = offClient half only; decryption is server-side and deliberately not ported. Reference — lx-config.md §6 (RU).
{ "type": "group", "tag": "dns-public", "mode": "stable", "servers": ["dns-cf", "dns-google", "dns-quad9"] } // stable | fastest | parallelReference — lx-config.md §5 (RU).
{
"type": "chain", "tag": "virtualisation",
"outbounds": ["selector-in", "selector-mid", "selector-exit"], // entry → exit, in packet order
"idle_timeout": "5m",
"strip": { "multiplex.padding": false }, // one-sided DPI tricks are stripped from links by default
"rewrite": { "wireguard": { "mtu": 1200 } } // merge-patch per node type, links only
}Tunnel links get their MTU lowered automatically; the path shows in detourList and GetChains, per-layer latency via URLTest on the hop tags <tag>#0, <tag>#1, …. Reference — lx-config.md §10 (RU).
No new types — a few fields on existing ones: urltest mode: round_robin + balancer{…} and passive_check (lx-config.md §3, RU); route.lx_idle_* sleep levels (lx-energy.md, RU); protocol names in the sniff action and protocol rules (lx-sniff.md, RU).
sing-box lxd (build tag with_lxd) hosts the core in-process behind a control channel that belongs to the daemon rather than to the box instance, so it survives every config change and is reachable exactly when the data plane is down.
sing-box lxd --state-dir ./lxd-state -c config.json- Reload without losing the channel —
POST /admin/applyvalidates the candidate in a subprocess, swaps the instance and promotes it to last-good only after a successful start; a failed start rolls back automatically. - One port, two planes — gRPC (the same
CommandClientcontract the Android client speaks) and admin-REST (plain stdlib client, Windows 7 friendly). - mTLS with enrolment — the daemon is its own CA, prints an
address#fingerprint#codeinvite, and knows clients by certificate afterwards. - Observability without a second port — memory, stats, logs, pprof, host telemetry (CPU per core, memory, thermal, disks, interfaces) and an IP → device directory.
- Service install on macOS; on Linux (systemd, OpenWrt/procd) the daemon prints the recipe instead of touching the disk.
📖 Operator's guide — docs-lx/lxd-daemon.md (RU); the client-facing observability contract — docs-lx/lxd-grpc-api.md (RU); OpenWrt walkthrough (VPN on a dedicated SSID) — docs-lx/openwrt-vpn-ssid.md (RU) with installer scripts in scripts-lx/openwrt/.
upstream/stable ──merge──► lx = upstream + // lx seams + lx-owned files + 4 fork submodules
│
└─► tag vX.Y.Z-lx.N ──► lx-release.yml ──► GitHub Release
- Manual merge of
upstream/stable, never a rebase.lxis both the working and the release branch and is never force-pushed. Drift is measured only by merge-base againstupstream/stable; the GitHub "N commits behind testing" banner is not drift. - Fork submodules are part of the delta: wireguard-go-awg2-lx (AmneziaWG runtime), sing-tun-lx (accept-loop self-heal), gvisor-lx (handshake nil-guard), utls-lx (Firefox 148 and Safari 26.3 presets). Each is its upstream plus a few commits; submodule drift is closed before the core merge.
- Hotfixes for upstream bugs carry an expiry: every patch in the HOTFIXES registry names the condition under which it is removed.
- Releases: tags
vX.Y.Z-lx.Nare stable,-rc.N/-alpha.N/-beta.Nare pre-releases; the procedure is the release runbook (RU); the engineering log is lx-changelog.md, user-facing notes are indocs-lx/releases/. - Spec Kit:
SPECS/FEATURESdescribes each feature's current state as a black box;SPECS/TASKSholds one folder per unit of work (SPEC → PLAN → TASKS → report), with a roadmap and status codes; CONSTITUTION holds the rules. - Remotes:
origin=Leadaxe/sing-box-lx(default branchlx),upstream=SagerNet/sing-box.
| Consumer | Platform | What it takes from here |
|---|---|---|
| singbox-launcher | desktop | the sing-box binary (bundled as bin/sing-box), optionally the lxd daemon |
| LxBox | Android | libbox.aar and the CommandClient extensions |
| OpenWrt routers | mips / musl builds | the binary as lxd with the installer scripts |
Mapping subscription links to config fields is a consumer-side job; the same config JSON applies everywhere.
Everything downstream is either a new file or a seam marked // lx; grep -rn "lx:begin" finds every seam in an upstream file.
| Path | Purpose |
|---|---|
Makefile.lx |
build with the lx tag set and the -lx version; lx-build, lx-check, lx-print-tags, lx-proto |
go.version / upstream.version |
pinned Go toolchain / the upstream version the fork is based on |
.github/workflows/lx-ci.yml, lx-release.yml, lx-build.yml |
CI matrix, release on v*-lx.* tags, on-demand builder for any branch |
SPECS/ |
Spec Kit: FEATURES/ (state), TASKS/ (work), CONSTITUTION.md |
docs-lx/ |
fork documentation (EN + RU), changelog, release notes |
lx-test/ |
sample configs for sing-box check and live stands (zombie, chain, …) |
scripts-lx/openwrt/ |
router installer for lxd |
transport/v2rayxhttp/ |
XHTTP client transport |
transport/wireguard/device_awg.go, submodules/wireguard-go |
AmneziaWG parameters and runtime |
protocol/masque/ |
MASQUE / CONNECT-IP outbound |
protocol/chain/ |
chain outbound |
common/tls/ (*_lx*), submodules/utls |
REALITY key share, fragmentation, fingerprint presets |
common/sniff/*_lx.go |
protocol sniffers |
dns/transport/group/, common/dnstrack/ |
DNS server group and the DNS query trace behind SubscribeDNSQueries |
experimental/libbox/, daemon/ (lx: seams) |
CommandClient extensions |
lxd/ |
the lxd daemon |
option/v2ray_xhttp.go, option/wireguard_awg.go, option/masque_lx.go, option/chain_lx.go |
feature options |
submodules/sing-tun, submodules/gvisor |
fork submodules for the TUN stack |
| Upstream | SagerNet/sing-box · docs |
| Config overview | docs-lx/lx-config.md (RU) — every field of every feature, with examples |
| Protocols & transports | docs-lx/lx-protocols-transports.md (RU) — XHTTP, AmneziaWG, MASQUE in depth |
| Energy guide | docs-lx/lx-energy.md (RU) — idle-suspend levels, passive_check, tuning |
| Sniffers | docs-lx/lx-sniff.md (RU) |
lxd operator's guide |
docs-lx/lxd-daemon.md (RU) |
| Observability API | docs-lx/lxd-grpc-api.md (RU) — the contract clients speak, gRPC daemon and Android AAR alike |
| OpenWrt walkthrough | docs-lx/openwrt-vpn-ssid.md (RU) |
| Release runbook | docs-lx/lx-release-runbook.md (RU) |
| Changelog & release notes | docs-lx/lx-changelog.md · docs-lx/releases/ |
| Reference cores | docs-lx/lx-reference-cores.md (RU) — where to look for wire-protocol answers |
| Spec Kit | SPECS/FEATURES · SPECS/TASKS · CONSTITUTION |
| Protocol origins | XTLS/Xray-core (XHTTP, REALITY, VLESS encryption) · amnezia-vpn/amneziawg-go · Cloudflare WARP / MASQUE |
Inherits the upstream sing-box license (GPL-3.0). All edits are marked // lx and distributed under the same license. This is an unofficial fork, not affiliated with SagerNet.