Snapshot of the Pi 'wan' Claude memory: wayback van-router build notes, ZT DNS, HA VM, LAN port, and the Pi port memory updated for the 2026-07-06 USB hub move (AP live on the Pi) and the cockpit-bridge fd-limit fix. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
52 lines
12 KiB
Markdown
52 lines
12 KiB
Markdown
---
|
||
name: wayback-campervan-ap
|
||
description: "wayback campervan router/AP — hand-rolled hostapd (RTL8852BU, 80MHz/HE) + dnsmasq + nftables; NM owns WAN; eventual Starlink+4G multi-WAN"
|
||
metadata:
|
||
node_type: memory
|
||
type: project
|
||
originSessionId: 0f399db0-9a91-4f55-b102-70875f05be7a
|
||
---
|
||
|
||
Goal: turn wayback (Asus UX391U laptop, Ubuntu 24.04) into a campervan hub/router/AP. Eventual WAN = Starlink (ethernet) + 4G/5G modem with failover; LAN = wifi AP for clients. See [[wayback-fan-max-ec-latch]].
|
||
|
||
**SOURCE OF TRUTH: `~/vanlink/` on wayback** (2026-06-28). Consolidated working dir, Claude Code now installed ON wayback so future van-router dev happens there. Contains README.md (full architecture + gotchas + ops), `deploy.sh` (copies files→system locations, idempotent), and copies of every config/script grouped: `ap/` `failover/` `dns/` `cockpit/vanrouter/`. Edit there, `sudo ./deploy.sh`. This memory is the why/history; the README is the operational reference.
|
||
|
||
**Architecture (2026-06-28): hand-rolled hostapd + dnsmasq + nftables, NM owns WAN.** Decided against NM-hotspot (capped at HT20/20MHz) and against RaspAP (RPi-OS/dhcpcd tool; bare-metal installer would enable dhcpcd → fight NM, and disable systemd-resolved → unsafe on this x86/Ubuntu/NM box).
|
||
|
||
Radios:
|
||
- **phy1 = Realtek RTL8852BU** (`0bda:b832`, driver `rtw89_8852bu`, iface `wlxc83a35a4ee55`) = AP radio. Confirmed empirically: AP mode + **VHT80 + HE (WiFi-6)** at 80MHz works.
|
||
- **phy0 = Intel 8265** (`wlp1s0`) = mgmt/uplink, assoc home SSID `Wapana` (192.168.10.27).
|
||
- **2.4GHz AP added 2026-07-06 (commit `e652b0f`): Linksys WUSB6300v2** (`13b1:0045`, RTL8822BU, driver `rtw88_8822bu`, iface `wlxd8ec5e2faa8c`). Same SSID/PSK, ch6 HT20, bridged into br0. **Own hostapd instance** (`hostapd-2g.service` + `van-ap-watchdog-2g`) so one radio's USB wedge can't kill the other; `van-ap-watchdog` now takes conf+unit args. `/etc/modprobe.d/rtw88.conf`: `disable_lps_deep=Y` (PS gotcha analog) + `switch_usb_mode=N` (blocks driver's USB2→3 self-upgrade only — the dongle sits in a USB3 port and still enumerates SuperSpeed; move to a USB2 port if 2.4GHz range/interference disappoints). Shares Bus 002 with an RTL8153 — watch for the hub-contention signature. Cockpit vanrouter plugin shows both bands with per-band Restart (`const APS` list in vanrouter.js, commit `db16964`).
|
||
|
||
Management/recovery paths (3): ethernet `enx00e04c3600ab` **192.168.10.235** (USB RTL8152; now PRIMARY default route metric100 — previews Starlink-on-eth), wifi `wlp1s0` .27 (metric600), ZeroTier `ztuga7c2kh` 192.168.196.22.
|
||
|
||
Deployed config (all enabled at boot):
|
||
- **hostapd** `/etc/hostapd/hostapd.conf`: SSID `VanLink`, ch149 VHT80/HE, WPA2-PSK (user changed it 2026-06-28; valid = 8-63 chars), `country_code=CA`. `/etc/default/hostapd` DAEMON_CONF set. (was masked during testing — now unmasked/enabled.)
|
||
- **rtw89 power-save MUST be disabled** for AP stability: `/etc/modprobe.d/rtw89.conf` = `options rtw89_core disable_ps_mode=Y`. ROOT CAUSE of "SSID disappears after a few min": when the last client idles out (hostapd 5-min inactivity timer), rtw89 low-power mode sleeps the radio and STOPS beaconing until restart. To apply live you must unload the WHOLE stack so rtw89_core reloads (`modprobe -r rtw89_8852bu rtw89_usb rtw89_8852b rtw89_8852b_common rtw89_core` then `modprobe rtw89_8852bu`; -r of just the leaf does NOT cascade to core). Verify `cat /sys/module/rtw89_core/parameters/disable_ps_mode` = Y.
|
||
- GOTCHA: Ubuntu's hostapd does NOT support `noscan` (rejects "unknown configuration item 'noscan'" → service fails). Don't add it. Restarts occasionally log stuck at HT_SCAN but still beacon — trust `iw dev <ap> info` (ssid+channel+width present = beaconing), not the journal ENABLED line.
|
||
- AP iface **unmanaged by NM** via `/etc/NetworkManager/conf.d/van-ap-unmanaged.conf`; static IP 10.42.0.1/24 via **systemd-networkd** `/etc/systemd/network/10-van-ap.network` (ConfigureWithoutCarrier=yes).
|
||
- **dnsmasq** dedicated instance (binary from dnsmasq-base, NOT the distro service): config `/etc/van-ap/dnsmasq.conf` (interface=AP, bind-dynamic → no clash with systemd-resolved on 127.0.0.53), unit `van-ap-dnsmasq.service`. DHCP 10.42.0.10-254/12h, gw+dns 10.42.0.1.
|
||
- **nftables** `/etc/nftables.conf`: own table `van_router_nat` (create+delete idiom, no global flush) masquerading `10.42.0.0/24 oifname != AP` → covers any WAN. `ip_forward=1` persisted in `/etc/sysctl.d/99-van-router.conf`.
|
||
- **regdomain.service** (oneshot `iw reg set CA`, Before=NetworkManager) — needed: country 00 only allows 5GHz ch36/48; CA unlocks ch149-161 @30dBm no-DFS.
|
||
- Cockpit on :9090 still installed (system/WAN monitoring; canNOT edit wifi — cockpit-networkmanager has no wifi UI).
|
||
|
||
To change AP: edit `/etc/hostapd/hostapd.conf` + `systemctl restart hostapd`. DHCP: `/etc/van-ap/dnsmasq.conf` + restart `van-ap-dnsmasq`.
|
||
|
||
Reboot-persistence VERIFIED (2026-06-28): after `systemctl reboot` all 4 services auto-started, regdomain CA applied, disable_ps_mode=Y from boot, VanLink beaconing 80MHz, ethernet .235 recovery path back. (Lesson: avoid hot-reloading rtw89_8852bu; reboot to apply module options.)
|
||
|
||
**RESOLVED — load-hang was USB hub contention.** Symptom: Android Speedtest (good numbers, then dropped), SSID invisible while hostapd still "active". Fatal dmesg signature = `c2h reg timeout` + `Polling beacon packet empty fail` (chip↔host USB comms hang → beacon TX stops); recovers via `systemctl restart hostapd`. Root cause: the dongle was on a shared USB-2 hub (`1-1.4`) with the r8152 ethernet + a camera; under load the shared bus starved chip comms. FIX (2026-06-28): moved Realtek to its own root USB-C port (`1-3`). After move: 3 Speedtests completed, ZERO c2h/beacon-fail errors, 2 clients at 80MHz HE (WiFi-6) >1Gbit/s PHY, tx-failed ~0. The lone post-move `timed out to flush queues` is BENIGN (doesn't drop AP); the c2h+beacon-fail combo is the fatal one.
|
||
Caveats: (1) the 8852BU is **USB-2.0-native** — enumerates 480M even on a USB-C/USB-3 port (USB3 can't speed a USB2 device); ~280Mbps real USB ceiling = fine for Starlink/4G van WAN but that's the aggregate cap. (2) In the van build keep the AP dongle and the WAN ethernet on **separate USB controllers** — don't re-share a hub or the c2h hang returns. (3) Interface name is MAC-based (wlxc83a35a4ee55), survives port moves; all configs reference the name. Unused fallback if it ever regresses: pivot AP to Intel 8265 (PCIe, WiFi5/ac 80MHz).
|
||
Note: iw sometimes reports control channel as 153 (not the configured 149) within the same 149-161/80MHz block — cosmetic, clients connect fine.
|
||
|
||
Pending / next steps:
|
||
- **Idle-survival still being confirmed**: original symptom was beacon dropping ~5min after last client idled out (hostapd 5-min inactivity deauth). Watching across an idle cycle post-fix. Strongest real test = connect a device, use it, let it idle past 5 min, confirm SSID stays visible.
|
||
- **Verify**: client association → DHCP + internet (basic assoc seen; full internet path not yet end-to-end tested).
|
||
- **Multi-WAN failover BUILT + TESTED (2026-06-28).** Daemon `/usr/local/sbin/van-failover` (Python), config `/etc/van-failover/config.json`, unit `van-failover.service` (Restart=always, enabled). 3 WANs, priority = **WiFi(wlp1s0)=100 → Starlink/eth(enxd8ec5eeb3512)=200 → 4G(Koodo gsm)=300** (user chose WiFi-first to save Starlink; 4G auto last-resort). How it works: probes each WAN's real internet every 4s via HTTP-204 check (catches "link up no internet" + captive portals), demotes a failed WAN by raising its NM route-metric (+10000) so kernel routes via next-best healthy WAN; auto fail-back with hysteresis (3 fail→down, 2 ok→up). Writes `/run/van-failover/state.json` (0644) → Cockpit "WAN Failover" card reads it. NAT (nftables oifname != AP) follows automatically; nothing else needed. Tested with an nft block on wlp1s0:80 → failed over to Starlink in ~30s, failed back in ~20s.
|
||
- **GOTCHA: per-WAN probing needs `curl --interface if!<dev>`** (explicit SO_BINDTODEVICE) — plain `--interface <name>` binds source IP but still routes via the default WAN, so all probes test the same path. rp_filter is already 2 (loose) which is required. Probe all (WAN×url) pairs CONCURRENTLY else a dead WAN takes N×timeout serially (was why first failover test looked broken). `ping -I` to test eth is unreliable here (ICMP lossy on the gateway) — use the curl-204 check.
|
||
- Absent WANs (modem unplugged → Koodo has no device): daemon skips probing, just sets the profile's base metric so it lands right when it connects. ModemManager active + `Koodo` gsm profile autoconnect=yes already present; lights up when USB modem arrives.
|
||
- **CRITICAL fix (r8152 USB-ethernet flapping)**: the daemon must change route-metrics via `ip route` (del/add default at new metric), NOT `nmcli device reapply` — **reapply RESETS the r8152 carrier** (verified: reapply=2 carrier events, ip-route=0), causing ~10s ping drops + a feedback loop (transient probe fail → reapply → carrier reset → more fails). Daemon keeps the NM profile metric in sync (`nmcli con mod`, no reapply) so NM re-assertions don't drift. Also: **disable EEE** on the eth adapter or its idle (backup, no-traffic) link parks and probes fail — done via NM dispatcher `/etc/NetworkManager/dispatcher.d/50-disable-eee` (runs `ethtool --set-eee <if> eee off` on up; ethtool setting doesn't persist otherwise). Also: **arp_ignore=1 / arp_announce=2** (`/etc/sysctl.d/99-van-arp.conf`) to stop ARP flux when two WANs share a subnet (a home-LAN test artifact; in the van Starlink+wifi are on different subnets). After all three: eth stable, failover/failback clean, 0 carrier resets even when eth becomes active.
|
||
- To tune: edit config.json (probe_interval/timeout, thresholds, probe_urls, wans list) + `systemctl restart van-failover`. WAN list keys eth/wifi by `device`, cellular by `connection` name.
|
||
- **Cockpit plugin BUILT (basic v1, 2026-06-28)**: `/usr/share/cockpit/vanrouter/` (manifest.json menu "Van Router" + index.html + vanrouter.css + vanrouter.js). Pure static + cockpit.js: read-only status via `cockpit.spawn` as logged-in user (iw info/station dump, nmcli device status, `ip -j route/addr`, systemctl is-active); mutating actions use `{superuser:"require"}` (polkit). Features: AP panel (hostapd state, SSID/ch/width, client list) + Restart AP; WAN panel (per NM ethernet/wifi device: state/IP/route-metric, ★=active default) with Up/Down (`nmcli device connect/disconnect`) and Prefer (sets chosen route-metric=50, others=200, `nmcli device reapply`). AP iface name hardcoded as const AP. Confirmed discovered via `cockpit-bridge --packages`. To see it: reload Cockpit browser / re-login; enable Administrative access for the buttons. **Now also has a "WAN Failover" card** reading `/run/van-failover/state.json` (active egress + per-WAN priority/device/up-down/metric). Source only on host + session scratchpad (not in a repo).
|
||
- **Evaluated & REJECTED `apsetup-cockpit`** (github cyberorg/apsetup-cockpit, 2026-06-28): NM-hotspot-based AP tool (uses an NM dispatcher `90apnmdispatcher` + its own dnsmasq + NAT; needs `DNSStubListener=no`). Doesn't fit: (1) NM-created AP on rtw89 = HT20/20MHz, throws away our 80MHz/HE; (2) it owns the AP (own NM conn/dnsmasq/NAT) → collides with our hand-rolled hostapd+van-ap-dnsmasq+nftables + AP-iface-unmanaged; (3) disables resolved stub host-wide (we kept resolved via bind-dynamic). If a web AP-config form is wanted, ADD an SSID/channel/PSK card to our own vanrouter plugin editing /etc/hostapd/hostapd.conf + restart hostapd — keeps 80MHz, no conflict.
|
||
- **Mgmt ethernet changed (2026-06-28)**: now `enxd8ec5eeb3512` @ 192.168.10.251 (metric100, active default); old `enx00e04c3600ab` @ .235 now `unavailable` (swapped/unplugged during USB reorg). Cockpit now at https://192.168.10.251:9090. AP NAT (oifname != AP) follows it automatically. Stale NM profile for the .235 adapter still present (shows "unavailable" in plugin).
|