# banger One-command development sandboxes on Firecracker microVMs. **Requirements:** Linux + KVM (`/dev/kvm`), `firecracker` on PATH (or `firecracker_bin` in config). banger is tested against [Firecracker v1.14.1](https://github.com/firecracker-microvm/firecracker/releases/tag/v1.14.1) and supports any Firecracker ≥ v1.5.0. `banger doctor` warns when the installed version sits outside the tested range, and prints a distro-aware install hint when it's missing. ## Quick start ```bash curl -fsSL https://releases.thaloco.com/banger/install.sh | bash banger vm run --name sandbox ``` The installer runs as you, downloads + verifies the latest signed release, then prompts before re-execing `sudo` for the system-install step (writing `/usr/local/bin` + creating systemd units). If you'd rather audit the script first: ```bash curl -fsSL https://releases.thaloco.com/banger/install.sh -o install.sh less install.sh bash install.sh ``` Or build from source: ```bash make build sudo ./build/bin/banger system install --owner "$USER" banger vm run --name sandbox ``` That's it. `banger vm run` auto-pulls the default golden image (a pre-built Debian rootfs with sshd, mise, and the usual dev tools: Debian bookworm with systemd, sshd, Docker CE, git, jq, and mise) and kernel, creates a VM, starts it, and drops you into an interactive ssh session. First run takes a couple minutes (bundle download); subsequent `vm run`s are seconds. ## Supported host path banger's supported host/runtime path is: - Linux on `x86_64 / amd64` - `systemd` as the host init/service manager - `bangerd.service` running as the installed owner user - `bangerd-root.service` running as the privileged host helper Other setups may work with manual adaptation, but they are not the supported operating model for this repo. ## Requirements - **x86_64 / amd64 Linux** — arm64 is not supported today. The companion binaries, the published kernel catalog, and the OCI import path all assume `linux/amd64`. `banger doctor` surfaces this as a failing check on other architectures. - **systemd on the host** — this is the supported service-management path. banger's supported install/run model is the owner-user `bangerd.service` plus the privileged `bangerd-root.service` installed by `banger system install`. - `/dev/kvm` - `sudo` for the install/admin commands (`system install`, `system restart`, `system uninstall`) - Firecracker on `PATH`, or `firecracker_bin` set in config - host tools checked by `banger doctor` ## Build + install ```bash make build sudo ./build/bin/banger system install --owner "$USER" ``` This installs two systemd units, copies the current `banger`, `bangerd`, and `banger-vsock-agent` binaries into `/usr/local`, writes install metadata under `/etc/banger`, and starts both services: - `bangerd.service` runs as the configured owner user and exposes the public CLI socket at `/run/banger/bangerd.sock`. - `bangerd-root.service` runs as root and handles the narrow set of privileged host operations over the private helper socket at `/run/banger-root/bangerd-root.sock`. After that, normal daily commands such as `banger vm run` and `banger image pull` are unprivileged. This `systemd` service flow is the supported path. If you're not on a host that can run both services, you're outside the supported host model even if some pieces happen to work. The split matters: - `bangerd.service` runs as the owner user, keeps its writable state in `/var/lib/banger`, `/var/cache/banger`, and `/run/banger`, and sees the owner home read-only. - `bangerd-root.service` is the only process that keeps elevated host capabilities, and that capability set is limited to the host-kernel primitives banger actually uses (`CAP_CHOWN`, `CAP_DAC_OVERRIDE`, `CAP_FOWNER`, `CAP_KILL`, `CAP_MKNOD`, `CAP_NET_ADMIN`, `CAP_NET_RAW`, `CAP_SETGID`, `CAP_SETUID`, `CAP_SYS_ADMIN`, `CAP_SYS_CHROOT`). To inspect or refresh the services: ```bash banger system status sudo banger system restart ``` To remove the system services: ```bash sudo banger system uninstall ``` Add `--purge` if you also want to remove system-owned VM/image/cache state under `/var/lib/banger`, `/var/cache/banger`, `/run/banger`, and `/run/banger-root`. User config stays in place under your home directory: - `~/.config/banger/` — config, optional `ssh_config` - `~/.local/state/banger/ssh/` — user SSH key + known_hosts ### Shell completion `banger` ships completion scripts for bash, zsh, fish, and powershell. Tab-completion covers subcommands, flags, and live resource names (VM, image, kernel) looked up from the installed services. With the services down, resource completion silently returns nothing — no file-completion fallback. ```bash # bash (system-wide) banger completion bash | sudo tee /etc/bash_completion.d/banger # zsh (user-local; ~/.zfunc must be on fpath) banger completion zsh > ~/.zfunc/_banger # fish banger completion fish > ~/.config/fish/completions/banger.fish ``` `banger completion --help` shows the shell-specific loading recipes. ## `vm run` One command, four common shapes: ```bash banger vm run # bare sandbox — drops into ssh banger vm run ./repo # workspace at /root/repo — drops into ssh banger vm run ./repo -- make test # workspace + run command, exits with its status banger vm run --rm -- script.sh # ephemeral: VM is deleted on exit ``` - **Bare mode** gives you a clean shell. - **Workspace mode** (path given) copies the repo's git-tracked files into `/root/repo` and kicks off a best-effort `mise` tooling bootstrap from the repo's `.mise.toml` / `.tool-versions`. Log: `/root/.cache/banger/vm-run-tooling-.log`. Untracked files (including local `.env`, scratch notes, credentials that aren't gitignored) are skipped by default — pass `--include-untracked` to also ship them. Pass `--dry-run` to print the exact file list and exit without creating a VM. - **Command mode** (`-- `) runs the command in the guest; exit code propagates through `banger`. Disconnecting from an interactive session leaves the VM running. Use `vm stop` / `vm delete` to clean up — or pass `--rm` so the VM auto-deletes once the session / command exits. `--branch`, `--from`, `--include-untracked`, and `--dry-run` apply only to workspace mode. `--rm` skips the delete when the initial ssh wait times out, so a wedged sshd leaves the VM alive for `banger vm logs` inspection. ## Hostnames: reaching `.vm` banger's owner daemon runs a DNS server for the `.vm` zone. With host-side DNS routing you can `curl http://sandbox.vm:3000` from anywhere on the host — no copy-pasting guest IPs. On systemd-resolved hosts the owner daemon asks the root helper to auto-wire this and that is the supported path. Everywhere else there's a best-effort manual recipe. See [`docs/dns-routing.md`](docs/dns-routing.md). ### Optional: `ssh .vm` shortcut `banger vm ssh ` works out of the box. If you'd also like plain `ssh sandbox.vm` from any terminal (using banger's key + known_hosts), opt in: ```bash banger ssh-config --install # adds `Include ~/.config/banger/ssh_config` # to ~/.ssh/config in a marker-fenced block banger ssh-config --uninstall # reverse it banger ssh-config # show the include line to paste manually ``` banger never touches `~/.ssh/config` on its own — the daemon keeps its own known_hosts under `/var/lib/banger/ssh/known_hosts`, while `banger ssh-config` keeps the user-facing file fresh at `~/.config/banger/ssh_config`; whether and how it's pulled into your SSH config is up to you. ## Image catalog `banger image pull ` fetches a pre-built bundle from the embedded catalog. `vm run` calls this for you on demand. Today's catalog: | Name | What it is | |------|-----------| | `debian-bookworm` | Debian 12 slim + sshd + docker + dev tools | See [`docs/image-catalog.md`](docs/image-catalog.md) for the bundle format and how to publish a new entry. ## Config Config lives at `~/.config/banger/config.toml`. All keys optional. Most commonly set: - `default_image_name` — image used when `--image` is omitted (default `debian-bookworm`, auto-pulled from the catalog if not local). - `ssh_key_path` — host SSH key. If unset, banger creates `~/.local/state/banger/ssh/id_ed25519`. Accepts absolute paths or `~/`-anchored paths; `~/foo` expands against `$HOME`. Relative paths are rejected at config load. - `firecracker_bin` — override the auto-resolved `PATH` lookup. Full key reference: [`docs/config.md`](docs/config.md). ### `vm_defaults` — sizing for new VMs Every `vm run` / `vm create` prints a `spec:` line up front showing the vCPU, RAM, and disk the VM will get. When the flags aren't set, those values come from: 1. `[vm_defaults]` in config (if present, wins). 2. Host-derived heuristics (roughly: `cpus/4` capped at 4, `ram/8` capped at 8 GiB, 8 GiB disk). 3. Built-in constants (floor). `banger doctor` prints the effective defaults with provenance. ```toml [vm_defaults] vcpu = 4 memory_mib = 4096 disk_size = "16G" ``` All keys optional — omit whichever you want banger to decide. ### `file_sync` — host → guest file copies ```toml [[file_sync]] host = "~/.aws" # whole directory, recursive guest = "~/.aws" [[file_sync]] host = "~/.config/gh/hosts.yml" guest = "~/.config/gh/hosts.yml" [[file_sync]] host = "~/bin/my-script" guest = "~/bin/my-script" mode = "0755" # optional; default 0600 for files ``` Runs at `vm create` time. Each entry copies `host` → `guest` onto the VM's work disk (mounted at `/root` in the guest). Guest paths must live under `~/` or `/root/...`. Host paths must live under the installed owner's home directory; `~/...` is the intended form, and absolute paths are accepted only when they still point inside that home. Default is no entries — add the ones you want. A top-level symlink is followed only when its resolved target stays inside the owner home. Symlinks encountered while recursing into a synced directory are skipped with a warning — they'd otherwise leak files from outside the named tree (e.g. a symlink inside `~/.aws` pointing to an unrelated credential dir). ## Updating ```bash banger update --check # is a newer release available? sudo banger update # download, verify, swap, restart, run doctor sudo banger update --to v0.1.1 sudo banger update --dry-run ``` `banger update` pulls the release manifest from `https://releases.thaloco.com/banger/manifest.json`, downloads the release tarball + `SHA256SUMS` + `SHA256SUMS.sig`, verifies the cosign signature against the public key embedded in the running binary, hashes the tarball, atomically swaps the three banger binaries, restarts both systemd services, and runs `banger doctor`. On any failure post-swap, it auto-restores the previous install from `.previous` backups before surfacing the original error. Refuses to start while any banger operation is in flight. No background update checks; updates only happen when you ask. See [`docs/privileges.md`](docs/privileges.md) for the trust model. ## Advanced The common path is `vm run`. Power-user flows (`vm create`, OCI pull for arbitrary images, `image register`, manual workspace prepare) are documented in [`docs/advanced.md`](docs/advanced.md). ## Security Guest VMs are single-user development sandboxes, not multi-tenant servers. Each guest's sshd is configured with: ``` PermitRootLogin prohibit-password PubkeyAuthentication yes PasswordAuthentication no KbdInteractiveAuthentication no AuthorizedKeysFile /root/.ssh/authorized_keys ``` The host SSH key is the only authentication mechanism. `StrictModes` is on (sshd's default); banger normalises `/root`, `/root/.ssh`, and `authorized_keys` perms at provisioning time so the default passes. VMs are reachable only through the host bridge network (`172.16.0.0/24` by default). Do not expose the bridge interface or guest IPs to an untrusted network. ## Further reading - [`docs/config.md`](docs/config.md) — full config key reference. - [`docs/dns-routing.md`](docs/dns-routing.md) — resolving `.vm` hostnames from the host. - [`docs/image-catalog.md`](docs/image-catalog.md) — bundle format and publishing. - [`docs/kernel-catalog.md`](docs/kernel-catalog.md) — kernel bundles. - [`docs/oci-import.md`](docs/oci-import.md) — pulling arbitrary OCI images. - [`docs/advanced.md`](docs/advanced.md) — power-user flows.