Skip to content

Add --base-path support for reverse proxy subpath deployment#713

Open
d0nperinion wants to merge 2 commits intoperber:mainfrom
d0nperinion:feat/base-path
Open

Add --base-path support for reverse proxy subpath deployment#713
d0nperinion wants to merge 2 commits intoperber:mainfrom
d0nperinion:feat/base-path

Conversation

@d0nperinion
Copy link

Summary

  • Add --base-path CLI flag (env: LEAFWIKI_BASE_PATH) so LeafWiki can be served from an arbitrary URL prefix (e.g. example.com/wiki/)
  • Mount all backend routes under a Gin route group using the configured base path
  • Scope auth and CSRF cookies to the base path
  • Inject base path into index.html via tag; frontend reads it for API calls, React Router basename, asset URLs, and link resolution

Test plan

  • go test ./... passes
  • Without --base-path: everything works at / as before (no regression)
  • With --base-path /wiki: page loads at /wiki, API at /wiki/api/config, navigation/assets/favicon/static/branding all work, cookies scoped to
    /wiki

Backend changes

  • cmd/leafwiki/main.go: Added --base-path flag (string, env LEAFWIKI_BASE_PATH), normalizeBasePath() function that converts any input to /mypath
    format (or "" for root), passed to RouterOptions.BasePath
  • internal/http/router.go: Added BasePath to RouterOptions. Created base := router.Group(options.BasePath) and mounted all routes (/assets, /api,
    /branding, /static, /favicon.svg) under it. NoRoute stays on router but strips basePath before checking prefixes. Replaces {{BASE_PATH}} in
    index.html. Added basePath to /api/config response. Passes cookiePath to cookie constructors.
  • internal/http/middleware/auth/auth_cookie.go: Added CookiePath field, updated NewAuthCookies() to accept cookiePath parameter, replaced
    hardcoded Path: "/" with Path: a.CookiePath
  • internal/http/middleware/security/csrf_cookie.go: Same pattern — CookiePath field, updated constructor, dynamic path in all cookies

Frontend changes

  • ui/leafwiki-ui/index.html: Added
  • src/lib/config.ts: Reads BASE_PATH from meta tag, uses it as default API_BASE_URL when VITE_API_URL is unset
  • src/features/router/router.tsx: Added basename parameter, passed to createBrowserRouter()
  • src/App.tsx: Imports BASE_PATH, passes to createLeafWikiRouter()
  • src/features/preview/MarkdownImage.tsx: Prepends BASE_PATH to /assets/... src URLs
  • src/features/preview/MarkdownLink.tsx: Prepends BASE_PATH to asset hrefs; strips BASE_PATH from window.location.pathname before resolving
    relative links
  • src/lib/urlUtil.ts: stripBasePath() helper; buildEditUrl/buildViewUrl strip BASE_PATH prefix before processing

Test fixes

Updated all NewAuthCookies() and NewCSRFCookie() calls in test files to include the new cookiePath parameter ("/").

vibecoded this in a hour, looks like it works.

  Allow serving LeafWiki from an arbitrary URL prefix (e.g. /wiki) when
  behind a reverse proxy. Routes, API calls, static assets, and cookies
  are all scoped to the configured base path.
@d0nperinion d0nperinion requested a review from perber as a code owner February 26, 2026 00:17
@perber
Copy link
Owner

perber commented Feb 26, 2026

Hi @d0nperinion,

Thanks for your PR.
I will take a look tomorrow.

Could you run npm run format in the leafwiki-ui directory. This should resolve the linting issues.

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