omarandClaude Opus 5 6476722372
test / go + panel tests (push) Successful in 5m26s
release / test gate (push) Successful in 5m28s
release / apk aarch64_cortex-a53 (push) Successful in 6m7s
release / apk x86_64 (push) Successful in 3m5s
release / release apk (push) Successful in 7s
fix(panel): stop shipping a fabricated router in the binary
mock.ts was a static import and the mock switch was read from the query string at
runtime, so the bundle that ships inside the daemon carried a complete fictional
router and a link ending in ?dev rendered it: protected, 119 of 122 nodes alive,
without a single request to the daemon. The only tell was a line in the footer.
That is worse than any wrong number — there is no data at all and nothing says
so. It is out of the production bundle now, which is 21 kB smaller for it.

Unknown state stopped reading as good news in two more places. The kill-switch
tile treated an absent plane as armed, because the check was "not none" and
undefined satisfies it — the contract in the API types says the opposite. And the
apply page announced "daemon auto-rolled back" from its own timer, while the
daemon, seeing the state generation move, disarms and says it is NOT rolling back
in the log only.

Alerts moved to Settings. They are about the kill switch, apply failures, new
devices and subscription expiry, and they lived at the bottom of the DNS page,
while Settings mentioned them in prose with nothing to click.

Findings truncation is visible now: the notice that says how many were suppressed
arrives as info, and the attention list keeps only critical and warning, so past
fifty findings the operator saw forty-nine and no hint of the rest.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 15:40:39 +03:00
2026-06-25 16:36:07 +08:00
2026-06-25 17:38:53 +08:00
2026-06-25 17:39:02 +08:00
2026-02-27 14:58:06 +08:00
2026-06-25 17:38:01 +08:00
2025-04-29 20:45:19 +08:00
2023-12-29 18:00:40 +08:00
2023-12-29 18:00:40 +08:00
2026-02-26 14:13:32 +08:00
2026-06-25 19:47:32 +08:00
2026-07-08 00:34:26 +08:00

shater

A self-hosted internet-control appliance for OpenWrt routers. One box turns a home or office network into a transparent VPN gateway, a network-wide ad/tracker/malware blocker, per-device parental control, and a live traffic dashboard — all local, all configured from a rich built-in web panel.

The primary README is Russian — README.md. This is a condensed English mirror.

License: GPL-3.0 targets: x86_64 · aarch64_cortex-a53

What it is

shater is a network proxy stack for OpenWrt / ImmortalWrt / BananaWRT routers (Banana Pi BPI-R3, BPI-R4 and compatible). It transparently routes all LAN traffic through a proxy (split by domain/geo/client), filters DNS, gathers statistics, and is managed from a built-in web panel.

The engine is a fork of sing-box via sing-box-lx, compiled into a single Go binary shaterd together with the control plane, DNS filter, stats aggregator and the web panel itself. Broad protocol set: VLESS/VMess/Trojan/Shadowsocks, Reality/XTLS, WireGuard, AmneziaWG 2.0, Hysteria2, TUIC, XHTTP, MASQUE/CONNECT-IP.

A thin LuCI launcher (mini-dashboard + "Open panel" button) hands the browser a single-use token into the standalone SPA the daemon serves on its own port (default :8088).

Highlights

  • Transparent TPROXY data plane (TCP + UDP), SNI/Host/QUIC sniffing, no DNS leaks — :53 interception is on by default and covers the queries a client sends to the router itself, not just the ones aimed around it (globals.dns_intercept, D24).
  • First-match routing by source / destination / list / geo / client → outbound / selector / chain / direct / block; node groups with balancer/observatory; multi-hop chains; per-rule egress.
  • Fail-closed kill-switch (dead group → block, never a silent direct leak); own inet shater nft table; atomic apply with nft -c validation and commit-confirm auto-rollback.
  • DNS filtering & blocklists with flexible sources (inline / file / url / geosite), compiled .srs matcher; Block-DoH/DoT to stop filter bypass.
  • Subscriptions (Clash / sing-box / Xray-JSON) and manual nodes; node health board.
  • Per-device control (proxy/blocklist toggles, exit country, per-device block/allow, schedules) and per-domain/client/device statistics from in-process DNS events.

Full list with MVP/T1/T2 tags — docs-shater/FEATURES.md.

Install

One signed apk feed (OpenWrt / ImmortalWrt / BananaWRT 25.12+), one release per arch. Verbatim commands, the manual .apk install and the rolling-vs-pinned choice are in docs-shater/INSTALL.md.

wget -O /etc/apk/keys/shater-apk.pem   "https://git.qomar.pw/omar/shater/releases/download/apk-latest-$(cat /etc/apk/arch)/shater-apk.pem"
echo "https://git.qomar.pw/omar/shater/releases/download/apk-latest-$(cat /etc/apk/arch)/packages.adb"   > /etc/apk/repositories.d/shater.list
apk update && apk add luci-app-shater         # -> shater-core -> shaterd

apk-latest-<arch> is a moving pointer refreshed by every release run — install once and apk update && apk upgrade shaterd shater-core luci-app-shater byedpi keeps the router current. Point the repo line at apk-vX.Y.Z-<arch> instead to pin a build; that file then has to be edited by hand for every upgrade.

shater ships inert (globals off) so install never breaks connectivity. After configuring nodes/rules: uci set shater.globals.enabled=1 && uci commit shater, then shaterd apply and shaterd confirm.

Build from source

scripts/build-shaterd.sh [VERSION] [--fast] builds the SPA (Vite), embeds it via //go:embed, cross-builds musl-static {amd64, arm64} and UPX-packs the artifact into openwrt/shaterd/files/. Details in docs-shater/INSTALL.md.

Repository layout

Path What
shater/ Go control plane, DNS filter, stats aggregator, engine host
panel/ Admin SPA (Vite + React + TS) and its Go server
openwrt/ Packages: shaterd, shater-core, luci-app-shater, byedpi
docs-shater/ Product documentation
scripts/, ci/, .gitea/workflows/ Build script, apk feed/release scripts, CI
SPECS/, docs-lx/ Engine-fork constitution/specs and feature-config reference
docs/, mkdocs.yml Upstream sing-box docs (mkdocs) — kept as-is
adapter/ cmd/ dns/ route/ option/ protocol/ transport/ … sing-box-lx engine tree

CI, upstream & license

CI (.gitea/workflows/release.yml) builds all 4 packages and publishes a signed per-arch apk repo (EC key shater-apk.pem). A vX.Y.Z tag → the pinnable apk-vX.Y.Z-<arch>; every run also refreshes the rolling apk-latest-<arch> and asserts over the API that it really serves the version just built.

The engine is the sing-box-lx fork — a thin downstream of upstream sing-box that lives by rebase, never merge; its constitution is SPECS/CONSTITUTION.md. Licensed under GPL-3.0, like upstream sing-box. Unofficial fork, not affiliated with SagerNet.

S
Description
OpenWrt XRAY management plugin � passwall-class, but cleaner. Design + code.
Readme
56 MiB
2026-07-28 07:50:40 -04:00
Languages
Go 77.7%
TypeScript 12.4%
PureBasic 4.2%
Shell 2.5%
CSS 2.1%
Other 1%