Both apk jobs of v0.2.2 died with `Disk quota exceeded`. The SDK was running `apk mkpkg` on 3593 kmod-* packages (mlx5, amdgpu, ata, isdn — none of which we ship) before it ever got near our four. Root cause: ci/sdk-build-apk.sh APPENDED our package selections to the .config that ships inside the ImmortalWrt SDK tarball. That file is the buildbot's fully-expanded config and carries CONFIG_ALL_KMODS=y plus CONFIG_ALL_NONSHARED=y (see config.buildinfo next to the SDK), so `make defconfig` re-selected every kernel module of the target as =m and package/kernel/linux/compile — pulled in via shater-core's nft kmod deps — packed the lot. Fix, modelled on Slava-Shchipunov/awg-openwrt's "Setup SDK and feeds": start the .config EMPTY so kconfig can only pull in what our packages actually select. Carried over from the SDK's .config, nothing more: the target choice and its BOARD/SUBTARGET/ARCH_PACKAGES identities (a wrong guess here means silently cross-compiling for another arch), CONFIG_USE_APK (decides .apk vs .ipk — the point of this lane), and CONFIG_KERNEL_* verbatim (they generate the kernel .config; dropping one makes the buildsystem reconfigure and rebuild the SDK's prebuilt kernel). Also adds the diagnostics this lane never had, since a failed run leaves a 27 MB log: the carried-over identity lines, the post-defconfig kmod count and target readout, a hard check that all four of our packages survived defconfig, an abort if the kmod count is back in the hundreds, and du/df after compile. opkg lane (ci/sdk-build.sh, ci/make-index.sh) untouched. LOCALMIRROR, CONFIG_DOWNLOAD_FOLDER and every cache path are unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
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.
- 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 shaternft table; atomic apply withnft -cvalidation and commit-confirm auto-rollback. - DNS filtering & blocklists with flexible sources (inline / file / url /
geosite), compiled
.srsmatcher; 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
Two signed feeds. Pick by the router's OpenWrt version. Verbatim commands and the
manual .ipk/.apk install are in docs-shater/INSTALL.md.
opkg (OpenWrt 24.10):
wget -O /etc/opkg/keys/5ac4b177689cb8e0 \
https://git.qomar.pw/omar/shater/releases/download/latest/shater-feed.pub
echo "src/gz shater https://git.qomar.pw/omar/shater/releases/download/latest" \
>> /etc/opkg/customfeeds.conf
opkg update && opkg install luci-app-shater # -> shater-core -> shaterd
apk (OpenWrt / ImmortalWrt / BananaWRT 25.12+):
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
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, 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 signed
feeds: opkg (usign, key 5ac4b177689cb8e0) and apk (EC key shater-apk.pem). A
vX.Y.Z tag → versioned release; workflow_dispatch → rolling latest.
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.