8-screen first-boot installer spec extending Robert's 4-screen wireframe with the YunoHost-style post-install pattern (domain, SSL, diagnostic, confirm). Covers: - Entry point via https://proksi.local with local CA cert install - Screens S1-S8, each mapped to archinstall config fields or side effects (SSL cert issuance, DNS delegation, diagnostic gates) - Data model mapping wizard fields to user_configuration.json + user_credentials.json - Locked tech picks with rejected alternatives: Caddy (reverse proxy), Authentik (SSO), NS delegation (managed gateway DNS), local CA (HTTPS on proksi.local) - Open questions for Robert: Backend on/off meaning, local CA vs Tailscale ACME, UI framework choice, language list, S2 auto-setup branch behavior Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
12 KiB
Installer Wizard Flow
End-to-end spec for the Homebase first-boot installer. Extends Robert's wireframes in installer-wireframes.md with the post-install pattern proven by YunoHost (see competitors.md). Concrete tech picks are locked in at the bottom so Robert has unambiguous targets for the next coding session.
Status: Draft spec 2026-04-13. Not implemented yet. Open questions for Robert at the end.
Goals
- Your dad can install this. Boot USB, answer plain-language questions, get a working server. No terminal required on the happy path.
- HTTPS from boot #1. No plaintext admin UI at any stage — unlike Umbrel (#546) and CasaOS. Even the pre-install wizard uses HTTPS via a local CA.
- No post-install CLI required. By screen S8 (confirm), the user has a reachable domain, valid TLS, admin credentials, and the base OS installing. Everything else is reachable from the web UI.
Entry point
- User flashes ISO to USB (Etcher /
dd/ Rufus). - Boots target machine from USB into a headless live environment.
- Live image auto-starts:
webinstallerFlask app on port 443 with TLS- mDNS advertising
proksi.local - Local CA cert generated on first boot, served at
http://proksi.local/ca.crt(plaintext port 80 serves only the CA cert download and a redirect to HTTPS — nothing else)
- User opens
https://proksi.localon any device on the same LAN. - First screen before S1: browser warning page with a one-click "Download Homebase CA" button and OS-specific install instructions (macOS Keychain, Windows cert store, iOS profile, Android). After install, user clicks "Continue" and proceeds to S1 with no further warnings.
Why not self-signed (YunoHost model)? Users learn to click through warnings, which kills trust. A single one-time CA install gives clean green padlocks for every Homebase service after.
Wizard screens
Each screen is one Flask route under /install/<step>. The Flask settings dict in webinstaller/app.py accumulates answers and is flushed to user_configuration.json + credentials.json at S8.
S1 — Welcome / Account
From Robert's wireframe Screen 1, trimmed.
| Field | Type | Notes |
|---|---|---|
| Hostname | text | Default furtka. Becomes hostname in archinstall config. |
| Admin username | text | Becomes first entry in users[].username. |
| Password | password | |
| Password (confirm) | password | Must match. |
| Language | select | Sets archinstall-language + locale_config.locale. |
Dropped from wireframe: "Backend on/off" and "Backend address" — meaning is unclear, see open questions.
S2 — Drive Selection
From Robert's wireframe Screen 2.
- Lists drives via
webinstaller/drives.py::list_scored_devices()(already implemented — do not duplicate). - Each row shows: device path, size, score, SMART status.
- Radio selection for boot drive, with highest-score drive pre-selected.
- "Auto setup" button — accepts the recommendation, jumps past S3.
- Remaining drives carried into S3.
| Field | Type | Maps to |
|---|---|---|
| Boot drive | radio | disk_config.device |
S3 — Per-Device Purpose
From Robert's wireframe Screen 3. One screen per non-boot drive.
| Purpose | Action at install time |
|---|---|
| Mass storage (default for large HDDs) | Added to a shared data pool mounted at /mnt/data. |
| App storage (default for fast drives) | Mounted at /var/lib/docker/homebase-apps, used for container volumes. |
| Backup target | Formatted and scheduled in the backup service (deferred). |
| I don't know | Same as "Mass storage" — safe fallback. |
Radio buttons; default is I don't know.
S4 — Network
From Robert's wireframe Screen 4.
| Field | Type | Notes |
|---|---|---|
| Network mode | radio | DHCP (default) / static |
| Static config | group | IP, gateway, DNS — shown only if "static" picked |
| VPN | toggle | Deferred — stub this out in v1; no VPN config in the wizard yet |
S5 — Domain (NEW)
The YunoHost-style domain picker. Three paths:
| Option | What it does | Who it's for |
|---|---|---|
Free *.homebase.cloud subdomain |
User picks myname.homebase.cloud. DNS is ours, wildcard cert via DNS-01 issued automatically. Managed gateway path. |
The "your dad" default. |
| Bring your own domain | User enters e.g. example.com. Wizard shows two NS records (ns1.homebase.cloud, ns2.homebase.cloud) to paste at their registrar. We handle the rest. |
Users who already have a domain. |
| Skip — LAN only | No public domain. Apps accessible as <app>.proksi.local via mDNS, with certs from the local CA. |
Paranoid users / offline networks. |
Screen validates propagation in the background (NS query every 5s, green check when nslookup resolves to our NS). User can click "Next" past yellow, but not past red.
S6 — SSL / Gateway (NEW)
Auto-configured based on S5.
| S5 choice | S6 behavior |
|---|---|
| Free subdomain | Silent — wildcard cert already issued by our infra, Caddy picks it up. One line: "✅ TLS ready for *.myname.homebase.cloud." |
| BYO domain | Waits for NS propagation (can take minutes–hours). Page auto-refreshes. Shows "⏳ Waiting for example.com to point to us…" → green check. |
| LAN only | Local CA cert used for *.proksi.local. One line: "✅ Local TLS ready." |
User can't advance past S6 until cert is ready (or they go back to S5 and pick a different option).
S7 — Diagnostic (NEW)
YunoHost-style health check before confirming. Runs in parallel, shows results as they land.
| Check | Green | Yellow | Red |
|---|---|---|---|
| DNS resolves target domain | nslookup succeeds |
Succeeds but propagation incomplete | Fails |
| Ports 80 + 443 reachable from WAN | Inbound probe succeeds | CGNAT detected (fallback to Tailscale/Cloudflare tunnel suggested) | Blocked |
| Boot drive mounted | — | — | Fails |
| Docker available | — | — | Missing |
| SMART healthy (all drives) | PASSED | No SMART data | FAILED |
| Admin password strength | ≥12 chars, mixed | 8–11 chars | <8 chars |
Rules: user can continue past yellow with a "I understand" checkbox. Red blocks Next and offers a fix-it shortcut back to the relevant screen.
S8 — Overview + Confirm
Shows the full user_configuration.json and credentials.json side by side (credentials masked, with a "show" toggle). User clicks Install → wizard POSTs to /install/run, which:
- Writes the two JSON files to
/tmp/homebase/. - Fires
archinstall --config /tmp/homebase/user_configuration.json --creds /tmp/homebase/user_credentials.json --silent. - Streams output to a log pane on-screen.
- On success: shows "🎉 Install complete. Remove USB and reboot. After reboot, log in at
https://<your-domain>."
Data model
The wizard accumulates answers in the Flask settings dict at webinstaller/app.py:6. At S8, two JSON files are written. The mapping:
| Wizard field | Target file | Target path |
|---|---|---|
hostname |
user_configuration.json |
hostname |
language |
user_configuration.json |
archinstall-language |
language (derived) |
user_configuration.json |
locale_config.locale |
S2 boot_drive |
user_configuration.json |
disk_config.device |
| S3 per-device mounts | user_configuration.json |
disk_config.additional_mounts (new field; extend archinstall profile) |
S4 network_mode |
user_configuration.json |
network_config.type |
S5 domain |
— | Stored in Homebase state (/etc/homebase/domain.conf), read by Caddy + Authentik at first boot post-install |
S5 domain_mode |
— | Same |
admin_username |
user_credentials.json |
users[0].username |
admin_password |
user_credentials.json |
users[0].password |
admin_password (hash) |
— | Also pushed to Authentik bootstrap config |
New archinstall fields (beyond what's in the current archinstall/user_configuration.json):
disk_config.additional_mounts— list of{device, mountpoint, purpose}— needs a custom archinstall profile script.- Bootstrap script hook to deploy Caddy + Authentik + Homebase admin UI containers on first boot.
Tech decisions (locked)
| Decision | Choice | Why | Rejected |
|---|---|---|---|
| Reverse proxy | Caddy | Automatic Let's Encrypt built-in. Caddyfile is the simplest config of any reverse proxy — matches the "simple" ethos. Auto-reloads on config change. | Traefik (label-based config is elegant for Docker but overkill and Kubernetes-flavored), nginx (battle-tested but manual SSL = every competitor's failure mode). |
| Identity provider | Authentik | Bundled SSO from day one — every app template wires to it at install (YunoHost's best move). Active development, clean admin UI, OIDC + SAML + LDAP. | Authelia (lighter but worse UI and no built-in user management — needs external LDAP), external-only (loses the YunoHost wedge of SSO-by-default). |
| Managed gateway DNS | NS delegation to ns1.homebase.cloud / ns2.homebase.cloud |
User delegates once at registrar; we handle wildcard cert via Let's Encrypt DNS-01, subdomain creation, propagation. The single biggest UX cliff every competitor dies on. | CNAME-per-subdomain (clunky, users see our hostnames in records), manual A records (the exact pain point we're solving). |
| Local HTTPS | Local CA generated at first boot | Single cert install in browser → green padlock for every service, no warnings ever. | Self-signed (YunoHost's model — users learn to click through warnings), public CA for .proksi.local (impossible — .local is reserved for mDNS), Tailscale-style ACME (good but adds a vendor dependency). |
| Base OS | Arch (confirmed) | Rolling releases, Robert's existing Proxmox work. No user-visible difference. | Debian fallback remains documented in README. |
| Container runtime | Docker + Compose | Confirmed in README. Authentik and Caddy ship as Compose stacks. | Podman (cleaner rootless story, but Compose ecosystem is smaller and Authentik ships Docker-first). |
What this spec does NOT cover (deferred)
- App store UI and install flow (separate spec after bootable ISO lands).
- Backup target scheduling (S3 stub points to this).
- VPN configuration (S4 stub points to this).
- Multi-node / cluster setup (not v1).
- Update mechanism (rolling updates via Arch pacman +
docker compose pull).
Open questions for Robert
- "Backend on/off" and "Backend address" fields in your Screen 1 wireframe — what do these configure? Dropped from S1 above until this is clear. If it's "connect to Homebase cloud for managed gateway," that's already covered by the S5 "free subdomain" path.
- Local CA vs Tailscale-style ACME — I locked in local CA because it's self-contained and works offline. Tailscale's approach (public cert for
*.ts.net) is smoother but requires Tailscale. Your call. - Wizard UI framework — currently Jinja templates + plain HTML (see
webinstaller/templates/). If you want HTMX or Alpine for the async parts (S6 cert wait, S7 diagnostics), decide now so the templates don't need rework later. - Language list — which languages ship in v1? Defaulting to English + German + Polish would cover us; anything else up to you.
- Auto-setup branch from S2 — should it skip S3 entirely (purpose auto-assigned by drive type) or still show S3 with pre-filled defaults for confirmation?