Add edge-node advertiser compose for the Pi

The Pi is arm64 and the NAS amd64 with no shared registry yet, so this
builds from source on the target instead of pulling. SET_NAME=pi keeps its
records in a separate file from the NAS set, which is what makes two hosts
advertising into one dnsmasq safe without any merge logic.
main
Claude Opus 5 (1M context) 2026-08-05 22:21:46 -07:00
parent c562fafdd4
commit 5235e9856b
2 changed files with 49 additions and 0 deletions

View File

@ -76,3 +76,14 @@ All except `/healthz` require `Authorization: Bearer $AUTH_TOKEN`.
Run the advertiser there, changing only `SET_NAME` and `TARGET_V4`/`TARGET_V6`.
Nothing on the DNS host needs to change.
`compose.pi.yaml` is that file for the Pi, and the template for any host after
it. It is separate from `compose.yaml` because that one is the *DNS host's*
stack - dnsmasq and the receiver - while an edge node runs only the advertiser.
It uses `build:` rather than `image:` on purpose: the Pi is arm64 and the NAS is
amd64, and there is no registry both can reach yet, so building on the target is
what lets one repo serve both. Switch to `image:` once that is configured.
`SET_NAME` must be unique per host. It is the filename dnsmasq reads, so two
hosts sharing one would silently overwrite each other's records.

38
compose.pi.yaml 100644
View File

@ -0,0 +1,38 @@
# dnsmasq-advertiser for the Pi.
#
# Separate from compose.yaml because that one is the DNS HOST's stack - dnsmasq
# itself plus the receiver. Everything in here is what an EDGE node runs: just
# the advertiser, pointed at a receiver that lives somewhere else.
#
# Copy this file for any further Docker host and change only SET_NAME and
# TARGET_V4/TARGET_V6. Nothing else is host-specific.
#
# The image is built from source on the target rather than pulled. The Pi is
# arm64 and the NAS is amd64, and there is no registry both can reach yet, so
# `build:` is what makes one repo serve both architectures today. Swap to an
# `image:` line once the registry account is configured.
services:
dnsmasq-advertiser:
build:
context: ./advertiser
container_name: dnsmasq-advertiser
restart: unless-stopped
environment:
# The receiver runs on the NAS, reached over the tailnet. This is the only
# cross-host dependency, and it fails safe: if the NAS is unreachable the
# advertiser retries and dnsmasq keeps serving the last set it was given.
RECEIVER_URL: ${DNSMASQ_RECEIVER_URL:-http://100.94.2.124:8053}
AUTH_TOKEN: ${DNSMASQ_RECEIVER_TOKEN:?set DNSMASQ_RECEIVER_TOKEN}
# This host's identity. SET_NAME is the filename dnsmasq reads, so it must
# differ from every other host's or two hosts would overwrite each other.
SET_NAME: pi
TARGET_V4: ${DEFAULT_TARGET:-100.123.172.95}
# Without a v6 target dnsmasq forwards AAAA upstream for these names, and
# an IPv6-preferring client (RFC 6724) would take the public path while
# IPv4 took the tailnet.
TARGET_V6: ${DEFAULT_TARGET6:-fd7a:115c:a1e0:ab12:4843:cd96:627b:ac5f}
volumes:
# Read-only: this lists containers and follows the event stream. It never
# signals anything, so it needs no write access.
- /var/run/docker.sock:/var/run/docker.sock:ro