From 1cba9bfc32954a5ba38b982cfa9644228003c822 Mon Sep 17 00:00:00 2001 From: Ricardo Mancinas Date: Thu, 30 Jul 2026 14:47:19 -0700 Subject: [PATCH] fix(galactus): give containers Tailscale's resolver so MagicDNS names resolve MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the image fixed, the API got as far as connecting and then died with Prisma P1001 "can't reach database server". The cause is DNS, not routing. galactus runs systemd-resolved, whose 127.0.0.53 stub is unreachable from inside a container, so Docker falls back to the upstream resolver in /run/systemd/resolve/resolv.conf — the LAN router, which knows nothing about the tailnet. Verified from a probe container on galactus: resolving galactus.tail01aa2.ts.net fails outright, while `nc 100.103.77.46 3306` is OPEN. Only the lookup was broken. Pin the api and web services to Tailscale's own resolver (100.100.100.100, the same anycast address on every tailnet) with this tailnet's search suffix. Both are overridable via TAILSCALE_DNS / TAILNET_SUFFIX. db and minio need nothing — they make no outbound calls. Verified end to end: the published image, unmodified, with only these DNS settings, boots on galactus against the real database and serves /health {"status":"ok"} /version {"service":"api","version":"master","gitSha":"3ff56e6b..."} Co-Authored-By: Claude Opus 5 --- deploy/galactus/jorgecuadros-app.compose.yml | 20 ++++++++++++++++ docs/DEPLOY_AND_MIGRATIONS.md | 24 ++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/deploy/galactus/jorgecuadros-app.compose.yml b/deploy/galactus/jorgecuadros-app.compose.yml index f496965..e8b1275 100644 --- a/deploy/galactus/jorgecuadros-app.compose.yml +++ b/deploy/galactus/jorgecuadros-app.compose.yml @@ -11,6 +11,16 @@ # name galactus's own address and the published port — exactly as on cubex # today. Do not "simplify" them to `mysql:3306`. # +# ...which means these containers have to resolve galactus's MagicDNS name, and +# by default they CANNOT. The host runs systemd-resolved, whose 127.0.0.53 stub +# is unreachable from a container, so Docker falls back to the upstream resolver +# in /run/systemd/resolve/resolv.conf — the LAN router, which knows nothing +# about the tailnet. Routing to 100.x works fine; only the lookup fails, and the +# API dies with Prisma P1001 "can't reach database server". Pointing the +# containers at Tailscale's own resolver fixes it. 100.100.100.100 is Tailscale's +# fixed anycast MagicDNS address (identical on every tailnet); the search domain +# is this tailnet's suffix. +# # The web image is NOT URL-baked: the browser's API origin is injected at # runtime from API_ORIGIN (apps/web/src/app/layout.tsx), so the same image works # for any deployment. APP_VERSION / GIT_SHA / BUILD_DATE come baked in from @@ -27,6 +37,10 @@ services: # survives stack renames; the compose service name does not. labels: io.jorgecuadros.role: "api" + dns: + - ${TAILSCALE_DNS:-100.100.100.100} + dns_search: + - ${TAILNET_SUFFIX:-tail01aa2.ts.net} environment: DATABASE_URL: ${DATABASE_URL:?DATABASE_URL must be set} SESSION_SECRET: ${SESSION_SECRET:?SESSION_SECRET must be set} @@ -59,6 +73,12 @@ services: restart: unless-stopped labels: io.jorgecuadros.role: "web" + # Next server-side rendering can call the API by API_ORIGIN, which is the + # same MagicDNS name — so the web container needs the resolver too. + dns: + - ${TAILSCALE_DNS:-100.100.100.100} + dns_search: + - ${TAILNET_SUFFIX:-tail01aa2.ts.net} environment: # Public API URL the browser calls (injected at runtime, see layout.tsx). API_ORIGIN: ${API_ORIGIN:?API_ORIGIN must be set} diff --git a/docs/DEPLOY_AND_MIGRATIONS.md b/docs/DEPLOY_AND_MIGRATIONS.md index ba06f2c..50375c1 100644 --- a/docs/DEPLOY_AND_MIGRATIONS.md +++ b/docs/DEPLOY_AND_MIGRATIONS.md @@ -148,6 +148,30 @@ service DNS: db, minio and app are three separate stacks, so three separate networks. `DATABASE_URL` and `S3_ENDPOINT` name the host and its published port. Do not "simplify" them to `mysql:3306`. +### galactus is addressed by MagicDNS, and containers need help resolving it + +galactus is Tailscale-only once it is installed in the office, so every URL +names `galactus.tail01aa2.ts.net`. Its LAN IP is a DHCP lease and has already +drifted once — never put a `192.168.4.x` address in a secret. + +Containers on galactus cannot resolve that name by default. The host runs +systemd-resolved, whose `127.0.0.53` stub is unreachable from inside a +container, so Docker falls back to the upstream resolver listed in +`/run/systemd/resolve/resolv.conf` — the LAN router, which knows nothing about +the tailnet. Routing to `100.x` works fine; only the *lookup* fails, and the +symptom is Prisma **P1001 "can't reach database server"** on a container that +otherwise started cleanly. + +`deploy/galactus/jorgecuadros-app.compose.yml` therefore pins the resolver: + +```yaml +dns: [100.100.100.100] # Tailscale's fixed anycast MagicDNS address +dns_search: [tail01aa2.ts.net] # this tailnet's suffix +``` + +Both are overridable (`TAILSCALE_DNS`, `TAILNET_SUFFIX`) if the tailnet changes. +Browser-facing origins need none of this — those names resolve on the client. + ## Replication galactus's MySQL is the **master**; every other MySQL in the estate is a