Merge pull request 'fix: vision(#623): per-project subdomain fallback path (contingency) (#713)' (#732) from fix/issue-713 into main
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
This commit is contained in:
commit
eaf0f724fa
3 changed files with 157 additions and 0 deletions
149
docs/edge-routing-fallback.md
Normal file
149
docs/edge-routing-fallback.md
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
# Edge Routing Fallback: Per-Project Subdomains
|
||||
|
||||
> **Status:** Contingency plan. Only implement if subpath routing (#704 / #708)
|
||||
> proves unworkable.
|
||||
|
||||
## Context
|
||||
|
||||
The primary approach routes services under subpaths of `<project>.disinto.ai`:
|
||||
|
||||
| Service | Primary (subpath) |
|
||||
|------------|--------------------------------------------|
|
||||
| Forgejo | `<project>.disinto.ai/forge/` |
|
||||
| Woodpecker | `<project>.disinto.ai/ci/` |
|
||||
| Chat | `<project>.disinto.ai/chat/` |
|
||||
| Staging | `<project>.disinto.ai/staging/` |
|
||||
|
||||
The fallback uses per-service subdomains instead:
|
||||
|
||||
| Service | Fallback (subdomain) |
|
||||
|------------|--------------------------------------------|
|
||||
| Forgejo | `forge.<project>.disinto.ai/` |
|
||||
| Woodpecker | `ci.<project>.disinto.ai/` |
|
||||
| Chat | `chat.<project>.disinto.ai/` |
|
||||
| Staging | `<project>.disinto.ai/` (root) |
|
||||
|
||||
The wildcard cert from #621 already covers `*.<project>.disinto.ai` — no new
|
||||
DNS records or certs are needed for sub-subdomains because `*.disinto.ai`
|
||||
matches one level deep. For sub-subdomains like `forge.<project>.disinto.ai`
|
||||
we would need to add a second wildcard (`*.*.disinto.ai`) or explicit DNS
|
||||
records per project. Both are straightforward with the existing Gandi DNS-01
|
||||
setup.
|
||||
|
||||
## Pivot Decision Criteria
|
||||
|
||||
**Pivot if:**
|
||||
|
||||
- Forgejo `ROOT_URL` under a subpath (`/forge/`) causes redirect loops that
|
||||
cannot be fixed with `X-Forwarded-Prefix` or Caddy `uri strip_prefix`.
|
||||
- Woodpecker's `WOODPECKER_HOST` does not honour subpath prefixes, causing
|
||||
OAuth callback mismatches that persist after adjusting redirect URIs.
|
||||
- Forward-auth on `/chat/*` conflicts with Forgejo's own OAuth flow when both
|
||||
share the same origin (cookie collision, CSRF token mismatch).
|
||||
|
||||
**Do NOT pivot if:**
|
||||
|
||||
- Forgejo login redirects to `/` instead of `/forge/` — fixable with Caddy
|
||||
`handle_path` + `uri prefix` rewrite.
|
||||
- Woodpecker UI assets 404 under `/ci/` — fixable with asset prefix config
|
||||
(`WOODPECKER_ROOT_PATH`).
|
||||
- A single OAuth app needs a second redirect URI — Forgejo supports multiple
|
||||
`redirect_uris` in the same app.
|
||||
|
||||
## Fallback Topology
|
||||
|
||||
### Caddyfile
|
||||
|
||||
Replace the single `:80` block with four host blocks:
|
||||
|
||||
```caddy
|
||||
# Main project domain — staging / landing
|
||||
<project>.disinto.ai {
|
||||
reverse_proxy staging:80
|
||||
}
|
||||
|
||||
# Forgejo — root path, no subpath rewrite needed
|
||||
forge.<project>.disinto.ai {
|
||||
reverse_proxy forgejo:3000
|
||||
}
|
||||
|
||||
# Woodpecker CI — root path
|
||||
ci.<project>.disinto.ai {
|
||||
reverse_proxy woodpecker:8000
|
||||
}
|
||||
|
||||
# Chat — with forward_auth (same as #709, but on its own host)
|
||||
chat.<project>.disinto.ai {
|
||||
handle /login {
|
||||
reverse_proxy chat:8080
|
||||
}
|
||||
handle /oauth/callback {
|
||||
reverse_proxy chat:8080
|
||||
}
|
||||
handle /* {
|
||||
forward_auth chat:8080 {
|
||||
uri /auth/verify
|
||||
copy_headers X-Forwarded-User
|
||||
header_up X-Forward-Auth-Secret {$FORWARD_AUTH_SECRET}
|
||||
}
|
||||
reverse_proxy chat:8080
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Current file:** `docker/Caddyfile` (generated by `lib/generators.sh:_generate_caddyfile_impl`, line ~596).
|
||||
|
||||
### Service Configuration Changes
|
||||
|
||||
| Variable / Setting | Current (subpath) | Fallback (subdomain) | File |
|
||||
|----------------------------|------------------------------------------------|-------------------------------------------------|-----------------------------|
|
||||
| Forgejo `ROOT_URL` | `https://<project>.disinto.ai/forge/` | `https://forge.<project>.disinto.ai/` | forgejo `app.ini` |
|
||||
| `WOODPECKER_HOST` | `http://localhost:8000` (subpath via proxy) | `https://ci.<project>.disinto.ai` | `lib/ci-setup.sh` line ~164 |
|
||||
| Woodpecker OAuth redirect | `https://<project>.disinto.ai/ci/authorize` | `https://ci.<project>.disinto.ai/authorize` | `lib/ci-setup.sh` line ~153 |
|
||||
| Chat OAuth redirect | `https://<project>.disinto.ai/chat/oauth/callback` | `https://chat.<project>.disinto.ai/oauth/callback` | `lib/ci-setup.sh` line ~188 |
|
||||
| `EDGE_TUNNEL_FQDN` | `<project>.disinto.ai` | unchanged (main domain) | `lib/generators.sh` line ~432 |
|
||||
|
||||
### New Environment Variables (pivot only)
|
||||
|
||||
These would be added to `lib/generators.sh` `_generate_compose_impl()` in the
|
||||
edge service environment block (currently line ~415):
|
||||
|
||||
| Variable | Value |
|
||||
|------------------------------|----------------------------------------|
|
||||
| `EDGE_TUNNEL_FQDN_FORGE` | `forge.<project>.disinto.ai` |
|
||||
| `EDGE_TUNNEL_FQDN_CI` | `ci.<project>.disinto.ai` |
|
||||
| `EDGE_TUNNEL_FQDN_CHAT` | `chat.<project>.disinto.ai` |
|
||||
|
||||
### DNS
|
||||
|
||||
No new records needed if the registrar supports `*.*.disinto.ai` wildcards.
|
||||
Otherwise, add explicit A/CNAME records per project:
|
||||
|
||||
```
|
||||
forge.<project>.disinto.ai → edge server IP
|
||||
ci.<project>.disinto.ai → edge server IP
|
||||
chat.<project>.disinto.ai → edge server IP
|
||||
```
|
||||
|
||||
The edge server already handles TLS via Caddy's automatic HTTPS with the
|
||||
existing ACME / DNS-01 challenge.
|
||||
|
||||
### Edge Control (`tools/edge-control/register.sh`)
|
||||
|
||||
Currently `do_register()` creates a single route for `<project>.disinto.ai`.
|
||||
The fallback would need to register four routes (or accept a `--subdomain`
|
||||
parameter). See the TODO in `register.sh`.
|
||||
|
||||
## Files to Change on Pivot
|
||||
|
||||
| File | What changes |
|
||||
|-----------------------------------|-----------------------------------------------------------------|
|
||||
| `docker/Caddyfile` | Replace single host block → four host blocks (see above) |
|
||||
| `lib/generators.sh` | Add `EDGE_TUNNEL_FQDN_{FORGE,CI,CHAT}` env vars to compose |
|
||||
| `lib/ci-setup.sh` ~line 153 | Woodpecker OAuth redirect URI → `ci.<project>` subdomain |
|
||||
| `lib/ci-setup.sh` ~line 188 | Chat OAuth redirect URI → `chat.<project>` subdomain |
|
||||
| `tools/edge-control/register.sh` | Register four routes per project instead of one |
|
||||
| `tools/edge-control/lib/caddy.sh`| `add_route()` gains subdomain support |
|
||||
| forgejo `app.ini` | `ROOT_URL` → `https://forge.<project>.disinto.ai/` |
|
||||
|
||||
Estimated effort for a full pivot: **under one day** given this plan.
|
||||
|
|
@ -430,6 +430,9 @@ services:
|
|||
- EDGE_TUNNEL_USER=${EDGE_TUNNEL_USER:-tunnel}
|
||||
- EDGE_TUNNEL_PORT=${EDGE_TUNNEL_PORT:-}
|
||||
- EDGE_TUNNEL_FQDN=${EDGE_TUNNEL_FQDN:-}
|
||||
# Subdomain fallback (#713): if subpath routing (#704/#708) fails, add:
|
||||
# EDGE_TUNNEL_FQDN_FORGE, EDGE_TUNNEL_FQDN_CI, EDGE_TUNNEL_FQDN_CHAT
|
||||
# See docs/edge-routing-fallback.md for the full pivot plan.
|
||||
# Shared secret for Caddy ↔ chat forward_auth (#709)
|
||||
- FORWARD_AUTH_SECRET=${FORWARD_AUTH_SECRET:-}
|
||||
volumes:
|
||||
|
|
|
|||
|
|
@ -39,6 +39,11 @@ EOF
|
|||
exit 1
|
||||
}
|
||||
|
||||
# TODO(#713): Subdomain fallback — if subpath routing (#704/#708) fails, this
|
||||
# function would need to register additional routes for forge.<project>,
|
||||
# ci.<project>, chat.<project> subdomains (or accept a --subdomain parameter).
|
||||
# See docs/edge-routing-fallback.md for the full pivot plan.
|
||||
|
||||
# Register a new tunnel
|
||||
# Usage: do_register <project> <pubkey>
|
||||
do_register() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue