Skip to content

feat: captive-portal onboarding (bumi/hub-os-config)#1

Closed
reneaaron wants to merge 2 commits into
masterfrom
feat/captive-portal-onboarding
Closed

feat: captive-portal onboarding (bumi/hub-os-config)#1
reneaaron wants to merge 2 commits into
masterfrom
feat/captive-portal-onboarding

Conversation

@reneaaron

Copy link
Copy Markdown
Member

What

Integrates bumi/hub-os-config so a fresh Pi onboards without any Raspberry Pi Imager customization:

flash → boot → join the open albyhub-setup WiFi → captive portal pops up → pick your home WiFi + a few hub options → Pi reboots online → open http://albyhub.local.

This kills the recurring "Imager 2.0 won't customize a custom image, so WiFi/SSH silently don't apply" pain for the common case. (Imager/SSH WiFi setup still works — if WiFi is already configured, the portal never appears.)

Draft on purpose — I want a look at the integration, and there are two real decisions below to settle before merge.

How it's wired

  • CI (build.yml): cross-compiles the hub-os-config arm64 binary from source at a pinned commit (HUBOSCONFIG_COMMIT) and stages it into the overlay before the image build. No prebuilt artifact dependency (upstream has no releases yet). Verified the arm64 build locally (6.3 MB static ELF).
  • albyhub module: ships hub-os-config.service + /etc/hub-os-config/config.toml; installs NetworkManager / dnsmasq-base / rfkill / iw; bakes a WiFi regulatory country (ALBYHUB_WIFI_COUNTRY=US — AP mode silently fails without one); enables the service. If the binary isn't staged (local build), the chroot script skips onboarding gracefully so the build still succeeds.
  • Port :80 gate: bumi assumes the hub runs on :8080; our image runs it on :80, which collides with the setup-mode captive portal (also :80). Added albyhub-wait-online as an ExecStartPre on albyhub.service — the hub doesn't claim :80 until the device is actually online, so on first boot the portal owns :80. Once online the probe returns instantly and the hub starts. The gate self-disables when onboarding isn't installed.

Decisions to settle before merge

  1. Mid-life revert-to-setup still collides on :80. The wait-online gate fixes first boot, but once the hub is online and holding :80, if connectivity is later lost past bumi's 30-min hysteresis, hub-os-config tries to re-enter Setup Mode and re-bind :80 — which the running hub still holds. The clean fix is to let hub-os-config manage albyhub.service (stop on Setup, start on Normal) — which would also remove the need for the wait-online gate entirely. That's a small upstream change. Alternative: run the hub on :8080 (bumi's assumption) and reverse-proxy/redirect — but we lose the clean http://albyhub.local URL. Leaning toward: propose the lifecycle-management change upstream.
  2. Ownership. hub-os-config is single-author with no tagged releases; pinned by commit here. Its Go module path is already github.com/getAlby/hub-os-config, so moving it under getAlby/ and cutting releases looks like the intended path. If we ship it in the official image, we own it.

Not touched

  • bumi's self-updater (hub-os-config update) points at a hardcoded release URL that doesn't exist yet — left disabled (no timer). Separate from our existing autoupdate.sh (which updates the hub binary). Reconcile once releases exist.

Test plan

  • CI green (binary build + image build)
  • Flash, first boot with no WiFi → albyhub-setup AP appears, portal configures WiFi
  • Reboot online → albyhub.local serves the hub on :80, config UI on :8090
  • Pre-configured WiFi → portal never appears, boots straight online

Flash → boot → join the "albyhub-setup" WiFi → pick your network in a
captive portal → done. Removes the Raspberry Pi Imager customization
dependency (the recurring "Imager 2.0 won't customize custom images"
pain) for first-time WiFi setup.

- build.yml: cross-compile the hub-os-config arm64 binary from source at
  a pinned commit and stage it into the overlay before the image build.
- albyhub module: ship hub-os-config.service + config.toml, install NM /
  dnsmasq-base / rfkill / iw, bake a WiFi regulatory country (required for
  AP mode), enable the service (gracefully skipped if the binary isn't
  staged, e.g. local builds).
- albyhub.service: gate startup on connectivity (albyhub-wait-online) so
  the hub doesn't claim :80 while the setup portal needs it on first boot.
- README: rewrite onboarding around the captive-portal flow.
The CustomPiOS base module runs after the albyhub module and overwrites
/etc/hostname with BASE_OVERRIDE_HOSTNAME, which defaults to the lowercased
DIST_NAME (hubos). That broke avahi's albyhub.local advertisement. Pin the
hostname explicitly at the distro level.
@reneaaron

Copy link
Copy Markdown
Member Author

Closing in favor of #2 (WiFi onboarding via balena wifi-connect). Both approaches were validated end-to-end on a Raspberry Pi Zero 2 W, but #2 is the cleaner path to the same result: a pinned, checksum-verified upstream release instead of a build-from-source binary (no CI Go step), a smaller diff that leaves albyhub.service untouched, and no bespoke service to maintain. bumi's Advanced-section env editing is the only feature dropped, and those keys are all reachable in Alby Hub's own onboarding UI. Thanks @bumi — this was a useful reference implementation.

@reneaaron reneaaron closed this Jul 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant