feat(selfhosted): unified email — Stalwart, email-oauth2-proxy, imapsync#2441
Open
dapperdivers wants to merge 1 commit intomainfrom
Open
feat(selfhosted): unified email — Stalwart, email-oauth2-proxy, imapsync#2441dapperdivers wants to merge 1 commit intomainfrom
dapperdivers wants to merge 1 commit intomainfrom
Conversation
…mapsync Deploy Stalwart Mail Server as the single IMAP/SMTP endpoint consolidating Gmail, Outlook.com, and Migadu accounts. email-oauth2-proxy handles Outlook XOAUTH2, and imapsync CronJobs pull mail from all three providers. - stalwart: wrenix/stalwart-mail chart v0.4.9, app v0.15.5 RocksDB storage, per-sender SMTP relay, spam threshold 8, LoadBalancer on MAIL_VIP_GATEWAY (10.100.0.30), Authentik ingress - email-oauth2-proxy: app-template, Outlook.com OAuth2→IMAP bridge - imapsync: app-template, 3 CronJob controllers (gmail/outlook/migadu) staggered every 10 min, suspended until secrets + import complete - All secrets via ExternalSecret (Infisical, STALWART_* prefix) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Contributor
--- kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: actions-runner-system/cluster-settings
+++ kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: actions-runner-system/cluster-settings
@@ -4,12 +4,13 @@
CLUSTER_NAME: kubernetes
EMQX_VIP_GATEWAY: 10.100.0.26
ESP_HOME_VIP_GATEWAY: 10.100.0.19
EXTERNAL_VIP_GATEWAY: 10.100.0.22
INTERNAL_VIP_GATEWAY: 10.100.0.20
KUBE_VIP_GATEWAY: 10.100.0.21
+ MAIL_VIP_GATEWAY: 10.100.0.30
NUT_VIP_GATEWAY: 10.100.0.28
PLEX_VIP_GATEWAY: 10.100.0.24
POSTGRESS_VIP_GATEWAY: 10.100.0.25
SMTP_VIP_GATEWAY: 10.100.0.27
TIME_ZONE: America/Chicago
UNIFI_VIP_GATEWAY: 10.100.0.23
--- kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: ai/cluster-settings
+++ kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: ai/cluster-settings
@@ -4,12 +4,13 @@
CLUSTER_NAME: kubernetes
EMQX_VIP_GATEWAY: 10.100.0.26
ESP_HOME_VIP_GATEWAY: 10.100.0.19
EXTERNAL_VIP_GATEWAY: 10.100.0.22
INTERNAL_VIP_GATEWAY: 10.100.0.20
KUBE_VIP_GATEWAY: 10.100.0.21
+ MAIL_VIP_GATEWAY: 10.100.0.30
NUT_VIP_GATEWAY: 10.100.0.28
PLEX_VIP_GATEWAY: 10.100.0.24
POSTGRESS_VIP_GATEWAY: 10.100.0.25
SMTP_VIP_GATEWAY: 10.100.0.27
TIME_ZONE: America/Chicago
UNIFI_VIP_GATEWAY: 10.100.0.23
--- kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: cert-manager/cluster-settings
+++ kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: cert-manager/cluster-settings
@@ -4,12 +4,13 @@
CLUSTER_NAME: kubernetes
EMQX_VIP_GATEWAY: 10.100.0.26
ESP_HOME_VIP_GATEWAY: 10.100.0.19
EXTERNAL_VIP_GATEWAY: 10.100.0.22
INTERNAL_VIP_GATEWAY: 10.100.0.20
KUBE_VIP_GATEWAY: 10.100.0.21
+ MAIL_VIP_GATEWAY: 10.100.0.30
NUT_VIP_GATEWAY: 10.100.0.28
PLEX_VIP_GATEWAY: 10.100.0.24
POSTGRESS_VIP_GATEWAY: 10.100.0.25
SMTP_VIP_GATEWAY: 10.100.0.27
TIME_ZONE: America/Chicago
UNIFI_VIP_GATEWAY: 10.100.0.23
--- kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: database/cluster-settings
+++ kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: database/cluster-settings
@@ -4,12 +4,13 @@
CLUSTER_NAME: kubernetes
EMQX_VIP_GATEWAY: 10.100.0.26
ESP_HOME_VIP_GATEWAY: 10.100.0.19
EXTERNAL_VIP_GATEWAY: 10.100.0.22
INTERNAL_VIP_GATEWAY: 10.100.0.20
KUBE_VIP_GATEWAY: 10.100.0.21
+ MAIL_VIP_GATEWAY: 10.100.0.30
NUT_VIP_GATEWAY: 10.100.0.28
PLEX_VIP_GATEWAY: 10.100.0.24
POSTGRESS_VIP_GATEWAY: 10.100.0.25
SMTP_VIP_GATEWAY: 10.100.0.27
TIME_ZONE: America/Chicago
UNIFI_VIP_GATEWAY: 10.100.0.23
--- kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: default/cluster-settings
+++ kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: default/cluster-settings
@@ -4,12 +4,13 @@
CLUSTER_NAME: kubernetes
EMQX_VIP_GATEWAY: 10.100.0.26
ESP_HOME_VIP_GATEWAY: 10.100.0.19
EXTERNAL_VIP_GATEWAY: 10.100.0.22
INTERNAL_VIP_GATEWAY: 10.100.0.20
KUBE_VIP_GATEWAY: 10.100.0.21
+ MAIL_VIP_GATEWAY: 10.100.0.30
NUT_VIP_GATEWAY: 10.100.0.28
PLEX_VIP_GATEWAY: 10.100.0.24
POSTGRESS_VIP_GATEWAY: 10.100.0.25
SMTP_VIP_GATEWAY: 10.100.0.27
TIME_ZONE: America/Chicago
UNIFI_VIP_GATEWAY: 10.100.0.23
--- kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: external-secrets/cluster-settings
+++ kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: external-secrets/cluster-settings
@@ -4,12 +4,13 @@
CLUSTER_NAME: kubernetes
EMQX_VIP_GATEWAY: 10.100.0.26
ESP_HOME_VIP_GATEWAY: 10.100.0.19
EXTERNAL_VIP_GATEWAY: 10.100.0.22
INTERNAL_VIP_GATEWAY: 10.100.0.20
KUBE_VIP_GATEWAY: 10.100.0.21
+ MAIL_VIP_GATEWAY: 10.100.0.30
NUT_VIP_GATEWAY: 10.100.0.28
PLEX_VIP_GATEWAY: 10.100.0.24
POSTGRESS_VIP_GATEWAY: 10.100.0.25
SMTP_VIP_GATEWAY: 10.100.0.27
TIME_ZONE: America/Chicago
UNIFI_VIP_GATEWAY: 10.100.0.23
--- kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: flux-system/cluster-settings
+++ kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: flux-system/cluster-settings
@@ -4,12 +4,13 @@
CLUSTER_NAME: kubernetes
EMQX_VIP_GATEWAY: 10.100.0.26
ESP_HOME_VIP_GATEWAY: 10.100.0.19
EXTERNAL_VIP_GATEWAY: 10.100.0.22
INTERNAL_VIP_GATEWAY: 10.100.0.20
KUBE_VIP_GATEWAY: 10.100.0.21
+ MAIL_VIP_GATEWAY: 10.100.0.30
NUT_VIP_GATEWAY: 10.100.0.28
PLEX_VIP_GATEWAY: 10.100.0.24
POSTGRESS_VIP_GATEWAY: 10.100.0.25
SMTP_VIP_GATEWAY: 10.100.0.27
TIME_ZONE: America/Chicago
UNIFI_VIP_GATEWAY: 10.100.0.23
--- kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: home-automation/cluster-settings
+++ kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: home-automation/cluster-settings
@@ -4,12 +4,13 @@
CLUSTER_NAME: kubernetes
EMQX_VIP_GATEWAY: 10.100.0.26
ESP_HOME_VIP_GATEWAY: 10.100.0.19
EXTERNAL_VIP_GATEWAY: 10.100.0.22
INTERNAL_VIP_GATEWAY: 10.100.0.20
KUBE_VIP_GATEWAY: 10.100.0.21
+ MAIL_VIP_GATEWAY: 10.100.0.30
NUT_VIP_GATEWAY: 10.100.0.28
PLEX_VIP_GATEWAY: 10.100.0.24
POSTGRESS_VIP_GATEWAY: 10.100.0.25
SMTP_VIP_GATEWAY: 10.100.0.27
TIME_ZONE: America/Chicago
UNIFI_VIP_GATEWAY: 10.100.0.23
--- kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: kube-system/cluster-settings
+++ kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: kube-system/cluster-settings
@@ -4,12 +4,13 @@
CLUSTER_NAME: kubernetes
EMQX_VIP_GATEWAY: 10.100.0.26
ESP_HOME_VIP_GATEWAY: 10.100.0.19
EXTERNAL_VIP_GATEWAY: 10.100.0.22
INTERNAL_VIP_GATEWAY: 10.100.0.20
KUBE_VIP_GATEWAY: 10.100.0.21
+ MAIL_VIP_GATEWAY: 10.100.0.30
NUT_VIP_GATEWAY: 10.100.0.28
PLEX_VIP_GATEWAY: 10.100.0.24
POSTGRESS_VIP_GATEWAY: 10.100.0.25
SMTP_VIP_GATEWAY: 10.100.0.27
TIME_ZONE: America/Chicago
UNIFI_VIP_GATEWAY: 10.100.0.23
--- kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: kyverno/cluster-settings
+++ kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: kyverno/cluster-settings
@@ -4,12 +4,13 @@
CLUSTER_NAME: kubernetes
EMQX_VIP_GATEWAY: 10.100.0.26
ESP_HOME_VIP_GATEWAY: 10.100.0.19
EXTERNAL_VIP_GATEWAY: 10.100.0.22
INTERNAL_VIP_GATEWAY: 10.100.0.20
KUBE_VIP_GATEWAY: 10.100.0.21
+ MAIL_VIP_GATEWAY: 10.100.0.30
NUT_VIP_GATEWAY: 10.100.0.28
PLEX_VIP_GATEWAY: 10.100.0.24
POSTGRESS_VIP_GATEWAY: 10.100.0.25
SMTP_VIP_GATEWAY: 10.100.0.27
TIME_ZONE: America/Chicago
UNIFI_VIP_GATEWAY: 10.100.0.23
--- kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: media/cluster-settings
+++ kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: media/cluster-settings
@@ -4,12 +4,13 @@
CLUSTER_NAME: kubernetes
EMQX_VIP_GATEWAY: 10.100.0.26
ESP_HOME_VIP_GATEWAY: 10.100.0.19
EXTERNAL_VIP_GATEWAY: 10.100.0.22
INTERNAL_VIP_GATEWAY: 10.100.0.20
KUBE_VIP_GATEWAY: 10.100.0.21
+ MAIL_VIP_GATEWAY: 10.100.0.30
NUT_VIP_GATEWAY: 10.100.0.28
PLEX_VIP_GATEWAY: 10.100.0.24
POSTGRESS_VIP_GATEWAY: 10.100.0.25
SMTP_VIP_GATEWAY: 10.100.0.27
TIME_ZONE: America/Chicago
UNIFI_VIP_GATEWAY: 10.100.0.23
--- kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: network/cluster-settings
+++ kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: network/cluster-settings
@@ -4,12 +4,13 @@
CLUSTER_NAME: kubernetes
EMQX_VIP_GATEWAY: 10.100.0.26
ESP_HOME_VIP_GATEWAY: 10.100.0.19
EXTERNAL_VIP_GATEWAY: 10.100.0.22
INTERNAL_VIP_GATEWAY: 10.100.0.20
KUBE_VIP_GATEWAY: 10.100.0.21
+ MAIL_VIP_GATEWAY: 10.100.0.30
NUT_VIP_GATEWAY: 10.100.0.28
PLEX_VIP_GATEWAY: 10.100.0.24
POSTGRESS_VIP_GATEWAY: 10.100.0.25
SMTP_VIP_GATEWAY: 10.100.0.27
TIME_ZONE: America/Chicago
UNIFI_VIP_GATEWAY: 10.100.0.23
--- kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: observability/cluster-settings
+++ kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: observability/cluster-settings
@@ -4,12 +4,13 @@
CLUSTER_NAME: kubernetes
EMQX_VIP_GATEWAY: 10.100.0.26
ESP_HOME_VIP_GATEWAY: 10.100.0.19
EXTERNAL_VIP_GATEWAY: 10.100.0.22
INTERNAL_VIP_GATEWAY: 10.100.0.20
KUBE_VIP_GATEWAY: 10.100.0.21
+ MAIL_VIP_GATEWAY: 10.100.0.30
NUT_VIP_GATEWAY: 10.100.0.28
PLEX_VIP_GATEWAY: 10.100.0.24
POSTGRESS_VIP_GATEWAY: 10.100.0.25
SMTP_VIP_GATEWAY: 10.100.0.27
TIME_ZONE: America/Chicago
UNIFI_VIP_GATEWAY: 10.100.0.23
--- kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: rook-ceph/cluster-settings
+++ kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: rook-ceph/cluster-settings
@@ -4,12 +4,13 @@
CLUSTER_NAME: kubernetes
EMQX_VIP_GATEWAY: 10.100.0.26
ESP_HOME_VIP_GATEWAY: 10.100.0.19
EXTERNAL_VIP_GATEWAY: 10.100.0.22
INTERNAL_VIP_GATEWAY: 10.100.0.20
KUBE_VIP_GATEWAY: 10.100.0.21
+ MAIL_VIP_GATEWAY: 10.100.0.30
NUT_VIP_GATEWAY: 10.100.0.28
PLEX_VIP_GATEWAY: 10.100.0.24
POSTGRESS_VIP_GATEWAY: 10.100.0.25
SMTP_VIP_GATEWAY: 10.100.0.27
TIME_ZONE: America/Chicago
UNIFI_VIP_GATEWAY: 10.100.0.23
--- kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: roundtable/cluster-settings
+++ kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: roundtable/cluster-settings
@@ -4,12 +4,13 @@
CLUSTER_NAME: kubernetes
EMQX_VIP_GATEWAY: 10.100.0.26
ESP_HOME_VIP_GATEWAY: 10.100.0.19
EXTERNAL_VIP_GATEWAY: 10.100.0.22
INTERNAL_VIP_GATEWAY: 10.100.0.20
KUBE_VIP_GATEWAY: 10.100.0.21
+ MAIL_VIP_GATEWAY: 10.100.0.30
NUT_VIP_GATEWAY: 10.100.0.28
PLEX_VIP_GATEWAY: 10.100.0.24
POSTGRESS_VIP_GATEWAY: 10.100.0.25
SMTP_VIP_GATEWAY: 10.100.0.27
TIME_ZONE: America/Chicago
UNIFI_VIP_GATEWAY: 10.100.0.23
--- kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: security/cluster-settings
+++ kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: security/cluster-settings
@@ -4,12 +4,13 @@
CLUSTER_NAME: kubernetes
EMQX_VIP_GATEWAY: 10.100.0.26
ESP_HOME_VIP_GATEWAY: 10.100.0.19
EXTERNAL_VIP_GATEWAY: 10.100.0.22
INTERNAL_VIP_GATEWAY: 10.100.0.20
KUBE_VIP_GATEWAY: 10.100.0.21
+ MAIL_VIP_GATEWAY: 10.100.0.30
NUT_VIP_GATEWAY: 10.100.0.28
PLEX_VIP_GATEWAY: 10.100.0.24
POSTGRESS_VIP_GATEWAY: 10.100.0.25
SMTP_VIP_GATEWAY: 10.100.0.27
TIME_ZONE: America/Chicago
UNIFI_VIP_GATEWAY: 10.100.0.23
--- kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: selfhosted/cluster-settings
+++ kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: selfhosted/cluster-settings
@@ -4,12 +4,13 @@
CLUSTER_NAME: kubernetes
EMQX_VIP_GATEWAY: 10.100.0.26
ESP_HOME_VIP_GATEWAY: 10.100.0.19
EXTERNAL_VIP_GATEWAY: 10.100.0.22
INTERNAL_VIP_GATEWAY: 10.100.0.20
KUBE_VIP_GATEWAY: 10.100.0.21
+ MAIL_VIP_GATEWAY: 10.100.0.30
NUT_VIP_GATEWAY: 10.100.0.28
PLEX_VIP_GATEWAY: 10.100.0.24
POSTGRESS_VIP_GATEWAY: 10.100.0.25
SMTP_VIP_GATEWAY: 10.100.0.27
TIME_ZONE: America/Chicago
UNIFI_VIP_GATEWAY: 10.100.0.23
--- kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: storage/cluster-settings
+++ kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: storage/cluster-settings
@@ -4,12 +4,13 @@
CLUSTER_NAME: kubernetes
EMQX_VIP_GATEWAY: 10.100.0.26
ESP_HOME_VIP_GATEWAY: 10.100.0.19
EXTERNAL_VIP_GATEWAY: 10.100.0.22
INTERNAL_VIP_GATEWAY: 10.100.0.20
KUBE_VIP_GATEWAY: 10.100.0.21
+ MAIL_VIP_GATEWAY: 10.100.0.30
NUT_VIP_GATEWAY: 10.100.0.28
PLEX_VIP_GATEWAY: 10.100.0.24
POSTGRESS_VIP_GATEWAY: 10.100.0.25
SMTP_VIP_GATEWAY: 10.100.0.27
TIME_ZONE: America/Chicago
UNIFI_VIP_GATEWAY: 10.100.0.23
--- kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: system-upgrade/cluster-settings
+++ kubernetes/apps Kustomization: flux-system/cluster-apps ConfigMap: system-upgrade/cluster-settings
@@ -4,12 +4,13 @@
CLUSTER_NAME: kubernetes
EMQX_VIP_GATEWAY: 10.100.0.26
ESP_HOME_VIP_GATEWAY: 10.100.0.19
EXTERNAL_VIP_GATEWAY: 10.100.0.22
INTERNAL_VIP_GATEWAY: 10.100.0.20
KUBE_VIP_GATEWAY: 10.100.0.21
+ MAIL_VIP_GATEWAY: 10.100.0.30
NUT_VIP_GATEWAY: 10.100.0.28
PLEX_VIP_GATEWAY: 10.100.0.24
POSTGRESS_VIP_GATEWAY: 10.100.0.25
SMTP_VIP_GATEWAY: 10.100.0.27
TIME_ZONE: America/Chicago
UNIFI_VIP_GATEWAY: 10.100.0.23
--- kubernetes/apps Kustomization: flux-system/cluster-apps Kustomization: selfhosted/stalwart
+++ kubernetes/apps Kustomization: flux-system/cluster-apps Kustomization: selfhosted/stalwart
@@ -0,0 +1,40 @@
+---
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+ labels:
+ kustomize.toolkit.fluxcd.io/name: cluster-apps
+ kustomize.toolkit.fluxcd.io/namespace: flux-system
+ name: stalwart
+ namespace: selfhosted
+spec:
+ commonMetadata:
+ labels:
+ app.kubernetes.io/name: stalwart
+ decryption:
+ provider: sops
+ secretRef:
+ name: sops-age
+ dependsOn:
+ - name: external-secrets-stores
+ namespace: external-secrets
+ interval: 30m
+ path: ./kubernetes/apps/selfhosted/stalwart/app
+ postBuild:
+ substitute:
+ APP: stalwart
+ substituteFrom:
+ - kind: ConfigMap
+ name: cluster-settings
+ - kind: Secret
+ name: cluster-secrets
+ prune: true
+ retryInterval: 1m
+ sourceRef:
+ kind: GitRepository
+ name: flux-system
+ namespace: flux-system
+ targetNamespace: selfhosted
+ timeout: 10m
+ wait: true
+
--- kubernetes/apps Kustomization: flux-system/cluster-apps Kustomization: selfhosted/email-oauth2-proxy
+++ kubernetes/apps Kustomization: flux-system/cluster-apps Kustomization: selfhosted/email-oauth2-proxy
@@ -0,0 +1,42 @@
+---
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+ labels:
+ kustomize.toolkit.fluxcd.io/name: cluster-apps
+ kustomize.toolkit.fluxcd.io/namespace: flux-system
+ name: email-oauth2-proxy
+ namespace: selfhosted
+spec:
+ commonMetadata:
+ labels:
+ app.kubernetes.io/name: email-oauth2-proxy
+ decryption:
+ provider: sops
+ secretRef:
+ name: sops-age
+ dependsOn:
+ - name: stalwart
+ namespace: selfhosted
+ - name: external-secrets-stores
+ namespace: external-secrets
+ interval: 30m
+ path: ./kubernetes/apps/selfhosted/email-oauth2-proxy/app
+ postBuild:
+ substitute:
+ APP: email-oauth2-proxy
+ substituteFrom:
+ - kind: ConfigMap
+ name: cluster-settings
+ - kind: Secret
+ name: cluster-secrets
+ prune: true
+ retryInterval: 1m
+ sourceRef:
+ kind: GitRepository
+ name: flux-system
+ namespace: flux-system
+ targetNamespace: selfhosted
+ timeout: 5m
+ wait: true
+
--- kubernetes/apps Kustomization: flux-system/cluster-apps Kustomization: selfhosted/imapsync
+++ kubernetes/apps Kustomization: flux-system/cluster-apps Kustomization: selfhosted/imapsync
@@ -0,0 +1,44 @@
+---
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+ labels:
+ kustomize.toolkit.fluxcd.io/name: cluster-apps
+ kustomize.toolkit.fluxcd.io/namespace: flux-system
+ name: imapsync
+ namespace: selfhosted
+spec:
+ commonMetadata:
+ labels:
+ app.kubernetes.io/name: imapsync
+ decryption:
+ provider: sops
+ secretRef:
+ name: sops-age
+ dependsOn:
+ - name: stalwart
+ namespace: selfhosted
+ - name: email-oauth2-proxy
+ namespace: selfhosted
+ - name: external-secrets-stores
+ namespace: external-secrets
+ interval: 30m
+ path: ./kubernetes/apps/selfhosted/imapsync/app
+ postBuild:
+ substitute:
+ APP: imapsync
+ substituteFrom:
+ - kind: ConfigMap
+ name: cluster-settings
+ - kind: Secret
+ name: cluster-secrets
+ prune: true
+ retryInterval: 1m
+ sourceRef:
+ kind: GitRepository
+ name: flux-system
+ namespace: flux-system
+ targetNamespace: selfhosted
+ timeout: 5m
+ wait: false
+
--- kubernetes/apps/selfhosted/gotenberg/app Kustomization: selfhosted/gotenberg ConfigMap: selfhosted/cluster-settings
+++ kubernetes/apps/selfhosted/gotenberg/app Kustomization: selfhosted/gotenberg ConfigMap: selfhosted/cluster-settings
@@ -4,12 +4,13 @@
CLUSTER_NAME: kubernetes
EMQX_VIP_GATEWAY: 10.100.0.26
ESP_HOME_VIP_GATEWAY: 10.100.0.19
EXTERNAL_VIP_GATEWAY: 10.100.0.22
INTERNAL_VIP_GATEWAY: 10.100.0.20
KUBE_VIP_GATEWAY: 10.100.0.21
+ MAIL_VIP_GATEWAY: 10.100.0.30
NUT_VIP_GATEWAY: 10.100.0.28
PLEX_VIP_GATEWAY: 10.100.0.24
POSTGRESS_VIP_GATEWAY: 10.100.0.25
SMTP_VIP_GATEWAY: 10.100.0.27
TIME_ZONE: America/Chicago
UNIFI_VIP_GATEWAY: 10.100.0.23
--- kubernetes/apps/selfhosted/stalwart/app Kustomization: selfhosted/stalwart OCIRepository: selfhosted/stalwart-mail
+++ kubernetes/apps/selfhosted/stalwart/app Kustomization: selfhosted/stalwart OCIRepository: selfhosted/stalwart-mail
@@ -0,0 +1,19 @@
+---
+apiVersion: source.toolkit.fluxcd.io/v1
+kind: OCIRepository
+metadata:
+ labels:
+ app.kubernetes.io/name: stalwart
+ kustomize.toolkit.fluxcd.io/name: stalwart
+ kustomize.toolkit.fluxcd.io/namespace: selfhosted
+ name: stalwart-mail
+ namespace: selfhosted
+spec:
+ interval: 5m
+ layerSelector:
+ mediaType: application/vnd.cncf.helm.chart.content.v1.tar+gzip
+ operation: copy
+ ref:
+ tag: 0.4.9
+ url: oci://codeberg.org/wrenix/helm-charts/stalwart-mail
+
--- kubernetes/apps/selfhosted/stalwart/app Kustomization: selfhosted/stalwart HelmRelease: selfhosted/stalwart
+++ kubernetes/apps/selfhosted/stalwart/app Kustomization: selfhosted/stalwart HelmRelease: selfhosted/stalwart
@@ -0,0 +1,220 @@
+---
+apiVersion: helm.toolkit.fluxcd.io/v2
+kind: HelmRelease
+metadata:
+ labels:
+ app.kubernetes.io/name: stalwart
+ kustomize.toolkit.fluxcd.io/name: stalwart
+ kustomize.toolkit.fluxcd.io/namespace: selfhosted
+ name: stalwart
+ namespace: selfhosted
+spec:
+ chartRef:
+ kind: OCIRepository
+ name: stalwart-mail
+ install:
+ remediation:
+ retries: 3
+ interval: 30m
+ upgrade:
+ cleanupOnFail: true
+ remediation:
+ retries: 3
+ strategy: rollback
+ values:
+ backup:
+ enabled: false
+ certificate:
+ certmanager:
+ enabled: false
+ secretName: -.PLACEHOLDER_SECRET_DOMAIN..-tls
+ config:
+ authentication:
+ fallback-admin:
+ secret: '%{env:FALLBACK_ADMIN_SECRET}%'
+ user: admin
+ certificate:
+ default:
+ cert: '%{file:/opt/stalwart/etc/certs/tls.crt}%'
+ default: true
+ private-key: '%{file:/opt/stalwart/etc/certs/tls.key}%'
+ directory:
+ internal:
+ store: rocksdb
+ type: internal
+ http:
+ use-x-forwarded: true
+ metrics:
+ prometheus:
+ auth:
+ secret: '%{env:METRICS_SECRET}%'
+ username: '%{env:METRICS_USERNAME}%'
+ enable: true
+ queue:
+ outbound:
+ hostname: mail...PLACEHOLDER_SECRET_DOMAIN..
+ remote:
+ gmail-relay:
+ address: smtp.gmail.com
+ auth:
+ secret: '%{env:GMAIL_SMTP_PASSWORD}%'
+ username: '%{env:GMAIL_ADDRESS}%'
+ port: 587
+ protocol: smtp
+ tls:
+ implicit: false
+ start-tls: true
+ migadu-relay:
+ address: smtp.migadu.com
+ auth:
+ secret: '%{env:MIGADU_SMTP_PASSWORD}%'
+ username: '%{env:MIGADU_ADDRESS}%'
+ port: 587
+ protocol: smtp
+ tls:
+ implicit: false
+ start-tls: true
+ outlook-relay:
+ address: smtp.office365.com
+ auth:
+ secret: '%{env:OUTLOOK_SMTP_PASSWORD}%'
+ username: '%{env:OUTLOOK_ADDRESS}%'
+ port: 587
+ protocol: smtp
+ tls:
+ implicit: false
+ start-tls: true
+ server:
+ allowed-ip:
+ 10.0.0.0/8: ''
+ 172.16.0.0/12: ''
+ 192.168.0.0/16: ''
+ listener:
+ http:
+ bind:
+ - '[::]:80'
+ protocol: http
+ imap:
+ bind:
+ - '[::]:143'
+ protocol: imap
+ imaptls:
+ bind:
+ - '[::]:993'
+ protocol: imap
+ tls:
+ implicit: true
+ sieve:
+ bind:
+ - '[::]:4190'
+ protocol: managesieve
+ smtp:
+ bind:
+ - '[::]:25'
+ protocol: smtp
+ submission:
+ bind:
+ - '[::]:587'
+ protocol: smtp
+ submissions:
+ bind:
+ - '[::]:465'
+ protocol: smtp
+ tls:
+ implicit: true
+ spam-filter:
+ auto-update: true
+ dnsbl:
+ card-is-ham: true
+ header:
+ is-spam: X-Spam-Status
+ score:
+ discard: 0
+ reject: 0
+ spam: 8
+ storage:
+ blob: rocksdb
+ data: rocksdb
+ directory: internal
+ fts: rocksdb
+ lookup: rocksdb
+ store:
+ rocksdb:
+ compression: lz4
+ path: /data
+ type: rocksdb
+ write-buffer-size: 268435456
+ tracer:
+ otel:
+ enable: false
+ stdout:
+ ansi: false
+ enable: true
+ level: info
+ type: stdout
+ envFrom:
+ - secretRef:
+ name: stalwart-secret
+ image:
+ tag: v0.15.5
+ ingress:
+ annotations:
+ authentik.home.arpa/internal: 'true'
+ external-dns.alpha.kubernetes.io/target: internal...PLACEHOLDER_SECRET_DOMAIN..
+ className: internal
+ enabled: true
+ hosts:
+ - host: mail...PLACEHOLDER_SECRET_DOMAIN..
+ paths:
+ - path: /
+ pathType: ImplementationSpecific
+ tls:
+ - hosts:
+ - mail...PLACEHOLDER_SECRET_DOMAIN..
+ secretName: -.PLACEHOLDER_SECRET_DOMAIN..-tls
+ livenessProbe:
+ httpGet:
+ httpHeaders:
+ - name: X-Forwarded-For
+ value: 127.0.0.1
+ path: /healthz/live
+ port: http
+ initialDelaySeconds: 5
+ periodSeconds: 10
+ persistence:
+ accessMode: ReadWriteOnce
+ enabled: true
+ size: 50Gi
+ storageClass: ceph-rbd
+ readinessProbe:
+ httpGet:
+ httpHeaders:
+ - name: X-Forwarded-For
+ value: 127.0.0.1
+ path: /healthz/ready
+ port: http
+ initialDelaySeconds: 30
+ periodSeconds: 10
+ resources:
+ limits:
+ cpu: 2000m
+ memory: 4Gi
+ requests:
+ cpu: 500m
+ memory: 1Gi
+ secrets:
+ create: false
+ service:
+ annotations:
+ external-dns.alpha.kubernetes.io/hostname: mail...PLACEHOLDER_SECRET_DOMAIN..
+ lbipam.cilium.io/ips: 10.100.0.30
+ ports:
+ http: 80
+ imap: 143
+ imaptls: 993
+ sieve: 4190
+ smtp: 25
+ submission: 587
+ submissions: 465
+ type: LoadBalancer
+
--- kubernetes/apps/selfhosted/stalwart/app Kustomization: selfhosted/stalwart ExternalSecret: selfhosted/stalwart
+++ kubernetes/apps/selfhosted/stalwart/app Kustomization: selfhosted/stalwart ExternalSecret: selfhosted/stalwart
@@ -0,0 +1,40 @@
+---
+apiVersion: external-secrets.io/v1
+kind: ExternalSecret
+metadata:
+ labels:
+ app.kubernetes.io/name: stalwart
+ kustomize.toolkit.fluxcd.io/name: stalwart
+ kustomize.toolkit.fluxcd.io/namespace: selfhosted
+ name: stalwart
+ namespace: selfhosted
+spec:
+ dataFrom:
+ - find:
+ name:
+ regexp: ^STALWART.*
+ secretStoreRef:
+ kind: ClusterSecretStore
+ name: infisical
+ target:
+ name: stalwart-secret
+ template:
+ data:
+ FALLBACK_ADMIN_SECRET: '{{ .STALWART_ADMIN_PASSWORD }}'
+ GMAIL_ADDRESS: '{{ .STALWART_GMAIL_ADDRESS }}'
+ GMAIL_IMAP_PASSWORD: '{{ .STALWART_GMAIL_IMAP_PASSWORD }}'
+ GMAIL_SMTP_PASSWORD: '{{ .STALWART_GMAIL_SMTP_PASSWORD }}'
+ METRICS_SECRET: '{{ .STALWART_METRICS_PASSWORD }}'
+ METRICS_USERNAME: prometheus
+ MIGADU_ADDRESS: '{{ .STALWART_MIGADU_ADDRESS }}'
+ MIGADU_IMAP_PASSWORD: '{{ .STALWART_MIGADU_IMAP_PASSWORD }}'
+ MIGADU_SMTP_PASSWORD: '{{ .STALWART_MIGADU_SMTP_PASSWORD }}'
+ OUTLOOK_ADDRESS: '{{ .STALWART_OUTLOOK_ADDRESS }}'
+ OUTLOOK_OAUTH_CLIENT_ID: '{{ .STALWART_OUTLOOK_OAUTH_CLIENT_ID }}'
+ OUTLOOK_OAUTH_CLIENT_SECRET: '{{ .STALWART_OUTLOOK_OAUTH_CLIENT_SECRET }}'
+ OUTLOOK_SMTP_PASSWORD: '{{ .STALWART_OUTLOOK_SMTP_PASSWORD }}'
+ STALWART_PASSWORD: '{{ .STALWART_PRIMARY_PASSWORD }}'
+ STALWART_USER: '{{ .STALWART_PRIMARY_USER }}'
+ engineVersion: v2
+ mergePolicy: Replace
+
--- kubernetes/apps/selfhosted/email-oauth2-proxy/app Kustomization: selfhosted/email-oauth2-proxy HelmRelease: selfhosted/email-oauth2-proxy
+++ kubernetes/apps/selfhosted/email-oauth2-proxy/app Kustomization: selfhosted/email-oauth2-proxy HelmRelease: selfhosted/email-oauth2-proxy
@@ -0,0 +1,90 @@
+---
+apiVersion: helm.toolkit.fluxcd.io/v2
+kind: HelmRelease
+metadata:
+ labels:
+ app.kubernetes.io/name: email-oauth2-proxy
+ kustomize.toolkit.fluxcd.io/name: email-oauth2-proxy
+ kustomize.toolkit.fluxcd.io/namespace: selfhosted
+ name: email-oauth2-proxy
+ namespace: selfhosted
+spec:
+ chartRef:
+ kind: OCIRepository
+ name: app-template
+ install:
+ remediation:
+ retries: 3
+ interval: 30m
+ upgrade:
+ cleanupOnFail: true
+ remediation:
+ retries: 3
+ strategy: rollback
+ values:
+ controllers:
+ main:
+ annotations:
+ reloader.stakater.com/auto: 'true'
+ containers:
+ app:
+ env:
+ CACHE_STORE: /config/credstore.config
+ LOGFILE: 'true'
+ envFrom:
+ - secretRef:
+ name: email-oauth2-proxy-secret
+ image:
+ repository: blacktirion/email-oauth2-proxy-docker
+ tag: 2.4.0
+ probes:
+ liveness:
+ custom: true
+ enabled: true
+ spec:
+ initialDelaySeconds: 10
+ periodSeconds: 30
+ tcpSocket:
+ port: 1993
+ readiness:
+ custom: true
+ enabled: true
+ spec:
+ initialDelaySeconds: 5
+ periodSeconds: 10
+ tcpSocket:
+ port: 1993
+ resources:
+ limits:
+ cpu: 200m
+ memory: 256Mi
+ requests:
+ cpu: 100m
+ memory: 128Mi
+ strategy: Recreate
+ persistence:
+ config:
+ advancedMounts:
+ main:
+ app:
+ - path: /app/emailproxy.config
+ readOnly: true
+ subPath: emailproxy.config
+ name: email-oauth2-proxy-config
+ type: configMap
+ data:
+ accessMode: ReadWriteOnce
+ advancedMounts:
+ main:
+ app:
+ - path: /config
+ size: 100Mi
+ storageClass: ceph-rbd
+ type: persistentVolumeClaim
+ service:
+ app:
+ controller: main
+ ports:
+ imap:
+ port: 1993
+
--- kubernetes/apps/selfhosted/email-oauth2-proxy/app Kustomization: selfhosted/email-oauth2-proxy ExternalSecret: selfhosted/email-oauth2-proxy
+++ kubernetes/apps/selfhosted/email-oauth2-proxy/app Kustomization: selfhosted/email-oauth2-proxy ExternalSecret: selfhosted/email-oauth2-proxy
@@ -0,0 +1,28 @@
+---
+apiVersion: external-secrets.io/v1
+kind: ExternalSecret
+metadata:
+ labels:
+ app.kubernetes.io/name: email-oauth2-proxy
+ kustomize.toolkit.fluxcd.io/name: email-oauth2-proxy
+ kustomize.toolkit.fluxcd.io/namespace: selfhosted
+ name: email-oauth2-proxy
+ namespace: selfhosted
+spec:
+ dataFrom:
+ - find:
+ name:
+ regexp: ^STALWART_OUTLOOK.*
+ secretStoreRef:
+ kind: ClusterSecretStore
+ name: infisical
+ target:
+ name: email-oauth2-proxy-secret
+ template:
+ data:
+ OUTLOOK_ADDRESS: '{{ .STALWART_OUTLOOK_ADDRESS }}'
+ OUTLOOK_OAUTH_CLIENT_ID: '{{ .STALWART_OUTLOOK_OAUTH_CLIENT_ID }}'
+ OUTLOOK_OAUTH_CLIENT_SECRET: '{{ .STALWART_OUTLOOK_OAUTH_CLIENT_SECRET }}'
+ engineVersion: v2
+ mergePolicy: Replace
+
--- kubernetes/apps/selfhosted/email-oauth2-proxy/app Kustomization: selfhosted/email-oauth2-proxy ConfigMap: selfhosted/email-oauth2-proxy-config
+++ kubernetes/apps/selfhosted/email-oauth2-proxy/app Kustomization: selfhosted/email-oauth2-proxy ConfigMap: selfhosted/email-oauth2-proxy-config
@@ -0,0 +1,29 @@
+---
+apiVersion: v1
+data:
+ emailproxy.config: |
+ [Email OAuth 2.0 Proxy configuration]
+ # Log to stdout for k8s log collection
+ delete_account_token_on_password_error = False
+ encrypt_client_secret_on_first_use = False
+
+ [outlook]
+ permission_url = https://login.microsoftonline.com/common/oauth2/v2.0/authorize
+ token_url = https://login.microsoftonline.com/common/oauth2/v2.0/token
+ oauth2_scope = https://outlook.office.com/IMAP.AccessAsUser.All offline_access
+ redirect_uri = https://login.microsoftonline.com/common/oauth2/nativeclient
+
+ server_address = outlook.office.com
+ server_port = 993
+
+ local_address = 0.0.0.0
+ local_port = 1993
+kind: ConfigMap
+metadata:
+ labels:
+ app.kubernetes.io/name: email-oauth2-proxy
+ kustomize.toolkit.fluxcd.io/name: email-oauth2-proxy
+ kustomize.toolkit.fluxcd.io/namespace: selfhosted
+ name: email-oauth2-proxy-config
+ namespace: selfhosted
+
--- kubernetes/apps/selfhosted/imapsync/app Kustomization: selfhosted/imapsync HelmRelease: selfhosted/imapsync
+++ kubernetes/apps/selfhosted/imapsync/app Kustomization: selfhosted/imapsync HelmRelease: selfhosted/imapsync
@@ -0,0 +1,230 @@
+---
+apiVersion: helm.toolkit.fluxcd.io/v2
+kind: HelmRelease
+metadata:
+ labels:
+ app.kubernetes.io/name: imapsync
+ kustomize.toolkit.fluxcd.io/name: imapsync
+ kustomize.toolkit.fluxcd.io/namespace: selfhosted
+ name: imapsync
+ namespace: selfhosted
+spec:
+ chartRef:
+ kind: OCIRepository
+ name: app-template
+ install:
+ remediation:
+ retries: 3
+ interval: 30m
+ upgrade:
+ cleanupOnFail: true
+ remediation:
+ retries: 3
+ strategy: rollback
+ values:
+ controllers:
+ gmail:
+ containers:
+ app:
+ args:
+ - --gmail1
+ - --host2=stalwart.selfhosted.svc.cluster.local
+ - --port2=143
+ - --user1=$(GMAIL_ADDRESS)
+ - --passfile1=/secrets/gmail-password
+ - --user2=$(STALWART_USER)
+ - --passfile2=/secrets/stalwart-password
+ - --skipcrossduplicates
+ - --exclude=\[Gmail\]/(All Mail|Important|Starred|Spam|Chats|Trash)
+ - --usecache
+ - --tmpdir=/cache
+ - --logdir=/cache/logs
+ - --maxmessagespersecond=3
+ - --errorsmax=200
+ - --pidfilelocking
+ - --pidfile=/cache/gmail.pid
+ env:
+ GMAIL_ADDRESS:
+ valueFrom:
+ secretKeyRef:
+ key: GMAIL_ADDRESS
+ name: imapsync-credentials
+ STALWART_USER:
+ valueFrom:
+ secretKeyRef:
+ key: STALWART_USER
+ name: imapsync-credentials
+ image:
+ repository: gilleslamiral/imapsync
+ tag: '2.314'
+ resources:
+ limits:
+ cpu: 500m
+ memory: 512Mi
+ requests:
+ cpu: 100m
+ memory: 256Mi
+ cronjob:
+ activeDeadlineSeconds: 540
+ backoffLimit: 2
+ concurrencyPolicy: Forbid
+ failedJobsHistory: 5
+ schedule: '*/10 * * * *'
+ startingDeadlineSeconds: 300
+ successfulJobsHistory: 3
+ suspend: true
+ timeZone: Etc/UTC
+ pod:
+ restartPolicy: Never
+ type: cronjob
+ migadu:
+ containers:
+ app:
+ args:
+ - --host1=imap.migadu.com
+ - --port1=993
+ - --ssl1
+ - --host2=stalwart.selfhosted.svc.cluster.local
+ - --port2=143
+ - --user1=$(MIGADU_ADDRESS)
+ - --passfile1=/secrets/migadu-password
+ - --user2=$(STALWART_USER)
+ - --passfile2=/secrets/stalwart-password
+ - --usecache
+ - --tmpdir=/cache
+ - --logdir=/cache/logs
+ - --errorsmax=200
+ - --pidfilelocking
+ - --pidfile=/cache/migadu.pid
+ env:
+ MIGADU_ADDRESS:
+ valueFrom:
+ secretKeyRef:
+ key: MIGADU_ADDRESS
+ name: imapsync-credentials
+ STALWART_USER:
+ valueFrom:
+ secretKeyRef:
+ key: STALWART_USER
+ name: imapsync-credentials
+ image:
+ repository: gilleslamiral/imapsync
+ tag: '2.314'
+ resources:
+ limits:
+ cpu: 500m
+ memory: 512Mi
+ requests:
+ cpu: 100m
+ memory: 256Mi
+ cronjob:
+ activeDeadlineSeconds: 540
+ backoffLimit: 2
+ concurrencyPolicy: Forbid
+ failedJobsHistory: 5
+ schedule: 4-54/10 * * * *
+ startingDeadlineSeconds: 300
+ successfulJobsHistory: 3
+ suspend: true
+ timeZone: Etc/UTC
+ pod:
+ restartPolicy: Never
+ type: cronjob
+ outlook:
+ containers:
+ app:
+ args:
+ - --host1=email-oauth2-proxy.selfhosted.svc.cluster.local
+ - --port1=1993
+ - --host2=stalwart.selfhosted.svc.cluster.local
+ - --port2=143
+ - --user1=$(OUTLOOK_ADDRESS)
+ - --passfile1=/secrets/outlook-password
+ - --user2=$(STALWART_USER)
+ - --passfile2=/secrets/stalwart-password
+ - --usecache
+ - --tmpdir=/cache
+ - --logdir=/cache/logs
+ - --errorsmax=200
+ - --pidfilelocking
+ - --pidfile=/cache/outlook.pid
+ env:
+ OUTLOOK_ADDRESS:
+ valueFrom:
+ secretKeyRef:
+ key: OUTLOOK_ADDRESS
+ name: imapsync-credentials
+ STALWART_USER:
+ valueFrom:
+ secretKeyRef:
+ key: STALWART_USER
+ name: imapsync-credentials
+ image:
+ repository: gilleslamiral/imapsync
+ tag: '2.314'
+ resources:
+ limits:
+ cpu: 500m
+ memory: 512Mi
+ requests:
+ cpu: 100m
+ memory: 256Mi
+ cronjob:
+ activeDeadlineSeconds: 540
+ backoffLimit: 2
+ concurrencyPolicy: Forbid
+ failedJobsHistory: 5
+ schedule: 2-52/10 * * * *
+ startingDeadlineSeconds: 300
+ successfulJobsHistory: 3
+ suspend: true
+ timeZone: Etc/UTC
+ pod:
+ restartPolicy: Never
+ type: cronjob
+ persistence:
+ cache-gmail:
+ accessMode: ReadWriteOnce
+ advancedMounts:
+ gmail:
+ app:
+ - path: /cache
+ size: 1Gi
+ storageClass: ceph-rbd
+ type: persistentVolumeClaim
+ cache-migadu:
+ accessMode: ReadWriteOnce
+ advancedMounts:
+ migadu:
+ app:
+ - path: /cache
+ size: 1Gi
+ storageClass: ceph-rbd
+ type: persistentVolumeClaim
+ cache-outlook:
+ accessMode: ReadWriteOnce
+ advancedMounts:
+ outlook:
+ app:
+ - path: /cache
+ size: 1Gi
+ storageClass: ceph-rbd
+ type: persistentVolumeClaim
+ secrets:
+ advancedMounts:
+ gmail:
+ app:
+ - path: /secrets
+ readOnly: true
+ migadu:
+ app:
+ - path: /secrets
+ readOnly: true
+ outlook:
+ app:
+ - path: /secrets
+ readOnly: true
+ defaultMode: 256
+ name: imapsync-credentials
+ type: secret
+
--- kubernetes/apps/selfhosted/imapsync/app Kustomization: selfhosted/imapsync ExternalSecret: selfhosted/imapsync
+++ kubernetes/apps/selfhosted/imapsync/app Kustomization: selfhosted/imapsync ExternalSecret: selfhosted/imapsync
@@ -0,0 +1,33 @@
+---
+apiVersion: external-secrets.io/v1
+kind: ExternalSecret
+metadata:
+ labels:
+ app.kubernetes.io/name: imapsync
+ kustomize.toolkit.fluxcd.io/name: imapsync
+ kustomize.toolkit.fluxcd.io/namespace: selfhosted
+ name: imapsync
+ namespace: selfhosted
+spec:
+ dataFrom:
+ - find:
+ name:
+ regexp: ^STALWART.*
+ secretStoreRef:
+ kind: ClusterSecretStore
+ name: infisical
+ target:
+ name: imapsync-credentials
+ template:
+ data:
+ GMAIL_ADDRESS: '{{ .STALWART_GMAIL_ADDRESS }}'
+ MIGADU_ADDRESS: '{{ .STALWART_MIGADU_ADDRESS }}'
+ OUTLOOK_ADDRESS: '{{ .STALWART_OUTLOOK_ADDRESS }}'
+ STALWART_USER: '{{ .STALWART_PRIMARY_USER }}'
+ gmail-password: '{{ .STALWART_GMAIL_IMAP_PASSWORD }}'
+ migadu-password: '{{ .STALWART_MIGADU_IMAP_PASSWORD }}'
+ outlook-password: '{{ .STALWART_OUTLOOK_IMAP_PASSWORD }}'
+ stalwart-password: '{{ .STALWART_PRIMARY_PASSWORD }}'
+ engineVersion: v2
+ mergePolicy: Replace
+ |
Contributor
--- HelmRelease: selfhosted/email-oauth2-proxy PersistentVolumeClaim: selfhosted/email-oauth2-proxy
+++ HelmRelease: selfhosted/email-oauth2-proxy PersistentVolumeClaim: selfhosted/email-oauth2-proxy
@@ -0,0 +1,18 @@
+---
+kind: PersistentVolumeClaim
+apiVersion: v1
+metadata:
+ name: email-oauth2-proxy
+ labels:
+ app.kubernetes.io/instance: email-oauth2-proxy
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/name: email-oauth2-proxy
+ namespace: selfhosted
+spec:
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 100Mi
+ storageClassName: ceph-rbd
+
--- HelmRelease: selfhosted/email-oauth2-proxy Service: selfhosted/email-oauth2-proxy
+++ HelmRelease: selfhosted/email-oauth2-proxy Service: selfhosted/email-oauth2-proxy
@@ -0,0 +1,23 @@
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: email-oauth2-proxy
+ labels:
+ app.kubernetes.io/instance: email-oauth2-proxy
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/name: email-oauth2-proxy
+ app.kubernetes.io/service: email-oauth2-proxy
+ namespace: selfhosted
+spec:
+ type: ClusterIP
+ ports:
+ - port: 1993
+ targetPort: 1993
+ protocol: TCP
+ name: imap
+ selector:
+ app.kubernetes.io/controller: main
+ app.kubernetes.io/instance: email-oauth2-proxy
+ app.kubernetes.io/name: email-oauth2-proxy
+
--- HelmRelease: selfhosted/email-oauth2-proxy Deployment: selfhosted/email-oauth2-proxy
+++ HelmRelease: selfhosted/email-oauth2-proxy Deployment: selfhosted/email-oauth2-proxy
@@ -0,0 +1,80 @@
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: email-oauth2-proxy
+ labels:
+ app.kubernetes.io/controller: main
+ app.kubernetes.io/instance: email-oauth2-proxy
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/name: email-oauth2-proxy
+ annotations:
+ reloader.stakater.com/auto: 'true'
+ namespace: selfhosted
+spec:
+ revisionHistoryLimit: 3
+ replicas: 1
+ strategy:
+ type: Recreate
+ selector:
+ matchLabels:
+ app.kubernetes.io/controller: main
+ app.kubernetes.io/name: email-oauth2-proxy
+ app.kubernetes.io/instance: email-oauth2-proxy
+ template:
+ metadata:
+ labels:
+ app.kubernetes.io/controller: main
+ app.kubernetes.io/instance: email-oauth2-proxy
+ app.kubernetes.io/name: email-oauth2-proxy
+ spec:
+ enableServiceLinks: false
+ serviceAccountName: default
+ automountServiceAccountToken: true
+ hostIPC: false
+ hostNetwork: false
+ hostPID: false
+ dnsPolicy: ClusterFirst
+ containers:
+ - env:
+ - name: CACHE_STORE
+ value: /config/credstore.config
+ - name: LOGFILE
+ value: 'true'
+ envFrom:
+ - secretRef:
+ name: email-oauth2-proxy-secret
+ image: blacktirion/email-oauth2-proxy-docker:2.4.0
+ livenessProbe:
+ initialDelaySeconds: 10
+ periodSeconds: 30
+ tcpSocket:
+ port: 1993
+ name: app
+ readinessProbe:
+ initialDelaySeconds: 5
+ periodSeconds: 10
+ tcpSocket:
+ port: 1993
+ resources:
+ limits:
+ cpu: 200m
+ memory: 256Mi
+ requests:
+ cpu: 100m
+ memory: 128Mi
+ volumeMounts:
+ - mountPath: /app/emailproxy.config
+ name: config
+ readOnly: true
+ subPath: emailproxy.config
+ - mountPath: /config
+ name: data
+ volumes:
+ - configMap:
+ name: email-oauth2-proxy-config
+ name: config
+ - name: data
+ persistentVolumeClaim:
+ claimName: email-oauth2-proxy
+
--- HelmRelease: selfhosted/imapsync PersistentVolumeClaim: selfhosted/imapsync-cache-gmail
+++ HelmRelease: selfhosted/imapsync PersistentVolumeClaim: selfhosted/imapsync-cache-gmail
@@ -0,0 +1,18 @@
+---
+kind: PersistentVolumeClaim
+apiVersion: v1
+metadata:
+ name: imapsync-cache-gmail
+ labels:
+ app.kubernetes.io/instance: imapsync
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/name: imapsync
+ namespace: selfhosted
+spec:
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 1Gi
+ storageClassName: ceph-rbd
+
--- HelmRelease: selfhosted/imapsync PersistentVolumeClaim: selfhosted/imapsync-cache-migadu
+++ HelmRelease: selfhosted/imapsync PersistentVolumeClaim: selfhosted/imapsync-cache-migadu
@@ -0,0 +1,18 @@
+---
+kind: PersistentVolumeClaim
+apiVersion: v1
+metadata:
+ name: imapsync-cache-migadu
+ labels:
+ app.kubernetes.io/instance: imapsync
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/name: imapsync
+ namespace: selfhosted
+spec:
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 1Gi
+ storageClassName: ceph-rbd
+
--- HelmRelease: selfhosted/imapsync PersistentVolumeClaim: selfhosted/imapsync-cache-outlook
+++ HelmRelease: selfhosted/imapsync PersistentVolumeClaim: selfhosted/imapsync-cache-outlook
@@ -0,0 +1,18 @@
+---
+kind: PersistentVolumeClaim
+apiVersion: v1
+metadata:
+ name: imapsync-cache-outlook
+ labels:
+ app.kubernetes.io/instance: imapsync
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/name: imapsync
+ namespace: selfhosted
+spec:
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 1Gi
+ storageClassName: ceph-rbd
+
--- HelmRelease: selfhosted/imapsync CronJob: selfhosted/imapsync-outlook
+++ HelmRelease: selfhosted/imapsync CronJob: selfhosted/imapsync-outlook
@@ -0,0 +1,89 @@
+---
+apiVersion: batch/v1
+kind: CronJob
+metadata:
+ name: imapsync-outlook
+ labels:
+ app.kubernetes.io/controller: outlook
+ app.kubernetes.io/instance: imapsync
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/name: imapsync
+ namespace: selfhosted
+spec:
+ suspend: true
+ concurrencyPolicy: Forbid
+ startingDeadlineSeconds: 300
+ timeZone: Etc/UTC
+ schedule: 2-52/10 * * * *
+ successfulJobsHistoryLimit: 3
+ failedJobsHistoryLimit: 5
+ jobTemplate:
+ spec:
+ activeDeadlineSeconds: 540
+ backoffLimit: 2
+ template:
+ metadata:
+ labels:
+ app.kubernetes.io/controller: outlook
+ app.kubernetes.io/instance: imapsync
+ app.kubernetes.io/name: imapsync
+ spec:
+ enableServiceLinks: false
+ serviceAccountName: default
+ automountServiceAccountToken: true
+ hostIPC: false
+ hostNetwork: false
+ hostPID: false
+ dnsPolicy: ClusterFirst
+ restartPolicy: Never
+ containers:
+ - args:
+ - --host1=email-oauth2-proxy.selfhosted.svc.cluster.local
+ - --port1=1993
+ - --host2=stalwart.selfhosted.svc.cluster.local
+ - --port2=143
+ - --user1=$(OUTLOOK_ADDRESS)
+ - --passfile1=/secrets/outlook-password
+ - --user2=$(STALWART_USER)
+ - --passfile2=/secrets/stalwart-password
+ - --usecache
+ - --tmpdir=/cache
+ - --logdir=/cache/logs
+ - --errorsmax=200
+ - --pidfilelocking
+ - --pidfile=/cache/outlook.pid
+ env:
+ - name: OUTLOOK_ADDRESS
+ valueFrom:
+ secretKeyRef:
+ key: OUTLOOK_ADDRESS
+ name: imapsync-credentials
+ - name: STALWART_USER
+ valueFrom:
+ secretKeyRef:
+ key: STALWART_USER
+ name: imapsync-credentials
+ image: gilleslamiral/imapsync:2.314
+ name: app
+ resources:
+ limits:
+ cpu: 500m
+ memory: 512Mi
+ requests:
+ cpu: 100m
+ memory: 256Mi
+ volumeMounts:
+ - mountPath: /cache
+ name: cache-outlook
+ - mountPath: /secrets
+ name: secrets
+ readOnly: true
+ volumes:
+ - name: cache-outlook
+ persistentVolumeClaim:
+ claimName: imapsync-cache-outlook
+ - name: secrets
+ secret:
+ defaultMode: 256
+ secretName: imapsync-credentials
+
--- HelmRelease: selfhosted/imapsync CronJob: selfhosted/imapsync-gmail
+++ HelmRelease: selfhosted/imapsync CronJob: selfhosted/imapsync-gmail
@@ -0,0 +1,91 @@
+---
+apiVersion: batch/v1
+kind: CronJob
+metadata:
+ name: imapsync-gmail
+ labels:
+ app.kubernetes.io/controller: gmail
+ app.kubernetes.io/instance: imapsync
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/name: imapsync
+ namespace: selfhosted
+spec:
+ suspend: true
+ concurrencyPolicy: Forbid
+ startingDeadlineSeconds: 300
+ timeZone: Etc/UTC
+ schedule: '*/10 * * * *'
+ successfulJobsHistoryLimit: 3
+ failedJobsHistoryLimit: 5
+ jobTemplate:
+ spec:
+ activeDeadlineSeconds: 540
+ backoffLimit: 2
+ template:
+ metadata:
+ labels:
+ app.kubernetes.io/controller: gmail
+ app.kubernetes.io/instance: imapsync
+ app.kubernetes.io/name: imapsync
+ spec:
+ enableServiceLinks: false
+ serviceAccountName: default
+ automountServiceAccountToken: true
+ hostIPC: false
+ hostNetwork: false
+ hostPID: false
+ dnsPolicy: ClusterFirst
+ restartPolicy: Never
+ containers:
+ - args:
+ - --gmail1
+ - --host2=stalwart.selfhosted.svc.cluster.local
+ - --port2=143
+ - --user1=$(GMAIL_ADDRESS)
+ - --passfile1=/secrets/gmail-password
+ - --user2=$(STALWART_USER)
+ - --passfile2=/secrets/stalwart-password
+ - --skipcrossduplicates
+ - --exclude=\[Gmail\]/(All Mail|Important|Starred|Spam|Chats|Trash)
+ - --usecache
+ - --tmpdir=/cache
+ - --logdir=/cache/logs
+ - --maxmessagespersecond=3
+ - --errorsmax=200
+ - --pidfilelocking
+ - --pidfile=/cache/gmail.pid
+ env:
+ - name: GMAIL_ADDRESS
+ valueFrom:
+ secretKeyRef:
+ key: GMAIL_ADDRESS
+ name: imapsync-credentials
+ - name: STALWART_USER
+ valueFrom:
+ secretKeyRef:
+ key: STALWART_USER
+ name: imapsync-credentials
+ image: gilleslamiral/imapsync:2.314
+ name: app
+ resources:
+ limits:
+ cpu: 500m
+ memory: 512Mi
+ requests:
+ cpu: 100m
+ memory: 256Mi
+ volumeMounts:
+ - mountPath: /cache
+ name: cache-gmail
+ - mountPath: /secrets
+ name: secrets
+ readOnly: true
+ volumes:
+ - name: cache-gmail
+ persistentVolumeClaim:
+ claimName: imapsync-cache-gmail
+ - name: secrets
+ secret:
+ defaultMode: 256
+ secretName: imapsync-credentials
+
--- HelmRelease: selfhosted/imapsync CronJob: selfhosted/imapsync-migadu
+++ HelmRelease: selfhosted/imapsync CronJob: selfhosted/imapsync-migadu
@@ -0,0 +1,90 @@
+---
+apiVersion: batch/v1
+kind: CronJob
+metadata:
+ name: imapsync-migadu
+ labels:
+ app.kubernetes.io/controller: migadu
+ app.kubernetes.io/instance: imapsync
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/name: imapsync
+ namespace: selfhosted
+spec:
+ suspend: true
+ concurrencyPolicy: Forbid
+ startingDeadlineSeconds: 300
+ timeZone: Etc/UTC
+ schedule: 4-54/10 * * * *
+ successfulJobsHistoryLimit: 3
+ failedJobsHistoryLimit: 5
+ jobTemplate:
+ spec:
+ activeDeadlineSeconds: 540
+ backoffLimit: 2
+ template:
+ metadata:
+ labels:
+ app.kubernetes.io/controller: migadu
+ app.kubernetes.io/instance: imapsync
+ app.kubernetes.io/name: imapsync
+ spec:
+ enableServiceLinks: false
+ serviceAccountName: default
+ automountServiceAccountToken: true
+ hostIPC: false
+ hostNetwork: false
+ hostPID: false
+ dnsPolicy: ClusterFirst
+ restartPolicy: Never
+ containers:
+ - args:
+ - --host1=imap.migadu.com
+ - --port1=993
+ - --ssl1
+ - --host2=stalwart.selfhosted.svc.cluster.local
+ - --port2=143
+ - --user1=$(MIGADU_ADDRESS)
+ - --passfile1=/secrets/migadu-password
+ - --user2=$(STALWART_USER)
+ - --passfile2=/secrets/stalwart-password
+ - --usecache
+ - --tmpdir=/cache
+ - --logdir=/cache/logs
+ - --errorsmax=200
+ - --pidfilelocking
+ - --pidfile=/cache/migadu.pid
+ env:
+ - name: MIGADU_ADDRESS
+ valueFrom:
+ secretKeyRef:
+ key: MIGADU_ADDRESS
+ name: imapsync-credentials
+ - name: STALWART_USER
+ valueFrom:
+ secretKeyRef:
+ key: STALWART_USER
+ name: imapsync-credentials
+ image: gilleslamiral/imapsync:2.314
+ name: app
+ resources:
+ limits:
+ cpu: 500m
+ memory: 512Mi
+ requests:
+ cpu: 100m
+ memory: 256Mi
+ volumeMounts:
+ - mountPath: /cache
+ name: cache-migadu
+ - mountPath: /secrets
+ name: secrets
+ readOnly: true
+ volumes:
+ - name: cache-migadu
+ persistentVolumeClaim:
+ claimName: imapsync-cache-migadu
+ - name: secrets
+ secret:
+ defaultMode: 256
+ secretName: imapsync-credentials
+
--- HelmRelease: selfhosted/stalwart ConfigMap: selfhosted/stalwart-stalwart-mail
+++ HelmRelease: selfhosted/stalwart ConfigMap: selfhosted/stalwart-stalwart-mail
@@ -0,0 +1,176 @@
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: stalwart-stalwart-mail
+ labels:
+ app.kubernetes.io/name: stalwart-mail
+ app.kubernetes.io/instance: stalwart
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/component: main
+data:
+ config.toml: |
+ [auth]
+ [auth.dkim]
+ verify = "relaxed"
+
+ [[auth.dkim.sign]]
+ if = "listener != 'smtp' && is_local_domain('', sender_domain)"
+ then = "['rsa-' + sender_domain, 'ed25519-' + sender_domain]"
+
+ [[auth.dkim.sign]]
+ else = false
+
+ [authentication]
+ [authentication.fallback-admin]
+ secret = "%{env:FALLBACK_ADMIN_SECRET}%"
+ user = "admin"
+
+ [certificate]
+ [certificate.default]
+ cert = "%{file:/opt/stalwart/etc/certs/tls.crt}%"
+ default = true
+ private-key = "%{file:/opt/stalwart/etc/certs/tls.key}%"
+
+ [cluster]
+ node-id = "%{env:POD_INDEX}%"
+
+ [config]
+ local-keys = ["store.*", "directory.*", "tracer.*", "!server.blocked-ip.*", "server.*", "authentication.fallback-admin.*", "cluster.*", "config.local-keys.*", "storage.data", "storage.blob", "storage.lookup", "storage.fts", "storage.directory", "certificate.*", "server.allowed-ip.*", "metrics.prometheus.*", "auth.dkim.sign.*", "auth.dkim.verify", "http.use-x-forwarded", "report.domain"]
+
+ [directory]
+ [directory.internal]
+ store = "rocksdb"
+ type = "internal"
+
+ [http]
+ use-x-forwarded = true
+
+ [metrics]
+ [metrics.prometheus]
+ enable = true
+ [metrics.prometheus.auth]
+ secret = "%{env:METRICS_SECRET}%"
+ username = "%{env:METRICS_USERNAME}%"
+
+ [queue]
+ [queue.outbound]
+ hostname = "mail...PLACEHOLDER_SECRET_DOMAIN.."
+
+ [remote]
+ [remote.gmail-relay]
+ address = "smtp.gmail.com"
+ port = 587
+ protocol = "smtp"
+ [remote.gmail-relay.auth]
+ secret = "%{env:GMAIL_SMTP_PASSWORD}%"
+ username = "%{env:GMAIL_ADDRESS}%"
+ [remote.gmail-relay.tls]
+ implicit = false
+ start-tls = true
+ [remote.migadu-relay]
+ address = "smtp.migadu.com"
+ port = 587
+ protocol = "smtp"
+ [remote.migadu-relay.auth]
+ secret = "%{env:MIGADU_SMTP_PASSWORD}%"
+ username = "%{env:MIGADU_ADDRESS}%"
+ [remote.migadu-relay.tls]
+ implicit = false
+ start-tls = true
+ [remote.outlook-relay]
+ address = "smtp.office365.com"
+ port = 587
+ protocol = "smtp"
+ [remote.outlook-relay.auth]
+ secret = "%{env:OUTLOOK_SMTP_PASSWORD}%"
+ username = "%{env:OUTLOOK_ADDRESS}%"
+ [remote.outlook-relay.tls]
+ implicit = false
+ start-tls = true
+
+ [server]
+ [server.allowed-ip]
+ "10.0.0.0/8" = ""
+ "10.42.0.1/16" = ""
+ "172.16.0.0/12" = ""
+ "192.168.0.0/16" = ""
+ [server.listener]
+ [server.listener.http]
+ bind = ["[::]:80"]
+ protocol = "http"
+ [server.listener.https]
+ bind = ["[::]:443"]
+ protocol = "http"
+ [server.listener.https.tls]
+ implicit = true
+ [server.listener.imap]
+ bind = ["[::]:143"]
+ protocol = "imap"
+ [server.listener.imaptls]
+ bind = ["[::]:993"]
+ protocol = "imap"
+ [server.listener.imaptls.tls]
+ implicit = true
+ [server.listener.pop3]
+ bind = ["[::]:110"]
+ protocol = "pop3"
+ [server.listener.pop3s]
+ bind = ["[::]:995"]
+ protocol = "pop3"
+ [server.listener.pop3s.tls]
+ implicit = true
+ [server.listener.sieve]
+ bind = ["[::]:4190"]
+ protocol = "managesieve"
+ [server.listener.smtp]
+ bind = ["[::]:25"]
+ protocol = "smtp"
+ [server.listener.submission]
+ bind = ["[::]:587"]
+ protocol = "smtp"
+ [server.listener.submissions]
+ bind = ["[::]:465"]
+ protocol = "smtp"
+ [server.listener.submissions.tls]
+ implicit = true
+
+ [spam-filter]
+ auto-update = true
+ [spam-filter.dnsbl]
+ card-is-ham = true
+ [spam-filter.header]
+ is-spam = "X-Spam-Status"
+ [spam-filter.score]
+ discard = 0
+ reject = 0
+ spam = 8
+
+ [storage]
+ blob = "rocksdb"
+ data = "rocksdb"
+ directory = "internal"
+ fts = "rocksdb"
+ lookup = "rocksdb"
+
+ [store]
+ [store.rocksdb]
+ compression = "lz4"
+ path = "/data"
+ type = "rocksdb"
+ write-buffer-size = 268435456
+
+ [tracer]
+ [tracer.otel]
+ enable = false
+ endpoint = "https://127.0.0.1/otel"
+ headers = []
+ level = "info"
+ transport = "grpc"
+ type = "open-telemetry"
+ [tracer.stdout]
+ ansi = false
+ enable = true
+ level = "info"
+ type = "stdout"
+
--- HelmRelease: selfhosted/stalwart PersistentVolumeClaim: selfhosted/stalwart-stalwart-mail
+++ HelmRelease: selfhosted/stalwart PersistentVolumeClaim: selfhosted/stalwart-stalwart-mail
@@ -0,0 +1,17 @@
+---
+kind: PersistentVolumeClaim
+apiVersion: v1
+metadata:
+ name: stalwart-stalwart-mail
+ labels:
+ app.kubernetes.io/name: stalwart-mail
+ app.kubernetes.io/instance: stalwart
+ app.kubernetes.io/managed-by: Helm
+spec:
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 50Gi
+ storageClassName: ceph-rbd
+
--- HelmRelease: selfhosted/stalwart Service: selfhosted/stalwart-stalwart-mail
+++ HelmRelease: selfhosted/stalwart Service: selfhosted/stalwart-stalwart-mail
@@ -0,0 +1,64 @@
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: stalwart-stalwart-mail
+ labels:
+ app.kubernetes.io/name: stalwart-mail
+ app.kubernetes.io/instance: stalwart
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/component: main
+ annotations:
+ external-dns.alpha.kubernetes.io/hostname: mail...PLACEHOLDER_SECRET_DOMAIN..
+ lbipam.cilium.io/ips: 10.100.0.30
+spec:
+ type: LoadBalancer
+ ipFamilyPolicy: SingleStack
+ ipFamilies:
+ - IPv4
+ ports:
+ - port: 80
+ targetPort: http
+ protocol: TCP
+ name: http
+ - port: 443
+ targetPort: https
+ protocol: TCP
+ name: https
+ - port: 143
+ targetPort: imap
+ protocol: TCP
+ name: imap
+ - port: 993
+ targetPort: imaptls
+ protocol: TCP
+ name: imaptls
+ - port: 110
+ targetPort: pop3
+ protocol: TCP
+ name: pop3
+ - port: 995
+ targetPort: pop3s
+ protocol: TCP
+ name: pop3s
+ - port: 4190
+ targetPort: sieve
+ protocol: TCP
+ name: sieve
+ - port: 25
+ targetPort: smtp
+ protocol: TCP
+ name: smtp
+ - port: 587
+ targetPort: submission
+ protocol: TCP
+ name: submission
+ - port: 465
+ targetPort: submissions
+ protocol: TCP
+ name: submissions
+ selector:
+ app.kubernetes.io/name: stalwart-mail
+ app.kubernetes.io/instance: stalwart
+ app.kubernetes.io/component: main
+
--- HelmRelease: selfhosted/stalwart StatefulSet: selfhosted/stalwart-stalwart-mail
+++ HelmRelease: selfhosted/stalwart StatefulSet: selfhosted/stalwart-stalwart-mail
@@ -0,0 +1,139 @@
+---
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+ name: stalwart-stalwart-mail
+ labels:
+ app.kubernetes.io/name: stalwart-mail
+ app.kubernetes.io/instance: stalwart
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/component: main
+spec:
+ replicas: 1
+ podManagementPolicy: Parallel
+ ordinals:
+ start: 1
+ selector:
+ matchLabels:
+ app.kubernetes.io/name: stalwart-mail
+ app.kubernetes.io/instance: stalwart
+ app.kubernetes.io/component: main
+ template:
+ metadata:
+ annotations:
+ config-hash: 8df30b7f12f3ef38a9162bd3a888c4401e3f370b156420af20806865716fd351
+ secret-env-hash: f52d711103d50a437830c6fbcd04fb4bab49a0f82f6d26d1c791c6e8488dd090
+ labels:
+ app.kubernetes.io/name: stalwart-mail
+ app.kubernetes.io/instance: stalwart
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/component: main
+ spec:
+ serviceAccountName: default
+ securityContext: {}
+ containers:
+ - name: stalwart-mail
+ securityContext: {}
+ image: ghcr.io/stalwartlabs/stalwart:v0.15.5
+ imagePullPolicy: IfNotPresent
+ env:
+ - name: POD_INDEX
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.labels['apps.kubernetes.io/pod-index']
+ - name: POD_IP
+ valueFrom:
+ fieldRef:
+ fieldPath: status.podIP
+ - name: URL
+ value: http://localhost:80
+ - name: CREDENTIALS
+ value: admin:$(FALLBACK_ADMIN_SECRET)
+ envFrom:
+ - secretRef:
+ name: stalwart-secret
+ ports:
+ - name: http
+ containerPort: 80
+ protocol: TCP
+ - name: https
+ containerPort: 443
+ protocol: TCP
+ - name: imap
+ containerPort: 143
+ protocol: TCP
+ - name: imaptls
+ containerPort: 993
+ protocol: TCP
+ - name: pop3
+ containerPort: 110
+ protocol: TCP
+ - name: pop3s
+ containerPort: 995
+ protocol: TCP
+ - name: sieve
+ containerPort: 4190
+ protocol: TCP
+ - name: smtp
+ containerPort: 25
+ protocol: TCP
+ - name: submission
+ containerPort: 587
+ protocol: TCP
+ - name: submissions
+ containerPort: 465
+ protocol: TCP
+ livenessProbe:
+ httpGet:
+ httpHeaders:
+ - name: X-Forwarded-For
+ value: 127.0.0.1
+ path: /healthz/live
+ port: http
+ initialDelaySeconds: 5
+ periodSeconds: 10
+ readinessProbe:
+ httpGet:
+ httpHeaders:
+ - name: X-Forwarded-For
+ value: 127.0.0.1
+ path: /healthz/ready
+ port: http
+ initialDelaySeconds: 30
+ periodSeconds: 10
+ resources:
+ limits:
+ cpu: 2000m
+ memory: 4Gi
+ requests:
+ cpu: 500m
+ memory: 1Gi
+ volumeMounts:
+ - name: data
+ mountPath: /data
+ - name: data
+ mountPath: /data/blobs
+ subPath: blobs
+ - name: data
+ mountPath: /data/queue
+ subPath: queue
+ - name: data
+ mountPath: /data/reports
+ subPath: reports
+ - name: config
+ mountPath: /opt/stalwart/etc/config.toml
+ subPath: config.toml
+ readOnly: true
+ - name: certificate
+ mountPath: /opt/stalwart/etc/certs
+ volumes:
+ - name: config
+ configMap:
+ name: stalwart-stalwart-mail
+ - name: certificate
+ secret:
+ secretName: -.PLACEHOLDER_SECRET_DOMAIN..-tls
+ - name: data
+ persistentVolumeClaim:
+ claimName: stalwart-stalwart-mail
+
--- HelmRelease: selfhosted/stalwart Ingress: selfhosted/stalwart-stalwart-mail
+++ HelmRelease: selfhosted/stalwart Ingress: selfhosted/stalwart-stalwart-mail
@@ -0,0 +1,30 @@
+---
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: stalwart-stalwart-mail
+ labels:
+ app.kubernetes.io/name: stalwart-mail
+ app.kubernetes.io/instance: stalwart
+ app.kubernetes.io/managed-by: Helm
+ annotations:
+ authentik.home.arpa/internal: 'true'
+ external-dns.alpha.kubernetes.io/target: internal...PLACEHOLDER_SECRET_DOMAIN..
+spec:
+ ingressClassName: internal
+ tls:
+ - hosts:
+ - mail...PLACEHOLDER_SECRET_DOMAIN..
+ secretName: -.PLACEHOLDER_SECRET_DOMAIN..-tls
+ rules:
+ - host: mail...PLACEHOLDER_SECRET_DOMAIN..
+ http:
+ paths:
+ - path: /
+ pathType: ImplementationSpecific
+ backend:
+ service:
+ name: stalwart-stalwart-mail
+ port:
+ number: 80
+ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Architecture
Components
MAIL_VIP_GATEWAY(10.100.0.30), per-sender SMTP relay, Authentik-protected web UIFiles Changed (16 files, +805 lines)
cluster-settings.yaml— newMAIL_VIP_GATEWAY: 10.100.0.30selfhosted/kustomization.yaml— register 3 new appsstalwart/— ks.yaml, ocirepository, helmrelease, externalsecret, kustomizationemail-oauth2-proxy/— ks.yaml, helmrelease, externalsecret, configmap, kustomizationimapsync/— ks.yaml, helmrelease, externalsecret, kustomizationPre-deploy Checklist
STALWART_*prefix) for all ExternalSecret referencesTest Plan
kustomize buildpasses for all 3 apps (verified locally)🤖 Generated with Claude Code