First-Run Validation

A practical smoke-test playbook for a fresh yeet + catch host.

Use this playbook after yeet init on a fresh host. It checks the control plane first, then the payload paths that should work on a normal Debian/Ubuntu-style server. Optional host capabilities such as KVM, LAN macvlan, and ZFS are checked separately.

All examples use disposable service names. If you have more than one catch host, set CATCH_HOST=<catch-host> or pass --host=<catch-host> so every command targets the fresh host.

1) Confirm catch is reachable

CATCH_HOST=<catch-host> yeet version
CATCH_HOST=<catch-host> yeet status

If this is your only catch host, the unqualified commands should work too:

yeet version
yeet status

If you have Tailscale installed locally, yeet list-hosts can also confirm the catch node is visible in your tailnet. It is optional for this playbook because normal yeet RPC uses embedded tsnet.

If yeet status cannot connect, confirm yeet init stored a Tailscale OAuth client secret or catch-node auth key, and confirm the catch node is tagged. For repeatable setup, rerun init with the OAuth client secret:

yeet init --install-docker --ts-client-secret=<secret> root@<machine-host>

Advanced users can rerun init with a direct catch-node auth key:

yeet init --install-docker --ts-auth-key=<key> root@<machine-host>

See Tailscale if the SSH machine host and catch host names are confusing, or if the tailnet policy needs tagOwners/grant changes before catch can use the tag you selected.

2) Smoke-test Docker image payloads

This validates the most common path: Docker on the host, generated Compose, published host ports, service status, logs, and cleanup.

yeet run -p 18080:80 yeet-smoke-web nginx:alpine
yeet status yeet-smoke-web
yeet info yeet-smoke-web
yeet logs yeet-smoke-web

From the catch host itself, confirm the published port answers:

yeet ssh -- curl -fsS http://127.0.0.1:18080/ >/dev/null

Then remove the disposable service:

yeet rm --clean-data yeet-smoke-web

If this fails, start with Docker errors.

3) Smoke-test script payloads

This validates host systemd services without involving containers.

cat > yeet-smoke-script.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
while true; do
  date
  sleep 30
done
EOF
chmod +x yeet-smoke-script.sh

yeet run yeet-smoke-script ./yeet-smoke-script.sh
yeet status yeet-smoke-script
yeet logs yeet-smoke-script
yeet rm --clean-data yeet-smoke-script
rm yeet-smoke-script.sh

If this fails while Docker payloads work, inspect the unit with:

yeet ssh -- systemctl status yeet-smoke-script.service

4) Smoke-test cron payloads

Cron payloads are systemd timers. This validates timer creation and one scheduled run. It takes about one minute.

cat > yeet-smoke-cron.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
date
EOF
chmod +x yeet-smoke-cron.sh

yeet cron yeet-smoke-cron ./yeet-smoke-cron.sh "* * * * *"
yeet status yeet-smoke-cron
sleep 70
yeet logs yeet-smoke-cron
yeet rm --clean-data yeet-smoke-cron
rm yeet-smoke-cron.sh

5) Check VM capability before creating a VM

VM payloads require x86_64 Linux, KVM, TUN/TAP, and a few host filesystem and networking tools. Many VPS providers do not expose nested virtualization; that is a host limitation, not a failed yeet install.

yeet ssh -- sh -lc '
test -e /dev/kvm && echo kvm=yes || echo kvm=no
test -e /dev/net/tun && echo tun=yes || echo tun=no
for c in qemu-img zstd e2fsck resize2fs mount umount ip; do
  command -v "$c" >/dev/null && echo "$c=yes" || echo "$c=no"
done
'

If the VM devices exist but tools are missing on a Debian/Ubuntu host, rerun yeet init --install-vm-tools root@<machine-host> or install the packages listed in Installation.

If KVM and TUN/TAP are available and the required tools are present, create a disposable VM:

yeet vm images catalog
yeet run yeet-smoke-vm vm://ubuntu/26.04
yeet ssh yeet-smoke-vm -- uname -a
yeet rm --clean-data yeet-smoke-vm

To verify the NixOS image family too, run the same smoke check with vm://nixos/26.05.

If KVM is missing, use containers, binaries, scripts, and cron jobs on this host, and run VM payloads on a KVM-capable machine. See VMs.

6) Check optional host features only when needed

LAN networking depends on the host being attached to a network where macvlan and DHCP make sense. A WAN-only VPS usually should skip this check.

yeet run yeet-smoke-lan nginx:alpine --net=lan
yeet ip yeet-smoke-lan
yeet rm --clean-data yeet-smoke-lan

ZFS-backed service roots require an existing parent dataset. Skip this if you do not plan to use ZFS.

yeet run yeet-smoke-zfs nginx:alpine --service-root=tank/apps/yeet-smoke-zfs --zfs
yeet rm --clean-data yeet-smoke-zfs

See Networking and ZFS for the full model.

Cleanup check

After the smoke tests, yeet status should not list the disposable services:

yeet status

If a service removal fails, rerun the remove command and then inspect Troubleshooting for the relevant payload type.