OpenRiot v6.4 — Installer Image

“Install OpenRiot in five minutes, offline, with no internet required.”


Release Overview

OpenRiot v6.4 ships a fully automated OpenBSD installer image builder. Run make img on any OpenBSD 7.9 machine, flash the resulting .img to USB, and boot. The installer handles disk selection, partitioning, base install, offline package installation, doas.conf, and user setup — with only hostname, passwords, and disk layout requiring input.

No network required during installation. No manual pkg_add. No setup.sh run from the live system. Everything is baked into the image.

Total changes: image builder, offline packages, installer compliance, doas automation, games excluded.


💾 Bootable Installer Image (make img)

The Problem: Installing OpenRiot required booting standard OpenBSD, running a curl pipe to setup.sh, then manually installing dozens of packages with pkg_add. This took 30+ minutes, required internet, and assumed the user knew OpenBSD partitioning.

The Fix: make img builds a self-contained USB installer.

Workflow

doas make img        # Build install/openriot.img (+ .sha256)
dd if=Build/Images/openriot.img of=/dev/rsdX bs=1m

The image is a standard OpenBSD install79.img expanded to hold ~1–1.5GB of packages, configs, and the OpenRiot repo. It shrinks to minimum size + 10% buffer after content injection. Final output is under 2GB.

What the User Sees

Prompt Default Input Required
Disk selection none Choose SSD/HDD
Partition layout Edit Customize or accept
Hostname none Type name
Root password none Set password
User account none Create username
User password none Set password
Timezone US/Pacific Hit Enter or change

Everything else — sets, packages, config, repo — happens automatically.


📦 Offline Package Installation

The Problem: Previous attempts at make img never actually installed packages. install.site was packed inside the tarball (invisible to the installer), used broken pkg_add syntax (stripped base names instead of full .tgz paths), and tried to tar xzf a file on the install media instead of the target filesystem.

The Fix:

  • site79.tgz is extracted by the OpenBSD installer as a standard set (replaces non-compliant openriot.tgz naming)
  • Packages ship inside site79.tgz at /openriot/packages/snapshots/amd64/
  • install.site runs post-install and calls pkg_add with full .tgz paths: pkg_add "$PKG_PATH_LOCAL"/*.tgz
  • install.site and install.conf are copied to the install media root (not inside the tarball), so the OpenBSD installer discovers them

All packages from packages.yaml are installed offline. No pkg_add -i over the network. No dependency resolution failures.


🛡️ doas and Wheel Configuration

The Problem: The installer creates a user account, but OpenBSD does not automatically add it to the wheel group. Without wheel, doas.conf’s permit nopass :wheel grants nothing. The user would need to su - and usermod manually on first boot.

The Fix: install.site now explicitly adds every user in /home/* to the wheel group:

usermod -G wheel "$username"

/etc/doas.conf is written with permit nopass :wheel and mode 0440. The first login has working doas with no manual steps.


🚫 Games Excluded from Image

The Problem: Desktop games (gottet, wesnoth, openttd, cataclysm-dda, etc.) total over 2GB. Including them would push the installer image past the 2GB practical limit for USB flashing and vnconfig/growfs workflows.

The Fix: Build/exceptions.yaml now supports module-level exclusion:

modules:
  - desktop.games

DownloadPackages() skips the entire desktop.games module during image builds. Games install normally via setup.sh on live systems.


🐛 Bug Fixes

Empty Image File Accepted

CheckPrereqs accepted 0-byte files as valid base images. A failed prior wget left an empty install79.img, which was then truncated to 2GB of zeros. growfs failed with “superblock not recognized.”

  • CheckPrereqs now rejects files with Size() == 0
  • downloadBaseImage() cleans up empty files on wget failure
  • Downloaded images are verified non-empty before continuing

Disklabel Geometry Faked

writeDisklabel() generated a hardcoded partition table with fabricated DUID, cylinder counts, and geometry. This rarely matched the actual base image, causing silent filesystem corruption or boot failures.

  • writeDisklabel() now reads the existing label via disklabel vnd0
  • Only the a: partition size is modified — DUID, geometry, and other partitions (c:, i:) are preserved exactly

📦 Package Changes

  • Image-excluded: desktop.games module (14 packages, >2GB)
  • Image-excluded: go (Build/exception.yaml exclude:)
  • Added: bitcoin-30.2p0 remains in image (from v6.3)

🧾 Files Changed

File Nature of Change
source/imaging/prereqs.go Auto-download base image, zero-file guard
source/imaging/download.go Module exceptions.yaml, newline on warn fix
source/imaging/site.go site79.tgz, pkg_add, usermod wheel fix
source/imaging/build.go Media root inject, real disklabel update
source/config/loader.go GetPackagesExcluding() module + package filter
Build/exceptions.yaml modules: section, desktop.games excluded
docs/v6.4-Release-Notes.md This file

🗣️ Final Words

“v6.0 was beauty. v6.1 was correctness. v6.2 was readability. v6.3 was choice. v6.4 is independence.”

This release eliminates the single biggest barrier to OpenRiot adoption: installing it. No more 30-minute pkg_add marathons over hotel WiFi. No more partitioning anxiety. Burn the image, boot, answer five prompts, and you have a fully configured OpenRiot workstation with doas, fish, i3, Firefox, Bitcoin, Monero, and every tool we ship.

The installer fits on a 2GB USB stick. It works on a ThinkPad in a cabin with no cell service. That is the point.

— The OpenRiot Crew

“Privacy requires control. Control requires booting your own OS. Now you can, anywhere, no internet required.”