This is the multi-page printable view of this section. .
Guides
- 1: Download and Install Barn
- 2: Linux Quick Start
- 3: macOS Virtual Machines
- 4: Daily Operations
- 5: Storage, Files, and Service Access
- 6: Image Repositories
- 7: Automation and Guest Scripts
- 8: Troubleshooting
- 9: Build from Source
- 10: Uninstall and Clean Up
These guides cover Barn 1.2.0. The Barn 1.2.0 release notes summarize its changes and the upgrade from 1.1.0. You can run both Linux labs and isolated macOS VMs on the same Apple Silicon Mac—each workflow manages its own VMs under ~/.barn.
Get started
- Install Barn — Install the stable CLI on macOS or Linux, check host requirements, and upgrade existing installations.
- Linux Quick Start — Bring up an Ubuntu 24.04 VM, connect over SSH, and scale to a multi-node fixed-IP lab from one
barn.yml. - macOS Virtual Machines — Create and manage macOS 27 guests on Apple Silicon with a native desktop, SSH, shared folders, and clipboard sync.
Day-to-day Linux operations
- Daily Operations — Inspect status, stop and start nodes, preview inventory changes with
plan, andrecreateordestroymachines. - Storage and Access — Configure persistent test data disks, transfer files over SSH, forward ports, and mount Virtio-9p host shares.
- Image Repositories — Pick from 9 distribution families, switch to the China mirror, build a static image repository, or import a local
qcow2. - Automation — Run unattended host setup, validate
--jsonoutput withjq, execute scripts viabarn provision, and pair with Pigsty.
Diagnostics, source builds, and cleanup
- Troubleshooting — Runbooks for host readiness, network repairs, guest stage warnings, SSH keys, and interrupted commands.
- Build from Source — Compile the
v1.2.0CLI,barn-hosts-helper, and nativeBarn.appbundle, and run contributor test gates. - Uninstall and Clean Up — Tear down Linux and macOS VMs cleanly, prune image caches, remove host networking, and uninstall Barn.
1 - Download and Install Barn
Barn 1.2.0 ships archives for macOS and Linux on arm64 and amd64, along with DEB and RPM packages for Linux. Always run barn as your normal Unix user; after installing, continue with the Linux quick start or macOS VM guide.
Barn 1.2.0 is the current stable release. It is published on GitHub’s regular release channel, so releases/latest, the installer without BARN_VERSION, and the Homebrew formula select it; set BARN_VERSION=1.2.0 to pin it. The Apple Silicon archive includes the matching barn, barn-hosts-helper, and native macOS app bundle (Barn.app), signed with Developer ID and notarized by Apple. Go and Xcode are only needed for source builds.
| Component | Purpose | Included in 1.2.0 downloads |
|---|---|---|
barn |
Go CLI for Linux labs and macOS VM lifecycle | All four platform archives and Linux packages |
barn-hosts-helper |
Companion binary for /etc/hosts name integration |
Packaged alongside its matching CLI |
Barn.app |
Native Virtualization.framework runner and macOS guest desktop |
Included in the Darwin arm64 archive and Apple Silicon Homebrew install; macOS guests only |
Install the release
Choose the operating system of your host machine. Use Homebrew on macOS or the release installer script on Linux.
Install Barn and its QEMU dependency with Homebrew as your normal user:
On Apple Silicon, the Homebrew formula also installs Barn.app under libexec, where the CLI discovers it automatically. On macOS 27+, run barn mac doctor and continue with the Mac guide. Intel Macs use the CLI and helper for Linux guests.
Download install.sh and run it. Without BARN_VERSION, it installs the latest stable release; set BARN_VERSION=1.2.0 to pin this one. The script detects amd64 or arm64, verifies the archive SHA-256 against checksums.txt, and installs the CLI and matching barn-hosts-helper under ~/.local/bin without sudo:
Add export PATH="$HOME/.local/bin:$PATH" to your shell startup file (such as ~/.bashrc or ~/.zshrc), and keep the versioned .barn-releases/ directory layout intact. You can also run this same installer on macOS if you prefer not to use Homebrew; barn setup will handle QEMU and host-network dependencies separately.
When you run barn up interactively for the first time, Barn checks for missing Linux-guest dependencies and host networking, shows the host-preparation plan, and asks once before installing anything; it requests administrator access (sudo) only when a step needs it. Without a terminal, barn up only reports what is missing, so run barn setup --yes for unattended preparation. To preview the host changes without applying them, run barn setup --dry-run.
System requirements
| Guest | Host | Runtime |
|---|---|---|
| Linux | macOS, Apple Silicon or Intel | QEMU 8.2.1+, HVF |
| Linux | Linux, arm64 or amd64 | QEMU 6.2+, usable KVM, NetworkManager or systemd-networkd |
| macOS 27 | Apple Silicon, macOS 27+, logged-in desktop session | Barn.app native component; no QEMU required |
A default Linux VM uses 1 vCPU and 2 GiB of memory, backed by thin-provisioned qcow2 disks (64 GiB root disk and 128 GiB test data disk) that grow as data is written.
The first macOS VM requires roughly 65 GiB of free disk space to hold Apple’s ~25 GiB restore image, the ~27 GiB installed base image, and initial guest writes. By default, a Mac VM uses 4 vCPUs, 8 GiB of memory, and a 100 GiB APFS clone disk. Later Mac VMs inherit the prepared base image’s capacity unless you pass --disk. See Platforms and limits for guest-specific constraints.
Download Barn 1.2.0
The stable release was published on 2026-11-12. Select the host operating system and CPU architecture:
| Host OS | Architecture | Archive | Debian / Ubuntu | RHEL / Fedora |
|---|---|---|---|---|
| macOS | Apple Silicon (arm64) |
tar.gz | — | — |
| macOS | Intel (amd64) |
tar.gz | — | — |
| Linux | x86-64 (amd64) |
tar.gz | DEB | RPM |
| Linux | ARM64 (arm64) |
tar.gz | DEB | RPM |
SHA-256 checksums · Release metadata · Installer script
Each archive and package has a matching .spdx.json dependency inventory on the GitHub Release. The Darwin arm64 archive includes the signed, notarized Barn.app.
Other installation methods
Linux packages
The DEB and RPM packages declare their QEMU, UEFI firmware, and OpenSSH dependencies automatically. On ARM64 hosts, replace amd64 with arm64:
Manual archives
Download barn_1.2.0_<os>_<arch>.tar.gz (darwin or linux, arm64 or amd64) and checksums.txt from Barn 1.2.0 on GitHub, then verify the SHA-256 digest before extracting:
Extract the archive and add its bin/ directory to PATH. Keep the packaged layout intact: barn and barn-hosts-helper must stay paired, and the Darwin arm64 archive also contains bin/Barn.app. The CLI verifies the helper’s embedded SHA-256 before invoking it and discovers the app beside the binary.
Build from source
To work on Barn or compile the native Barn.app bundle for macOS guests, see Build from Source.
Upgrade Barn
Upgrading from 1.1.0 to 1.2.0 preserves VM disks, SSH keys, state, and configuration under ~/.barn. Stop running Mac VMs before replacing the CLI, helper, and Barn.app together. Linux inventories that omit CPU/memory now resolve to 1 vCPU / 2 GiB; explicitly set vm_cpu: 2 and vm_mem: 4GiB to preserve the old defaults and inspect barn plan. Existing applied VMs keep their resources until a resource-changing operation is requested. See the 1.2.0 release notes.
Upgrade using the same channel you used to install Barn. On macOS with Homebrew:
On Linux, re-run install.sh (it selects the latest stable release unless BARN_VERSION is set) or install the newer .deb / .rpm package, then run command -v barn and barn version to confirm the active binary. If both a user-directory install and a system package/Homebrew install exist, update the copy selected by PATH, or adjust PATH and verify the version again.
Barn decouples CLI upgrades from guest image updates so existing VMs never change OS versions unexpectedly:
| Target | Command | Effect on existing VMs |
|---|---|---|
| Barn CLI, helper & bundled app | Reinstall or brew upgrade |
Preserves all VM disks and state |
| Linux image catalog | barn update (or barn update --mirror) |
Updates catalog for new or recreated nodes |
| macOS base image | barn mac image update |
Prepares a new base image; apply to an existing VM with barn mac recreate NAME --update |
For proxy or PATH issues, see Troubleshooting. To remove Barn and its host state, see Uninstall and Clean Up.
2 - Linux Quick Start
Create an Ubuntu 24.04 VM on your Mac or Linux host, connect over SSH, and scale it into a multi-node fixed-IP lab from a single YAML inventory. For macOS guests on Apple Silicon, see the macOS VM guide.
This walkthrough uses Barn 1.2.0, with 1 vCPU and 2 GiB per node by default. Set resource fields explicitly to customize the lab; see configuration defaults.
Before you start
Install Barn and make sure your host has at least 2 GiB of free memory for the guest. Run the commands below as your normal user in an interactive terminal: Barn asks once before it changes the host and prompts for sudo only for the steps that need it. For unattended CI runs, see Automation. In mainland China, add --mirror to the first barn up to download images from the China repository at repo.pigsty.cc.
Customize before the first start
The default lab is one Ubuntu node using the host architecture: arm64 on Apple Silicon, amd64 on Intel/AMD. No architecture setting is needed for normal use; see image and architecture settings for cross-architecture selection and precedence. To keep the defaults, skip to Start and connect. To choose the topology, subnet, or OS image first, write and edit the inventory before the first barn up:
-
Generate a starter
barn.yml(dual,trio, orfullcreates 2, 3, or 4 nodes;-c 10.20.30.0/24selects a custom subnet,-I el9writes one image for every node, and-A amd64setsvm_arch): -
Edit
barn.ymlto choose your image and resources:barn.yml -
Validate the YAML and preview the plan:
barn validate and barn plan resolve catalog metadata without requiring QEMU or host-network setup, and the next section’s barn up uses this barn.yml. See Linux Configuration for all inventory variables.
Start and connect
When neither an inventory file nor an active deployment exists, barn up prints a short setup plan before it changes anything. Only the rows that apply appear: dependencies lists missing packages (QEMU, UEFI firmware, OpenSSH) and the package manager, network names the fixed-IP subnet it prepares, config names the one-node barn.yml it writes, and sudo says which steps need root. On a host that already has QEMU:
Answer once; sudo may then ask for your password. Barn downloads and verifies the base image, updates the live progress table on a terminal, and waits until SSH is ready:
If barn up stops with an error instead, run barn doctor to check the host and barn logs meta to read the guest console, fix the reported problem, and run barn up again. See Troubleshooting for common failures.
Log in to the guest:
barn ssh logs you in as dba with key-based SSH and passwordless sudo. barn up also installs SSH aliases, so plain ssh meta works too. Type exit to return to your host shell; the remaining commands run on the host.
| Default | Value |
|---|---|
| Node and address | meta at 10.10.10.10 |
| Image | Ubuntu 24.04 (u24:stable, native host architecture) |
| CPU and memory | 1 vCPU, 2 GiB |
| Disks | 64 GiB root overlay, 128 GiB test data disk mounted at /data |
Both disks are thin-provisioned qcow2 files that grow as data is written. If 10.10.10.0/24 conflicts with an existing route on your machine, first-run setup automatically picks a free private /24 for a fresh default template—check the generated barn.yml and barn status for the assigned IP.
One Linux deployment per BARN_HOME: Barn stores your active Linux lab under BARN_HOME (default ~/.barn). Changing working directories does not create a second lab; running barn up in a directory without an inventory simply resumes the existing deployment. See One Deployment, No Projects for the rationale.
Inspect and use the VM
barn status reports each node’s fixed address, recorded state, image release, and size. Run guest commands from the host by putting -- before the remote command:
barn up verifies management SSH and reports guest-stage warnings such as an unavailable data disk or private interface. If setup is interrupted or you fix a host issue, run barn up again—healthy VMs stay running while Barn finishes the remaining steps.
Data disks are disposable test storage. During guest recovery, barn up resets an ext4 or XFS data filesystem when the filesystem checker reports recognized corruption, including on persistent disks. Keep important files on the host; see Storage and Access for disk retention and recovery boundaries.
Scale to a multi-node lab
To grow the lab to four nodes (8 GiB of guest memory at the default 2 GiB per node), add three host entries under all.children.nodes.hosts in your existing barn.yml. Use addresses from the same /24 as meta; if first-run setup chose another subnet, use that one:
Preview the change and converge the new nodes:
barn plan reports create: node-1, node-2, node-3, and barn up creates them without restarting meta.
If you change an existing node’s CPU or memory, apply the change with barn resize <node>; it preserves the VM identity and disks. Image changes still use barn recreate <node>, which replaces its root disk. Removing a host entry from barn.yml leaves the VM untouched on disk until you run barn destroy <node>.
Stop, resume, and clean up
Both stop and start preserve all VM disks. When you finish with the lab, run barn destroy and type destroy to confirm. Barn deletes the VMs with their root overlays and non-persistent data disks, removes the deployment state and the SSH aliases it installed, and keeps persistent data disks, the deployment keys, cached base images, and the host network. Running barn up in ~/barn-lab again builds a fresh lab from barn.yml. For a full teardown, see Uninstall and Clean Up.
Next steps
- Daily Operations — Inspect logs, restart nodes, apply inventory changes, and destroy VMs.
- Storage and Access — Configure persistent disks, copy files with OpenSSH, and reach guest ports.
- Image Repositories — Select Debian, Rocky Linux, Ubuntu, or local
qcow2images. - Automation — Run unattended
setup --yes, parse--jsonoutput, run guest scripts, or pairpigsty.ymlwith Pigsty.
3 - macOS Virtual Machines
barn mac provisions disposable macOS VMs on Apple Silicon Macs for building, testing, and reproducing macOS-specific issues. Each VM comes with an administrator account, passwordless sudo, pinned SSH keys, and a dedicated private IP, running directly under your user account via Apple’s Virtualization framework without sudo.
Mac VMs are managed independently from the Linux lab: they do not read barn.yml, they store their state under $BARN_HOME/mac (default ~/.barn/mac), and Linux barn destroy or barn purge commands never touch them.
Requirements
- An Apple Silicon Mac running macOS 27 or later with an active logged-in desktop session (guests also run macOS 27).
- Roughly 65 GiB of free disk space for the first VM—covering Apple’s ~25 GiB restore image (
.ipsw), the ~27 GiB installed base image, and initial guest writes. Each VM clones the base image on APFS and grows up to its configured capacity (100 GiB by default). - The native
Barn.appbundle paired with the CLI from the same release, included in the Apple Silicon release and Homebrew installation. - No
sudoprivileges required.
Apple’s Virtualization framework allows at most two running macOS VMs at a time per Mac across all virtualization tools (including an active macOS base-image installation). You can keep additional stopped VMs on disk and start any two at once, subject to the Apple software license.
Install
Install the prebuilt release with Homebrew:
Homebrew installs the signed, notarized Barn.app and matching CLI/helper together. No Go or Xcode installation is needed. The download installer and manual archive also include the app on Apple Silicon. Stop running Mac VMs before upgrading or replacing the app.
To develop Barn itself, see Build the Mac component.
Create your first machine
When no macOS base image exists yet, barn mac up displays the download and disk requirements before asking for confirmation:
Once you confirm, Barn completes three steps:
- Downloads the restore image from Apple (
updates.cdn-apple.com), resuming any partial transfer and verifying Apple’s published SHA-256 digest. - Installs macOS once into an unbooted base image, temporarily using one of the two macOS VM slots during installation.
- Clones
mac1from the base image using APFS copy-on-write, boots the guest, configures your user account, and waits until SSH and passwordlesssudoare ready.
Subsequent VMs clone the prepared base image in seconds without repeating the IPSW restore. Barn pins initial setup to macOS 27.0 (26A428); use barn mac image update when you want to adopt a newer macOS 27 build.
If you already have a local copy of Apple’s restore image, pass --ipsw to skip the download (Barn clones it without copying if it resides on the same APFS volume):
In non-interactive scripts, pass --yes to authorize the 25 GiB download, or run barn mac setup ahead of time to prepare the base image without creating a VM. If you start a new VM with --no-wait (which returns as soon as the VM process starts), run barn mac up NAME without --no-wait to finish SSH and sudo provisioning before calling ssh or exec.
Work in the machine
Shell and commands
By default, the guest administrator account matches your host macOS username (override with --user at creation time). Place -- before the remote command: ssh passes a command string to the guest shell, while exec passes the program and arguments directly (use sh -c for shell pipelines or redirection; see the SSH/exec contract). Both return the remote command’s exit status, and --json captures stdout, stderr, and exit_code:
See the Mac command reference for the complete JSON schema.
Desktop
barn mac open launches a native window that resizes the guest display dynamically (use View → Enter Full Screen for full-screen mode). Closing the window leaves the VM running in the background; run barn mac open again to reopen it, or to boot a stopped VM and open its display.
While the guest window has focus, keyboard shortcuts are sent to the guest OS, so use the macOS menu bar for host actions:
| Menu item | Action |
|---|---|
| Machine → Share Clipboard | Toggle plain-text clipboard sync for the current session |
| Machine → Restart… | Restart macOS inside the guest |
| Machine → Shut Down… | Perform a clean guest shutdown (equivalent to barn mac stop) |
| Window → Keep Running in Background | Hide the desktop window while keeping the VM running |
| Barn → Quit Barn… | Choose whether to keep the VM running in the background or shut it down |
When you log out of or shut down the host Mac, Barn requests a clean guest shutdown and powers off the VM if it does not stop before the timeout.
Each VM also generates a random password for the macOS lock screen and GUI administrator prompts. Copy it directly to your host clipboard without printing it to the terminal:
Clipboard
Clipboard sharing syncs plain text across focus changes over the VM’s SSH channel without installing extra guest agents: focusing the guest window syncs text copied on the host Mac, and switching back to a host app syncs text copied inside the guest. Concealed items from password managers, images, and files are never transferred.
To disable clipboard sharing persistently for a VM, run barn mac configure mac1 --clipboard off (applied on the next start).
Shared folders
Pass one or more --share flags when creating a VM to mount host directories inside the guest under /Volumes/My Shared Files/<name>:
The share name defaults to the directory’s basename, and appending :ro mounts it read-only. Each shared path must resolve to an existing directory (symlinks are supported); Barn never creates or deletes shared host directories. To add or remove shares on an existing VM, stop it first and run barn mac configure:
Because VirtioFS on macOS guests can briefly cache file contents after host-side edits, use scp or rsync to copy files onto the guest disk when a build requires immediate byte-level consistency.
SSH from other tools
When the first Mac VM becomes ready, Barn adds a marked Include line to ~/.ssh/config so ssh mac1, scp, rsync, and IDE Remote-SSH extensions work out of the box using each VM’s dedicated key and pinned host key:
If ~/.ssh/config is a symlink managed by a dotfile tool, Barn leaves the file untouched and prints the Include line for you to add. Re-enable automatic integration after --remove with barn mac ssh-config --install. If your personal ~/.ssh/config already defines a Host alias with the same name as a VM, Barn preserves your alias and writes its managed entry by IP address only.
Multiple machines
Assign each VM a lowercase alphanumeric name (starting with a letter, with optional internal hyphens). Creation flags (--cpu, --memory, --disk, --user, --share) apply only when creating a new VM:
When you omit the VM name, commands target the sole existing VM or mac1 (and ask you to disambiguate when multiple VMs exist). If you request a --disk size that differs from the prepared base image’s capacity, Barn installs a new base image at that capacity from the restore image first.
Each VM gets its own /24 private subnet starting at 10.10.20.0/24 (guest IP .10), automatically skipping subnets that overlap with your LAN, VPNs, the Linux lab, or other Mac VMs. If two Mac VMs are already running, starting a third fails immediately and suggests a VM to stop:
Everyday lifecycle
Use barn mac stop --force for an immediate power-off, or barn mac start --recovery to boot into macOS Recovery with the desktop window open.
barn mac up never mutates an existing VM’s specification—passing changed creation flags on an existing VM returns a hint pointing to barn mac configure:
Stop the VM before changing CPUs, memory, shared folders, or subnet with configure (clipboard settings can be toggled while running):
To reset a VM’s disk to a clean clone of the base image while preserving its name, account, hardware settings, shares, and IP, run barn mac recreate. To delete the VM completely, run barn mac destroy. Both commands ask for typed confirmation on a terminal; pass --yes in non-interactive scripts:
| Operation | Guest disk and installed apps | Hardware settings, IP, and account |
|---|---|---|
stop / start, restart, repeated up |
Preserved | Preserved |
configure |
Preserved | Updated as requested |
recreate |
Replaced with a fresh macOS clone | Preserved (generates new login password and SSH keys) |
destroy |
Deleted | Deleted (base image is retained) |
macOS versions and disk space
Run barn mac image update to query Apple for the newest supported macOS 27 build, download its IPSW, and prepare a new default base image for future VMs. Existing VMs stay on their current build until you run barn mac recreate NAME --update (if a VM uses a custom disk size such as 200G, prepare the matching base image first with barn mac setup --disk 200G).
Use barn mac image prune to inspect unused non-default base images, adding --installers to include downloaded .ipsw files and --yes to delete them:
Because APFS clones share physical storage blocks with the base image, ON DISK and per-VM disk figures overlap and do not sum linearly.
Troubleshooting
Run barn mac doctor to check host compatibility, the native Barn.app bundle, base images, and every VM, and use barn mac logs [name] to inspect startup, network, and Virtualization framework logs.
| Symptom | Resolution |
|---|---|
network … overlaps route … on start |
A VPN or new host route now overlaps the VM’s subnet. Run barn mac configure NAME --subnet auto. |
macOS allows 2 macOS virtual machines at a time |
Stop one of the running Mac VMs (barn mac stop NAME) or quit another tool’s macOS VM. |
Third-party SSH client reports No route to host for ssh mac1 |
Grant Local Network access to your terminal/IDE in System Settings → Privacy & Security → Local Network, or use /usr/bin/ssh (barn mac ssh and exec use Apple’s system binary). |
mac_runner_missing or mac_runner_protocol |
Keep barn, barn-hosts-helper, barn-mac-runner, and Barn.app from the same make mac-build output directory together. |
| Starting a VM fails from a remote SSH session | Run barn mac inside a terminal attached to the Mac’s logged-in graphical desktop session with the login keychain unlocked. |
Apple Account sign-in inside macOS guests is not reliably supported by Apple’s Virtualization framework, and USB passthrough, snapshots, and VM suspend/resume are not supported.
Clean up
Destroying the last Mac VM automatically cleans up its ~/.ssh/config entries while keeping the default base image. For a complete removal of all Mac VM state:
- Destroy all Mac VMs (
barn mac destroy ...) and runbarn mac ssh-config --remove. - Delete
$BARN_HOME/mac(default~/.barn/mac). - Optionally remove
~/Library/Preferences/com.pgsty.barn.plist(io.pgsty.barn.mac-runner.plistin0.9.0), which stores desktop window geometry.
4 - Daily Operations
This guide covers day-to-day Linux lab management. For macOS guests, see the macOS VM guide.
Inspect and access
These commands read the active deployment under BARN_HOME (default ~/.barn) and work from any directory when that path points to the same location. If you set BARN_HOME yourself, use an absolute path across working directories. barn status lists each node’s image and resource allocation (including any software-emulated tcg notice), while barn status --verbose adds guest architecture, accelerator, loopback SSH port, and QEMU PID.
When you run barn up (including on a subset of nodes), Barn refreshes the ~/.ssh/barn_config aliases for the entire applied deployment so ssh meta and peer aliases stay current. You can also regenerate those aliases at any time with barn ssh-config --install.
Commands that reconcile configuration—plan, up, reload, resize, and recreate—locate the inventory in this order:
- An explicit
-f /path/to/inventory.ymlflag (required when bothbarn.ymlandpigsty.ymlexist in the same directory and you wantpigsty.yml). - The first matching file in the current working directory (
barn.yml,barn.yaml,pigsty.yml, thenpigsty.yaml; parent directories are never searched). - The previously applied deployment specification in
BARN_HOME(exceptbarn validate, which always requires a file).
Re-running barn up retries any unfinished guest setup stages and updates guest helper scripts in place without restarting healthy VMs. Any remaining guest limitations or automatic test-disk repairs are surfaced in the terminal summary and under nodes[].warnings / nodes[].repairs in JSON/YAML output (see Data disks).
Stop and start
barn start boots stopped VMs, re-verifies running ones, and updates SSH aliases if any automatic loopback port was reassigned. barn reload validates the inventory and startup dependencies before stopping selected nodes, then runs barn up for that selection.
reload is a controlled stop-and-boot cycle. It can add new nodes and start stopped nodes, but it refuses existing-node changes to CPU, memory, image, disks, shares, addresses, or other VM definitions before stopping anything.
For CPU or memory changes, edit vm_cpu or vm_mem and run barn resize. Supported increases can use hotplug; decreases and unsupported backends use a stop/start fallback while preserving VM identity and disks. Barn 1.2.0 also supports in-place root growth with resize -D. Image, data-disk, network, and share changes require recreate.
If online resize is interrupted after hotplugging, barn status reports that live CPU and memory may differ from the applied configuration (reason: resize_incomplete). Run barn resize NODE again, or run barn restart NODE to return to the committed resources. Offline resize holds the deployment lock while stopping and updating the node.
Passing --no-wait to a start command returns as soon as QEMU starts, skipping readiness checks, guest recovery, and /etc/hosts or control-node SSH updates until your next barn up.
Change the deployment
barn plan compares your inventory against the applied state and reports image selections, aggregate resources, drift reasons, and disk impact:
| Detected change | Meaning | How to apply |
|---|---|---|
create |
Node is in the inventory but not yet provisioned | barn up |
resize |
Node CPU or memory changed | barn resize <node> |
recreate |
Node image, disk, share, or other VM specification changed | barn recreate <node> |
missing |
Provisioned node was removed from the inventory YAML | Restore the YAML entry, or run barn destroy <node> |
In JSON output, start, create, resize, recreate, and missing are node lists. The top-level action summarizes the plan as one of create, start, converge, resize, recreate, blocked-removal, repair, or none; blocked, when present, is an explanation string. whole_deployment: true marks a deployment-wide recreation; follow the suggested command so that new nodes are included alongside existing ones.
Editing or deleting YAML entries never destroys a VM automatically, and changes to service-level Pigsty variables that Barn does not consume report action: none. Interactive recreate and destroy prompt you to type the command name to confirm; pass --yes (or --force) in non-interactive scripts.
recreate is the explicit replacement path. Barn validates the new image, network, shares, and persistent-disk attachment contract first, then destroys the selected VM artifacts and boots a fresh VM from the desired inventory. Root and non-persistent data disks are replaced; compatible persistent disks remain attached. The replacement gets a new VM identity and refreshes SSH host-key state.
Without node names, recreate replaces every node in the deployment and lists them in the confirmation. It refuses an inventory that no longer lists an existing node before any VM stops (exit 4, reason: nodes_removed): remove that node explicitly with barn destroy <node> or add it back to the inventory. Barn checks the scope again under the destruction lock and reports deployment_changed if the applied state changed during preflight.
Apply changes to selected nodes
You can edit several nodes in the inventory and apply them in batches:
plan, up, reload, recreate, and resize with explicit selectors retain every unselected peer’s applied definition, including peers changed or temporarily omitted in YAML. Images for uncreated, unselected nodes are resolved when you select those nodes. The entire inventory must still parse correctly, and selected changes must not conflict with applied addresses, aliases, control-node roles, or deployment-wide settings.
Without selectors, Barn evaluates the whole inventory: CPU and memory changes use resize, other changed existing VMs require recreate, and missing VMs require restoring their definitions or explicitly destroying them.
Concurrent commands
For parallel node work within one command, Barn 1.2.0 adds --parallel/-p with a CPU-based default; see Lifecycle concurrency for the supported commands and the difference from Barn 1.1.0.
Mutating commands (up, start, stop, restart, reload, resize, recreate, destroy, purge, and provision) acquire the deployment lock in BARN_HOME, waiting up to 10 minutes (provision --timeout can impose a shorter deadline) if another operation is in flight. While waiting, Barn prints the lock holder’s command, PID, and start time; if the wait times out, it exits with code 4 (error: conflict, reason: deployment_busy). The lock releases automatically when the holding process exits—never delete lock files manually.
Read-only and access commands (status, ssh, exec, ssh-config, and the state read in hosts) read the last published state without waiting on the lock. If a mutating command is currently running, barn status includes a note indicating the active operation. See Troubleshooting for interrupted runs.
Destroy
Pick the teardown command that matches the scope you want to remove:
barn destroy <node>deletes only the named node and refreshes SSH aliases for the remaining nodes. If it removes the control node, the first remaining node becomes the control node, sossh-config,hosts,exec, andprovisionkeep working; setadmin_ipin the inventory to that node’s address (and remove the destroyed entry unless you wantupto create it again), then runbarn upto install its control SSH access.barn destroyremoves all VMs along with their root overlays and non-persistent data disks, the deployment state, and the SSH aliases Barn installed, while retaining persistent disks, deployment keys, cached images, and host networking. Runbarn upagain to build a fresh lab from the inventory.barn destroy --delete-persistentandbarn destroy --purgeapply to the entire deployment (they cannot be combined with node names).--purgealso removes persistent disks, SSH keys, and deployment state.barn purgeimmediately removes the entire Linux lab, verified retained persistent disks, keys, and deployment state; the image cache and host network remain. To review the node list and deletion scope first, usebarn purge --ask:y/yesconfirms;n/no, an empty line, or EOF cancels. It accepts no--yes,-y, or--force.
To remove the shared Linux host network after all VMs are gone:
See Image Repositories for image cache management, or Uninstall and Clean Up for a full host teardown.
5 - Storage, Files, and Service Access
This guide covers disk configuration, file transfer, and service access for Linux labs. It builds on the Linux Quick Start using node meta at 10.10.10.10.
Configure disks before creating the VM
By default, every Linux node gets a 64 GiB root overlay disk and one 128 GiB non-persistent data disk mounted at /data. vm_disk sets the root disk capacity in GiB (as an integer like 64 or with a unit like 64GiB), while vm_disks replaces the default data-disk list (vm_disks: [] disables extra data disks).
For a new single-node lab, save the following inventory as storage.yml:
If meta already exists with a different disk layout, barn up reports drift; inspect barn plan and back up any needed files before running barn recreate meta (which replaces root and non-persistent disks).
Validate the inventory, provision the VM, and verify the mounted filesystems:
Disk sizes (size: 64 or size: 64GiB) are thin-provisioned virtual capacities that consume host space as data is written. With fs: auto, Barn formats new disks as XFS when mkfs.xfs is available in the guest and falls back to ext4 otherwise. Check barn up warnings and findmnt to confirm that every data disk mounted cleanly.
What survives each operation
| Operation | Root and non-persistent disks | Persistent disks (persistent: true) |
|---|---|---|
stop then start, or restart |
Retained | Retained |
Repeated up on a healthy node |
Retained | Retained |
Compatible recreate |
Replaced | Retained and reattached |
Ordinary destroy |
Deleted | Retained |
Whole-deployment destroy --delete-persistent or purge |
Deleted | Deleted (including retained disks) |
Barn matches retained persistent disks by disk identity and specification: to reattach a retained disk across recreate or after destroy, keep the node name, mount path, size, and fs type identical. Barn rejects mismatched retained disks rather than attempting in-place resizing, renaming, or filesystem conversion.
Persistent disks are still disposable test storage. persistent: true preserves the disk across ordinary destroy and recreate runs, but during guest recovery barn up still resets an ext4 or XFS data filesystem when the filesystem checker reports recognized corruption (reporting the reset in nodes[].repairs). A disk with a partition table, a signature without a UUID, unsupported filesystem features, or an unknown checker failure keeps its data and reports a warning, and transient device absences, failed probes, busy mounts, and host I/O errors never trigger formatting. Keep backups of valuable data on the host.
Newly formatted data filesystems are owned by root. You can verify that data written to /data persists across a stop and start cycle:
For macOS guest folder sharing, see the macOS VM guide.
Copy files over managed SSH
Export a standalone OpenSSH configuration from the running deployment to use ssh, scp, or rsync directly:
The exported fragment points to the current loopback SSH port, deployment key path, and instance-scoped known_hosts file without embedding private key material. Regenerate barn-ssh.conf if you recreate a node or its loopback port changes, or run barn ssh-config --install so ssh meta and scp work without -F.
Reach services inside the guest
When a service inside the guest listens on the node’s fixed private IP (for example, PostgreSQL on 10.10.10.10:5432) and the guest firewall permits it, your host and peer nodes can connect to that IP directly.
If a service binds only to 127.0.0.1 inside the guest, forward a local host port over SSH:
While that command remains running, connect local clients on the host to 127.0.0.1:15432 (press Ctrl-C to close the tunnel).
SSH aliases (ssh meta) apply only to OpenSSH tools. If you also want browsers, psql, or other host applications to resolve node names and vm_alias entries via /etc/hosts, preview and apply the optional hosts integration:
barn hosts install --yes updates /etc/hosts on the local host (requesting sudo when needed); re-run it after adding nodes or changing IPs.
Barn inventories do not use vm_ports or vm_forwards—connect via the fixed-IP network or OpenSSH port forwarding. Because management SSH runs over an independent loopback port, barn ssh and -L tunnels remain usable even if the fixed-IP bridge reports a limitation.
Host directory sharing
Linux and macOS hosts can share directories with Linux guests through QEMU Virtio-9p. Set vm_shares under all.vars or a host entry before the first barn up:
host accepts paths relative to the inventory’s real file, ~/, and directory symlinks. The directory must exist, be accessible, and not overlap BARN_HOME; it need not belong to the Barn user. Multiple guests may write the same tree, with writes coordinated by the user.
Host QEMU and the guest kernel must support 9p. Writable shares also depend on guest permissions; failed writable mounts fall back to read-only with a warning without changing host ownership. After changing existing shares, run barn recreate <node>. Native macOS guests use VirtioFS through barn mac up --share or barn mac configure --share.
See Linux Configuration for the complete disk and share schema.
6 - Image Repositories
This guide covers Linux guest image selection, mirrors, static repositories, and cache management.
With the default inventory, barn up automatically resolves u24:stable for your host architecture and downloads the matching verified qcow2 image on demand. Barn starts with the signed image catalog embedded in the binary (revision 2026110502, 17 artifacts across 9 distribution families); run barn update whenever you want to fetch, verify, and activate the latest catalog from the repository (or barn image sync to load an exact catalog URL or local file).
Choose an image
Inspect the available distribution families and channels:
Barn provides nine built-in distribution families: el7, el8, el9, el10, d12, d13, u22, u24, and u26. A bare family name such as el9 selects the stable channel, name:channel selects an explicit channel, and name@version pins an exact immutable build. You can also set a numeric prefix in vm_version to pick the newest matching release along dot boundaries:
Here "9.8" selects the newest 9.8.x build in the active catalog, while "9" selects the newest 9.x build (quote numeric vm_version values in YAML so they remain strings). Do not combine vm_version with a :channel or @version suffix in vm_image.
For strict reproducibility across catalog updates, pin the full version string reported by barn image info:
After changing vm_image or vm_version, preview the change with barn plan. Existing nodes keep their current root disk until you run barn recreate <node>; updating the catalog with barn update only affects newly created or recreated nodes.
Temporary overrides and architecture
Use -I (--image) and -A (--arch) to override image and architecture settings for one command invocation.
Guests default to the host architecture unless explicitly overridden by vm_arch or --arch/-A. Precedence is -A → vm_arch → host architecture. -A native overrides a fixed inventory architecture and follows the host again. amd64 accepts x86_64 and x64 aliases; arm64 accepts aarch64 and a64.
-I u24 replaces selected nodes’ vm_image and vm_version without changing the architecture. These overrides leave the inventory intact. To keep them, set vm_image and all.vars.vm_arch, removing superseded vm_version, or generate a new inventory with barn init -I u24 -A amd64. Existing nodes still require recreate to change image or architecture; architecture changes must include all existing nodes. See the configuration reference.
barn image list displays all architectures. Standalone info and pull default to the host architecture without reading inventory vm_arch; use --arch/-A to override it (legacy -a also works). A missing architecture variant is an error, not a reason to select another architecture. Barn currently accepts only amd64 and arm64 guests:
el7is supported only on nativelinux/amd64hosts.el8onarm64automatically runs under QEMU TCG software emulation on Apple Silicon because the stock RHEL/Rocky 8arm64kernel requires a 64 KiB page granule that macOS HVF does not support. See Runtime rules for foreign-architecture emulator requirements.
All image versions in the embedded catalog carry supported status except the EOL el7 compatibility build, which is marked deprecated.
Use a mirror
Release builds default to https://repo.pigsty.io/barn. Pass --mirror to use the China mirror (https://repo.pigsty.cc/barn), or --repo to point at a custom repository URL or local directory:
To set a default repository for your current shell session, export BARN_REPO:
Repository selection follows the precedence --repo → --mirror → BARN_REPO → global default (https://repo.pigsty.io/barn). Both official repositories and any plain http:// repository require a valid Minisign signature (catalog.json.minisig); explicit local directory paths and custom https:// endpoints may use an unsigned catalog.json. Every image download is verified against the catalog’s byte size, SHA-256 digest, and qemu-img structural checks.
When downloading from either official repository, Barn automatically retries transient network errors, resumes partial transfers, and falls back to the peer official mirror if an artifact is unreachable. Custom --repo endpoints never fall back to external servers.
Each repository root maintains its own active catalog state under BARN_HOME. When you point --repo at a custom repository that defines new image entries, run barn update --repo <root> first to activate its catalog before running plan or up.
Build a static repository
A Barn image repository is a plain directory that you can serve over static HTTP/HTTPS, copy with rsync, or read directly from a local path:
/srv/barn
- barn/
- repo.yamlHuman-maintained image definitions and channels
- catalog.jsonGenerated catalog with SHA-256 and file sizes
- catalog.json.minisigMinisign signature (required for official and HTTP repos)
- images/
- d13-1-arm64.qcow2Verified cloud-init qcow2 base image
repo.yaml is the sole human-edited file. For the single arm64 image above, create /srv/barn/repo.yaml:
Place your cloud-init-capable qcow2 image at /srv/barn/images/d13-1-arm64.qcow2 (relative roots, directory symlinks, and shared writable directories are supported), then generate and verify catalog.json on a host with qemu-img installed:
barn repo scan inspects the directory layout read-only, while barn repo build runs qemu-img check and writes catalog.json with exact filenames, SHA-256 digests, compressed sizes, and virtual capacities. Increment revision whenever you update repo.yaml or add images, and upload immutable .qcow2 files before publishing the updated catalog.json (and .minisig signature).
Activate and test the local repository:
Pass --repo /srv/barn (or export BARN_REPO=/srv/barn) to plan, up, and recreate, and set vm_image: d13@1 in your inventory. To revert /srv/barn back to the binary’s embedded catalog while keeping its anti-rollback high-water mark, run barn image reset --repo /srv/barn.
Import a local image and prune the cache
To use a single custom qcow2 image without creating a repository, import it into Barn’s local cache with a local- alias. The recorded architecture defaults to the host:
--name (must start with local-), --boot (uefi or bios), and --source-user are required together when registering an alias; omitting them caches the verified qcow2 bytes by content digest without creating an alias. The image must already include cloud-init support for Barn’s first-boot provisioning. Named local-* aliases are immutable—register a new local-* name whenever you rebuild the image, and reference it in barn.yml with vm_image: local-mybase.
Named imports accept -A, for example barn image import /path/to/arm64.qcow2 --name local-arm64 --boot uefi --source-user ubuntu -A arm64. This records your declaration; it does not convert the image or detect its guest CPU. Set inventory vm_arch or the lifecycle command’s -A to match when using it. -A requires --name on import.
To reclaim disk space from unreferenced images and interrupted download staging files:
barn image prune (which requires qemu-img) preserves all images listed in the selected repository’s active catalog, all base images used by existing nodes in BARN_HOME, and all registered local-* aliases.
See Linux Images for catalog signature rules, anti-rollback protection, and cache layout, or Image Pipeline for building new base images from upstream cloud releases.
7 - Automation and Guest Scripts
This guide shows how to drive Barn from unattended scripts and CI pipelines. Run all commands as the Unix user who owns the deployment, and pass the same -f <inventory> and BARN_HOME across invocations.
Prepare a predictable lab
Keep your inventory file in version control and pin vm_image to an exact version (such as vm_image: u24@20261017.0.1) so catalog updates never alter your base image mid-pipeline. Passing -f explicitly also prevents first-run setup from relocating an unedited default template to a different subnet. If you use a custom image repository, activate its catalog first with barn update --repo URL and pass the same --repo to setup and up.
Generate and validate the inventory before running host setup:
Once you have reviewed the host plan and ensured non-interactive sudo credentials (or a NOPASSWD policy) are available, prepare the host and bring up the lab:
For a generated inventory, barn init [template] --image <reference> writes all.vars.vm_image, so every node inherits the same image. References can be catalog aliases (el9), channels (u24:stable), or version selectors (u24@20261017.0.1). barn setup [template] --image <reference> also selects an image during generation, but rejects this generation flag when using an existing inventory.
--image/-I and --arch/-A share consistent spellings: barn init full -I u24 -A amd64 saves both choices in a new inventory; the same flags on validate, plan, up, reload, recreate, and resize only override desired state for that invocation. For example, preview barn plan -f barn.yml -I u24 -A arm64 --json, then use the same overrides when applying it. Setup’s -I/-A remain limited to template generation.
The same commands also accept --cpu/-C, --mem/-M, --scale/-S, and --disk/-D. Each specification follows CLI flags → nonempty BARN_* environment variables → inventory → defaults. Reuse the same flags and environment for validate, plan, and the operation that applies the plan.
Without an architecture flag, Barn uses BARN_ARCH, then inventory vm_arch, falling back to the host when unset; -A native overrides both and follows the host. Existing VMs require recreate to change image or architecture. For repeatable CI, save vm_image, vm_arch, and an exact image version; see the configuration reference.
barn setup --yes accepts the host-preparation plan without asking. On a terminal, up, start, restart, and reload show the same plan and ask once before installing packages or the Barn network; without a terminal they only report what is missing, so run barn setup --yes before them.
Validate JSON output alongside the exit code
Barn writes structured JSON/YAML payloads to stdout and human diagnostics to stderr. Because barn up returns exit code 0 when management SSH is ready—even if an optional stage such as a secondary data disk, Virtio-9p share, or peer SSH config reported a limitation (nodes[].warnings) or reformatted a damaged test disk (nodes[].repairs)—automation scripts should inspect the JSON payload alongside the exit code:
When a subsequent pipeline step requires ready guests, omit --no-wait on barn up (barn status --json reads cached state without re-probing guest SSH).
Exit codes and command-specific payloads
Pair CLI exit codes with each command’s JSON schema:
- Exit
2(usage): Missing inventory on first run, invalid flags, unknown image aliases, ordestroy/recreatewithout--yeswhen stdin is not a terminal (purgeruns without asking). - Exit
4(conflict): Inventory drift requiring explicit action (reason: recreate_requiredornodes_removed), applied state that changed during arecreatepreflight (reason: deployment_changed), or a deployment lock timeout (reason: deployment_busyafter waiting up to 10 minutes). - Exit
5(partial): Multi-nodeuporprovisionwhere some nodes succeeded and others failed—inspectnodes[]orresults[]before retrying. - Exit
7(integrity): A digest, signature, or identity check failed, including a catalog signature or signed revision that does not verify (reason: catalog_signatureorcatalog_equivocation). - Command-specific reports:
barn doctor --jsonexits0when host compute passes even if aclass: networkcheck reports an error; checkchecks[]andbarn network status --jsonbefore relying on the private bridge.barn sshandbarn execreturn the remote command’s exit status (or255on OpenSSH transport failure) and recordsuccess,exit_code,stdout, andstderrin--jsonmode.networkandhostsinstall/uninstallwithout--yesonly print the plan and exit0when stdin is not a terminal or the output is--json/--yaml; checkappliedin the result, or pass--yes.
Run single commands or batch scripts
Always place -- between the node selector and the remote command, and put Barn flags (--json, --verbose) before --:
Pass the program and its arguments as separate tokens to barn exec, using sh -c explicitly for pipes, redirection, or shell variables (see SSH passthrough and completion).
To run a health check or setup script across multiple running Linux nodes, save a local Bash script (a regular file or symlink to one, up to 4 MiB):
Execute it with barn provision:
Omitting node selectors runs the script on every node in the deployment (all target nodes must already be running). Barn streams the verified script bytes directly to Bash over SSH without writing a temporary script file in the guest, and records the script’s SHA-256 in the audit result.
- Concurrency and timeouts: Serial by default;
--parallelaccepts positive integers, with workers capped at the selected node count.--timeoutbounds the whole operation, defaults to1h, and accepts any positive duration.--sudouses non-interactivesudo -n. - Output capture and idempotency: Each node captures up to 1 MiB of
stdoutand 1 MiB ofstderr(settingstdout_truncated/stderr_truncatedwhen exceeded). Because partial runs leave completed guest changes in place, write idempotent scripts that are safe to re-run. - Exit codes:
provisionexits5when some nodes succeed and others fail, passes through a single target’s positive non-255exit code on failure, and exits1otherwise.
Pair the lab with Pigsty
Barn and Pigsty share the same Ansible YAML format. While barn init generates VM hardware topology, Pigsty provides complete service inventories (pigsty.yml) for PostgreSQL, Redis, and monitoring stacks. Provision the VMs with Barn first:
During barn up, Barn provisions the guest administrator account and installs the deployment private key on the control node designated by admin_ip, configuring its ~/.ssh/config so Ansible can reach all peer nodes over their fixed private IPs (see Security and Trust). Once barn up completes, SSH into the control node and run Pigsty’s deployment playbooks.
8 - Troubleshooting
This guide covers Linux lab diagnostics. For macOS guests, run barn mac doctor and see the Mac troubleshooting section.
Start by collecting the three JSON diagnostic reports (barn status also reconciles interrupted process state when no other command holds the lock):
barn doctor exits 0 whenever host compute checks pass, even if a class: network check reports an error—inspect both checks[] and barn network status --json before assuming barn up can attach to the private network.
Download and PATH problems
The release installer downloads binaries from GitHub Releases (--mirror only selects the guest image repository). If your network requires a proxy to reach GitHub, export HTTPS_PROXY or ALL_PROXY in your terminal session (macOS System Settings proxy entries are not inherited by CLI tools automatically).
The user-scoped installer places binaries in ~/.local/bin. If barn is not found or runs an older version after installation, verify your PATH:
Always keep barn and its packaged barn-hosts-helper from the same release in their relative directory layout.
No inventory found
When neither an inventory file nor an applied deployment exists, an interactive barn up generates a starter barn.yml. To use an existing file, run plan, up, or validate in the directory containing barn.yml / pigsty.yml or pass -f /path/to/file (or generate a template first with barn init).
Without -f, plan, up, reload, resize, and recreate check the current directory for barn.yml, barn.yaml, pigsty.yml, and pigsty.yaml in that order, falling back to the applied specification in BARN_HOME only when none of those files exist. If the first matching file contains syntax errors, Barn fails immediately rather than falling back; pass -f pigsty.yml when an older barn.yml sits in the same directory.
If barn status reports no deployment state found, the active BARN_HOME has no applied deployment (either fresh or previously purged).
init output paths and symlinks
barn init and barn setup work through directory symlinks, and barn init -o ./lab/config/barn.yml creates missing parent directories. An existing output file requires --force. Barn never writes through an output-file symlink: with --force it reports will not overwrite …: it is a symlink, so pass the link’s target path instead:
Setup needs sudo
Before prompting for a password, barn setup prints the exact host mutation it is about to perform and hands the interactive terminal directly to sudo. Passing --yes auto-confirms Barn’s plan prompt, while sudo authentication itself still requires an interactive terminal, cached credentials, or a NOPASSWD sudoers rule. Run barn setup --dry-run to preview the host plan without executing it.
On macOS, barn setup downloads and verifies the pinned socket_vmnet package before requesting sudo, so a network failure never prompts for a password.
Native acceleration or compatibility runtime is unavailable
Barn requires HVF on macOS or KVM on Linux for native hardware acceleration, and uses QEMU TCG software emulation only when you explicitly request a foreign vm_arch or run an image covered by a built-in compatibility rule (such as el8 arm64 on Apple Silicon). It never falls back to TCG after a native HVF/KVM failure.
Homebrew’s qemu formula includes both arm64 and amd64 system emulators, whereas Linux barn setup installs only the host-native emulator—install the matching qemu-system-* binary and UEFI firmware manually before running foreign-architecture guests on Linux.
Network is partial or invalid
When the Barn host network is intact but stopped, an interactive barn up includes the restart in its host-preparation plan and asks once before applying it; without a terminal, run barn setup --yes. If barn network status reports a partial or invalid state, inspect and apply Barn’s managed cleanup plan instead of deleting system network files by hand:
If the Linux bridge smoke test fails during setup, Barn rolls back the network changes automatically; only an explicit automatic rollback failed message requires manual cleanup.
On macOS, barn setup automatically repairs a missing or overly restrictive /var/log/barn-vmnet directory (root:wheel 0755), while refusing to touch a symlink, foreign owner, or group/world-writable directory—follow the exact remediation command printed by barn network status.
Linux bridge helper fails
On Debian and Ubuntu hosts, check the ownership and setuid mode on /usr/lib/qemu/qemu-bridge-helper (expected root:<caller-accessible-group> 4750):
Plan reports recreate or missing
recreate: The node’s inventory specification changed. Inspectbarn planand back up any data on the root or non-persistent disks before runningbarn recreate <node>(pass--yesin non-interactive scripts).missing: A provisioned node was removed from the YAML inventory. Either restore its YAML entry or runbarn destroy <node>to delete the VM. While a node is missing,barn recreatewithout node names refuses to run before any VM stops (exit4,reason: nodes_removed).
With node selectors, barn plan node-1 and barn recreate node-1 retain unselected peers’ applied definitions, so an unrelated peer edit does not have to be rebuilt at the same time. Real conflicts in addresses, aliases, control-node roles, or deployment-wide settings still need to be resolved.
A node did not become ready
Readiness requires a working management SSH connection and a verified guest instance UUID. When a node fails to create, boot, or become reachable over management SSH, barn up reports the failing node and stage and exits with code 5. Inspect its logs:
Secondary guest stages—data disks, Virtio-9p shares, hostname, /etc/hosts, control-node SSH, and the fixed-IP private interface—run independently after management SSH comes up. If one of those stages fails, barn up exits 0 and records the limitation under nodes[].warnings:
| Reported limitation | Remediation |
|---|---|
| Data disk unavailable | Resolve the missing device, filesystem tool, busy mount, or host I/O error, then re-run barn up. A disk with a partition table, a signature without a UUID, or unsupported filesystem features keeps its data and stays unmounted |
| Shared directory is read-only | Check host and guest write permissions, then re-run barn up |
| Guest hosts or control-node SSH incomplete | Re-run barn up to refresh the managed files inside the guest |
| Private interface unavailable | Check barn network status, repair the host bridge/vmnet, and re-run barn up |
Re-running barn up retries only the unfinished stages without restarting healthy VMs. It initializes blank data disks and resets an ext4 or XFS data filesystem only when the filesystem checker reports recognized corruption (see Data disks). Pass --rollback to barn up if you want failed initial preparation artifacts removed in the same run.
For Linux shared folders, both QEMU and the guest kernel need 9p support. A valid host path cannot make an unsupported guest kernel mount 9p; use SSH/SCP/rsync or a kernel with 9p support. This applies on macOS hosts as well as Linux hosts; native macOS guests use VirtioFS separately.
SSH fails
Check barn status, barn ssh-config, and barn logs <node>.
- Deployment SSH keys: If the host’s
.pubfile is missing, Barn derives it from the intact private key on startup. If the private key itself is missing, restore it from backup—Barn never generates a replacement key for existing VMs. If the control node’s copy of the private key is missing,barn upreports acontrol-sshwarning while host-to-guest management SSH continues to work. - Port reassignment and host keys: If another process occupies a stopped VM’s loopback SSH port, the next
barn startorbarn uppicks a free port and updates~/.ssh/barn_config. SSH host-key verification is scoped to each VM instance UUID, so recreating a node never triggers staleknown_hostserrors. - Dotfile-managed
~/.ssh/config: If~/.ssh/configis a symlink or hard link, Barn writes~/.ssh/barn_configand prints theIncludeline for you to add. Ifbarn ssh metaworks butssh metafails, verify thatIncludeline. - Remote command syntax: Place
--between the node name and remote command (barn exec meta -- hostname); see SSH passthrough and completion.
Catalog or image verification fails
Barn embeds active and standby Minisign public keys and rejects unknown signers, catalog revision rollbacks, file size or SHA-256 mismatches, and malformed qcow2 files. A catalog signature or signed revision that does not verify exits 7 (error: integrity, reason: catalog_signature or catalog_equivocation); a permission or I/O error while reading a cached signature remains a runtime failure (exit 1). Always pull from a validly signed repository or register local images through barn image import --sha256 ... rather than copying files directly into ~/.barn/images.
A command was killed
Pressing Ctrl-C or sending SIGTERM cancels a command with exit 130 (cancelled). Barn sends SIGTERM to the processes it started, which sudo forwards to privileged commands, and waits at most 10 seconds for them; a descendant that ignores SIGTERM keeps running until you stop it.
After an interruption, run barn status first. If another Barn process currently holds the deployment lock, status displays a note—wait for that operation to finish before intervening.
When no command holds the lock, barn status verifies each recorded QEMU process identity (matching both PID and process start time) and reconciles the state automatically:
| Interrupted state | Automatic recovery / next step |
|---|---|
| Host rebooted or QEMU PID was recycled by an unrelated process | barn status detects the mismatched process identity and marks the VM stopped; run barn start |
barn stop was interrupted while QEMU stayed running |
barn status restores running state; re-run barn stop if you still want to shut it down |
Online barn resize was interrupted after changing the live guest |
barn status reports resize_incomplete; re-run barn resize <node> or run barn restart <node> |
Initial barn up failed during preparation |
Fix the inventory and re-run barn up -f barn.yml; Barn rolls back journaled unfinished artifacts |
barn destroy was interrupted midway |
Re-run the same barn destroy or barn purge command to finish cleanup |
If Barn cannot confirm whether a recorded process belongs to the node (or if a QEMU process is alive but its QMP socket is missing), it blocks further mutations so it never kills an unrelated process. Preserve the state directory and logs (barn logs <node> --source qemu --verbose) rather than deleting PID or lock files by hand.
When filing an issue on GitHub, include the exact command and exit code, barn version, host OS/architecture, QEMU version, and the JSON output of barn doctor, barn network status, and barn status.
9 - Build from Source
Build Barn from source when developing a change or auditing a release tag. For prebuilt CLI binaries and the native Barn.app included in the Apple Silicon release, see Install Barn.
Check out the source
Clone tag v1.2.0 to reproduce the documented release (or omit --branch v1.2.0 to work on main), and record git log -1 --oneline and git status --short alongside any build report:
Tag v1.2.0 reproduces the published release described in the Barn 1.2.0 release notes. Leave BARN_VERSION unset for a development build.
Build the CLI
Barn 1.2.0 pins Go 1.27.4 in go.mod and packaging/toolchain.env, and requires Git, Make, Bash, and standard C/POSIX build tools (compiling the CLI does not require QEMU or host-network setup):
make build compiles both barn and barn-hosts-helper into bin/.barn-releases/, embeds the helper’s SHA-256 digest into the CLI, and creates entry-point symlinks under bin/. Always use make build rather than a bare go build ./cmd/barn, and keep bin/.barn-releases/ alongside the bin/ links if you move the build output.
Without BARN_VERSION, development builds report dev, and the commit field marks modified working trees as uncommitted.
To cross-compile the Go CLI and helper for all four supported targets (darwin_amd64, darwin_arm64, linux_amd64, and linux_arm64), run make cross. Keep build artifacts (bin/, dist/, .goreleaser-*/) and lab inventories out of version control; check ignore rules before generating them in the working tree.
Run the contributor checks below against the exact checkout you intend to use. Earlier dated acceptance records are kept in Validation History.
Follow packaging/toolchain.env in the checkout being built. Formal assets use the signed and notarized release procedure.
Build the Mac component
Before rebuilding a local Mac bundle, stop any running Mac VMs that use it.
On an Apple Silicon Mac running macOS 27+ with Xcode 27+ selected for xcrun (providing the macOS 27 SDK and Swift compiler), run:
make mac-build produces a matched bundle under bin/mac (barn, barn-hosts-helper, standalone barn-mac-runner, and Barn.app) as well as bin/barn-mac-darwin-arm64.tar.gz. Run make mac-native-test to execute the Swift component test suite, and follow the macOS VM guide to provision a guest.
| Source tag | Native app bundle | Bundle identifier |
|---|---|---|
v0.9.0 |
Barn Mac.app |
io.pgsty.barn.mac-runner |
v0.9.1 and later |
Barn.app |
com.pgsty.barn |
The current CLI discovers both Barn.app and legacy Barn Mac.app bundles, whereas the 0.9.0 CLI only looks for Barn Mac.app—always use the barn CLI and native app built together in bin/mac.
Code signing and notarization
When signing environment variables are unset, make mac-build applies an ad-hoc signature for local development. For signed or notarized builds:
- Set
BARN_CODESIGN_IDENTITYto signBarn.appwith a Developer ID certificate. - Set
BARN_NOTARY_PROFILEandBARN_MAC_REQUIRE_NOTARIZATION=1to submitBarn.appfor Apple notarization, staple the ticket, and verify Gatekeeper acceptance. - With
BARN_CODESIGN_IDENTITYset,make mac-buildalso signs the Go helper before embedding its final SHA-256 in the CLI, then signs the CLI. The Mac release handbook adds joint notarization of the CLI/helper/app and verification of the exported release payload.
Run contributor checks
Running the full make check suite requires Python 3, jq, a C compiler (for -race), and the linter/scanner versions pinned in packaging/toolchain.env:
Ensure GOBIN (or $(go env GOPATH)/bin) is on your PATH, then run:
make check verifies go.mod, shell scripts, repository maintenance rules, unit and race tests, go vet, staticcheck, deadcode, golangci-lint, govulncheck, four-target cross-builds, image-pipeline and installer tests, and dependency licenses. See Contributing and Release Engineering for packaging snapshot checks.
10 - Uninstall and Clean Up
Barn manages Linux labs and macOS VMs independently. barn purge removes only the Linux deployment—it does not delete Mac VMs. Keep the barn CLI installed until you have finished removing VMs, integrations, cached images, and host networking.
Choose what to remove
| Goal | Command |
|---|---|
| Stop running VMs while keeping disks | barn stop; barn mac stop --all for Mac VMs |
| Delete a single Linux node | barn destroy <node> |
| Delete the Linux lab, keeping persistent disks | barn destroy |
| Delete the Linux lab, persistent disks, and keys | barn purge (deletes immediately; --ask enables confirmation) |
| Delete named Mac VMs | barn mac destroy <name...> (prompts for confirmation) |
Check barn status (for Linux nodes) and barn mac ls (for Mac VMs), and copy any files you want to keep onto the host before destroying machines.
Full teardown steps
-
Destroy Linux and Mac virtual machines
To discard the entire Linux lab—including retained persistent disks and deployment keys—run:
This deletes immediately. Use
barn purge --askto review the VM list and deletion scope, then entery/yesto confirm orn/noto cancel. It accepts no--yes,-y, or--force. If you also created macOS VMs, list and destroy them by name: -
Remove SSH and
/etc/hostsintegrationsWhole-deployment Linux
destroy/purgeremoves the default~/.ssh/barn_configintegration automatically. If you installed a custom named SSH fragment,/etc/hostsentries, or Mac SSH aliases, remove them:These commands remove only Barn’s managed blocks, leaving your personal
~/.ssh/configand/etc/hostsentries intact. -
Prune cached images
Preview and delete cached Linux and macOS images:
-
Uninstall Linux host networking
Preview and remove the shared Linux host network (it stops while any Linux VM is running, so destroy the lab first; Mac VM networks tear down automatically when the VM stops):
When Barn uses systemd-networkd, the uninstall leaves the global networkd unit state unchanged if other host links exist or exclusive Barn use cannot be established; the plan reports
preserve_networkd, and the applied report explains the decision inchecks.networkd. -
Uninstall the Barn application and remaining state
If you installed Barn through a package manager, remove the package:
HomebrewDebian / UbuntuRHEL / Fedora- User-scoped
install.sh: Removebarn,barn-hosts-helper,.barn-current,.barn-releases/, and.barn-install.lockfrom~/.local/bin(and remove thePATHentry from your shell rc file). - Manual archive or source build: After stopping all Mac guests, remove the extracted release directory,
bin/mac, or any copiedBarn.app(Barn Mac.appin0.9.0), plus~/Library/Preferences/com.pgsty.barn.plist(io.pgsty.barn.mac-runner.plistin0.9.0). - Manually installed hosts helper: If
/opt/barn/libexec/barn-hosts-helperwas installed manually and no other user on the host uses Barn, remove it after runningbarn hosts uninstall --yes.
- User-scoped
Delete ~/.barn (or your custom BARN_HOME) only after destroying both Linux and Mac VMs. ~/.barn holds active VM state, keys, persistent disks, and base images for both workflows; if a VM is still running or destroy fails, resolve the error with barn status / barn mac ls before deleting the directory.