Incus
Read when you:
- want a built-in local or self-hosted Linux SSH-lease provider backed by Incus;
- need the
incus:config keys,CRABBOX_INCUS_*env overrides, or--incus-* - are validating the deterministic doctor contract or the opt-in Apple Silicon /
flags;
local live smoke path.
provider: incus is a direct ssh-lease backend. Crabbox talks to Incus through the official Go client, creates a Crabbox-managed instance, waits for a reachable SSH target, then uses the normal Crabbox SSH sync/run lifecycle.
#Current contract
- Canonical provider id:
incus - Kind:
ssh-lease - Targets: Linux only
- Coordinator: never
- Features:
ssh,crabbox-sync,cleanup - Authentication model: reuse existing Incus client trust state or an explicit
socket/address override; no Crabbox-specific token flags
The first implementation is intentionally small:
- Linux guests only
- direct Incus control only
- no broker/Worker path
- no delegated
incus execmode - no provider-native checkpoint/fork support in v1
#Connection modes
Crabbox connects to Incus in this order:
incus.socket/--incus-socketincus.address/--incus-address- named remote from the local Incus client config (
incus.remote)
Named remote resolution uses the official Incus client config loader, so the provider can reuse incus remote add ..., project defaults, and local TLS material instead of shelling out to the incus CLI.
#Doctor contract
crabbox doctor --provider incus is read-only. It resolves the same socket/address/remote selection order as the provider, runs a cheap inventory list, and reports the selected connection context in the provider line:
mode=socket|address|remotecontrol_plane=local|remoteendpoint=<socket-or-address>project=<incus-project>auth=unix_socket|tls_client_cert|tls_client_cert_insecure_tls|tls|oidc|publicremote=<name>when named-remote mode is active
The check stays non-mutating (api=list mutation=false). On a configured machine it should return ok provider ... runtime=go_client ...; on an unconfigured or broken machine it should fail with the normal doctor class=config|auth|network|provider contract instead of creating or changing Incus resources.
#Config
YAML:
provider: incus
incus:
remote: local
project: default
instanceType: container
image: images:ubuntu/24.04/cloud
user: crabbox
workRoot: /work/crabbox
deleteOnRelease: true
startTimeout: 10m
launchPort: "22"
proxyListenHost: 127.0.0.1
proxyListenPort: "2222"
proxyDevice: crabbox-ssh
Key fields:
incus.remote: named Incus remote from the local client config. Default:incus.project: Incus project override. Default:defaultincus.address: explicit HTTPS Incus API address, for exampleincus.socket: explicit Unix socket path overrideincus.instanceType:containerorvm. Default:containerincus.image: image alias/fingerprint. Default:incus.profile: optional Incus profile applied to created instancesincus.user: SSH user inside the guest. Default:crabboxincus.workRoot: Crabbox work root inside the guest. Default:incus.deleteOnRelease: delete the instance instead of stopping it onincus.startTimeout: create/start/address wait timeout. Default:10mincus.launchPort: guest SSH port. Default:22incus.proxyListenHost: host-side bind address for the optional Incus proxyincus.proxyListenPort: host-side published SSH port. When set, Crabbox usesincus.proxyDevice: Incus device name for the SSH proxy. Default:incus.tlsServerCert: trusted Incus server certificate path for explicitincus.insecureTLS: allow untrusted TLS certs in explicitincus.addressincus.remoteImageServer: optional simplestreams image server URL used when
local
https://incus-host.example:8443
images:ubuntu/24.04/cloud. Unqualified aliases and fingerprints use the active Incus daemon unless incus.remoteImageServer is set
/work/crabbox
release. Default: true
device. Default: 127.0.0.1
this as the returned SSH port. Proxy devices are supported for containers; VMs must be directly reachable because Incus VM proxies require a static NIC
crabbox-ssh
incus.address mode
mode
an unqualified alias should resolve remotely, or as a fallback when a named image remote cannot be loaded from the local Incus config
#Environment
Environment overrides follow the normal CRABBOX_<PROVIDER>_* pattern:
CRABBOX_PROVIDER=incus
CRABBOX_INCUS_REMOTE=local
CRABBOX_INCUS_PROJECT=default
CRABBOX_INCUS_ADDRESS=https://incus-host.example:8443
CRABBOX_INCUS_SOCKET=$HOME/.config/incus/unix.socket
CRABBOX_INCUS_INSTANCE_TYPE=container
CRABBOX_INCUS_IMAGE=images:ubuntu/24.04/cloud
CRABBOX_INCUS_PROFILE=crabbox
CRABBOX_INCUS_USER=crabbox
CRABBOX_INCUS_WORK_ROOT=/work/crabbox
CRABBOX_INCUS_DELETE_ON_RELEASE=true
CRABBOX_INCUS_START_TIMEOUT=10m
CRABBOX_INCUS_LAUNCH_PORT=22
CRABBOX_INCUS_PROXY_LISTEN_HOST=127.0.0.1
CRABBOX_INCUS_PROXY_LISTEN_PORT=2222
CRABBOX_INCUS_PROXY_DEVICE=crabbox-ssh
CRABBOX_INCUS_TLS_SERVER_CERT=$HOME/.config/incus/server.crt
CRABBOX_INCUS_INSECURE_TLS=false
#Flags
crabbox warmup \
--provider incus \
--incus-remote local \
--incus-project default \
--incus-instance-type container \
--incus-image images:ubuntu/24.04/cloud \
--incus-user crabbox \
--incus-work-root /work/crabbox \
--incus-proxy-listen-port 2222
Supported flags:
--incus-remote--incus-project--incus-address--incus-socket--incus-instance-type--incus-image--incus-profile--incus-user--incus-work-root--incus-delete-on-release--incus-start-timeout--incus-launch-port--incus-proxy-listen-host--incus-proxy-listen-port--incus-proxy-device--incus-tls-server-cert--incus-insecure-tls--incus-remote-image-server
#Lease behavior
On acquire, Crabbox:
- allocates a Crabbox lease id and slug;
- generates a per-lease SSH key;
- creates an Incus instance from the configured image;
- injects Crabbox cloud-init plus provider metadata in
user.crabbox.* - optionally adds an Incus TCP proxy device for containers when
- starts the instance and waits for a reachable SSH path;
- returns a normal Crabbox SSH lease target.
instance config keys;
incus.proxyListenPort is set;
Crabbox-managed metadata is stored on the instance itself in user.crabbox.* keys. That is how list/resolve/touch/cleanup identify managed leases without any extra Incus-side service.
On release:
- default behavior deletes the instance;
- if
incus.deleteOnRelease: false, Crabbox stops the instance and keeps the
retained lease reusable through later --id resolves.
#Examples
Warm and run through a local socket-backed daemon:
crabbox warmup --provider incus --incus-socket /var/lib/incus/unix.socket
crabbox run --provider incus --id blue-lobster -- echo incus-ok
crabbox stop --provider incus blue-lobster
Use a named remote that already exists in the local Incus client config:
incus remote add local-incus-testbed <host-or-token>
crabbox warmup --provider incus --incus-remote local-incus-testbed
Use an explicit address that matches an authenticated remote in the local Incus client config:
incus remote add local-incus-testbed https://incus-host.example:8443
crabbox warmup \
--provider incus \
--incus-remote local-incus-testbed \
--incus-address https://incus-host.example:8443 \
--incus-project crabbox
Crabbox reuses that matching remote's TLS client certificate or OIDC tokens. --incus-insecure-tls only disables server certificate verification; it does not authenticate the client to a private Incus API.
#Deterministic verification
Implementation-complete checks for this provider are mostly deterministic; the final doctor probe stays read-only and validates the configured control-plane contract:
go test -count=1 ./internal/providers/incus ./internal/cli
go test -count=1 ./...
go vet ./...
go build -trimpath -o bin/crabbox ./cmd/crabbox
scripts/check-docs.sh
go run ./cmd/crabbox doctor --provider incus --json
These prove the built-in provider registration, typed config surface, fake-backed lifecycle behavior, the hardened read-only doctor contract, and docs/catalog consistency. The doctor command should either emit explicit connection metadata or fail with the documented config/auth contract without mutating any Incus state.
#Opt-in live smoke
The live Incus path stays opt-in because most maintainer machines do not have a reachable local daemon and guest route by default. The documented contract is:
crabbox doctor --provider incusmust pass first- Crabbox config or env must resolve one of
incus.socket,incus.address, or - the Mac must reach the Incus-managed guest either directly over the bridge or
CRABBOX_LIVE_REPOmust point at the repo you want the smoke to sync and run
incus.remote
through an Incus-published SSH path such as incus.proxyListenPort
The default live-smoke matrix still skips Incus. Opt in explicitly:
go build -trimpath -o bin/crabbox ./cmd/crabbox
CRABBOX_BIN=bin/crabbox CRABBOX_LIVE_DOCTOR_PROVIDERS=incus scripts/live-doctor-smoke.sh
CRABBOX_LIVE=1 CRABBOX_BIN=bin/crabbox CRABBOX_LIVE_PROVIDERS=incus CRABBOX_LIVE_REPO=$PWD scripts/live-smoke.sh
The doctor smoke only proves daemon/control-plane readiness. The full live smoke proves warmup, status --wait, run, list, stop, and one retained reuse cycle from the Mac, then forces a final delete so repeat runs do not strand test instances.
#Limits
- Linux only
- coordinator unsupported
- no Windows or macOS guests
- SSH proxy devices are container-only; VM leases require direct guest
- OIDC remotes require a macOS or Linux Crabbox client so refreshed credentials
- no provider-native snapshot/checkpoint/fork support in v1
reachability
can be persisted atomically; Windows clients can use TLS certificate auth
#Troubleshooting
unknown provider "incus": the binary was built without the built-in providerprovider=incus supports target=linux only: remove a non-Linux target overrideprovider=incus: incus.remote, incus.address, or incus.socket not configured ...:provider=incus address mode requires a matching authenticated Incus remote ...:crabbox doctor --provider incusnow printsmode,endpoint,project,- timeout waiting for an Incus address: the guest started, but Crabbox could not
- SSH bootstrap timeout: the instance is up, but the published SSH path is still
registry import or from an older checkout
the default local Unix-socket remote is Linux-only; on macOS point Crabbox at a reachable Linux Incus daemon instead of the local remote stub
add the address as an Incus remote first so Crabbox can reuse its TLS client certificate or OIDC tokens; server trust and --incus-insecure-tls do not provide client authentication
and auth; use those fields to confirm Crabbox picked the intended socket, explicit address, or named remote before blaming the live smoke path
derive a host-reachable address from runtime state or proxy-device settings
wrong or the guest bootstrap did not finish yet