Files
claude-memory/wayback-campervan-ap.md
Andreas WredeandClaude Fable 5 a304b6d197 memory: initial import (transferred from wayback) + hub-move and cockpit-EMFILE updates
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>
2026-07-06 18:36:43 -04:00

12 KiB
Raw Permalink Blame History

name, description, metadata
name description metadata
wayback-campervan-ap wayback campervan router/AP — hand-rolled hostapd (RTL8852BU, 80MHz/HE) + dnsmasq + nftables; NM owns WAN; eventual Starlink+4G multi-WAN
node_type type originSessionId
memory project 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 reapplyreapply 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).