update
diff --git a/charts/matrix/.helmignore b/charts/matrix/.helmignore
new file mode 100644
index 0000000..0e8a0eb
--- /dev/null
+++ b/charts/matrix/.helmignore
@@ -0,0 +1,23 @@
+# Patterns to ignore when building packages.
+# This supports shell glob matching, relative path matching, and
+# negation (prefixed with !). Only one pattern per line.
+.DS_Store
+# Common VCS dirs
+.git/
+.gitignore
+.bzr/
+.bzrignore
+.hg/
+.hgignore
+.svn/
+# Common backup files
+*.swp
+*.bak
+*.tmp
+*.orig
+*~
+# Various IDEs
+.project
+.idea/
+*.tmproj
+.vscode/
diff --git a/charts/matrix/Chart.yaml b/charts/matrix/Chart.yaml
new file mode 100644
index 0000000..51cb744
--- /dev/null
+++ b/charts/matrix/Chart.yaml
@@ -0,0 +1,6 @@
+apiVersion: v2
+name: matrix
+description: A Helm chart for Matrix on PCloud
+type: application
+version: 0.0.1
+appVersion: "0.0.1"
diff --git a/charts/matrix/templates/config-to-merge.yaml b/charts/matrix/templates/config-to-merge.yaml
new file mode 100644
index 0000000..eefe3e3
--- /dev/null
+++ b/charts/matrix/templates/config-to-merge.yaml
@@ -0,0 +1,44 @@
+apiVersion: dodo.cloud.dodo.cloud/v1
+kind: ResourceRenderer
+metadata:
+  name: config-renderer
+  namespace: {{ .Release.Namespace }}
+  annotations:
+    helm.sh/hook: pre-install
+    helm.sh/hook-weight: "-10"
+spec:
+  secretName: {{ .Values.oauth2.secretName }}
+  resourceTemplate: |
+    apiVersion: v1
+    kind: ConfigMap
+    metadata:
+      name: {{ .Values.configMerge.configName }}
+      namespace: {{ .Release.Namespace }}
+    data:
+      {{ .Values.configMerge.fileName }}: |
+        public_baseurl: https://{{ .Values.subdomain }}.{{ .Values.domain }}/
+        enable_registration: false
+        database:
+         name: psycopg2
+         txn_limit: 10000
+         args:
+           host: {{ .Values.postgresql.host }}
+           port: {{ .Values.postgresql.port }}
+           database: {{ .Values.postgresql.database }}
+           user: {{ .Values.postgresql.user }}
+           password: {{ .Values.postgresql.password }}
+           cp_min: 5
+           cp_max: 10
+        oidc_providers:
+          - idp_id: pcloud
+            idp_name: "PCloud"
+            skip_verification: true
+            issuer: {{ .Values.oauth2.issuer }}
+            client_id: "{{`{{ .client_id }}`}}"
+            client_secret: "{{`{{ .client_secret }}`}}"
+            scopes: ["openid", "profile"]
+            allow_existing_users: true
+            user_mapping_provider:
+              config:
+                localpart_template: "{{ cat "{{" "\"" "{{user.username}}" "\"" "}}" | nospace}}"
+                display_name_template: "{{ cat "{{" "\"" "{{user.username}}" "\"" "}}" | nospace}}"
diff --git a/charts/matrix/templates/matrix.yaml b/charts/matrix/templates/matrix.yaml
new file mode 100644
index 0000000..2cbc59a
--- /dev/null
+++ b/charts/matrix/templates/matrix.yaml
@@ -0,0 +1,202 @@
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: CreateConfigMaps
+  namespace: {{ .Release.Namespace }}
+  annotations:
+    helm.sh/hook: pre-install
+    helm.sh/hook-weight: "-10"
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - configmaps
+  verbs:
+  - create
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: default-CreateConfigMaps
+  namespace: {{ .Release.Namespace }}
+  annotations:
+    helm.sh/hook: pre-install
+    helm.sh/hook-weight: "-10"
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: CreateConfigMaps
+subjects:
+- kind: ServiceAccount
+  name: default
+  namespace: {{ .Release.Namespace }}
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: matrix
+  namespace: {{ .Release.Namespace }}
+spec:
+  type: ClusterIP
+  selector:
+    app: matrix
+  ports:
+  - name: http
+    port: 80
+    targetPort: http
+    protocol: TCP
+---
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  name: ingress
+  namespace: {{ .Release.Namespace }}
+  {{- if .Values.certificateIssuer }}
+  annotations:
+    acme.cert-manager.io/http01-edit-in-place: "true"
+    cert-manager.io/cluster-issuer: {{ .Values.certificateIssuer }}
+  {{- end }}
+spec:
+  ingressClassName: {{ .Values.ingressClassName }}
+  tls:
+  - hosts:
+    - {{ .Values.subdomain }}.{{ .Values.domain }}
+    secretName: cert-{{ .Values.subdomain }}.{{ .Values.domain }}
+  rules:
+  - host: {{ .Values.subdomain }}.{{ .Values.domain }}
+    http:
+      paths:
+      - path: /
+        pathType: Prefix
+        backend:
+          service:
+            name: matrix
+            port:
+              name: http
+---
+apiVersion: batch/v1
+kind: Job
+metadata:
+  name: generate-config
+  namespace: {{ .Release.Namespace }}
+  annotations:
+    helm.sh/hook: pre-install
+    helm.sh/hook-weight: "-5"
+spec:
+  template:
+    metadata:
+      labels:
+        app: generate-config
+    spec:
+      restartPolicy: OnFailure
+      volumes:
+      - name: data
+        persistentVolumeClaim:
+          claimName: data
+      - name: config
+        configMap:
+          name: {{ .Values.configMerge.configName }}
+      initContainers:
+      - name: matrix
+        image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
+        imagePullPolicy: {{ .Values.image.pullPolicy }}
+        ports:
+        - name: http
+          containerPort: 8008
+          protocol: TCP
+        env:
+        - name: SYNAPSE_SERVER_NAME
+          value: "{{ .Values.domain }}"
+        - name: SYNAPSE_REPORT_STATS
+          value: "no"
+        - name: SYNAPSE_CONFIG_DIR
+          value: "/data"
+        - name: SYNAPSE_CONFIG_PATH
+          value: "/data/homeserver.yaml"
+        - name: SYNAPSE_DATA_DIR
+          value: "/data"
+        command:
+        - /start.py
+        - generate
+        volumeMounts:
+        - name: data
+          mountPath: /data
+      containers:
+      - name: capture-config
+        image: giolekva/capture-config:latest
+        imagePullPolicy: Always
+        command:
+        - /capture-config
+        - --base=/data/homeserver.yaml
+        - --merge-with=/config-to-merge/{{ .Values.configMerge.fileName }}
+        - --namespace={{ .Release.Namespace }}
+        - --config-map-name=config
+        volumeMounts:
+        - name: data
+          mountPath: /data
+        - name: config
+          mountPath: /config-to-merge
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: matrix
+  namespace: {{ .Release.Namespace }}
+spec:
+  selector:
+    matchLabels:
+      app: matrix
+  replicas: 1
+  template:
+    metadata:
+      labels:
+        app: matrix
+    spec:
+      volumes:
+      - name: data
+        persistentVolumeClaim:
+          claimName: data
+      - name: homeserver-config
+        configMap:
+          name: config
+      containers:
+      - name: matrix
+        image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
+        imagePullPolicy: {{ .Values.image.pullPolicy }}
+        ports:
+        - name: http
+          containerPort: 8008
+          protocol: TCP
+        env:
+        - name: SYNAPSE_SERVER_NAME
+          value: "{{ .Values.domain }}"
+        - name: SYNAPSE_REPORT_STATS
+          value: "no"
+        - name: SYNAPSE_CONFIG_DIR
+          value: "/data"
+        - name: SYNAPSE_CONFIG_PATH
+          value: "/homeserver-config/homeserver.yaml"
+        - name: SYNAPSE_DATA_DIR
+          value: "/data"
+        command: ["/start.py"]
+        volumeMounts:
+        - name: data
+          mountPath: /data
+        - name: homeserver-config
+          mountPath: /homeserver-config
+          readOnly: true
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+  name: data
+  namespace: {{ .Release.Namespace }}
+  annotations:
+    helm.sh/hook: pre-install
+    helm.sh/hook-weight: "-10"
+spec:
+  accessModes:
+    - ReadWriteOnce
+  resources:
+    requests:
+      storage: 10Gi
diff --git a/charts/matrix/templates/well-known.yaml b/charts/matrix/templates/well-known.yaml
new file mode 100644
index 0000000..33e4b94
--- /dev/null
+++ b/charts/matrix/templates/well-known.yaml
@@ -0,0 +1,118 @@
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: well-known
+  namespace: {{ .Release.Namespace }}
+spec:
+  type: ClusterIP
+  selector:
+    app: well-known
+  ports:
+  - name: http
+    port: 80
+    targetPort: http
+    protocol: TCP
+---
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  name: well-known
+  namespace: {{ .Release.Namespace }}
+  {{- if .Values.certificateIssuer }}
+  annotations:
+    acme.cert-manager.io/http01-edit-in-place: "true"
+    cert-manager.io/cluster-issuer: {{ .Values.certificateIssuer }}
+  {{- end }}
+spec:
+  ingressClassName: {{ .Values.ingressClassName }}
+  tls:
+  - hosts:
+    - {{ .Values.domain }}
+    secretName: cert-{{ .Values.domain }}
+  rules:
+  - host: {{ .Values.domain }}
+    http:
+      paths:
+      - path: /.well-known/matrix
+        pathType: ImplementationSpecific
+        backend:
+          service:
+            name: well-known
+            port:
+              name: http
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: well-known
+  namespace: {{ .Release.Namespace }}
+data:
+  nginx.conf: |
+    # user       www www;
+    worker_processes  1;
+    error_log   /dev/null   crit;
+    # pid        logs/nginx.pid;
+    worker_rlimit_nofile 8192;
+    events {
+        worker_connections  1024;
+    }
+    http {
+        server {
+            listen 8080;
+            location /.well-known/matrix/client {
+                return 200 '{"m.homeserver": {"base_url": "https://{{ .Values.subdomain }}.{{ .Values.domain }}"}}';
+                default_type application/json;
+                add_header Access-Control-Allow-Origin *;
+            }
+            location /.well-known/matrix/server {
+                return 200 '{"m.server": "{{ .Values.subdomain }}.{{ .Values.domain }}:443"}';
+                default_type application/json;
+                add_header Access-Control-Allow-Origin *;
+            }
+        }
+    }
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: well-known
+  namespace: {{ .Release.Namespace }}
+spec:
+  selector:
+    matchLabels:
+      app: well-known
+  replicas: 1
+  template:
+    metadata:
+      labels:
+        app: well-known
+    spec:
+      volumes:
+      - name: config
+        configMap:
+          name: well-known
+      containers:
+      - name: nginx
+        image: nginx:1.21.3-alpine
+        imagePullPolicy: IfNotPresent
+        ports:
+        - name: http
+          containerPort: 8080
+          protocol: TCP
+        volumeMounts:
+        - name: config
+          mountPath: /etc/nginx
+          readOnly: true
+        resources:
+          requests:
+            memory: "10Mi"
+            cpu: "10m"
+          limits:
+            memory: "20Mi"
+            cpu: "100m"
+      tolerations:
+      - key: "pcloud"
+        operator: "Equal"
+        value: "role"
+        effect: "NoSchedule"
diff --git a/charts/matrix/values.yaml b/charts/matrix/values.yaml
new file mode 100644
index 0000000..5d57ae0
--- /dev/null
+++ b/charts/matrix/values.yaml
@@ -0,0 +1,20 @@
+image:
+  repository: matrixdotorg/synapse
+  tag: v1.98.0
+  pullPolicy: IfNotPresent
+domain: example.com
+subdomain: matrix
+oauth2:
+  issuer: https://oidc-issuer.example.com
+  secretName: oauth2-client
+postgresql:
+  host: postgresql
+  port: 5432
+  database: synapse
+  user: synapse_user
+  password: password
+certificateIssuer: public
+ingressClassName: nginx
+configMerge:
+  configName: config-to-merge
+  fileName: to-merge.yaml