fix(mdns): publish via host avahi over D-Bus (not a second daemon)
A container running its own avahi-daemon collides with the host's on :5353. Instead publish to the host avahi over its mounted D-Bus socket using avahi-tools (avahi-publish). Needs apparmor=unconfined (docker-default blocks the D-Bus publish). Documented host prereqs incl. allow-interfaces for multi-bridge hosts. Tested: publish reaches host avahi and registers the names; on hosts with many docker bridges avahi self-collides until restricted to the LAN interface. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,14 @@
|
||||
# mDNS toggle — publish *.local service names over Avahi for zero-config guest
|
||||
# resolution. Enabled when ENABLE_MDNS=true in .env (build-stack layers it in)
|
||||
# and only meaningful when BASE_DOMAIN=*.local. Host networking is required for
|
||||
# link-local multicast.
|
||||
# mDNS toggle — publish *.local service names via the HOST's avahi-daemon for
|
||||
# zero-config guest resolution. Enabled when ENABLE_MDNS=true in .env and only
|
||||
# meaningful when BASE_DOMAIN=*.local.
|
||||
#
|
||||
# Host prerequisites:
|
||||
# - avahi-daemon running on the host
|
||||
# - if the host has many interfaces (e.g. lots of docker bridges), restrict
|
||||
# avahi to the LAN NIC in /etc/avahi/avahi-daemon.conf:
|
||||
# allow-interfaces=<lan-iface>
|
||||
# otherwise avahi sees its own announcements across bridges → "Local name
|
||||
# collision" and publishing fails.
|
||||
services:
|
||||
avahi:
|
||||
build: ./docker/avahi
|
||||
@@ -9,6 +16,13 @@ services:
|
||||
container_name: avahi
|
||||
restart: unless-stopped
|
||||
network_mode: host
|
||||
# AppArmor's docker-default profile blocks the D-Bus publish to host avahi.
|
||||
security_opt:
|
||||
- apparmor=unconfined
|
||||
environment:
|
||||
BASE_DOMAIN: ${BASE_DOMAIN}
|
||||
HOST_LAN_IP: ${HOST_LAN_IP}
|
||||
DBUS_SYSTEM_BUS_ADDRESS: "unix:path=/run/dbus/system_bus_socket"
|
||||
volumes:
|
||||
# Talk to the host's avahi-daemon (host must run avahi-daemon).
|
||||
- /run/dbus/system_bus_socket:/run/dbus/system_bus_socket
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
# Self-contained mDNS responder: publishes the stack's service names on .local
|
||||
# so guests resolve them with zero DNS/client config (macOS/Linux native;
|
||||
# Windows needs Bonjour). Used only when ENABLE_MDNS=true and BASE_DOMAIN=*.local.
|
||||
# Publishes the stack's service names on .local via the HOST's avahi-daemon
|
||||
# (over its D-Bus socket — no second daemon, avoids the :5353 collision).
|
||||
# Requires the host to run avahi-daemon and the socket to be mounted (see
|
||||
# docker-compose.avahi.yml). Used when ENABLE_MDNS=true and BASE_DOMAIN=*.local.
|
||||
FROM alpine:3.20
|
||||
RUN apk add --no-cache avahi dbus
|
||||
RUN apk add --no-cache avahi-tools
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
# Publish A records for the stack's service names over mDNS (.local).
|
||||
# Requires host networking (mDNS is link-local multicast). One avahi-publish
|
||||
# per name; if any dies the container exits so Docker restarts it.
|
||||
# Publish A records for the stack's service names on .local via the HOST's
|
||||
# avahi-daemon (reached over its mounted D-Bus socket). One avahi-publish per
|
||||
# name; if any drops the container exits so Docker restarts it.
|
||||
set -eu
|
||||
|
||||
: "${BASE_DOMAIN:?BASE_DOMAIN unset}"
|
||||
@@ -12,21 +12,21 @@ case "$BASE_DOMAIN" in
|
||||
*) echo "WARN: mDNS resolves only .local — BASE_DOMAIN=$BASE_DOMAIN will NOT be discoverable via avahi. Set BASE_DOMAIN=*.local to use mDNS." >&2 ;;
|
||||
esac
|
||||
|
||||
mkdir -p /run/dbus
|
||||
rm -f /run/dbus/pid /run/dbus/system_bus_socket 2>/dev/null || true
|
||||
dbus-daemon --system
|
||||
for _ in 1 2 3 4 5; do [ -S /run/dbus/system_bus_socket ] && break; sleep 1; done
|
||||
|
||||
avahi-daemon --daemonize --no-chroot
|
||||
sleep 2
|
||||
bus="${DBUS_SYSTEM_BUS_ADDRESS:-unix:path=/run/dbus/system_bus_socket}"
|
||||
sock=${bus#unix:path=}
|
||||
if [ ! -S "$sock" ]; then
|
||||
echo "ERROR: host D-Bus socket '$sock' not found. Mount the host's" >&2
|
||||
echo " /run/dbus/system_bus_socket and ensure avahi-daemon runs on the host." >&2
|
||||
exit 1
|
||||
fi
|
||||
export DBUS_SYSTEM_BUS_ADDRESS="$bus"
|
||||
|
||||
pids=""
|
||||
for n in "$BASE_DOMAIN" "auth.$BASE_DOMAIN" "packwiz.$BASE_DOMAIN" "mc.$BASE_DOMAIN"; do
|
||||
echo "mDNS publish: $n -> $HOST_LAN_IP"
|
||||
echo "mDNS publish (host avahi): $n -> $HOST_LAN_IP"
|
||||
avahi-publish -a "$n" "$HOST_LAN_IP" &
|
||||
pids="$pids $!"
|
||||
done
|
||||
|
||||
# Block on the publishers; exit (→ restart) if one drops.
|
||||
# shellcheck disable=SC2086
|
||||
wait -n $pids 2>/dev/null || wait
|
||||
|
||||
Reference in New Issue
Block a user