- Rotate the session token at the OIDC callback and restore the full lifetime; cap pre-auth sessions at 15 minutes and write no session for bare anonymous requests - Treat db-dsn as a secret: accept db-dsn-file, log only host, port, database and user, and never echo a malformed DSN in an error - Guard the logout callback with a state cookie so a forged visit cannot end a live session - Collapse FedWiki site actions on a foreign tenant's domain to the not-found answer, as for a domain that does not exist
86 lines
3.3 KiB
Markdown
86 lines
3.3 KiB
Markdown
---
|
|
title: "Hosting member-console"
|
|
audience: [admin]
|
|
summary: "Build the container image and generate the secrets needed to run a member-console instance."
|
|
---
|
|
|
|
# Hosting member-console
|
|
|
|
Operational steps for running your own member-console instance. For how the
|
|
console fits alongside a public site and identity provider, see
|
|
[deployment-architecture.md](deployment-architecture.md); for identity-provider
|
|
configuration, see [identity-provider-setup.md](identity-provider-setup.md).
|
|
|
|
## Building the image
|
|
|
|
The container image is built with Docker Buildx for both ARM64 and AMD64. Tag it
|
|
for your own registry:
|
|
|
|
```bash
|
|
docker buildx build \
|
|
--platform linux/arm64,linux/amd64 \
|
|
-t your-registry.example/your-org/member-console:latest \
|
|
-t your-registry.example/your-org/member-console:$(date +%Y-%m-%d) \
|
|
--push \
|
|
.
|
|
```
|
|
|
|
> The canonical image is published to `git.coopcloud.tech/wiki-cafe/member-console`.
|
|
> Substitute your own registry when self-hosting.
|
|
|
|
## Secrets
|
|
|
|
Three configuration keys are secrets, each with a `-file` variant that reads
|
|
the value from a file at startup (`docs/environment-reference.md`):
|
|
|
|
- `oidc-sp-client-secret` — the OIDC client's secret, issued by the identity
|
|
provider.
|
|
- `valkey-password` — the session store's password. Required; the console
|
|
refuses to start without one.
|
|
- `temporal-oauth-client-secret` — only when Temporal is behind OAuth.
|
|
|
|
None of them is generated by or for the console: each is a credential for
|
|
something external, obtained from that system. Sessions are stored server-side
|
|
in Valkey and carry no signing secret of their own; rotating any of the three
|
|
means updating the deployment's configuration and restarting.
|
|
|
|
## Session store limits
|
|
|
|
Every key member-console writes to the session store carries a TTL: a
|
|
signed-in session lives for the deployment's configured lifetime, and a
|
|
pre-sign-in session, the one `/login` creates to hold the OIDC state, nonce,
|
|
and PKCE verifier, lives fifteen minutes. A bare, unauthenticated request no
|
|
longer writes anything to the store. A flood of `/login` requests still
|
|
writes one short-lived key per request, so the store's memory is still a
|
|
resource a flood can spend.
|
|
|
|
Set `maxmemory` on the Valkey instance to a bound sized for the deployment's
|
|
expected number of concurrent sessions, and set `maxmemory-policy` to
|
|
`volatile-lru`. Under that policy, once the bound is reached, Valkey evicts
|
|
the least recently used session first; that session can belong to a
|
|
signed-in person, and losing it signs them out, so they sign in again.
|
|
`noeviction`, Valkey's default, is worse: once `maxmemory` is reached it
|
|
rejects new writes instead, and a write rejected during `/login` or
|
|
`/callback` turns the flood into failed sign-ins for everyone hitting the
|
|
store, not just whichever session would have been evicted.
|
|
|
|
Rate limit `/login` at the reverse proxy, since the memory bound above
|
|
caps damage but does not stop a flood from reaching the store in the first
|
|
place. With Caddy and the caddy-ratelimit plugin's `rate_limit` directive:
|
|
|
|
```caddyfile
|
|
handle /login* {
|
|
rate_limit {
|
|
zone login {
|
|
key {remote_host}
|
|
events 20
|
|
window 1m
|
|
}
|
|
}
|
|
reverse_proxy member-console:8080
|
|
}
|
|
```
|
|
|
|
Any reverse proxy that can key a limit by client address and scope it to
|
|
one path serves the same purpose.
|