Skip to content

Commit b7bb860

Browse files
committed
Address CodeRabbit review feedback
- Replace the "data never leaves your server / the VM" phrasing with what the architecture actually guarantees: every byte is served from your own origin to a browser your auth layer admitted, and to no third party. The app is client-side, so the bytes do reach an authenticated browser, and the old wording read as a stronger residency claim than that. - Note that same-origin is necessary but not sufficient for cookie auth: the cookie's own Path must cover the URL, so a layout spreading the app, the API, and the project files across sibling paths wants Path=/. - Present the GeoLens API key as one of two options rather than the mechanism, matching what the plugin section already said about a same-origin session authorizing private datasets with no key. - Name the Caddy catch-all upstream `geolens:8080` and say what it is: the GeoLens entry point, which routes /api to its API service internally, so one upstream covers both. Adding a separate /api route was suggested; `handle_path` would strip the prefix the API expects, so the comment explains what to do instead when a deployment does split them.
1 parent d03edc1 commit b7bb860

1 file changed

Lines changed: 25 additions & 11 deletions

File tree

docs/self-hosting.md

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,10 @@ This page answers both. The short version:
2222
spatial catalog (FastAPI + PostGIS) with accounts, per-dataset permissions,
2323
and OGC/STAC APIs. Host the **GeoLibre web build** next to it on the *same
2424
origin*, behind the *same* authentication layer. Then use GeoLibre's built-in
25-
**GeoLens plugin** to search the catalog and add datasets to the map. Data
26-
never leaves your server, credentials never leave your auth layer, and there
27-
is no CORS to configure.
25+
**GeoLens plugin** to search the catalog and add datasets to the map. Every
26+
byte is served from your own origin to an authenticated browser and to
27+
nowhere else, credentials are sent only to that origin, and there is no CORS
28+
to configure.
2829

2930
## Why same-origin matters
3031

@@ -36,7 +37,10 @@ apply:
3637
when the data URL is on the **same origin** as the app, and is **not** sent
3738
when it is on a different origin. So a cookie-gated dataset works out of the
3839
box on one origin, and cross-origin it fails whatever the server does, because
39-
the request arrives with no cookie for the server to check.
40+
the request arrives with no cookie for the server to check. Same-origin is
41+
necessary but not sufficient: the cookie's own `Path` still has to cover the
42+
URL being requested, so set it to `Path=/` for a layout that spreads the app,
43+
the API, and the project files across sibling paths.
4044
- **CORS.** Same-origin requests need no CORS headers at all. Cross-origin ones
4145
need the data host to allow your GeoLibre origin explicitly.
4246
- **Tile requests.** MapLibre issues raster and vector tile requests itself.
@@ -106,9 +110,12 @@ Then set at least these in its `.env` before exposing it (see the
106110
| `ENVIRONMENT=production` | Hides the API docs endpoints and hardens OAuth cookies. |
107111
| `JWT_SECRET_KEY` | Signing secret for sessions. |
108112

109-
Upload your datasets, keep them private (GeoLens uses role-based access control
110-
with per-dataset permissions), and create a per-user API key for programmatic
111-
access. That key is what the GeoLibre plugin uses to read private datasets.
113+
Upload your datasets and keep them private: GeoLens uses role-based access
114+
control with per-dataset permissions. The GeoLibre plugin can then read them two
115+
ways, and which one applies depends on how your deployment authorizes API
116+
requests. On a same-origin deployment the plugin's calls carry the visitor's
117+
GeoLens session automatically. Otherwise, create a per-user API key and paste it
118+
into the plugin panel.
112119

113120
## 2. Host the GeoLibre web build next to it
114121

@@ -173,8 +180,13 @@ maps.example.org {
173180
file_server
174181
}
175182
183+
# Catch-all: GeoLens's own entry point, which serves its UI and routes
184+
# /api to its API service internally, so one upstream covers both. Check
185+
# your GeoLens deployment: if it exposes the API on a separate address,
186+
# give it its own route above this block, and match on `handle` rather than
187+
# `handle_path` so the `/api` prefix survives (the API expects it).
176188
handle {
177-
reverse_proxy geolens-frontend:80
189+
reverse_proxy geolens:8080
178190
}
179191
}
180192
```
@@ -186,7 +198,8 @@ https://maps.example.org/gis/?url=https://maps.example.org/projects/watershed.ge
186198
```
187199

188200
opens a private project for an authenticated user and returns the login redirect
189-
for anyone else. No CORS headers, no tokens in URLs, no data leaving the VM.
201+
for anyone else. No CORS headers, no tokens in URLs, and nothing served to
202+
anyone the SSO layer has not admitted.
190203

191204
!!! note "`url=` must be absolute"
192205
The project deep link is validated as an absolute `http(s)` URL, so
@@ -272,8 +285,9 @@ same SSO layer, as described above.
272285
| Data or tokens reaching a third party | None |
273286
| Cost | You run and update one more container |
274287

275-
This is the pattern to choose when the requirement is that the data must not
276-
leave the server.
288+
This is the pattern to choose when the requirement is that the data must reach
289+
nobody but the users your own auth layer admits, and no third-party service
290+
along the way.
277291

278292
### Pattern B: hosted GeoLibre, private data elsewhere
279293

0 commit comments

Comments
 (0)