# Matrix Synapse + Element Web # PostgreSQL 16 + Synapse homeserver + Element Web client # ArgoCD managed - BlueJay Lab --- apiVersion: v1 kind: Namespace metadata: name: matrix labels: app.kubernetes.io/part-of: bluejay-infra --- apiVersion: v1 kind: Secret metadata: name: matrix-db-secret namespace: matrix type: Opaque stringData: POSTGRES_USER: synapse POSTGRES_PASSWORD: BlueJay-Matrix-DB-2026 POSTGRES_DB: synapse POSTGRES_INITDB_ARGS: "--encoding=UTF-8 --lc-collate=C --lc-ctype=C" --- # PostgreSQL 16 StatefulSet apiVersion: apps/v1 kind: StatefulSet metadata: name: matrix-postgres namespace: matrix labels: app: matrix-postgres spec: serviceName: matrix-postgres replicas: 1 selector: matchLabels: app: matrix-postgres template: metadata: labels: app: matrix-postgres spec: containers: - name: postgres image: postgres:16-alpine ports: - containerPort: 5432 name: postgres envFrom: - secretRef: name: matrix-db-secret volumeMounts: - name: matrix-postgres-data mountPath: /var/lib/postgresql/data subPath: pgdata resources: requests: memory: 256Mi cpu: 100m limits: memory: 1Gi cpu: 500m livenessProbe: exec: command: - pg_isready - -U - synapse initialDelaySeconds: 30 periodSeconds: 10 readinessProbe: exec: command: - pg_isready - -U - synapse initialDelaySeconds: 5 periodSeconds: 5 volumeClaimTemplates: - metadata: name: matrix-postgres-data spec: accessModes: [ReadWriteOnce] resources: requests: storage: 5Gi --- apiVersion: v1 kind: Service metadata: name: matrix-postgres namespace: matrix spec: selector: app: matrix-postgres ports: - port: 5432 targetPort: 5432 name: postgres clusterIP: None --- # Synapse Data PVC apiVersion: v1 kind: PersistentVolumeClaim metadata: name: synapse-data namespace: matrix spec: accessModes: [ReadWriteOnce] resources: requests: storage: 2Gi --- # Synapse Homeserver Deployment apiVersion: apps/v1 kind: Deployment metadata: name: synapse namespace: matrix labels: app: synapse spec: replicas: 1 strategy: type: Recreate selector: matchLabels: app: synapse template: metadata: labels: app: synapse spec: containers: - name: synapse image: matrixdotorg/synapse:latest ports: - containerPort: 8008 name: http env: - name: SYNAPSE_SERVER_NAME value: iamworkin.lan - name: SYNAPSE_REPORT_STATS value: "no" - name: SYNAPSE_CONFIG_DIR value: /data - name: SYNAPSE_DATA_DIR value: /data - name: POSTGRES_HOST value: matrix-postgres - name: POSTGRES_PORT value: "5432" - name: POSTGRES_DB valueFrom: secretKeyRef: name: matrix-db-secret key: POSTGRES_DB - name: POSTGRES_USER valueFrom: secretKeyRef: name: matrix-db-secret key: POSTGRES_USER - name: POSTGRES_PASSWORD valueFrom: secretKeyRef: name: matrix-db-secret key: POSTGRES_PASSWORD volumeMounts: - name: synapse-data mountPath: /data resources: requests: memory: 512Mi cpu: 200m limits: memory: 2Gi cpu: "1" livenessProbe: httpGet: path: /health port: 8008 initialDelaySeconds: 60 periodSeconds: 10 readinessProbe: httpGet: path: /health port: 8008 initialDelaySeconds: 30 periodSeconds: 5 volumes: - name: synapse-data persistentVolumeClaim: claimName: synapse-data --- apiVersion: v1 kind: Service metadata: name: synapse namespace: matrix spec: selector: app: synapse ports: - port: 8008 targetPort: 8008 name: http --- # Element Web ConfigMap apiVersion: v1 kind: ConfigMap metadata: name: element-web-config namespace: matrix data: config.json: | { "default_server_config": { "m.homeserver": { "base_url": "https://matrix.iamworkin.lan", "server_name": "iamworkin.lan" } }, "brand": "BlueJay Chat", "disable_guests": true, "disable_3pid_login": true } --- # Element Web Deployment apiVersion: apps/v1 kind: Deployment metadata: name: element-web namespace: matrix labels: app: element-web spec: replicas: 1 selector: matchLabels: app: element-web template: metadata: labels: app: element-web spec: containers: - name: element-web image: vectorim/element-web:latest ports: - containerPort: 80 name: http volumeMounts: - name: element-config mountPath: /app/config.json subPath: config.json resources: requests: memory: 32Mi cpu: 10m limits: memory: 128Mi cpu: 100m livenessProbe: httpGet: path: / port: 80 initialDelaySeconds: 10 periodSeconds: 10 readinessProbe: httpGet: path: / port: 80 initialDelaySeconds: 5 periodSeconds: 5 volumes: - name: element-config configMap: name: element-web-config --- apiVersion: v1 kind: Service metadata: name: element-web namespace: matrix spec: selector: app: element-web ports: - port: 80 targetPort: 80 name: http --- # TLS Certificates via cert-manager apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: matrix-tls namespace: matrix spec: secretName: matrix-tls issuerRef: name: step-ca-acme kind: ClusterIssuer dnsNames: - matrix.iamworkin.lan --- apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: element-tls namespace: matrix spec: secretName: element-tls issuerRef: name: step-ca-acme kind: ClusterIssuer dnsNames: - element.iamworkin.lan --- # Traefik IngressRoute - Synapse apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: synapse namespace: matrix spec: entryPoints: - websecure routes: - match: Host(`matrix.iamworkin.lan`) kind: Rule services: - name: synapse port: 8008 tls: secretName: matrix-tls --- # Traefik IngressRoute - Element Web apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: element-web namespace: matrix spec: entryPoints: - websecure routes: - match: Host(`element.iamworkin.lan`) kind: Rule services: - name: element-web port: 80 tls: secretName: element-tls