After the 26.19 → 26.20 self-update the bench had furtka-welcome.timer linked + enabled but inactive (dead): enable only arms a timer for the next boot. The link also pointed at /opt/furtka/versions/<ver>/ instead of /opt/furtka/current/, unlike the installer-created links, so it would have stopped following later updates and rollbacks. Link via current, enable, start. Adds docs/hardware-test-2026-08.md (timeline, five findings with root causes / fixes / validation status, what worked, open items) and a 'Real hardware' section in iso/README.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MScAinbyMdeNc7H2BZdnnG
88 lines
7.7 KiB
Markdown
88 lines
7.7 KiB
Markdown
# Live ISO build
|
||
|
||
Builds a bootable Arch-based live ISO that auto-starts the Flask webinstaller from `../webinstaller/` on boot. User plugs in a USB, boots, and the installer wizard comes up on `http://proksi.local:5000` (or the raw IP shown on the console).
|
||
|
||
Runnable locally (below) or through Forgejo Actions — `.forgejo/workflows/build-iso.yml` builds on every push to `main` and on manual `workflow_dispatch`. The ISO lands as an artifact named `furtka-iso`, retained for 14 days. Feature branches don't trigger the ISO build; see `memory/project_ci_branching` for why.
|
||
|
||
## Run a build locally
|
||
|
||
Needs a host with Docker. Disk space required: ~15 GB scratch during the build, ~1.5 GB for the final ISO.
|
||
|
||
```bash
|
||
./iso/build.sh
|
||
```
|
||
|
||
Output ISO ends up in `iso/out/furtka-<date>-x86_64.iso`. Around 3–10 min on a 4-core VM. First run is slower because it pulls `archlinux:latest` and all packages from upstream.
|
||
|
||
The script re-execs itself inside a privileged `archlinux:latest` container. That's so `mkarchiso` has root + loop-mount access without polluting the host — Ubuntu hosts don't ship archiso natively anyway.
|
||
|
||
## What gets baked in
|
||
|
||
The build starts from Arch's stock `releng` profile (the same one used to build the official Arch ISO), then overlays our customizations from `overlay/`:
|
||
|
||
| Overlay file | Effect |
|
||
|----------------------------------------------|----------------------------------------------------------------------------------|
|
||
| `overlay/packages.extra` | Appended to the package list. Adds `python`, `python-flask`, `avahi`, `nss-mdns` |
|
||
| `overlay/profiledef.sh` | Appended to `profiledef.sh`. Renames the ISO to `furtka-*` with a dated version |
|
||
| `overlay/airootfs/opt/furtka/` | Directory where `webinstaller/` is copied at build time |
|
||
| `overlay/airootfs/etc/hostname` | Live-ISO hostname (`proksi`) so mDNS advertises the installer as `proksi.local` |
|
||
| `overlay/airootfs/etc/issue` | Welcome banner on the TTY pointing users at `http://proksi.local:5000` |
|
||
| `overlay/airootfs/usr/local/bin/furtka-update-issue` | Rewrites `/etc/issue` at runtime so the banner always carries a fallback line: the DHCP-assigned IP(s), or a "no IP yet — check cable / DHCP" hint until one arrives. Only touches the file (and `agetty --reload`s) when the text changed |
|
||
| `overlay/airootfs/etc/systemd/system/` | `furtka-webinstaller.service` (Flask on :5000) + `furtka-issue.service` (banner-updater, first run at boot) in `multi-user.target.wants/`, and `furtka-issue.timer` (re-runs the updater every 5 s) in `timers.target.wants/` |
|
||
|
||
The systemd service runs `flask --app app run --host 0.0.0.0 --port 5000` under `/opt/furtka`. The `0.0.0.0` binding is important — the Flask default is localhost-only, which wouldn't be reachable from another machine on the LAN.
|
||
|
||
mDNS is wired: `avahi-daemon` + `nss-mdns` come from `packages.extra`, the live ISO's hostname is `proksi`, and as soon as `systemd-networkd-wait-online` fires the installer is reachable at `http://proksi.local:5000`. The raw IP still shows on the console for fallback — some Windows clients need the Bonjour service for `.local` to resolve at all.
|
||
|
||
`build.sh` also deletes releng's `getty@tty1.service.d/autologin.conf`. With root auto-logged-in, tty1 belongs to a shell and `agetty --reload` can't redraw the banner, so the IP line was a snapshot of whatever DHCP had done by the time getty started. Without autologin tty1 sits at the login prompt showing the live banner; for a shell type `root` + Enter (releng's root has no password) — the banner says so.
|
||
|
||
## Test flow
|
||
|
||
1. Build: `./iso/build.sh`
|
||
2. Copy the ISO to your Proxmox host's ISO storage (typically `/var/lib/vz/template/iso/`). Browser uploads of 1.5 GB truncate silently — prefer `scp` over the Proxmox WebUI.
|
||
3. Create a VM with:
|
||
- 2 vCPU, 4 GB RAM, 20 GB disk (empty)
|
||
- **BIOS: OVMF (UEFI)**, add EFI Disk on `local-lvm`. SeaBIOS fails to load `ldlinux.c32` from our ISO; only the UEFI path works reliably.
|
||
- **Secure Boot disabled**. Our GRUB isn't signed, so Secure Boot rejects it with `Access Denied`. Either boot into OVMF setup (Esc during boot) → Device Manager → Secure Boot Configuration → Attempt Secure Boot [ ] → F10 → reboot. Or remove the EFI Disk and re-add it with "Pre-Enroll keys" unchecked.
|
||
- CD-ROM attached with the Furtka ISO
|
||
- Boot order: CD before disk
|
||
- Network: same bridge as your LAN, DHCP
|
||
4. Start the VM. Wait ~30 s for boot.
|
||
5. Find its IP in Proxmox's VM summary (or your router's DHCP table)
|
||
6. Open `http://<vm-ip>:5000` — the existing 3-screen wizard should be there
|
||
|
||
## Real hardware (what differs from the VM flow)
|
||
|
||
Learned on the first bare-metal run, see [docs/hardware-test-2026-08.md](../docs/hardware-test-2026-08.md):
|
||
|
||
- **BIOS boxes work.** The hybrid ISO boots via syslinux on legacy firmware
|
||
(you'll see the stock Arch splash — only the menu labels are branded), and
|
||
the installer detects the missing `/sys/firmware/efi` and picks GRUB + MBR.
|
||
- **Pull the USB stick before "restart now".** Most BIOSes boot USB before
|
||
the disk; the done page says so above the button since 26.20-alpha.
|
||
- **Disks with a previous OS are fine since 26.20-alpha.** The live ISO
|
||
auto-activates old LVM/RAID/swap; `webinstaller/diskprep.py` releases the
|
||
disk before archinstall partitions it. On 26.19 and earlier you'd hit
|
||
`unable to inform the kernel of the change … in use` at 12 % — clear it
|
||
from the tty1 root shell with `dmsetup remove <node>` for every dm node
|
||
shown by `lsblk`, then `wipefs -a /dev/sdX` and retry.
|
||
- **Slow NICs.** The console banner's IP fallback line is timer-driven
|
||
since 26.20-alpha; on 26.19 it only appeared if DHCP beat getty.
|
||
- **Shell on the live ISO**: since 26.20-alpha tty1 stays at the login
|
||
prompt (banner refreshes live); log in as `root`, no password. sshd runs;
|
||
set a root password with `passwd` to reach it over the network.
|
||
|
||
## What you see after install + reboot
|
||
|
||
Once `archinstall` finishes and you click **Reboot now**, the VM comes up into the installed system. No more port `:5000` — the wizard ISO is gone. Instead:
|
||
|
||
- **Console**: agetty shows `Furtka is ready. Open http://<hostname>.local …` with the IP fallback underneath.
|
||
- **Browser** at `http://<hostname>.local` (default `http://furtka.local` — the form's default hostname is `furtka`; only the live-installer ISO uses `proksi`): Caddy-served landing page with three live status tiles (uptime, Docker version, free disk) refreshed every 30 s by `furtka-status.timer`. HTTPS is opt-in (26.15-alpha) — flip the toggle in `/settings` to switch on Caddy's `tls internal` on `:443`, then trust `rootCA.crt` from `/settings` to clear browser warnings.
|
||
- **SSH**: `ssh <user>@<hostname>.local` works; `docker ps` works without `sudo` because the user is in the `docker` group.
|
||
|
||
This is a demo shell — no Authentik, no app store yet. The landing page lives at `/srv/furtka/www/`, served by Caddy on `:80` per `/etc/caddy/Caddyfile`. All of this is written into the target by `webinstaller/app.py`'s `_post_install_commands` via archinstall's `custom_commands`.
|
||
|
||
## Known rough edges
|
||
|
||
- **Disk space**: the first time you build on a fresh host, the squashfs/xorriso steps need ~15 GB free. If the host's LVM-root is smaller, `xorriso` silently dies at the very end with "Image size exceeds free space on media".
|
||
- **Live-installer wizard is still HTTP-only**. `http://proksi.local:5000` during install has no TLS; once the box reboots, Caddy can serve `tls internal` on `:443` if the user opts in via `/settings` (26.15-alpha), but bringing TLS to the wizard itself is a later milestone.
|