Repository navigation
Fix the full-Docker dev stack: no webapp source in the container, and no host.docker.internal on Linux #482
Copy link
Copy link
Closed
Labels
Milestone
Description
Summary
The README offers make up-dev as the full-Docker way to run docs.plus locally. Two compose problems break it. The webapp container has no webapp source. On Linux with Docker Engine, the REST and WebSocket containers cannot reach local Supabase. A third gap leaves push off on this path: no service gets a VAPID key.
- Severity: Medium. The full-Docker alternative does not serve the app. The default
make dev-localpath works. - Area:
docker-compose.dev.yml - Source: docs and README review of 2026-10-14. Five review agents each covered one docs area. A separate agent then checked each finding against the code and tried to refute it. Every item below survived that check. "Checked" lists the evidence. Item 3 was added on 2026-10-14 from the staff review of Fix the first-run docs: Supabase Cloud steps, full-Docker order, and local setup gaps #483.
Items
1. In the full-Docker alternative, the webapp container has no webapp source, so make up-dev cannot serve the app at http://localhost:3000.
- Where:
README.md:80 - Severity: medium
- Checked: Confirmed by reading the files. Nothing was run. README.md:80-117 offers
make up-devand lists webapp at http://localhost:3000.make -n up-devrunsdocker compose -f docker-compose.dev.yml --env-file .env.developmentwith no override file. The webapp service is in docker-compose.dev.yml:271-313. It buildstarget: build-extensionsand mounts only./packages:/app/packagesplus the anonymous/app/node_modules. It runsbun run dev:ci(next dev --turbopack, apps/webapp/package.json:8) in/app/apps/webapp. In apps/webapp/docker/Dockerfile.bun, the build-extensions stage getsapps/only from deps (line 94). Deps copies onlyapps/webapp/package.json(line 58). So the container has no webappsrc/,pages, ornext.config. Commit 006e7c9 shows the cause. Before the move, the webapp lived atpackages/webapp, so the./packagesmount covered it. The commit changedworking_dirto/app/apps/webappbut added no mount, and the old comment ('webapp with .next') is now stale. The admin-dashboard service mounts./apps/admin-dashboard(line 361), so the gap is specific to the webapp. A reader who follows README §Alternative: full Docker gets no webapp on port 3000. The proposed fix needs one more line. A bare./apps/webappmount would also mount the host'sapps/webapp/node_modules, which exists and links into the host's own Bun store. In the container, those links can point at missing or macOS-only packages. An anonymous volume for that path keeps the image's own copy. - Fix: In docker-compose.dev.yml, add these lines to the webapp
volumes:list:- ./apps/webapp:/app/apps/webappand- /app/apps/webapp/node_modules. The second line keeps the host's macOS node_modules out of the container. Fix the stale mount comment at the same time. Fix the first-run docs: Supabase Cloud steps, full-Docker order, and local setup gaps #483 owns the README §Alternative: full Docker text, so this issue changes no README line.
2. On Linux with Docker Engine, the REST and WebSocket containers cannot resolve host.docker.internal, so they cannot reach local Supabase.
- Where:
README.md:104 - Severity: medium
- Checked: README.md:104 says "The containers read
SUPABASE_URL: http://host.docker.internal:54321from the host". .env.example:70 setsSUPABASE_URL=http://host.docker.internal:54321. The Makefileup-devtarget (Makefile:138) passes it in with--env-file .env.development. In docker-compose.dev.yml, rest-api (:92) and hocuspocus-server (:164) takeSUPABASE_URL: ${SUPABASE_URL}and have noextra_hosts. Only webapp (:288-289) and admin-dashboard (:349-350) have'host.docker.internal:host-gateway'. This shows the maintainers knew about the Linux gap but did not add the entry to the two backend services. Plain Docker Engine on Linux does not resolvehost.docker.internalunlesshost-gatewayis mapped. The backend creates its anon and service-role Supabase clients from this URL (apps/hocuspocus.server/src/lib/supabase.ts:50,63). It also uses the URL in api/middleware/adminAuth.ts, the health service and the MCP module. So on Linux, every backend call to Supabase fails while the containers still look healthy. The README says nothing about Linux limits. Its only platform note, README.md:35, advises OrbStack on macOS. This is not a settled decision. Medium is the right severity. The stack starts, but every backend path that needs Supabase fails, and the reader loses time finding out why. The best fix is the compose change, because it is two lines in each service and matches the existing webapp entry. A README caveat alone leaves the bug in place. - Fix: In docker-compose.dev.yml, add
extra_hosts: ['host.docker.internal:host-gateway']to the rest-api and hocuspocus-server services, the same as webapp (:288) and admin-dashboard (:349). This needs no README change.
3. The dev compose file passes no VAPID key to any service, so push cannot work on the make up-dev path.
- Where:
docker-compose.dev.yml, servicesrest-api,hocuspocus-workerandwebapp - Severity: low
- Checked:
grep -n VAPID docker-compose.dev.ymlprints nothing. The file has noenv_file:(comment atdocker-compose.dev.yml:94), so a key set in.env.developmentreaches a container only when itsenvironment:list names it. Production names three:VAPID_PUBLIC_KEYonrest-api(docker-compose.prod.yml:212), all threeVAPID_*keys onhocuspocus-worker(:435–:437), andNEXT_PUBLIC_VAPID_PUBLIC_KEYonwebapp(:530). The webapp reads that key atapps/webapp/src/utils/push-notifications.ts:5. The worker sends the pushes (apps/hocuspocus.server/src/lib/push/sender.ts). So on this path the browser cannot subscribe and the worker cannot send, even when Fix the first-run docs: Supabase Cloud steps, full-Docker order, and local setup gaps #483 item 2 adds the key to the README. - Fix: In
docker-compose.dev.yml, mirror production. AddVAPID_PUBLIC_KEY: ${VAPID_PUBLIC_KEY:-}torest-api. AddVAPID_PUBLIC_KEY: ${VAPID_PUBLIC_KEY:-}andVAPID_PRIVATE_KEY: ${VAPID_PRIVATE_KEY:-}tohocuspocus-worker. Copy production'sVAPID_SUBJECT: ${VAPID_SUBJECT:-mailto:support@docs.plus}line exactly. An empty default would pass"", and the schema default (apps/hocuspocus.server/src/config/env.schema.ts:140) replaces only a missing value. AddNEXT_PUBLIC_VAPID_PUBLIC_KEY: ${NEXT_PUBLIC_VAPID_PUBLIC_KEY:-}to thewebappenvironment:list. No build arg is needed, because the dev webapp runsnext dev, which readsNEXT_PUBLIC_*values when it compiles. Push stays optional: with the keys empty, the stack starts as it does today.
Checked in the main session
apps/webapp/docker/Dockerfile.bun, stagebuild-extensions, copies/app/appsfromdeps. Thedepsstage holds only the threeapps/*/package.jsonfiles (lines 58–60). The devwebappservice mounts only./packagesand runsbun run dev:ci(next dev --turbopack). Sonext devhas noapps/webapp/srcto serve.git log -S './apps/webapp' -- docker-compose.dev.ymlfinds no commit. The mount never existed, so adding it undoes no earlier decision.target: build-extensionsdates from cb1cad9, before the move. That stage never held webapp source; the old./packagesmount supplied it. Only thebuilderstage copiesapps/webapp(Dockerfile.bun:194), and it runs a production build. So a target change is not a smaller fix.hocuspocus-workergets noSUPABASE_URLin this file, so it needs noextra_hostsline.
Acceptance criteria
- Item 1 is fixed as its Fix says, or a comment here says why not.
- Item 2 is fixed as its Fix says, or a comment here says why not.
- Item 3 is fixed as its Fix says, or a comment here says why not.
- On macOS, after
make up-dev, http://localhost:3000 shows the home page. - On Linux with Docker Engine,
rest-apiandhocuspocus-serverreachhttp://host.docker.internal:54321.
Verify
docker compose -f docker-compose.dev.yml --env-file .env.development configshows the new mounts andextra_hosts.- Run the README full-Docker steps on a fresh clone, then open http://localhost:3000. Until Fix the first-run docs: Supabase Cloud steps, full-Docker order, and local setup gaps #483 item 3 lands, run
bun installfirst. - On Linux:
docker compose -f docker-compose.dev.yml exec rest-api getent hosts host.docker.internalprints an address. - With the VAPID keys set in
.env.development,docker compose -f docker-compose.dev.yml --env-file .env.development configshows them onrest-api,hocuspocus-workerandwebapp. With them empty,make up-devstill starts.
Related
- Fix the first-run docs: Supabase Cloud steps, full-Docker order, and local setup gaps #483 first-run docs. Its item 3 owns the README full-Docker text.
- Stop
make cleanfrom tearing down the production stack #476make clean, which tears down this same dev stack. - Run the local setup from a clean clone and report every point of friction #149 clean-clone friction report. This issue is one finding of that kind, on the full-Docker path.
- Let docker-compose.dev.yml scale rest-api past one container #236 dev compose scaling. It edits the same
rest-apiservice block as item 2, with no conflict.
Generated by Claude Code
Reactions are currently unavailable
Activity
HMarzban commentedon Oct 15, 2026
Related issues
Cross-link review, 2026-10-15. Generated by Claude Code
fix(dev): mount webapp source and the host gateway in dev compose
fix(dev): start the backend and admin containers in make up-dev
HMarzban commentedon Oct 21, 2026
macOS config check, 2026-10-21
On
mainat0130027bf,docker compose -f docker-compose.dev.yml --env-file .env.development configrenders with no error.webappmountsapps/webappandpackagesinto/app, with its ownnode_modulesand.nextvolumes. Three services carryhost.docker.internal=host-gateway, andSUPABASE_URLpoints athttp://host.docker.internal:54321.rest-api,hocuspocus-workerandwebapp.Not run yet:
make up-devforce-removes every container nameddocsy-, so it would remove a runningmake dev-localstack. Run it on a fresh clone, or withdev-localstopped.HMarzban commentedon Oct 21, 2026
Verify 2 passes on macOS, 2026-10-21
A fresh clone of
mainat0130027bfin an empty folder, following the README full-Docker steps. Local Supabase was already running on:54321, so thesupabase startline was skipped.bun install: 1741 packages in 8 s.cp .env.example .env.development, thenmake up-dev: exit 0. All 7 containers arehealthy: webapp, admin-dashboard, rest-api, hocuspocus server and worker, Postgres and Redis.http://localhost:3000shows the home page in a browser. Create New Document opens a pad with its editor and outline, so the webapp reaches rest-api and the WebSocket server.rest-apiresolveshost.docker.internal, and a request from inside it tohttp://host.docker.internal:54321/auth/v1/healthreturns200./healthand worker/healthreturn200.Still open: Verify 3 and the Linux acceptance line, which need a Linux host with Docker Engine. Items 1 to 3 and the macOS line are done.
HMarzban commentedon Oct 21, 2026
Verify 3 passes on Linux Docker Engine, 2026-10-21
Run on a Linux host with Docker Engine 29.1.3, in throwaway
--rmcontainers on the default bridge network. No dev stack was started there, because that host serves production.getent hosts host.docker.internalsshd,0.0.0.0:2269)--add-host host.docker.internal:host-gateway172.17.0.1The second row is the original bug, and the first row is the fix.
docker-compose.dev.ymlputs the samehost.docker.internal=host-gatewayentry onrest-apiandhocuspocus-server, and also on the worker, webapp and admin. Local Supabase binds0.0.0.0:54321, so it is reachable through the gateway the same way.With Verify 2 on macOS (comment above), every acceptance line holds, so this issue closes.