Fixes#63 — app doesn't work when accessed via a reverse proxy subdomain (e.g., gitea-mirror.mydomain.tld). Pages show no content and users can't sign in.
Root cause
Better Auth's trustedOrigins only included http://localhost:4321 by default. When the browser sends Origin: https://gitea-mirror.mydomain.tld, it was rejected as "invalid origin". Additionally, SSE streams were buffered by Nginx, breaking real-time updates.
Changes
Auto-detect origin from request headers (src/lib/auth.ts)
Changed trustedOrigins from a static IIFE to an async function that receives the incoming request
Auto-detects origin from X-Forwarded-Host/Host + X-Forwarded-Proto headers for per-request CSRF validation
Handles multi-value X-Forwarded-Host and X-Forwarded-Proto (chained proxy setups) — takes first value only
Validates proto is strictly "http" or "https"
Restores startup logging of static trusted origins for debugging
SSE buffering fix (src/pages/api/sse/index.ts)
Added X-Accel-Buffering: no response header to prevent Nginx from buffering the SSE stream
Documentation (src/pages/docs/advanced.astro)
Added prominent red warning callout: BETTER_AUTH_URL, PUBLIC_BETTER_AUTH_URL, and BETTER_AUTH_TRUSTED_ORIGINS are mandatory for reverse proxy deployments
Added Docker Compose example with required env vars
Added X-Forwarded-For, X-Forwarded-Proto, Host headers to Nginx SSE example
Added dedicated "REVERSE PROXY CONFIGURATION" section in .env.example
Added PUBLIC_BETTER_AUTH_URL and BETTER_AUTH_TRUSTED_ORIGINS to docker-compose.yml
Added reverse proxy comments to docker-compose.alt.yml
Test plan
All 171 tests pass
Production build succeeds
Rebased cleanly onto main (after PR #235 and #236 merges)
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.
## 📋 Pull Request Information
**Original PR:** https://github.com/RayLabsHQ/gitea-mirror/pull/237
**Author:** [@arunavo4](https://github.com/arunavo4)
**Created:** 3/18/2026
**Status:** ✅ Merged
**Merged:** 3/18/2026
**Merged by:** [@arunavo4](https://github.com/arunavo4)
**Base:** `main` ← **Head:** `fix/63-reverse-proxy-support`
---
### 📝 Commits (4)
- [`470be29`](https://github.com/RayLabsHQ/gitea-mirror/commit/470be29d2816f0d5cf446389ccf967f39a503a8b) fix: improve reverse proxy support for subdomain deployments (#63)
- [`9b99e5e`](https://github.com/RayLabsHQ/gitea-mirror/commit/9b99e5e63227e06dcbeba70563bd2609dbb770e2) fix: address review findings for reverse proxy origin detection
- [`60034c5`](https://github.com/RayLabsHQ/gitea-mirror/commit/60034c5395c8284331669d2fd0ddf744c20db4b3) fix: handle multi-value x-forwarded-host in chained proxy setups
- [`2e2b420`](https://github.com/RayLabsHQ/gitea-mirror/commit/2e2b42058473ce155004a337fcc23a2d0f3a451b) test: add unit tests for reverse proxy origin detection
### 📊 Changes
**7 files changed** (+268 additions, -46 deletions)
<details>
<summary>View changed files</summary>
📝 `.env.example` (+18 -1)
📝 `docker-compose.alt.yml` (+4 -0)
📝 `docker-compose.yml` (+7 -0)
➕ `src/lib/auth-origins.test.ts` (+119 -0)
📝 `src/lib/auth.ts` (+71 -42)
📝 `src/pages/api/sse/index.ts` (+1 -0)
📝 `src/pages/docs/advanced.astro` (+48 -3)
</details>
### 📄 Description
## Summary
Fixes #63 — app doesn't work when accessed via a reverse proxy subdomain (e.g., `gitea-mirror.mydomain.tld`). Pages show no content and users can't sign in.
### Root cause
Better Auth's `trustedOrigins` only included `http://localhost:4321` by default. When the browser sends `Origin: https://gitea-mirror.mydomain.tld`, it was rejected as "invalid origin". Additionally, SSE streams were buffered by Nginx, breaking real-time updates.
### Changes
**Auto-detect origin from request headers** (`src/lib/auth.ts`)
- Changed `trustedOrigins` from a static IIFE to an async function that receives the incoming request
- Auto-detects origin from `X-Forwarded-Host`/`Host` + `X-Forwarded-Proto` headers for per-request CSRF validation
- Handles multi-value `X-Forwarded-Host` and `X-Forwarded-Proto` (chained proxy setups) — takes first value only
- Validates proto is strictly `"http"` or `"https"`
- Restores startup logging of static trusted origins for debugging
**SSE buffering fix** (`src/pages/api/sse/index.ts`)
- Added `X-Accel-Buffering: no` response header to prevent Nginx from buffering the SSE stream
**Documentation** (`src/pages/docs/advanced.astro`)
- Added prominent red warning callout: `BETTER_AUTH_URL`, `PUBLIC_BETTER_AUTH_URL`, and `BETTER_AUTH_TRUSTED_ORIGINS` are mandatory for reverse proxy deployments
- Added Docker Compose example with required env vars
- Added `X-Forwarded-For`, `X-Forwarded-Proto`, `Host` headers to Nginx SSE example
**Config/Docker** (`.env.example`, `docker-compose.yml`, `docker-compose.alt.yml`)
- Added dedicated "REVERSE PROXY CONFIGURATION" section in `.env.example`
- Added `PUBLIC_BETTER_AUTH_URL` and `BETTER_AUTH_TRUSTED_ORIGINS` to `docker-compose.yml`
- Added reverse proxy comments to `docker-compose.alt.yml`
## Test plan
- [x] All 171 tests pass
- [x] Production build succeeds
- [x] Rebased cleanly onto main (after PR #235 and #236 merges)
---
<sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
📋 Pull Request Information
Original PR: https://github.com/RayLabsHQ/gitea-mirror/pull/237
Author: @arunavo4
Created: 3/18/2026
Status: ✅ Merged
Merged: 3/18/2026
Merged by: @arunavo4
Base:
main← Head:fix/63-reverse-proxy-support📝 Commits (4)
470be29fix: improve reverse proxy support for subdomain deployments (#63)9b99e5efix: address review findings for reverse proxy origin detection60034c5fix: handle multi-value x-forwarded-host in chained proxy setups2e2b420test: add unit tests for reverse proxy origin detection📊 Changes
7 files changed (+268 additions, -46 deletions)
View changed files
📝
.env.example(+18 -1)📝
docker-compose.alt.yml(+4 -0)📝
docker-compose.yml(+7 -0)➕
src/lib/auth-origins.test.ts(+119 -0)📝
src/lib/auth.ts(+71 -42)📝
src/pages/api/sse/index.ts(+1 -0)📝
src/pages/docs/advanced.astro(+48 -3)📄 Description
Summary
Fixes #63 — app doesn't work when accessed via a reverse proxy subdomain (e.g.,
gitea-mirror.mydomain.tld). Pages show no content and users can't sign in.Root cause
Better Auth's
trustedOriginsonly includedhttp://localhost:4321by default. When the browser sendsOrigin: https://gitea-mirror.mydomain.tld, it was rejected as "invalid origin". Additionally, SSE streams were buffered by Nginx, breaking real-time updates.Changes
Auto-detect origin from request headers (
src/lib/auth.ts)trustedOriginsfrom a static IIFE to an async function that receives the incoming requestX-Forwarded-Host/Host+X-Forwarded-Protoheaders for per-request CSRF validationX-Forwarded-HostandX-Forwarded-Proto(chained proxy setups) — takes first value only"http"or"https"SSE buffering fix (
src/pages/api/sse/index.ts)X-Accel-Buffering: noresponse header to prevent Nginx from buffering the SSE streamDocumentation (
src/pages/docs/advanced.astro)BETTER_AUTH_URL,PUBLIC_BETTER_AUTH_URL, andBETTER_AUTH_TRUSTED_ORIGINSare mandatory for reverse proxy deploymentsX-Forwarded-For,X-Forwarded-Proto,Hostheaders to Nginx SSE exampleConfig/Docker (
.env.example,docker-compose.yml,docker-compose.alt.yml).env.examplePUBLIC_BETTER_AUTH_URLandBETTER_AUTH_TRUSTED_ORIGINStodocker-compose.ymldocker-compose.alt.ymlTest plan
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.