github Leadaxe/singbox-launcher v2.3.0
release v2.3.0

latest release: v2.3.1
5 hours ago

Release v2.3.0

Downloads

macOS (Universal) - Supports both Apple Silicon and Intel

Option 1: Installation Script (Recommended)

Install with a single command (version v2.3.0):

curl -fsSL https://raw.githubusercontent.com/Leadaxe/singbox-launcher/develop/scripts/install-macos.sh | bash -s -- v2.3.0

The script will:

  • Download the release archive
  • Extract and install to /Applications/
  • Fix macOS quarantine attributes and permissions
  • Launch the application automatically

Option 2: Manual Installation

  1. Download: singbox-launcher-v2.3.0-macos.zip
  2. Extract the ZIP file
  3. Remove quarantine attribute (required):
    xattr -cr "singbox-launcher.app" && chmod +x "singbox-launcher.app/Contents/MacOS/singbox-launcher"
  4. Double-click singbox-launcher.app to run
    • If macOS blocks the app, go to System Settings → Privacy & Security and click "Open Anyway"
    • Alternatively, right-click the app and select "Open" (first time only)

Windows (amd64)

Option 1: Installer (Recommended)

  1. Download: singbox-launcher-v2.3.0-win64-setup.exe
  2. Run it and confirm the administrator prompt once. The launcher goes to C:\Program Files\singbox-launcher, your data to %LOCALAPPDATA%\singbox-launcher; sing-box.exe, wintun.dll, the config template and Mesa3D are included, nothing is downloaded on first launch
    • Tasks: desktop shortcut, Start with Windows, software OpenGL (Mesa3D) for RDP / VMs without a GPU
    • Installing over a previous version keeps your data; uninstall from Settings → Apps asks whether to remove the data too
    • The installer is not code-signed yet: if SmartScreen shows "Windows protected your PC", click More info → Run anyway

Option 2: Portable ZIP

  1. Download: singbox-launcher-v2.3.0-win64.zip
    • or singbox-launcher-v2.3.0-win64-full.zip — full bundle: sing-box.exe, wintun.dll, the config template and Mesa3D (mesa3d/, used only when no hardware OpenGL — RDP, VMs) are already inside, nothing is downloaded on first launch
  2. Extract the ZIP file to a folder your account can write to, for example D:\Tools\singbox-launcher\ — settings stay next to the program (portable.txt)
    • Under C:\Program Files\ the launcher keeps its data in %LOCALAPPDATA%\singbox-launcher instead
  3. Run singbox-launcher.exe from that folder — no administrator rights, no UAC prompt
    • TUN needs administrator rights: Start offers Restart as administrator or Switch to proxy mode
    • The regular archive downloads sing-box and wintun.dll on first launch

Windows 7 (x86, legacy)

  1. Download: singbox-launcher-v2.3.0-win7-32.zip
  2. Extract the ZIP file to a folder and run singbox-launcher-win7-32.exe
    • For Windows 7 / 32-bit or legacy compatibility only
    • Runs as administrator (UAC prompt on every start), settings stay next to the program (portable.txt); no installer and no daemon service

Linux Support

⚠️ Linux build temporarily unavailable - мы ищем тестировщика для ручного тестирования перед включением автоматической сборки.

Checksums

See checksums.txt for SHA256 checksums of all files.

Release notes — v2.3.0 (2026-09-26)

EN

Minor release on top of v2.2.0. Core sing-box-lx 1.14.2-lx.4 (was 1.14.2-lx.2), contract 1.1.80 (was 1.1.53).

The release is about nodes. The registry is now the only source of node rules (SPEC 142): links, subscriptions, sing-box and Xray configs and backups are judged by the same rules on every input, and warnings that used to reach only the log now show up in the node list and the build report. The config template gets one canonical walker (SPEC 143). WireGuard and AmneziaWG nodes show their live state in Servers and can be switched off and on without editing the config.

Highlights

WireGuard / AmneziaWG: live state and on/off switch

  • State in the Servers list. The subtitle of a WireGuard/AmneziaWG node row ends with its state in the running core — up, sleep, freed, starting or off — refreshed every 10 s while the tab is visible. A node switched off by hand shows a grey off instead of a red Error: it is not broken.
  • Disable WireGuard / Enable WireGuard in the row's menu switches the node off and on in the running core without editing the config.
  • WireGuard section in the Info window of the node: its state (up, asleep, released, not started yet, disabled…) with the time since its last traffic, refreshed every 10 s, and a Disable / Enable button next to the state.
  • The switch lasts until the core restarts or the config is applied. Works in daemon mode and on remote machines (the classic core has no such API); needs core 1.14.2-lx.4.

Config template: one canonical walker (SPEC 143)

  • Config template: one canonical walker now substitutes @var / #if everywhere — the main config, on_change.set, preset bodies and template DNS servers (SPEC 143). Template warnings (undeclared variable, unknown directive, number out of range or not a number, a preset rule / rule set / DNS rule / DNS server dropped because a setting is empty) now come first in the build report Summary instead of the log; they never block Save. Language changes: an array in a branch of a conditional array element is spliced one level up (nest with [[...]]); ["@name"] is no longer collapsed into a scalar; options work with any type except bool, options_open: true allows free input, enum is text with closed options; a value becomes a number only by its declared type: int (clamped to [0, 65535], a non-number stays a string) — the hard-coded list of numeric variable names is gone, so custom templates that declare MTU or a port as type: text now get a string; @runtime.platform / @runtime.arch / @runtime.target are allowed as values in config. Settings draws a dropdown from options, a combo box with options_open, and checks int fields as numbers. Contract 1.1.68–1.1.70.

