Networking

Choose who can reach a service, what it can resolve, and how it gets out.

Network mode choice decides who can reach the workload, what names it can resolve, and where ordinary outbound internet goes.

Choose the inbound path and the outbound path together. A service that can be reached still needs to resolve names, download updates, and call APIs.

Start here

NeedUseInternet egress
Publish one container port on the catch host-p HOST:CONTAINERThe workload's current network path
Private yeet service traffic and yeet DNS--net=svcCatch host gateway
Tailnet identity plus normal service networking--net=svc,tsCatch host gateway
Internet-only workload, reachable from catch--net=isoCatch host NAT to public IPv4 only
Isolated container service plus tailnet identity--net=iso,tsCatch host NAT plus explicit tailnet routes
LAN or VLAN address--net=lanDHCP gateway from the LAN or VLAN
LAN or VLAN address plus tailnet identity--net=lan,tsDHCP gateway from the LAN or VLAN
Tailnet-only service--net=tsNo ordinary internet unless you configure an exit node
VM LAN access plus yeet-managed fallback--net=svc,lanLAN gateway for normal traffic

For most services that need a Tailscale identity, start with svc,ts, not plain ts. svc,ts keeps yeet DNS, private service traffic, and internet egress through the catch host while adding a tailnet identity. Plain ts is for services that are intentionally tailnet-only or have an exit-node plan.

Modes are comma-separated:

yeet run <svc> ./compose.yml --net=svc,ts --ts-tags=tag:app

Use the yeet run network flags for the initial deployment. For an existing non-VM service, use yeet service set instead:

yeet service set <svc> --net=iso
yeet service set <svc> --net=ts --ts-tags=tag:app
yeet service set <svc> --net=host
yeet service set <svc> --ts-exit=

VMs support svc, lan, svc,lan, and iso. A VM cannot combine iso with another Yeet-managed mode. VM networking does not support ts; install Tailscale inside the guest when it needs a tailnet identity.

Change an existing network

yeet service set applies network changes to existing non-VM services. The change restarts the service immediately. If the replacement cannot be activated, Catch attempts to restore the previous network. If that rollback cannot be completed, Catch stops the service or quarantines its network state instead of leaving a partially active network. yeet run remains the payload deployment command. If its saved or supplied network settings differ from Catch's desired configuration, it stops with guidance to use yeet service set before changing the workload.

The network flags form a patch:

FlagExisting-service behavior
--netReplace the complete mode set. Use host to leave managed networks.
--ts-tagsReplace the tag list. Repeat the flag for multiple tags; use --ts-tags= to clear it.
--ts-verSet the Tailscale version; use --ts-ver= to clear it.
--ts-exitSet the exit node; use --ts-exit= to clear it.
--ts-auth-keySupply a non-empty enrollment key for this operation only. Yeet does not display or save it.
--macvlan-parentSet the parent interface; use --macvlan-parent= to clear it.
--macvlan-vlanSet the VLAN; use --macvlan-vlan= to clear it.
--macvlan-macSet the MAC address; use --macvlan-mac= to clear it.

Omitted fields keep their stored values. --net= is invalid. Whenever the resulting modes include ts, the resulting tag list must be non-empty. A service can inherit valid stored tags when it enters ts, but otherwise the same command must provide --ts-tags.

Catch is authoritative after a successful remote mutation. If yeet cannot update the matching yeet.toml entry afterward, repair the local copy with:

yeet service sync <svc>

The non-VM flags above do not change VM networks. Keep VM mutations under yeet vm set:

yeet vm set <vm> --net=lan
yeet vm set <vm> --net=svc,lan --macvlan-parent=vmbr0

Published ports

Use published ports when the workload only needs a TCP port on the catch host:

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

-p is not a network mode. It exposes a host port for image, Dockerfile, Python, and TypeScript payloads. Use --net only when the workload also needs private service networking, LAN presence, or a Tailscale identity. More network modes make the service reachable in more ways, which is not automatically a win.

iso workloads cannot publish ports. Catch already has a routed management path to every iso endpoint, while public or LAN ingress is intentionally absent.

Change ports later with service set. The port list is complete, so include every mapping you want to keep:

yeet service set vaultwarden -p 80:80 -p 443:443

Replace or clear the list intentionally with --publish-reset:

yeet service set vaultwarden --publish-reset -p 443:443
yeet service set vaultwarden --publish-reset

Check the live ports first:

yeet info vaultwarden

Service network (svc)

svc gives a service or VM a private yeet-managed address.

Use svc when the workload needs:

  • Private service-to-service traffic.
  • Yeet DNS names, such as vaultwarden and vaultwarden.yeet.internal.
  • Ordinary outbound internet through the catch host's gateway.
  • A stable VM management path through catch.
yeet run <svc> ./compose.yml --net=svc
yeet ip <svc>

Services and VMs on svc can resolve each other by short name and *.yeet.internal names:

http://home-assistant:8123
postgres://postgres:5432/app

Use svc as the default private app network. Add ts when the service also needs a tailnet identity. Add lan when the service or VM also needs a LAN address.

The svc network currently requires exclusive use of 192.168.100.0/24 on the catch host. If that range overlaps an existing host route, catch rejects new svc networking.

See DNS for resolver behavior.

Isolated network (iso)

iso is for a workload that needs the public internet but should not initiate connections to the host or private networks:

yeet run <svc> nginx:alpine --net=iso
yeet run <vm> vm://ubuntu/26.04 --net=iso

Every VM, native endpoint, and container component gets a stable RFC1918 IPv4 address. Catch can initiate connections to those addresses on any protocol or port, including the Catch-proxied path used by yeet ssh <iso-vm>. Return traffic is allowed. A workload cannot initiate a new flow to Catch, another iso project, svc, LAN, CGNAT/Tailscale, link-local or metadata addresses, or other non-public IPv4 space. Public IPv4 traffic is NATed through Catch.

Components in one admitted Compose project may communicate with each other; the project is the isolation unit. Other Yeet projects cannot reach them. Public and LAN clients cannot use Catch's route as an ingress path.

iso provides a dedicated public-only DNS view. It refuses Yeet-local records, private and IPv6 address answers, direct public DNS on port 53, and DNS over TLS on port 853. DNS over HTTPS looks like permitted HTTPS traffic, so iso does not claim to block it. IPv6 is disabled for iso attachments.

iso supports VMs, native binaries and scripts, timer-backed jobs, images, client-built Dockerfiles, Python, TypeScript, and an admitted subset of Compose. A native workload's generated systemd service joins the iso namespace; a timer remains the scheduling unit while its invoked service joins the namespace. Network selection does not change User=, Group=, capabilities, or filesystem policy. Root and non-root native services use the same network path. iso controls ordinary workload traffic; it is not containment against a host-root process.

Compose is trusted deployment code: Catch resolves it through Docker and rejects host networking, published ports, privilege or host-namespace changes, unsafe mounts and sockets, custom DNS, extra networks, Catch-side builds, replicas, and unknown service fields before starting containers. One iso Compose project supports up to 29 named components.

iso cannot combine with svc or lan. Supported container-backed services may use iso,ts to add a service-owned Tailscale identity; this is an explicit exception to the internet-only rule. Native binaries, scripts, and timer-backed jobs cannot combine iso with ts. VMs also use iso alone and can install Tailscale inside the guest.

Catch selects and persists a non-overlapping RFC1918 /16 before the first iso allocation, preferring 172.30.0.0/16. Set a different pool before any iso allocation or cleanup tombstone exists:

yeet host set --iso-pool=172.28.0.0/16

The value must be an RFC1918 IPv4 /16 with no live or persisted overlap. Yeet does not renumber existing iso workloads automatically.

LAN (lan)

lan attaches a workload to the catch host's LAN. Containers and other non-VM services use macvlan. VMs attach their guest TAP device to a host bridge. In both cases, the workload requests addressing through DHCP.

Use lan when the workload should behave like a normal device on the LAN or VLAN:

yeet run <svc> ./compose.yml --net=lan
yeet ip <svc>

With lan, ordinary outbound internet uses the gateway and DNS from that LAN or VLAN. If the LAN has no gateway, blocks outbound access, or hands out the wrong DNS, the workload inherits that behavior.

Use lan,ts when LAN clients and tailnet clients both need to reach the same service:

yeet run <svc> ./compose.yml --net=lan,ts --ts-tags=tag:app

Override the parent interface or VLAN when needed:

yeet run <svc> ./compose.yml --net=lan --macvlan-parent=<iface>
yeet run <svc> ./compose.yml --net=lan --macvlan-parent=<iface> --macvlan-vlan=<id>

Use lan only on networks where macvlan, DHCP, and the selected parent interface make sense. A WAN-only VPS usually should not use lan. If there is no meaningful LAN, use svc or ts instead.

For VM lan networking, yeet needs a bridge on the host LAN. If the host already has one on the default route, yeet uses it. On supported Debian/Ubuntu hosts without a bridge, interactive yeet init or the first yeet run <vm> ... --net=lan can prepare br0 after confirmation. Bridge preparation can briefly interrupt host networking; if your command disconnects during the change, rerun it after the host comes back.

Tailscale (ts)

ts gives a service its own Tailscale identity, tailnet IP, tags, ACLs, and Tailscale Serve support.

Use svc,ts for most services that need Tailscale:

yeet run <svc> ./compose.yml --net=svc,ts --ts-tags=tag:app
yeet ip <svc>

This keeps yeet DNS and ordinary outbound internet through the catch host while adding a tailnet identity.

Use plain ts only when the service is intentionally tailnet-only:

yeet run <svc> ./compose.yml --net=ts --ts-tags=tag:app

Plain ts does not provide ordinary outbound internet by itself. Configure a Tailscale exit node when a ts-only service needs internet access:

yeet run <svc> ./compose.yml --net=ts --ts-tags=tag:app --ts-exit=<exit-node>

For an existing Tailscale service, update the desired exit node through service set:

yeet service set <svc> --ts-exit=<exit-node>
yeet service set <svc> --ts-exit=

Make sure the OAuth client saved during catch setup can assign every tag you pass with --ts-tags.

See Tailscale for OAuth setup, tags, exit nodes, and yeet tailscale commands.

Combine modes

ModeUse whenAvoid when
svcThe workload needs private yeet traffic, yeet DNS, or catch-host internet egress.LAN clients need a LAN IP or tailnet clients need a service identity.
lanThe workload should be a LAN or VLAN device.The host network cannot provide DHCP, routing, or macvlan support.
tsThe workload is deliberately tailnet-only, or an exit node handles internet egress.The workload needs normal internet, yeet DNS, or private service traffic.
isoA workload needs public IPv4 egress and Catch-only ingress.The workload must initiate traffic to Catch, LAN, svc, another project, or other private space.
iso,tsA supported container-backed service needs isolation plus an explicit tailnet identity.The workload is a VM, native binary or script, timer-backed job, or plain iso covers the access path.
svc,tsThe workload needs private yeet networking plus a tailnet identity.The workload must appear as a LAN device.
lan,tsThe LAN handles ordinary egress and the service also needs a tailnet identity.The workload needs yeet DNS or private service traffic.
svc,lanA VM or service needs LAN presence plus yeet private networking.The workload does not need the LAN.
svc,lan,tsA non-VM service truly needs private yeet traffic, LAN presence, and tailnet identity.A simpler mode covers the real access path.

For VMs, svc is the default. svc,lan gives the VM LAN access and keeps a catch-managed fallback path. A LAN-only VM must be reachable from your workstation on its guest LAN IP for yeet ssh <vm> to connect directly. If no host LAN bridge is ready yet, yeet asks to prepare one before creating the VM. Bridge preparation can briefly interrupt host networking.

yeet run <vm> vm://ubuntu/26.04 --net=svc,lan
yeet ssh <vm>

Force the proxy path:

yeet ssh --force-proxy <vm>

Check a network choice

Inspect the current addresses and desired/effective network model:

yeet info <svc>
yeet ip <svc>

Use the output to confirm:

  • svc shows a private service-network address.
  • lan shows a LAN or VLAN address from DHCP.
  • ts shows a tailnet address and Tailscale state.
  • iso shows the isolation state, public-egress and DNS policy, and stable VM or component endpoints.
  • Network modes always shows the effective modes, including host.
  • Desired network modes appears when a failed or quarantined transition left desired and effective state different.

If the service has no outbound internet, debug by network mode:

  • Use svc or svc,ts when the catch host should provide egress.
  • Check the LAN gateway and DNS when the service uses lan.
  • Configure a Tailscale exit node when the service uses plain ts.
  • For iso, confirm the isolation state is ready and test a globally reachable IPv4 destination. Private destinations are expected to fail.

Mounts

mount and umount manage host-level network mounts:

yeet mount host:/export data-share --type=nfs --opts=defaults
yeet umount data-share

Mounts are host-level resources, not per-service network modes.

  • Tailscale covers catch host access, per-service Tailscale identities, tags, and exit nodes.
  • DNS covers names inside svc and iso's public-only resolver.
  • VMs covers VM networking and SSH behavior.
  • Troubleshooting covers common network failures.