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>
6.3 KiB
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.
./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
- Build:
./iso/build.sh - Copy the ISO to your Proxmox host's ISO storage (typically
/var/lib/vz/template/iso/). Browser uploads of 1.5 GB truncate silently — preferscpover the Proxmox WebUI. - 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 loadldlinux.c32from 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
- Start the VM. Wait ~30 s for boot.
- Find its IP in Proxmox's VM summary (or your router's DHCP table)
- 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(defaulthttp://furtka.local— the form's default hostname isfurtka; only the live-installer ISO usesproksi): Caddy-served landing page with three live status tiles (uptime, Docker version, free disk) refreshed every 30 s byfurtka-status.timer. Since 26.4-alpha,https://<hostname>.localis also served via Caddy'stls internal— trustrootCA.crtfrom/settingsto clear browser warnings. - SSH:
ssh <user>@<hostname>.localworks;docker psworks withoutsudobecause the user is in thedockergroup.
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,
xorrisosilently dies at the very end with "Image size exceeds free space on media". - Live-installer wizard is still HTTP-only.
http://proksi.local:5000during install has no TLS; the installed box gets Caddy +tls internalon:443once 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=diskand 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 (viafindmnt /run/archiso/bootmntor similar) and filtering it out inwebinstaller/drives.py.