docs: DNS routing guide; README aimed at common users

Adds docs/dns-routing.md covering how `<vm>.vm` resolution works:
auto-configuration on systemd-resolved hosts (what the daemon
already does), and per-resolver recipes for dnsmasq /
NetworkManager+dnsmasq / /etc/resolv.conf / macOS `/etc/resolver/`
/ WSL. Plus verification via `dig @127.0.0.1 -p 42069` and
troubleshooting for the common failure modes.

README reshape: lead with the three things a common user needs —
quick start, what `vm run` does, where to put hostnames + image +
config — and push the rest to docs. `vm create` / OCI `image pull`
/ `image register` / workspace-and-session primitives are all still
documented, just under docs/advanced.md where they're not in the
first-time reader's way. Web UI and unnecessary implementation
notes dropped; the "further reading" section at the bottom
enumerates the five docs pages so nothing becomes hard to find.

README shrinks from 208 → 158 lines.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Thales Maciel 2026-04-18 17:24:50 -03:00
parent 2584f94828
commit 88425fb857
No known key found for this signature in database
GPG key ID: 33112E6833C34679
3 changed files with 296 additions and 109 deletions

98
docs/advanced.md Normal file
View file

@ -0,0 +1,98 @@
# Advanced flows
`banger vm run` covers the common sandbox case. This doc is for the
rest: scripting, arbitrary images, custom rootfs stacks, long-lived
guest processes.
## `vm create` — the low-level primitive
Use when you want to provision without starting, or when you need to
script VM creation piecewise.
```bash
banger vm create --image debian-bookworm --name testbox --no-start
banger vm start testbox
banger vm ssh testbox
banger vm stop testbox
banger vm delete testbox
```
`vm create` is synchronous by default, but on a TTY it shows live
progress until the VM is fully ready.
## `image pull <oci-ref>` — arbitrary container images
For images outside banger's catalog, pull from any OCI registry:
```bash
banger image pull docker.io/library/alpine:3.20 --kernel-ref generic-6.12
```
Layers are flattened, ownership is fixed (setuid binaries, root-owned
config preserved), banger's guest agents are injected, and a first-boot
systemd service installs `openssh-server` via the guest's package
manager so the VM is reachable on first boot.
See [`docs/oci-import.md`](oci-import.md) for supported distros,
caveats, and the `internal/imagepull` design.
## `image register` — existing host-side stack
If you already have an ext4 rootfs, a kernel, optional initrd, and
optional modules as files on disk:
```bash
banger image register --name base \
--rootfs /abs/path/rootfs.ext4 \
--kernel-ref generic-6.12
```
You can mix `--kernel-ref` (a cataloged kernel) with `--rootfs` from
disk, or pass `--kernel /abs/path/vmlinux` for a one-off kernel.
For reproducible custom images, write a Dockerfile and publish it to
an image catalog. See [`docs/image-catalog.md`](image-catalog.md).
## Workspace + session primitives
Long-lived guest commands managed by the daemon, attachable over a
local Unix socket bridge. Useful for agent/background processes that
need to survive SSH disconnects.
```bash
banger vm workspace prepare <vm> ./other-repo --guest-path /root/repo
banger vm session start <vm> --name planner --cwd /root/repo \
--stdin-mode pipe -- pi --mode rpc
banger vm session attach <vm> planner
banger vm session logs <vm> planner --stream stderr
banger vm session stop <vm> planner
```
Details:
- `vm workspace prepare` materialises a local git checkout into a
running VM. Default guest path `/root/repo`; default mode is a
shallow metadata copy plus tracked and untracked non-ignored
overlay.
- `vm session start` launches a daemon-managed long-lived guest
command. The daemon preflights that the guest `cwd` exists and the
command is on guest `PATH` before launch. Use `--stdin-mode pipe`
when you need live `attach`.
- `vm session attach` is exclusive and same-host only. Pipe-mode
sessions survive daemon restarts.
## Inspecting boot failures
When a VM's create flow errors ("ssh did not come up within 90s" or
similar), the VM is kept alive for inspection:
- `banger vm logs <name>` — the firecracker serial console output,
the best window into a stuck boot (systemd unit failures, kernel
panics, missing modules).
- `banger vm ports <name>` — what's listening in the guest. Works as
long as banger's vsock agent has come up, even if SSH is wedged.
- `banger vm show <name>` — daemon-side state (IP, PID, overlay
paths).
`--rm` on `vm run` intentionally does NOT fire when the initial ssh
wait times out, so the VM stays around for post-mortem.

138
docs/dns-routing.md Normal file
View file

@ -0,0 +1,138 @@
# DNS routing — resolving `<vm>.vm` hostnames from the host
banger's daemon runs a local DNS server on `127.0.0.1:42069` that
answers queries under the `.vm` zone. Every VM you create gets a
record:
```
devbox.vm → 172.16.0.9 (whatever guest IP it was assigned)
```
With that plus host-side DNS routing, you can:
```bash
ssh root@devbox.vm
curl http://devbox.vm:3000
```
from anywhere on the host without copy-pasting guest IPs.
## systemd-resolved hosts — nothing to configure
If your host uses `systemd-resolved` (most modern Linux desktops —
Ubuntu ≥18.04, Fedora, Arch with the service enabled), banger
auto-wires it. On daemon start it runs:
```
sudo resolvectl dns <bridge> 127.0.0.1:42069
sudo resolvectl domain <bridge> ~vm
sudo resolvectl default-route <bridge> no
```
against the banger bridge (`br-fc` by default). systemd-resolved
routes only `.vm` lookups to banger's DNS; everything else goes to
your normal upstream. No other changes needed.
Verify: `resolvectl status br-fc` should list `127.0.0.1:42069` under
**Current DNS Server** and `~vm` under **DNS Domain**.
`banger daemon stop` reverts the bridge's resolvectl state on shutdown.
## Non-systemd-resolved hosts
banger detects `resolvectl`'s absence and skips the auto-wire. You
configure your own resolver. Below are recipes for the common cases.
In every case the goal is the same: **route `.vm` queries to
`127.0.0.1` port `42069`, leave everything else alone**.
### dnsmasq
Add a stanza to your dnsmasq config (e.g.
`/etc/dnsmasq.d/banger-vm.conf`):
```
server=/vm/127.0.0.1#42069
```
Reload dnsmasq (`sudo systemctl reload dnsmasq` or equivalent) and
test:
```
dig devbox.vm
```
### NetworkManager with dnsmasq plugin
Same file as above; NetworkManager picks it up automatically if it's
configured to use the dnsmasq plugin (`dns=dnsmasq` in
`/etc/NetworkManager/NetworkManager.conf`). Restart NetworkManager
after editing.
### Raw `/etc/resolv.conf`
If you edit `resolv.conf` directly, there's no per-domain routing —
you'd have to point ALL DNS through banger, which you probably don't
want. Install `dnsmasq` instead and use the stanza above.
### macOS (if you ever run banger on a Linux VM hosted on macOS)
macOS supports per-TLD resolvers out of the box. Create
`/etc/resolver/vm` (as root):
```
nameserver 127.0.0.1
port 42069
```
No daemon reload needed — `scutil --dns` should list `.vm` under
"Resolver configurations" immediately.
### Windows/WSL
WSL2 inherits the Windows resolver by default and cannot be told to
route `.vm` anywhere. Options:
1. Run banger inside WSL but resolve manually: `ssh root@172.16.0.9`.
2. Set up `dnsmasq` on the WSL distro and point its resolv.conf at
it; then follow the dnsmasq recipe above.
## Verifying the DNS server
Regardless of host-side routing, you can always query banger's DNS
server directly:
```bash
dig @127.0.0.1 -p 42069 devbox.vm
```
Returns the guest IP if the VM is running. If it returns NXDOMAIN,
the VM either doesn't exist under that name or isn't running yet.
`banger vm list` shows the VM names banger knows about.
## Troubleshooting
- **`resolvectl` errors about "system has not been booted with systemd
as init system"** — you're probably inside a container. banger's
DNS still works; set up your resolver manually.
- **Port 42069 already in use** — another daemon is bound there
(previous banger instance not shut down cleanly, or an unrelated
app). `ss -ulpn | grep 42069` shows who. `banger daemon stop`
cleans up banger's own listener.
- **`devbox.vm` resolves but SSH hangs** — DNS is fine; the VM
might not be up yet or the bridge NAT is misconfigured.
`banger vm ssh devbox` uses the guest IP directly and bypasses
DNS — try that to isolate.
- **Changes to `default_dns` don't affect `.vm` resolution**
`default_dns` is the upstream the GUEST uses; it's unrelated to
host-side `.vm` routing.
## Port and bridge tuning
| Setting | Default | Notes |
|---|---|---|
| DNS listen addr | `127.0.0.1:42069` | Not configurable in v1. Edit `internal/vmdns/server.go` if you really need to change it. |
| Bridge name | `br-fc` | Configurable via `bridge_name` in `~/.config/banger/config.toml`. |
| Bridge IP | `172.16.0.1` | Configurable via `bridge_ip`. |
| Resolver route domain | `~vm` | Not configurable. |