Skip to content

docs: add a self-hosting and private data guide - #1808

Merged
giswqs merged 3 commits into
mainfrom
docs/self-hosting-private-data
Aug 9, 2026
Merged

docs: add a self-hosting and private data guide#1808
giswqs merged 3 commits into
mainfrom
docs/self-hosting-private-data

Conversation

@giswqs

@giswqs giswqs commented Aug 9, 2026

Copy link
Copy Markdown
Member

Answers discussion #1807: how to run GeoLibre where neither the source data nor the .geolibre.json project can be public (Indigenous and local community monitoring data, in that case).

New page: docs/self-hosting.md

The recommended shape, and why:

  • Host the data with GeoLens (self-hosted FastAPI + PostGIS catalog with accounts, OIDC SSO, per-dataset permissions, and OGC/STAC APIs), host the GeoLibre web build on the same origin behind the same sign-on layer, and read it with the built-in GeoLens plugin. Nothing to install on the user's side: maplibreGeoLensPlugin is already registered in usePlugins.ts.
  • Why same-origin is the deciding factor. GeoLibre's fetches (fetchProjectFromUrl, the GeoLens client) use the browser default same-origin credentials mode, so an SSO session cookie reaches same-origin data automatically and never reaches a different origin; CORS stops being a configuration problem; MapLibre's own tile requests follow the same rules.
  • A worked Caddy config putting GeoLibre, GeoLens, and static project files under one hostname behind one forward-auth layer, plus the deployment variables that matter for a private install (GEOLIBRE_SHARE_URL=off, GEOLIBRE_APP_BASE, sidecar confinement, embed origins).
  • How the plugin handles credentials: API key held in memory for the session only, never written to localStorage or the project file; a saved project records only the server URL and dataset id; public layers restore automatically while private ones stay blank until the recipient reconnects with their own key; a private raster's key is scoped to exactly that raster's tile-URL prefix.
  • Pattern B compared honestly (hosted web.geolibre.app reading private data elsewhere): cookies cannot work cross-origin, CORS must allow the app origin, signed expiring URLs are the only practical mechanism, and tokens in URLs leak.
  • Private data paths without GeoLens (cloud-native files, OGC services, PostGIS via Martin, desktop/offline), how to reduce outbound requests (basemaps, geocoding, Pyodide mirror, AI, share, collab), and a deployment checklist.

Two gotchas verified against the code and written down: ?url= rejects relative paths (normalizeProjectUrl requires an absolute http/https URL), and docker/nginx.conf's loopback connect-src allowances should be dropped before public exposure.

Supporting changes

  • docs/user-guide/data-integrations.md: a Self-hosted catalogs section documenting the GeoLens plugin, which the user guide was missing entirely.
  • Cross-links from getting-started.md (Run with Docker, Basic Auth), index.md, and embedding.md, where a login-protected ?url= fails cross-origin with no obvious explanation.
  • mkdocs.yml: nav entry under Reference.
  • geolens-api.ts: the GeoLensRasterTiles docblock still described API-key-only private rasters as unrenderable. registerRasterApiKey renders them through MapLibre's transformRequest hook, so the comment now matches the code. Comment only, no behavior change.

Testing

Docs only, plus one code comment. Internal links and anchors verified; no em dashes; mermaid fence matches the one already in architecture.md.

Summary by CodeRabbit

  • New Features

    • Private raster datasets secured with API keys can now render successfully.
    • Added guidance for self-hosting GeoLibre alongside private data, including authentication, HTTPS, cookies, CORS, and security policies.
    • Added documentation for self-hosted catalogs, GeoLens integration, deployment options, and API-key handling.
    • Expanded embedding guidance for private resources and same-origin requirements.
  • Documentation

    • Added a comprehensive Self-Hosting guide and linked it in the documentation navigation.
    • Updated getting-started and data integration guides with deployment and private-data recommendations.

Answers #1807: how to run GeoLibre where neither the
source data nor the project can be public.

New docs/self-hosting.md covers the recommended shape: host the data with
GeoLens (self-hosted catalog, accounts, per-dataset permissions), host the
GeoLibre web build on the same origin behind the same sign-on layer, and
read it with the built-in GeoLens plugin. It documents why same-origin is
the deciding factor (requests use the default same-origin credentials mode,
so a session cookie reaches same-origin data and never reaches a different
origin, and CORS stops being a configuration problem at all), a worked
reverse-proxy config, how the plugin handles credentials (API key in memory
only, project files record just the server URL and dataset id), and what
does and does not work when a hosted GeoLibre reads private data elsewhere.

