Skip to content

yeetrun/yeet

Repository files navigation

yeet logo

yeet

Homelab service manager built around Tailscale RPC.

yeetrun.com · Quick Start · Install · First-Run Validation · Docs

Yeet is open source homelab infrastructure tooling. You run the yeet CLI from your workstation and install the catch daemon on Linux hosts you control. From there, yeet deploys containers, host services, cron jobs, and Firecracker-backed Linux VMs over Tailscale/tsnet RPC.

Yeet is intentionally opinionated:

  • Hosts run Linux with systemd.
  • SSH is used for yeet init; RPC uses catch's embedded tsnet node.
  • Docker is used for container payloads.
  • Services are currently managed as root-owned systemd units.
  • VM payloads require x86_64 Linux, KVM (/dev/kvm), TUN/TAP, and VM filesystem/networking tools on the catch host.

Within those constraints, the release path is intended to be installable on a fresh Ubuntu/Debian-style host with SSH access.

Install

Install the release binary:

curl -fsSL https://yeetrun.com/install.sh | sh

Nightly build:

curl -fsSL https://yeetrun.com/install.sh | sh -s -- --nightly

Upgrade

Check the local CLI and the selected catch host:

yeet upgrade check

Upgrade both from verified GitHub release assets:

yeet upgrade

In a project with multiple catch hosts in yeet.toml, scan and upgrade all of them explicitly:

yeet upgrade check --all
yeet upgrade --all

To reinstall the latest public release even when a component is already current, newer, or currently a source/dev build:

yeet upgrade --all --force

To install a specific public release instead of latest, select the tag explicitly. Use --force when that would reinstall or downgrade a component:

yeet upgrade --all --version v0.6.1 --force

Bootstrap a Host

Start with a Linux host that has systemd and SSH access. Docker can be installed by yeet init on Debian/Ubuntu-style hosts. A plain first run is valid; if catch needs to join Tailscale, yeet init prompts for a Tailscale OAuth client secret and uses it to enroll catch as a tagged device:

yeet init root@<machine-host>
yeet init --install-docker root@<machine-host>

On KVM-capable hosts where you plan to run VM payloads, let init install the VM filesystem tools too:

yeet init --install-docker --install-vm-tools root@<machine-host>

Catch uses an embedded Tailscale node for RPC. That node must end up with a tag-based identity, such as tag:catch; user-owned catch nodes are rejected. If your tailnet policy does not already allow that tag, update tagOwners in Tailscale before first setup. The OAuth client secret should have the auth_keys scope and be allowed to assign tag:catch, either directly or via an owner tag such as tag:yeet.

For repeatable or non-interactive bootstrap, pass the OAuth client secret:

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

Advanced users can also create a preauthorized Tailscale auth key that assigns the catch server tag and pass it with:

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

If your tailnet separates catch hosts by cluster or location, include the tags your ACLs or grants expect on that key.

Host names matter:

  • root@<machine-host> is the SSH target used only for init/install.
  • CATCH_HOST, --host, and <svc>@<host> refer to the catch tsnet hostname.

See Installation and Tailscale for details.

Validate the First Run

Confirm the control plane is reachable:

yeet version
yeet status

If you have Tailscale installed locally, yeet list-hosts can also discover tagged catch nodes. It is optional for normal RPC because yeet embeds tsnet.

Then run a disposable container:

yeet run -p 18080:80 yeet-smoke-web nginx:alpine
yeet ssh -- curl -fsS http://127.0.0.1:18080/ >/dev/null
yeet rm --clean-data yeet-smoke-web

For the full fresh-host playbook, including script services, cron timers, VM capability, LAN networking, and ZFS checks, use First-Run Validation.

Common Workflows

Docker Compose:

yeet run <svc> ./compose.yml
yeet logs -f <svc>
yeet run --pull <svc> ./compose.yml

Docker image:

yeet run -p 8080:80 <svc> nginx:alpine

Dockerfile:

yeet run <svc> ./Dockerfile

Binary or script:

GOOS=linux GOARCH=amd64 go build -o ./bin/<svc> ./cmd/<svc>
yeet run <svc> ./bin/<svc>
yeet run <svc> ./script.sh -- --app-flag value

Cron job:

yeet cron <svc> ./job.sh "0 9 * * *"

VM on a KVM-capable host:

yeet vm images catalog
yeet run devbox vm://ubuntu/26.04
yeet ssh devbox
yeet vm console devbox

The official VM catalog is loaded from yeet-vm-images at runtime. The catalog defines supported vm://... families, and each family points at a stable latest manifest. New image versions are picked up through that manifest rather than a yeet release. Run a vm:// payload once per VM name; change an existing VM with yeet vm set or remove and recreate it for a fresh guest.

Detach from an active VM console by pressing Enter, then typing ~.. The VM keeps running.

Official VM images also include NixOS:

yeet run lab vm://nixos/26.05

For a VM that should also request an address on the catch host's LAN, keep the default management network and add LAN networking:

yeet run devbox vm://ubuntu/26.04 --net=svc,lan

LAN-only VMs are reached directly at their guest LAN IP. svc or svc,lan keeps a catch-proxied yeet ssh management path. Services and VMs on svc also resolve other service-network names through yeet DNS, including short names and *.yeet.internal names.

Local image built on your workstation:

yeet docker push <svc> <local-image>:<tag> --run

After the first successful deploy, yeet writes a yeet.toml replay file. You can usually rerun the same service with:

yeet run <svc>

See Workflows and Payloads for the complete guides.

Optional Host Capabilities

Yeet works without every optional feature. The host determines which payloads and network modes are available:

  • Docker is required for container payloads.
  • x86_64 Linux, KVM, TUN/TAP, and VM filesystem/networking tools are required for VM payloads. yeet init checks this and --install-vm-tools installs missing Debian/Ubuntu packages when the host can run VMs.
  • LAN/macvlan networking requires a host network where macvlan and DHCP make sense.
  • ZFS is optional and enables dataset-backed service roots, snapshots, and fast repeated VM disk clones.
  • --net=ts service networking requires Tailscale auth for each service netns.

Yeet warns during init or deploy when a host cannot support a requested feature. See Networking, VMs, and ZFS.

Documentation

The docs site is the user manual and the source of truth for behavior:

Development from Source

Use mise to install the pinned toolchain from .mise.toml:

curl https://mise.run | sh
echo 'eval "$(mise activate zsh)"' >> ~/.zshrc
mise install

Build locally:

go build ./cmd/yeet
go build ./cmd/catch

Install repo hooks once:

mise run install-githooks

Run the normal local quality gate:

mise run quality

Heavier checks are available for release or deeper quality work:

mise run race
mise run fuzz
mise run mutation
mise run quality:goal

Security Notes

Services managed by catch currently run as root. That is acceptable for a single-operator homelab, but it is not a good default for production or multi-tenant setups. See the FAQ for current limitations.

License

BSD 3-Clause. See LICENSE.