bsdt
Repeatable FreeBSD development VMs from a TOML file, for working on
FreeBSD targets from Linux or macOS. It aims for the same feel as
docker compose up: describe the environment in bsdt.toml, run
bsdt up, and get the same machine every time.
bsdt boots the official FreeBSD BASIC-CLOUDINIT VM image with QEMU.
The image is downloaded once, checked against the release's
CHECKSUM.SHA256, and cached. Each project gets a copy-on-write overlay
disk on top of it, so throwing a VM away and starting fresh takes seconds.
On first boot bsdt sets up SSH access through FreeBSD's own nuageinit,
installs your packages, copies the project in with rsync, and runs your
provision commands.
NetBSD and OpenBSD are planned next, in that order.
Usage
exec and ssh work in the guest directory matching your current
directory, so running bsdt exec -- make from src/ runs it in the
guest's copy of src/.
bsdt.toml
[]
= "freebsd"
= "15.1"
# arch = "auto" # auto (match the host), amd64 or aarch64
= "4G"
= ["8080"] # or "HOST:GUEST"; bound to 127.0.0.1
# update = true # install security updates on first boot (slower)
[]
= ["rust", "git"]
[]
= ["target"] # not copied, and not deleted in the guest
[]
= ["sysrc nginx_enable=YES"]
= ["cargo fetch"] # as the bsdt user, in the synced directory
Only vm.os and vm.version are required. The man page documents every
key. Use -f other.toml to give one project several VMs, for example a
second one on an older release.
Desktop
[]
= "freebsd"
= "15.1"
= true
is enough for a sway desktop in a window. The first bsdt up installs
sway, seatd, wayvnc and the foot terminal, and every up starts them and
opens a VNC viewer on the host. Every setting under [gui] has a default;
see the man page to use your own desktop, port, resolution, modifier key
or full screen. Sway uses Alt as its modifier by default (alt+return for
a terminal), because the host desktop usually keeps Super for itself.
FreeBSD has no driver for QEMU's virtual graphics cards, so sway draws to
a headless output in software and wayvnc shares it. Input comes from the
VM's emulated USB keyboard and tablet through /dev/input, so
bsdt key and bsdt type can drive the desktop from scripts, and tools
that read input devices directly see those keys. input = true gives you
the keyboard and tablet without a desktop.
On Linux, install a VNC viewer such as TigerVNC (apt install tigervnc-viewer). On macOS, bsdt uses TigerVNC Viewer if it is installed
(brew install --cask tigervnc-viewer) and Screen Sharing otherwise.
Requirements
- QEMU:
qemu-system-x86_64orqemu-system-aarch64(plus UEFI firmware for aarch64), andqemu-img ssh,ssh-keygen,rsyncandcurl- For
gui = true, a VNC viewer
Guests that match the host architecture use KVM on Linux and the Hypervisor framework on macOS, so an Apple Silicon Mac gets a fast aarch64 FreeBSD guest. Other architectures fall back to emulation, which works but is slow.
How it works
- Images are cached in
~/.cache/bsdt/images(Linux) or~/Library/Caches/bsdt/images(macOS). SetBSDT_CACHE_DIRto put them somewhere else. - Per-VM state lives in
.bsdt/<file stem>/besidebsdt.toml: the overlay disk, an SSH key pair generated for this VM, the console log and QEMU's pid file. The directory has its own.gitignore. - First boot: bsdt writes a tiny FAT disk labelled
CIDATAwith cloud-config user data.nuageinitreads it to create absdtuser and allow the VM's key to log in asbsdtand as root. No ISO tools are needed on the host. - Access is SSH on a port forwarded from
127.0.0.1. Syncing is a one-wayrsync --deletefrom the host.
Man page
cargo install only installs the binary, so the man page is built into it
instead. bsdt man --install writes it to ../share/man/man1/ relative
to the binary, which is ~/.cargo/share/man/man1/bsdt.1. man-db searches
there automatically for anything in ~/.cargo/bin on your PATH, so
man bsdt works with no MANPATH changes. make install does both
steps. The page's source is man/bsdt.1, written by hand in
mdoc. A test checks that it mentions every subcommand and flag.
The project website lives in docs/ and is served by GitHub
Pages. make docs rebuilds it (needs mandoc):
the home page comes from templates/index.html,
and the manual page and license are rendered into the same layout. Run it
after editing the man page or templates, and commit the result.
Development
Run make to list the targets: build, install, test, lint,
docs, and publish-check/publish for crates.io releases.
To try a change against a real VM, make try builds a debug binary and
boots examples/hello-c, a C program that needs
nothing installed. EXAMPLE=hello-rust boots
examples/hello-rust instead, and EXAMPLE=gui
boots examples/gui, a sway desktop. make try-down and
make try-destroy stop and delete the VM. TESTING.md is the
checklist to run by hand before merging develop into master.
License
BSD 3-Clause; see LICENSE.