Files
shater/README.md
T
omarandClaude Opus 5 f86501bf77 ci!: drop the opkg lane — apk only, and fix the stale rolling release
Both routers are past opkg: mini_router runs ImmortalWrt 25.12.1 and
main_router OpenWrt 25.12.0, both with apk-tools 3.0.5, and main_router has
no `opkg` binary at all. The 24.10 lane was building and signing a feed no
device could consume.

Removed jobs `build` and `release` with the scripts only they called
(ci/build-feed.sh, ci/sdk-build.sh, ci/make-index.sh, ci/install-usign.sh)
and the usign trust anchor dist/shater-feed.pub. A committed public key is
an instruction: it invites the old install path for a feed that is no longer
produced. The key is retired, not revoked -- git history keeps it, KEY_BUILD
still holds the secret half, and a usign secret contains its own public half,
so the identity is reconstructible if a 24.10 device ever needs serving.
D7 is marked SUPERSEDED by the new D22 rather than deleted.

Separately: the rolling `apk-latest-<arch>` release was frozen at 0.2.0 from
2026-07-24 while every tag run published its versioned release correctly.
The publish loop was an either/or -- `TAG=apk-latest-<arch>` when VER=latest
(workflow_dispatch only), ELSE `TAG=apk-<ver>-<arch>` -- so a `v*` tag run
never touched the rolling pointer. Asset replacement was never the problem;
ci/gitea-release.sh already deletes before recreating. A router pinned to
the rolling URL sat on 0.2.0 while `apk update` reported success: silent
staleness, the failure mode this repo keeps having to close.

The rolling pointer is now published on EVERY run, tag runs included, and a
new assert reads the release back over the API afterwards: our three
tag-versioned packages at the built version plus the index and the key must
be present (exit 13), and no package asset at any other version may survive
(exit 14). Same class of check as sdk-build-apk.sh's package-version assert,
added for the same reason -- the previous failure mode was silent.

KEY_BUILD can now be deleted from the Gitea repo secrets; nothing references
it. Docs state plainly that mini_router is deliberately pinned to a
versioned URL and that the hand-edit per release is the price of pinning.

Known consequence: the x86_64 QEMU testbed is still OpenWrt 24.10.3 and can
no longer install our packages. Its 25.12 rebuild is in flight separately.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H4PcWfrBRyg4eWN58axaGN
2026-07-25 18:46:21 +03:00

20 KiB
Raw Permalink Blame History

shater

Управляемый интернет-шлюз для роутеров на OpenWrt. Одна коробка превращает домашнюю или офисную сеть в прозрачный VPN-шлюз, сетевой блокировщик рекламы, трекеров и вредоносных доменов, средство родительского контроля по устройствам и живую панель аналитики трафика — всё локально, всё self-hosted, всё настраивается из богатой веб-панели.

License: GPL-3.0 targets: x86_64 · aarch64_cortex-a53 feed: apk 25.12+


Что это

shater — это сетевой прокси-стек для роутеров на OpenWrt / ImmortalWrt / BananaWRT (Banana Pi BPI-R3, BPI-R4 и совместимые). Он прозрачно (без настройки клиентов) заворачивает весь LAN-трафик через прокси с маршрутизацией по домену, гео и клиенту, фильтрует DNS, собирает статистику и управляется из встроенной веб-панели.

Ядро — форк движка sing-box через sing-box-lx — вкомпилировано в один Go-бинарь shaterd вместе с control-plane, DNS-фильтром, агрегатором статистики и самой веб-панелью. За счёт sing-box поддерживается широкий и актуальный набор протоколов: VLESS/VMess/Trojan/Shadowsocks, Reality/XTLS, WireGuard, AmneziaWG 2.0, Hysteria2, TUIC, XHTTP, MASQUE/CONNECT-IP.

Интеграция в OpenWrt — тонкий LuCI-лаунчер: мини-дашборд и кнопка «Открыть панель», которая по одноразовому токену передаёт браузер в полноценную SPA-панель, поднятую демоном на собственном порту (по умолчанию :8088).


Ключевые возможности

Прозрачный прокси и маршрутизация

  • TPROXY data-plane для нескольких LAN-интерфейсов (TCP + UDP), сниффинг SNI/Host/QUIC, без утечек DNS.
  • Правила маршрутизации по источнику (IP/CIDR/MAC/интерфейс/зона), назначению (domain/suffix/keyword/geosite), спискам, порту, протоколу → outbound / selector / chain / direct / block.
  • Группы узлов с балансировщиком/обсерваторией (least-ping / failover / round-robin), мульти-хоп цепочки и выбор egress по правилу.

Надёжность («железно»)

  • Fail-closed kill-switch: мёртвая группа → block, а не тихая утечка мимо прокси; собственная nft-таблица inet shater и свои марки/таблицы, fw4 не трогаем.
  • Атомарный apply с валидацией движком и nft -c, commit-confirm с авто-откатом к последней рабочей конфигурации.
  • Идемпотентный reconcile из hotplug/boot под flock; management-bypass (SSH/LuCI/LAN) всегда в обход.

DNS, фильтрация, блокировки

  • Перехват :53, DNS движка sing-box в процессе; резолверы DoH/DoT/plain/FakeIP, выбор резолвера по домену.
  • Блок-листы с гибкими источниками: inline / file / url (авто-обновление) / категория geosite; hosts-файл, plain-список или AdBlock-стиль ||domain^ компилируются в локальный .srs. Эффективный компилированный матчер вместо dnsmasq-мегасписков.
  • Block-DoH/DoT — не даёт устройствам обходить фильтр через свой шифрованный DNS.

Подписки и узлы

  • Подписки (VLESS/VMess/Trojan/SS/WG/AmneziaWG), форматы Clash/sing-box/Xray-JSON, интервал обновления + вручную + на загрузке; стабильная идентичность узла между обновлениями; квоты/срок из subscription-userinfo.
  • Ручные узлы: share-ссылки, импорт файла, wg-quick/AmneziaWG .conf.
  • Health board: TCP + реальная проба через прокси-путь, exit-IP, «протестировать все».

Контроль по устройствам

  • Авто-обнаружение устройств (dhcp.leases + ip neigh), имена, живой статус/трафик.
  • Тумблеры на устройство: прокси on/off, блок-листы on/off, страна/узел выхода; блок/allow домена для одного устройства или для всех; расписания.

Статистика и видимость

  • Топ доменов (запрошенные/заблокированные), allowed-vs-blocked, разбивка по устройствам, таймлайны — из DNS-событий движка в процессе (без скрейпинга логов).
  • Трафик по клиенту/узлу/правилу (байты) из nft-счётчиков; живой query-log.

Панель и профили

  • Встроенная SPA-панель (собственный порт, вшита в бинарь): overview, узлы и подписки, правила маршрутизации, DNS/блок-листы, устройства, apply/rollback.
  • Именованные профили/сцены и WAN-профили (условные оверрайды).

Полный список с тегами MVP/T1/T2 — docs-shater/FEATURES.md.


Архитектура

Один бинарь shaterd держит движок, control-plane, DNS-фильтр и веб-сервер панели в одном процессе; OpenWrt-обвязка (тонкий LuCI + procd/system glue) оборачивает его. Конфиг — UCI desired-state; демон рендерит его в конфиг движка и применяет; телеметрия течёт обратно в панель.

flowchart TB
  subgraph BIN["shaterd — один бинарь (форк sing-box-lx)"]
    ENG["движок sing-box\nпротоколы · Reality · AmneziaWG 2.0 · DNS · routing · stats"]
    CTRL["control-plane (shater/)\nUCI-модель · генерация конфига · apply/rollback · nft/routing"]
    FILT["DNS-фильтр + блок-листы + политика по устройствам (shater/)"]
    STAT["агрегатор статистики (shater/)"]
    PANEL["веб-сервер панели + вшитая SPA (свой порт, токен-auth)"]
  end
  subgraph WRT["OpenWrt-обвязка (openwrt/)"]
    LUCI["тонкий LuCI — мини-дашборд + кнопка «Открыть панель»"]
    PROCD["procd init · hotplug · uci-defaults · fw4/routing"]
  end
  LUCI -->|"ubus: mint token"| PANEL
  PROCD --> BIN
  CTRL --> ENG
  FILT --> ENG
  ENG --> STAT
  STAT --> PANEL

Путь трафика: LAN-клиент → nft tproxy (mark → tproxy-порт) → tproxy-inbound sing-box (сниффинг SNI/Host/QUIC) → маршрут по правилу → outbound/selector/chain (проксировано) · direct (flow-offload) · block. Подробные диаграммы (auth-handoff, data-plane, DNS-flow, apply-flow) — в docs-shater/ARCHITECTURE.md.


Установка

shater поставляется одним подписанным apk-фидом (OpenWrt / ImmortalWrt / BananaWRT 25.12+: .apk, индекс packages.adb, EC-ключ в /etc/apk/keys/). Старый opkg-фид (.ipk, 24.10) снят — оба наших роутера на 25.12 с apk-tools 3, бинаря opkg там просто нет (docs-shater/DECISIONS.md D22).

Пакеты ставятся по зависимостям: shaterd → shater-core → luci-app-shater (+ опциональный byedpi). shaterd подтягивается автоматически как зависимость.

Фид apk

/etc/apk/arch сам выбирает нужный per-arch релиз (apk-релизы раздельны по арке):

# 1) доверяем ключу apk-фида (любое имя *.pem под /etc/apk/keys подходит).
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"

# 2) добавляем репозиторий — строка указывает на сам ФАЙЛ-ИНДЕКС packages.adb.
echo "https://git.qomar.pw/omar/shater/releases/download/apk-latest-$(cat /etc/apk/arch)/packages.adb" \
  > /etc/apk/repositories.d/shater.list

# 3) обновляемся и ставим (shaterd подтянется как зависимость).
apk update
apk add luci-app-shater        # -> shater-core -> shaterd
apk add byedpi                 # опционально: ByeDPI desync-egress

Обновление — перечисляйте пакеты явно, голый apk upgrade не запускайте: без аргументов apk пересобирает состояние ВСЕХ установленных пакетов по ВСЕМ подключённым репозиториям и может задеть (в т.ч. откатить) посторонние системные пакеты.

apk update
apk upgrade shaterd shater-core luci-app-shater byedpi
# эквивалент, дополнительно закрепляющий пакеты в world:
# apk add -u shaterd shater-core luci-app-shater byedpi

Документация apk-tools 3 про apk upgrade: «If list of packages is provided, only those packages are upgraded along with needed dependencies». Проверить установленные версии: apk list -I shaterd shater-core luci-app-shater byedpi.

Роллинг или фиксация — это выбор URL в shater.list. apk-latest-<arch> — движущийся указатель: каждый релизный прогон заменяет его ассеты, поэтому «поставил и забыл»: apk update сам видит новую сборку. apk-vX.Y.Z-<arch> — фиксация на конкретной сборке: роутер не получит ничего нового, пока /etc/apk/repositories.d/shater.list не отредактируют руками — на каждом роутере и на каждый релиз. На mini_router сознательно прописан версионированный URL, и ручная правка — его цена. Подробнее — docs-shater/INSTALL.md §5.1.

Версии пакетов CI берёт из git-тега (vX.Y.Z → X.Y.Z-r1, сборка вне тега → X.Y.Z-r<коммитов+1>), поэтому каждая новая сборка действительно видна менеджеру пакетов как новая. Подробности — docs-shater/INSTALL.md §2.1.

Полные инструкции — ручная установка из .apk, фиксация версии (apk-vX.Y.Z-<arch>), совместимость с BananaWRT 25.12-mtk-vendor — в docs-shater/INSTALL.md.

Включение

shater ставится инертным (globals выключены), чтобы установка не рвала связь. Настройте узлы/правила (через панель или uci), затем включите и примените:

uci set shater.globals.enabled=1
uci commit shater
shaterd apply        # apply + вооружить commit-confirm на живом демоне
shaterd confirm      # подтвердить (отменяет авто-откат)

/etc/init.d/shater enable && /etc/init.d/shater start поднимает демона под procd. Кнопка «Открыть панель» в LuCI чеканит одноразовый токен и передаёт браузер в панель (:8088 по умолчанию).


Сборка из исходников

Ship-артефакт — бинарь shaterd со вшитой SPA. Собирается вне дерева SDK скриптом scripts/build-shaterd.sh:

scripts/build-shaterd.sh [VERSION] [--fast]