Also documents the GeoLens plugin in the user guide, which it was missing,
and cross-links the new page from Getting Started, the home page, and the
embedding URL parameters, where a login-protected `?url=` silently fails
cross-origin.

The docblock on GeoLensRasterTiles still described API-key-only private
rasters as unrenderable; registerRasterApiKey renders them through
MapLibre's transformRequest hook, so the comment is updated to match.
Copilot AI lite review requested due to automatic review settings August 9, 2026 20:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: db30072f-b7c8-4fcd-9efd-52dd122def8e

📥 Commits

Reviewing files that changed from the base of the PR and between b7bb860 and beea319.

📒 Files selected for processing (1)
  • docs/self-hosting.md

📝 Walkthrough

Walkthrough

The PR adds a self-hosting guide for private GeoLibre deployments, links it from existing documentation, documents GeoLens catalog integration and credential handling, clarifies same-origin embedding behavior, and updates raster API-key documentation.

Changes

Private data deployment documentation

Layer / File(s) Summary
Self-hosting architecture and deployment
docs/self-hosting.md
Documents same-origin architecture, HTTPS, authentication, deployment configuration, private-data alternatives, outbound-request controls, and deployment checks.
GeoLens and private resource access
docs/self-hosting.md, docs/user-guide/data-integrations.md, docs/user-guide/embedding.md, packages/plugins/src/plugins/geolens-api.ts
Documents self-hosted GeoLens catalogs, credential behavior, private-layer restoration, same-origin embedding, and scoped X-Api-Key handling for raster tiles.
Self-hosting documentation links
docs/getting-started.md, docs/index.md, mkdocs.yml
Adds links to self-hosting and private-data guidance from deployment, authentication, and site navigation pages.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

Poem

A rabbit checks each private gate,
Same-origin paths keep access straight.
GeoLens catalogs join the trail,
Scoped raster keys guard every tile.
Self-hosting notes now guide the way—
Hop, deploy, and map the day!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding documentation for self-hosting and private data deployments.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/self-hosting-private-data

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Code review

This is a documentation-only PR (docs/self-hosting.md plus cross-links, a mkdocs.yml nav entry, and one corrected code comment in geolens-api.ts), so most standard review categories don't apply. I cross-checked the doc's technical claims against the actual implementation rather than just proofreading prose.

Bugs: None found.

Security: None found. The doc's description of how the GeoLens plugin handles credentials is accurate: the API key is only used in plain fetch calls (browser-default same-origin credentials, no explicit override), and maplibre-geolens.ts confirms the key is never persisted to localStorage or into layer/project metadata (only geolensBaseUrl and dataset id are saved) — consistent with the "never leaves memory" claims in the new page. High confidence.

Performance: N/A (docs only).

Quality: No issues. The updated geolens-api.ts docblock (removing the old "known limitation" note) accurately reflects registerRasterApiKey/transformRequest in maplibre-geolens.ts, which does attach X-Api-Key to raster tile requests scoped to the dataset's tile-URL prefix — the comment fix is a genuine correction, not stale. High confidence.

