- Go 69.4%
- Shell 21.7%
- JavaScript 8.1%
- Makefile 0.8%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
All checks were successful
/ build (push) Successful in 30m20s
Read-only sampler na routeru: peak-6s klouzavé okno per-WAN wire TX/RX, CAKE drops, podíl TCP retransmisí a MPTCP reinjecty za okno uživatelova testu. Verdikt rozliší: bond dovezl součet shaperů (úzké hrdlo je za VPS / na test serveru) vs reálná ztráta na WAN segmentu vs nenaplněný bond. Vzešlo z honu 2026-07-17 na 'upload cap 60' — drát nesl 115 Mbit, appka 62, a přesně tahle triáž se dělala ručně. Negenerui vlastní zátěž. Co-Authored-By: Claude Fable 5 <[email protected]> |
||
| .claude | ||
| .forgejo/workflows | ||
| cmd/gobond | ||
| deploy | ||
| docs | ||
| internal | ||
| lab | ||
| openwrt/package | ||
| test-evidence | ||
| .gitattributes | ||
| .gitignore | ||
| CLAUDE.md | ||
| DEVELOPMENT.md | ||
| go.mod | ||
| go.sum | ||
| OMR-shrnuti-a-navrh-Go-nadstavby.md | ||
| README.md | ||
gobond — lean Go multi-WAN bonding (an OpenMPTCProuter alternative)
One encrypted L3 tunnel across multiple WAN links, userspace UDP bonding with a custom scheduler, and a
VPS edge that NATs traffic in and out of the tunnel. A single Go binary, two roles (router / vps), packaged
for stock OpenWrt (no fork). A lean, robust alternative to OpenMPTCProuter (OMR).
What it does
- Aggregation of multiple WANs into higher throughput + failover on link loss (download and upload, TCP and UDP).
- One public egress IP on the VPS (hides the real WAN IPs).
- Inbound hosting — a server behind the router (TS3, game servers) reachable from the internet via the VPS (DNAT into the tunnel).
- Dual-stack IPv4 + IPv6 end-to-end.
- Encryption: Noise IK + ChaCha20-Poly1305 (forward secrecy, rekey, anti-replay) —
wireguard-gocrypto+TUN as a library, with a custom datagram bonding scheduler (pin-only multi-flow + optional FEC on lossy links). - TCP auto-bonds via kernel-MPTCP dual-PEP (a single flow aggregates all WANs + seamless failover); UDP / ICMP / P2P / inbound stay on the L3 tunnel — with no configuration. Path MTU auto-tunes (PLPMTUD).
- QoS / bufferbloat: per-WAN CAKE (sized from each WAN) + CAKE on
gob0+ BBR — low latency under load with app-priority, and switchable for an external qosmate/SQM. Plus adaptive FEC and capacity auto-rate.
Status
Working, verified on real hardware over the internet (OpenWrt router + Debian VPS, real WANs): encrypted tunnel, multipath bonding, ~ms WAN-down failover, inbound hosting, dual-stack IPv6 (NAT66 + auto VRRP-gateway fix, client→v6-internet HW-verified), per-WAN CAKE QoS + BBR (low bufferbloat). Single binary, self-programming VPS edge, OpenWrt package (netifd proto + procd + UCI + LuCI). Performance tuning on a small VPS is ongoing — measure real throughput, don't treat metrics as final.
Install
You need a VPS (Debian/Ubuntu, public IPv4; IPv6 is optional and works either way — see IPv6) and an OpenWrt router. Both sides are a single command.
1) VPS — one command, as root
Downloads the prebuilt binary (or builds from source as a fallback), installs a hardened systemd service
(CAP_NET_ADMIN/NET_RAW only, NoNewPrivileges, ProtectSystem=strict), generates the keypair, and prints the
values to paste into the router:
curl -fsSL https://git.xn--la-mia8p.eu/ladab/gobond/raw/branch/main/deploy/vps-edge/bootstrap.sh | sh
Re-running is safe (it keeps the keypair; ROTATE_KEYS=1 regenerates it, which means you must re-pair the router).
VPS-internal ports live in the reserved 65000–65535 range (underlay :65535, admin SSH :65022), so every port
below 65000 is free to forward to a LAN host. The installer also frees port 22 by moving SSH to :65022 (opt out
with KEEP_SSH_22=1) and sets a minimal host firewall.
The optional legacy TCP PEP (
tcp_pep, off by default — superseded by the auto-on MPTCP dual-PEP) also listens in the reserved range (:65333), so it never occupies a forwardable port. Like the underlay and the MPTCP PEP it binds all interfaces; the minimal host firewall the installer sets covers it.
2) Router (OpenWrt) — install, then configure in LuCI
Fetch the installer and run it with no arguments — it installs both packages (gobond + luci-app-gobond,
from the feed or the release) and stops:
wget https://git.xn--la-mia8p.eu/ladab/gobond/raw/branch/main/deploy/router/openwrt-install.sh
sh openwrt-install.sh
Then open LuCI → Network → gobond → Settings and fill in: the VPS server, the router private key +
VPS public key the VPS installer printed, and your WANs (each with optional Down/Up, or a Measure
button). Save & Apply — the tunnel comes up and reconfigures itself. The firewall zone, lan → tunnel
forwarding and default route are created automatically by the package (uci-defaults + an ifup hotplug).
Prefer the command line? Run it with the values inline and it configures the interface for you too:
SERVER=<vps_ip> PEER_PUBLIC_KEY=<VPS public key> PRIVATE_KEY=<Router private key> \ WANS="wan:150 wwan0:30" sh openwrt-install.sh
WANS= space-separated<openwrt_iface>:<down_mbit>[:<up_mbit>](seeds the scheduler weights).
That's it — TCP auto-bonds via MPTCP, UDP/ICMP/P2P stay on L3, the MTU auto-tunes, and WAN-down failover is ~ms.
To force plain L3 (no MPTCP PEP): set Scheduler-adjacent option mptcp_pep_disable (or option mptcp_pep_disable '1').
Updating
Ship a new version by tagging — CI builds and publishes the release:
git tag v0.3.0 && git push origin v0.3.0 # builds the binaries + .apk (version 0.3.0) and publishes a release
Then one command per machine (keys and config are preserved):
- VPS — re-run the same one-liner (downloads the new binary, atomically swaps it, restarts the service):
curl -fsSL https://git.xn--la-mia8p.eu/ladab/gobond/raw/branch/main/deploy/vps-edge/bootstrap.sh | sh - Router — the gobond binary lives inside the
.apk, so a package upgrade is the binary upgrade, and the package re-ups the interface by itself. Either LuCI → System → Software → Updates (the new version shows because the.apkcarries the tag version) → upgradegobond; or, over SSH:sh openwrt-install.sh # no variables = UPDATE mode: apk upgrade gobond + reactivate, keys untouched
Usage
# router: tunnel status (established, paths, weights, RTT, loss)
gobond -config /var/run/gobond-wanbond.json -status
# measure real speed (through OpenWrt), per-WAN or the bonded aggregate
gobond-speedtest wan # one link only (source-bound)
gobond-speedtest # bonded tunnel (aggregate)
gobond-speedtest --set wan # measure + write the real rate into the config (seeds the scheduler weights)
# "my speed test shows less than the WAN sum — is it the bond?" — start this, run your speed test
# from a LAN device while it samples, read the verdict (bond fine / lossy WAN / bond underfilled)
gobond-diag 30
# VPS: edge status
gobond -config /etc/gobond/vps.json -status
systemctl status gobond-vps
Port forwards are managed from OpenWrt (firewall redirects) and propagate to the VPS automatically. Per-WAN speeds are either seeded manually or detected by auto-rate.
QoS / SQM (bufferbloat)
gobond shapes in two places, because traffic takes two paths: TCP auto-bonds over kernel-MPTCP subflows
that ride the raw WAN interfaces (not the tunnel), while UDP / ICMP / P2P ride the decrypted L3 tunnel gob0.
Both layers are on by default and are independently switchable in LuCI → Network → gobond → Settings.
- Smart Queue (per-WAN CAKE) — the main bufferbloat fix. Sized from each WAN's Down/Up, it attaches CAKE to
every physical WAN: ingress (download) via an IFB + egress (upload) with
ack-filter,diffserv4, per-host fairness and the correct PPPoE/cable overhead. This is where bonded TCP's bufferbloat actually lives, so it is what holds latency down under load and lets a bulk download yield to streaming / games / VoIP. HW-measured: loaded latency 62/304 ms → 29/36 ms (down/up). Toggle: Smart Queue (QoS) (needs per-WAN Down/Up set); switch it off to run your own SQM/qosmate on the WAN devices instead — it tears down immediately on Save & Apply (no reconnect needed). - Queue management (
gob0) — CAKE on the decrypted tunnel, which carries the UDP/ICMP/P2P that does not ride the MPTCP subflows. Toggle: set it to off to handgob0to an external qosmate / SQM — point it at thegob0interface, bandwidth = the bonded aggregate (a little under the real total, which is variable as WANs come and go, so be conservative). off leavesgob0on the default qdisc so two qdiscs don't collide.
Both ends also run BBR + fq (the VPS is the sender for your download), pacing to the bottleneck instead of
filling the buffer; the per-WAN CAKE owns the actual rate, BBR just keeps the sender from over-driving the
asymmetric link.
IPv6
Dual-stack is automatic — the tunnel carries IPv6 natively and the VPS gives your LAN clients IPv6 with no configuration, on either kind of provider:
- Routed prefix — routed straight down the tunnel to the LAN (no NAT).
- Single on-link /64 (most cheap VPSes, e.g. ZONER) — NAT66 out the VPS's own global IPv6, exactly like
the IPv4 egress (one public exit). gobond also auto-handles the common provider quirk where the IPv6 gateway is
a VRRP virtual router that ignores Neighbor Solicitation: the VPS edge pins the gateway's VRRP MAC as a
static neighbour (derived from the working v4 VRRP gateway) and re-pins it if the uplink flaps — so IPv6 works
even on a box where a bare
ping6fails. No-op on a normal network where the gateway answers NDP.
Outbound (clients → IPv6 internet) is done and HW-verified. Inbound IPv6 hosting (port-forward DNAT to a backend) is implemented end to end — the VPS edge installs a v6 DNAT + NAT66 branch and the router propagates the gob0 IPv6 backend with each forward — but is not yet HW-verified (the v4 inbound path is).
Developing
Building from source, the test/lab harness, releasing, and the OpenWrt package feed are covered in
DEVELOPMENT.md. The architecture, the locked decisions (D1–D17), the phase roadmap, and the
synthesis-vs-verified ledger live in docs/.