feat: configure Forgejo ROOT_URL for /forge/ subpath routing #1080

Closed
opened 2026-04-20 15:08:27 +00:00 by disinto-admin · 0 comments

Goal

/forge/* subpath routing returns 404 because Forgejo is configured with ROOT_URL = http://forgejo:3000/ (no subpath). Forgejo doesn't know requests arrive under /forge/ so its internal route table misses. Configure Forgejo with a subpath-aware ROOT_URL and verify the Caddyfile handle block cooperates (no prefix strip needed — Forgejo handles the prefix natively when ROOT_URL is set).

Evidence

Live probe on 2026-04-20:

$ curl -sI http://localhost/forge/
HTTP/1.1 404 Not Found
Server: ...
Cache-Control: max-age=0, private, must-revalidate, no-transform

Forgejo container env (verified via docker exec disinto-forgejo env):

FORGEJO__server__ROOT_URL=http://forgejo:3000/

Should be:

FORGEJO__server__ROOT_URL=http://forgejo:3000/forge/

Forgejo's app.ini mirrors this as ROOT_URL = http://forgejo:3000/forge/.

The fix

Set FORGEJO__server__ROOT_URL to include the /forge/ suffix in the compose service env. The generator at lib/generators.sh emits this value; update so it produces the subpath form when EDGE_TUNNEL_FQDN is set (existing logic at bin/disinto:842-847 mentioned in #1025 body may already cover part of this — verify).

Also verify the Caddyfile handle /forge/* block does not strip the prefix (unlike staging #NNNN). Forgejo needs the full /forge/... path to arrive so its own router recognizes it.

# Correct — no strip_prefix
handle /forge/* {
    reverse_proxy forgejo:3000
}

Acceptance criteria

  • FORGEJO__server__ROOT_URL set to include /forge/ subpath when subpath routing is active
  • Verify via docker exec disinto-forgejo env | grep ROOT_URL
  • curl http://localhost/forge/ returns 200 with Forgejo landing page HTML (not 404)
  • Forgejo login flow completes without redirect loops: curl -L http://localhost/forge/user/login returns a 200 with the login form
  • Forgejo-generated internal links in the rendered HTML use /forge/ prefix (grep the response for href="/)
  • Woodpecker ↔ Forgejo OAuth still works: existing Woodpecker login flow functional (check via /ci/ end-to-end)
  • tests/smoke-edge-subpath.sh Test 2 and Test 3 pass against live edge
  • No regression on Woodpecker subpath (/ci/ stays 200)

Affected files

  • lib/generators.sh — FORGEJO__server__ROOT_URL emission (and WOODPECKER_HOST if analogous)
  • Possibly docker-compose.yml (if ROOT_URL is hardcoded there instead of generated)
  • tests/smoke-edge-subpath.sh — no change expected; already covers this path

Notes

Forgejo subpath has known upstream quirks (asset paths, avatar URLs, OAuth callback URLs). The sprint pitch for #623 (edge-subpath-chat) explicitly flagged this as a risk and documented a fallback plan at docs/edge-routing-fallback.md — if subpath routing has intractable issues after this fix, pivot to per-service subdomains per that plan.

  • Vision #623 — edge subpath routing
  • #1025 — smoke-test tool which surfaced this gap
  • #1028 — automated subdomain fallback (merged); relevant if this fix can't land cleanly
  • Companion issue: /staging/ strip_prefix fix
## Goal `/forge/*` subpath routing returns 404 because Forgejo is configured with `ROOT_URL = http://forgejo:3000/` (no subpath). Forgejo doesn't know requests arrive under `/forge/` so its internal route table misses. Configure Forgejo with a subpath-aware `ROOT_URL` and verify the Caddyfile handle block cooperates (no prefix strip needed — Forgejo handles the prefix natively when ROOT_URL is set). ## Evidence Live probe on 2026-04-20: ``` $ curl -sI http://localhost/forge/ HTTP/1.1 404 Not Found Server: ... Cache-Control: max-age=0, private, must-revalidate, no-transform ``` Forgejo container env (verified via `docker exec disinto-forgejo env`): ``` FORGEJO__server__ROOT_URL=http://forgejo:3000/ ``` Should be: ``` FORGEJO__server__ROOT_URL=http://forgejo:3000/forge/ ``` Forgejo's app.ini mirrors this as `ROOT_URL = http://forgejo:3000/forge/`. ## The fix Set `FORGEJO__server__ROOT_URL` to include the `/forge/` suffix in the compose service env. The generator at `lib/generators.sh` emits this value; update so it produces the subpath form when `EDGE_TUNNEL_FQDN` is set (existing logic at `bin/disinto:842-847` mentioned in #1025 body may already cover part of this — verify). Also verify the Caddyfile `handle /forge/*` block does **not** strip the prefix (unlike staging #NNNN). Forgejo needs the full `/forge/...` path to arrive so its own router recognizes it. ``` # Correct — no strip_prefix handle /forge/* { reverse_proxy forgejo:3000 } ``` ## Acceptance criteria - [ ] `FORGEJO__server__ROOT_URL` set to include `/forge/` subpath when subpath routing is active - [ ] Verify via `docker exec disinto-forgejo env | grep ROOT_URL` - [ ] `curl http://localhost/forge/` returns 200 with Forgejo landing page HTML (not 404) - [ ] Forgejo login flow completes without redirect loops: `curl -L http://localhost/forge/user/login` returns a 200 with the login form - [ ] Forgejo-generated internal links in the rendered HTML use `/forge/` prefix (grep the response for `href="/`) - [ ] Woodpecker ↔ Forgejo OAuth still works: existing Woodpecker login flow functional (check via `/ci/` end-to-end) - [ ] `tests/smoke-edge-subpath.sh` Test 2 and Test 3 pass against live edge - [ ] No regression on Woodpecker subpath (`/ci/` stays 200) ## Affected files - `lib/generators.sh` — FORGEJO__server__ROOT_URL emission (and WOODPECKER_HOST if analogous) - Possibly `docker-compose.yml` (if ROOT_URL is hardcoded there instead of generated) - `tests/smoke-edge-subpath.sh` — no change expected; already covers this path ## Notes Forgejo subpath has known upstream quirks (asset paths, avatar URLs, OAuth callback URLs). The sprint pitch for #623 (`edge-subpath-chat`) explicitly flagged this as a risk and documented a fallback plan at `docs/edge-routing-fallback.md` — if subpath routing has intractable issues after this fix, pivot to per-service subdomains per that plan. ## Related - Vision #623 — edge subpath routing - #1025 — smoke-test tool which surfaced this gap - #1028 — automated subdomain fallback (merged); relevant if this fix can't land cleanly - Companion issue: `/staging/` strip_prefix fix
disinto-admin added the
backlog
label 2026-04-20 15:08:27 +00:00
dev-qwen self-assigned this 2026-04-20 15:09:30 +00:00
dev-qwen added
in-progress
and removed
backlog
labels 2026-04-20 15:09:30 +00:00
dev-qwen removed their assignment 2026-04-20 15:36:18 +00:00
dev-qwen removed the
in-progress
label 2026-04-20 15:36:18 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: disinto-admin/disinto#1080
No description provided.