Skip to content

feat(dawarich): keep managed Dawarich off the shared Docker network - #683

Merged
Medformatik merged 1 commit into
mainfrom
feat/dawarich-network-isolation
Oct 30, 2026
Merged

Medformatik merged 1 commit into
mainfrom
feat/dawarich-network-isolation

Conversation

@Medformatik

Copy link
Copy Markdown
Collaborator

What changed and why

This is the follow-up to #681: the managed Dawarich containers leave the shared openmapx Docker network. URLs that Dawarich users configure can then no longer reach OpenMapX's internal services.

Dawarich fetches URLs its users choose:

  • Since 1.18, the worker sends geofence events to each user's webhook.
  • The worker runs the Immich and PhotoPrism imports.
  • The web app proxies photo thumbnails and returns the fetched body (send_data(upstream.body) for any 2xx answer).

The managed app runs with SELF_HOSTED=true, so Dawarich accepts private addresses and Docker service names. On openmapx, a Dawarich user could reach any OpenMapX service. Through the thumbnail proxy they could also read the body of any GET that answered 2xx.

The four Dawarich containers now use two private networks instead:

Network Members
openmapx-private-dawarich app, worker, Postgres, Redis; internet access as before
openmapx-private-dawarich-ingress app, plus traefik (public route) and app-api (timeline reads via http://dawarich-app:3000)

Manifest capability

This needed a new first-party manifest capability:

  • privateNetworks names the openmapx-private-<name> networks a service joins.
  • platformNetwork: false keeps a service off openmapx, and requires at least one private network.
  • Bridges: a service that stays on openmapx and lists a private network, like Traefik and app-api, joins it only while an enabled member that left openmapx declares it. Installs without Dawarich render no extra network.
  • Addressing: each private network is dual-stack like openmapx, with a stable IPv6 /64 derived from its name inside fd4d:5058::/48, so IPv6 webhook egress keeps working. The renderer fails if two names derive the same /64.
  • Aliases: for a service off openmapx, network aliases go on its private networks.
  • Policy: community manifests can't declare either field, at validation or at render, and neither combines with host networking.

The JSON schema, OpenAPI document and generated SDK model are regenerated. @openmapx/extension-contracts gets a minor changeset, and the extension CLI a patch to rebuild against it.

Reach that remains

  • Webhooks inside the bundle: a webhook can still target the bundle's own Postgres (password-protected), Redis (which drops HTTP-looking connections) and web app.
  • Web app to Traefik and app-api: the web app can reach Traefik's public entrypoints and app-api. Through the thumbnail proxy, a user could read app-api's unauthenticated /api/internal/metrics counters, which contain no personal data, and its public routes.
  • External proxy: with OPENMAPX_PROXY_NETWORK, the web app also joins the operator's proxy network, as before.

Docs

  • The service manifest reference documents both fields, bridge semantics and the Dawarich topology.
  • The Dawarich runbook replaces the webhook-reach warning with the isolation design and the remaining reach. Its 1.15.3 → 1.19.0 section notes that Compose recreates the containers on the new networks.
  • The unreleased managed-dawarich-1-19 fragment now describes the isolation instead of the reach. Its required action now covers operators' own services that called Dawarich over openmapx.

Verification

  • Renderer tests: new unit tests cover private-only members, aliases on private networks, bridge gating, distinct subnets and the policy rejections. A test against the shipped manifests asserts the full topology with Dawarich enabled, and that a stack without Dawarich renders only openmapx.
  • Live topology: I ran the rendered network blocks in Docker with the pinned Dawarich 1.19.0, PostGIS and Redis 8.10 images and stand-ins for app-api, Traefik and openmapx-only peers. Only the openmapx stand-in moved to another ULA, because a local stack already holds fd4d:5058::/64.
    • The app is healthy, binding :: on the dual-stack private network.
    • app-api and Traefik reach dawarich-app:3000/api/v1/health; an openmapx-only peer cannot resolve it.
    • From the worker, openmapx names don't resolve, and direct IPv4 and IPv6 connections to their addresses time out.
    • Dawarich's own Webhook#resolved_url_ip! fails for data-manager and app-api with BlockedUrlError and resolves example.com.
    • Both the worker and the web app still fetch https://example.com (200).
    • The web app reaches app-api and Traefik but no other openmapx peer.
  • Repository checks: pnpm lint, pnpm check-types, pnpm check:policy, pnpm check-openapi, pnpm check-service-files and the contract schema check pass. The full Vitest suite passes: 1,950 files, 24,062 tests.
  • Not run: moving a real deployment's running containers onto the new networks, OIDC sign-in and the timeline day viewer against a live stack, Linux Docker Engine (I verified the isolation on Docker Desktop) and any deployment.

Release and upgrade impact

Product impact: security, operator-action

The next stack update recreates the four Dawarich containers on the private networks and adds Traefik and app-api to the ingress network; volumes are untouched. If you added your own service that calls dawarich-app or the Dawarich database by name over openmapx, it loses that reach.

Dawarich fetches URLs its users choose (geofencing webhooks, Immich and
PhotoPrism imports and the thumbnail proxy) and, in self-hosted mode,
accepts private addresses. Move its four containers onto private networks:
one for the bundle and internet access, one through which only Traefik and
app-api reach the web app. A new first-party manifest capability,
privateNetworks with platformNetwork: false, renders them.
@Medformatik Medformatik added documentation Documentation content, tooling or workspace dependencies docker Container images and Docker build or deployment tooling labels Oct 30, 2026
@Medformatik Medformatik self-assigned this Oct 30, 2026
@Medformatik
Medformatik merged commit 250aa78 into main Oct 30, 2026
28 checks passed
@Medformatik
Medformatik deleted the feat/dawarich-network-isolation branch October 30, 2026 07:33
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 30, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

docker Container images and Docker build or deployment tooling documentation Documentation content, tooling or workspace dependencies

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant