Closes #9. New apps/README.md walks through the four-file contract (manifest.json, docker-compose.yaml, .env.example, icon.svg) with the rules enforced by furtka/manifest.py and the SVG sanitiser, using apps/fileshare as the reference. Root README: release list now covers 26.1/26.3/26.4 (26.2 stalled on the jq apt hang). Local HTTPS Phase 1 and the post-build smoke VM on pollux both flip to [x]; the old proksi.local HTTPS TODO becomes a Phase 2 entry (dedicated local CA + HTTPS on the live-installer wizard). iso/README: mDNS is wired — live ISO advertises proksi.local, installed box defaults to furtka.local (the form's default hostname, not proksi). HTTPS section notes Caddy tls internal on :443 shipped in 26.4 while the wizard itself is still HTTP. Overlay table picks up etc/hostname, etc/issue, furtka-update-issue, and furtka-issue.service. website/README: auto-deploy via .forgejo/workflows/deploy-site.yml is the default path now; website/deploy.sh stays as the SSH-hop fallback for off-CI pushes, and deploy-ci.sh is called out in the structure map. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
66 lines
6.3 KiB
Markdown
66 lines
6.3 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 also shows the DHCP-assigned IP as a fallback URL |
|
||
| `overlay/airootfs/etc/systemd/system/` | `furtka-webinstaller.service` (Flask on :5000) + `furtka-issue.service` (runs the banner-updater on network-online), each symlinked into `multi-user.target.wants/` to auto-start on boot |
|
||
|
||
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.
|
||
|
||
## 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
|
||
|
||
## 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`. Since 26.4-alpha, `https://<hostname>.local` is also served via Caddy's `tls internal` — 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; the installed box gets Caddy + `tls internal` on `:443` once it reboots (26.4-alpha), but bringing the same story to the wizard itself is a later milestone.
|
||
- **Boot USB could appear as an install target on bare metal**. On a VM the ISO is a CD-ROM (filtered) and SATA is the only disk, so the picker only shows the install target. On bare metal with a USB stick, the USB is `TYPE=disk` and shows up alongside the real install drive; a user could in theory pick the USB they just booted from. Mitigating this needs detecting the boot media (via `findmnt /run/archiso/bootmnt` or similar) and filtering it out in `webinstaller/drives.py`.
|