matrix
Matrix (Element Server Suite) — Synapse homeserver, MAS auth with Keycloak OIDC, Element Web/Admin, MatrixRTC/LiveKit SFU with HA defaults
@r8s/matrix
Components (4)
MatrixSSO
import { Platform } from '@r8s/recipes'
import { Matrix } from '@r8s/matrix'
export default (
<Platform secrets={{ backend: 'openbao', mount: 'kv', path: 'matrix' }}>
<Matrix
domain="example.com"
sso={{ issuer: 'https://keycloak.example.com/realms/berget', clientId: 'matrix' }}
database={{
backup: {
destinationPath: 's3://backups/matrix-cnpg',
endpointURL: 'https://s3.example.com',
},
}}
rtc={{ manualIP: '203.0.113.10' }}
appservices={[
{
name: 'hookshot',
registration: {
id: 'hookshot',
as_token: 'PROVIDED_VIA_GITOPS',
hs_token: 'PROVIDED_VIA_GITOPS',
namespaces: { users: [{ regex: '@hookshot:example.com', exclusive: true }] },
url: 'http://hookshot:9000',
},
},
]}
/>
</Platform>
)
issuerstringRequired—Keycloak/OIDC issuer URL (e.g. https://keycloak.example.com/realms/berget)
clientIdstringRequired—OIDC client id registered in the realm
clientSecretRefstringOptional—Name of an existing Secret containing key clientSecret. Required unless a secrets backend (openbao/vault) is configured on the surrounding Platform — the backend then provisions ${name}-keycloak-oidc.
humanNamestringOptional—Display name on the MAS login button (default: 'SSO')
scopestringOptional—OIDC scope (default: 'openid email profile')
MatrixDatabase
import { Platform } from '@r8s/recipes'
import { Matrix } from '@r8s/matrix'
export default (
<Platform secrets={{ backend: 'openbao', mount: 'kv', path: 'matrix' }}>
<Matrix
domain="example.com"
sso={{ issuer: 'https://keycloak.example.com/realms/berget', clientId: 'matrix' }}
database={{
backup: {
destinationPath: 's3://backups/matrix-cnpg',
endpointURL: 'https://s3.example.com',
},
}}
rtc={{ manualIP: '203.0.113.10' }}
appservices={[
{
name: 'hookshot',
registration: {
id: 'hookshot',
as_token: 'PROVIDED_VIA_GITOPS',
hs_token: 'PROVIDED_VIA_GITOPS',
namespaces: { users: [{ regex: '@hookshot:example.com', exclusive: true }] },
url: 'http://hookshot:9000',
},
},
]}
/>
</Platform>
)
replicasnumberOptional—CNPG instances (default: 2)
storagestringOptional—Storage size per database (default: '20Gi')
storageClassstringOptional—StorageClass name (default: cluster default)
backup{ destinationPath: string, endpointURL: string, credentialsSecret?: string, retention?: string, schedule?: string } | nullOptional—Backup configuration — barman object store + scheduled full backups. Set to false to disable. Defaults to off unless specified (explicit opt-in so you can't forget: a disk-full WAL incident is exactly what this prevents).
MatrixRTC
import { Platform } from '@r8s/recipes'
import { Matrix } from '@r8s/matrix'
export default (
<Platform secrets={{ backend: 'openbao', mount: 'kv', path: 'matrix' }}>
<Matrix
domain="example.com"
sso={{ issuer: 'https://keycloak.example.com/realms/berget', clientId: 'matrix' }}
database={{
backup: {
destinationPath: 's3://backups/matrix-cnpg',
endpointURL: 'https://s3.example.com',
},
}}
rtc={{ manualIP: '203.0.113.10' }}
appservices={[
{
name: 'hookshot',
registration: {
id: 'hookshot',
as_token: 'PROVIDED_VIA_GITOPS',
hs_token: 'PROVIDED_VIA_GITOPS',
namespaces: { users: [{ regex: '@hookshot:example.com', exclusive: true }] },
url: 'http://hookshot:9000',
},
},
]}
/>
</Platform>
)
enabledbooleanOptional—Enable MatrixRTC / LiveKit SFU (default: true)
manualIPstringOptional—External IP for the SFU LoadBalancer — LiveKit needs a real IP (not DNS) for ICE. Leave unset to rely on STUN discovery.
turnPortnumberOptional—TURN server port on the combined LoadBalancer (default: 30004, 0 disables)
stunServersstring[]Optional—Extra STUN servers for client NAT traversal
sfuVersionstringOptional—LiveKit image tag (default: v1.10.1 — pinned for the IPv6 ICE URL regression)
Matrix
Matrix — full Element Server Suite: Synapse homeserver, MAS with Keycloak OIDC, Element Web + Admin, MatrixRTC/LiveKit SFU.
import { Platform } from '@r8s/recipes'
import { Matrix } from '@r8s/matrix'
export default (
<Platform secrets={{ backend: 'openbao', mount: 'kv', path: 'matrix' }}>
<Matrix
domain="example.com"
sso={{ issuer: 'https://keycloak.example.com/realms/berget', clientId: 'matrix' }}
database={{
backup: {
destinationPath: 's3://backups/matrix-cnpg',
endpointURL: 'https://s3.example.com',
},
}}
rtc={{ manualIP: '203.0.113.10' }}
appservices={[
{
name: 'hookshot',
registration: {
id: 'hookshot',
as_token: 'PROVIDED_VIA_GITOPS',
hs_token: 'PROVIDED_VIA_GITOPS',
namespaces: { users: [{ regex: '@hookshot:example.com', exclusive: true }] },
url: 'http://hookshot:9000',
},
},
]}
/>
</Platform>
)
namestringOptional—Resource name (defaults to 'matrix')
namespacestringOptional—Kubernetes namespace (inherited from Platform context when omitted)
domainstringRequired—Base domain — derives the five public hosts (see hosts)
hostsPartialOptional—Host overrides. Defaults: web: element.<domain>, synapse: matrix.<domain>, admin: element-admin.<domain>, account: matrix-account.<domain>, rtc: matrix-rtc.<domain>
replicasnumberOptional—Replicas for the stateless web/admin/mas/haproxy-ish layers (default: 2; synapse and SFU stay at 1 until federation workers land)
serverNamestringOptional—Matrix server name — becomes part of user IDs (@user:serverName). Defaults to domain.
ssoMatrixSSOPropsOptional—SSO/OIDC upstream for MAS (Keycloak). Password login disabled when set.
databaseMatrixDatabasePropsOptional—Per-database sizing + backup for synapse-db and mas-db
rtcMatrixRTCPropsOptional—MatrixRTC / LiveKit SFU (Element Call backend)
appservices( | { name: string; registration: Record<string, unknown>; secretRef?: never; key?: never } | { name: string; secretRef: string; key?: string; registration?: never } )[]Optional—Appservice registrations (hookshot, bots…). Each mounts one registration.yaml into Synapse's appservice directory. Two modes per entry: - registration: inline YAML data rendered as a Secret (never a ConfigMap — registrations carry as_token/hs_token). Use placeholders for the tokens and let GitOps fill them, or expect the noPlaintextSecrets guardrail to flag live token values. - secretRef: name of an existing Secret holding registration.yaml (key override via key). Nothing rendered — the preferred mode when the file lives in the secrets backend.
version{ synapse?: string, mas?: string, web?: string, admin?: string, sfu?: string }Optional—Version pinning per component (production: pin these — the defaults are already pinned for known upstream regressions): web: v1.12.15 (MSC4143 Authorization header fix), sfu: v1.10.1 (IPv6 ICE URL fix)
urlPreviewbooleanOptional—Disable the URL-preview SSRF blacklist preset (default: enabled, hardened)