Skip to content

stack: realtime service cannot run (or be consumed) in docker mode #5788

Description

@martijnwalraven

Pinned at: develop @ 31d6fb97 · macOS arm64 (Darwin 25.5), Docker Desktop (server 29.5.3), Node 24.18.0, realtime image v2.112.3 (DEFAULT_VERSIONS), consuming @supabase/stack via createStack().

Enabling realtime in docker mode (createStack({ mode: "docker", realtime: { port } })) never reaches ready, and even a healthy realtime container can't be consumed by supabase-js through the stack. Three findings, plus one observation:

1. The realtime container can't reach postgres — start() hangs indefinitely.
The realtime ServiceDef's env (packages/stack/src/services/realtime.ts) doesn't set DB_IP_VERSION. On Docker Desktop for Mac, every connection attempt fails with:

Postgrex.Protocol failed to connect: ** (DBConnection.ConnectionError)
tcp connect (host.docker.internal:53976): network is unreachable - :enetunreach

— while getent ahosts host.docker.internal inside the same image resolves IPv4-only (192.168.65.254), and GoTrue/PostgREST connect fine over the identical wiring. The migration runner gives up after ~15s, the container exits, unless-stopped restart-loops it forever, and stack.start() waits with no diagnostic (the no-timeout behavior noted in #5787 makes this a silent hang).

Verified fix: re-running the identical container with only DB_IP_VERSION=ipv4 added makes migrations run instantly. This looks like the known realtime self-host IPv6-preference gotcha; the ServiceDef probably wants DB_IP_VERSION=ipv4 for the host.docker.internal path.

Worth noting the docker-mode e2e suite doesn't enable realtime, so this path appears never to have been exercised.

2. The ApiProxy can't carry realtime websockets.
The proxy routes /realtime/v1/* as plain HTTP (ApiProxy.ts) and neither it nor the Node platform layer (node.ts — bare createServer()) registers any upgrade handling, so supabase-js — which derives wss://…/realtime/v1/websocket from the project URL — can never connect through stack.url.

3. The direct service endpoint can't serve supabase-js either.
Bypassing the proxy fails independently three ways: the bare realtime server 404s /realtime/v1/websocket (it serves /socket/websocket; the /realtime/v1 prefix is proxy vocabulary), tenant resolution is Host-based (bare-IP → 401 {"message":"Tenant not found in database"}; Host: realtime-dev → 200), and the apikey must be a real JWT since the proxy's publishable-key→JWT transform is HTTP-only. A raw handshake at /socket/websocket with a tenant-bearing hostname and a signed anon JWT does return 101 — so websocket upgrade support in the proxy (path rewrite + tenant Host + the existing auth transform) would make supabase-js work end-to-end with no client changes.

4. Observation, not root-caused: with finding 1 worked around and a 101 handshake established, channel joins still fail with UnableToConnectToTenantDatabase / UnableToConnectToProject — the SEED_SELF_HOST tenant's own (encrypted-settings) connection pool appears not to honor the env-level IPv4 fix. Happy to provide the full repro.

Suggested resolutions: DB_IP_VERSION=ipv4 (or equivalent) in the realtime ServiceDef; websocket upgrade support in the ApiProxy; realtime coverage in the docker-mode e2e.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions