Skip to content

Support hosting Fider under a URL sub-path (e.g., example.com/feedback/) #1453

@3rg0n

Description

@3rg0n

Fider Cloud or Self Hosted
Self Hosted: 0.21.1

Describe the bug
Fider cannot be hosted under a URL sub-path (e.g., https://example.com/feedback/) behind a reverse proxy. While BASE_URL accepts a path component, the path is not used consistently across the backend or frontend, causing broken redirects, broken API calls, and broken navigation links. This goes beyond the Context.BaseURL() bug reported in #1452 — even after fixing that, there are ~120 locations across the codebase with hardcoded root-relative paths.

To Reproduce

  1. Set BASE_URL=https://example.com/feedback and HOST_MODE=single
  2. Configure a reverse proxy to forward /feedback/ to Fider, stripping the prefix
  3. Open Fider at https://example.com/feedback/
  4. Delete a post — the DELETE API call goes to /api/v1/posts/6 (missing /feedback prefix), and navigator.goHome() redirects to https://example.com/ instead of https://example.com/feedback/
  5. Click any navigation link (Settings, Admin, etc.) — the browser navigates to https://example.com/settings instead of https://example.com/feedback/settings
  6. Sign in via OAuth — the callback redirects to / instead of /feedback/

Expected behavior
When BASE_URL includes a path component, all redirects, API calls, navigation links, and URL construction should respect that path prefix. Fider should be fully functional when hosted under a sub-path.

Additional context
I'm using 0.21.1 of Fider. Self hosted.

Here is a full audit of all affected areas:

1. Core Bug — Context.BaseURL() strips path (see #1452)

The Context.BaseURL() method ignores the path in BASE_URL, which is the root cause for redirects and frontend navigation.

2. Backend — Hardcoded root-relative redirects

9 locations use c.Redirect("/") or c.Redirect("/path") instead of c.Redirect(c.BaseURL() + "/path"):

File Line Current Code
app/handlers/oauth.go 34 c.Redirect("/")
app/handlers/oauth.go 40 c.Redirect("/")
app/handlers/oauth.go 109 c.Redirect("/not-invited")
app/handlers/signin.go 383 c.Redirect("/")
app/handlers/signup.go 144 c.Redirect("/")
app/handlers/post.go 101 c.Redirect(fmt.Sprintf("/posts/%d/%s", ...))
app/middlewares/tenant.go 83 c.Redirect("/signup")
app/middlewares/tenant.go 130 c.Redirect("/signin?redirect=...")
app/middlewares/tenant.go 132 c.Redirect("/signin")

3. Frontend — API calls don't include base path

The http service in public/services/http.ts passes root-relative URLs (e.g., /api/v1/posts/6) directly to fetch(). When hosted at /feedback/, these requests miss the path prefix. All ~70 API call sites in public/services/actions/*.ts are affected.

4. Frontend — Hardcoded location.href assignments

Several files bypass the navigator service (which was partially fixed in 95f7b91) and assign root-relative paths directly:

File Line Current Code
public/pages/SignIn/CompleteSignInProfile.page.tsx 26 location.href = "/?c=" + props.c
public/pages/SignIn/CompleteSignInProfile.page.tsx 28 location.href = "/"
public/pages/Administration/pages/GeneralSettings.page.tsx 25 location.href = "/"
public/pages/Home/components/ShareFeedback.tsx 199 location.href = `/posts/${...}`

5. Frontend — Hardcoded href attributes in React components

23+ components use hardcoded root-relative href values in <a> tags. Key examples:

  • public/components/Header.tsxhref="/"
  • public/components/UserMenu.tsxhref="/settings", href="/admin", href="/signout"
  • public/pages/Administration/components/SideMenu.tsx — 12 admin links
  • public/pages/Administration/pages/Export.page.tsx — export download links
  • public/components/common/Legal.tsxhref="/terms", href="/privacy"
  • public/components/ReadOnlyNotice.tsxhref="/admin/billing"

6. Frontend — window.history.pushState with hardcoded paths

File Line Current Code
public/pages/Home/Home.page.tsx 74 pushState({...}, "", `/posts/${postNumber}/${slug}`)
public/pages/Home/Home.page.tsx 80 pushState({}, "", "/")

7. HTML Templates — Hardcoded feed paths

File Line Current Code
views/index.html 3 href="/feed/global.atom"
views/index.html 5 href="/feed/posts/{{ $.public.props.post.ID }}.atom"

Proposed Solution

  1. Fix Context.BaseURL() to return the full BASE_URL in single-host mode (see [BUG] Context.BaseURL() strips path from BASE_URL, breaking subfolder/sub-path hosting #1452)
  2. Add a basePath helper to the frontend that extracts the path portion of baseURL for URL construction
  3. Prepend base path in http.ts so all API calls include the prefix automatically
  4. Replace all hardcoded redirects in Go handlers with c.BaseURL() + path
  5. Replace all hardcoded location.href assignments with navigator.goTo() / navigator.goHome()
  6. Update all href attributes to use the base path utility
  7. Update HTML templates to use the template-provided baseURL for feed links

Workaround

Hosting via a dedicated subdomain (e.g., feedback.example.com) works correctly and avoids all these issues. Sub-path hosting currently requires a reverse proxy configuration that routes both /feedback/* AND /api/v1/*, /assets/*, /_api/*, /static/*, /feed/* to Fider, which is fragile.

Metadata

Metadata

Assignees

No one assigned

    Labels

    type: enhancementmake something that is already working even better

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions