Machines
A nest is a machine you deploy to. Your own machine is the first nest,
called local. Registering a remote machine makes it a target that projects can
name.
The registry
ant nest machines list # list registered machines
ant nest machines add prod --hostname prod.example.com
ant nest machines add prod --node-id 7f2e… # already-running worker
ant nest machines add prod --host ADDR --ssh-key ~/.ssh/id_ed25519 # provision over SSH
ant nest machines remove prod
ant nest machines decommission prod --host ADDR --ssh-key ~/.ssh/id_ed25519 --yes
ant nest machines network prod --name ant-prod --driver bridge
add registers a machine by NodeID, or provisions it over SSH when --host is
given (--ssh-user, --ssh-port, --ssh-key, --ssh-password /
--ssh-password-stdin, --docker-mode, --no-caddy, --no-caddy-check, and
--id). decommission reverses provisioning on the machine over SSH
(--purge also removes the worker user, state, containers, images, and
networks; --keep-record keeps the local entry). network shows or sets the
machine-wide network. See Remote machines.
Each machine has a stable key (local, prod, …) and the machine it points at.
A project targets one by name via machine: in ant.yaml.
Everything nests under a machine
In schema v2, groups, projects, and Caddy settings belong to a machine:
machines
└── local
├── caddy { auto_start: true }
├── docker { mode: rootless }
├── network { name: ant-local }
├── groups { backend: { network: {…}, domains: [example.com] } }
└── project_dirs [ /home/me/code/api, /home/me/code/worker ]
This is what makes remote deploys coherent: a group and its project directories are facts about a machine, not about your laptop in the abstract. When a project joins a group, its directory moves to the group.
v1 configs migrate on load; a top-level local object folds into
machines.local, flat groups/project_dirs/caddy are nested, and a legacy
group carrying a machine: field nests under that machine.
Inspecting a machine
ant nest # overview of the local machine (--json)
ant nest ping [machine] # is the worker reachable? is iroh available? (--timeout)
ant nest doctor # Docker, Caddy, docker mode, tools (--machine M for a nest)
ant nest identity show # a machine's NodeID
ant nest identity generate # create a machine identity (--force)
ant nest audit # tamper-evident action log (--limit, --json)
ant nest state export --out state.json # back up roster and invites
ant nest state import --file state.json # restore (owner-only; --force)
ant nest tools # inspect tools (also install | allow-ports)
ant nest tunnel --container app --port 8080 # forward a local port over iroh
ant nest ping reports that iroh is unavailable on platforms built without the
transport (see Installation). ant nest doctor
checks the Docker daemon, Caddy, the docker mode, and tools; locally, or over
the worker RPCs with --machine M (host-level port grants are reported as not
applicable remotely). ant nest tunnel reaches a published container port from
your machine without opening one on the nest; see Tunnels.
Privileged work is operator-run
Ant's worker never invokes sudo. Provisioning a machine (installing the
worker, opening ports) is an operator action; ant nest bootstrap --host runs
the same steps over SSH through the SSH user's sudo:
ant nest bootstrap # print the root-run steps for a machine
ant nest reconcile --apply # run them (root)
The worker itself runs unprivileged. See Security model.