forgejo: make dev.jinemi.com canonical (ROOT_URL and OAuth callback)
All checks were successful
PR build (required check) / changes (pull_request) Successful in 6s
PR build (required check) / build-backend (pull_request) Has been skipped
PR build (required check) / build-frontend (pull_request) Has been skipped
secrets-guard / encrypted (pull_request) Successful in 9s
shell-lint / shellcheck (pull_request) Successful in 7s
PR build (required check) / validate-observability (pull_request) Has been skipped
PR build (required check) / gate (pull_request) Successful in 1s
All checks were successful
PR build (required check) / changes (pull_request) Successful in 6s
PR build (required check) / build-backend (pull_request) Has been skipped
PR build (required check) / build-frontend (pull_request) Has been skipped
secrets-guard / encrypted (pull_request) Successful in 9s
shell-lint / shellcheck (pull_request) Successful in 7s
PR build (required check) / validate-observability (pull_request) Has been skipped
PR build (required check) / gate (pull_request) Successful in 1s
Forgejo derives every absolute URL from its single ROOT_URL, so this is what moves clone URLs, the Google OAuth callback, webhook payload URLs and mail links onto the new domain. Both redirect URIs are registered on the Google OAuth client and were verified against Google before the flip — login is SSO-only, so a mismatch locks everyone out of the UI including out of undoing it. README documents the probe so the check is repeatable rather than assumed. git.thermograph.org stays on the same Caddy site block and stays load-bearing: the registry host baked into image names, the mesh /etc/hosts pins that make the /v2/* matcher see a mesh source IP, and the runners' registered instance URL all still use it. Renaming the registry is a separate migration; the docs now say so where someone would otherwise retire the name as dead weight. The stack has no auto-deploy, so this takes effect on a manual `docker stack deploy` from the manager.
This commit is contained in:
parent
7fca3556e8
commit
a83a0b7d32
6 changed files with 77 additions and 52 deletions
|
|
@ -26,7 +26,7 @@ rather than which environment happens to live there:
|
||||||
|
|
||||||
| Host | Public IP | Mesh IP | Role |
|
| Host | Public IP | Mesh IP | Role |
|
||||||
|------|-----------|---------|------|
|
|------|-----------|---------|------|
|
||||||
| **vps1** | `75.119.132.91` | `10.10.0.2` | "Operational programs": Forgejo (git + CI + registry, `git.thermograph.org`, also served at `dev.jinemi.com` — migration in progress, `.org` still canonical), Grafana/Loki/Alloy (`dashboard.thermograph.org`), the `emigriffith.dev` portfolio, and the **dev** environment (mesh-only, `10.10.0.2:8137`, no public DNS/Caddy/TLS) |
|
| **vps1** | `75.119.132.91` | `10.10.0.2` | "Operational programs": Forgejo (git + CI + registry; `dev.jinemi.com` canonical, `git.thermograph.org` still served and still used by the registry/mesh pins/runners), Grafana/Loki/Alloy (`dashboard.thermograph.org`), the `emigriffith.dev` portfolio, and the **dev** environment (mesh-only, `10.10.0.2:8137`, no public DNS/Caddy/TLS) |
|
||||||
| **vps2** | `169.58.46.181` | `10.10.0.1` | "The deployed environment": **prod** and **beta**, as two separate Docker Swarm stacks, plus Centralis, Postfix, the backups, and the one shared TimescaleDB instance both stacks use |
|
| **vps2** | `169.58.46.181` | `10.10.0.1` | "The deployed environment": **prod** and **beta**, as two separate Docker Swarm stacks, plus Centralis, Postfix, the backups, and the one shared TimescaleDB instance both stacks use |
|
||||||
| **desktop** | — | `10.10.0.3` | AI-model hosting (voice-to-text, an upcoming-feature LLM) plus flex Swarm-worker capacity. Hosts **no** Thermograph environment — `make dev-up` still works there, but only as a laptop-local rehearsal |
|
| **desktop** | — | `10.10.0.3` | AI-model hosting (voice-to-text, an upcoming-feature LLM) plus flex Swarm-worker capacity. Hosts **no** Thermograph environment — `make dev-up` still works there, but only as a laptop-local rehearsal |
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,10 @@ Two VPS boxes plus the operator's desktop, on one WireGuard mesh, named by
|
||||||
ROLE rather than by environment:
|
ROLE rather than by environment:
|
||||||
|
|
||||||
- **vps1** — `75.119.132.91`, mesh `10.10.0.2`. "Operational programs": Forgejo
|
- **vps1** — `75.119.132.91`, mesh `10.10.0.2`. "Operational programs": Forgejo
|
||||||
(git + CI + registry, `git.thermograph.org`, also served at `dev.jinemi.com`
|
(git + CI + registry; `dev.jinemi.com` is canonical — Forgejo's `ROOT_URL` —
|
||||||
— one Caddy site block, the `.org` name still canonical; migration in
|
and `git.thermograph.org` is still served off the same Caddy site block and
|
||||||
progress, see `deploy/forgejo/README.md`), Grafana/Loki/Alloy
|
still load-bearing for the registry, mesh pins and runner URLs, so don't
|
||||||
|
retire it; see `deploy/forgejo/README.md`), Grafana/Loki/Alloy
|
||||||
(`dashboard.thermograph.org`), the `emigriffith.dev` portfolio site, and the
|
(`dashboard.thermograph.org`), the `emigriffith.dev` portfolio site, and the
|
||||||
**dev** environment (`/opt/thermograph-dev`, tracks `dev`), with its own
|
**dev** environment (`/opt/thermograph-dev`, tracks `dev`), with its own
|
||||||
Postgres container. Dev is mesh-only here — published on `10.10.0.2:8137`,
|
Postgres container. Dev is mesh-only here — published on `10.10.0.2:8137`,
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,11 @@
|
||||||
#
|
#
|
||||||
# vps1 serves:
|
# vps1 serves:
|
||||||
# emigriffith.dev -> static portfolio site (from disk)
|
# emigriffith.dev -> static portfolio site (from disk)
|
||||||
# git.thermograph.org -> Forgejo (see deploy/forgejo/caddy-git.conf)
|
# dev.jinemi.com -> Forgejo, CANONICAL (Forgejo's ROOT_URL)
|
||||||
# dev.jinemi.com -> Forgejo, same site block — migration target for
|
# git.thermograph.org -> Forgejo, same site block — still served and
|
||||||
# git.thermograph.org, both served, the .org one
|
# still needed: the registry host in image names,
|
||||||
# still canonical (that file's header explains)
|
# the mesh /etc/hosts pins and the runners' URLs
|
||||||
|
# all use it (see deploy/forgejo/caddy-git.conf)
|
||||||
# dashboard.thermograph.org -> Grafana (see observability/caddy-grafana.conf)
|
# dashboard.thermograph.org -> Grafana (see observability/caddy-grafana.conf)
|
||||||
#
|
#
|
||||||
# and hosts the **dev** environment at dev.thermograph.org (below).
|
# and hosts the **dev** environment at dev.thermograph.org (below).
|
||||||
|
|
|
||||||
|
|
@ -85,50 +85,55 @@ pattern as its other site blocks, same automatic-HTTPS.
|
||||||
|
|
||||||
## Migrating the domain (git.thermograph.org -> dev.jinemi.com)
|
## Migrating the domain (git.thermograph.org -> dev.jinemi.com)
|
||||||
|
|
||||||
In progress. **Both hostnames are served**; `git.thermograph.org` is still the
|
**Web UI and OAuth: done.** `dev.jinemi.com` is Forgejo's `ROOT_URL`
|
||||||
canonical one.
|
(`FORGEJO_DOMAIN` in `docker-stack.yml`), so it is the name Forgejo generates in
|
||||||
|
clone URLs, the Google OAuth callback, webhook payload URLs and mail links.
|
||||||
|
|
||||||
|
**Registry: deliberately not done.** Renaming the registry host is a separate
|
||||||
|
migration from renaming the web UI, and the two need not happen together.
|
||||||
|
|
||||||
`caddy-git.conf` lists both names on a *single* site block. That is deliberate,
|
`caddy-git.conf` lists both names on a *single* site block. That is deliberate,
|
||||||
not cosmetic: the `/v2/*` mesh-only matcher is per-block, so a second block for
|
not cosmetic: the `/v2/*` mesh-only matcher is per-block, so a second block for
|
||||||
`dev.jinemi.com` would re-expose the registry API publicly and undo hazard #15.
|
either name would re-expose the registry API publicly and undo hazard #15.
|
||||||
Whatever else changes, keep the two names in one block.
|
Whatever else changes, keep the two names in one block.
|
||||||
|
|
||||||
Serving a second hostname is the cheap half. Forgejo has exactly one
|
**`git.thermograph.org` must stay served.** It is not a courtesy redirect for
|
||||||
`ROOT_URL`, and it builds every absolute URL from it, so on the non-canonical
|
old bookmarks — CI resolves it:
|
||||||
host today:
|
|
||||||
|
|
||||||
- clone URLs on repo pages read `git.thermograph.org`,
|
- images are named by registry host, and the `git.thermograph.org/` prefix is
|
||||||
- the OAuth callback and post-login redirect land on `git.thermograph.org`
|
baked into the runner labels (`register-lan-runner.sh`,
|
||||||
(login is Google-SSO-only — see `docker-stack.yml`),
|
`runner-vps2/README.md`), the CI-runner image (`ci-runner/Dockerfile`),
|
||||||
- webhook payload URLs and notification mail links use `git.thermograph.org`.
|
`REGISTRY_HOST` in `infra/.env.example`, and every already-pushed tag;
|
||||||
|
- every mesh client in "Registry access from mesh clients" below pins
|
||||||
|
`git.thermograph.org` to `10.10.0.2` in `/etc/hosts`, which is what makes
|
||||||
|
Caddy's `/v2/*` matcher see a mesh source IP instead of returning 403;
|
||||||
|
- registered runners hold the instance URL they registered with
|
||||||
|
(`https://git.thermograph.org`); they keep working while that name resolves.
|
||||||
|
|
||||||
Browsing, git-over-HTTP and the API all work on `dev.jinemi.com` regardless.
|
### Before changing ROOT_URL again
|
||||||
|
|
||||||
Flipping canonical (`FORGEJO_DOMAIN=dev.jinemi.com`, then `docker stack deploy`)
|
Login is Google-SSO-only, so the Google OAuth client must already carry a
|
||||||
needs these **first**, or it breaks login and CI rather than just renaming
|
matching redirect URI, or nobody can reach the UI — including to undo the
|
||||||
things:
|
change. Both of these are registered on client
|
||||||
|
`337247886376-4360kepi20f24pue62ptg0lnqhcht46l.apps.googleusercontent.com`:
|
||||||
|
|
||||||
1. **Google OAuth** — add `https://dev.jinemi.com/user/oauth2/<name>/callback`
|
https://dev.jinemi.com/user/oauth2/google/callback
|
||||||
as an authorized redirect URI in the Google Cloud console *before* the flip.
|
https://git.thermograph.org/user/oauth2/google/callback
|
||||||
Not in this repo; nothing here can verify it. Miss it and no one can log in,
|
|
||||||
including to undo the flip.
|
|
||||||
2. **The registry host in image names** — images are named by registry host, and
|
|
||||||
the `git.thermograph.org/` prefix is baked into the runner labels
|
|
||||||
(`register-lan-runner.sh`, `runner-vps2/README.md`), the CI-runner image
|
|
||||||
(`ci-runner/Dockerfile`), `REGISTRY_HOST` in `infra/.env.example`, and every
|
|
||||||
already-pushed tag. Renaming the registry host is a separate migration from
|
|
||||||
renaming the web UI; the two need not happen together, and doing the web UI
|
|
||||||
alone is much the smaller change.
|
|
||||||
3. **Mesh `/etc/hosts` pins** — every node in "Registry access from mesh
|
|
||||||
clients" below pins `git.thermograph.org` to `10.10.0.2`. A node pulling
|
|
||||||
under a new hostname needs its own pin, or Caddy's `/v2/*` matcher sees a
|
|
||||||
public source IP and returns 403.
|
|
||||||
4. **Runner instance URL** — registered runners hold the instance URL they were
|
|
||||||
registered with. Existing runners keep working against the old name as long
|
|
||||||
as it resolves; a *re*-registration must use whichever name is canonical then.
|
|
||||||
|
|
||||||
Until all four are handled, leaving `ROOT_URL` on `git.thermograph.org` is the
|
Verify rather than assume. Google answers this with no credentials: a
|
||||||
correct state, not an unfinished one.
|
registered URI serves the sign-in page, an unregistered one returns
|
||||||
|
`redirect_uri_mismatch`. Substitute the host you intend to make canonical:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
CID=337247886376-4360kepi20f24pue62ptg0lnqhcht46l.apps.googleusercontent.com
|
||||||
|
curl -sL "https://accounts.google.com/o/oauth2/v2/auth?client_id=$CID&redirect_uri=https%3A%2F%2F<host>%2Fuser%2Foauth2%2Fgoogle%2Fcallback&response_type=code&scope=openid+email+profile&state=probe" \
|
||||||
|
| grep -q redirect_uri_mismatch && echo REJECTED || echo ACCEPTED
|
||||||
|
```
|
||||||
|
|
||||||
|
The stack has **no auto-deploy**: a `FORGEJO_DOMAIN` change here only takes
|
||||||
|
effect when someone re-runs `docker stack deploy` by hand on the manager (vps2)
|
||||||
|
— see "Deploy / update" above. Until then the running service keeps whatever
|
||||||
|
`ROOT_URL` it was last deployed with, regardless of what this file says.
|
||||||
|
|
||||||
## Registry access from mesh clients
|
## Registry access from mesh clients
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,15 +14,16 @@
|
||||||
# both. Splitting dev.jinemi.com into its own block serves the same Forgejo
|
# both. Splitting dev.jinemi.com into its own block serves the same Forgejo
|
||||||
# with the registry API open to the public internet.
|
# with the registry API open to the public internet.
|
||||||
#
|
#
|
||||||
# dev.jinemi.com is the migration target for git.thermograph.org; both are
|
# dev.jinemi.com is CANONICAL — it is Forgejo's ROOT_URL (docker-stack.yml,
|
||||||
# served during the transition. Each gets its own Let's Encrypt cert
|
# FORGEJO_DOMAIN), so it is the name Forgejo puts in clone URLs, the OAuth
|
||||||
# automatically (HTTP-01) — both A records already point at vps1.
|
# callback, webhook payload URLs and mail links.
|
||||||
#
|
#
|
||||||
# git.thermograph.org stays CANONICAL until Forgejo's ROOT_URL is flipped
|
# git.thermograph.org is kept as a served alias, NOT as dead weight: the
|
||||||
# (docker-stack.yml, FORGEJO_DOMAIN). Until then dev.jinemi.com serves every
|
# registry host baked into image names, the mesh /etc/hosts pins and the
|
||||||
# page, but Forgejo builds absolute URLs from ROOT_URL, so clone URLs, the
|
# runners' registered instance URL all still say git.thermograph.org. Removing
|
||||||
# OAuth callback and post-login redirects still name git.thermograph.org.
|
# this name from the block breaks CI, not just old bookmarks. Both names get
|
||||||
# Flipping it is NOT just this file — see README.md, "Migrating the domain".
|
# their own Let's Encrypt cert automatically (HTTP-01); both A records point
|
||||||
|
# at vps1. See README.md, "Migrating the domain".
|
||||||
#
|
#
|
||||||
# Registry exposure (hazard #15, see docker-stack.yml's header comment):
|
# Registry exposure (hazard #15, see docker-stack.yml's header comment):
|
||||||
# /v2/* is the built-in OCI registry API. It's blocked from anywhere except
|
# /v2/* is the built-in OCI registry API. It's blocked from anywhere except
|
||||||
|
|
|
||||||
|
|
@ -80,8 +80,25 @@ services:
|
||||||
FORGEJO__database__HOST: db:5432
|
FORGEJO__database__HOST: db:5432
|
||||||
FORGEJO__database__NAME: forgejo
|
FORGEJO__database__NAME: forgejo
|
||||||
FORGEJO__database__USER: forgejo
|
FORGEJO__database__USER: forgejo
|
||||||
FORGEJO__server__DOMAIN: "${FORGEJO_DOMAIN:-git.thermograph.org}"
|
# Canonical domain. Forgejo has exactly ONE ROOT_URL and derives every
|
||||||
FORGEJO__server__ROOT_URL: "https://${FORGEJO_DOMAIN:-git.thermograph.org}/"
|
# absolute URL from it — clone URLs, the Google OAuth callback, webhook
|
||||||
|
# payload URLs, mail links. git.thermograph.org is still served (Caddy
|
||||||
|
# answers for both names off one site block, deploy/forgejo/caddy-git.conf)
|
||||||
|
# and still works for browsing, git-over-HTTP and the API; it is simply no
|
||||||
|
# longer the name Forgejo generates.
|
||||||
|
#
|
||||||
|
# Changing this breaks login unless the matching redirect URI exists on
|
||||||
|
# the Google OAuth client FIRST — login is SSO-only, so a mismatch locks
|
||||||
|
# everyone out of the UI, including out of the ability to undo it. Both
|
||||||
|
# https://dev.jinemi.com/user/oauth2/google/callback and the
|
||||||
|
# git.thermograph.org one are registered; verify with a probe before
|
||||||
|
# changing this again (deploy/forgejo/README.md, "Migrating the domain").
|
||||||
|
#
|
||||||
|
# NOT changed by this: the registry host baked into image names, the mesh
|
||||||
|
# /etc/hosts pins, and the runners' registered instance URL all still say
|
||||||
|
# git.thermograph.org. That is a separate migration.
|
||||||
|
FORGEJO__server__DOMAIN: "${FORGEJO_DOMAIN:-dev.jinemi.com}"
|
||||||
|
FORGEJO__server__ROOT_URL: "https://${FORGEJO_DOMAIN:-dev.jinemi.com}/"
|
||||||
FORGEJO__server__SSH_PORT: "2222"
|
FORGEJO__server__SSH_PORT: "2222"
|
||||||
# Without this, Forgejo starts no SSH server at all despite SSH_PORT
|
# Without this, Forgejo starts no SSH server at all despite SSH_PORT
|
||||||
# being set — git@ clones get "connection refused", not a slow failure.
|
# being set — git@ clones get "connection refused", not a slow failure.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue