A Helm chart for deploying a Matrix homeserver stack on Kubernetes.
See the README.md for docs auto-generated from the values.yaml.
Read through the parameters and modify them locally before installing the chart:
# add the helm repo locally helm repo add matrix https://small-hack.github.io/matrix-chart # downloads the values.yaml locally helm show values matrix/matrix > values.yaml # You should then edit the values.yaml to your liking. ## NOTE: The most important helm parameter is matrix.hostname ## without it, this chart may not work! # install the chart helm install my-release-name matrix/matrix --values values.yamlImportant
The most important helm parameter is matrix.hostname. Without it, this chart may not work!**
Warning
This chart used to support the Sliding Sync Proxy, but as it is deprecated, we no longer support it. See this matrix blog post for more info.
- Latest version of Synapse (the official matrix homeserver)
- Ingress definitions for federated Synapse (aka Matrix homeserver) and Element (default client for matrix)
- Use existing Persistent Volume Claims
- Use existing Kubernetes Secrets for confidential data, such as passwords
- Use OIDC configs for SSO either directly via Synapse (see docs for more info) or via MAS
- Use MAS (matrix-org/matrix-authentication-service) via matrix-authentication-service-chart as a sub chart for using element-x which recommends for OIDC auth
- Latest version of the Element web app to provide a web interface for chat (you can disable this and still use element apps)
- Use s3 to store media using element-hq/synapse-s3-storage-provider
- small-hack/matrix-alertmanager - Prometheus Alertmanager bridge for syncing between matrix and Alertmanager
These features still need to be tested, but are technically baked into the chart from the fork or from previous versions of this chart:
- mautrix/discord - Discord bridge for syncing between matrix and Discord (we no longer test this directly but we're open to PRs to improve support!)
- Coturn TURN server subchart for VoIP calls (may not be needed in Matrix 2.0 API)
- Use of lightweight Exim relay
- matrix-org/matrix-appservice-irc IRC bridge
- tulir/mautrix-whatsapp WhatsApp bridge (we may deprecate this feature in the future, as to not support Big Tech)
- Databases
- Ingress
- Federation
- Notes on using MAS (Matrix Authentication Service)
- Bridges
- About and Status
You must select one of the following options:
- Use the Bitnami PostgreSQL subchart (set
postgresql.enabledtotrue) - Use your own external database, which can also be PostgreSQL. (set
externalDatabase.enabledtotrue)
Note
You cannot enable both externalDatabase and postgresql. You must select one.
A previous version of this chart supported using the synapse.ingress.host parameter. This option has been removed. You must now set a synapse.ingress.hosts. Because of this, you must now also set matrix.hostname or certain functionality will not work. Example of how to setup ingress and hostname:
matrix: # used for setting up config files that require your homeserver hostname # such as bridging between your matrix homeserver (synapse) and other services # such as discord or WhatsApp hostname: my-synapse-hostname.com synapse: ingress: className: "nginx" annotations: # required for TLS certs issued by cert-manager cert-manager.io/cluster-issuer: letsencrypt-staging # -- This annotation is required for the Nginx ingress provider. You can # remove it if you use a different ingress provider nginx.ingress.kubernetes.io/configuration-snippet: | proxy_intercept_errors off; hosts: - host: "my-synapse-hostname.com" paths: - path: / pathType: ImplementationSpecific # if mas.enabled is set to true, you want pathType for / to be Prefix # pathType: Prefix # if mas.enabled is set to true, you want to uncomment the following: # - path: "/_matrix/client/(r0|v3)/(refresh|login|logout).*" # pathType: ImplementationSpecific # backend: # service: # value: release-name-mas # port: # name: http # -- enable tls for synapse ingress tls: - secretName: "matrix-tls" hosts: - my-synapse-hostnameThis can be broken for a number of reasons, and some of them are listed in the official synapse docs, but one that was persistent for the devs here was constantly getting a 401 when testing.
I managed to finally get past that by adding the following to my values.yaml:
matrix: hostname: my-synapse-hostname.com federation: enabled: true synapse: ingress: # replace matrix.mydomain.com with your actual matrix domain nginx.ingress.kubernetes.io/configuration-snippet: | location /.well-known/matrix/server { return 200 '{"m.server": "matrix.mydomain.com:443"}'; add_header Content-Type application/json; }Note
By the way, you can test by going to https://federationtester.matrix.org/api/report?server_name=matrix.mydomain.com where matrix.mydomain.com is replaced by your synapse server.
Later on, I realized I could also use serve_server_wellknown in the synapse config, so I've added it to the Chart's parameters and you can use it like this in your values.yaml:
matrix: hostname: my-synapse-hostname.com federation: enabled: true serve_server_wellknown: trueIf you'd like to get your trusted_key_servers from an existing Kubernetes Secret, you can do so with an in-line yaml block. Here's an example values.yaml:
matrix: hostname: my-synapse-hostname.com federation: enabled: true security: trustedKeyServersExistingSecret: "trusted-key-servers" trustedKeyServersSecretKey: "trustedKeyServers"Here's an example Kubernetes Secret using in-line YAML (NOTE the trusted_key_servers):
apiVersion: v1 kind: Secret metadata: name: trusted-key-servers namespace: matrix type: Opaque stringData: # friend.com is the matrix server you'd like to federate with :) trustedKeyServers: |- trusted_key_servers: - server_name: friend.com verify_keys: ed25519:auto: abcdefghijklmnopqrstuvwxyz1234567890MAS is currently the only way to use OIDC with element-x. If you're using MAS (Matrix Authentication Service), you'll need to set mas.enabled to true. You'll also need to setup proper routes for synapse to redirect to MAS. See example below:
matrix: hostname: my-synapse-hostname.com experimental_features: msc3861: # Likely needed if using OIDC on synapse and you want to allow usage of Element-X (the beta of element) enabled: true # -- Synapse will call `{issuer}/.well-known/openid-configuration` to get the OIDC configuration issuer: http://my-mas-domain.com/ # -- Matches the `mas.mas.client_id` in the auth service config client_id: 0000000000000000000SYNAPSE # -- Matches the `mas.mas.client_auth_method` in the auth service config client_auth_method: client_secret_basic # -- Matches the `mas.mas.clients.client_secret` in the auth service config client_secret: "SomeRandomSecret" # -- Matches the `mas.mas.matrix.secret` in the auth service config admin_token: "special-secret-for-msc3861" # -- URL to advertise to clients where users can self-manage their account account_management_url: "https://my-mas-domain.com/account" synapse: enabled: true ingress: enabled: true className: "nginx" annotations: # you need for the routing to work properly nginx.ingress.kubernetes.io/use-regex: "true" # -- This annotation is required for the Nginx ingress provider. You can # remove it if you use a different ingress provider nginx.ingress.kubernetes.io/configuration-snippet: | proxy_intercept_errors off; # -- required for TLS certs issued by cert-manager cert-manager.io/cluster-issuer: letsencrypt-staging hosts: - host: 'my-synapse-hostname.com' paths: - path: "/_matrix/client/(r0|v3)/(refresh|login|logout).*" pathType: ImplementationSpecific backend: service: # this assumes you passed in mas.fullnameOverride="mas" name: mas port: name: http - path: / pathType: Prefix tls: - secretName: matrix-tls hosts: - 'my-synapse-hostname.com' mas: enabled: true # sets all MAS resources to be called mas fullnameOverride: "mas" postgresql: enabled: true ingress: enabled: true className: "nginx" annotations: cert-manager.io/cluster-issuer: 'letsencrypt-prod' hosts: - host: 'my-mas-domain.com' paths: - path: / pathType: Prefix tls: - secretName: matrix-authentication-service-tls hosts: - 'my-mas-domain.com' # templates out the Matrix Authentication Service config file mas: database: # if blank, this can be autogenerated from mas.postgres or mas.externalDatabase # settings, or you set this to a valid postgres URI # https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING-URIS uri: "" http: # -- Public URL base used when building absolute public URLs public_base: "https://my-mas-domain.com/" # List of HTTP listeners, see below listeners: # The name of the listener, used in logs and metrics - name: web # List of resources to serve resources: - name: discovery - name: human - name: oauth - name: compat - name: graphql - name: assets binds: - host: 0.0.0.0 port: 8080 policy: client_registration: # don't require URIs to be on the same host. default: false allow_host_mismatch: true # allow non-SSL and localhost URIs. default: false allow_insecure_uris: true # this is mostly ignored in favor of the above masClientSecret variable clients: - client_id: "0000000000000000000SYNAPSE" client_auth_method: client_secret_basic client_secret: "SomeRandomSecret" matrix: homeserver: "my-synapse-hostname.com" endpoint: "https://my-synapse-hostname.com" secret: "special-secret-for-msc3861" upstream_oauth2: existingSecret: "synapse-oidc" secretKeys: # -- key in secret with the issuer issuer: "issuer" # -- key in secret with the client_id client_id: "client_id" # -- key in secret with the client_secret client_secret: "client_secret" # this below example is compatible with zitadel providers: # -- A unique identifier (ULID) for the provider: https://www.ulidtools.com # in the valid redirect uris, you want to use this id - id: "01HYZ2G7QS9P2BHSDS94F3GR80" issuer: https://example-zitadel-domain.com/ client_id: "idgenreatedbyyourupstreamoidcprovider" client_secret: "secretgenreatedbyyourupstreamoidcprovider" token_endpoint_auth_method: client_secret_basic claims_imports: subject: template: "{{ user.sub }}" localpart: action: require template: "{{ user.preferred_username }}" displayname: action: suggest template: "{{ user.name }}" email: action: suggest template: "{{ user.email }}" set_email_verification: alwaysWe've only recently started adding/testing bridges to this stack, so there may be some bugs, but so far, we've got the discord bridge upgraded. The rest of the bridges are in a beta/alpha state and although we want to support them, we haven't had the time to test them out since the major fork. If you find something wrong with them, please feel free to submit an Issue or Pull Request.
So far we've tested and gotten working two bots/bridges: Alertmanager and Discord. We wanted to get hookshot working, but try as we might, we could never get the bot to respond to queries in a matrix chat.
Check out the upstream repo for more info (especially .env.default), but here's the gist for configuring it via this chart.
bridges: alertmanager: enabled: false existingSecret: # -- optional secret to replace the entire registration.yaml registration: "" # this section is for registering the application service with matrix # read more about application services here: # https://spec.matrix.org/v1.11/application-service-api/ registration: # -- url of the alertmanager service. if not provided, we will template it # for you like http://matrix-alertmanager-service:3000 url: "" # A secret token that the application service will use to authenticate # requests to the homeserver. as_token: "" # -- Use an existing Kubernetes Secret to store your own generated appservice # and homeserver tokens. If this is not set, we'll generate them for you. # Setting this won't override the ENTIRE registration.yaml we generate for # the synapse pod to authenticate mautrix/discord. It will only replaces the tokens. # To replaces the ENTIRE registration.yaml, use # bridges.alertmanager.existingSecret.registration existingSecret: "" existingSecretKeys: # -- key in existingSecret for as_token (application service token). If # provided and existingSecret is set, ignores bridges.alertmanager.registration.as_token as_token: "as_token" # -- key in existingSecret for hs_token (home server token) hs_token: "hs_token" encryption: false config: # -- secret key for the alertmanager webhook config URL app_alertmanager_secret: "" # -- your homeserver url, e.g. https://homeserver.tld homeserver_url: "" bot: # -- optional: display name to set for the bot user display_name: "" # -- optional: mxc:// avatar to set for the bot user avatar_url: "" # -- rooms to send alerts to, separated by a | # Each entry contains the receiver name (from alertmanager) and the # internal id (not the public alias) of the Matrix channel to forward to. # example: reciever1/!789fhdsauoh48:mymatrix.hostname.com rooms: "" # -- Set this to true to make firing alerts do a `@room` mention. # NOTE! Bot should also have enough power in the room for this to be useful. mention_room: false # -- set to enable Grafana links, e.g. https://grafana.example.com grafana_url: "" # -- grafana data source, e.g. default grafana_datasource: "" # -- set to enable silence link, e.g. https://alertmanager.example.com alertmanager_url: ""We previously had the halfshot/discord bridge as a part of this stack, but as of July 2024 the image was no longer being updated and hadn't been updated in 3 years, see: #589 for more info. Instead we now offer the mautrix/discord bridge. You can read their docs here.
Here's how we got it mostly working on our end via the values.yaml:
matrix: hostname: my-synapse-hostname.com bridges: discord_mautrix: enabled: true # this just keeps the replicasets from getting # out of control, feel free to set to 10 to # keep more history for rollbacks revisionHistoryLimit: 1 # -- extra volumes for the mautrix/discord deployment # we created this separately from the chart extraVolumes: - name: sqllite persistentVolumeClaim: claimName: mautrix-discord-bridge-sqlite extraVolumeMounts: - name: sqllite mountPath: /sql admin_users: - friend - admin config: # Homeserver details homeserver: address: "https://my-synapse-hostname.com" domain: "my-synapse-hostname.com" appservice: # Database config - we used sqllite because it's easy database: type: sqlite3-fk-wal uri: file:/sql/mautrixdiscord.db?_txlock=immediate bridge: encryption: # -- Allow encryption, work in group chat rooms with e2ee enabled allow: true # -- Default to encryption, force-enable encryption in all portals the bridge creates # This will cause the bridge bot to be in private chats for the encryption to work properly. default: trueExample PVC for the sqllite file to persist:
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mautrix-discord-bridge-sqlite namespace: matrix spec: accessModes: - ReadWriteOnce resources: requests: storage: 2Gi storageClassName: local-pathAfter you set this up, you'll still need to authenticate the matrix bot (mautrix/discord) with your Discord bot. For that, you'll need to follow the instructions in the mautrix discord docs.
This is a fork of Arkaniad/matrix-chart, which is a fork of typokign/matrix-chart. We recently transferred this chart from @jessebot to the small-hack org to help with maintanence longterm :) Working on full stability, but always happy to receive GitHub Issues or PRs! Please star the repo if you like our work 💙
Our goal is to provide regular updates using renovatebot and provide some level of basic security from a k8s perspective. We're also trying to standardize the chart more by following predictable values.yaml patterns.