Skip to content

Repository files navigation

XUI BW Guard v8

A safe, update-resistant Linux traffic-control sidecar for 3x-ui / Xray, with an adapter architecture for Marzban and other Xray panels.

BW Guard applies strict per-client/IP/inbound bandwidth queues without patching the panel binary, database, frontend, or generated Xray configuration. That is the central design decision: panel updates can change UI/backend internals without overwriting the shaper.

v8 is a ground-up Go refactor of the original Bash implementation. It defaults to dry-run and refuses root-qdisc takeover until an administrator explicitly enables it.

What it does

  • Auto-discovers Xray inbounds and their ports.
  • First-class 3x-ui adapter using the panel API when configured, with runtime Xray fallback.
  • Per-client IP attribution using aggregate 3x-ui data when available, with a documented online-client/IP API fallback.
  • Generic Xray mode, plus an experimental Marzban adapter.
  • Per-inbound, per-client and per-IP policies with precedence and inheritance.
  • Independent download/upload rates, optional HTB peak ceilings/token-bucket sizing, priorities, FQ-CoDel leaves and optional strict quantum.
  • Optional hard max_connections admission control using a private nftables table.
  • IPv4 + IPv6 traffic filters.
  • Fast flow scans with slower cached panel/config discovery to keep API load low.
  • Automatic system-listener protection and Xray outbound discovery. Queue filters are scoped to client IP and the selected inbound port, so panel/SSH/outbound traffic does not enter client classes.
  • Automatic physical link-rate detection from sysfs/ethtool for safe HTB parent sizing, with an explicit override when needed.
  • Ownership-aware cleanup; does not flush nftables/firewall tables or blindly remove foreign tc objects.
  • Embedded responsive web UI + JSON HTTP API + Doctor diagnostics.
  • Safe migration helper for the legacy /etc/3xui-bw-guard/3xui-bw-guard.conf format.
  • Static Go binary; no Python/Node runtime required.

Architecture

3x-ui API ───────┐
Marzban API ─────┼─> discovery adapters ─┐
Xray config ─────┘                       │
ss/ip listeners ─────────────────────────┼─> reconciler ─> policy resolver
                                         │                    │
                                         │                    ├─> tc/HTB + FQ-CoDel
                                         │                    └─> nft connection guard
                                         └─> status/API/UI

The data plane is Linux-native. BW Guard does not modify 3x-ui files, React assets, SQLite/PostgreSQL state, or the Xray configuration generated by a panel.

Requirements

  • Linux with iproute2 (ip, tc, ss)
  • Kernel support for IFB, HTB, FQ-CoDel, flower classification and mirred actions
  • nftables for hard connection caps (speed shaping works without it)
  • kmod/modprobe where the networking classifiers are modules
  • ethtool for NIC-speed fallback detection and offload control (sysfs is tried first for auto link rates)

Installer support is included for apt, dnf/yum, pacman and zypper systems, plus systemd and OpenRC service layouts.

Build and install

git clone https://github.com/nimix3/XUI-Bandwidth-Guard
cd xui-bw-guard
make test vet build
sudo ./scripts/install.sh ./bin/xui-bw-guard

After release assets are published, the convenience installer is:

curl -fsSL https://raw.githubusercontent.com/nimix3/XUI-Bandwidth-Guard/main/scripts/install-release.sh | sudo bash

The installer starts the daemon in dry-run. Open the UI safely through SSH:

ssh -L 6178:127.0.0.1:6178 root@your-server

Then browse to http://127.0.0.1:6178.

Safe activation

Run:

sudo xui-bw-guard doctor
sudo tc qdisc show dev YOUR_INTERFACE root

Review the discovered inbounds, protected ports and current root qdisc in the UI. Only then:

  1. Set engine.takeover_qdisc=true if this host's root qdisc may safely be replaced by BW Guard.
  2. Keep dry_run=true, save and run one reconcile/Doctor pass.
  3. Set engine.dry_run=false to enforce.

If you use another QoS agent, hosting panel queue system, CNI, custom tc, DDoS appliance agent or provider qdisc on the same root interface, do not enable takeover until you have designed coexistence.

3x-ui integration

BW Guard's recommended 3x-ui integration is companion mode, not a source-code patch. Configure the panel URL and either a panel API token or a username + password file. Example:

sudo install -m 0600 /dev/null /etc/xui-bw-guard/3xui.password
sudo sh -c 'printf "%s" "YOUR_PASSWORD" > /etc/xui-bw-guard/3xui.password'

Then set in config.json:

"panel": {
  "base_url": "https://127.0.0.1:2053/your-web-base-path",
  "username": "admin",
  "password_file": "/etc/xui-bw-guard/3xui.password",
  "timeout": "5s"
}

You can also use api_token_file and omit password credentials. Secrets are read from files and are not stored in the BW Guard JSON config.

See docs/3XUI_INTEGRATION.md. Upgrading from the original Bash release is covered in docs/MIGRATION_V7.md.

Queue policy examples

Global default:

"default": {
  "download": "4mbit",
  "upload": "4mbit",
  "burst_download": "8mbit",
  "burst_upload": "8mbit",
  "burst_time_ms": 120,
  "priority": 4,
  "max_connections": 30
}

Client override; omitted fields inherit the less-specific policy:

{
  "name": "vip-alice",
  "match": {"client": "alice@example.com"},
  "limits": {
    "download": "30mbit",
    "upload": "15mbit",
    "priority": 2,
    "max_connections": 80
  }
}

Explicit max_connections: 0 disables the connection ceiling for that profile. enabled:false exempts a matching client/IP/inbound from shaping.

Policy specificity is additive: IP +100, client +80, inbound +40, global 0. Matching policies layer from broader to more specific, so a rule matching both client and inbound overrides a client-only or inbound-only rule; equal-specificity ties use configuration order. Omitted fields inherit from the broader policy.

Inbound selection

  • auto: manage all discovered enabled Xray inbounds except exclude_inbounds.
  • denylist: same behavior, intended for explicit operator-managed exclusions.
  • allowlist: only identifiers listed in include_inbounds are managed.

Identifiers may be an inbound ID, tag, remark or port string.

Commands

xui-bw-guard run                 daemon + web UI
xui-bw-guard doctor              prerequisites/safety checks
xui-bw-guard status              read daemon status (no shaping side effects)
xui-bw-guard reconcile           request immediate reconcile
xui-bw-guard cleanup             remove only BW Guard-owned kernel objects
xui-bw-guard configtest          validate config
xui-bw-guard migrate-legacy      convert the old Bash config to safe v8 config
xui-bw-guard version

Set BWGUARD_DEBUG=1 on the daemon to log the kernel commands generated by reconciliation.

Updating

Because BW Guard is a sidecar, updating 3x-ui does not overwrite BW Guard. After a panel update, run doctor and inspect the UI. If a 3x-ui API endpoint changes, local Xray discovery remains the fallback for inbound/outbound discovery.

BW Guard itself can be replaced atomically:

sudo systemctl stop xui-bw-guard
sudo xui-bw-guard cleanup
sudo install -m 0755 ./xui-bw-guard /usr/local/sbin/xui-bw-guard
sudo systemctl start xui-bw-guard

Important limits

Traffic classification is currently based on client IP + inbound port. This is robust and panel-independent, but if multiple Xray identities share the same public NAT IP on the same inbound, the Linux network layer cannot tell their encrypted streams apart. They will share the IP-level policy identity. True same-IP/per-Xray-user isolation requires a deeper Xray dataplane mark/hook; see the roadmap.

Connection caps reject new TCP connections after the observed IP exceeds its threshold. Existing TCP sessions remain alive; UDP is rate-shaped but is not rejected by the connection guard. Because admission is reconciled from observed sockets, a burst of new connections can briefly overshoot the configured number between scans; kernel-native exact connlimit is a planned backend improvement.

For the tightest hard rate ceiling, leave burst_download / burst_upload empty (or equal to the base rate); a higher burst value is an HTB peak ceiling and can intentionally allow borrowing above the base rate. Full MikroTik-style average-window burst/threshold semantics are listed on the roadmap.

disable_offloads=true can improve strictness on some NIC/virtual NIC combinations but costs CPU and may reduce maximum throughput. Leave it off unless measurements show GRO/GSO/TSO is affecting queue accuracy. BW Guard records the original GRO/GSO/TSO state and restores it during ownership-aware cleanup/service stop.

Development

make fmt
make test
make vet
make build

See docs/ARCHITECTURE.md, docs/SECURITY.md, docs/TROUBLESHOOTING.md, and docs/ROADMAP.md.

About

No description, website, or topics provided.

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages