From 462b4179f1cf10fa63d3a060c7a46af5bc81270d Mon Sep 17 00:00:00 2001 From: Tobias Gesellchen Date: Sat, 27 Jun 2026 19:53:37 +0200 Subject: [PATCH] fix(docs,service): persist the Docker data dir at /app/data + warn when empty (refs #517) The walkthrough mounted the volume at /data, but the image's DATA_DIR is /app/data, so the documented docker run never actually persisted the datastore, settings or CA; a recreated container silently lost all state. Correct the mount path, document what lives under /app/data and the cost of losing it, and add a Windows/macOS Docker Desktop note (host networking is Linux-only; publish ports; DNS interception needs :53/:443). The service also logs a clear notice on startup when the data dir looks empty. Co-Authored-By: Claude Opus 4.8 --- cmd/soundtouch-service/main.go | 6 ++++++ .../docs/guides/EXTERNAL-HOST-WALKTHROUGH.md | 17 ++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/cmd/soundtouch-service/main.go b/cmd/soundtouch-service/main.go index 3d2ce5d..00063c1 100644 --- a/cmd/soundtouch-service/main.go +++ b/cmd/soundtouch-service/main.go @@ -485,6 +485,12 @@ func main() { if persisted.ServerURL == "" { log.Printf("Creating default settings.json in %s", sanitizeLog(config.dataDir)) + log.Printf("Data directory %s looks empty (first run). If you did NOT expect this "+ + "(e.g. after recreating a Docker container), your previous settings, datastore and "+ + "CA were not persisted; mount a persistent volume at the data dir (Docker: "+ + "-v :/app/data) so device state and the CA survive restarts. A lost CA "+ + "forces re-migrating speakers and re-trusting the new CA.", + sanitizeLog(config.dataDir)) persisted = createDefaultSettings(ds, config) } diff --git a/docs/content/docs/guides/EXTERNAL-HOST-WALKTHROUGH.md b/docs/content/docs/guides/EXTERNAL-HOST-WALKTHROUGH.md index 5de1ded..d5a2fa0 100644 --- a/docs/content/docs/guides/EXTERNAL-HOST-WALKTHROUGH.md +++ b/docs/content/docs/guides/EXTERNAL-HOST-WALKTHROUGH.md @@ -66,13 +66,28 @@ docker run -d \ --name aftertouch \ --network host \ -e SERVER_URL=http://192.0.2.10:8000 \ - -v aftertouch-data:/data \ + -v aftertouch-data:/app/data \ ghcr.io/gesellix/bose-soundtouch:latest ``` Replace `192.0.2.10` with the host machine's LAN IP. The `--network host` flag is required so AfterTouch can reach the speakers and respond to mDNS discovery. +> **Persist the data directory.** The container stores everything stateful under +> `/app/data` (`DATA_DIR`): the datastore, `settings.json`, and the service CA. +> Mount a volume there (`-v :/app/data`, as above) or this state is lost +> when the container is recreated. Losing the CA forces you to re-migrate every +> speaker and re-trust the new CA, so back this volume up before upgrading. + +> **Windows / macOS (Docker Desktop):** `--network host` does not work the same +> way as on Linux, so publish the ports explicitly instead, e.g. +> `-p 8000:8000 -p 8443:8443`. mDNS discovery across the Docker Desktop network +> boundary is unreliable; add speakers by IP in the Devices tab. If you also use +> DNS interception (so the speaker resolves Bose hostnames to AfterTouch), you +> additionally need to publish the DNS port (`-p 53:53/udp -p 53:53/tcp`) and +> make AfterTouch reachable on `:443` (the hardcoded Bose hosts are plain HTTPS), +> e.g. `-p 443:8443`. Keep the same `-v :/app/data` mount. + --- ## Step 2 — Note your host's LAN IP and open the Admin UI