Troubleshooting
Start from the symptom, then check the boundary that usually breaks.
Start with the symptom you see. If this is a fresh host, run First-Run Validation after fixing the first connection problem.
Most failures happen at a boundary: workstation to catch, catch to Docker, service to network, VM to KVM, or local config to live state. Debug the boundary first.
Confirm you are targeting the catch hostname, not the SSH machine hostname:
CATCH_HOST=<catch-host> yeet status
yeet --host=<catch-host> status
Then check the layers in order:
- The catch Tailscale node exists.
- The node has a tag such as
tag:catch. - Your device or admin tag can reach the catch tag on TCP port
41548. - The catch service is running on the host.
If you have the Tailscale CLI installed locally, this can help confirm the tagged node is visible:
yeet list-hosts
See Tailscale Setup for the tailnet policy shape.
Catch rejects user-owned Tailscale nodes. It must join the tailnet with a tag-based identity. That keeps the daemon in the server side of the trust model.
Fix the Tailscale policy first, then rerun init:
yeet init root@<machine-host>
Tailscale assigned a suffix such as catch-1 because another device already
owns the requested hostname. This is not random naming. It is stale or
conflicting state showing up as DNS.
Use the assigned catch host:
yeet --host=catch-1 status
Or remove the stale/conflicting Tailscale device and rerun yeet init.
If you are adding a second catch host, choose a distinct name instead of
reusing the default catch name:
yeet --host=morpheus-catch init root@<machine-host>
Container payloads require Docker on the catch host. On Debian/Ubuntu-style hosts, interactive init can ask before installing it:
yeet init root@<machine-host>
If local image pushes do not show up on the host, rerun bootstrap and allow Docker setup. Yeet configures the Docker settings it needs during catch install.
For Compose services:
yeet info
yeet info <svc>
yeet logs <svc>
yeet ssh -- docker ps
See Containers for update and image workflows.
yeet service set protects the full published-port list. Include every mapping
you want to keep. Otherwise you are not adding a port; you are replacing the
list with a smaller one:
yeet service set vaultwarden -p 80:80 -p 443:443
To replace the list or clear it, use --publish-reset:
yeet service set vaultwarden --publish-reset -p 443:443
yeet service set vaultwarden --publish-reset
Use yeet info vaultwarden before changing ports.
First confirm the service has the network mode you expect:
yeet info <svc>
yeet ip <svc>
For svc networking, yeet info and yeet ip should show private
service-network addresses. For lan, the host network must support macvlan and
DHCP. A WAN-only VPS usually should not use lan.
If the service was running before a network change, restart it:
yeet restart <svc>
See Networking before changing modes on a shared host.
Check the service network mode first:
yeet info <svc>
yeet ip <svc>
Use the mode to choose the next check:
svcandsvc,tsuse the catch host's gateway for ordinary internet access. Confirm the catch host itself can reach the internet.lanandlan,tsuse the DHCP gateway and DNS from the LAN or VLAN. Check that network's router, DHCP lease, and ACLs.- Plain
tsis tailnet-only unless you configure a Tailscale exit node. Addsvc, use--ts-exit=<exit-node>, or runyeet tailscale <svc> -- set --exit-node=<exit-node>.
Yeet DNS only publishes names for services and VMs using svc networking.
Without a svc address, there is no record to publish.
Check the resolver from a service or VM on the service network:
dig @192.168.100.1 <svc> A +short
dig @192.168.100.1 <svc>.yeet.internal A +short
If the query returns nothing, confirm yeet info <svc> shows a service-network
IP. See DNS for records and resolver behavior.
VMs require a KVM-capable Linux catch host. Check the host:
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 KVM is missing, use containers, binaries, scripts, and cron jobs on that
host. If KVM and TUN/TAP exist but tools are missing on Debian/Ubuntu,
interactive yeet init can ask before installing them:
yeet init root@<machine-host>
See VMs for image cache and console diagnostics.
Build binaries for the catch host architecture. If the CPU cannot execute the file, the service cannot start it:
GOOS=linux GOARCH=amd64 go build -o ./bin/<svc> ./cmd/<svc>
yeet run <svc> ./bin/<svc>
Use the host's actual architecture when it is not amd64.
yeet edit and yeet env edit launch an editor. Run them from an interactive
shell.
Inspect the staged payload:
yeet stage <svc> show
Apply it:
yeet stage <svc> commit
Or discard it:
yeet stage <svc> clear
One side of a copy must be remote, such as <svc>:path or <vm>:path.
Examples:
yeet copy ./config.yml <svc>:config/config.yml
yeet copy ./configs/ <svc>:config/
yeet copy <vm>:"/var/log/*.log" ./logs/
Remote service paths are relative to the service data directory.
Yeet fixes a service type after the first install. If you installed a service as Compose, you cannot later replace it with a binary using the same service name.
Choose a new service name, or remove the old service first:
yeet rm <svc>
Use --clean only when you also want to delete the service data and remove the
local yeet.toml entry. Data deletion is separate from retrying a remove.
yeet cannot reach catch
yeet init says catch needs a tag
yeet init got a different catch hostname
Docker payloads fail
Published port changes fail
Service networking does not work
A service has no outbound internet
Yeet DNS names do not resolve
VM payloads do not start
Binary architecture mismatch
edit fails without a TTY
Staged changes are confusing
copy destination errors
Service type mismatch