nix-hex-box is a nix-darwin module that configures an Apple
container machine backed aarch64-linux remote builder for Nix.
Documentation site:
Current design highlights:
- installs Apple
containerfrom the official signed GitHub release package - pulls the published Alpine/Lix-based builder image by default, with an optional local custom image build
- creates a persistent Apple
container machineinstead of an ephemeral container - configures
nix.buildMachinesforssh-ng://container-builder - uses
ProxyCommandto auto-start the machine and relay SSH to guestsshd - lets the macOS root
nix-daemonsudo back to the runtime-owning user for the Apple container command - connects as the guest
builderuser and uses a narrow passwordless sudo wrapper for the remotenix-daemon - keeps the guest
/nixstore persistent across machine stops and starts - powers the guest off after a configurable idle timeout with no active SSH connections
- manages durable host state under
~/.local/state/hb - can install and manage Socktainer as an optional Docker-compatible API layer
- installs host-side SSH aliases for both
nix-builderandcontainer-builder - writes a generated
known_hostsfile under~/.local/state/hbso SSH verifies the builder host key - exposes
host.container.internalfor Apple containers by default viacontainer system dns - waits for a real SSH handshake before considering the builder ready
The flake exports:
darwinModules.defaultdarwinModules.container-builder
The repo also contains a scheduled workflow that opens a Robborg-authored PR for pinned runtime-version updates, validates it, and auto-merges it after the lint workflow passes.
{
inputs.hexbox.url = "github:RobertDeRose/nix-hex-box";
outputs = inputs: {
darwinConfigurations.my-host = inputs.darwin.lib.darwinSystem {
system = "aarch64-darwin";
modules = [
inputs.hexbox.darwinModules.default
{
services.container-builder = {
enable = true;
cpus = 4;
memory = "8G";
maxJobs = 4;
socktainer.enable = true;
# Optional override if you do not want to use config.system.primaryUser.
user = "myuser";
};
}
];
};
};
}This module is functional but still in progress.
Known open areas:
- evaluating a smaller systemd-based image once Apple
container machinehandles larger systemd images reliably
The module uses the HexBox builder image published by this repository by default:
ghcr.io/robertderose/nix-hex-box/hexbox-builder:latest
The image contains Alpine 3.22, OpenSSH, sudo, and Lix. The module creates a
persistent Apple container machine from that image and bootstraps the
host-specific SSH keys, nix.conf, sudoers rule, and idle timeout.
GitHub Actions rebuilds and publishes latest on the same weekly schedule as
the runtime-version updater so Alpine package updates, such as OpenSSH fixes,
are available to new or recreated machines. When the configured machine image
contract changes, HexBox recreates the builder machine automatically; this also
deletes the guest-local store.
Builder image publishing is skipped until the configured Lix tag is at least
seven days old. When the image definition changes on main, the workflow also
publishes the versioned release tag alpine-3.22-lix-2.95.2-2 for users who
prefer to pin.
The builder uses ssh-ng. The host SSH path is a generated ProxyCommand that
runs Apple container machine run --root -i ... socat STDIO TCP:127.0.0.1:<containerPort>,
so the machine starts on demand, IP changes do not affect Nix, and the relay
closes cleanly when SSH finishes. Custom imageContainerfile images must
include socat, or builder bootstrap will fail the SSH proxy preflight.
The guest /nix store lives in the machine's persistent storage. Stop/start
keeps build outputs and downloaded substitutes. hb builder reset deletes and
recreates the machine, which also deletes the guest-local store.
Available image options:
services.container-builder.imageRepositoryservices.container-builder.nixVersionservices.container-builder.imageContainerfileservices.container-builder.imageBuildContext
Set imageContainerfile to build and use a local custom image instead of the
published GHCR image. Set imageBuildContext to an absolute host path string
when the custom image needs a build context. Custom images must provide
socat, base64, getent, and a working /sbin/init, because HexBox
bootstrap, machine boot, and the SSH proxy all use those entrypoints. Bump
nixVersion or remove the local image when the Containerfile or context
changes.
Available machine options:
services.container-builder.cpusservices.container-builder.memoryservices.container-builder.homeMountservices.container-builder.idleShutdown.enableservices.container-builder.idleShutdown.timeoutSeconds
Available host/container integration options:
services.container-builder.exposeHostContainerInternalservices.container-builder.socktainer.enableservices.container-builder.socktainer.homeDirectoryservices.container-builder.socktainer.binaryservices.container-builder.socktainer.installer.urlservices.container-builder.socktainer.installer.hashservices.container-builder.socktainer.installer.version
The builder machine writes a minimal nix.conf with
https://cache.nixos.org/ configured as a substituter.
Example:
services.container-builder = {
enable = true;
};Set services.container-builder.socktainer.enable = true; to install the
official Socktainer pkg and manage a user launch agent for the current primary
user.
This exposes a Docker-compatible Unix socket at:
$HOME/.socktainer/container.sock
Example:
export DOCKER_HOST=unix://$HOME/.socktainer/container.sock
docker psSet services.container-builder.socktainer.setDockerHost = true; if you want
the module to export that socket as DOCKER_HOST in the user environment.
After activation, use:
hb builder status
hb builder repair
hb builder test
hb builder ssh
hb builder logs boot
hb builder logs idle
hb doctorhb builder repair ensures the Apple container system is healthy, builds a
custom local OCI image when configured and missing, creates or updates the
container machine, verifies SSH, checks outbound connectivity, and pings the
remote store. If repair fails, follow the reported recovery step for the
runtime, machine, or network failure that was detected.
After repair succeeds, run hb builder test to verify remote build execution.
See docs/spec.md for the detailed design notes.
