# DNS strategy + run modes How names resolve and which layers come up. Supersedes the "dnsmasq is core" assumption in `01-dnsmasq.md`. ## Domain: `.lan`, not `.local` `BASE_DOMAIN=ulicraft.lan` by default. `.local` is intercepted by mDNS on macOS/Linux and does **not** resolve through a normal unicast DNS server (that was the `DNS_PROBE_FINISHED_NXDOMAIN`). Use `.local` only with the mDNS path below. ## Run modes — `tooling/build-stack.sh --up ` | Mode | Compose layers | Use | |---|---|---| | `online` | base + static | internet present; landing + launcher; no mirror | | `airgap` | base + static + mirror | no internet; full asset mirror on `:443` (default) | | `core` | base | debugging | Base = drasl, minecraft, mc-backup, caddy(auth+packwiz). `static` = apex landing + launcher + `/ca.crt`. `mirror` = upstream spoof vhosts (`tls internal`) + `:443` + caddy aliases. `--up` prints the DNS records for the chosen mode. ## DNS: your own party server (primary) You run the party DNS. Generate records with `tooling/dns-records.sh `: - `online` → service names (`${BASE_DOMAIN}`, `auth.`, `packwiz.`, `mc.`) → `HOST_LAN_IP` - `airgap` → the above **plus** the spoofed upstreams (`meta.prismlauncher.org`, `piston-meta`/`piston-data.mojang.com`, `libraries.minecraft.net`, `maven.neoforged.net`, `resources.download.minecraft.net`) → `HOST_LAN_IP` Output formats: plain, `/etc/hosts`, BIND zone, dnsmasq `address=`, plus the Minecraft SRV line. Minecraft needs no port (`mc.${BASE_DOMAIN}` defaults to 25565). ## Optional resolver layers - **dnsmasq** (`docker-compose.dnsmasq.yml`) — turnkey DNS if you don't run your own. Binds `${HOST_LAN_IP}:53`. Serves the rendered `dnsmasq/dnsmasq.conf` (wildcard + airgap spoofs). - **mDNS / Avahi** (`docker-compose.avahi.yml`, `ENABLE_MDNS=true`) — zero-config `.local` for guests (macOS/Linux native; Windows needs Bonjour). See below. ## mDNS path (ENABLE_MDNS=true + BASE_DOMAIN=*.local) The `avahi` container publishes the service names to the **host's** avahi-daemon over its D-Bus socket (it does NOT run its own daemon — that collides with the host on `:5353`). Requirements / gotchas (build-stack warns on these): - host runs `avahi-daemon`; `/run/dbus/system_bus_socket` mounted in. - `security_opt: apparmor=unconfined` on the container (docker-default AppArmor blocks the D-Bus publish). - multi-interface hosts (e.g. many docker bridges) → avahi self-collides ("Local name collision"); set `allow-interfaces=` in `/etc/avahi/avahi-daemon.conf`. - mDNS resolves **only** `.local`, so it cannot serve the air-gap upstream spoofs (real public hostnames) — those always need real DNS. ## Status (tested 2026-05-24) - `.lan` + own-DNS path: verified end-to-end (apex/auth/packwiz/ca.crt/mirror all 200, minecraft healthy). - mDNS publish mechanism: verified reaching host avahi; full green-light blocked on this dev box only by its 38 docker bridges (allow-interfaces fixes it).