From 25a43a7a403e8990335becc766d1ef21df29bc03 Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Fri, 30 May 2025 13:33:31 +0300 Subject: [PATCH 01/33] Add node selector to prevent mailu run on other workers --- manifests/mailu/values.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/manifests/mailu/values.yaml b/manifests/mailu/values.yaml index da69a54..4b85f1c 100644 --- a/manifests/mailu/values.yaml +++ b/manifests/mailu/values.yaml @@ -61,3 +61,6 @@ front: dkim: enabled: true + +nodeSelector: + kubernetes.io/hostname: k3s-master-1 From 66fb7ff8c7c3d924249e704d4b97326c1fa3ca0c Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Fri, 30 May 2025 13:34:06 +0300 Subject: [PATCH 02/33] Add node selector to prevent mailu run on other workers --- manifests/mailu/values.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/manifests/mailu/values.yaml b/manifests/mailu/values.yaml index 4b85f1c..29d7e65 100644 --- a/manifests/mailu/values.yaml +++ b/manifests/mailu/values.yaml @@ -58,9 +58,9 @@ front: manageSieve: false nodePorts: smtp: 31025 + nodeSelector: + kubernetes.io/hostname: k3s-master-1 dkim: enabled: true -nodeSelector: - kubernetes.io/hostname: k3s-master-1 From b6d2bc58f4bde5095f4267f5696d92a2ee6aa574 Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Fri, 30 May 2025 15:55:01 +0300 Subject: [PATCH 03/33] Set rc to 1 --- manifests/mailu/values.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/manifests/mailu/values.yaml b/manifests/mailu/values.yaml index 29d7e65..c999440 100644 --- a/manifests/mailu/values.yaml +++ b/manifests/mailu/values.yaml @@ -41,6 +41,7 @@ service: # type: ClusterIP front: + replicaCount: 1 realIpFrom: - 192.168.10.0/24 externalService: From f838769de26593128ba67924061212ac082ab41a Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Fri, 30 May 2025 16:12:11 +0300 Subject: [PATCH 04/33] Set rc to 1 --- manifests/mailu/values.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/manifests/mailu/values.yaml b/manifests/mailu/values.yaml index c999440..dc4cfc5 100644 --- a/manifests/mailu/values.yaml +++ b/manifests/mailu/values.yaml @@ -2,6 +2,8 @@ domain: dvirlabs.com hostnames: - mail.dvirlabs.com +replicaCount: 1 + ingress: enabled: true className: traefik @@ -41,7 +43,6 @@ service: # type: ClusterIP front: - replicaCount: 1 realIpFrom: - 192.168.10.0/24 externalService: From 50d0450d0cc96420d3bf4f929422f7563ffad14f Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Fri, 30 May 2025 16:41:16 +0300 Subject: [PATCH 05/33] Try smtp with metallb --- manifests/mailu/values.yaml | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/manifests/mailu/values.yaml b/manifests/mailu/values.yaml index dc4cfc5..f2cac08 100644 --- a/manifests/mailu/values.yaml +++ b/manifests/mailu/values.yaml @@ -39,30 +39,16 @@ service: type: ClusterIP port: 80 targetPort: 80 - # smtp: - # type: ClusterIP + + smtp: + type: LoadBalancer + externalTrafficPolicy: Cluster + port: 25 + targetPort: 25 front: realIpFrom: - 192.168.10.0/24 - externalService: - enabled: true - type: NodePort - externalTrafficPolicy: Cluster - ports: - smtp: true - smtps: false - submission: false - imap: false - imaps: false - pop3: false - pop3s: false - manageSieve: false - nodePorts: - smtp: 31025 - nodeSelector: - kubernetes.io/hostname: k3s-master-1 dkim: enabled: true - From 159be06f303de5d156b78aabbf220c53379f836f Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Fri, 30 May 2025 16:51:29 +0300 Subject: [PATCH 06/33] Try smtp with metallb --- manifests/mailu/values.yaml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/manifests/mailu/values.yaml b/manifests/mailu/values.yaml index f2cac08..c10488c 100644 --- a/manifests/mailu/values.yaml +++ b/manifests/mailu/values.yaml @@ -49,6 +49,19 @@ service: front: realIpFrom: - 192.168.10.0/24 + externalService: + enabled: true + type: LoadBalancer + externalTrafficPolicy: Cluster + ports: + smtp: true + smtps: false + submission: false + imap: false + imaps: false + pop3: false + pop3s: false + manageSieve: false dkim: enabled: true From de2a4364865559b1d8e443c229ac3df41120390f Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Fri, 30 May 2025 17:01:05 +0300 Subject: [PATCH 07/33] Try smtp with metallb --- manifests/mailu/values.yaml | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/manifests/mailu/values.yaml b/manifests/mailu/values.yaml index c10488c..242cbfa 100644 --- a/manifests/mailu/values.yaml +++ b/manifests/mailu/values.yaml @@ -10,7 +10,6 @@ ingress: annotations: traefik.ingress.kubernetes.io/router.entrypoints: "web,websecure" traefik.ingress.kubernetes.io/router.tls: "true" - nginx.ingress.kubernetes.io/backend-protocol: "HTTP" hosts: - host: mail.dvirlabs.com paths: @@ -34,18 +33,6 @@ tls: certmanager: enabled: true -service: - front: - type: ClusterIP - port: 80 - targetPort: 80 - - smtp: - type: LoadBalancer - externalTrafficPolicy: Cluster - port: 25 - targetPort: 25 - front: realIpFrom: - 192.168.10.0/24 @@ -55,13 +42,18 @@ front: externalTrafficPolicy: Cluster ports: smtp: true - smtps: false - submission: false - imap: false - imaps: false - pop3: false - pop3s: false - manageSieve: false + nodeSelector: {} # הסר את ההגבלה ל־master אם יש לך מספיק נודים + +# הסרת hostPort אם נתמך: +front: + containerPortsOverride: + smtp: null + smtps: null + smtpd: null + imap: null + imaps: null + pop3: null + pop3s: null dkim: enabled: true From 42aa26a886be8ece7f284fd5885a8cd98e2f5133 Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Fri, 30 May 2025 17:10:00 +0300 Subject: [PATCH 08/33] Try smtp with metallb --- manifests/mailu/values.yaml | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/manifests/mailu/values.yaml b/manifests/mailu/values.yaml index 242cbfa..297c557 100644 --- a/manifests/mailu/values.yaml +++ b/manifests/mailu/values.yaml @@ -42,18 +42,12 @@ front: externalTrafficPolicy: Cluster ports: smtp: true - nodeSelector: {} # הסר את ההגבלה ל־master אם יש לך מספיק נודים - -# הסרת hostPort אם נתמך: -front: - containerPortsOverride: - smtp: null - smtps: null - smtpd: null - imap: null - imaps: null - pop3: null - pop3s: null + submission: true + imap: true + imaps: true + pop3: false + pop3s: false + manageSieve: false dkim: enabled: true From dec65c3782afd160634f5ea7f897b3e7f93f7d0b Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Fri, 30 May 2025 17:23:30 +0300 Subject: [PATCH 09/33] Try smtp with metallb --- manifests/mailu/values.yaml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/manifests/mailu/values.yaml b/manifests/mailu/values.yaml index 297c557..8902bc7 100644 --- a/manifests/mailu/values.yaml +++ b/manifests/mailu/values.yaml @@ -34,8 +34,8 @@ tls: enabled: true front: - realIpFrom: - - 192.168.10.0/24 + nodeSelector: + node-role.kubernetes.io/worker: "true" externalService: enabled: true type: LoadBalancer @@ -45,9 +45,6 @@ front: submission: true imap: true imaps: true - pop3: false - pop3s: false - manageSieve: false dkim: enabled: true From 2503b5c64d99337e78739e8d0475ec8db1fcb71c Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Fri, 30 May 2025 17:36:46 +0300 Subject: [PATCH 10/33] Try smtp with metallb --- manifests/mailu/values.yaml | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/manifests/mailu/values.yaml b/manifests/mailu/values.yaml index 8902bc7..5bc4f9d 100644 --- a/manifests/mailu/values.yaml +++ b/manifests/mailu/values.yaml @@ -10,6 +10,7 @@ ingress: annotations: traefik.ingress.kubernetes.io/router.entrypoints: "web,websecure" traefik.ingress.kubernetes.io/router.tls: "true" + nginx.ingress.kubernetes.io/backend-protocol: "HTTP" hosts: - host: mail.dvirlabs.com paths: @@ -33,18 +34,30 @@ tls: certmanager: enabled: true +# Internal service (ClusterIP) +service: + front: + type: ClusterIP + port: 80 + targetPort: 80 + +# External access via MetalLB (LoadBalancer) front: - nodeSelector: - node-role.kubernetes.io/worker: "true" + realIpFrom: + - 192.168.10.0/24 externalService: enabled: true type: LoadBalancer externalTrafficPolicy: Cluster ports: - smtp: true - submission: true - imap: true - imaps: true + smtp: true # port 25 + submission: true # port 587 + imap: true # port 143 + imaps: true # port 993 + # Optional: You can manually specify a loadBalancerIP here if you want to fix the IP + # loadBalancerIP: 192.168.10.241 + nodeSelector: + node-role.kubernetes.io/worker: "true" dkim: enabled: true From a31c25b9d9a97f071f136b65596e15fb3bd182d3 Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Fri, 30 May 2025 17:44:59 +0300 Subject: [PATCH 11/33] Try smtp with metallb --- manifests/mailu/values.yaml | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/manifests/mailu/values.yaml b/manifests/mailu/values.yaml index 5bc4f9d..02643e2 100644 --- a/manifests/mailu/values.yaml +++ b/manifests/mailu/values.yaml @@ -34,30 +34,25 @@ tls: certmanager: enabled: true -# Internal service (ClusterIP) -service: - front: - type: ClusterIP - port: 80 - targetPort: 80 - -# External access via MetalLB (LoadBalancer) front: realIpFrom: - 192.168.10.0/24 + nodeSelector: + node-role.kubernetes.io/worker: "true" + externalService: enabled: true type: LoadBalancer externalTrafficPolicy: Cluster ports: - smtp: true # port 25 - submission: true # port 587 - imap: true # port 143 - imaps: true # port 993 - # Optional: You can manually specify a loadBalancerIP here if you want to fix the IP - # loadBalancerIP: 192.168.10.241 - nodeSelector: - node-role.kubernetes.io/worker: "true" + smtp: true + smtps: true + submission: true + imap: true + imaps: true + pop3: false + pop3s: false + manageSieve: false dkim: enabled: true From acbb87b64925843447d2ad0d986c5d456d8842d6 Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Fri, 30 May 2025 17:58:44 +0300 Subject: [PATCH 12/33] Try smtp with metallb --- manifests/mailu/values.yaml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/manifests/mailu/values.yaml b/manifests/mailu/values.yaml index 02643e2..f0a1f8a 100644 --- a/manifests/mailu/values.yaml +++ b/manifests/mailu/values.yaml @@ -34,12 +34,15 @@ tls: certmanager: enabled: true +service: + front: + type: ClusterIP + port: 80 + targetPort: 80 + front: realIpFrom: - 192.168.10.0/24 - nodeSelector: - node-role.kubernetes.io/worker: "true" - externalService: enabled: true type: LoadBalancer @@ -53,6 +56,8 @@ front: pop3: false pop3s: false manageSieve: false + nodeSelector: + kubernetes.io/hostname: k3s-worker-3 dkim: enabled: true From 4740d34d994d7962e25d64356288eb25e29d899d Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Fri, 30 May 2025 18:24:55 +0300 Subject: [PATCH 13/33] Try smtp with metallb --- manifests/mailu/values.yaml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/manifests/mailu/values.yaml b/manifests/mailu/values.yaml index f0a1f8a..1b448dc 100644 --- a/manifests/mailu/values.yaml +++ b/manifests/mailu/values.yaml @@ -43,21 +43,24 @@ service: front: realIpFrom: - 192.168.10.0/24 + externalService: enabled: true type: LoadBalancer - externalTrafficPolicy: Cluster + externalTrafficPolicy: Local + loadBalancerIP: 192.168.10.241 ports: smtp: true - smtps: true - submission: true - imap: true - imaps: true + smtps: false + submission: false + imap: false + imaps: false pop3: false pop3s: false manageSieve: false + nodeSelector: - kubernetes.io/hostname: k3s-worker-3 + node-role.kubernetes.io/worker: "" dkim: enabled: true From 88206b6bde91c9de8f033f7a62ab7d4aeb720e2b Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Fri, 30 May 2025 18:42:22 +0300 Subject: [PATCH 14/33] Try smtp with metallb --- manifests/mailu/values.yaml | 49 ++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/manifests/mailu/values.yaml b/manifests/mailu/values.yaml index 1b448dc..d353c0a 100644 --- a/manifests/mailu/values.yaml +++ b/manifests/mailu/values.yaml @@ -1,4 +1,5 @@ domain: dvirlabs.com + hostnames: - mail.dvirlabs.com @@ -28,27 +29,43 @@ persistence: admin: username: admin - initialPassword: "changeme123" + initialPassword: changeme123 + nodeSelector: + node-role.kubernetes.io/worker: "true" + tolerations: [] -tls: - certmanager: - enabled: true +webmail: + nodeSelector: + node-role.kubernetes.io/worker: "true" + tolerations: [] -service: - front: - type: ClusterIP - port: 80 - targetPort: 80 +oletools: + nodeSelector: + node-role.kubernetes.io/worker: "true" + tolerations: [] + +rspamd: + nodeSelector: + node-role.kubernetes.io/worker: "true" + tolerations: [] + +dovecot: + nodeSelector: + node-role.kubernetes.io/worker: "true" + tolerations: [] + +postfix: + nodeSelector: + node-role.kubernetes.io/worker: "true" + tolerations: [] front: realIpFrom: - 192.168.10.0/24 - externalService: enabled: true type: LoadBalancer - externalTrafficPolicy: Local - loadBalancerIP: 192.168.10.241 + externalTrafficPolicy: Cluster ports: smtp: true smtps: false @@ -58,9 +75,13 @@ front: pop3: false pop3s: false manageSieve: false - nodeSelector: - node-role.kubernetes.io/worker: "" + node-role.kubernetes.io/worker: "true" + tolerations: [] + +tls: + certmanager: + enabled: true dkim: enabled: true From a962db73c886a6754b4a991f9e98258fd60f4bbf Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Sun, 17 May 2026 08:02:27 +0300 Subject: [PATCH 15/33] Add snnapymail and stalwart --- MAIL_STACK_README.md | 529 ++++++++++++++++++++ QUICKSTART.md | 298 +++++++++++ argocd-apps/snappymail.yaml | 36 ++ argocd-apps/stalwart.yaml | 36 ++ charts/snappymail/Chart.yaml | 15 + charts/snappymail/templates/_helpers.tpl | 49 ++ charts/snappymail/templates/configmap.yaml | 15 + charts/snappymail/templates/deployment.yaml | 69 +++ charts/snappymail/templates/ingress.yaml | 42 ++ charts/snappymail/templates/pvc.yaml | 16 + charts/snappymail/templates/service.yaml | 16 + charts/snappymail/values.yaml | 86 ++++ charts/stalwart/Chart.yaml | 16 + charts/stalwart/templates/_helpers.tpl | 60 +++ charts/stalwart/templates/ingress.yaml | 42 ++ charts/stalwart/templates/namespace.yaml | 6 + charts/stalwart/templates/secret.yaml | 12 + charts/stalwart/templates/service.yaml | 36 ++ charts/stalwart/templates/statefulset.yaml | 94 ++++ charts/stalwart/values.yaml | 104 ++++ manifests/snappymail/values.yaml | 54 ++ manifests/stalwart/values.yaml | 54 ++ 22 files changed, 1685 insertions(+) create mode 100644 MAIL_STACK_README.md create mode 100644 QUICKSTART.md create mode 100644 argocd-apps/snappymail.yaml create mode 100644 argocd-apps/stalwart.yaml create mode 100644 charts/snappymail/Chart.yaml create mode 100644 charts/snappymail/templates/_helpers.tpl create mode 100644 charts/snappymail/templates/configmap.yaml create mode 100644 charts/snappymail/templates/deployment.yaml create mode 100644 charts/snappymail/templates/ingress.yaml create mode 100644 charts/snappymail/templates/pvc.yaml create mode 100644 charts/snappymail/templates/service.yaml create mode 100644 charts/snappymail/values.yaml create mode 100644 charts/stalwart/Chart.yaml create mode 100644 charts/stalwart/templates/_helpers.tpl create mode 100644 charts/stalwart/templates/ingress.yaml create mode 100644 charts/stalwart/templates/namespace.yaml create mode 100644 charts/stalwart/templates/secret.yaml create mode 100644 charts/stalwart/templates/service.yaml create mode 100644 charts/stalwart/templates/statefulset.yaml create mode 100644 charts/stalwart/values.yaml create mode 100644 manifests/snappymail/values.yaml create mode 100644 manifests/stalwart/values.yaml diff --git a/MAIL_STACK_README.md b/MAIL_STACK_README.md new file mode 100644 index 0000000..4e5956a --- /dev/null +++ b/MAIL_STACK_README.md @@ -0,0 +1,529 @@ +# Lightweight Mail Stack for k3s GitOps Lab + +Complete deployment of **Stalwart Mail Server** + **SnappyMail** webmail using GitOps with ArgoCD. + +## 📋 Overview + +This repository deploys a lightweight, modern mail stack designed for self-hosting and lab environments: + +- **Stalwart Mail Server**: All-in-one mail server (SMTP, IMAP, Admin UI) +- **SnappyMail**: Modern, lightweight webmail client +- **GitOps**: Managed by ArgoCD +- **Storage**: NFS-based persistent volumes +- **Ingress**: Traefik for web UI access + +## 🏗️ Architecture + +``` +┌─────────────────────────────────────────────────┐ +│ Traefik Ingress │ +│ mail.dvirlabs.com webmail.dvirlabs.com │ +└───────────┬──────────────────────┬──────────────┘ + │ │ + │ │ + ┌───────▼────────┐ ┌────────▼────────┐ + │ Stalwart │◄───│ SnappyMail │ + │ Mail Server │ │ Webmail │ + │ │ │ │ + │ • SMTP │ │ Connects via: │ + │ • IMAP │ │ • IMAP:993 │ + │ • Admin UI │ │ • SMTP:587 │ + └────────┬───────┘ └─────────────────┘ + │ + │ + ┌────────▼───────┐ + │ NFS Storage │ + │ Mail Data │ + └────────────────┘ +``` + +## 📁 Repository Structure + +``` +mail-services/ +├── argocd-apps/ +│ ├── stalwart.yaml # ArgoCD Application for Stalwart +│ └── snappymail.yaml # ArgoCD Application for SnappyMail +├── charts/ +│ ├── stalwart/ # Local Helm chart for Stalwart +│ │ ├── Chart.yaml +│ │ ├── values.yaml # Default values +│ │ └── templates/ +│ │ ├── namespace.yaml +│ │ ├── secret.yaml +│ │ ├── statefulset.yaml +│ │ ├── service.yaml +│ │ └── ingress.yaml +│ └── snappymail/ # Local Helm chart for SnappyMail +│ ├── Chart.yaml +│ ├── values.yaml # Default values +│ └── templates/ +│ ├── deployment.yaml +│ ├── pvc.yaml +│ ├── service.yaml +│ ├── ingress.yaml +│ └── configmap.yaml +└── manifests/ + ├── stalwart/ + │ └── values.yaml # Custom values for dvirlabs.com + └── snappymail/ + └── values.yaml # Custom values for dvirlabs.com +``` + +## 🚀 Quick Start + +### Prerequisites + +- k3s cluster running +- ArgoCD installed and configured +- Traefik ingress controller +- NFS storage class (`nfs-client`) +- DNS records pointing to your cluster + +### Step 1: Update Configuration + +1. **Update ArgoCD Application manifests** with your Git repository URL: + +```bash +# Edit both files and replace YOUR_USERNAME with your actual repo +vim argocd-apps/stalwart.yaml +vim argocd-apps/snappymail.yaml +``` + +2. **Change the Stalwart admin password**: + +```bash +# Edit and set a strong password +vim manifests/stalwart/values.yaml +``` + +Find this section and change `CHANGE_ME_PLEASE_USE_STRONG_PASSWORD`: + +```yaml +secret: + create: true + name: stalwart-credentials + adminPassword: "YOUR_STRONG_PASSWORD_HERE" +``` + +3. **Update domain names** (if not using dvirlabs.com): + +```bash +# Update in both files +vim manifests/stalwart/values.yaml +vim manifests/snappymail/values.yaml +``` + +### Step 2: Deploy with ArgoCD + +```bash +# Apply ArgoCD Applications +kubectl apply -f argocd-apps/stalwart.yaml +kubectl apply -f argocd-apps/snappymail.yaml + +# Check deployment status +kubectl get applications -n argocd + +# Watch pods come up +kubectl get pods -n mail -w +``` + +### Step 3: Verify Deployment + +```bash +# Check all resources in mail namespace +kubectl get all -n mail + +# Check PVCs +kubectl get pvc -n mail + +# Check ingresses +kubectl get ingress -n mail +``` + +Expected output: +``` +NAME READY STATUS RESTARTS AGE +pod/stalwart-0 1/1 Running 0 2m +pod/snappymail-xxx-xxx 1/1 Running 0 2m + +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) +service/stalwart ClusterIP 10.43.x.x 8080/TCP,25/TCP,587/TCP,993/TCP +service/snappymail ClusterIP 10.43.x.x 8888/TCP + +NAME CLASS HOSTS +ingress.networking.k8s.io/stalwart traefik mail.dvirlabs.com +ingress.networking.k8s.io/snappymail traefik webmail.dvirlabs.com +``` + +## 🌐 Access the Services + +### Stalwart Admin UI + +URL: `https://mail.dvirlabs.com` + +Default credentials: +- Username: `admin@dvirlabs.com` +- Password: (the one you set in manifests/stalwart/values.yaml) + +### SnappyMail Webmail + +URL: `https://webmail.dvirlabs.com` + +First-time setup: +1. Access the admin panel: `https://webmail.dvirlabs.com/?admin` +2. Default admin password: `12345` (change immediately!) +3. Configure mail server connection: + - **IMAP Server**: `stalwart.mail.svc.cluster.local` + - **IMAP Port**: `993` + - **IMAP Security**: SSL/TLS + - **SMTP Server**: `stalwart.mail.svc.cluster.local` + - **SMTP Port**: `587` + - **SMTP Security**: STARTTLS + +## 📧 Configuring Real Mail Service + +### Important: Cloudflare Tunnel Limitations + +⚠️ **WARNING**: While Cloudflare Tunnel works fine for web UIs (admin panel and webmail), it **CANNOT** be used for actual email protocols (SMTP/IMAP). + +**What works through Cloudflare Tunnel:** +- ✅ Stalwart admin UI (HTTPS) +- ✅ SnappyMail webmail (HTTPS) + +**What does NOT work through Cloudflare Tunnel:** +- ❌ Receiving mail from other servers (SMTP port 25) +- ❌ Sending mail to other servers (SMTP port 25) +- ❌ External email clients (IMAP/SMTP) + +### Required for Real Email + +To receive and send real email, you need: + +#### 1. DNS Records + +```dns +; MX Record (Mail Exchange) +@ IN MX 10 mail.dvirlabs.com. + +; A Record (pointing to your public IP - NOT Cloudflare Tunnel) +mail IN A YOUR_PUBLIC_IP + +; SPF Record (Sender Policy Framework) +@ IN TXT "v=spf1 mx ~all" + +; DMARC Record +_dmarc IN TXT "v=DMARC1; p=quarantine; rua=mailto:admin@dvirlabs.com" + +; DKIM Record (generated by Stalwart) +; Get this from Stalwart admin UI after setup +default._domainkey IN TXT "v=DKIM1; k=rsa; p=YOUR_PUBLIC_KEY_HERE" +``` + +#### 2. Port Forwarding + +You need to expose these ports directly (NOT through Cloudflare): + +``` +Port 25 (SMTP) - Required for receiving mail from other servers +Port 587 (SMTP) - Required for sending mail (submission) +Port 465 (SMTPS) - Optional, secure SMTP submission +Port 993 (IMAPS) - Required for IMAP access +Port 143 (IMAP) - Optional, plaintext IMAP +``` + +**Option A: NodePort Service** + +```bash +kubectl apply -f - < mail.dvirlabs.com +``` + +This is **critical** for email deliverability. Without it, many servers will reject your mail. + +## 🔧 Configuration Management + +### Using External Secrets (Recommended for Production) + +Instead of storing passwords in Git, use External Secrets Operator: + +1. Install External Secrets Operator +2. Create a secret in your secret backend (Vault, AWS Secrets Manager, etc.) +3. Update manifests/stalwart/values.yaml: + +```yaml +secret: + create: false # Don't create the secret + name: stalwart-credentials # Reference external secret +``` + +4. Create an ExternalSecret: + +```yaml +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: stalwart-credentials + namespace: mail +spec: + refreshInterval: 1h + secretStoreRef: + name: your-secret-store + kind: SecretStore + target: + name: stalwart-credentials + data: + - secretKey: STALWART_ADMIN_PASSWORD + remoteRef: + key: mail/stalwart/admin-password +``` + +## 🛠️ Maintenance + +### View Stalwart Logs + +```bash +kubectl logs -n mail stalwart-0 -f +``` + +### View SnappyMail Logs + +```bash +kubectl logs -n mail -l app.kubernetes.io/name=snappymail -f +``` + +### Access Stalwart Shell + +```bash +kubectl exec -it -n mail stalwart-0 -- /bin/sh +``` + +### Backup Mail Data + +```bash +# Backup Stalwart data +kubectl exec -n mail stalwart-0 -- tar czf /tmp/mail-backup.tar.gz /opt/stalwart-mail +kubectl cp mail/stalwart-0:/tmp/mail-backup.tar.gz ./mail-backup-$(date +%Y%m%d).tar.gz + +# Backup SnappyMail config +kubectl exec -n mail -l app.kubernetes.io/name=snappymail -- tar czf /tmp/snappymail-backup.tar.gz /var/lib/snappymail +kubectl cp mail/snappymail-xxx:/tmp/snappymail-backup.tar.gz ./snappymail-backup-$(date +%Y%m%d).tar.gz +``` + +### Restore from Backup + +```bash +# Restore Stalwart +kubectl cp ./mail-backup.tar.gz mail/stalwart-0:/tmp/mail-backup.tar.gz +kubectl exec -n mail stalwart-0 -- tar xzf /tmp/mail-backup.tar.gz -C / +kubectl rollout restart statefulset -n mail stalwart +``` + +## 🔍 Troubleshooting + +### Pods Not Starting + +```bash +# Check pod events +kubectl describe pod -n mail stalwart-0 +kubectl describe pod -n mail -l app.kubernetes.io/name=snappymail + +# Check PVC status +kubectl get pvc -n mail +``` + +### Ingress Not Working + +```bash +# Check ingress status +kubectl describe ingress -n mail + +# Check Traefik logs +kubectl logs -n kube-system -l app.kubernetes.io/name=traefik + +# Test internal connectivity +kubectl run -it --rm debug --image=busybox -n mail -- wget -O- http://stalwart:8080 +``` + +### SnappyMail Can't Connect to Stalwart + +```bash +# Test IMAP connectivity from SnappyMail pod +kubectl exec -it -n mail -l app.kubernetes.io/name=snappymail -- nc -zv stalwart.mail.svc.cluster.local 993 + +# Check Stalwart service +kubectl get svc -n mail stalwart +``` + +### Email Not Being Delivered + +Common issues: +1. **No PTR record**: Check reverse DNS +2. **Port 25 blocked**: Many ISPs block outbound port 25 +3. **Missing SPF/DKIM/DMARC**: Check DNS records +4. **IP on blacklist**: Check https://mxtoolbox.com/blacklists.aspx + +## 📊 Monitoring + +### Check Mail Queue + +```bash +# Access Stalwart admin UI +# https://mail.dvirlabs.com +# Navigate to Queue section +``` + +### Resource Usage + +```bash +# Check pod resource usage +kubectl top pods -n mail + +# Check PVC usage +kubectl exec -n mail stalwart-0 -- df -h /opt/stalwart-mail +``` + +## 🔐 Security Hardening + +### Recommended Post-Deployment Steps + +1. **Change SnappyMail admin password** immediately +2. **Enable fail2ban** for brute force protection +3. **Set up TLS certificates** with cert-manager (if not using Cloudflare) +4. **Enable DKIM signing** in Stalwart +5. **Configure rate limiting** in Stalwart +6. **Regular backups** of mail data +7. **Monitor logs** for suspicious activity + +### TLS Certificates with cert-manager + +If you want Let's Encrypt certificates instead of Cloudflare: + +```yaml +# Add to ingress annotations +cert-manager.io/cluster-issuer: letsencrypt-prod +``` + +And configure TLS: + +```yaml +tls: + - hosts: + - mail.dvirlabs.com + secretName: stalwart-tls +``` + +## 📚 Additional Resources + +- [Stalwart Documentation](https://stalw.art/docs) +- [SnappyMail Documentation](https://snappymail.eu/) +- [Email Deliverability Best Practices](https://www.mail-tester.com/) +- [DKIM Setup Guide](https://www.cloudflare.com/learning/dns/dns-records/dns-dkim-record/) + +## ⚙️ Customization + +### Adjust Storage Size + +Edit `manifests/stalwart/values.yaml` or `manifests/snappymail/values.yaml`: + +```yaml +persistence: + size: 50Gi # Increase as needed +``` + +### Change Resource Limits + +Edit `manifests/*/values.yaml`: + +```yaml +resources: + requests: + memory: "2Gi" + cpu: "1000m" + limits: + memory: "8Gi" + cpu: "4000m" +``` + +### Add Multiple Domains + +Configure in Stalwart admin UI after deployment. + +## 🤝 Contributing + +This is a personal lab setup, but feel free to fork and adapt for your needs! + +## 📝 License + +MIT License - Use at your own risk + +## ⚠️ Disclaimer + +This setup is designed for lab/self-hosting environments. For production use: +- Use External Secrets for credentials +- Set up proper TLS certificates +- Configure backup automation +- Enable monitoring and alerting +- Review security best practices +- Test email deliverability thoroughly diff --git a/QUICKSTART.md b/QUICKSTART.md new file mode 100644 index 0000000..880bd11 --- /dev/null +++ b/QUICKSTART.md @@ -0,0 +1,298 @@ +# Quick Start Guide - Stalwart + SnappyMail Mail Stack + +## 📋 What Was Created + +A complete GitOps-ready mail stack with: +- ✅ Stalwart Mail Server (all-in-one: SMTP, IMAP, Admin UI) +- ✅ SnappyMail webmail client +- ✅ Local Helm charts for both applications +- ✅ ArgoCD Application manifests +- ✅ Custom values files for dvirlabs.com +- ✅ All manifests validated successfully + +## 📁 File Structure Created + +``` +mail-services/ +├── argocd-apps/ +│ ├── stalwart.yaml # ⚠️ UPDATE: Change repo URL +│ └── snappymail.yaml # ⚠️ UPDATE: Change repo URL +│ +├── charts/ +│ ├── stalwart/ # Local Helm chart for Stalwart +│ │ ├── Chart.yaml +│ │ ├── values.yaml +│ │ └── templates/ +│ │ ├── _helpers.tpl +│ │ ├── namespace.yaml +│ │ ├── secret.yaml +│ │ ├── statefulset.yaml +│ │ ├── service.yaml +│ │ └── ingress.yaml +│ │ +│ └── snappymail/ # Local Helm chart for SnappyMail +│ ├── Chart.yaml +│ ├── values.yaml +│ └── templates/ +│ ├── _helpers.tpl +│ ├── deployment.yaml +│ ├── pvc.yaml +│ ├── service.yaml +│ ├── ingress.yaml +│ └── configmap.yaml +│ +├── manifests/ +│ ├── stalwart/ +│ │ └── values.yaml # ⚠️ UPDATE: Change admin password +│ └── snappymail/ +│ └── values.yaml +│ +├── MAIL_STACK_README.md # 📖 Full documentation +└── QUICKSTART.md # 👈 This file +``` + +## ⚠️ REQUIRED CHANGES Before Deployment + +### 1. Update Git Repository URL + +Edit these files and replace `YOUR_USERNAME` with your actual Git username/organization: + +**File: `argocd-apps/stalwart.yaml`** +```yaml +source: + repoURL: https://github.com/YOUR_USERNAME/mail-services.git # ← CHANGE THIS +``` + +**File: `argocd-apps/snappymail.yaml`** +```yaml +source: + repoURL: https://github.com/YOUR_USERNAME/mail-services.git # ← CHANGE THIS +``` + +### 2. Change Admin Password (CRITICAL!) + +Edit `manifests/stalwart/values.yaml`: + +Find this section: +```yaml +secret: + create: true + name: stalwart-credentials + adminPassword: "CHANGE_ME_PLEASE_USE_STRONG_PASSWORD" # ← CHANGE THIS! +``` + +Replace with a strong password: +```yaml + adminPassword: "MyStr0ng!P@ssw0rd#2024" +``` + +**⚠️ DO NOT commit this file with the default password!** + +### 3. (Optional) Update Domain Names + +If you're not using `dvirlabs.com`, update these files: + +**`manifests/stalwart/values.yaml`:** +```yaml +ingress: + hosts: + - host: mail.YOUR-DOMAIN.com # ← Update +``` + +**`manifests/snappymail/values.yaml`:** +```yaml +ingress: + hosts: + - host: webmail.YOUR-DOMAIN.com # ← Update +``` + +## 🚀 Deployment Steps + +### Step 1: Commit and Push to Git + +```bash +cd c:\Users\dvirl\OneDrive\Desktop\gitea\mail-services + +# Review changes +git status + +# Add new files +git add argocd-apps/stalwart.yaml +git add argocd-apps/snappymail.yaml +git add charts/stalwart/ +git add charts/snappymail/ +git add manifests/stalwart/ +git add manifests/snappymail/ +git add MAIL_STACK_README.md +git add QUICKSTART.md + +# Commit +git commit -m "Add Stalwart Mail Server + SnappyMail stack" + +# Push to your Git server +git push origin main +``` + +### Step 2: Deploy with ArgoCD + +```bash +# Apply ArgoCD Applications +kubectl apply -f argocd-apps/stalwart.yaml +kubectl apply -f argocd-apps/snappymail.yaml + +# Watch ArgoCD sync +kubectl get applications -n argocd -w + +# Watch pods come up +kubectl get pods -n mail -w +``` + +### Step 3: Verify Deployment + +```bash +# Check all resources +kubectl get all -n mail + +# Expected output: +# - statefulset.apps/stalwart (1/1) +# - deployment.apps/snappymail (1/1) +# - service/stalwart +# - service/snappymail +# - ingress.networking.k8s.io/stalwart +# - ingress.networking.k8s.io/snappymail + +# Check PVCs +kubectl get pvc -n mail + +# Check logs +kubectl logs -n mail stalwart-0 +kubectl logs -n mail -l app.kubernetes.io/name=snappymail +``` + +## 🌐 Access the Services + +### Stalwart Admin UI +- URL: `https://mail.dvirlabs.com` +- Username: `admin@dvirlabs.com` +- Password: (what you set in manifests/stalwart/values.yaml) + +### SnappyMail Webmail +- URL: `https://webmail.dvirlabs.com` +- First access: Admin panel at `https://webmail.dvirlabs.com/?admin` +- Default admin password: `12345` (CHANGE IMMEDIATELY!) + +## ⚙️ SnappyMail Configuration + +After deployment, configure SnappyMail to connect to Stalwart: + +1. Go to `https://webmail.dvirlabs.com/?admin` +2. Login with default password `12345` +3. Change admin password immediately +4. Go to **Domains** → **Add Domain** +5. Configure: + - **IMAP Server:** `stalwart.mail.svc.cluster.local` + - **IMAP Port:** `993` + - **IMAP Secure:** `SSL/TLS` + - **SMTP Server:** `stalwart.mail.svc.cluster.local` + - **SMTP Port:** `587` + - **SMTP Secure:** `STARTTLS` + +## 📧 Setting Up Real Email + +### DNS Records Needed + +```dns +; MX Record +@ IN MX 10 mail.dvirlabs.com. + +; A Record (use your public IP, NOT Cloudflare proxy) +mail IN A YOUR_PUBLIC_IP + +; SPF Record +@ IN TXT "v=spf1 mx ~all" + +; DMARC Record +_dmarc IN TXT "v=DMARC1; p=quarantine; rua=mailto:admin@dvirlabs.com" +``` + +### Port Forwarding Required + +For real email (not just webmail), you need to expose these ports directly: + +``` +Port 25 (SMTP) - Receiving mail +Port 587 (SMTP) - Sending mail +Port 993 (IMAPS) - IMAP access +``` + +**⚠️ Important:** These ports CANNOT go through Cloudflare Tunnel! + +## 🔍 Troubleshooting + +### Pods stuck in Pending +```bash +# Check PVC status +kubectl describe pvc -n mail + +# Check if nfs-client storage class exists +kubectl get storageclass +``` + +### Can't access web UIs +```bash +# Check ingress +kubectl describe ingress -n mail + +# Check if DNS resolves to your cluster +nslookup mail.dvirlabs.com +nslookup webmail.dvirlabs.com +``` + +### SnappyMail can't connect to Stalwart +```bash +# Test connectivity from SnappyMail pod +kubectl exec -it -n mail deploy/snappymail -- nc -zv stalwart.mail.svc.cluster.local 993 +``` + +## 📖 Full Documentation + +See [MAIL_STACK_README.md](MAIL_STACK_README.md) for: +- Complete architecture overview +- External mail setup instructions +- Security hardening guide +- Backup and restore procedures +- Advanced configuration options +- External Secrets integration + +## ✅ Validation Results + +All manifests have been validated: +- ✅ Stalwart Helm chart renders correctly +- ✅ SnappyMail Helm chart renders correctly +- ✅ ArgoCD Application manifests are valid +- ✅ All Kubernetes resources are syntactically correct + +## 🎯 Next Steps + +1. **Update repo URL** in ArgoCD manifests ← DO THIS FIRST! +2. **Change admin password** in manifests/stalwart/values.yaml +3. **Commit and push** to Git +4. **Apply ArgoCD applications** +5. **Wait for deployment** (2-3 minutes) +6. **Access Stalwart admin UI** and configure mail settings +7. **Configure SnappyMail** to connect to Stalwart +8. **Set up DNS records** for real email +9. **Configure port forwarding** for mail protocols + +## 💡 Pro Tips + +- Start with web UIs only, add real mail later +- Use External Secrets for production passwords +- Enable DKIM in Stalwart for better deliverability +- Monitor logs during first email tests +- Test with mail-tester.com for deliverability score +- Backup mail data regularly + +--- + +**Need help?** Check [MAIL_STACK_README.md](MAIL_STACK_README.md) for detailed documentation. diff --git a/argocd-apps/snappymail.yaml b/argocd-apps/snappymail.yaml new file mode 100644 index 0000000..e78165d --- /dev/null +++ b/argocd-apps/snappymail.yaml @@ -0,0 +1,36 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: snappymail + namespace: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io +spec: + project: default + + source: + repoURL: https://github.com/YOUR_USERNAME/mail-services.git # TODO: Update with your repo URL + targetRevision: HEAD + path: charts/snappymail + helm: + valueFiles: + - ../../manifests/snappymail/values.yaml + + destination: + server: https://kubernetes.default.svc + namespace: mail + + syncPolicy: + automated: + prune: true + selfHeal: true + allowEmpty: false + syncOptions: + - CreateNamespace=true + - ServerSideApply=true + retry: + limit: 5 + backoff: + duration: 5s + factor: 2 + maxDuration: 3m diff --git a/argocd-apps/stalwart.yaml b/argocd-apps/stalwart.yaml new file mode 100644 index 0000000..6e5ad96 --- /dev/null +++ b/argocd-apps/stalwart.yaml @@ -0,0 +1,36 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: stalwart + namespace: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io +spec: + project: default + + source: + repoURL: https://github.com/YOUR_USERNAME/mail-services.git # TODO: Update with your repo URL + targetRevision: HEAD + path: charts/stalwart + helm: + valueFiles: + - ../../manifests/stalwart/values.yaml + + destination: + server: https://kubernetes.default.svc + namespace: mail + + syncPolicy: + automated: + prune: true + selfHeal: true + allowEmpty: false + syncOptions: + - CreateNamespace=true + - ServerSideApply=true + retry: + limit: 5 + backoff: + duration: 5s + factor: 2 + maxDuration: 3m diff --git a/charts/snappymail/Chart.yaml b/charts/snappymail/Chart.yaml new file mode 100644 index 0000000..5b53815 --- /dev/null +++ b/charts/snappymail/Chart.yaml @@ -0,0 +1,15 @@ +apiVersion: v2 +name: snappymail +description: SnappyMail - Simple, modern, lightweight webmail client +type: application +version: 1.0.0 +appVersion: "2.39.1" +keywords: + - webmail + - mail + - snappymail +home: https://snappymail.eu +sources: + - https://github.com/the-djmaze/snappymail +maintainers: + - name: dvirlabs diff --git a/charts/snappymail/templates/_helpers.tpl b/charts/snappymail/templates/_helpers.tpl new file mode 100644 index 0000000..d9a3dae --- /dev/null +++ b/charts/snappymail/templates/_helpers.tpl @@ -0,0 +1,49 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "snappymail.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +*/}} +{{- define "snappymail.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "snappymail.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "snappymail.labels" -}} +helm.sh/chart: {{ include "snappymail.chart" . }} +{{ include "snappymail.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "snappymail.selectorLabels" -}} +app.kubernetes.io/name: {{ include "snappymail.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} diff --git a/charts/snappymail/templates/configmap.yaml b/charts/snappymail/templates/configmap.yaml new file mode 100644 index 0000000..ffc3fba --- /dev/null +++ b/charts/snappymail/templates/configmap.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "snappymail.fullname" . }}-config + namespace: {{ .Values.namespace }} + labels: + {{- include "snappymail.labels" . | nindent 4 }} +data: + # Stalwart mail server connection info + # This can be used for documentation or manual configuration + # SnappyMail is configured through its web UI + IMAP_HOST: {{ .Values.stalwart.imap.host | quote }} + IMAP_PORT: {{ .Values.stalwart.imap.port | quote }} + SMTP_HOST: {{ .Values.stalwart.smtp.host | quote }} + SMTP_PORT: {{ .Values.stalwart.smtp.port | quote }} diff --git a/charts/snappymail/templates/deployment.yaml b/charts/snappymail/templates/deployment.yaml new file mode 100644 index 0000000..e486518 --- /dev/null +++ b/charts/snappymail/templates/deployment.yaml @@ -0,0 +1,69 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "snappymail.fullname" . }} + namespace: {{ .Values.namespace }} + labels: + {{- include "snappymail.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + {{- include "snappymail.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "snappymail.selectorLabels" . | nindent 8 }} + spec: + securityContext: + {{- toYaml .Values.securityContext | nindent 8 }} + containers: + - name: snappymail + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: {{ .Values.service.targetPort }} + protocol: TCP + volumeMounts: + - name: data + mountPath: {{ .Values.persistence.mountPath }} + resources: + {{- toYaml .Values.resources | nindent 10 }} + livenessProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 30 + periodSeconds: 10 + readinessProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 10 + periodSeconds: 5 + {{- with .Values.env }} + env: + {{- toYaml . | nindent 10 }} + {{- end }} + volumes: + {{- if .Values.persistence.enabled }} + - name: data + persistentVolumeClaim: + claimName: {{ include "snappymail.fullname" . }} + {{- else }} + - name: data + emptyDir: {} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/snappymail/templates/ingress.yaml b/charts/snappymail/templates/ingress.yaml new file mode 100644 index 0000000..b2e6271 --- /dev/null +++ b/charts/snappymail/templates/ingress.yaml @@ -0,0 +1,42 @@ +{{- if .Values.ingress.enabled -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "snappymail.fullname" . }} + namespace: {{ .Values.namespace }} + labels: + {{- include "snappymail.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.ingress.className }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ .pathType }} + backend: + service: + name: {{ include "snappymail.fullname" $ }} + port: + number: {{ $.Values.service.port }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/snappymail/templates/pvc.yaml b/charts/snappymail/templates/pvc.yaml new file mode 100644 index 0000000..1faa2d9 --- /dev/null +++ b/charts/snappymail/templates/pvc.yaml @@ -0,0 +1,16 @@ +{{- if .Values.persistence.enabled }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ include "snappymail.fullname" . }} + namespace: {{ .Values.namespace }} + labels: + {{- include "snappymail.labels" . | nindent 4 }} +spec: + accessModes: + - {{ .Values.persistence.accessMode }} + storageClassName: {{ .Values.persistence.storageClass }} + resources: + requests: + storage: {{ .Values.persistence.size }} +{{- end }} diff --git a/charts/snappymail/templates/service.yaml b/charts/snappymail/templates/service.yaml new file mode 100644 index 0000000..ed656f0 --- /dev/null +++ b/charts/snappymail/templates/service.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "snappymail.fullname" . }} + namespace: {{ .Values.namespace }} + labels: + {{- include "snappymail.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: {{ .Values.service.targetPort }} + protocol: TCP + name: http + selector: + {{- include "snappymail.selectorLabels" . | nindent 4 }} diff --git a/charts/snappymail/values.yaml b/charts/snappymail/values.yaml new file mode 100644 index 0000000..88a93eb --- /dev/null +++ b/charts/snappymail/values.yaml @@ -0,0 +1,86 @@ +## SnappyMail webmail configuration +## Default values for snappymail chart + +## Image configuration +image: + repository: djmaze/snappymail + tag: "2.39" + pullPolicy: IfNotPresent + +## Namespace +namespace: mail + +## Replica count +replicaCount: 1 + +## Service configuration +service: + type: ClusterIP + port: 8888 + targetPort: 8888 + +## Ingress configuration +ingress: + enabled: true + className: traefik + annotations: + traefik.ingress.kubernetes.io/router.entrypoints: websecure + traefik.ingress.kubernetes.io/router.tls: "true" + hosts: + - host: webmail.dvirlabs.com + paths: + - path: / + pathType: Prefix + tls: [] + +## Persistence configuration for SnappyMail data +persistence: + enabled: true + storageClass: nfs-client + accessMode: ReadWriteOnce + size: 1Gi + # Where SnappyMail stores its data + mountPath: /var/lib/snappymail + +## Resource limits +resources: + requests: + memory: "128Mi" + cpu: "100m" + limits: + memory: "512Mi" + cpu: "500m" + +## Stalwart mail server configuration +## SnappyMail will connect to Stalwart internally +stalwart: + # Service name of Stalwart in the same namespace + serviceName: stalwart + # IMAP configuration + imap: + host: stalwart.mail.svc.cluster.local + port: 993 + secure: true + # SMTP configuration + smtp: + host: stalwart.mail.svc.cluster.local + port: 587 + secure: true + +## Environment variables +env: {} + +## Pod Security Context +securityContext: + fsGroup: 82 # www-data group in Alpine + runAsUser: 82 + runAsNonRoot: true + +## Node selector +nodeSelector: {} + +## Tolerations +tolerations: [] + +## Affinity +affinity: {} diff --git a/charts/stalwart/Chart.yaml b/charts/stalwart/Chart.yaml new file mode 100644 index 0000000..121654f --- /dev/null +++ b/charts/stalwart/Chart.yaml @@ -0,0 +1,16 @@ +apiVersion: v2 +name: stalwart +description: Stalwart Mail Server - Modern all-in-one mail server +type: application +version: 1.0.0 +appVersion: "0.10.8" +keywords: + - mail + - smtp + - imap + - stalwart +home: https://stalw.art +sources: + - https://github.com/stalwartlabs/mail-server +maintainers: + - name: dvirlabs diff --git a/charts/stalwart/templates/_helpers.tpl b/charts/stalwart/templates/_helpers.tpl new file mode 100644 index 0000000..590f7a2 --- /dev/null +++ b/charts/stalwart/templates/_helpers.tpl @@ -0,0 +1,60 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "stalwart.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +*/}} +{{- define "stalwart.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "stalwart.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "stalwart.labels" -}} +helm.sh/chart: {{ include "stalwart.chart" . }} +{{ include "stalwart.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "stalwart.selectorLabels" -}} +app.kubernetes.io/name: {{ include "stalwart.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "stalwart.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "stalwart.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/charts/stalwart/templates/ingress.yaml b/charts/stalwart/templates/ingress.yaml new file mode 100644 index 0000000..56fc127 --- /dev/null +++ b/charts/stalwart/templates/ingress.yaml @@ -0,0 +1,42 @@ +{{- if .Values.ingress.enabled -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "stalwart.fullname" . }} + namespace: {{ .Values.namespace }} + labels: + {{- include "stalwart.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.ingress.className }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ .pathType }} + backend: + service: + name: {{ include "stalwart.fullname" $ }} + port: + number: {{ .servicePort }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/stalwart/templates/namespace.yaml b/charts/stalwart/templates/namespace.yaml new file mode 100644 index 0000000..bb65df0 --- /dev/null +++ b/charts/stalwart/templates/namespace.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: {{ .Values.namespace }} + labels: + {{- include "stalwart.labels" . | nindent 4 }} diff --git a/charts/stalwart/templates/secret.yaml b/charts/stalwart/templates/secret.yaml new file mode 100644 index 0000000..c829de1 --- /dev/null +++ b/charts/stalwart/templates/secret.yaml @@ -0,0 +1,12 @@ +{{- if .Values.secret.create }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Values.secret.name }} + namespace: {{ .Values.namespace }} + labels: + {{- include "stalwart.labels" . | nindent 4 }} +type: Opaque +stringData: + STALWART_ADMIN_PASSWORD: {{ .Values.secret.adminPassword | quote }} +{{- end }} diff --git a/charts/stalwart/templates/service.yaml b/charts/stalwart/templates/service.yaml new file mode 100644 index 0000000..38f1147 --- /dev/null +++ b/charts/stalwart/templates/service.yaml @@ -0,0 +1,36 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "stalwart.fullname" . }} + namespace: {{ .Values.namespace }} + labels: + {{- include "stalwart.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.web.port }} + targetPort: {{ .Values.service.web.targetPort }} + protocol: TCP + name: web + - port: {{ .Values.service.smtp.port }} + targetPort: {{ .Values.service.smtp.targetPort }} + protocol: TCP + name: smtp + - port: {{ .Values.service.smtps.port }} + targetPort: {{ .Values.service.smtps.targetPort }} + protocol: TCP + name: smtps + - port: {{ .Values.service.submission.port }} + targetPort: {{ .Values.service.submission.targetPort }} + protocol: TCP + name: submission + - port: {{ .Values.service.imap.port }} + targetPort: {{ .Values.service.imap.targetPort }} + protocol: TCP + name: imap + - port: {{ .Values.service.imaps.port }} + targetPort: {{ .Values.service.imaps.targetPort }} + protocol: TCP + name: imaps + selector: + {{- include "stalwart.selectorLabels" . | nindent 4 }} diff --git a/charts/stalwart/templates/statefulset.yaml b/charts/stalwart/templates/statefulset.yaml new file mode 100644 index 0000000..70318a4 --- /dev/null +++ b/charts/stalwart/templates/statefulset.yaml @@ -0,0 +1,94 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ include "stalwart.fullname" . }} + namespace: {{ .Values.namespace }} + labels: + {{- include "stalwart.labels" . | nindent 4 }} +spec: + serviceName: {{ include "stalwart.fullname" . }} + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + {{- include "stalwart.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "stalwart.selectorLabels" . | nindent 8 }} + spec: + securityContext: + {{- toYaml .Values.securityContext | nindent 8 }} + containers: + - name: stalwart + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: web + containerPort: {{ .Values.service.web.targetPort }} + protocol: TCP + - name: smtp + containerPort: {{ .Values.service.smtp.targetPort }} + protocol: TCP + - name: smtps + containerPort: {{ .Values.service.smtps.targetPort }} + protocol: TCP + - name: submission + containerPort: {{ .Values.service.submission.targetPort }} + protocol: TCP + - name: imap + containerPort: {{ .Values.service.imap.targetPort }} + protocol: TCP + - name: imaps + containerPort: {{ .Values.service.imaps.targetPort }} + protocol: TCP + env: + - name: STALWART_ADMIN_USER + value: {{ .Values.env.STALWART_ADMIN_USER | quote }} + - name: STALWART_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.secret.name }} + key: STALWART_ADMIN_PASSWORD + volumeMounts: + - name: data + mountPath: {{ .Values.persistence.mountPath }} + resources: + {{- toYaml .Values.resources | nindent 10 }} + livenessProbe: + httpGet: + path: / + port: web + initialDelaySeconds: 30 + periodSeconds: 10 + readinessProbe: + httpGet: + path: / + port: web + initialDelaySeconds: 10 + periodSeconds: 5 + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.persistence.enabled }} + volumeClaimTemplates: + - metadata: + name: data + labels: + {{- include "stalwart.labels" . | nindent 8 }} + spec: + accessModes: + - {{ .Values.persistence.accessMode }} + storageClassName: {{ .Values.persistence.storageClass }} + resources: + requests: + storage: {{ .Values.persistence.size }} + {{- end }} diff --git a/charts/stalwart/values.yaml b/charts/stalwart/values.yaml new file mode 100644 index 0000000..6fca9dc --- /dev/null +++ b/charts/stalwart/values.yaml @@ -0,0 +1,104 @@ +## Stalwart Mail Server configuration +## Default values for stalwart chart + +## Image configuration +image: + repository: stalwartlabs/mail-server + tag: v0.10.8 + pullPolicy: IfNotPresent + +## Namespace +namespace: mail + +## Replica count (should be 1 for StatefulSet with persistent data) +replicaCount: 1 + +## Service configuration +service: + type: ClusterIP + # Admin/Web UI port + web: + port: 8080 + targetPort: 8080 + # SMTP ports + smtp: + port: 25 + targetPort: 25 + smtps: + port: 465 + targetPort: 465 + submission: + port: 587 + targetPort: 587 + # IMAP ports + imap: + port: 143 + targetPort: 143 + imaps: + port: 993 + targetPort: 993 + +## Ingress configuration for admin UI +ingress: + enabled: true + className: traefik + annotations: + traefik.ingress.kubernetes.io/router.entrypoints: websecure + traefik.ingress.kubernetes.io/router.tls: "true" + hosts: + - host: mail.dvirlabs.com + paths: + - path: / + pathType: Prefix + servicePort: 8080 + tls: [] + +## Persistence configuration +persistence: + enabled: true + storageClass: nfs-client + accessMode: ReadWriteOnce + size: 10Gi + # Where Stalwart stores mail data + mountPath: /opt/stalwart-mail + +## Resource limits +resources: + requests: + memory: "512Mi" + cpu: "250m" + limits: + memory: "2Gi" + cpu: "1000m" + +## Environment variables for Stalwart configuration +env: + # Admin credentials - CHANGE THESE! + # Or reference a secret using envFrom + STALWART_ADMIN_USER: "admin@dvirlabs.com" + # Password should come from a secret + # STALWART_ADMIN_PASSWORD: defined in secret + +## Secret configuration +secret: + # Set to true to create a secret + create: true + # Name of the secret (if create: false, this should reference an existing secret) + name: stalwart-credentials + # Admin password - CHANGE THIS or use external secrets later + adminPassword: "CHANGE_ME_PLEASE" + +## Pod Security Context +securityContext: + fsGroup: 1000 + runAsUser: 1000 + runAsNonRoot: true + +## Node selector +nodeSelector: {} + +## Tolerations +tolerations: [] + +## Affinity +affinity: {} diff --git a/manifests/snappymail/values.yaml b/manifests/snappymail/values.yaml new file mode 100644 index 0000000..de5783e --- /dev/null +++ b/manifests/snappymail/values.yaml @@ -0,0 +1,54 @@ +## SnappyMail - Custom values for dvirlabs.com +## Override default chart values here + +## Namespace +namespace: mail + +## Image configuration +image: + repository: djmaze/snappymail + tag: "2.39" + pullPolicy: IfNotPresent + +## Persistence - using NFS storage +persistence: + enabled: true + storageClass: nfs-client + accessMode: ReadWriteOnce + size: 2Gi + mountPath: /var/lib/snappymail + +## Ingress for webmail UI +ingress: + enabled: true + className: traefik + annotations: + traefik.ingress.kubernetes.io/router.entrypoints: websecure + traefik.ingress.kubernetes.io/router.tls: "true" + hosts: + - host: webmail.dvirlabs.com + paths: + - path: / + pathType: Prefix + +## Stalwart mail server connection +## SnappyMail will connect to Stalwart internally +stalwart: + serviceName: stalwart + imap: + host: stalwart.mail.svc.cluster.local + port: 993 + secure: true + smtp: + host: stalwart.mail.svc.cluster.local + port: 587 + secure: true + +## Resource allocation +resources: + requests: + memory: "256Mi" + cpu: "200m" + limits: + memory: "1Gi" + cpu: "1000m" diff --git a/manifests/stalwart/values.yaml b/manifests/stalwart/values.yaml new file mode 100644 index 0000000..733afd2 --- /dev/null +++ b/manifests/stalwart/values.yaml @@ -0,0 +1,54 @@ +## Stalwart Mail Server - Custom values for dvirlabs.com +## Override default chart values here + +## Namespace +namespace: mail + +## Image configuration +image: + repository: stalwartlabs/mail-server + tag: v0.10.8 + pullPolicy: IfNotPresent + +## Persistence - using NFS storage +persistence: + enabled: true + storageClass: nfs-client + accessMode: ReadWriteOnce + size: 20Gi # Increased for production mail storage + mountPath: /opt/stalwart-mail + +## Ingress for admin UI only +ingress: + enabled: true + className: traefik + annotations: + traefik.ingress.kubernetes.io/router.entrypoints: websecure + traefik.ingress.kubernetes.io/router.tls: "true" + hosts: + - host: mail.dvirlabs.com + paths: + - path: / + pathType: Prefix + servicePort: 8080 + +## Admin credentials +env: + STALWART_ADMIN_USER: "admin@dvirlabs.com" + +## Secret configuration +## IMPORTANT: Change the adminPassword before deploying! +secret: + create: true + name: stalwart-credentials + # TODO: Replace with a strong password or use External Secrets + adminPassword: "CHANGE_ME_PLEASE_USE_STRONG_PASSWORD" + +## Resource allocation +resources: + requests: + memory: "1Gi" + cpu: "500m" + limits: + memory: "4Gi" + cpu: "2000m" From 154439047a1d6ece01b2ed3dcfd5db3d40dd950d Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Sun, 17 May 2026 08:03:24 +0300 Subject: [PATCH 16/33] Comment old mail services --- argocd-apps/mailu-certificates.yaml | 40 +++++++++++++-------------- argocd-apps/mailu.yaml | 42 ++++++++++++++--------------- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/argocd-apps/mailu-certificates.yaml b/argocd-apps/mailu-certificates.yaml index 17ed852..67050f6 100644 --- a/argocd-apps/mailu-certificates.yaml +++ b/argocd-apps/mailu-certificates.yaml @@ -1,20 +1,20 @@ -apiVersion: argoproj.io/v1alpha1 -kind: Application -metadata: - name: mailu-certificates - namespace: argocd -spec: - project: mail-services - source: - repoURL: 'https://git.dvirlabs.com/dvirlabs/mail-services.git' - targetRevision: HEAD - path: manifests/mailu - directory: - recurse: true - destination: - server: https://kubernetes.default.svc - namespace: mail-services - syncPolicy: - automated: - prune: true - selfHeal: true +# apiVersion: argoproj.io/v1alpha1 +# kind: Application +# metadata: +# name: mailu-certificates +# namespace: argocd +# spec: +# project: mail-services +# source: +# repoURL: 'https://git.dvirlabs.com/dvirlabs/mail-services.git' +# targetRevision: HEAD +# path: manifests/mailu +# directory: +# recurse: true +# destination: +# server: https://kubernetes.default.svc +# namespace: mail-services +# syncPolicy: +# automated: +# prune: true +# selfHeal: true diff --git a/argocd-apps/mailu.yaml b/argocd-apps/mailu.yaml index b82c64c..c0aa454 100644 --- a/argocd-apps/mailu.yaml +++ b/argocd-apps/mailu.yaml @@ -1,21 +1,21 @@ -apiVersion: argoproj.io/v1alpha1 -kind: Application -metadata: - name: mailu - namespace: argocd -spec: - project: mail-services - source: - repoURL: 'https://git.dvirlabs.com/dvirlabs/mail-services.git' - targetRevision: HEAD - path: charts/mailu - helm: - valueFiles: - - ../../manifests/mailu/values.yaml - destination: - server: https://kubernetes.default.svc - namespace: mail-services - syncPolicy: - automated: - prune: true - selfHeal: true +# apiVersion: argoproj.io/v1alpha1 +# kind: Application +# metadata: +# name: mailu +# namespace: argocd +# spec: +# project: mail-services +# source: +# repoURL: 'https://git.dvirlabs.com/dvirlabs/mail-services.git' +# targetRevision: HEAD +# path: charts/mailu +# helm: +# valueFiles: +# - ../../manifests/mailu/values.yaml +# destination: +# server: https://kubernetes.default.svc +# namespace: mail-services +# syncPolicy: +# automated: +# prune: true +# selfHeal: true From de40f4efe4ecf373324d74a80d01f0bd5e69c553 Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Sun, 17 May 2026 08:06:24 +0300 Subject: [PATCH 17/33] Comment old mail services --- {argocd-apps => old}/mailu-certificates.yaml | 0 {argocd-apps => old}/mailu.yaml | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {argocd-apps => old}/mailu-certificates.yaml (100%) rename {argocd-apps => old}/mailu.yaml (100%) diff --git a/argocd-apps/mailu-certificates.yaml b/old/mailu-certificates.yaml similarity index 100% rename from argocd-apps/mailu-certificates.yaml rename to old/mailu-certificates.yaml diff --git a/argocd-apps/mailu.yaml b/old/mailu.yaml similarity index 100% rename from argocd-apps/mailu.yaml rename to old/mailu.yaml From d2409835616a7ceacfbb4451793e07d4ecf1b555 Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Sun, 17 May 2026 08:09:36 +0300 Subject: [PATCH 18/33] Move old mailu chart to old/ directory - switching to Stalwart+SnappyMail --- {charts/mailu => old/mailu-chart}/CHANGELOG.md | 0 {charts/mailu => old/mailu-chart}/Chart.lock | 0 {charts/mailu => old/mailu-chart}/Chart.yaml | 0 {charts/mailu => old/mailu-chart}/MIGRATION_GUIDE.md | 0 {charts/mailu => old/mailu-chart}/README.md | 0 {charts/mailu => old/mailu-chart}/ci/helm-lint-values.yaml | 0 {charts/mailu => old/mailu-chart}/linter_values.yaml | 0 {charts/mailu => old/mailu-chart}/templates/NOTES.txt | 0 {charts/mailu => old/mailu-chart}/templates/_claims.tpl | 0 {charts/mailu => old/mailu-chart}/templates/_database.tpl | 0 {charts/mailu => old/mailu-chart}/templates/_helpers.tpl | 0 {charts/mailu => old/mailu-chart}/templates/_secrets.tpl | 0 {charts/mailu => old/mailu-chart}/templates/_services.tpl | 0 {charts/mailu => old/mailu-chart}/templates/admin/deployment.yaml | 0 {charts/mailu => old/mailu-chart}/templates/admin/pvc.yaml | 0 {charts/mailu => old/mailu-chart}/templates/admin/service.yaml | 0 .../mailu-chart}/templates/clamav/service-headless.yaml | 0 {charts/mailu => old/mailu-chart}/templates/clamav/service.yaml | 0 .../mailu => old/mailu-chart}/templates/clamav/statefulset.yaml | 0 .../mailu => old/mailu-chart}/templates/dovecot/configmap.yaml | 0 .../mailu => old/mailu-chart}/templates/dovecot/deployment.yaml | 0 {charts/mailu => old/mailu-chart}/templates/dovecot/pvc.yaml | 0 {charts/mailu => old/mailu-chart}/templates/dovecot/service.yaml | 0 .../mailu => old/mailu-chart}/templates/envvars-configmap.yaml | 0 .../mailu => old/mailu-chart}/templates/fetchmail/deployment.yaml | 0 {charts/mailu => old/mailu-chart}/templates/fetchmail/pvc.yaml | 0 {charts/mailu => old/mailu-chart}/templates/front/deployment.yaml | 0 {charts/mailu => old/mailu-chart}/templates/front/ingress.yaml | 0 .../mailu-chart}/templates/front/service-external.yaml | 0 {charts/mailu => old/mailu-chart}/templates/front/service.yaml | 0 {charts/mailu => old/mailu-chart}/templates/network-policies.yaml | 0 .../mailu => old/mailu-chart}/templates/oletools/deployment.yaml | 0 {charts/mailu => old/mailu-chart}/templates/oletools/service.yaml | 0 .../mailu => old/mailu-chart}/templates/postfix/configmap.yaml | 0 .../mailu => old/mailu-chart}/templates/postfix/deployment.yaml | 0 {charts/mailu => old/mailu-chart}/templates/postfix/pvc.yaml | 0 {charts/mailu => old/mailu-chart}/templates/postfix/service.yaml | 0 {charts/mailu => old/mailu-chart}/templates/pv-hostpath.yaml | 0 {charts/mailu => old/mailu-chart}/templates/pvc.yaml | 0 {charts/mailu => old/mailu-chart}/templates/rspamd/configmap.yaml | 0 .../mailu => old/mailu-chart}/templates/rspamd/deployment.yaml | 0 {charts/mailu => old/mailu-chart}/templates/rspamd/pvc.yaml | 0 {charts/mailu => old/mailu-chart}/templates/rspamd/service.yaml | 0 {charts/mailu => old/mailu-chart}/templates/secret-api.yaml | 0 .../mailu => old/mailu-chart}/templates/secret-external-db.yaml | 0 .../mailu-chart}/templates/secret-external-relay.yaml | 0 .../mailu-chart}/templates/secret-initial-account.yaml | 0 .../mailu => old/mailu-chart}/templates/secret-key-secret.yaml | 0 {charts/mailu => old/mailu-chart}/templates/secrets-tls.yaml | 0 {charts/mailu => old/mailu-chart}/templates/tika/deployment.yaml | 0 {charts/mailu => old/mailu-chart}/templates/tika/service.yaml | 0 .../mailu => old/mailu-chart}/templates/webdav/deployment.yaml | 0 {charts/mailu => old/mailu-chart}/templates/webdav/pvc.yaml | 0 {charts/mailu => old/mailu-chart}/templates/webdav/service.yaml | 0 .../mailu => old/mailu-chart}/templates/webmail/deployment.yaml | 0 {charts/mailu => old/mailu-chart}/templates/webmail/pvc.yaml | 0 {charts/mailu => old/mailu-chart}/templates/webmail/secret.yaml | 0 {charts/mailu => old/mailu-chart}/templates/webmail/service.yaml | 0 {charts/mailu => old/mailu-chart}/values.yaml | 0 59 files changed, 0 insertions(+), 0 deletions(-) rename {charts/mailu => old/mailu-chart}/CHANGELOG.md (100%) rename {charts/mailu => old/mailu-chart}/Chart.lock (100%) rename {charts/mailu => old/mailu-chart}/Chart.yaml (100%) rename {charts/mailu => old/mailu-chart}/MIGRATION_GUIDE.md (100%) rename {charts/mailu => old/mailu-chart}/README.md (100%) rename {charts/mailu => old/mailu-chart}/ci/helm-lint-values.yaml (100%) rename {charts/mailu => old/mailu-chart}/linter_values.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/NOTES.txt (100%) rename {charts/mailu => old/mailu-chart}/templates/_claims.tpl (100%) rename {charts/mailu => old/mailu-chart}/templates/_database.tpl (100%) rename {charts/mailu => old/mailu-chart}/templates/_helpers.tpl (100%) rename {charts/mailu => old/mailu-chart}/templates/_secrets.tpl (100%) rename {charts/mailu => old/mailu-chart}/templates/_services.tpl (100%) rename {charts/mailu => old/mailu-chart}/templates/admin/deployment.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/admin/pvc.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/admin/service.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/clamav/service-headless.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/clamav/service.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/clamav/statefulset.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/dovecot/configmap.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/dovecot/deployment.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/dovecot/pvc.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/dovecot/service.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/envvars-configmap.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/fetchmail/deployment.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/fetchmail/pvc.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/front/deployment.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/front/ingress.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/front/service-external.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/front/service.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/network-policies.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/oletools/deployment.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/oletools/service.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/postfix/configmap.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/postfix/deployment.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/postfix/pvc.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/postfix/service.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/pv-hostpath.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/pvc.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/rspamd/configmap.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/rspamd/deployment.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/rspamd/pvc.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/rspamd/service.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/secret-api.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/secret-external-db.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/secret-external-relay.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/secret-initial-account.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/secret-key-secret.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/secrets-tls.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/tika/deployment.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/tika/service.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/webdav/deployment.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/webdav/pvc.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/webdav/service.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/webmail/deployment.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/webmail/pvc.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/webmail/secret.yaml (100%) rename {charts/mailu => old/mailu-chart}/templates/webmail/service.yaml (100%) rename {charts/mailu => old/mailu-chart}/values.yaml (100%) diff --git a/charts/mailu/CHANGELOG.md b/old/mailu-chart/CHANGELOG.md similarity index 100% rename from charts/mailu/CHANGELOG.md rename to old/mailu-chart/CHANGELOG.md diff --git a/charts/mailu/Chart.lock b/old/mailu-chart/Chart.lock similarity index 100% rename from charts/mailu/Chart.lock rename to old/mailu-chart/Chart.lock diff --git a/charts/mailu/Chart.yaml b/old/mailu-chart/Chart.yaml similarity index 100% rename from charts/mailu/Chart.yaml rename to old/mailu-chart/Chart.yaml diff --git a/charts/mailu/MIGRATION_GUIDE.md b/old/mailu-chart/MIGRATION_GUIDE.md similarity index 100% rename from charts/mailu/MIGRATION_GUIDE.md rename to old/mailu-chart/MIGRATION_GUIDE.md diff --git a/charts/mailu/README.md b/old/mailu-chart/README.md similarity index 100% rename from charts/mailu/README.md rename to old/mailu-chart/README.md diff --git a/charts/mailu/ci/helm-lint-values.yaml b/old/mailu-chart/ci/helm-lint-values.yaml similarity index 100% rename from charts/mailu/ci/helm-lint-values.yaml rename to old/mailu-chart/ci/helm-lint-values.yaml diff --git a/charts/mailu/linter_values.yaml b/old/mailu-chart/linter_values.yaml similarity index 100% rename from charts/mailu/linter_values.yaml rename to old/mailu-chart/linter_values.yaml diff --git a/charts/mailu/templates/NOTES.txt b/old/mailu-chart/templates/NOTES.txt similarity index 100% rename from charts/mailu/templates/NOTES.txt rename to old/mailu-chart/templates/NOTES.txt diff --git a/charts/mailu/templates/_claims.tpl b/old/mailu-chart/templates/_claims.tpl similarity index 100% rename from charts/mailu/templates/_claims.tpl rename to old/mailu-chart/templates/_claims.tpl diff --git a/charts/mailu/templates/_database.tpl b/old/mailu-chart/templates/_database.tpl similarity index 100% rename from charts/mailu/templates/_database.tpl rename to old/mailu-chart/templates/_database.tpl diff --git a/charts/mailu/templates/_helpers.tpl b/old/mailu-chart/templates/_helpers.tpl similarity index 100% rename from charts/mailu/templates/_helpers.tpl rename to old/mailu-chart/templates/_helpers.tpl diff --git a/charts/mailu/templates/_secrets.tpl b/old/mailu-chart/templates/_secrets.tpl similarity index 100% rename from charts/mailu/templates/_secrets.tpl rename to old/mailu-chart/templates/_secrets.tpl diff --git a/charts/mailu/templates/_services.tpl b/old/mailu-chart/templates/_services.tpl similarity index 100% rename from charts/mailu/templates/_services.tpl rename to old/mailu-chart/templates/_services.tpl diff --git a/charts/mailu/templates/admin/deployment.yaml b/old/mailu-chart/templates/admin/deployment.yaml similarity index 100% rename from charts/mailu/templates/admin/deployment.yaml rename to old/mailu-chart/templates/admin/deployment.yaml diff --git a/charts/mailu/templates/admin/pvc.yaml b/old/mailu-chart/templates/admin/pvc.yaml similarity index 100% rename from charts/mailu/templates/admin/pvc.yaml rename to old/mailu-chart/templates/admin/pvc.yaml diff --git a/charts/mailu/templates/admin/service.yaml b/old/mailu-chart/templates/admin/service.yaml similarity index 100% rename from charts/mailu/templates/admin/service.yaml rename to old/mailu-chart/templates/admin/service.yaml diff --git a/charts/mailu/templates/clamav/service-headless.yaml b/old/mailu-chart/templates/clamav/service-headless.yaml similarity index 100% rename from charts/mailu/templates/clamav/service-headless.yaml rename to old/mailu-chart/templates/clamav/service-headless.yaml diff --git a/charts/mailu/templates/clamav/service.yaml b/old/mailu-chart/templates/clamav/service.yaml similarity index 100% rename from charts/mailu/templates/clamav/service.yaml rename to old/mailu-chart/templates/clamav/service.yaml diff --git a/charts/mailu/templates/clamav/statefulset.yaml b/old/mailu-chart/templates/clamav/statefulset.yaml similarity index 100% rename from charts/mailu/templates/clamav/statefulset.yaml rename to old/mailu-chart/templates/clamav/statefulset.yaml diff --git a/charts/mailu/templates/dovecot/configmap.yaml b/old/mailu-chart/templates/dovecot/configmap.yaml similarity index 100% rename from charts/mailu/templates/dovecot/configmap.yaml rename to old/mailu-chart/templates/dovecot/configmap.yaml diff --git a/charts/mailu/templates/dovecot/deployment.yaml b/old/mailu-chart/templates/dovecot/deployment.yaml similarity index 100% rename from charts/mailu/templates/dovecot/deployment.yaml rename to old/mailu-chart/templates/dovecot/deployment.yaml diff --git a/charts/mailu/templates/dovecot/pvc.yaml b/old/mailu-chart/templates/dovecot/pvc.yaml similarity index 100% rename from charts/mailu/templates/dovecot/pvc.yaml rename to old/mailu-chart/templates/dovecot/pvc.yaml diff --git a/charts/mailu/templates/dovecot/service.yaml b/old/mailu-chart/templates/dovecot/service.yaml similarity index 100% rename from charts/mailu/templates/dovecot/service.yaml rename to old/mailu-chart/templates/dovecot/service.yaml diff --git a/charts/mailu/templates/envvars-configmap.yaml b/old/mailu-chart/templates/envvars-configmap.yaml similarity index 100% rename from charts/mailu/templates/envvars-configmap.yaml rename to old/mailu-chart/templates/envvars-configmap.yaml diff --git a/charts/mailu/templates/fetchmail/deployment.yaml b/old/mailu-chart/templates/fetchmail/deployment.yaml similarity index 100% rename from charts/mailu/templates/fetchmail/deployment.yaml rename to old/mailu-chart/templates/fetchmail/deployment.yaml diff --git a/charts/mailu/templates/fetchmail/pvc.yaml b/old/mailu-chart/templates/fetchmail/pvc.yaml similarity index 100% rename from charts/mailu/templates/fetchmail/pvc.yaml rename to old/mailu-chart/templates/fetchmail/pvc.yaml diff --git a/charts/mailu/templates/front/deployment.yaml b/old/mailu-chart/templates/front/deployment.yaml similarity index 100% rename from charts/mailu/templates/front/deployment.yaml rename to old/mailu-chart/templates/front/deployment.yaml diff --git a/charts/mailu/templates/front/ingress.yaml b/old/mailu-chart/templates/front/ingress.yaml similarity index 100% rename from charts/mailu/templates/front/ingress.yaml rename to old/mailu-chart/templates/front/ingress.yaml diff --git a/charts/mailu/templates/front/service-external.yaml b/old/mailu-chart/templates/front/service-external.yaml similarity index 100% rename from charts/mailu/templates/front/service-external.yaml rename to old/mailu-chart/templates/front/service-external.yaml diff --git a/charts/mailu/templates/front/service.yaml b/old/mailu-chart/templates/front/service.yaml similarity index 100% rename from charts/mailu/templates/front/service.yaml rename to old/mailu-chart/templates/front/service.yaml diff --git a/charts/mailu/templates/network-policies.yaml b/old/mailu-chart/templates/network-policies.yaml similarity index 100% rename from charts/mailu/templates/network-policies.yaml rename to old/mailu-chart/templates/network-policies.yaml diff --git a/charts/mailu/templates/oletools/deployment.yaml b/old/mailu-chart/templates/oletools/deployment.yaml similarity index 100% rename from charts/mailu/templates/oletools/deployment.yaml rename to old/mailu-chart/templates/oletools/deployment.yaml diff --git a/charts/mailu/templates/oletools/service.yaml b/old/mailu-chart/templates/oletools/service.yaml similarity index 100% rename from charts/mailu/templates/oletools/service.yaml rename to old/mailu-chart/templates/oletools/service.yaml diff --git a/charts/mailu/templates/postfix/configmap.yaml b/old/mailu-chart/templates/postfix/configmap.yaml similarity index 100% rename from charts/mailu/templates/postfix/configmap.yaml rename to old/mailu-chart/templates/postfix/configmap.yaml diff --git a/charts/mailu/templates/postfix/deployment.yaml b/old/mailu-chart/templates/postfix/deployment.yaml similarity index 100% rename from charts/mailu/templates/postfix/deployment.yaml rename to old/mailu-chart/templates/postfix/deployment.yaml diff --git a/charts/mailu/templates/postfix/pvc.yaml b/old/mailu-chart/templates/postfix/pvc.yaml similarity index 100% rename from charts/mailu/templates/postfix/pvc.yaml rename to old/mailu-chart/templates/postfix/pvc.yaml diff --git a/charts/mailu/templates/postfix/service.yaml b/old/mailu-chart/templates/postfix/service.yaml similarity index 100% rename from charts/mailu/templates/postfix/service.yaml rename to old/mailu-chart/templates/postfix/service.yaml diff --git a/charts/mailu/templates/pv-hostpath.yaml b/old/mailu-chart/templates/pv-hostpath.yaml similarity index 100% rename from charts/mailu/templates/pv-hostpath.yaml rename to old/mailu-chart/templates/pv-hostpath.yaml diff --git a/charts/mailu/templates/pvc.yaml b/old/mailu-chart/templates/pvc.yaml similarity index 100% rename from charts/mailu/templates/pvc.yaml rename to old/mailu-chart/templates/pvc.yaml diff --git a/charts/mailu/templates/rspamd/configmap.yaml b/old/mailu-chart/templates/rspamd/configmap.yaml similarity index 100% rename from charts/mailu/templates/rspamd/configmap.yaml rename to old/mailu-chart/templates/rspamd/configmap.yaml diff --git a/charts/mailu/templates/rspamd/deployment.yaml b/old/mailu-chart/templates/rspamd/deployment.yaml similarity index 100% rename from charts/mailu/templates/rspamd/deployment.yaml rename to old/mailu-chart/templates/rspamd/deployment.yaml diff --git a/charts/mailu/templates/rspamd/pvc.yaml b/old/mailu-chart/templates/rspamd/pvc.yaml similarity index 100% rename from charts/mailu/templates/rspamd/pvc.yaml rename to old/mailu-chart/templates/rspamd/pvc.yaml diff --git a/charts/mailu/templates/rspamd/service.yaml b/old/mailu-chart/templates/rspamd/service.yaml similarity index 100% rename from charts/mailu/templates/rspamd/service.yaml rename to old/mailu-chart/templates/rspamd/service.yaml diff --git a/charts/mailu/templates/secret-api.yaml b/old/mailu-chart/templates/secret-api.yaml similarity index 100% rename from charts/mailu/templates/secret-api.yaml rename to old/mailu-chart/templates/secret-api.yaml diff --git a/charts/mailu/templates/secret-external-db.yaml b/old/mailu-chart/templates/secret-external-db.yaml similarity index 100% rename from charts/mailu/templates/secret-external-db.yaml rename to old/mailu-chart/templates/secret-external-db.yaml diff --git a/charts/mailu/templates/secret-external-relay.yaml b/old/mailu-chart/templates/secret-external-relay.yaml similarity index 100% rename from charts/mailu/templates/secret-external-relay.yaml rename to old/mailu-chart/templates/secret-external-relay.yaml diff --git a/charts/mailu/templates/secret-initial-account.yaml b/old/mailu-chart/templates/secret-initial-account.yaml similarity index 100% rename from charts/mailu/templates/secret-initial-account.yaml rename to old/mailu-chart/templates/secret-initial-account.yaml diff --git a/charts/mailu/templates/secret-key-secret.yaml b/old/mailu-chart/templates/secret-key-secret.yaml similarity index 100% rename from charts/mailu/templates/secret-key-secret.yaml rename to old/mailu-chart/templates/secret-key-secret.yaml diff --git a/charts/mailu/templates/secrets-tls.yaml b/old/mailu-chart/templates/secrets-tls.yaml similarity index 100% rename from charts/mailu/templates/secrets-tls.yaml rename to old/mailu-chart/templates/secrets-tls.yaml diff --git a/charts/mailu/templates/tika/deployment.yaml b/old/mailu-chart/templates/tika/deployment.yaml similarity index 100% rename from charts/mailu/templates/tika/deployment.yaml rename to old/mailu-chart/templates/tika/deployment.yaml diff --git a/charts/mailu/templates/tika/service.yaml b/old/mailu-chart/templates/tika/service.yaml similarity index 100% rename from charts/mailu/templates/tika/service.yaml rename to old/mailu-chart/templates/tika/service.yaml diff --git a/charts/mailu/templates/webdav/deployment.yaml b/old/mailu-chart/templates/webdav/deployment.yaml similarity index 100% rename from charts/mailu/templates/webdav/deployment.yaml rename to old/mailu-chart/templates/webdav/deployment.yaml diff --git a/charts/mailu/templates/webdav/pvc.yaml b/old/mailu-chart/templates/webdav/pvc.yaml similarity index 100% rename from charts/mailu/templates/webdav/pvc.yaml rename to old/mailu-chart/templates/webdav/pvc.yaml diff --git a/charts/mailu/templates/webdav/service.yaml b/old/mailu-chart/templates/webdav/service.yaml similarity index 100% rename from charts/mailu/templates/webdav/service.yaml rename to old/mailu-chart/templates/webdav/service.yaml diff --git a/charts/mailu/templates/webmail/deployment.yaml b/old/mailu-chart/templates/webmail/deployment.yaml similarity index 100% rename from charts/mailu/templates/webmail/deployment.yaml rename to old/mailu-chart/templates/webmail/deployment.yaml diff --git a/charts/mailu/templates/webmail/pvc.yaml b/old/mailu-chart/templates/webmail/pvc.yaml similarity index 100% rename from charts/mailu/templates/webmail/pvc.yaml rename to old/mailu-chart/templates/webmail/pvc.yaml diff --git a/charts/mailu/templates/webmail/secret.yaml b/old/mailu-chart/templates/webmail/secret.yaml similarity index 100% rename from charts/mailu/templates/webmail/secret.yaml rename to old/mailu-chart/templates/webmail/secret.yaml diff --git a/charts/mailu/templates/webmail/service.yaml b/old/mailu-chart/templates/webmail/service.yaml similarity index 100% rename from charts/mailu/templates/webmail/service.yaml rename to old/mailu-chart/templates/webmail/service.yaml diff --git a/charts/mailu/values.yaml b/old/mailu-chart/values.yaml similarity index 100% rename from charts/mailu/values.yaml rename to old/mailu-chart/values.yaml From c99d81708ba5641b3c8f98521fda0e858ee89070 Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Sun, 17 May 2026 08:11:07 +0300 Subject: [PATCH 19/33] Update ArgoCD repo URLs to git.dvirlabs.com --- argocd-apps/snappymail.yaml | 2 +- argocd-apps/stalwart.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/argocd-apps/snappymail.yaml b/argocd-apps/snappymail.yaml index e78165d..76c7fae 100644 --- a/argocd-apps/snappymail.yaml +++ b/argocd-apps/snappymail.yaml @@ -9,7 +9,7 @@ spec: project: default source: - repoURL: https://github.com/YOUR_USERNAME/mail-services.git # TODO: Update with your repo URL + repoURL: https://git.dvirlabs.com/dvirlabs/mail-services.git targetRevision: HEAD path: charts/snappymail helm: diff --git a/argocd-apps/stalwart.yaml b/argocd-apps/stalwart.yaml index 6e5ad96..80123e9 100644 --- a/argocd-apps/stalwart.yaml +++ b/argocd-apps/stalwart.yaml @@ -9,7 +9,7 @@ spec: project: default source: - repoURL: https://github.com/YOUR_USERNAME/mail-services.git # TODO: Update with your repo URL + repoURL: https://git.dvirlabs.com/dvirlabs/mail-services.git targetRevision: HEAD path: charts/stalwart helm: From 28cf53fd7627edd4367526cd32b2d94dc5e2b6e1 Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Sun, 17 May 2026 08:12:25 +0300 Subject: [PATCH 20/33] Fix: Use 'latest' image tags for Stalwart and SnappyMail --- manifests/snappymail/values.yaml | 2 +- manifests/stalwart/values.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/manifests/snappymail/values.yaml b/manifests/snappymail/values.yaml index de5783e..f3cbe3a 100644 --- a/manifests/snappymail/values.yaml +++ b/manifests/snappymail/values.yaml @@ -7,7 +7,7 @@ namespace: mail ## Image configuration image: repository: djmaze/snappymail - tag: "2.39" + tag: latest pullPolicy: IfNotPresent ## Persistence - using NFS storage diff --git a/manifests/stalwart/values.yaml b/manifests/stalwart/values.yaml index 733afd2..3cb659b 100644 --- a/manifests/stalwart/values.yaml +++ b/manifests/stalwart/values.yaml @@ -7,7 +7,7 @@ namespace: mail ## Image configuration image: repository: stalwartlabs/mail-server - tag: v0.10.8 + tag: latest pullPolicy: IfNotPresent ## Persistence - using NFS storage From 8099a64c9d06f0e6f16e7343028dbfa9baba8263 Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Sun, 17 May 2026 08:13:18 +0300 Subject: [PATCH 21/33] Fix: Remove restrictive security contexts to allow containers to run --- charts/snappymail/values.yaml | 4 +--- charts/stalwart/values.yaml | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/charts/snappymail/values.yaml b/charts/snappymail/values.yaml index 88a93eb..5c3a18b 100644 --- a/charts/snappymail/values.yaml +++ b/charts/snappymail/values.yaml @@ -72,9 +72,7 @@ env: {} ## Pod Security Context securityContext: - fsGroup: 82 # www-data group in Alpine - runAsUser: 82 - runAsNonRoot: true + {} # SnappyMail needs to run with default permissions ## Node selector nodeSelector: {} diff --git a/charts/stalwart/values.yaml b/charts/stalwart/values.yaml index 6fca9dc..fa575fa 100644 --- a/charts/stalwart/values.yaml +++ b/charts/stalwart/values.yaml @@ -90,9 +90,7 @@ secret: ## Pod Security Context securityContext: - fsGroup: 1000 - runAsUser: 1000 - runAsNonRoot: true + {} # Allow Stalwart to run with its default user ## Node selector nodeSelector: {} From ff444d09b3894089f2149f34dae8b002786ed57a Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Sun, 17 May 2026 08:15:00 +0300 Subject: [PATCH 22/33] Fix: Use v0.11.8 tag for Stalwart (latest available) --- manifests/stalwart/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifests/stalwart/values.yaml b/manifests/stalwart/values.yaml index 3cb659b..42610b6 100644 --- a/manifests/stalwart/values.yaml +++ b/manifests/stalwart/values.yaml @@ -7,7 +7,7 @@ namespace: mail ## Image configuration image: repository: stalwartlabs/mail-server - tag: latest + tag: v0.11.8 pullPolicy: IfNotPresent ## Persistence - using NFS storage From b094fe6fecf14b5e219fad822fbaa5b50272e104 Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Sun, 17 May 2026 08:18:10 +0300 Subject: [PATCH 23/33] Fix: Remove ServerSideApply and add ignoreDifferences for StatefulSet volumeClaimTemplates --- argocd-apps/stalwart.yaml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/argocd-apps/stalwart.yaml b/argocd-apps/stalwart.yaml index 80123e9..7ff8fbb 100644 --- a/argocd-apps/stalwart.yaml +++ b/argocd-apps/stalwart.yaml @@ -20,6 +20,12 @@ spec: server: https://kubernetes.default.svc namespace: mail + ignoreDifferences: + - group: apps + kind: StatefulSet + jqPathExpressions: + - '.spec.volumeClaimTemplates[]?' + syncPolicy: automated: prune: true @@ -27,7 +33,7 @@ spec: allowEmpty: false syncOptions: - CreateNamespace=true - - ServerSideApply=true + - RespectIgnoreDifferences=true retry: limit: 5 backoff: From bb9c85ae4377f7f064c1d0e735212805b9a914fe Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Sun, 17 May 2026 13:54:26 +0300 Subject: [PATCH 24/33] Add ArgoCD app for raw-resources-mail-services (LoadBalancer) --- argocd-apps/raw-resources-mail-services.yaml | 32 ++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 argocd-apps/raw-resources-mail-services.yaml diff --git a/argocd-apps/raw-resources-mail-services.yaml b/argocd-apps/raw-resources-mail-services.yaml new file mode 100644 index 0000000..10f55f0 --- /dev/null +++ b/argocd-apps/raw-resources-mail-services.yaml @@ -0,0 +1,32 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: raw-resources-mail-services + namespace: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io +spec: + project: default + + source: + repoURL: https://git.dvirlabs.com/dvirlabs/mail-services.git + targetRevision: HEAD + path: manifests/raw-resources-mail-services + + destination: + server: https://kubernetes.default.svc + namespace: mail + + syncPolicy: + automated: + prune: true + selfHeal: true + allowEmpty: false + syncOptions: + - CreateNamespace=true + retry: + limit: 5 + backoff: + duration: 5s + factor: 2 + maxDuration: 3m From 71dcd9be2686a4a15918d58437e9239173f4d7c0 Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Sun, 17 May 2026 13:56:50 +0300 Subject: [PATCH 25/33] Add LoadBalancer and NodePort service manifests --- .../stalwart-loadbalancer-service.yaml | 57 +++++++++++++++++ .../stalwart-nodeport-service.yaml | 63 +++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 manifests/raw-resources-mail-services/stalwart-loadbalancer-service.yaml create mode 100644 manifests/raw-resources-mail-services/stalwart-nodeport-service.yaml diff --git a/manifests/raw-resources-mail-services/stalwart-loadbalancer-service.yaml b/manifests/raw-resources-mail-services/stalwart-loadbalancer-service.yaml new file mode 100644 index 0000000..e36a631 --- /dev/null +++ b/manifests/raw-resources-mail-services/stalwart-loadbalancer-service.yaml @@ -0,0 +1,57 @@ +--- +# LoadBalancer Service for direct SMTP/IMAP access +# Use this if you have MetalLB or similar LoadBalancer provider +apiVersion: v1 +kind: Service +metadata: + name: stalwart-mail-ports + namespace: mail + labels: + app: stalwart + annotations: + # If using MetalLB, you can request a specific IP + # metallb.universe.tf/loadBalancerIPs: 192.168.10.241 +spec: + type: LoadBalancer + selector: + app: stalwart + ports: + # SMTP - Receiving mail from other servers + - name: smtp + port: 25 + targetPort: 25 + protocol: TCP + + # SMTP Submission - Sending mail + - name: submission + port: 587 + targetPort: 587 + protocol: TCP + + # SMTPS - Secure SMTP + - name: smtps + port: 465 + targetPort: 465 + protocol: TCP + + # IMAPS - Secure IMAP + - name: imaps + port: 993 + targetPort: 993 + protocol: TCP + + # IMAP - Plaintext IMAP + - name: imap + port: 143 + targetPort: 143 + protocol: TCP + +--- +# Instructions: +# 1. Apply this service: kubectl apply -f stalwart-loadbalancer-service.yaml +# 2. Get the LoadBalancer IP: kubectl get svc stalwart-mail-ports -n mail +# 3. If the IP is private (192.168.x.x), set up port forwarding from your router +# 4. Update DNS (turn OFF Cloudflare proxy): +# mail.dvirlabs.com A (gray cloud, not orange) +# 5. Add MX record: +# @ MX 10 mail.dvirlabs.com diff --git a/manifests/raw-resources-mail-services/stalwart-nodeport-service.yaml b/manifests/raw-resources-mail-services/stalwart-nodeport-service.yaml new file mode 100644 index 0000000..3d10257 --- /dev/null +++ b/manifests/raw-resources-mail-services/stalwart-nodeport-service.yaml @@ -0,0 +1,63 @@ +--- +# NodePort Service for direct SMTP/IMAP access +# Use this if you have a public IP and can port-forward +apiVersion: v1 +kind: Service +metadata: + name: stalwart-external + namespace: mail + labels: + app: stalwart +spec: + type: NodePort + selector: + app: stalwart + ports: + # SMTP - Receiving mail from other servers + - name: smtp + port: 25 + targetPort: 25 + nodePort: 30025 # Expose on node port 30025 + protocol: TCP + + # SMTP Submission - Sending mail + - name: submission + port: 587 + targetPort: 587 + nodePort: 30587 + protocol: TCP + + # SMTPS - Secure SMTP + - name: smtps + port: 465 + targetPort: 465 + nodePort: 30465 + protocol: TCP + + # IMAPS - Secure IMAP + - name: imaps + port: 993 + targetPort: 993 + nodePort: 30993 + protocol: TCP + + # IMAP - Plaintext IMAP + - name: imap + port: 143 + targetPort: 143 + nodePort: 30143 + protocol: TCP + +--- +# Instructions: +# 1. Apply this service: kubectl apply -f stalwart-nodeport-service.yaml +# 2. Forward ports from your router/firewall to your k3s node: +# - 25 → :30025 +# - 587 → :30587 +# - 465 → :30465 +# - 993 → :30993 +# - 143 → :30143 +# 3. Update DNS (turn OFF Cloudflare proxy): +# mail.dvirlabs.com A (gray cloud, not orange) +# 4. Add MX record: +# @ MX 10 mail.dvirlabs.com From d316b795f504159d351b4539630b22872aff9cf3 Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Sun, 17 May 2026 14:05:10 +0300 Subject: [PATCH 26/33] Migrate all resources from 'mail' to 'mail-services' namespace --- argocd-apps/raw-resources-mail-services.yaml | 2 +- argocd-apps/snappymail.yaml | 2 +- argocd-apps/stalwart.yaml | 2 +- charts/snappymail/values.yaml | 2 +- charts/stalwart/values.yaml | 2 +- .../stalwart-loadbalancer-service.yaml | 2 +- .../raw-resources-mail-services/stalwart-nodeport-service.yaml | 2 +- manifests/snappymail/values.yaml | 2 +- manifests/stalwart/values.yaml | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/argocd-apps/raw-resources-mail-services.yaml b/argocd-apps/raw-resources-mail-services.yaml index 10f55f0..ed37c32 100644 --- a/argocd-apps/raw-resources-mail-services.yaml +++ b/argocd-apps/raw-resources-mail-services.yaml @@ -15,7 +15,7 @@ spec: destination: server: https://kubernetes.default.svc - namespace: mail + namespace: mail-services syncPolicy: automated: diff --git a/argocd-apps/snappymail.yaml b/argocd-apps/snappymail.yaml index 76c7fae..eaa2fab 100644 --- a/argocd-apps/snappymail.yaml +++ b/argocd-apps/snappymail.yaml @@ -18,7 +18,7 @@ spec: destination: server: https://kubernetes.default.svc - namespace: mail + namespace: mail-services syncPolicy: automated: diff --git a/argocd-apps/stalwart.yaml b/argocd-apps/stalwart.yaml index 7ff8fbb..479ff32 100644 --- a/argocd-apps/stalwart.yaml +++ b/argocd-apps/stalwart.yaml @@ -18,7 +18,7 @@ spec: destination: server: https://kubernetes.default.svc - namespace: mail + namespace: mail-services ignoreDifferences: - group: apps diff --git a/charts/snappymail/values.yaml b/charts/snappymail/values.yaml index 5c3a18b..c9516b4 100644 --- a/charts/snappymail/values.yaml +++ b/charts/snappymail/values.yaml @@ -8,7 +8,7 @@ image: pullPolicy: IfNotPresent ## Namespace -namespace: mail +namespace: mail-services ## Replica count replicaCount: 1 diff --git a/charts/stalwart/values.yaml b/charts/stalwart/values.yaml index fa575fa..1d73b2a 100644 --- a/charts/stalwart/values.yaml +++ b/charts/stalwart/values.yaml @@ -8,7 +8,7 @@ image: pullPolicy: IfNotPresent ## Namespace -namespace: mail +namespace: mail-services ## Replica count (should be 1 for StatefulSet with persistent data) replicaCount: 1 diff --git a/manifests/raw-resources-mail-services/stalwart-loadbalancer-service.yaml b/manifests/raw-resources-mail-services/stalwart-loadbalancer-service.yaml index e36a631..082b47d 100644 --- a/manifests/raw-resources-mail-services/stalwart-loadbalancer-service.yaml +++ b/manifests/raw-resources-mail-services/stalwart-loadbalancer-service.yaml @@ -5,7 +5,7 @@ apiVersion: v1 kind: Service metadata: name: stalwart-mail-ports - namespace: mail + namespace: mail-services labels: app: stalwart annotations: diff --git a/manifests/raw-resources-mail-services/stalwart-nodeport-service.yaml b/manifests/raw-resources-mail-services/stalwart-nodeport-service.yaml index 3d10257..0b8cf8b 100644 --- a/manifests/raw-resources-mail-services/stalwart-nodeport-service.yaml +++ b/manifests/raw-resources-mail-services/stalwart-nodeport-service.yaml @@ -5,7 +5,7 @@ apiVersion: v1 kind: Service metadata: name: stalwart-external - namespace: mail + namespace: mail-services labels: app: stalwart spec: diff --git a/manifests/snappymail/values.yaml b/manifests/snappymail/values.yaml index f3cbe3a..9ebed9b 100644 --- a/manifests/snappymail/values.yaml +++ b/manifests/snappymail/values.yaml @@ -2,7 +2,7 @@ ## Override default chart values here ## Namespace -namespace: mail +namespace: mail-services ## Image configuration image: diff --git a/manifests/stalwart/values.yaml b/manifests/stalwart/values.yaml index 42610b6..642afbd 100644 --- a/manifests/stalwart/values.yaml +++ b/manifests/stalwart/values.yaml @@ -2,7 +2,7 @@ ## Override default chart values here ## Namespace -namespace: mail +namespace: mail-services ## Image configuration image: From 12434b659a1fd3665c567139e693c0558391d495 Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Sun, 17 May 2026 14:18:03 +0300 Subject: [PATCH 27/33] Fix SnappyMail namespace and increase Stalwart PVC to 30Gi --- manifests/snappymail/values.yaml | 4 ++-- manifests/stalwart/values.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/manifests/snappymail/values.yaml b/manifests/snappymail/values.yaml index 9ebed9b..81c3745 100644 --- a/manifests/snappymail/values.yaml +++ b/manifests/snappymail/values.yaml @@ -36,11 +36,11 @@ ingress: stalwart: serviceName: stalwart imap: - host: stalwart.mail.svc.cluster.local + host: stalwart.mail-services.svc.cluster.local port: 993 secure: true smtp: - host: stalwart.mail.svc.cluster.local + host: stalwart.mail-services.svc.cluster.local port: 587 secure: true diff --git a/manifests/stalwart/values.yaml b/manifests/stalwart/values.yaml index 642afbd..5dcf4e6 100644 --- a/manifests/stalwart/values.yaml +++ b/manifests/stalwart/values.yaml @@ -15,7 +15,7 @@ persistence: enabled: true storageClass: nfs-client accessMode: ReadWriteOnce - size: 20Gi # Increased for production mail storage + size: 30Gi # Increased for production mail storage mountPath: /opt/stalwart-mail ## Ingress for admin UI only From bab0394284ba02372418548ceb9dfeb6445eae26 Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Sun, 17 May 2026 16:11:17 +0300 Subject: [PATCH 28/33] Change Stalwart Admin UI from mail.dvirlabs.com to mail-admin.dvirlabs.com --- charts/stalwart/values.yaml | 2 +- manifests/stalwart/values.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/stalwart/values.yaml b/charts/stalwart/values.yaml index 1d73b2a..a7eba2c 100644 --- a/charts/stalwart/values.yaml +++ b/charts/stalwart/values.yaml @@ -46,7 +46,7 @@ ingress: traefik.ingress.kubernetes.io/router.entrypoints: websecure traefik.ingress.kubernetes.io/router.tls: "true" hosts: - - host: mail.dvirlabs.com + - host: mail-admin.dvirlabs.com paths: - path: / pathType: Prefix diff --git a/manifests/stalwart/values.yaml b/manifests/stalwart/values.yaml index 5dcf4e6..7c99402 100644 --- a/manifests/stalwart/values.yaml +++ b/manifests/stalwart/values.yaml @@ -26,7 +26,7 @@ ingress: traefik.ingress.kubernetes.io/router.entrypoints: websecure traefik.ingress.kubernetes.io/router.tls: "true" hosts: - - host: mail.dvirlabs.com + - host: mail-admin.dvirlabs.com paths: - path: / pathType: Prefix From 43d3fe575af519dea55a40f1484e419a2a470823 Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Sun, 17 May 2026 16:23:03 +0300 Subject: [PATCH 29/33] Update Stalwart to v0.13.0 for webadmin compatibility --- charts/stalwart/values.yaml | 2 +- manifests/stalwart/values.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/stalwart/values.yaml b/charts/stalwart/values.yaml index a7eba2c..bdde5ec 100644 --- a/charts/stalwart/values.yaml +++ b/charts/stalwart/values.yaml @@ -4,7 +4,7 @@ ## Image configuration image: repository: stalwartlabs/mail-server - tag: v0.10.8 + tag: v0.13.0 pullPolicy: IfNotPresent ## Namespace diff --git a/manifests/stalwart/values.yaml b/manifests/stalwart/values.yaml index 7c99402..c7cfee1 100644 --- a/manifests/stalwart/values.yaml +++ b/manifests/stalwart/values.yaml @@ -7,7 +7,7 @@ namespace: mail-services ## Image configuration image: repository: stalwartlabs/mail-server - tag: v0.11.8 + tag: v0.13.0 pullPolicy: IfNotPresent ## Persistence - using NFS storage From 13dd9c15e4cdf329d3bfb0bba83e3402c5801120 Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Sun, 17 May 2026 16:24:05 +0300 Subject: [PATCH 30/33] Try Stalwart latest tag to get compatible webadmin --- charts/stalwart/values.yaml | 4 ++-- manifests/stalwart/values.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/charts/stalwart/values.yaml b/charts/stalwart/values.yaml index bdde5ec..117fbdd 100644 --- a/charts/stalwart/values.yaml +++ b/charts/stalwart/values.yaml @@ -4,8 +4,8 @@ ## Image configuration image: repository: stalwartlabs/mail-server - tag: v0.13.0 - pullPolicy: IfNotPresent + tag: latest + pullPolicy: Always ## Namespace namespace: mail-services diff --git a/manifests/stalwart/values.yaml b/manifests/stalwart/values.yaml index c7cfee1..4a24d55 100644 --- a/manifests/stalwart/values.yaml +++ b/manifests/stalwart/values.yaml @@ -7,8 +7,8 @@ namespace: mail-services ## Image configuration image: repository: stalwartlabs/mail-server - tag: v0.13.0 - pullPolicy: IfNotPresent + tag: latest + pullPolicy: Always ## Persistence - using NFS storage persistence: From 0252c5629ba8785c4ffa12df824d58c96c46a799 Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Sun, 17 May 2026 16:24:38 +0300 Subject: [PATCH 31/33] Revert to v0.11.8 (webadmin incompatibility is a known issue) --- charts/stalwart/values.yaml | 4 ++-- manifests/stalwart/values.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/charts/stalwart/values.yaml b/charts/stalwart/values.yaml index 117fbdd..bef4062 100644 --- a/charts/stalwart/values.yaml +++ b/charts/stalwart/values.yaml @@ -4,8 +4,8 @@ ## Image configuration image: repository: stalwartlabs/mail-server - tag: latest - pullPolicy: Always + tag: v0.11.8 + pullPolicy: IfNotPresent ## Namespace namespace: mail-services diff --git a/manifests/stalwart/values.yaml b/manifests/stalwart/values.yaml index 4a24d55..7c99402 100644 --- a/manifests/stalwart/values.yaml +++ b/manifests/stalwart/values.yaml @@ -7,8 +7,8 @@ namespace: mail-services ## Image configuration image: repository: stalwartlabs/mail-server - tag: latest - pullPolicy: Always + tag: v0.11.8 + pullPolicy: IfNotPresent ## Persistence - using NFS storage persistence: From 6d606515fe0c8b69c4827e09d5d505e12a4bfb66 Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Sun, 17 May 2026 16:32:59 +0300 Subject: [PATCH 32/33] Update Stalwart to v0.13.0 for webadmin compatibility --- charts/stalwart/values.yaml | 2 +- manifests/stalwart/values.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/stalwart/values.yaml b/charts/stalwart/values.yaml index bef4062..bdde5ec 100644 --- a/charts/stalwart/values.yaml +++ b/charts/stalwart/values.yaml @@ -4,7 +4,7 @@ ## Image configuration image: repository: stalwartlabs/mail-server - tag: v0.11.8 + tag: v0.13.0 pullPolicy: IfNotPresent ## Namespace diff --git a/manifests/stalwart/values.yaml b/manifests/stalwart/values.yaml index 7c99402..c7cfee1 100644 --- a/manifests/stalwart/values.yaml +++ b/manifests/stalwart/values.yaml @@ -7,7 +7,7 @@ namespace: mail-services ## Image configuration image: repository: stalwartlabs/mail-server - tag: v0.11.8 + tag: v0.13.0 pullPolicy: IfNotPresent ## Persistence - using NFS storage From 1904bb8fe813b56b12cc823773a27185ea8f7382 Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Sun, 17 May 2026 16:33:55 +0300 Subject: [PATCH 33/33] Fix: Use stalwartlabs/stalwart repository for v0.13.0 --- charts/stalwart/values.yaml | 2 +- manifests/stalwart/values.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/stalwart/values.yaml b/charts/stalwart/values.yaml index bdde5ec..9a89b59 100644 --- a/charts/stalwart/values.yaml +++ b/charts/stalwart/values.yaml @@ -3,7 +3,7 @@ ## Image configuration image: - repository: stalwartlabs/mail-server + repository: stalwartlabs/stalwart tag: v0.13.0 pullPolicy: IfNotPresent diff --git a/manifests/stalwart/values.yaml b/manifests/stalwart/values.yaml index c7cfee1..75ec5de 100644 --- a/manifests/stalwart/values.yaml +++ b/manifests/stalwart/values.yaml @@ -6,7 +6,7 @@ namespace: mail-services ## Image configuration image: - repository: stalwartlabs/mail-server + repository: stalwartlabs/stalwart tag: v0.13.0 pullPolicy: IfNotPresent