Что он делает: (1) собирает панель — cd panel && npm ci && npm run build (Vite → panel/dist); (2) копирует panel/dist/* в shater/panel/webroot/, откуда //go:embed вшивает реальную SPA в бинарь; (3) кросс-собирает под {amd64, arm64} с musl-static набором тегов (CGO_ENABLED=0 GOOS=linux), stripped/trimmed; (4) прогоняет UPX --lzma --best (~42 МБ → ~8–11 МБ); (5) стейджит артефакт в openwrt/shaterd/files/ для пакета.

Затем OpenWrt-пакеты из openwrt/ собираются каноническим путём SDK. Детали (набор build-тегов, почему shaterd — prebuilt-пакет, порядок CI) — в docs-shater/INSTALL.md.


Структура репозитория

Репозиторий — это оверлей продукта shater поверх дерева форка движка sing-box-lx (конфликт-фри: движок в апстрим-каталогах, продукт в своих).

Путь Что это
shater/ Go: control-plane, DNS-фильтр, агрегатор статистики, хост движка
panel/ Админ-SPA (Vite + React + TS) и её Go-сервер
openwrt/ Пакеты: shaterd, shater-core, luci-app-shater, byedpi
docs-shater/ Документация продукта (см. таблицу ниже)
scripts/ build-shaterd.sh — сборка ship-артефакта
ci/ Скрипты сборки apk-фида и релизов (SDK, EC-подпись, Gitea API)
.gitea/workflows/ release.yml — CI: сборка пакетов + подписанный apk-фид
SPECS/ Конституция форка движка и спеки (Spec Kit)
docs-lx/ Справочник конфигурации фич движка (lx-config.md, .ru.md)
lx-test/, submodules/ Примеры конфигов движка и submodule AmneziaWG-рантайма
docs/, mkdocs.yml Апстрим документация sing-box (mkdocs) — как есть
adapter/ cmd/ dns/ route/ option/ protocol/ transport/ … Дерево движка sing-box-lx

CI и релизы

CI на Gitea Actions (.gitea/workflows/release.yml) собирает все 4 пакета и публикует подписанные фиды:

  • apk (25.12+) — единственный формат: по релизу на арку, индекс packages.adb подписан EC-ключом (публичный dist/shater-apk.pem; секрет — в Gitea-secret KEY_APK).

Триггеры: push тега vX.Y.Z → версионный релиз apk-vX.Y.Z-<arch>; workflow_dispatch → только роллинг. Роллинг apk-latest-<arch> обновляется на каждом прогоне, включая теговый, и после публикации проверяется через API: в нём обязаны лежать наши три пакета ровно собранной версии и ни одного ассета другой версии. Публикация — через Gitea API (ci/gitea-release.sh). Ключ никогда не перегенерируется — это инвалидировало бы доверие на всех развёрнутых роутерах.


Связь с upstream и движок

shater вкомпилирует форк движка sing-box-lx — тонкий downstream апстрима SagerNet/sing-box, добавляющий набор клиентских фич (XHTTP, AmneziaWG 2.0, MASQUE, расширения наблюдаемости) за build-тегами и живущий ребейзом на каждый upstream-тег, а не merge. Форк разрабатывается по Spec Kit; неизменяемые принципы — в SPECS/CONSTITUTION.md, справочник фич движка — в docs-lx/lx-config.ru.md.

История: v0.1 (движок на xray-core, полностью рабочая и VM-проверенная версия) сохранена на ветке v0.1. v0.2 схлопнула runtime в один форкнутый бинарь.


Документация

Документ О чём
docs-shater/CONTEXT.md Начните здесь — контекст проекта, история v0.1→v0.2, testbed/инфра
docs-shater/INSTALL.md Сборка ship-артефакта и установка apk-фида (роллинг/фиксация)
docs-shater/ARCHITECTURE.md One-binary дизайн, auth-handoff, data/DNS/apply-потоки (диаграммы)
docs-shater/FEATURES.md Полный список фич с тегами MVP/T1/T2
docs-shater/ROADMAP.md Фазовый план
docs-shater/DECISIONS.md Почему sing-box, почему форк, split панели, лицензия
docs-shater/DESIGN.md Визуальная система панели — «Faceplate», токены, компоненты
docs-shater/PORTING.md Порт проверенных кусков из v0.1

Индекс папки — docs-shater/README.md.


Оборудование

Арка aarch64_cortex-a53 покрывает Banana Pi BPI-R3 (MT7986/Filogic 830) и BPI-R4 (MT7988/Filogic 880) — оба таргет OpenWrt mediatek/filogic. x86_64 — QEMU-стенд для тестов.


Лицензия

GPL-3.0 — как у upstream sing-box. Подробности — в docs-shater/DECISIONS.md (D6). Неофициальный форк, не аффилирован с SagerNet.