Nodes: registry rules on every input (SPEC 142)

  • Hysteria2 links from 3x-ui with gecko obfuscation no longer lose the packet size range: minPacketSize/maxPacketSize are read, and security=tls is accepted silently (contract 1.1.54).
  • VLESS nodes with Vision flow over a transport (xhttp, ws, …) keep flow when the node has VLESS Encryption: the flow was stripped before and the server dropped the connection (contract 1.1.55).
  • XHTTP uplink_data_placement=header|cookie without mode gets mode: packet-up filled in on every input, sing-box JSON included; with another explicit mode the placement is dropped instead of the core rejecting the whole config. body/auto placements are no longer touched: links with uplinkDataPlacement=body and mode=stream-one used to get a false warning. Shadowsocks plugin_opts without plugin is dropped (contract 1.1.56).
  • A node link is now recognised by the registry itself: amneziawg:// links paste as servers instead of being taken for a subscription URL, and a new registry scheme needs no code change to be recognised. sing-box JSON import judges tls of a wrong shape and a missing server/server_port by registry rules on every input: the node gets a type_invalid / field_missing / port_invalid code instead of a silent fix or a bare rejection. The AmneziaWG obfuscation form saves only what the pipeline emits; a body the pipeline cannot build is not written, as in the JSON editor.
  • Hysteria (v1) nodes whose obfs arrives as a Hysteria2-style object {type, password} keep their obfuscation on every input — sing-box import, a JSON body pasted by hand, a restored backup: the password becomes the obfuscation string, with an info notice (obfs_object_flattened); an object without a password is removed with obfs_password_missing. MASQUE bodies with the legacy flat network/sni/skip_cert_verify keys have them removed with an unknown_key notice on every input, not only on sing-box import and not silently (contract 1.1.57).
  • The global TLS anti-DPI option (ClientHello/record fragmentation) now also applies to MASQUE nodes: the core fragments on the h2 leg and ignores it on h3. The set of schemes it applies to comes from the registry, not a list in code. The "Add WireGuard" form no longer accepts an MTU above 1500 (the registry limit; values above were silently dropped later) and, with Allowed IPs left empty, the node gets both 0.0.0.0/0 and ::/0. Invalid keys, MTU or keepalive are reported with the registry's own message. The AmneziaWG obfuscation form accepts any masquerade domain the core accepts (a name without a dot, underscores) and checks it by the registry; explicit i1/i2 next to the masquerade are removed with a field_conflict notice instead of silently; there is no longer a made-up ceiling on jc/jmin/jmax. The Tailscale form reports "LAN access without an exit node" instead of dropping the checkbox silently. Node subtitles show the transport the same way in the list and in the preview: only schemes with a transport show tcp, MASQUE without vhttp shows auto (contract 1.1.58).
  • REALITY nodes: one registry rule instead of two contradicting ones. A REALITY node without uTLS (a hand-written sing-box body, an Xray config without fingerprint) keeps REALITY and gets uTLS switched on with an info notice (reality_utls_enabled); before, the registry removed REALITY and the build then patched uTLS back in — the node went out as plain uTLS to a REALITY server. The fingerprint random under REALITY is pinned to chrome on every input with an info notice (reality_fp_random_pinned): the core resolves random once per start to one of five fingerprints, and two of them (edge, ios) lack the hybrid key exchange modern REALITY servers require. Nodes already stored in the state and manual config_json objects get the same fix at build time by the same registry rule, with the code in the log instead of the former silent patch; a node whose REALITY is dropped for a broken public key keeps its fingerprint. A chain that strips uTLS while one of its positions is a REALITY node is no longer excluded: stripping uTLS is turned off for that chain, with chain_strip_utls_on_reality in the log (contract 1.1.61).
  • AmneziaWG nodes with jmin greater than jmax no longer make the core refuse the whole config: on every input both bounds are removed with a fields_order_invalid notice and the node keeps working. Tailscale advertised routes are fixed up by the registry on every input: a bare address becomes a host route, host bits are cleared (192.168.10.5/24 → 192.168.10.0/24), and a default route (0.0.0.0/0, ::/0) is removed with a tailscale_default_route_advertised notice (the exit-node setting is for that) — before, only the add-server form checked this. In Xray configs, a chain hop that dials out through a freedom with fragment gets ClientHello fragmentation itself; before, it was put on the chain owner, whose TLS runs inside the hop's tunnel. vpn:// links are recognised regardless of letter case (contract 1.1.63).
  • MASQUE nodes: TLS settings the core does not use for MASQUE — alpn, ech, reality, kernel_tx/kernel_rx — are removed on every input with an info notice (masque_tls_field_ignored); TLS fragmentation is removed only on vhttp: h3 (masque_tls_fragment_h3) and the global anti-DPI option no longer adds it there, while h2/auto keep it. VLESS from an Xray config with encryption: "None" (capital N) is now rejected with vless_encryption_invalid, as on the link and sing-box inputs, instead of silently losing the encryption layer (contract 1.1.64).
  • Warnings that used to reach only the log now reach the user, translated from the registry: an imported sing-box config whose detour chain was cut (target missing, a group, a loop, too deep) marks the node with ⚠; a group left without members appears as an unsupported record with group_empty; a subscription cut by the node limit, a broken chain (core without chains, missing hop, nested chain, malformed), a chain whose uTLS strip was turned off for REALITY, a chain left out of a Direction it runs through, and a lost detour target of a source (one line per source and target, with the number of excluded nodes) are shown in the build report by their registry code.
  • WireGuard nodes with a listening port (listen_port, from a .conf or a link) that you route through a hop no longer make the core refuse the whole config: the build removes the listening port with a detour_with_listen_port notice in the build report and keeps the hop. A node routed through itself or through a loop of hops is reported by code (source_detour_self, source_detour_cycle). An SSH entry without a user in an imported sing-box config gets root written explicitly with an info notice (ssh_user_default) — the core used root anyway (contract 1.1.65).
  • An imported group (selector / urltest / Xray balancer) that lost some of its members now shows ⚠ with the number of missing members right in its row of the node list (group_member_missing), next to the pool size; before, the loss was only a line in the subscription update status. The notice survives backup export/import (contract 1.1.66).

Amnezia profiles and link names

  • The Origin of a node from an Amnezia vpn:// profile is now a complete .conf. The node keeps its own .conf text as its origin, with the container values written into it: the MTU from the profile (when [Interface] has none) and the profile DNS addresses instead of $PRIMARY_DNS / $SECONDARY_DNS. Regen from raw rebuilds the node from that text alone, without the vpn:// link; tags do not change. Nodes imported earlier keep working as before (contract 1.1.72); a subscription refresh rewrites their origin. A vpn:// line inside a list of links (in a subscription, pasted into Add or into the Source field of Add server, or a .vpn file) now gives every WireGuard/AmneziaWG container of the profile, each with its own .conf origin — the same nodes as a subscription made of that one link (contract 1.1.80).
  • Links whose sni= carries a label instead of a host name (Germany, an emoji) now get the server address as SNI for AnyTLS and Hysteria2, as the registry prescribes. The notice about the ignored WireGuard link DNS shows the address list decoded (1.1.1.1, 1.0.0.1, not 1.1.1.1,+1.0.0.1). A vmess:// link whose payload is neither a v2rayN JSON object nor a legacy method:uuid@host:port link — e.g. junk instead of base64 — is rejected with form_unrecognized instead of an unclear failure (contract 1.1.73, 1.1.74).
  • A broken byte in a node name (for example, a cp1251 label from an aggregator, percent-encoded in the link fragment or raw inside a base64 vmess payload) no longer costs the node: the node is imported and the damaged spot in its name shows as �, instead of being cut out or rejecting the whole link (contract 1.1.74).

Backup: folder and subscription fold

  • The fold of a folder or subscription (one group instead of its nodes in Directions) now travels in the backup file in the same form as in the app state — replace {mode, tag, auto} inside the folder/subscription record — instead of the former fold + fold_tag pair. The old form is not read and not migrated: an older backup that carries a fold in the fold form loses it on import (the keys are dropped with an "unknown field" warning, rules that pointed at the fold group arrive disabled), and the fold has to be set up again (contract 1.1.78, 1.1.79).

Fixed

  • The Overview tab of a node inside a folder now describes the node itself — its type, tag, enabled state and its own storage record — instead of the folder ("Type: Group", the folder's name and "Nodes: 5").
  • Preset DNS servers now honour their own #enable condition: with DNS override switched off, the russian preset's Yandex DoH/DoT servers no longer end up in config.json (they were emitted regardless; only the preset's rules respected the switch).

Migration notes

Custom templates

  • A template value becomes a number only when its variable declares type: int (clamped to [0, 65535]). The hard-coded list of numeric variable names is gone: if your own wizard_template.json declares an MTU, a port or another numeric setting as type: text, config.json now gets a string and the core may refuse it — declare the variable type: int. The bundled template already does.
  • Also check custom templates that relied on the old walker: an array in a branch of a conditional array element is now spliced one level up (nest with [[...]]), and ["@name"] is no longer collapsed into a scalar. Template warnings are listed first in the build report Summary.

Core

  • The WireGuard state and Disable / Enable WireGuard need core sing-box-lx 1.14.2-lx.4; the launcher offers to update the core. In daemon mode and on remote machines it is the daemon's core that has to be lx.4.

Technical / Internal

  • Core pinned to sing-box-lx 1.14.2-lx.4 (was 1.14.2-lx.3): the core reports the state of every WireGuard/AmneziaWG node and can switch a node off and on at runtime (fork SPEC 106). No configuration or state migration. gRPC stubs (internal/daemonpb) synced to the fork at 1.14.2-lx.4.
  • Core pinned to sing-box-lx 1.14.2-lx.3 (was 1.14.2-lx.2). Vision (flow: xtls-rprx-vision) now runs on top of VLESS Encryption on any transport, xhttp included (fork SPEC 105, sing-box-lx#29); together with contract 1.1.55 such nodes connect instead of being dropped by the server. No configuration or state migration.
  • Contract 1.1.56 primitives: body condition accepts value predicates on paths (in/not_in/scalar, mapper when grammar), relations take when, mapper when gets the $value selector (own source value; a miss is a silent skip, no on_when_false). Sanitizer rules: relations and conditions see fields of the object still being walked; an empty string or an absent_values literal counts as a missing key for default_when; an empty string does not satisfy any_set. All engine-level, no scheme names in code.
  • SPEC 142 wave 1: hand-written copies of registry rules removed — sing-box type → scheme table and the endpoint-scheme table (now registry.NodeSchemeForSingboxType by singbox_type + sources, registry.ProtocolKind), the direct-link prefix list (linkmap.SelectURI), the Xray socks hop builder (the engine's socks#xray section), tls shape and address pre-checks of sing-box import, dead uTLS/WS-early-data/Vision/MASQUE helpers. A chain type from a foreign config does not become a node (the scheme has no sources). Registry data unchanged, no contract bump.
  • SPEC 142 wave 2: the hand-written sing-box import sanitizer (SanitizeSingboxOutboundMap, singbox_sanitize.go) is removed. Its last two rules are registry data: new engine primitive on_invalid: unwrap (an object wrapper of a neighbouring dialect → the value of its key member, else_code otherwise; no scheme names in code) on hysteria.body.obfs, and the MASQUE legacy keys moved to body.skipped. Contract 1.1.57.
  • SPEC 142 wave 3: chain strip catalogue, AmneziaWG ip=quic → id requirement and LDH pattern of id, Tailscale exit_node_allow_lan_access → exit_node became registry data; the chain form, the AWG/WireGuard/Tailscale/WARP forms, TLS transforms, node transport labels and the MASQUE vhttp coercion read the registry (Field.AllowedForScheme, FieldAllowed, FieldStrings, FieldsWithBuildTag). The linkmap engine no longer names the transport-drop code or its parameter. Contract 1.1.58.
  • SPEC 142 wave 4: new registry field attribute role (credential | private_key). A node's credential (ParsedNode.UUID) is read by role the same way on every input (registry.Credential) — three hand-written per-scheme copies removed; link and JSON inputs no longer disagree (ssh/naive/socks/http JSON now carry the user name, an ss link the password instead of the cipher, WireGuard/MASQUE links no longer put the private key there; no user-facing reader depends on it). Share links that need confirmation (private key inside) are decided by the private_key role instead of a type table in code; same set (ssh, WireGuard, MASQUE). Contract 1.1.59.
  • SPEC 142 wave 5: node-level core gates are registry data. New attributes on_core_unsupported (protocol body, field, range form), range_form (awg_range only), levels/level/level_mark. One generic gate (nodeflow.NodeCoreRefusal) replaces the three per-protocol probes (naive, Tailscale, AmneziaWG 3.x) and the hand-written AWG 3.x field list (awg3.go removed); the app only reports the core's build tags. The AmneziaWG level label and the form's "remove AmneziaWG" (ranged keepalive collapsed to its lower bound) read the registry. Same nodes are dropped with the same codes; the build report now shows one line per code, titled from the registry ("AmneziaWG 3.x: core too old — 2 node(s) skipped: …"). Contract 1.1.60.
  • SPEC 142 wave 6: REALITY ↔ uTLS is one registry rule executed by the sanitizer on every input. New primitives: requires[].set (a missing required neighbour is materialised with a code instead of dropping the field), field coerce_when (conditional replacement of a valid value), both judged on the finished body after the walk, codes placed in body.order position; chain strip key attribute on_hop_required {action: unstrip} judged via nodeflow.StripBlocked (a hop body that would get the path back from requires … set). Bodies the build does not sanitize (frozen state bodies, manual config_json) get only the repair rules via nodeflow.Repairs. Removed: EnforceRealityFingerprint (node_parser_transport.go deleted), build.HealRealityFingerprints and its build step, NodeUsesReality/ChainStripsUTLS/ChainRealityConflict. Contract 1.1.61.
  • SPEC 142 wave 8: registry pointers to code (refs.go, impl, go of warning codes, notes) brought up to date — 141 refs.go entries pointed at removed hand-written parsers/emitters or past-the-end line numbers (53 left, as path.go[:Name]), ~335 notes point at where the rule runs now; new linter TestRegistryCodeRefsResolve checks that every referenced file exists and every named identifier is declared in it (Contract job, triggered by any .go change). Registry rules unchanged. Contract 1.1.62.
  • SPEC 142 wave 7: the last hand-written node rules are registry data. Body primitives: relation ordered (+ action drop), field item_forbidden, normalize cidr_masked, protocol-body exit_capable_when (ParsedNode.IsExitCapable reads it). Mapper primitives: sources context.<path> (value from the container unwrapper) and ref.<as>.<path> (a neighbour in the document found by a record's deref {key, as}), record substitute, when operator type_of. Removed: applyXrayFreedomFragment and its helpers, amneziaPrepareConf (MTU from last_config, $PRIMARY_DNS substitution — now wireguard conf records), the vpn:// literal (the amnezia_link source-kind detect, linkmap.MatchesUnwrap), the jmin ≤ jmax check of the AWG form, parseTailscalePrefixList. Sanitizer norm (PARSING_PRINCIPLES §6.2): a field removed by a value or relation rule counts as absent for the following relations and conditions (before, ib stayed after ip was removed). Contract 1.1.63.
  • SPEC 142 wave 9 (campaign tails): dead code removed — subscription/hysteria2_ports.go (its rules are registry data), percentEncodeUserinfoSpaces, the unread ParsedNode.UUID/ParsedJump.UUID fields and registry.Credential; new registry.Registry.FieldAllowedOn (would the sanitizer keep this field in this body) used by the build's TLS transforms; gendocs prints relation when conditions.
  • SPEC 142 wave 10b: new registry.Registry.YieldsTo — fields of a finished body that a conflicts {with} relation would drop once a build-written managed field is present; the build asks it right after setting detour. Warning go notes point at where wave 10a delivers the codes; body_dialect_unrecognized removed (no event, dead constant); direction_filter_matched_nothing registered (it was used by the Directions corpus only). Contract 1.1.65.
  • SPEC 142 wave 11a: warnings[] allowed on a group node (kind=auto) in state and backup; backup import keeps a group's warnings as is (no body to recount from). group_member_missing moved from a subscription-level code to the group node (subscription.markGroupMemberMissing, one entry per group, counts add up across parse steps). Corpus +1 body/singbox/group_member_missing. Contract 1.1.66.
  • SPEC 142 wave 12: a group member that drops out at config build (missing, disabled or excluded) now reaches the build report with code group_member_dropped (registry text, both languages) instead of a bare line. Contract text fixed: a core_rejected entry is exported as is but dropped on backup import — enabled comes from the file, import never turns the node on, the receiving core judges it again when the user enables it (the importer already worked this way). Contract 1.1.67.
  • Contract 1.1.68 → 1.1.80. Template language of SPEC 143 — splice one level, no ["@name"] collapse, options independent of type with options_open, @runtime.* in values (1.1.68); template_* codes reach the build report Summary as template_degraded (1.1.69), plus the new template_fragment_dropped for a preset or template DNS-server fragment left without a required field (1.1.70); SPEC 143 closed on desktop (1.1.71); the origin of a node from vpn:// is a self-contained .conf (wg_ini, 1.1.72); the corpus brought to the norm (LxBox task 560, 1.1.73); invalid UTF-8 after base64 is replaced with U+FFFD instead of failing the unpack, a run of broken bytes giving one U+FFFD (1.1.74, 1.1.75); the parsing rules document CANON.md is renamed to contract/docs/PARSING_PRINCIPLES.md ("Source parsing principles"), gains an introductory section 0 on its terms and becomes the entry point to the contract, "envelope" → "parse result" throughout — no behaviour, codes, registry or corpus changes (1.1.76); the contract gets a human entry point — ARCHITECTURE.md (one page: registry, engine, the four parsing steps on a vless example, a diagram), GLOSSARY.md and an introductory block in every main document (1.1.77); the fold of a folder or subscription is the replace {mode, tag, auto?} field of its record, one form in the state, the backup file and LxBox, the state key replace.strategy renamed to replace.auto (the old key is still read); LxBox keeps the selector genus of imported groups, its backup corpus overrides dropped (1.1.78); the old fold + fold_tag (1.0) and fold (0.x) are no longer read or migrated — unknown keys with backup_unknown_field, the fold is set up again; the selector_as_auto code retired from the registry, dart refs of twelve protocols point at uri_pipeline.dart:parseLinkViaPipeline (1.1.79); a vpn:// line in a list of links is the whole container, an invalid sni= (a label) yields to the next source of the chain — servername= — before the server address, anytls/hysteria2 read servername=, the unused backup_replace_tag_derived code retired, the last two dart refs fixed, and two build codes for a folder/subscription fold: replace_tag_conflict (the fold tag is already declared by a Direction, another fold above or a template tag — the fold is not built, the config is; a node with the same name gets a -2 suffix instead of breaking the config) and replace_group_empty (a folded source with no enabled nodes), the fold editor warns about a taken tag (1.1.80).

Specifications: SPEC 142 — registry over local rules · SPEC 143 — canonical template walker


RU

Минорный релиз поверх v2.2.0. Ядро sing-box-lx 1.14.2-lx.4 (было 1.14.2-lx.2), контракт 1.1.80 (было 1.1.53).

Релиз про узлы. Реестр теперь единственный источник правил об узлах (SPEC 142): ссылки, подписки, конфиги sing-box и Xray и бэкапы судятся одними правилами на любом входе, а предупреждения, которые раньше доходили только до лога, видны в списке узлов и в отчёте сборки. Шаблон конфигурации получил один канонический обходчик (SPEC 143). Узлы WireGuard и AmneziaWG показывают своё живое состояние в Servers, их можно выключить и включить без правки конфига.

Основное

WireGuard / AmneziaWG: живое состояние и выключатель

  • Состояние в списке Servers. Подзаголовок строки WireGuard/AmneziaWG-узла заканчивается его состоянием в работающем ядре — up, sleep, freed, starting или off, — обновляется раз в 10 с, пока вкладка на экране. Узел, выключенный вручную, показывает серое off вместо красного Error: он не сломан.
  • Disable WireGuard / Enable WireGuard в меню строки выключает и включает узел в работающем ядре без правки конфига.
  • Секция WireGuard в окне Info узла: состояние (поднят, усыплён, освобождён, ещё не поднимался, выключен…) и время с последнего трафика, обновляется раз в 10 с, и кнопка Выключить / Включить рядом с состоянием.
  • Переключение действует до перезапуска ядра или применения конфига. Работает в daemon-режиме и на удалённых машинах (у classic-ядра такого API нет); нужно ядро 1.14.2-lx.4.

Шаблон конфигурации: один канонический обходчик (SPEC 143)

  • Шаблон конфигурации: @var / #if теперь везде подставляет один канонический обходчик — главный конфиг, on_change.set, тела пресетов и шаблонные DNS-серверы (SPEC 143). Предупреждения шаблона (незаявленная переменная, неизвестная директива, число вне диапазона или не число, выпавшие из-за пустой настройки правило / набор правил / DNS-правило / DNS-сервер пресета) идут первыми строками в «Итог» отчёта сборки, а не в лог; Save они не блокируют. Язык: массив в ветке условного элемента массива вливается на уровень выше (вложение — через [[...]]); ["@name"] больше не сворачивается в скаляр; options работают при любом типе, кроме bool, options_open: true разрешает свой ввод, enum = text с закрытыми options; в число значение превращается только по объявленному type: int (clamp [0, 65535], не-число остаётся строкой) — зашитый список числовых имён переменных удалён, поэтому в пользовательских шаблонах, где MTU или порт объявлены type: text, теперь уедет строка; @runtime.platform / @runtime.arch / @runtime.target разрешены в значениях config. В Settings список рисуется по options, при options_open — комбобокс, поле int проверяется как число. Контракт 1.1.68–1.1.70.

Узлы: правила реестра на любом входе (SPEC 142)

  • Ссылки hysteria2 из 3x-ui с gecko-обфускацией больше не теряют диапазон размеров пакетов: minPacketSize/maxPacketSize читаются, security=tls принимается молча (контракт 1.1.54).
  • VLESS-узлы с Vision поверх транспорта (xhttp, ws и др.) сохраняют flow, если у узла есть VLESS Encryption: раньше flow снимался, и сервер рвал соединение (контракт 1.1.55).
  • XHTTP uplink_data_placement=header|cookie без mode получает mode: packet-up на любом входе, включая sing-box JSON; при явном другом режиме placement снимается, а не роняет весь конфиг ядра. body/auto больше не трогаются: ссылки с uplinkDataPlacement=body и mode=stream-one раньше получали ложное предупреждение. У Shadowsocks plugin_opts без plugin снимается (контракт 1.1.56).
  • Ссылку узла опознаёт сам реестр: ссылки amneziawg:// вставляются серверами, а не принимаются за URL подписки, и новая схема реестра опознаётся без правки кода. Импорт sing-box JSON судит tls негодной формы и отсутствие server/server_port правилами реестра, как и остальные входы: узел получает код type_invalid / field_missing / port_invalid вместо молчаливой правки или голого отказа. Форма обфускации AmneziaWG пишет только выход конвейера; тело, которое конвейер собрать не может, не записывается — как в редакторе JSON.
  • Узлы Hysteria (v1), у которых obfs приходит объектом в духе Hysteria2 {type, password}, сохраняют обфускацию на любом входе — импорт sing-box, JSON-тело, вставленное руками, восстановленный бэкап: пароль становится строкой обфускации, узел получает информационное предупреждение (obfs_object_flattened); объект без пароля снимается с obfs_password_missing. У тел MASQUE устаревшие плоские ключи network/sni/skip_cert_verify снимаются с предупреждением unknown_key на любом входе, а не только при импорте sing-box и не молча (контракт 1.1.57).
  • Глобальная анти-DPI опция TLS (фрагментация ClientHello и записей) теперь применяется и к узлам MASQUE: ядро фрагментирует на h2-ноге и игнорирует на h3. Набор схем берётся из реестра, а не из списка в коде. Форма «Добавить WireGuard» больше не принимает MTU выше 1500 (граница реестра; большее значение раньше молча снималось позже), а при пустом Allowed IPs узел получает и 0.0.0.0/0, и ::/0. Негодные ключи, MTU или keepalive называются текстом кода реестра. Форма обфускации AmneziaWG принимает любой домен маскировки, который принимает ядро (без точки, с подчёркиванием), и проверяет его по реестру; явные i1/i2 рядом с маскировкой снимаются с предупреждением field_conflict, а не молча; выдуманного потолка jc/jmin/jmax больше нет. Форма Tailscale сообщает «доступ к LAN без exit node» вместо молчаливого сброса галки. Подпись транспорта узла одинакова в списке и в превью: tcp показывают только схемы с транспортом, MASQUE без vhttp — auto (контракт 1.1.58).
  • REALITY-узлы: одно правило реестра вместо двух противоречащих. REALITY-узел без uTLS (sing-box-тело, написанное руками, конфиг Xray без fingerprint) сохраняет REALITY, uTLS включается с информационным предупреждением (reality_utls_enabled); раньше реестр снимал REALITY, а сборка потом дописывала uTLS — узел уходил голым uTLS на REALITY-сервер. Отпечаток random под REALITY на любом входе закрепляется как chrome с информационным предупреждением (reality_fp_random_pinned): ядро разворачивает random один раз при запуске в один из пяти отпечатков, и у двух из них (edge, ios) нет гибридного обмена ключами, которого требуют современные REALITY-серверы. Узлы, уже сохранённые в состоянии, и ручные объекты config_json получают ту же правку на сборке по тому же правилу реестра, с кодом в логе вместо прежней молчаливой; узел, чей REALITY снят за битый публичный ключ, сохраняет свой отпечаток. Цепочка, снимающая uTLS при REALITY-узле на одной из позиций, больше не исключается: снятие uTLS для неё отключается, в логе — chain_strip_utls_on_reality (контракт 1.1.61).
  • Узлы AmneziaWG с jmin больше jmax больше не заставляют ядро отвергать весь конфиг: на любом входе обе границы снимаются с предупреждением fields_order_invalid, узел работает. Анонсируемые маршруты Tailscale приводит реестр на любом входе: голый адрес становится маршрутом хоста, биты хоста обнуляются (192.168.10.5/24 → 192.168.10.0/24), маршрут по умолчанию (0.0.0.0/0, ::/0) снимается с предупреждением tailscale_default_route_advertised (для этого есть настройка выхода) — раньше это проверяла только форма добавления узла. В конфигах Xray звено цепочки, которое выходит наружу через freedom с fragment, получает фрагментацию ClientHello само; раньше её получал владелец цепочки, чей TLS идёт внутри туннеля звена. Ссылки vpn:// опознаются без учёта регистра (контракт 1.1.63).
  • Узлы MASQUE: TLS-настройки, которые ядро у MASQUE не использует — alpn, ech, reality, kernel_tx/kernel_rx, — снимаются на любом входе с info-уведомлением (masque_tls_field_ignored); фрагментация TLS снимается только при vhttp: h3 (masque_tls_fragment_h3), и глобальная анти-DPI опция её там больше не дописывает, на h2/auto остаётся. VLESS из конфига Xray с encryption: "None" (с заглавной) теперь отбраковывается кодом vless_encryption_invalid, как на ссылке и в sing-box, а не теряет слой шифрования молча (контракт 1.1.64).
  • Предупреждения, которые раньше доходили только до лога, теперь видны пользователю текстом реестра: у импортированного sing-box-конфига с обрезанной цепочкой detour (цели нет, цель — группа, кольцо, слишком глубоко) узел получает ⚠; группа без членов встаёт неразобранной записью с кодом group_empty; подписка, обрезанная лимитом узлов, несобравшаяся цепочка (ядро без цепочек, нет позиции, вложенная цепочка, нарушенное правило), цепочка, у которой снятие uTLS отключено ради REALITY, цепочка, не взятая в Направление, через которое идёт, и потерянная цель detour источника (одна строка на источник и цель с числом исключённых узлов) показываются в отчёте сборки по коду реестра.
  • Узлы WireGuard с портом прослушивания (listen_port из .conf или ссылки), которые вы ведёте через хоп, больше не заставляют ядро отвергать весь конфиг: сборка снимает порт прослушивания с кодом detour_with_listen_port в отчёте и сохраняет хоп. Узел, ведущийся через самого себя или через кольцо хопов, называется в отчёте кодом (source_detour_self, source_detour_cycle). Запись SSH без пользователя в импортированном конфиге sing-box получает явный root с info-кодом (ssh_user_default) — ядро и так подключалось как root (контракт 1.1.65).
  • Импортированная группа (selector / urltest / балансировщик Xray), потерявшая часть членов, теперь показывает ⚠ с числом потерянных прямо в своей строке списка узлов (group_member_missing), рядом с размером пула; прежде потеря была только строкой в статусе обновления подписки. Отметка переживает экспорт/импорт бэкапа (контракт 1.1.66).

Профили Amnezia и имена в ссылках

  • Origin узла из профиля Amnezia vpn:// теперь полный .conf. Узел хранит происхождением собственный текст .conf с перенесёнными в него значениями контейнера: MTU профиля (если в [Interface] его нет) и адреса DNS профиля вместо $PRIMARY_DNS / $SECONDARY_DNS. Regen from raw пересобирает узел из одного этого текста, без ссылки vpn://; теги не меняются. Узлы, импортированные раньше, работают как прежде (контракт 1.1.72); обновление подписки переписывает их происхождение. Строка vpn:// внутри списка ссылок (в подписке, во вставке в Add или в поле Source формы Add server, в файле .vpn) теперь даёт все WireGuard/AmneziaWG-контейнеры профиля, каждый со своим .conf в происхождении, — те же узлы, что подписка из одной этой ссылки (контракт 1.1.80).
  • Ссылки, у которых в sni= вместо имени хоста метка (Germany, эмодзи), у AnyTLS и Hysteria2 получают SNI с адреса сервера, как велит реестр. Уведомление о проигнорированном DNS WireGuard-ссылки показывает декодированный список адресов (1.1.1.1, 1.0.0.1, а не 1.1.1.1,+1.0.0.1). Ссылка vmess://, чей пейлоад не JSON-объект v2rayN и не legacy-ссылка method:uuid@host:port — например, мусор вместо base64, — отвергается с кодом form_unrecognized вместо невнятного отказа (контракт 1.1.73, 1.1.74).
  • Битый байт в имени узла (например, метка в cp1251 от агрегатора — percent-кодом во фрагменте ссылки или сырыми байтами внутри base64 у vmess) больше не стоит узла: узел импортируется, а место повреждения в имени видно как � — прежде кусок вырезался или отвергалась вся ссылка (контракт 1.1.74).

Бэкап: свёртка папки и подписки

  • Свёртка папки или подписки (одна группа вместо её узлов в Направлениях) едет в файле бэкапа той же формой, что в состоянии приложения, — replace {mode, tag, auto} внутри записи папки/подписки — вместо прежней пары fold + fold_tag. Прежняя форма не читается и не мигрирует: старый бэкап со свёрткой формы fold её теряет (ключи отбрасываются с предупреждением о неизвестном поле, правила на группу свёртки приезжают выключенными) — свёртку настраивают заново (контракт 1.1.78, 1.1.79).

Исправления

  • Вкладка Overview у узла внутри папки теперь описывает сам узел — вид, тег, включённость и его собственную запись хранилища, — а не папку («Type: Group», имя папки и «Nodes: 5»).
  • Пресетные DNS-серверы теперь подчиняются своему условию #enable: при выключенном DNS override серверы Yandex DoH/DoT пресета russian больше не попадают в config.json (раньше они уезжали всегда, переключатель учитывали только правила пресета).

Что проверить после обновления

Свои шаблоны

  • Значение шаблона становится числом, только если переменная объявлена type: int (clamp [0, 65535]). Зашитого списка числовых имён больше нет: если в вашем wizard_template.json MTU, порт или другая числовая настройка объявлены type: text, в config.json теперь уедет строка, и ядро может отвергнуть конфиг — объявите переменную type: int. Штатный шаблон это уже делает.
  • Проверьте и шаблоны, которые опирались на старый обходчик: массив в ветке условного элемента массива теперь вливается на уровень выше (вложение — через [[...]]), а ["@name"] больше не сворачивается в скаляр. Предупреждения шаблона идут первыми строками в «Итог» отчёта сборки.

Ядро

  • Состояние WireGuard и Disable / Enable WireGuard требуют ядра sing-box-lx 1.14.2-lx.4; лаунчер предложит обновить ядро. В daemon-режиме и на удалённых машинах lx.4 должно быть ядро демона.

Техническое / Внутреннее

  • Пин ядра sing-box-lx 1.14.2-lx.4 (было 1.14.2-lx.3): ядро отдаёт состояние каждого WireGuard/AmneziaWG-узла и умеет выключать и включать узел на лету (SPEC 106 форка). Миграции конфига и состояния нет. gRPC-стабы (internal/daemonpb) синхронизированы с форком на 1.14.2-lx.4.
  • Пин ядра sing-box-lx 1.14.2-lx.3 (было 1.14.2-lx.2). Vision (flow: xtls-rprx-vision) теперь работает поверх VLESS Encryption на любом транспорте, xhttp в том числе (SPEC 105 форка, sing-box-lx#29); вместе с контрактом 1.1.55 такие узлы подключаются, а не рвутся сервером. Миграции конфига и состояния нет.
  • Примитивы контракта 1.1.56: condition тела принимает предикаты по значению путей (in/not_in/скаляр, грамматика when маппера), у связей появился when, в when маппера — селектор $value (собственное значение записи; промах — молчаливый пропуск без on_when_false). Нормы санитайзера: связи и условия видят поля объекта, обход которого ещё идёт; пустая строка и литерал absent_values для default_when равны отсутствию ключа; пустая строка не выполняет any_set. Всё на уровне движка, без имён схем в коде.
  • SPEC 142 волна 1: сняты рукописные копии правил реестра — таблица «тип sing-box → схема» и таблица endpoint-схем (теперь registry.NodeSchemeForSingboxType по singbox_type + sources, registry.ProtocolKind), список префиксов прямой ссылки (linkmap.SelectURI), сборка socks-звена Xray (секция движка socks#xray), предпроверки формы tls и адреса в импорте sing-box, мёртвые хелперы uTLS / WS early data / Vision / MASQUE. Тип chain из чужого конфига узлом не становится (у схемы нет sources). Данные реестра не менялись, бампа контракта нет.
  • SPEC 142 волна 2: рукописный санитайзер импорта sing-box (SanitizeSingboxOutboundMap, singbox_sanitize.go) снят. Два его последних правила стали данными реестра: новый примитив движка on_invalid: unwrap (объект-обёртка соседнего диалекта → значение его члена key, иначе else_code; без имён схем в коде) у hysteria.body.obfs и перенос legacy-ключей MASQUE в body.skipped. Контракт 1.1.57.
  • SPEC 142 волна 3: каталог strip цепочки, требование ip=quic → id и LDH-шаблон id у AmneziaWG, связь Tailscale exit_node_allow_lan_access → exit_node стали данными реестра; форма цепочки, формы AWG/WireGuard/Tailscale/WARP, трансформы TLS, подписи транспорта и приведение vhttp MASQUE читают реестр (Field.AllowedForScheme, FieldAllowed, FieldStrings, FieldsWithBuildTag). Движок linkmap больше не называет код отказа транспорта и его параметр. Контракт 1.1.58.
  • SPEC 142 волна 4: новый атрибут поля реестра role (credential | private_key). Учётные данные узла (ParsedNode.UUID) читаются по роли одинаково на всех входах (registry.Credential) — три рукописные копии по имени схемы сняты; ссылка и JSON больше не расходятся (у JSON ssh/naive/socks/http теперь имя пользователя, у ссылки ss — пароль вместо шифра, у ссылок WireGuard/MASQUE приватный ключ туда больше не кладётся; пользовательских читателей у поля нет). Какие share-ссылки требуют подтверждения (несут приватный ключ), решает роль private_key, а не таблица типов в коде; состав тот же (ssh, WireGuard, MASQUE). Контракт 1.1.59.
  • SPEC 142 волна 5: узловые гейты ядра — данные реестра. Новые атрибуты on_core_unsupported (тело протокола, поле, форма-диапазон), range_form (только awg_range), levels/level/level_mark. Один общий гейт (nodeflow.NodeCoreRefusal) заменил три пробы по протоколу (naive, Tailscale, AmneziaWG 3.x) и рукописный список полей AWG 3.x (awg3.go снят); приложение сообщает только теги сборки ядра. Подпись уровня AmneziaWG и кнопка формы «убрать AmneziaWG» (диапазонный keepalive схлопывается в нижнюю границу) читают реестр. Снимаются те же узлы с теми же кодами; в отчёте сборки — одна строка на код с заголовком из реестра («AmneziaWG 3.x: ядро слишком старое — пропущено узлов: 2 — …»). Контракт 1.1.60.
  • SPEC 142 волна 6: REALITY ↔ uTLS — одно правило реестра, его исполняет санитайзер на всех входах. Новые примитивы: requires[].set (недостающий требуемый сосед материализуется с кодом вместо снятия поля), атрибут поля coerce_when (условная замена годного значения) — оба судятся по готовому телу после обхода, коды встают на место по body.order; атрибут ключа каталога strip цепочки on_hop_required {action: unstrip}, судит nodeflow.StripBlocked (тело звена получило бы путь обратно от requires … set). Тела, которые сборка не прогоняет через санитайзер (замороженные тела состояния, ручной config_json), получают только правила-починки через nodeflow.Repairs. Сняты: EnforceRealityFingerprint (файл node_parser_transport.go удалён), build.HealRealityFingerprints и его шаг сборки, NodeUsesReality/ChainStripsUTLS/ChainRealityConflict. Контракт 1.1.61.
  • SPEC 142 волна 8: указатели реестра на код (refs.go, impl, go у кодов, заметки) приведены к правде — 141 запись refs.go вела в удалённые рукописные парсеры/эмиттеры или на строки за концом файла (осталось 53, в форме путь.go[:Имя]), ~335 заметок указывают, где правило исполняется сейчас; новый линтер TestRegistryCodeRefsResolve проверяет, что каждый файл существует, а названное имя в нём объявлено (джоба Contract, триггер — любой .go). Правила реестра не менялись. Контракт 1.1.62.
  • SPEC 142 волна 7: последние рукописные правила об узлах — данные реестра. Примитивы тела: связь ordered (+ действие drop), атрибут поля item_forbidden, normalize cidr_masked, атрибут тела протокола exit_capable_when (его читает ParsedNode.IsExitCapable). Примитивы маппера: источники context.<путь> (значение от распаковщика контейнера) и ref.<as>.<путь> (сосед по документу, найденный записью с deref {key, as}), атрибут записи substitute, оператор when type_of. Сняты: applyXrayFreedomFragment с хелперами, amneziaPrepareConf (MTU из last_config, подстановка $PRIMARY_DNS — теперь записи секции conf wireguard), литерал vpn:// (detect вида источника amnezia_link, linkmap.MatchesUnwrap), проверка jmin ≤ jmax в форме AWG, parseTailscalePrefixList. Норма санитайзера (PARSING_PRINCIPLES §6.2): поле, снятое правилом значения или связи, для последующих связей и условий отсутствует (раньше ib оставался после снятия ip). Контракт 1.1.63.
  • SPEC 142 волна 9 (хвосты кампании): снят мёртвый код — subscription/hysteria2_ports.go (его правила — данные реестра), percentEncodeUserinfoSpaces, нечитаемые поля ParsedNode.UUID/ParsedJump.UUID и registry.Credential; новый registry.Registry.FieldAllowedOn (оставил бы санитайзер поле в этом теле) — им пользуются TLS-трансформы сборки; gendocs печатает условие when у связей.
  • SPEC 142 волна 10b: новый registry.Registry.YieldsTo — поля готового тела, которые связь conflicts {with} сняла бы, когда managed-поле, дописанное сборкой, уже есть; сборка спрашивает его сразу после проставления detour. Поля go кодов указывают, где их доставляет волна 10a; body_dialect_unrecognized снят (события нет, константа мёртвая); direction_filter_matched_nothing зарегистрирован (им пользовался только корпус Направлений). Контракт 1.1.65.
  • SPEC 142 волна 11a: warnings[] разрешены у узла-группы (kind=auto) в состоянии и бэкапе; импорт бэкапа берёт записи группы как есть (тела нет — пересчитывать нечем). group_member_missing перенесён с уровня тела подписки на узел-группу (subscription.markGroupMemberMissing, одна запись на группу, число складывается по шагам разбора). Корпус +1 body/singbox/group_member_missing. Контракт 1.1.66.
  • SPEC 142 волна 12: член группы, выпавший при сборке конфига (узла нет, он выключен или исключён), доходит до отчёта сборки с кодом group_member_dropped (текст из реестра, оба языка) вместо голой строки. Поправлен текст контракта: запись core_rejected экспортируется как есть, но при импорте бэкапа снимается — enabled берётся из файла, импорт узел не включает, ядро приёмника судит его заново, когда человек включит узел (импорт так уже и работал). Контракт 1.1.67.
  • Контракт 1.1.68 → 1.1.80. Язык шаблонов SPEC 143 — сплайс на один уровень, без коллапса ["@name"], options независимо от type и options_open, @runtime.* в значениях (1.1.68); коды template_* доходят до «Итога» отчёта сборки видом template_degraded (1.1.69), плюс новый template_fragment_dropped для фрагмента пресета или шаблонного DNS-сервера, оставшегося без обязательного поля (1.1.70); SPEC 143 закрыта на desktop (1.1.71); origin узла из vpn:// — самодостаточный .conf (wg_ini, 1.1.72); корпус приведён к норме (задача LxBox 560, 1.1.73); невалидный UTF-8 после base64 заменяется U+FFFD, а не роняет раскрытие, серия битых байтов даёт один U+FFFD (1.1.74, 1.1.75); документ о правилах разбора CANON.md переименован в contract/docs/PARSING_PRINCIPLES.md («Принципы разбора источников»), получил вводный раздел 0 о терминах и стал точкой входа в контракт, «конверт» → «результат разбора» по всему контракту — поведение, коды, реестр и корпус не менялись (1.1.76); у контракта появился вход для человека — ARCHITECTURE.md (одна страница: реестр, движок, четыре шага разбора на примере vless, схема), GLOSSARY.md и вводный блок в каждом основном документе (1.1.77); свёртка папки или подписки — поле replace {mode, tag, auto?} её записи, одна форма в состоянии, файле бэкапа и у LxBox, ключ состояния replace.strategy переименован в replace.auto (старый читается); LxBox сохраняет род selector у импортированных групп, его override корпуса бэкапа сняты (1.1.78); прежние fold + fold_tag (1.0) и fold (0.x) больше не читаются и не мигрируют — неизвестные ключи с backup_unknown_field, свёртку настраивают заново; код selector_as_auto выведен из реестра, dart-ссылки двенадцати протоколов ведут на uri_pipeline.dart:parseLinkViaPipeline (1.1.79); строка vpn:// в списке ссылок — контейнер целиком, негодный sni= (метка) уступает сперва следующему источнику цепочки — servername=, — и лишь потом адресу сервера, anytls/hysteria2 читают servername=, неиспользуемый код backup_replace_tag_derived выведен, две последние dart-ссылки поправлены, и два кода сборки для свёртки папки/подписки: replace_tag_conflict (тег свёртки уже объявлен Направлением, свёрткой выше по списку или тегом шаблона — свёртка не собирается, конфиг собирается; узел с тем же именем получает суффикс -2, а не ломает конфиг) и replace_group_empty (у свёрнутого источника нет включённых узлов), редактор свёртки предупреждает о занятом теге (1.1.80).

Спецификации: SPEC 142 — реестр важнее локальных правил · SPEC 143 — канонический обходчик шаблона

Don't miss a new singbox-launcher release

NewReleases is sending notifications on new releases.