Skip to main content

DEFAULT_TEMPLATE

Constant DEFAULT_TEMPLATE 

Source
pub const DEFAULT_TEMPLATE: &str = "#cloud-config\n# yah-cloud mirror bootstrap (R092-F2 \u{2014} containerd + yubaba + cloudflared + tailscaled).\n#\n# Substitutions (written as {{ KEY }} with inner spaces so these docs survive rendering):\n#   {{ MACHINE_NAME }}           \u{2014} machine name from .yah/cloud/machines/<name>.toml\n#   {{ YAH_YUBABA_URL }}         \u{2014} HTTPS URL of the yah-yubaba release tar.gz\n#                                  (published by .github/workflows/release.yml per musl target;\n#                                  R406-T13: now also contains the kamaji binary +\n#                                  yubaba.service + kamaji.service + yubaba.slice)\n#   {{ YAH_YUBABA_SHA256 }}      \u{2014} lowercase hex sha256 of the tar.gz at YAH_YUBABA_URL\n#   {{ YUBABA_CHANNEL }}         \u{2014} release channel: stable | beta\n#   {{ CONTAINERD_VERSION }}     \u{2014} containerd apt version pin (e.g. 1.7.2~3-0~debian-bookworm);\n#                                  use DEFAULT_CONTAINERD_VERSION constant for Phase 1 baseline\n#   {{ HEADSCALE_PREAUTH_KEY }}  \u{2014} Tailscale/Headscale pre-auth key (consumed once at join)\n#   {{ MESH_LOGIN_SERVER_ARG }}  \u{2014} expands to ` --login-server <url>` when a custom Headscale\n#                                  coordinator is configured; empty string for Tailscale SaaS\n#   {{ TAGS }}                   \u{2014} comma-joined machine.mesh_tags for Tailscale advertise-tags\n#   {{ CLOUDFLARED_BLOCK }}      \u{2014} cloudflared apt-repo install + `cloudflared service install\n#                                  <tok>` (token is a positional arg, not a --token flag \u{2014}\n#                                  R330-B29) + `systemctl enable --now cloudflared` when\n#                                  machine.cloudflared is set; empty string otherwise\n#   {{ OPERATOR_BRIDGE_BLOCK }}  \u{2014} tailscaled install + `tailscale up` + ufw allow on tailscale0\n#                                  when machine.hosts_operator_bridge = true; empty otherwise\n#   {{ COSIGN_VERIFY_BLOCK }}    \u{2014} cosign install + `cosign verify-blob` of the yubaba tarball\n#                                  against a pinned GitHub-OIDC identity-regexp when\n#                                  yubaba_cosign_identity_regexp is set (R330-F19/F20); empty\n#                                  string otherwise (sha256 verify stays as the trust gate)\n#\n# The yubaba tarball is curl-fetched at boot (not base64-embedded) because Hetzner caps\n# user_data at 32 KiB (R040-F11). The runcmd verifies sha256, extracts, and installs\n# /usr/local/bin/yubaba + /usr/local/bin/kamaji + three systemd units under\n# /etc/systemd/system/ before the systemd hand-off.\n#\n# Supervision model (W154, R406-T13): yubaba.service and kamaji.service are sibling\n# units, both pinned to yubaba.slice (created by the slice unit, owned by kamaji via\n# Slice= directive). Kamaji starts first (UDS server up before yubaba\'s first Hello);\n# yubaba joins on After=kamaji.service. systemd\'s role is reduced to supervising the\n# two siblings \u{2014} it does NOT see individual workloads, which kamaji owns directly via\n# pidfds + cgroup-v2 syscalls under yubaba.slice.\n#\n# Containerd is the container runtime yubaba drives via gRPC. Podman/podman-compose\n# were removed in R092-F2 (yubaba is now the workload lifecycle owner; see yah-yubaba-\n# integration-testing.md for the ContainerRuntime abstraction).\n#\n# Tailscale (operator-bridge) is optional: only installed when machine.hosts_operator_bridge\n# is true. The yubaba cluster mesh uses its own WireGuard plane (yah-cluster-mesh.md) and\n# does not depend on Tailscale for cluster-internal traffic.\n\nhostname: {{MACHINE_NAME}}\npreserve_hostname: false\n\npackage_update: true\npackage_upgrade: true\npackages:\n  - wireguard-tools\n  - chrony\n  - curl\n  - ca-certificates\n  - openssh-server\n  - ufw\n\nruncmd:\n  # Disk bounds FIRST, before anything on this box starts writing. yah doctrine:\n  # no process ever grows on disk without an explicit ceiling \u{2014} a full disk takes\n  # the node down no matter how good the software above it is. Debian\'s journald\n  # default is 10% of the filesystem (capped at 4G), which is a fraction, not a\n  # bound. RuntimeMaxUse also bounds RAM, since /run is tmpfs.\n  - mkdir -p /etc/systemd/journald.conf.d\n  - sh -c \'printf \"[Journal]\\nSystemMaxUse=500M\\nSystemKeepFree=1G\\nSystemMaxFileSize=50M\\nRuntimeMaxUse=64M\\n\" > /etc/systemd/journald.conf.d/10-yah-disk-bounds.conf\'\n  - systemctl restart systemd-journald\n  # containerd \u{2014} kamaji\'s container backend. Installed unpinned: yubaba drives\n  # it over a stable gRPC API, and an exact apt version pin matches neither the\n  # Debian repo\'s suffixed versions (e.g. 1.6.20~ds1) nor newer point releases,\n  # so it broke first-boot on Debian 12/13 alike (R330-T9).\n  - apt-get install -y containerd\n  - systemctl enable --now containerd\n  # Yubaba + kamaji bundle \u{2014} fetch + verify + install (R406-T13).\n  # The tarball contains: yubaba, kamaji, yubaba.service, kamaji.service,\n  # yubaba.slice. cloud-init lays the binaries under /usr/local/bin and the units\n  # under /etc/systemd/system/ before systemctl daemon-reload.\n  - curl -fsSL -o /tmp/yah-yubaba.tar.gz {{YAH_YUBABA_URL}}\n  # cosign verify-blob \u{2014} primary trust gate when yubaba_cosign_identity_regexp is\n  # set (R330-F19/F20). sha256 line below stays as a redundant integrity check.\n{{COSIGN_VERIFY_BLOCK}}\n  - sh -c \'echo \"{{YAH_YUBABA_SHA256}}  /tmp/yah-yubaba.tar.gz\" | sha256sum -c -\'\n  - tar -xzf /tmp/yah-yubaba.tar.gz -C /tmp\n  - sh -c \'cp /tmp/yubaba-*/yubaba /usr/local/bin/yubaba\'\n  - sh -c \'cp /tmp/yubaba-*/kamaji /usr/local/bin/kamaji\'\n  - chmod +x /usr/local/bin/yubaba /usr/local/bin/kamaji\n  - sh -c \'cp /tmp/yubaba-*/yubaba.slice /etc/systemd/system/yubaba.slice\'\n  - sh -c \'cp /tmp/yubaba-*/kamaji.service /etc/systemd/system/kamaji.service\'\n  - sh -c \'cp /tmp/yubaba-*/yubaba.service /etc/systemd/system/yubaba.service\'\n  # litestream-headscale.service \u{2014} headscale DB replication for whichever node\n  # holds the ingress owner role. Laid down here and never enabled: leader.rs\n  # starts it on gaining that role and stops it on losing it. It MUST be\n  # pre-staged for the same reason headscale.service is (see the coordinator\n  # pre-stage block below) \u{2014} yubaba runs ProtectSystem=strict and cannot write\n  # /etc/systemd/system, so a unit it \"installs\" at runtime is a silent EROFS.\n  - sh -c \'cp /tmp/yubaba-*/litestream-headscale.service /etc/systemd/system/litestream-headscale.service\'\n  - chmod 0644 /etc/systemd/system/yubaba.slice /etc/systemd/system/kamaji.service /etc/systemd/system/yubaba.service /etc/systemd/system/litestream-headscale.service\n  - sh -c \'rm -rf /tmp/yah-yubaba.tar.gz /tmp/yubaba-*\'\n  # litestream \u{2014} the replicate/restore binary litestream-headscale.service execs\n  # and leader.rs shells for `litestream restore` before starting the appliance.\n  # Absent from every node in the fleet as of 2026-09-04, which made the whole\n  # DB-continuity path inert regardless of configuration.\n  #\n  # PINNED TO 0.3.13, NOT LATEST (0.5.x): litestream 0.5 is a rewrite onto the\n  # LTX format with a changed config schema, and `litestream::generate_config`\n  # emits the 0.3 `dbs[].replicas[].url` shape. Moving to 0.5 is a real\n  # migration \u{2014} new config emitter, and a replica written by 0.3 is not a\n  # replica 0.5 reads \u{2014} not a version bump. Checksums below were computed by\n  # downloading these exact assets, not copied from the release page.\n  # A BLOCK SCALAR, not a plain multi-line one: the `echo \"litestream: ...\"`\n  # below contains a colon-space, which YAML reads as a mapping indicator and\n  # which broke this template\'s parse when it was first written inline.\n  - |-\n    sh -c \'\n      case \"$(dpkg --print-architecture)\" in\n        amd64) LS_ARCH=amd64; LS_SHA=eb75a3de5cab03875cdae9f5f539e6aedadd66607003d9b1e7a9077948818ba0 ;;\n        arm64) LS_ARCH=arm64; LS_SHA=9585f5a508516bd66af2b2376bab4de256a5ef8e2b73ec760559e679628f2d59 ;;\n        *) echo \"litestream: unsupported arch, skipping\" >&2; exit 0 ;;\n      esac\n      curl -fsSL -o /tmp/litestream.tar.gz \\\n        \"https://github.com/benbjohnson/litestream/releases/download/v0.3.13/litestream-v0.3.13-linux-${LS_ARCH}.tar.gz\"\n      echo \"${LS_SHA}  /tmp/litestream.tar.gz\" | sha256sum -c -\n      tar -xzf /tmp/litestream.tar.gz -C /usr/local/bin litestream\n      chmod +x /usr/local/bin/litestream\n      rm -f /tmp/litestream.tar.gz\n    \'\n  # headscale \u{2014} the coordination server\'s own binary, on EVERY node rather than\n  # only the one that was promoted (R858-T4).\n  #\n  # Why every node: `headscale_appliance::appliance_spec` is a NATIVE workload,\n  # so kamaji forks `/var/lib/yah-cloud/headscale/headscale` and pulls nothing.\n  # Until now the binary arrived only via `POST /headscale/deploy` \u{2014} the promote\n  # path \u{2014} which is why us-west-001 had it (51,593,368 bytes, mtime Jun 22) and\n  # us-south-001 had no binary, no config.yaml and no DB. On 2026-09-03\n  # ownership moved to south anyway and the appliance ran nowhere for 37 hours.\n  # A moveable native appliance needs its executable to be a PROVISIONED\n  # PREREQUISITE on every candidate, not a side effect of having once been the\n  # coordinator. Staged and never started: leader.rs decides who runs it.\n  #\n  # Pinned to 0.23.0 \u{2014} the same pin `cloud::mesh::HEADSCALE_VERSION` and\n  # `yubaba::DEFAULT_HEADSCALE_VERSION` already carry, kept in lockstep by\n  # convention like the config renderers (there is no dependency edge from this\n  # template to either constant, so a bump has to touch all three).\n  #\n  # Checksums were computed by DOWNLOADING these exact assets, not copied off\n  # the release page \u{2014} the same standard the litestream block above records. The\n  # amd64 size matches the binary already on us-west-001 byte-for-byte, which is\n  # the corroboration that this is the asset the fleet is already running.\n  #\n  # A BLOCK SCALAR for the same reason as litestream\'s: the `echo \"headscale:\n  # ...\"` below contains a colon-space, which YAML reads as a mapping indicator.\n  - |-\n    sh -c \'\n      case \"$(dpkg --print-architecture)\" in\n        amd64) HS_ARCH=amd64; HS_SHA=d9193dad4b070b9b3f6d54c8f14366952944b6e917672c0bc1dfd8f5491287a7 ;;\n        arm64) HS_ARCH=arm64; HS_SHA=99fa9b2944c50759882b578e78aa11968d6fdec9bbfeced88237a1138b89e9fe ;;\n        *) echo \"headscale: unsupported arch, skipping\" >&2; exit 0 ;;\n      esac\n      mkdir -p /var/lib/yah-cloud/headscale\n      curl -fsSL -o /tmp/headscale \\\n        \"https://github.com/juanfont/headscale/releases/download/v0.23.0/headscale_0.23.0_linux_${HS_ARCH}\"\n      echo \"${HS_SHA}  /tmp/headscale\" | sha256sum -c -\n      mv /tmp/headscale /var/lib/yah-cloud/headscale/headscale\n      chmod +x /var/lib/yah-cloud/headscale/headscale\n    \'\n  # Channel goes into a drop-in (yubaba.service\'s ExecStart bakes the default args;\n  # the channel is operator-tunable per node).\n  - mkdir -p /etc/systemd/system/yubaba.service.d\n  - sh -c \'printf \"[Service]\\nEnvironment=YUBABA_CHANNEL={{YUBABA_CHANNEL}}\\n\" > /etc/systemd/system/yubaba.service.d/channel.conf\'\n  # Cloudflare Tunnel \u{2014} public ingress (when machine.cloudflared is set)\n{{CLOUDFLARED_BLOCK}}\n  # Operator-bridge \u{2014} Tailscale mesh access (when machine.hosts_operator_bridge = true)\n{{OPERATOR_BRIDGE_BLOCK}}\n  # Firewall \u{2014} allow SSH; yubaba RPC (7443) reachability depends on mesh role:\n  # mesh-only (deny public) when joining a mesh, or public on a standalone\n  # coordinator so the operator can attach + `yah mesh bootstrap` it before any\n  # mesh exists to reach it over (R330-F28 #13).\n  - ufw --force enable\n  - ufw allow 22/tcp\n{{UFW_YUBABA_RULE}}\n  # Coordinator pre-stage (standalone only) \u{2014} cloud-init runs unsandboxed at boot,\n  # so it lays down the headscale.service unit + opens ufw 80/443 here. yubaba runs\n  # under ProtectSystem=strict and CANNOT write /etc/systemd/system or /etc/ufw, so\n  # `yah mesh bootstrap` only writes config + `systemctl enable --now headscale`\n  # against this pre-staged unit (R330-F28 #15). Empty for joining nodes.\n{{COORDINATOR_PRESTAGE_BLOCK}}\n  # /var/lib/yah/yubaba (the secret store, in yubaba.service\'s ReadWritePaths)\n  # is created by the unit itself via StateDirectory=yah/yubaba (R589-T2), so no\n  # pre-mkdir crutch is needed here \u{2014} the unit no longer fails 226/NAMESPACE.\n  # Bring up the supervision tree (W154 ordering): slice \u{2192} kamaji \u{2192} yubaba.\n  # kamaji.service has After=yubaba.slice + PartOf=yubaba.slice; yubaba.service\n  # has After=kamaji.service + Wants=kamaji.service, so enabling yubaba\n  # transitively starts the other two \u{2014} but enabling each explicitly here makes\n  # the bring-up order deterministic and surfaces failure on the right unit.\n  - systemctl daemon-reload\n  - systemctl enable --now yubaba.slice\n  - systemctl enable --now kamaji.service\n  - systemctl enable --now yubaba.service\n";
Expand description

Built-in fallback template, used when .yah/infra/cloud-init/mirror.yml is absent. Keeps the binary self-contained for tests + new workspaces.