Hobby tool / utility
A single-host, single-service yoink.yaml built locally with no registry — the minimal five-line config.
A Slack bot, admin CLI, internal status board, cron-as-container: one container that needs a host but doesn't justify CI + a registry + Kubernetes.
The minimum yoink.yaml: one host, one service, Dockerfile next to the config, no registry. yoink up --build.
# yoink.yaml — sits alongside the Dockerfile
hosts:
- { address: my-server, user: deploy } # tailnet hostname
services:
- name: my-tool
image: my-tool # bare name; `build:` block makes it local-only
tag: dev
build:
context: . # `.` = same directory as yoink.yaml
run:
port: 8080yoink up --build~15 seconds for a small image. The build: block makes the image local-only, so yoink ships it from your docker daemon to the host over SSH via unregistry; only changed layers cross the wire.
What yoink does without you asking
The container inherits yoink's hardened defaults: read-only rootfs, no Linux caps, no setuid escalation, fork-bomb bound, tini as PID 1, healthcheck-gated swap. See secure by default for the full list.
If my-tool needs to write somewhere, give it a tmpfs:
run:
port: 8080
options:
tmpfs:
/tmp: "size=64m,mode=1777" # auto-noexec,nosuid,nodev appliedWhen to graduate
This shape stays fine for hobby / utility / internal-tool deployments. Outgrow it when:
- Replicas: single-container swap downtime is your downtime. Add
replicas: 2for rolling swap (capacity N-1). - Multiple hosts: yoink ships the build artifact from your daemon to every host on every deploy. Once painful, add a self-hosted tailnet registry so hosts pull from a shared cache.
- CI-triggered deploys: keep
build:, add a real registry, switch toyoink build --push+yoink up.
See also
- First deploy — the tutorial form of the same standalone deploy pattern.
- Standalone (no-registry) deploys — how
--buildships images over SSH without a registry. - Polyglot stack — the next shape up: multiple services, networks, and a reverse proxy.