Android VPN client powered by sing-box. Multi-subscription, smart routing, built-in speed test.
Download latest release | Документация на русском
Servers & Subscriptions — manage proxy sources in one place
Add servers by subscription URL, direct proxy link, WireGuard URI/INI, or raw sing-box JSON outbound. Smart-paste dialog auto-detects format and previews the content. Enable/disable subscriptions without deleting. Offline rehydrate — nodes restored from body cache after app restart. Per-subscription settings for detour servers.
- 10 protocols: VLESS, VMess, Trojan, Shadowsocks, Hysteria2, TUIC v5, NaïveProxy, SSH, SOCKS, WireGuard
- Formats: Base64, Xray JSON Array (chained proxy), plain text, raw sing-box JSON
- Per-subscription Update interval picker (1/3/6/12/24/48/72/168h), honors
profile-update-intervalheader - Subscription row subtitle:
124 nodes · 🔄 24h · 🕐 3h ago · (2 fails) - Title fallback from
Content-Disposition: filename=...(RFC 5987) - Quick Start with built-in free VPN preset
Subscription auto-update — 4 triggers, hard gates against spam
Subscriptions refresh in the background without spamming providers. Every request is gated; nothing runs off the rails.
- Triggers: app start · 2 min after VPN connected · every hour · immediately on VPN disconnected · manual ⟳ (force)
- Gates:
minRetryInterval=15min(persists vialastUpdateAttempt),maxFailsPerSession=5(in-memory, thaws on app restart),10s ± 2sbetween subs,_running/_inFlightdedup flags,inProgressguard against double-clicks - Crash-safe init sweep: stuck
inProgresson disk resets tofailed - Rebuild config never triggers HTTP — only local assembly from loaded nodes
- See spec 027
Home Screen — connect and manage nodes
One-tap VPN start/stop with animated status chip. Choose proxy group, sort nodes by ping/name, mass-ping all servers. Traffic bar shows real-time speed, connections count, uptime.
- Node row layout (v1.3.1+):
[ACTIVE green pill] PROTOCOL · · · 50MS →— protocol label (VLESS/Hy2/WG/TUIC/SS) from outbound type, ping right-aligned with colour by latency - Proxy groups:
auto-proxy-out, VPN ①/②/③ - Node filter: choose which nodes participate in auto-selection
- Detour servers (⚙) visibility toggle
- Sticky restart warning under Stop — doesn't disappear when you cancel Stop dialog
- Long-press: Ping · Use this node · View JSON · Copy URI (vless://, wireguard://, etc) · Copy server (JSON) · Copy detour · Copy server + detour
Quick Connect — toggle VPN without opening the app (v1.5.0)
Two paths to flip the VPN on/off without launching the UI: a Quick Settings tile in the status-bar shade and a long-press shortcut on the home-screen icon.
- Quick Settings tile — pull down the shade, edit tiles, drag L×Box in. Tap = on/off, live
Connected/Disconnected/Connecting…/Stopping…subtitle. Add via App Settings → General → Quick connect →Add(system prompt on Android 13+, manual instructions on older). - Home-screen shortcut — long-press the icon → Toggle VPN.
- First tap shows a one-shot toast and flashes
MainActivityfor the system VPN consent dialog (Android API requires Activity context); subsequent taps go directly to the service. After consent the activity finishes itself — no UI flash on regular use. - Tile state survives OOM-kill of the service:
currentStatusis reset ononDestroyso the tile won't lie «Connected».
Routing — unified rule model (v1.4.0)
Block ads, route Russian domains directly, send BitTorrent through specific proxy, route per-app, match private IPs. Every user rule goes through a single CustomRule model with all match fields in parallel (OR within category, AND across — per sing-box default rule formula).
- 4 tabs: Channels (proxy groups) · Presets (read-only catalog → Copy to Rules) · Rules (your registry) · Tunnel apps (OS-level split-tunneling — see below)
- Match fields: domain, domain_suffix, domain_keyword, ip_cidr, port, port_range, packages (per-app), protocols (tls/quic/bittorrent/…), ip_is_private, wifi_ssid / wifi_bssid (v1.7.3), remote .srs rule-set
- SRS local-only — no auto-update, manual download via ☁ icon, rule disabled until cached
- Drag-reorder + long-press → Delete with confirm
- Params / View tabs in rule editor — View shows live sing-box config preview
- Dirty-aware save — unsaved back → "Discard changes?" dialog
- Default traffic fallback (
route.final) - See spec 030, spec 011, spec 051
Wi-Fi-aware routing — different rules on different networks (v1.7.3)
Declare rules like "on this Wi-Fi → direct" persistently — no temporary PUT /config hacks. Rules with wifi_ssid / wifi_bssid AND-combine with all other match fields:
wifi_ssid: [HomeWiFi] → direct— bypass VPN at homewifi_ssid: [OfficeWiFi] AND domain: [*.bank.com] → direct— banking only on office networkrule_set: [geosite-ru] AND wifi_ssid: [HomeWiFi] → ru-direct— country-specific routing per Wi-Fi
Editor UI in the rule editor: chips with Add current (read live SSID), Pick saved (history of visited networks), Manual (type SSID or paste BSSID). Permission gates wired in (Android 13+ requires NEARBY_WIFI_DEVICES; sing-box also needs ACCESS_BACKGROUND_LOCATION to read SSID from a foreground-service VPN).
- Auto-record opt-in (App Settings → Diagnostics):
WifiNetworkObserverlistens toConnectivityManager.NetworkCallbackand writes a network intowifi_historyonly if you've stayed on it ≥5 minutes. Privacy default — off; turn on to populate the Pick saved picker without manual input. - History capped at 50 entries (LRU evict). Manageable via
GET/POST/DELETE /wifi_historyDebug API for tests / restore. - See spec 051, feature highlight
Detour Servers — chain proxies for extra privacy
Build multi-hop chains: your traffic goes through an intermediate server before reaching the final proxy. Great for bypassing geo-restricted networks: put your home WireGuard as a detour → foreign mobile internet becomes a tunnel to home.
- Add your own server (paste URI / paste JSON / WG INI) — it becomes a candidate for detour
- Mark as detour server switch in Node Settings — adds
⚙prefix - Override detour per subscription: route all its nodes through your chosen server
- Register / Use toggles for detour servers from subscriptions
- Detour dropdown in Node Settings persists via
overrideDetour(no JSON roundtrip drift)
DNS Settings — full control over name resolution
16 DNS server presets (Cloudflare, Google, Yandex, Quad9, AdGuard) with UDP/DoT/DoH variants. Custom servers via JSON editor. Strategy, cache, rules — all configurable.
- Enable/disable servers with switches
- DNS Strategy: prefer_ipv4 / prefer_ipv6 / ipv4_only / ipv6_only
- DNS Rules editor, DNS Final, Default Domain Resolver
- Bundle preset "Russian domains direct" (spec 033) — self-contained
.ru/.su/.рф/.рус/.москва/.moscow/.tatar/.дети/.онлайн/.сайт/.орг/.комrule + own Yandex DNS servers +@out/@dns_servervars
DPI Bypass — bypass censorship
Three orthogonal tricks — combinable on the same outbound.
- TLS Fragment — splits ClientHello over TCP segments
- TLS Record Fragment — splits handshake into multiple TLS records
- Mixed-case SNI (v1.3.0+) — randomises
server_namecase (WwW.gOoGle.CoM). Bypasses naive exact-match DPI used by regional providers. Per RFC 6066 SNI is case-insensitive; the trick doesn't change server behaviour. Ineffective against GFW-class filtering. - All tricks applied to first-hop only (inner hops are inside the tunnel, local DPI doesn't see them).
- See spec 020, spec 028
Haptic Feedback — vibro on VPN events
Short vibration on VPN transitions, errors, and taps. Respects the Android system Touch feedback setting.
- Tap Start/Stop → light tick
- VPN connected → medium impact; user disconnect → light
- Revoked / heartbeat fail (first only, not per tick) → heavy
- Manual subscription fetch success/fail → light/medium
- Auto triggers don't vibrate; 100 ms throttle prevents spam
- Toggle in App Settings → Feedback (default on)
- See spec 029
Speed Test — measure your connection
Built-in speed test with 10 servers worldwide. Per-server ping measures latency to the actual download server. Parallel download streams, upload test, session history.
- Servers: Cloudflare, Hostkey (5 cities), Selectel, Tele2, OVH, ThinkBroadband
- Configurable streams (1/4/10), upload method per server
- Session history with server name
Statistics & Connections — see what's happening
Real-time traffic by outbound with expandable cards. Each connection shows host, protocol, routing rule, traffic, duration, proxy chain, and app/process name. Close individual connections.
- 4 tabs: Overview · Connections · Per-app · Live (system-wide, v1.7.2)
- Live tab — discovery without picking a target: see every TCP/UDP open and DNS resolve happening on the device in real time. Filter chips (kind / unattributed-only / app multi-select / domain-IP-process search), pause/resume, long-press → "Open in Per-app session for <pkg>" quick-discovery flow. 60s rolling buffer × 3000 events. Inline
CoreLogsHintBannerappears whenForward sing-box logsis off (without it DNS resolves and process attribution don't reach the buffer)
Per-app traffic profiler — trace any app's network in real time (v1.7.0)
Pick an app, hit ▶ Record, and see every domain, IP, and routing decision — including which CDN your bank uses, where it gets routed, and whether part of the traffic leaks through a different outbound. Built-in connection-issue detection flags failed DNS and likely-blocked TCP connections.
- Stats → Per-app tab: select package via app picker, [▶ START] / [⏹ STOP], status row shows
Recording 02:34 · 47 doms · 53 ips · 287 ev - 4 sub-tabs:
- Live — newest events first (DNS resolves with CNAME chain · TCP/UDP open/close), monospace IP
↗chip jumps to Domains - Domains — aggregated unique domains, sortable; expanded view = CNAME targets, all resolved IPs, outbounds, issues. Search field matches by
domain||ip||cname target(cross-domain CDN audit) - IPs — aggregated by destination IP (ports, conn count, bytes, outbound). Each row has
↗to jump back to Domains filtered by that IP - Connections — per-connection timeline. Tap header to inline-expand: CNAME chain, all IPs, rule, issues, button
[View in Domains →]that focuses the corresponding aggregate row
- Live — newest events first (DNS resolves with CNAME chain · TCP/UDP open/close), monospace IP
- Connection-issue detection (2 locale-agnostic types):
dnsTimeout(sing-boxdns: exchange failedlog — direct engine signal, not heuristic),tcpReset(TCP closed within 1s with 0 bytes — likely firewall RST / unreachable). ⚠ icon on Live row + Domain expanded view shows full description - Process inference — when sing-box's
find_processmisses (rare with WebView/system processes), profiler attributes connection by recently resolved IP within a 10s post-DNS window; rows marked〽 inferred from prior DNS - Recording indicators:
- HomeScreen
_buildTrafficBarchip⚡ <pkg>next to traffic stats; tap whole row →StatsScreen(initialTab: perApp) - Stats
Per-apptab title gets red⚡while recording
- HomeScreen
- Overflow menu (⋮) in Per-app tab: Verbose core logs (debug-level, applies on next session), Copy session JSON, Share, Clear all sessions, Help
- In-memory only — last 5 finished sessions kept, plus 1 active. 3h sliding window per session + 50k events fallback cap.
force-stop/ app kill wipes everything (no persist by design — diagnostic-only) - Debug API (Bearer-auth, port 9269):
POST /profiler/start {package, verbose?}·POST /profiler/stop·GET /profiler/active·GET /profiler/sessions·GET /profiler/session/<id>?include=events,domains,ips·DELETE /profiler/session/<id>·DELETE /profiler/sessions·GET /profiler/stream(Server-Sent Events, fire-and-forget) - Docs: user guide with use cases & curl recipes · §044 spec
VPN Settings — tune the engine
Two tabs (v1.7.3 reorg, see §052):
- System — Android-side
VpnService.Buildertoggles:Allow VPN bypass(apps usingConnectivityManagercan step around the tun),Keep VPN on exit(tunnel survives app close),Tunnel sleep mode(never/lazyDoze-only /alwaysscreen-off — battery vs reliability trade-off). - Core — sing-box engine vars (
chapter: 'core'in template —mtu/log_level/dns_final/ etc). Routing- and DNS-specific vars live on their own screens (Routing, DNS Settings).
All changes autosaved. URLTest parameters for auto-proxy latency testing. Permissions block (Battery / Notifications / Location / Wi-Fi / App info) lives in App Settings → Diagnostics (interactive — tap to grant).
Config Editor — for power users
View and edit raw sing-box JSON config. Pretty-printed display with copy button. Save, paste from clipboard, load from file, share.
App Settings — personalize
- Theme: System / Light / Dark
- Auto-start VPN on boot
- Keep VPN active when app is closed
- Auto-rebuild config on settings change
- Battery optimization tile — status + shortcut to system whitelist (v1.4.0)
- App info (OEM power settings) with hint dialog for Autostart / Background activity toggles (v1.4.0)
- Auto-ping after connect — ping active group 5s after VPN up (default on, v1.4.0)
- Haptic feedback toggle
- See spec 022
| Protocol | URI scheme | Transport |
|---|---|---|
| VLESS | vless:// |
TCP, WebSocket, gRPC, H2, HTTPUpgrade, REALITY |
| VMess | vmess:// (v2rayN base64) |
TCP, WebSocket, gRPC, H2, HTTPUpgrade |
| Trojan | trojan:// |
TCP, WebSocket, gRPC |
| Shadowsocks | ss:// (SIP002 + legacy + SS2022) |
TCP, UDP, SIP003 plugins |
| Hysteria2 | hy2:// / hysteria2:// |
QUIC, Salamander obfs |
| TUIC v5 | tuic:// |
QUIC, BBR/CUBIC/NewReno, zero-RTT |
| NaïveProxy | naive+https:// |
Real Chrome TLS via cronet, extra-headers |
| SSH | ssh:// |
TCP, host key / password / private key |
| SOCKS | socks:// / socks5:// |
TCP, auth |
| WireGuard | wireguard://, INI config |
UDP, multi-peer |
XHTTP transport auto-falls back to HTTPUpgrade (sing-box 1.12.x doesn't support xhttp natively) — warning surfaced in UI.
See Protocol Documentation for full URI format details and sing-box mapping.
L×Box is built around a 3-layer parser/builder pipeline (spec 026, v1.3.0+):
UI / Controller
│
▼
parseFromSource(source) ← HTTP fetch + body_decoder + typed parser
│ returns: List<NodeSpec>, meta, rawBody
▼
ServerList (sealed) ← SubscriptionServers | UserServer
│ .build(ctx) applies tagPrefix, detour policy, allocateTag
▼
buildConfig(lists, settings) ← template + post-steps (DPI, DNS, rules)
│ returns: BuildResult{ config, validation, warnings }
▼
sing-box JSON
- Sealed
NodeSpec— 9 protocols, polymorphicemit(vars)/toUri()(round-trip invariant) EmitContext— passes template vars into per-node emitNodeEntries{main, detours[]}— named struct for chain resultsValidationResult— typed issues: dangling refs, empty urltest, invalid selector default
See Architecture for the full picture.
Spec-driven development — 30 feature specifications document every capability.
| Document | Description |
|---|---|
| Protocol Reference | URI formats, parameters, sing-box mapping |
| Architecture | 3-layer pipeline, data flows, native bridge |
| Build | Build instructions, CI, APK signing, local-build marker |
| Development Guide | Principles, testing (167 tests), spec organisation |
| Changelog | Release history |
| Release Notes | Detailed per-version notes (EN + RU) |
./scripts/build-local-apk.shThe script wraps flutter build apk --release with --dart-defines that embed git describe info. About screen shows a pink 🧪 LOCAL BUILD · N commits since vX.Y.Z badge to distinguish from CI builds.
L×Box is licensed under the GNU General Public License v3.0.
Commercial licensing from Leadaxe may be available for Leadaxe's own code in L×Box. Note that L×Box links against libbox (sing-box, GPLv3), so any compiled L×Box build remains under GPLv3 regardless — a Leadaxe-only commercial license cannot authorize embedding L×Box into a proprietary product. Scope and limits: LICENSING.md. Inquiries: ledaxe@gmail.com.










