Demo content from demo/admin-guide (0c17989)
This commit is contained in:
parent
8385e2024a
commit
3c566c0cc9
11 changed files with 645 additions and 2 deletions
8
.order
Normal file
8
.order
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
sign-in-options
|
||||||
|
entra-id
|
||||||
|
forgejo-identity-provider
|
||||||
|
github-sign-in
|
||||||
|
spaces-and-git-providers
|
||||||
|
configuration-reference
|
||||||
|
backup-and-restore
|
||||||
|
operations
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
# admin-guide
|
|
||||||
|
|
||||||
69
backup-and-restore/index.md
Normal file
69
backup-and-restore/index.md
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
---
|
||||||
|
id: backup-and-restore
|
||||||
|
title: Backup and restore
|
||||||
|
description: What actually needs a backup — Git holds the content, the database only holds a derived index.
|
||||||
|
tags: [admin, backup, restore]
|
||||||
|
lang: en
|
||||||
|
---
|
||||||
|
|
||||||
|
# Backup and restore
|
||||||
|
|
||||||
|
f451's split between "Git is the source of truth" and "Postgres is only an
|
||||||
|
index" (see *Principles* in the Developer Guide) turns backup planning
|
||||||
|
into a short list, not a long one.
|
||||||
|
|
||||||
|
## The one thing that matters
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> **The Forgejo data volume is the only backup-critical piece of a whole
|
||||||
|
> f451 deployment.** It holds every space's repository content plus
|
||||||
|
> Forgejo's own configuration and account database. Losing it without a
|
||||||
|
> backup means the wiki content is gone — there is nothing else it can be
|
||||||
|
> rebuilt from.
|
||||||
|
|
||||||
|
If a space lives on GitHub instead of the bundled Forgejo, that content is
|
||||||
|
already backed up by GitHub itself; only Forgejo-hosted spaces are this
|
||||||
|
deployment's own responsibility.
|
||||||
|
|
||||||
|
## The database is a rebuildable cache
|
||||||
|
|
||||||
|
The Postgres volume holds the search index, rendered page content, the
|
||||||
|
knowledge-graph edges, sessions, and encrypted provider tokens. All of the
|
||||||
|
content-derived pieces are rebuilt automatically:
|
||||||
|
|
||||||
|
- `POST /admin/reindex` (bearer-token-protected, see
|
||||||
|
[[operations]]) rebuilds the full index for one or all spaces from Git,
|
||||||
|
on demand.
|
||||||
|
- The drift job (see [[spaces-and-git-providers]]) rebuilds it
|
||||||
|
automatically within about five minutes of a missed webhook, without any
|
||||||
|
manual step.
|
||||||
|
|
||||||
|
Losing the database without a backup costs two things, neither of them
|
||||||
|
content:
|
||||||
|
|
||||||
|
- **Sessions** — everyone has to sign in again.
|
||||||
|
- **Encrypted provider tokens** — everyone has to reconnect their Forgejo
|
||||||
|
or GitHub account once (see [[sign-in-options]]).
|
||||||
|
|
||||||
|
A database backup is still worth having in practice, purely to skip the
|
||||||
|
reindex time and avoid the mass reconnect — but it is never the *only*
|
||||||
|
copy of anything.
|
||||||
|
|
||||||
|
## Restore, in outline
|
||||||
|
|
||||||
|
1. Stop both stacks (the Git stack and the application stack).
|
||||||
|
2. Restore the Forgejo data volume from backup.
|
||||||
|
3. Start the Git stack and wait for it to report healthy.
|
||||||
|
4. Start the application stack. The database starts empty — apply pending
|
||||||
|
migrations before traffic reaches the new containers (the production
|
||||||
|
image ships a compiled migration runner for exactly this).
|
||||||
|
5. Trigger a full reindex of all spaces (`POST /admin/reindex`) rather than
|
||||||
|
waiting for the drift job — after a restore there is no reason to wait
|
||||||
|
up to five minutes for content to reappear.
|
||||||
|
6. Verify: the space list responds, a known page is readable, and
|
||||||
|
`GET /admin/status` reports no indexing errors for the reindex that just
|
||||||
|
ran.
|
||||||
|
|
||||||
|
Sessions and account connections are deliberately not part of this
|
||||||
|
procedure — people sign in again and, if needed, reconnect their Git
|
||||||
|
account once, exactly as described above.
|
||||||
123
configuration-reference/index.md
Normal file
123
configuration-reference/index.md
Normal file
|
|
@ -0,0 +1,123 @@
|
||||||
|
---
|
||||||
|
id: configuration-reference
|
||||||
|
title: Configuration reference
|
||||||
|
description: Every environment variable the api service reads, grouped by concern.
|
||||||
|
tags: [admin, reference, configuration]
|
||||||
|
lang: en
|
||||||
|
---
|
||||||
|
|
||||||
|
# Configuration reference
|
||||||
|
|
||||||
|
All variables below are read by the `api` service. None are required to
|
||||||
|
start f451 at all — an instance with nothing set runs in a minimal,
|
||||||
|
read-only, unauthenticated mode (`/healthz`/`/readyz` only). Each group
|
||||||
|
becomes meaningful once you set its first variable.
|
||||||
|
|
||||||
|
## Spaces and providers
|
||||||
|
|
||||||
|
See [[spaces-and-git-providers]] for the full explanation.
|
||||||
|
|
||||||
|
| Variable | Required when | Default |
|
||||||
|
|---|---|---|
|
||||||
|
| `F451_SPACES` | Any space should be visible | — (minimal mode) |
|
||||||
|
| `F451_FORGEJO_URL` | A space uses `provider: "forgejo"`, or Forgejo account linking is enabled | — |
|
||||||
|
| `F451_FORGEJO_TOKEN` | A space uses `provider: "forgejo"` | — |
|
||||||
|
| `F451_GITHUB_TOKEN` | A space uses `provider: "github"` | — |
|
||||||
|
| `F451_WEBHOOK_SECRET_FORGEJO` | Forgejo webhooks should be accepted | — |
|
||||||
|
| `F451_WEBHOOK_SECRET_GITHUB` | GitHub webhooks should be accepted | — |
|
||||||
|
| `F451_GLOBAL_TEMPLATES` | A provider-wide template repository is shared across spaces | — |
|
||||||
|
|
||||||
|
## Sign-in (OIDC)
|
||||||
|
|
||||||
|
See [[sign-in-options]], [[entra-id]], [[forgejo-identity-provider]].
|
||||||
|
|
||||||
|
| Variable | Required when | Default |
|
||||||
|
|---|---|---|
|
||||||
|
| `F451_OIDC_ISSUER` | Auth should be enabled at all — unset means the entire API is unauthenticated | — (auth off) |
|
||||||
|
| `F451_OIDC_CLIENT_ID` | `F451_OIDC_ISSUER` is set | — |
|
||||||
|
| `F451_OIDC_CLIENT_SECRET` | `F451_OIDC_ISSUER` is set | — |
|
||||||
|
| `F451_OIDC_REDIRECT_URL` | `F451_OIDC_ISSUER` is set — must equal `https://<host>/auth/callback` | — |
|
||||||
|
| `F451_OIDC_PROVIDER_NAME` | Never required | unset → plain "Sign in" button |
|
||||||
|
| `F451_TOKEN_KEY` | `F451_OIDC_ISSUER` is set — otherwise the api fails to start | — |
|
||||||
|
|
||||||
|
## Sign-in (GitHub)
|
||||||
|
|
||||||
|
See [[github-sign-in]].
|
||||||
|
|
||||||
|
| Variable | Required when | Default |
|
||||||
|
|---|---|---|
|
||||||
|
| `F451_GITHUB_LOGIN` | GitHub should appear as a sign-in method | `0` (off) |
|
||||||
|
| `F451_GITHUB_OAUTH_CLIENT_ID` | `F451_GITHUB_LOGIN=1` | — |
|
||||||
|
| `F451_GITHUB_OAUTH_CLIENT_SECRET` | `F451_GITHUB_LOGIN=1` | — |
|
||||||
|
|
||||||
|
## Account linking (reading and writing)
|
||||||
|
|
||||||
|
Independent of which method someone signed in with — see
|
||||||
|
[[sign-in-options]].
|
||||||
|
|
||||||
|
| Variable | Required when | Default |
|
||||||
|
|---|---|---|
|
||||||
|
| `F451_FORGEJO_OAUTH_CLIENT_ID` / `_SECRET` | "Connect Forgejo" should be offered (needs `F451_FORGEJO_URL` too) | — (linking off) |
|
||||||
|
| `F451_GITHUB_OAUTH_CLIENT_ID` / `_SECRET` | "Connect GitHub" should be offered | — (linking off) |
|
||||||
|
|
||||||
|
## Cookies and running more than one instance on a host
|
||||||
|
|
||||||
|
| Variable | Required when | Default |
|
||||||
|
|---|---|---|
|
||||||
|
| `F451_COOKIE_PREFIX` | A second instance shares a host with this one — browsers do not separate cookies by port | `f451` |
|
||||||
|
| `F451_WEB_PORT` | A second instance needs a different host port for the web UI | `8080` |
|
||||||
|
| `F451_DRAWIO_PORT` | A second instance needs a different host port for the diagram editor | `8081` |
|
||||||
|
| `F451_FORGEJO_HTTP_PORT` / `F451_FORGEJO_SSH_PORT` | A second Forgejo instance shares a host | Forgejo defaults |
|
||||||
|
| `F451_FORGEJO_ROOT_URL` | A second Forgejo instance shares a host | Forgejo default |
|
||||||
|
|
||||||
|
## Local development only
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> Never set either of these in production.
|
||||||
|
|
||||||
|
| Variable | Effect |
|
||||||
|
|---|---|
|
||||||
|
| `F451_INSECURE_COOKIES=1` | Drops `secure` on session cookies (plain HTTP). |
|
||||||
|
| `F451_OIDC_ALLOW_INSECURE=1` | Allows an `http://` OIDC issuer. |
|
||||||
|
|
||||||
|
## Admin and operations
|
||||||
|
|
||||||
|
See [[operations]] and [[backup-and-restore]].
|
||||||
|
|
||||||
|
| Variable | Required when | Default |
|
||||||
|
|---|---|---|
|
||||||
|
| `F451_ADMIN_TOKEN` | `POST /admin/reindex` and `GET /admin/status` should work at all — unset means both are fail-closed | — (disabled) |
|
||||||
|
| `F451_MAX_UPLOAD_MB` | A non-default media upload limit is needed | `10` |
|
||||||
|
|
||||||
|
## Rate limits and reverse proxy
|
||||||
|
|
||||||
|
| Variable | Required when | Default |
|
||||||
|
|---|---|---|
|
||||||
|
| `F451_RATE_LIMIT_AUTH_MAX` | A non-default auth rate limit is needed (per route, per client IP) | `10`/min |
|
||||||
|
| `F451_RATE_LIMIT_SEARCH_MAX` | A non-default search rate limit is needed | `60`/min |
|
||||||
|
| `F451_RATE_LIMIT_API_TOKEN_MAX` | A non-default limit for API-token traffic (MCP agents) is needed, per user across their tokens | `300`/min |
|
||||||
|
| `F451_TRUST_PROXY` | This deployment always runs behind a reverse proxy — without it, every user shares one rate-limit bucket | — (no proxy trusted) |
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> `F451_TRUST_PROXY` needs the number of trusted hops between the reverse
|
||||||
|
> proxy and the `api` service, not just "on" or "off". Setting it to `true`
|
||||||
|
> trusts the left-most `X-Forwarded-For` entry, which a client can set
|
||||||
|
> itself — that makes the rate limits trivially bypassable. Verify the
|
||||||
|
> correct hop count against your actual proxy chain before relying on the
|
||||||
|
> limits in production; see [[operations]].
|
||||||
|
|
||||||
|
## Public URL
|
||||||
|
|
||||||
|
| Variable | Required when | Default |
|
||||||
|
|---|---|---|
|
||||||
|
| `F451_PUBLIC_BASE_URL` | Production, effectively always | — (falls back to the request's `Host` header) |
|
||||||
|
|
||||||
|
`F451_PUBLIC_BASE_URL` is the exact scheme and host (no path) that users
|
||||||
|
type into their browser. It is the basis for the OAuth `redirect_uri` used
|
||||||
|
when connecting a Forgejo or GitHub account, and it is the "our own
|
||||||
|
origin" side of the CSRF origin check on every write request.
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> A wrong value here does not fail loudly at startup — it fails at the
|
||||||
|
> first save, with every mutating browser request rejected with `403`. See
|
||||||
|
> [[operations]] for this symptom in the troubleshooting table.
|
||||||
77
entra-id/index.md
Normal file
77
entra-id/index.md
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
---
|
||||||
|
id: entra-id
|
||||||
|
title: Microsoft Entra ID
|
||||||
|
description: Registering an app in Entra and pointing f451's OIDC configuration at it, step by step.
|
||||||
|
tags: [admin, auth, entra]
|
||||||
|
lang: en
|
||||||
|
---
|
||||||
|
|
||||||
|
# Microsoft Entra ID
|
||||||
|
|
||||||
|
Entra ID is a standard OpenID Connect provider from f451's point of view —
|
||||||
|
nothing here is Entra-specific in the code, only in the app registration
|
||||||
|
steps below.
|
||||||
|
|
||||||
|
## 1. Register an application
|
||||||
|
|
||||||
|
In the Entra admin center, create a new **app registration**:
|
||||||
|
|
||||||
|
- **Single tenant** (unless you specifically need multi-tenant sign-in).
|
||||||
|
- **Redirect URI**, platform *Web*: `https://<host>/auth/callback` — this
|
||||||
|
must match `F451_OIDC_REDIRECT_URL` exactly, including scheme and any
|
||||||
|
trailing slash.
|
||||||
|
- Under **Certificates & secrets**, create a **client secret**.
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> Client secrets expire. Note the expiry date somewhere your team actually
|
||||||
|
> looks (a calendar reminder, not just the Entra portal) — an expired
|
||||||
|
> secret takes sign-in down for everyone until it is rotated. Rotating it
|
||||||
|
> means generating a new secret in Entra and updating
|
||||||
|
> `F451_OIDC_CLIENT_SECRET`, then restarting the `api` service.
|
||||||
|
|
||||||
|
## 2. Configure the ID token claims
|
||||||
|
|
||||||
|
Recommended: add the optional claim **`email`** to the ID token (**Token
|
||||||
|
configuration** → **Add optional claim** → ID). f451 reads the user's
|
||||||
|
email from the `email` claim, falling back to `preferred_username` or
|
||||||
|
`upn` if either of those looks like an email address (contains `@`).
|
||||||
|
Without a usable email claim, sign-in still works, but the identity f451
|
||||||
|
records for that person is less predictable.
|
||||||
|
|
||||||
|
## 3. Restrict who may sign in
|
||||||
|
|
||||||
|
By default, anyone in the tenant with access to the app can sign in. To
|
||||||
|
restrict that, open the **enterprise application** for this app
|
||||||
|
registration and turn on **Assignment required** under **Properties**,
|
||||||
|
then assign the users or groups who should have access under **Users and
|
||||||
|
groups**. This is the only access control at the sign-in layer — it does
|
||||||
|
not grant access to any space; that still comes from the person's Forgejo
|
||||||
|
or GitHub permissions (see [[sign-in-options]]).
|
||||||
|
|
||||||
|
## 4. Configure f451
|
||||||
|
|
||||||
|
Set on the `api` service:
|
||||||
|
|
||||||
|
| Variable | Value |
|
||||||
|
|---|---|
|
||||||
|
| `F451_OIDC_ISSUER` | `https://login.microsoftonline.com/<tenant-id>/v2.0` |
|
||||||
|
| `F451_OIDC_CLIENT_ID` | the app registration's Application (client) ID |
|
||||||
|
| `F451_OIDC_CLIENT_SECRET` | the client secret from step 1 |
|
||||||
|
| `F451_OIDC_REDIRECT_URL` | `https://<host>/auth/callback` |
|
||||||
|
| `F451_TOKEN_KEY` | 32 random bytes, base64-encoded (`openssl rand -base64 32`) — encrypts stored provider tokens, independent of Entra |
|
||||||
|
| `F451_OIDC_PROVIDER_NAME` | optional, e.g. `Microsoft Entra` — labels the sign-in button "Sign in with Microsoft Entra"; unset shows a plain "Sign in" |
|
||||||
|
|
||||||
|
f451 requests the scopes `openid email profile` — no Entra-side API
|
||||||
|
permissions need to be granted beyond what a standard app registration
|
||||||
|
gets by default.
|
||||||
|
|
||||||
|
## Forgejo can use Entra too
|
||||||
|
|
||||||
|
If your Forgejo instance should show the same people as f451 without a
|
||||||
|
separate identity system, configure Entra as an **authentication source**
|
||||||
|
in Forgejo itself (Forgejo admin panel → Authentication Sources → add an
|
||||||
|
OAuth2/OIDC source pointed at the same Entra app, or a dedicated one).
|
||||||
|
Users then still take the one extra step of linking their Forgejo account
|
||||||
|
under **Settings → Connections** in f451 — Entra authenticating both
|
||||||
|
systems does not by itself connect them. See
|
||||||
|
[[forgejo-identity-provider]] for the setup that removes even that step.
|
||||||
67
forgejo-identity-provider/index.md
Normal file
67
forgejo-identity-provider/index.md
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
---
|
||||||
|
id: forgejo-identity-provider
|
||||||
|
title: Forgejo as the identity provider
|
||||||
|
description: Using the bundled Forgejo's built-in OIDC provider for sign-in, and linking accounts in one step.
|
||||||
|
tags: [admin, auth, forgejo]
|
||||||
|
lang: en
|
||||||
|
---
|
||||||
|
|
||||||
|
# Forgejo as the identity provider
|
||||||
|
|
||||||
|
Forgejo ships a built-in OpenID Connect provider
|
||||||
|
(`/.well-known/openid-configuration`). f451 can point its one configured
|
||||||
|
OIDC issuer at it instead of an external identity provider — useful for
|
||||||
|
local development, and viable for production if Forgejo is already your
|
||||||
|
single source of identity (see [[entra-id]] for federating Forgejo's own
|
||||||
|
accounts to Entra, so user management still lives in one place).
|
||||||
|
|
||||||
|
## Create the OAuth2 application in Forgejo
|
||||||
|
|
||||||
|
In Forgejo, as an administrator (or as the account that should own the
|
||||||
|
app): **Settings → Applications → OAuth2 Applications**, create a new
|
||||||
|
application with redirect URI `https://<host>/auth/callback`. Forgejo
|
||||||
|
gives you a **Client ID** and **Client Secret** — set these as
|
||||||
|
`F451_OIDC_CLIENT_ID` / `F451_OIDC_CLIENT_SECRET`, and set
|
||||||
|
`F451_OIDC_ISSUER` to the Forgejo instance's base URL.
|
||||||
|
|
||||||
|
## The one-app trick: sign-in and account linking together
|
||||||
|
|
||||||
|
Normally, signing in and connecting a Forgejo account (for reading and
|
||||||
|
writing spaces, see [[sign-in-options]]) are two separate steps: sign in
|
||||||
|
via whatever OIDC provider is configured, then separately connect Forgejo
|
||||||
|
under **Settings → Connections**.
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> If f451's OIDC client (`F451_OIDC_CLIENT_ID`/`_SECRET`) and the Forgejo
|
||||||
|
> account-linking connection (`F451_FORGEJO_OAUTH_CLIENT_ID`/`_SECRET`)
|
||||||
|
> point at the **same** Forgejo OAuth2 application, the first sign-in
|
||||||
|
> already links the Forgejo account — there is no second step. This is
|
||||||
|
> exactly the setup `scripts/dev-local-setup.sh` creates for local
|
||||||
|
> development.
|
||||||
|
|
||||||
|
Using two different Forgejo OAuth2 applications for the two purposes also
|
||||||
|
works — it just means a person signs in, then still has to connect Forgejo
|
||||||
|
separately before they see any space.
|
||||||
|
|
||||||
|
## User management lives in Forgejo
|
||||||
|
|
||||||
|
Once Forgejo is the identity source, account lifecycle — creating
|
||||||
|
accounts, password resets, two-factor authentication, or federating a
|
||||||
|
further upstream source like LDAP — happens entirely in Forgejo's own
|
||||||
|
admin panel. f451 does not duplicate any of it; it only consumes the
|
||||||
|
resulting OIDC identity.
|
||||||
|
|
||||||
|
## Local-only settings
|
||||||
|
|
||||||
|
Running Forgejo as the identity provider over plain HTTP (typical for
|
||||||
|
local development) needs two additional variables on the `api` service:
|
||||||
|
|
||||||
|
| Variable | Effect |
|
||||||
|
|---|---|
|
||||||
|
| `F451_INSECURE_COOKIES=1` | Drops the `secure` flag on session cookies so they survive over HTTP. |
|
||||||
|
| `F451_OIDC_ALLOW_INSECURE=1` | Allows an `http://` issuer during OIDC discovery. |
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> Both are for local HTTP development only. Never set either in
|
||||||
|
> production — a production Entra issuer only ever speaks HTTPS anyway, so
|
||||||
|
> there is nothing to gain and a cookie without `secure` to lose.
|
||||||
48
github-sign-in/index.md
Normal file
48
github-sign-in/index.md
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
---
|
||||||
|
id: github-sign-in
|
||||||
|
title: GitHub sign-in
|
||||||
|
description: Enabling GitHub as a sign-in method, independent of or alongside OIDC.
|
||||||
|
tags: [admin, auth, github]
|
||||||
|
lang: en
|
||||||
|
---
|
||||||
|
|
||||||
|
# GitHub sign-in
|
||||||
|
|
||||||
|
GitHub can be enabled as its own sign-in method, separate from the single
|
||||||
|
configured OIDC provider (see [[sign-in-options]]). It works whether or
|
||||||
|
not an OIDC provider is configured at all.
|
||||||
|
|
||||||
|
## Enable it
|
||||||
|
|
||||||
|
| Variable | Effect |
|
||||||
|
|---|---|
|
||||||
|
| `F451_GITHUB_LOGIN` | Set to `1` to turn on "Sign in with GitHub". |
|
||||||
|
| `F451_GITHUB_OAUTH_CLIENT_ID` | Client ID of a GitHub OAuth app. |
|
||||||
|
| `F451_GITHUB_OAUTH_CLIENT_SECRET` | Client secret of the same app. |
|
||||||
|
|
||||||
|
## Register the OAuth app on GitHub
|
||||||
|
|
||||||
|
Under `https://github.com/settings/developers`, create an **OAuth App**
|
||||||
|
with **Authorization callback URL** set to `https://<host>/auth/`. Use
|
||||||
|
exactly that path, not a more specific one — it must cover both
|
||||||
|
`/auth/github/callback` (sign-in) and `/auth/connect/github/callback`
|
||||||
|
(account linking, used when GitHub is only being connected rather than
|
||||||
|
signed in with).
|
||||||
|
|
||||||
|
## Sign-in also links the account
|
||||||
|
|
||||||
|
Signing in with GitHub links the GitHub account in the same step — there
|
||||||
|
is no separate "connect GitHub" action needed afterwards, unlike signing
|
||||||
|
in through OIDC and connecting a Git account separately (see
|
||||||
|
[[sign-in-options]]).
|
||||||
|
|
||||||
|
## One person, two users
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> f451 has no concept of "the same person across sign-in methods." Someone
|
||||||
|
> who signs in once via your OIDC provider and once via GitHub becomes
|
||||||
|
> **two** separate f451 users — with separate sessions and separate sets of
|
||||||
|
> connected accounts. This is rarely a problem in practice (most people use
|
||||||
|
> one method consistently), but worth knowing before you enable a second
|
||||||
|
> method for a team that already uses the first: tell people to pick one
|
||||||
|
> method and stick with it, rather than discovering the split themselves.
|
||||||
46
index.md
Normal file
46
index.md
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
---
|
||||||
|
id: admin-home
|
||||||
|
title: Admin Guide
|
||||||
|
description: Deploying and running f451 — sign-in setup, spaces, configuration, backup, and day-to-day operations.
|
||||||
|
tags: [admin, guide]
|
||||||
|
lang: en
|
||||||
|
---
|
||||||
|
|
||||||
|
# Admin Guide
|
||||||
|
|
||||||
|
f451 is git-native: every space is a repository on Forgejo or GitHub, every
|
||||||
|
page a Markdown file in it. Postgres holds only a derived index (rendered
|
||||||
|
content, search vectors, graph edges) plus sessions and encrypted provider
|
||||||
|
tokens — nothing that lives exclusively in the database is irreplaceable.
|
||||||
|
That single fact shapes most of the operational decisions in this guide,
|
||||||
|
especially backup and restore.
|
||||||
|
|
||||||
|
This guide is for the people who deploy and run an instance, not for people
|
||||||
|
writing pages in it — for that, see the User Guide space.
|
||||||
|
|
||||||
|
## How this guide is organised
|
||||||
|
|
||||||
|
- [[sign-in-options]] — the identity providers f451 supports, and why there
|
||||||
|
are no local accounts
|
||||||
|
- [[entra-id]] — step-by-step setup with Microsoft Entra ID
|
||||||
|
- [[forgejo-identity-provider]] — using the bundled Forgejo as the identity
|
||||||
|
source, and linking accounts in one step
|
||||||
|
- [[github-sign-in]] — enabling GitHub as a sign-in method
|
||||||
|
- [[spaces-and-git-providers]] — configuring spaces, service tokens,
|
||||||
|
webhooks, and the drift job
|
||||||
|
- [[configuration-reference]] — every environment variable, grouped by
|
||||||
|
concern
|
||||||
|
- [[backup-and-restore]] — what actually needs a backup, and what a reindex
|
||||||
|
rebuilds for you
|
||||||
|
- [[operations]] — health checks, troubleshooting, and running two
|
||||||
|
instances on one host
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> **f451 has no role system of its own.** Who may sign in is decided by
|
||||||
|
> your identity provider; what a signed-in person can see and write is
|
||||||
|
> decided entirely by their linked Git account's permissions on the
|
||||||
|
> repository behind each space. See [[sign-in-options]].
|
||||||
|
|
||||||
|
If you are setting up sign-in for the first time, start with
|
||||||
|
[[sign-in-options]] to decide which provider fits your setup, then follow
|
||||||
|
the matching page.
|
||||||
72
operations/index.md
Normal file
72
operations/index.md
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
---
|
||||||
|
id: operations
|
||||||
|
title: Operations
|
||||||
|
description: Health checks, the admin reindex endpoint, a troubleshooting playbook, and running two instances on one host.
|
||||||
|
tags: [admin, operations, monitoring]
|
||||||
|
lang: en
|
||||||
|
---
|
||||||
|
|
||||||
|
# Operations
|
||||||
|
|
||||||
|
## Health and readiness
|
||||||
|
|
||||||
|
| Endpoint | Meaning |
|
||||||
|
|---|---|
|
||||||
|
| `GET /healthz` | Always `200` if the process is running — no database access. |
|
||||||
|
| `GET /readyz` | `200` if a query against Postgres succeeds, `503` otherwise. Use this for orchestration readiness probes. |
|
||||||
|
| `GET /admin/status` | Bearer-token-protected (`F451_ADMIN_TOKEN`, see [[configuration-reference]]). Returns in-memory counters (`webhookErrors`, `indexerErrors`, `driftErrors`) and a `since` timestamp. The counters reset on every process restart — treat this as "is something wrong right now", not as a historical audit log. |
|
||||||
|
|
||||||
|
## Triggering a reindex
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST https://<host>/admin/reindex \
|
||||||
|
-H "Authorization: Bearer $F451_ADMIN_TOKEN" \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{}'
|
||||||
|
```
|
||||||
|
|
||||||
|
An empty body reindexes every configured space; `{"space":"<space-id>"}`
|
||||||
|
reindexes just one. The response reports success or failure per space —
|
||||||
|
`200` if at least one space succeeded, `502` only if all of them failed
|
||||||
|
(check `GET /admin/status` and the `api` logs next).
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> If OIDC sign-in is active, `/admin/*` routes need a valid session **in
|
||||||
|
> addition to** the bearer token — a plain `curl` call without a browser
|
||||||
|
> session behind it gets a reproducible `401`. Run admin calls from a
|
||||||
|
> browser context where you are already signed in (developer tools'
|
||||||
|
> network/fetch panel with the session cookie present), not from a bare
|
||||||
|
> terminal.
|
||||||
|
|
||||||
|
## Troubleshooting playbook
|
||||||
|
|
||||||
|
| Symptom | Likely cause |
|
||||||
|
|---|---|
|
||||||
|
| Every API route is reachable without signing in | `F451_OIDC_ISSUER` is unset — auth is intentionally off in that state. |
|
||||||
|
| Sign-in redirects to an error page after the identity provider | `F451_OIDC_REDIRECT_URL` (or the app registration's redirect URI) doesn't match the actual callback URL exactly. |
|
||||||
|
| Every save/publish/release fails with `403` | `F451_PUBLIC_BASE_URL` doesn't match the URL users actually browse to — the CSRF origin check rejects the mismatch. See [[configuration-reference]]. |
|
||||||
|
| A webhook call fails with `401` | `F451_WEBHOOK_SECRET_FORGEJO`/`_GITHUB` doesn't match the secret configured on the repository's webhook. |
|
||||||
|
| A page edited directly in Git takes a few minutes to show up | Expected — the drift job catches up within about 5 minutes if the webhook was missed. See [[spaces-and-git-providers]]. |
|
||||||
|
| `POST /admin/reindex` / `GET /admin/status` returns `503` | `F451_ADMIN_TOKEN` is unset — both endpoints are fail-closed without it. |
|
||||||
|
| `POST /admin/reindex` returns `401` from a plain terminal call | Missing session — see the note above. |
|
||||||
|
| The rate limits seem to apply to "everyone at once" instead of per person | `F451_TRUST_PROXY` is unset or wrong for the real proxy chain — see [[configuration-reference]]. |
|
||||||
|
| The same person appears as two different users | They signed in through two different methods (e.g. OIDC once, GitHub once) — see [[github-sign-in]]. Not a bug, a consequence of having no shared identity across methods. |
|
||||||
|
| A user reports "I don't see any spaces" | Their account is signed in but has no linked Forgejo/GitHub account yet, or that account lacks repository access — see [[sign-in-options]]. |
|
||||||
|
|
||||||
|
## Running a second instance on the same host
|
||||||
|
|
||||||
|
Both the Forgejo stack and the application stack expose their ports and
|
||||||
|
cookie naming as variables, so a second instance (for example a demo or a
|
||||||
|
staging copy) can run alongside the first without conflicting:
|
||||||
|
|
||||||
|
| Variable | What it separates |
|
||||||
|
|---|---|
|
||||||
|
| `F451_COOKIE_PREFIX` | Session cookie names — without a distinct value, two instances sharing a host would overwrite each other's cookies in the browser. |
|
||||||
|
| `F451_WEB_PORT` | Host port for the web UI. |
|
||||||
|
| `F451_DRAWIO_PORT` | Host port for the diagram editor. |
|
||||||
|
| `F451_FORGEJO_HTTP_PORT` / `F451_FORGEJO_SSH_PORT` | Host ports for the second Forgejo instance. |
|
||||||
|
| `F451_FORGEJO_ROOT_URL` | The second Forgejo instance's own public URL. |
|
||||||
|
|
||||||
|
Give the second instance's Git stack its own Compose project name
|
||||||
|
(`docker compose -p <name> ...`) so its containers and volumes don't
|
||||||
|
collide with the first instance's.
|
||||||
60
sign-in-options/index.md
Normal file
60
sign-in-options/index.md
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
---
|
||||||
|
id: sign-in-options
|
||||||
|
title: Sign-in options
|
||||||
|
description: The identity providers f451 supports, how they compare, and why there are no local accounts.
|
||||||
|
tags: [admin, auth]
|
||||||
|
lang: en
|
||||||
|
---
|
||||||
|
|
||||||
|
# Sign-in options
|
||||||
|
|
||||||
|
f451 never stores a password. Every sign-in goes through an external
|
||||||
|
identity provider, and every permission check after that goes through the
|
||||||
|
Git provider behind the space a person is looking at — see *Principles* in the Developer Guide
|
||||||
|
in the developer guide for why that split exists. This page is about the
|
||||||
|
first half: who is allowed to sign in at all.
|
||||||
|
|
||||||
|
## Why no local accounts
|
||||||
|
|
||||||
|
A local account system would need its own password reset, its own
|
||||||
|
lockout policy, its own audit trail — none of which f451 could do better
|
||||||
|
than the identity provider your organisation already runs and already
|
||||||
|
trusts for offboarding. Instead, f451 delegates entirely: one configured
|
||||||
|
OIDC issuer, optionally GitHub as a second method, and permissions that
|
||||||
|
come from the linked Forgejo or GitHub account rather than from anything
|
||||||
|
f451 tracks itself.
|
||||||
|
|
||||||
|
## Comparison
|
||||||
|
|
||||||
|
| Provider | Use case | What f451 needs | Notes |
|
||||||
|
|---|---|---|---|
|
||||||
|
| **Microsoft Entra ID** | Production, organisation-managed identities | `F451_OIDC_ISSUER`/`_CLIENT_ID`/`_CLIENT_SECRET`/`_REDIRECT_URL`, `F451_TOKEN_KEY` | See [[entra-id]]. Sign-in only — reading/writing still needs a separately connected Forgejo or GitHub account, unless Forgejo itself also authenticates against Entra (see next row). |
|
||||||
|
| **Forgejo (bundled)** | Local development, or production where Forgejo is the single identity source | Same OIDC variables, pointed at Forgejo's built-in OIDC provider | See [[forgejo-identity-provider]]. Can also make the *first* sign-in link the Forgejo account automatically. |
|
||||||
|
| **Other OIDC provider** (Keycloak, Authentik, Zitadel, Okta, Google, …) | Any organisation already standardised on a different IdP | Same OIDC variables, pointed at that provider's issuer | Configuration only — f451 speaks standard OpenID Connect, nothing provider-specific. |
|
||||||
|
| **GitHub** | Teams whose spaces already live on GitHub | `F451_GITHUB_LOGIN=1`, `F451_GITHUB_OAUTH_CLIENT_ID`/`_SECRET` | See [[github-sign-in]]. Works with or without an OIDC provider configured; signing in with GitHub also links the GitHub account in the same step. |
|
||||||
|
|
||||||
|
Only one OIDC issuer can be configured at a time — f451 does not offer a
|
||||||
|
picker between several OIDC providers. GitHub sign-in is independent of
|
||||||
|
that and can be enabled alongside it, or on its own.
|
||||||
|
|
||||||
|
## What sign-in does and does not unlock
|
||||||
|
|
||||||
|
Signing in only authenticates *who someone is*. It does not, by itself,
|
||||||
|
grant access to any space's content:
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> **Reading and writing follow the linked Git account, not the sign-in
|
||||||
|
> method.** A person who signs in but never connects a Forgejo or GitHub
|
||||||
|
> account sees no spaces at all — not because f451 hides them, but because
|
||||||
|
> there is no permission to check against.
|
||||||
|
|
||||||
|
See [[spaces-and-git-providers]] for how a space is tied to a repository,
|
||||||
|
and the User Guide's *Getting started* page for what connecting an account
|
||||||
|
looks like for the person doing it.
|
||||||
|
|
||||||
|
## One person, several identities
|
||||||
|
|
||||||
|
Because each sign-in method produces its own identity, a person who signs
|
||||||
|
in once through Entra and once through GitHub becomes **two** separate
|
||||||
|
f451 users, each with its own set of connected Git accounts — see
|
||||||
|
[[github-sign-in]] for the practical consequence of that.
|
||||||
75
spaces-and-git-providers/index.md
Normal file
75
spaces-and-git-providers/index.md
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
---
|
||||||
|
id: spaces-and-git-providers
|
||||||
|
title: Spaces and Git providers
|
||||||
|
description: Configuring which repositories are wiki spaces, service tokens, webhooks, and how the index stays current.
|
||||||
|
tags: [admin, spaces, git]
|
||||||
|
lang: en
|
||||||
|
---
|
||||||
|
|
||||||
|
# Spaces and Git providers
|
||||||
|
|
||||||
|
A space is one repository on Forgejo or GitHub, declared to f451 as one
|
||||||
|
entry in `F451_SPACES` — a JSON array on the `api` service:
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "handbook",
|
||||||
|
"name": "Handbook",
|
||||||
|
"provider": "forgejo",
|
||||||
|
"owner": "docs",
|
||||||
|
"repo": "handbook",
|
||||||
|
"defaultLang": "en"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Without `F451_SPACES` set, the API starts in a minimal mode: only
|
||||||
|
`/healthz` and `/readyz` respond, and no space is visible at all.
|
||||||
|
|
||||||
|
## Service tokens are for indexing, not for user access
|
||||||
|
|
||||||
|
Each provider used by at least one space needs a service-account token:
|
||||||
|
|
||||||
|
| Variable | Used for |
|
||||||
|
|---|---|
|
||||||
|
| `F451_FORGEJO_URL` | Base URL of the Forgejo instance (no `/api/v1`). Also the one source for the service-account registry, the write-permission check, and — if Forgejo doubles as identity provider — the OIDC issuer. |
|
||||||
|
| `F451_FORGEJO_TOKEN` | Service-account token Forgejo spaces are indexed with. |
|
||||||
|
| `F451_GITHUB_TOKEN` | Service-account token GitHub spaces are indexed with. |
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> These tokens exist purely so the indexer can *read* repository content to
|
||||||
|
> build the search index and page tree. They are never used to write on a
|
||||||
|
> user's behalf — every write is committed with the writer's own linked
|
||||||
|
> provider token (see [[sign-in-options]]). A misconfigured or missing
|
||||||
|
> service token breaks indexing for that provider's spaces, not writing.
|
||||||
|
|
||||||
|
## Webhooks keep the index current
|
||||||
|
|
||||||
|
Configure a webhook in each space's repository pointing at f451, and set a
|
||||||
|
matching secret on the `api` service so f451 can verify it:
|
||||||
|
|
||||||
|
| Variable | Effect |
|
||||||
|
|---|---|
|
||||||
|
| `F451_WEBHOOK_SECRET_FORGEJO` | HMAC secret for Forgejo webhooks. Must match the secret entered when creating the webhook in the Forgejo repository. |
|
||||||
|
| `F451_WEBHOOK_SECRET_GITHUB` | Same, for GitHub webhooks. |
|
||||||
|
|
||||||
|
Without the matching secret set, every webhook signature check fails
|
||||||
|
(`401`) and pushes never trigger an incremental reindex — see
|
||||||
|
[[operations]] for how that shows up and how it self-heals.
|
||||||
|
|
||||||
|
## The drift job is the safety net
|
||||||
|
|
||||||
|
A background job compares each space's current `main` HEAD against the
|
||||||
|
last fully indexed commit every 5 minutes, and triggers a full reindex on
|
||||||
|
a mismatch. This means a webhook that never arrives — a firewall rule, a
|
||||||
|
wrong secret, a Git provider outage — is not a lasting problem: the index
|
||||||
|
catches up on its own within 5 minutes, no manual action required. See
|
||||||
|
[[operations]] for how to observe this happening.
|
||||||
|
|
||||||
|
## Templates across spaces
|
||||||
|
|
||||||
|
`F451_GLOBAL_TEMPLATES` optionally names one more repository
|
||||||
|
(`{"provider","owner","repo"}`, same shape as an `F451_SPACES` entry) that
|
||||||
|
supplies templates available to every space, in addition to a space's own
|
||||||
|
`_templates/*.md`.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue