SkillAgentSearch skills...

Heads

A minimal Linux that runs as a coreboot or LinuxBoot ROM payload to provide a secure, flexible boot environment for laptops, workstations and servers.

Install / Use

/learn @linuxboot/Heads
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Heads booting on an x230

Heads: the other side of TAILS

Heads is a configuration for laptops and servers that tries to bring more security to commodity hardware. Among its goals are:

  • Use free software on the boot path
  • Move the root of trust into hardware (or at least the ROM bootblock)
  • Measure and attest to the state of the firmware
  • Measure and verify all filesystems

Flashing Heads into the boot ROM

NOTE: It is a work in progress and not yet ready for non-technical users. If you're interested in contributing, please get in touch. Installation requires disassembly of your laptop or server, external SPI flash programmers, possible risk of destruction and significant frustration.

More information is available in the 33C3 presentation of building "Slightly more secure systems".

Documentation

Please refer to Heads-wiki for your Heads' documentation needs.

Contributing

We welcome contributions to the Heads project! Before contributing, please read our Contributing Guidelines for information on how to get started, submit issues, and propose changes.

Building heads with prebuilt and versioned docker images

Heads now builds with Nix built docker images since https://github.com/linuxboot/heads/pull/1661.

The short path to build Heads is to do what CircleCI would do (./docker_repro.sh under heads git cloned directory):

  • Install Docker (docker-ce) for your OS by following Docker's official installation instructions: https://docs.docker.com/engine/install/
  • run ./docker_repro.sh make BOARD=XYZ

Note: ./docker_repro.sh is the canonical, reproducible way to build and test Heads. The docker_local_dev.sh helper is intended for developers who need to modify the local image built from flake.nix/flake.lock and is not recommended for general testing.

Important: the supported and tested workflow uses the provided Docker wrappers (./docker_repro.sh, ./docker_local_dev.sh, or ./docker_latest.sh). Host-side installation of QEMU, swtpm, or other QEMU-related tooling is unnecessary for the standard workflow and is not part of the tested configuration. Only advanced or edge-case workflows may require installing those tools on the host (see targets/qemu.md for guidance).

The Docker images produced by our Nix build include QEMU (qemu-system-x86_64), swtpm / libtpms, canokey-qemu (a virtual OpenPGP smartcard), and other userspace tooling required to build and test QEMU boards. If you use ./docker_repro.sh you only need Docker on the host (for example, docker-ce). For KVM acceleration the host must expose /dev/kvm (load kvm_intel / kvm_amd as appropriate); our wrapper scripts mount /dev/kvm automatically when it exists.

If you plan to manage disk images or use qemu-img snapshots on the host (outside containers), install the qemu-utils package locally (which provides qemu-img).

Inspecting and cleaning local Docker images

# List local images
docker images

# Inspect a specific image (IDs, digests, repo tags)
docker image inspect <image>

# Remove a specific image
docker rmi <image>

# Remove all local images (destructive)
docker rmi -f $(docker images -aq)

# Remove unused images/containers/networks/build cache (destructive)
docker system prune -a --volumes

Note: you may need to prefix commands with sudo depending on your Docker setup.

QEMU disk snapshots with qemu-img

If you manage qcow2 disk images on the host, qemu-img can create, list, restore, and delete snapshots. These examples assume a qcow2 disk image:

# Create a snapshot
qemu-img snapshot -c clean root.qcow2

# List snapshots
qemu-img snapshot -l root.qcow2

# Restore (apply) a snapshot
qemu-img snapshot -a clean root.qcow2

# Delete a snapshot
qemu-img snapshot -d clean root.qcow2

# Optional: create an overlay backed by a base image
qemu-img create -f qcow2 -b base.qcow2 overlay.qcow2

If you prefer to run these inside the container, prefix with ./docker_repro.sh (for example, ./docker_repro.sh qemu-img snapshot -l root.qcow2).

If you do not specify USB_TOKEN when running QEMU targets, the container will use the included canokey-qemu virtual token by default; set USB_TOKEN (or use hostbus/hostport/vendorid,productid) to forward a hardware token instead.

Docker wrapper helper reference

Each wrapper now shows its own focused help (only the variables it actually uses). For the complete environment reference, run docker/common.sh directly:

# Wrapper-specific help
./docker_repro.sh --help
./docker_latest.sh --help
./docker_local_dev.sh --help

# Full environment variable reference (shared helper)
./docker/common.sh

The shared helper documents all supported environment variables (opt-ins and opt-outs) and defaults. Wrapper help is intentionally narrower so it only lists variables relevant to that wrapper.

Wrapper options & environment variables

All wrapper scripts (./docker_repro.sh, ./docker_latest.sh, ./docker_local_dev.sh):

  • HEADS_MAINTAINER_DOCKER_IMAGE — override the canonical maintainer's Docker image repository (default: tlaurion/heads-dev-env). Use this for local testing or if you maintain a fork. Example: export HEADS_MAINTAINER_DOCKER_IMAGE="myuser/heads-dev-env". This affects reproducibility checks and default image references across all Docker wrapper scripts.

  • HEADS_CHECK_REPRODUCIBILITY_REMOTE — specify which remote image to compare against when verifying reproducibility (default: ${HEADS_MAINTAINER_DOCKER_IMAGE}:latest). Use this to test against a specific tagged version instead of :latest.

    # Compare against a specific version
    export HEADS_CHECK_REPRODUCIBILITY_REMOTE="tlaurion/heads-dev-env:v0.2.7"
    HEADS_CHECK_REPRODUCIBILITY=1 ./docker_local_dev.sh
    
  • HEADS_DISABLE_USB=1 — disable automatic USB passthrough and the automatic USB cleanup (default: 0).

  • HEADS_X11_XAUTH=1 — force mounting your ${HOME}/.Xauthority into the container for X11 authentication. When set the helper will bypass programmatic Xauthority generation and mount your ${HOME}/.Xauthority (if present); if the file is missing the helper will warn and will not attempt automatic cookie creation (GUI may fail).

./docker_local_dev.sh:

  • HEADS_SKIP_DOCKER_REBUILD=1 — skip automatically rebuilding the local image when flake.nix/flake.lock are dirty

  • HEADS_CHECK_REPRODUCIBILITY=1recommended for verifying reproducible builds. After building/loading the local image, automatically compares its digest with the published maintainer image to verify reproducibility. Requires network access. By default compares against ${HEADS_MAINTAINER_DOCKER_IMAGE}:latest. Use HEADS_CHECK_REPRODUCIBILITY_REMOTE to specify a different tag (e.g., v0.2.7). See the "Verifying reproducibility" section below for detailed examples and expected outputs.

  • HEADS_AUTO_INSTALL_NIX=1 — automatically attempt to download the Nix single-user installer when nix is missing (interactive prompt suppressed). For supply-chain safety the helper will download the installer to a temporary file and print its SHA256; it will NOT execute the installer automatically unless the downloaded installer matches a pinned hash. The helper will also attempt to detect the installer version heuristically (when possible) and suggest the canonical releases URL (for example https://releases.nixos.org/nix/nix-2.33.2/install.sha256) so you can fetch the published sha and compare. To verify:

    • Preferred: pin a release version (recommended): set HEADS_NIX_INSTALLER_VERSION to a release (for example nix-2.33.2). The helper will fetch https://releases.nixos.org/nix/${HEADS_NIX_INSTALLER_VERSION}/install and install.sha256 and show both checksums for you to compare. To auto-run in trusted automation, set HEADS_NIX_INSTALLER_SHA256 to the expected sha256 as well.

    • Or compute-and-pin locally: run ./docker/fetch_nix_installer.sh --version nix-2.33.2 (or --url) to download the installer and print its sha256, then set HEADS_NIX_INSTALLER_SHA256 to that value for automation.

    Otherwise verify the downloaded installer manually and run it yourself: sh /path/to/installer --no-daemon.

  • HEADS_AUTO_ENABLE_FLAKES=1 — automatically enable flakes by writing experimental-features = nix-command flakes to $HOME/.config/nix/nix.conf (interactive prompt suppressed)

  • HEADS_MIN_DISK_GB — minimum free disk space in GB required on /nix (or / if /nix missing) for building (default: 50)

  • HEADS_SKIP_DISK_CHECK=1 — skip the preflight disk-space check

  • HEADS_ALLOW_UNPINNED_LATEST=1 — when set, bypass the interactive warning that using :latest in ./docker_latest.sh is a supply-chain risk (otherwise :latest requires confirmation unless DOCKER_LATEST_DIGEST is set or the wrapper can fall back to DOCKER_REPRO_DIGEST for the maintainer image)

  • DOCKER_REPRO_DIGEST — pin the image used by ./docker_repro.sh to an immutable digest: tlaurion/heads-dev-env@<digest> (recommended for reproducible and secure builds). Note: DOCKER_REPRO_DIGEST is consumed by ./docker_repro.sh (via resolve_docker_image in docker/common.sh) and is the canonical way to pin the repro image for reproducible builds.

For details about selecting or forwarding a physical USB token to QEMU (handled by the USB_TOKEN make variable), see targets/qemu.md.

Note: when USB passthrough is active the wrappers will detect processes that may be holding a USB token (for example scdaemon or pcscd). The wrapper will warn and, on interactive shells, give a 3s abort window before attempting to kill those processes to free the token. Set HEADS_DISABLE_USB=1 to opt out of thi

Related Skills

View on GitHub
GitHub Stars1.5k
CategoryDevelopment
Updated22h ago
Forks207

Languages

Makefile

Security Score

100/100

Audited on Mar 31, 2026

No findings