CLAUDE.md: No violations. Verified against project conventions:

  • ?url= absolute-URL requirement matches normalizeProjectUrl in apps/geolibre-desktop/src/lib/urls.ts.
  • Env vars documented (GEOLIBRE_SHARE_URL, GEOLIBRE_APP_BASE, GEOLIBRE_CONVERSION_ROOTS, GEOLIBRE_POSTGIS_HOSTS, GEOLIBRE_DISABLE_SIDECAR, GEOLIBRE_EMBED_ORIGINS, VITE_WELCOME_DISABLED, VITE_PYODIDE_INDEX_URL) all match existing behavior in getting-started.md/code.
  • docker/nginx.conf's loopback connect-src allowance and the warning to drop it before public exposure matches the existing comment in that file.
  • The enable_dataset_editing feature-flag description matches geolens-api.ts.
  • Internal anchor links (self-hosting.md#putting-both-behind-one-auth-layer, data-integrations.md#self-hosted-catalogs, data-integrations.md#geocoding, downloads.md#what-the-store-build-leaves-out) all resolve to real headings.
  • The mermaid fence style matches the existing one in architecture.md, and all linked target pages (server-api.md, collaboration.md, privacy.md, downloads.md) exist.

No findings to raise — this is a well-verified, internally consistent documentation addition.

@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

🔍 Cloudflare PR preview

Item Value
Site https://7ce53785.geolibre-preview.pages.dev
Demo app https://7ce53785.geolibre-preview.pages.dev/demo/
Commit beea319

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/self-hosting.md`:
- Around line 109-111: Update the authentication guidance around the dataset
access and same-origin session sections to present per-user API keys as one
available option rather than a requirement. Clarify that private requests may
also be authorized through a same-origin GeoLens session, while preserving the
existing distinction for programmatic plugin access.
- Around line 20-27: Update the “Recommended setup” tip and the corresponding
repeated claims to describe browser delivery accurately: state that data is
served from the operator-controlled origin and is not sent to third-party
services, while removing claims that data never leaves the server or VM and that
credentials never leave the authentication layer. Preserve the existing GeoLens
setup guidance.
- Around line 176-179: Update the Caddy example in the self-hosting
documentation to add a handle_path /api/* block before the existing catch-all
handle, proxying API requests to geolens-api on the documented API port; keep
the frontend reverse_proxy as the fallback for non-API routes.
- Around line 34-39: Update the Cookies section in the self-hosting
documentation to state that the SSO cookie must cover the /gis, /api, and
/projects paths, typically by setting Path=/. Preserve the existing same-origin
explanation while documenting this path requirement for private project and tile
requests.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 59649583-c4cf-4ba6-bda7-97b2c834fdc0

📥 Commits

Reviewing files that changed from the base of the PR and between e06500c and d03edc1.

📒 Files selected for processing (7)
  • docs/getting-started.md
  • docs/index.md
  • docs/self-hosting.md
  • docs/user-guide/data-integrations.md
  • docs/user-guide/embedding.md
  • mkdocs.yml
  • packages/plugins/src/plugins/geolens-api.ts

Comment thread docs/self-hosting.md Outdated
Comment thread docs/self-hosting.md Outdated
Comment thread docs/self-hosting.md Outdated
Comment thread docs/self-hosting.md
- 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.
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Code review

This is a docs-only PR (plus one comment-only code change) adding docs/self-hosting.md and cross-links. I fact-checked every verifiable technical claim in the new content against the actual source:

  • normalizeProjectUrl (apps/geolibre-desktop/src/lib/urls.ts) does reject relative ?url= values as claimed.
  • fetchProjectFromUrl uses a bare fetch() call with no explicit credentials option, so the browser's same-origin default applies, matching the cookie-behavior claims.
  • registerRasterApiKey / geolensTransformRequest in maplibre-geolens.ts confirm the updated GeoLensRasterTiles docblock in geolens-api.ts — the "known limitation" comment removal is accurate, not a regression in behavior description.
  • normalizeBaseUrl in geolens-api.ts confirms the plugin-panel URL-entry claims (trailing slash trimmed, bare host coerced to https://).
  • enable_dataset_editing / /api/settings/feature-flags/ claim matches geolens-api.ts:702-707.
  • All referenced env vars (GEOLIBRE_SHARE_URL, GEOLIBRE_APP_BASE, GEOLIBRE_COLLAB_URL, GEOLIBRE_AUTH_USER/GEOLIBRE_AUTH_PASSWORD, GEOLIBRE_CONVERSION_ROOTS, GEOLIBRE_POSTGIS_HOSTS, GEOLIBRE_DISABLE_SIDECAR, GEOLIBRE_EMBED_ORIGINS, GEOLIBRE_AI_URL) exist in docker/entrypoint.sh / backend code with the described semantics.
  • The docker/nginx.conf warning about loopback connect-src allowances matches the actual CSP comments in that file.
  • Internal doc links and anchors (self-hosting.md#putting-both-behind-one-auth-layer, data-integrations.md#self-hosted-catalogs, downloads.md#what-the-store-build-leaves-out, etc.) all resolve to real headers/files, and the mermaid fence matches the pymdownx.superfences mermaid config already enabled in mkdocs.yml.

Bugs: None found.

Security: None found — the guide's security-relevant guidance (drop loopback CSP allowances before public exposure, scope GEOLIBRE_POSTGIS_HOSTS, keep API keys in memory only) is consistent with the actual code's enforcement.

Performance: N/A (docs-only change).

Quality: No issues. Prose is clear, internal links resolve, and the one code comment update (geolens-api.ts) accurately reflects current behavior rather than the stale "known limitation" note it replaces.

CLAUDE.md: Compliant — no code paths touched that require lockfile refreshes, catalog regeneration, or other checklist items in CLAUDE.md; this is a pure docs/comment change.

No inline comments were posted; I found nothing rising to a reportable issue after verifying the claims against the source.

@giswqs
giswqs enabled auto-merge (squash) August 9, 2026 20:50
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

🔍 GitHub Pages PR preview

Item Value
Site Deploy failed. See the job log.
Demo app Unavailable
Commit beea319

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/self-hosting.md`:
- Around line 183-189: Update the self-hosting documentation around the
catch-all GeoLens reverse-proxy configuration to explicitly require verifying
that the outer SSO identity is consumed by GeoLens and that a GeoLens browser
session is created. Document the fallback requirement for same-origin session
cookies or a configured X-Api-Key so private datasets remain accessible, and
retain the existing forward_auth routing guidance.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 36797a73-7a0e-4e67-9cc9-47073a93822f

📥 Commits

Reviewing files that changed from the base of the PR and between d03edc1 and b7bb860.

📒 Files selected for processing (1)
  • docs/self-hosting.md

Comment thread docs/self-hosting.md
- Say explicitly that the forward-auth layer and GeoLens are two separate
  authentication layers. The proxy decides who reaches the origin; it does
  not tell GeoLens who the visitor is, and the plugin sends only a
  same-origin cookie plus an optional X-Api-Key. So the visitor needs a
  GeoLens identity as well: either point GeoLens at the same OIDC provider
  so signing in yields a GeoLens session on this origin, or hand each user
  a per-user API key. Names the symptom (public datasets appear, private
  ones stay invisible) so the failure is recognizable.
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Code review

Reviewed the full diff (docs-only content plus a one-line-summary-worthy comment fix in packages/plugins/src/plugins/geolens-api.ts). Checked every verifiable technical claim in the new docs/self-hosting.md and the edits to getting-started.md, index.md, data-integrations.md, embedding.md, and mkdocs.yml against the actual source:

  • registerRasterApiKey / geolensTransformRequest in packages/plugins/src/plugins/maplibre-geolens.ts confirm the updated GeoLensRasterTiles docblock — API-key-only private rasters do render via transformRequest, scoped by tile-URL prefix. The old "known limitation" comment was indeed stale; this is a comment-only fix as the PR states.
  • normalizeProjectUrl (apps/geolibre-desktop/src/lib/urls.ts) does require an absolute http(s) URL, matching the "url= must be absolute" callout.
  • GEOLIBRE_POSTGIS_HOSTS, GEOLIBRE_APP_BASE, GEOLIBRE_EMBED_ORIGINS, GEOLIBRE_COLLAB_URL, GEOLIBRE_DISABLE_SIDECAR, GEOLIBRE_AUTH_USER/PASSWORD, and VITE_WELCOME_DISABLED all exist with the described semantics in Dockerfile/docker/entrypoint.sh/docker/nginx.conf.
  • enable_dataset_editing is read from /api/settings/feature-flags/ exactly as described (packages/plugins/src/plugins/geolens-api.ts).
  • All internal doc anchors referenced (self-hosting.md#putting-both-behind-one-auth-layer, downloads.md#what-the-store-build-leaves-out, data-integrations.md#geocoding, getting-started.md#run-with-docker) resolve to real headings, and the mermaid fence matches the style already used in architecture.md.

Bugs: None found.

Security: None found — the guide's security claims (same-origin cookie behavior, CORS necessity, CSP loopback warning, PostGIS host allowlisting) are accurate and, if anything, steer readers toward the safer configuration.

Performance: N/A (docs-only change).

Quality: No issues — the new page is well-organized, cross-linked correctly, and the supporting edits are minimal and on-topic.

CLAUDE.md: No violations. This is a docs-only change (plus one doc-comment fix) with no code/test/build implications, consistent with the PR's stated "Docs only, plus one code comment" testing note.

No inline comments were posted — I found nothing to flag.

@giswqs
giswqs merged commit 55dd184 into main Aug 9, 2026
24 checks passed
@giswqs
giswqs deleted the docs/self-hosting-private-data branch August 9, 2026 22:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants