Skip to content

Commit d9712eb

Browse files
committed
docs(deploy): tell Docker users to browse 127.0.0.1, not localhost
The Docker walkthrough's Step 6 sends users to http://localhost:7456. That is the one loopback name the daemon reserves for powered previews whenever it is bound to 127.0.0.1, so the browser's /api calls come back 403 'Powered preview origin cannot access this API route' and the front end renders the swallowed failure as an empty project list. curl and MCP clients send no sec-fetch-* headers and are unaffected, which is why it reads as missing data rather than a blocked request. Measured against the guard on main, with the Host header as the only variable: bind 127.0.0.1 (docker-compose.linux.yml) Host: localhost -> 403, 127.0.0.1 -> 200 bind 0.0.0.0 (docker-compose.yml) Host: localhost -> 403, 127.0.0.1 -> 200 So this is not Linux-specific as originally reported: reportHostForPoweredPreview() maps 0.0.0.0 to 127.0.0.1, which leaves localhost reserved under the default Compose file too. Points Step 6 at 127.0.0.1 (matching the curl in Step 5), explains why, adds a symptom-keyed entry to Common Issues, and notes the browser URL in the Linux host-networking section of deploy/README.md. Part of #6263
1 parent 517f39a commit d9712eb

2 files changed

Lines changed: 15 additions & 1 deletion

File tree

deploy/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,13 @@ OPEN_DESIGN_IMAGE=open-design-local
109109
docker compose -f docker-compose.yml -f docker-compose.linux.yml up -d --no-build
110110
```
111111

112+
Then open **`http://127.0.0.1:7456`** in the browser — not `http://localhost:7456`.
113+
The Linux override binds the daemon to `127.0.0.1`, which leaves `localhost` as
114+
the reserved powered-preview origin: a tab on that name has its `/api` requests
115+
answered with `403 Powered preview origin cannot access this API route`, and the
116+
project list comes up empty even though the projects exist. `curl` and MCP
117+
clients are unaffected, since the guard keys off browser `sec-fetch-*` headers.
118+
112119
Common install paths:
113120

114121
| CLI | Default path |

docs/deployment/docker.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,16 @@ Success looks like:
8181
## Step 6: Open Open Design in Your Browser
8282

8383
Open:
84-
- `http://localhost:7456/`
84+
- `http://127.0.0.1:7456/`
8585

8686
You should see the Open Design interface.
8787

88+
Use `127.0.0.1`, not `localhost`. The daemon reserves whichever of the two
89+
names it is *not* bound to as the powered-preview origin, so browsing via that
90+
other name makes the daemon treat the tab as a sandboxed preview and reject its
91+
`/api` calls with `403`. Both Compose files bind a `127.0.0.1`-equivalent host,
92+
which leaves `localhost` as the reserved name.
93+
8894
![Open Design home (desktop)](../screenshots/deployment/docker/01-open-design-home.png)
8995
![Open Design home (mobile)](../screenshots/deployment/docker/03-open-design-mobile.png)
9096

@@ -96,3 +102,4 @@ You should see the Open Design interface.
96102
- `pull access denied` or `authentication required` for `ghcr.io/nexu-io/od`: the GHCR package must be public for anonymous Docker, Compose, and Dokploy pulls. An organization maintainer must open GitHub -> Packages -> `od` -> Package settings and change visibility to Public.
97103
- reverse proxy + `OD_API_TOKEN`: either inject `Authorization: Bearer <OD_API_TOKEN>` at the proxy, or set `OPEN_DESIGN_DISABLE_API_AUTH=1` only when that proxy already authenticates every request and the daemon is not directly exposed.
98104
- `Authorization: Bearer <OD_API_TOKEN> required` on macOS: Docker Desktop bridge networking makes the daemon see requests as non-loopback. See [Docker Desktop on macOS](../../deploy/README.md#docker-desktop-on-macos) for the host networking workaround.
105+
- **Empty project list in the browser while `curl` returns real projects**: you are browsing `http://localhost:7456` instead of `http://127.0.0.1:7456`. The daemon reserves the loopback name it is not bound to for powered previews, so `/api/projects` answers `403 {"error":"Powered preview origin cannot access this API route"}`. `curl` and MCP clients send no `sec-fetch-*` headers and are unaffected, which is why the failure looks like missing data rather than a blocked request. Confirm in DevTools -> Network, then reopen on `127.0.0.1`.

0 commit comments

Comments
 (0)