# Quadlet unit: alloy (ROOT system service, boot-persistent). # # Install path on dankclaw: /etc/containers/systemd/alloy.container # Unit name: alloy.service (container name: alloy) — SYSTEM manager, root. # # WHY ROOT (not rootless, unlike its observability siblings). Alloy reads the # host journal. The journal files are root:systemd-journal 0640 (other::---); # a rootless container carries no supplementary groups and cannot open them — # a rootless read of system.journal returns DENIED (see the Alloy page in the # vault). Running as root, one loki.source.journal reads system.journal AND # user-1000.journal, so it carries both host logs and the rootless Quadlet # containers' logs. Validated 2026-10-20: a root probe read 31,825 journal # lines and pushed 26,966 into Loki in 20 s, zero drops. # # NETWORK=host. Loki publishes 127.0.0.1:3100 (loopback only) on the host, and # no bridge container — rootless or root — can reach the host's loopback, so # this unit runs on the host network and pushes to 127.0.0.1:3100. The side # effect: the UI must bind loopback too, so Exec sets the listen-addr to # 127.0.0.1 (the old rootless unit used 0.0.0.0 only because container loopback # was not host loopback; under Network=host they are the same address, so the # unauthenticated UI stays loopback-only — nothing off-host reaches it). # # THE /etc/machine-id MOUNT IS LOAD-BEARING. sd_journal locates the journal # directory by the local machine id; without it the container opens nothing and # the journal source reads exactly 0 lines — silently, no error, health green. # This mount is the entire reason the pipeline carries data. Never remove it. # # IMAGE. Built rootless by build_compose_image alloy, then mirrored into the # root image store by the deployer (a root build runs in the build container's # own resolver and fails on DNS here). Pull=never: boot must not reach for the # local tag at a registry. [Unit] Description=Alloy log shipper (Dankclaw) After=network-online.target [Container] ContainerName=alloy Image=localhost/franksdank/alloy:latest Pull=never Network=host Exec=run --server.http.listen-addr=127.0.0.1:12345 /etc/alloy/config.alloy Volume=/opt/alloy/config:/etc/alloy:ro Volume=/etc/machine-id:/etc/machine-id:ro Volume=/run/systemd/journal/socket:/run/systemd/journal/socket:ro Volume=/var/log/journal:/var/log/journal:ro Volume=/run/log/journal:/run/log/journal:ro HealthCmd=/usr/local/bin/busybox wget --spider -q http://127.0.0.1:12345/-/healthy HealthInterval=30s HealthTimeout=10s HealthRetries=3 HealthStartPeriod=30s [Service] Restart=always RestartSec=10 [Install] WantedBy=multi-user.target