This commit is contained in:
dvirlabs 2026-05-18 14:50:43 +03:00
commit feb509fa55
89 changed files with 1918 additions and 55 deletions

529
MAIL_STACK_README.md Normal file
View File

@ -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 <none> 8080/TCP,25/TCP,587/TCP,993/TCP
service/snappymail ClusterIP 10.43.x.x <none> 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 - <<EOF
apiVersion: v1
kind: Service
metadata:
name: stalwart-external
namespace: mail
spec:
type: NodePort
ports:
- name: smtp
port: 25
targetPort: 25
nodePort: 30025
- name: submission
port: 587
targetPort: 587
nodePort: 30587
- name: imaps
port: 993
targetPort: 993
nodePort: 30993
selector:
app.kubernetes.io/name: stalwart
EOF
```
Then forward ports 25, 587, 993 from your router to your k3s node on ports 30025, 30587, 30993.
**Option B: LoadBalancer with MetalLB**
If you have MetalLB configured:
```bash
kubectl apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
name: stalwart-lb
namespace: mail
spec:
type: LoadBalancer
loadBalancerIP: YOUR_LB_IP
ports:
- name: smtp
port: 25
targetPort: 25
- name: submission
port: 587
targetPort: 587
- name: imaps
port: 993
targetPort: 993
selector:
app.kubernetes.io/name: stalwart
EOF
```
#### 3. PTR (Reverse DNS) Record
Contact your ISP or VPS provider to set a PTR record:
```
YOUR_PUBLIC_IP -> 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

298
QUICKSTART.md Normal file
View File

@ -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.

View File

@ -1,20 +0,0 @@
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

View File

@ -1,21 +0,0 @@
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

View File

@ -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-services
syncPolicy:
automated:
prune: true
selfHeal: true
allowEmpty: false
syncOptions:
- CreateNamespace=true
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m

View File

@ -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://git.dvirlabs.com/dvirlabs/mail-services.git
targetRevision: HEAD
path: charts/snappymail
helm:
valueFiles:
- ../../manifests/snappymail/values.yaml
destination:
server: https://kubernetes.default.svc
namespace: mail-services
syncPolicy:
automated:
prune: true
selfHeal: true
allowEmpty: false
syncOptions:
- CreateNamespace=true
- ServerSideApply=true
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m

42
argocd-apps/stalwart.yaml Normal file
View File

@ -0,0 +1,42 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: stalwart
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source:
repoURL: https://git.dvirlabs.com/dvirlabs/mail-services.git
targetRevision: HEAD
path: charts/stalwart
helm:
valueFiles:
- ../../manifests/stalwart/values.yaml
destination:
server: https://kubernetes.default.svc
namespace: mail-services
ignoreDifferences:
- group: apps
kind: StatefulSet
jqPathExpressions:
- '.spec.volumeClaimTemplates[]?'
syncPolicy:
automated:
prune: true
selfHeal: true
allowEmpty: false
syncOptions:
- CreateNamespace=true
- RespectIgnoreDifferences=true
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m

View File

@ -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

View File

@ -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 }}

View File

@ -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 }}

View File

@ -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 }}

View File

@ -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 }}

View File

@ -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 }}

View File

@ -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 }}

View File

@ -0,0 +1,84 @@
## SnappyMail webmail configuration
## Default values for snappymail chart
## Image configuration
image:
repository: djmaze/snappymail
tag: "2.39"
pullPolicy: IfNotPresent
## Namespace
namespace: mail-services
## 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:
{} # SnappyMail needs to run with default permissions
## Node selector
nodeSelector: {}
## Tolerations
tolerations: []
## Affinity
affinity: {}

View File

@ -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

View File

@ -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 }}

View File

@ -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 }}

View File

@ -0,0 +1,6 @@
apiVersion: v1
kind: Namespace
metadata:
name: {{ .Values.namespace }}
labels:
{{- include "stalwart.labels" . | nindent 4 }}

View File

@ -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 }}

View File

@ -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 }}

View File

@ -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 }}

102
charts/stalwart/values.yaml Normal file
View File

@ -0,0 +1,102 @@
## Stalwart Mail Server configuration
## Default values for stalwart chart
## Image configuration
image:
repository: stalwartlabs/stalwart
tag: v0.13.0
pullPolicy: IfNotPresent
## Namespace
namespace: mail-services
## 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-admin.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:
{} # Allow Stalwart to run with its default user
## Node selector
nodeSelector: {}
## Tolerations
tolerations: []
## Affinity
affinity: {}

View File

@ -1,7 +1,10 @@
domain: dvirlabs.com
hostnames:
- mail.dvirlabs.com
replicaCount: 1
ingress:
enabled: true
className: traefik
@ -26,26 +29,42 @@ 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
# smtp:
# type: ClusterIP
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: NodePort
type: LoadBalancer
externalTrafficPolicy: Cluster
ports:
smtp: true
@ -56,8 +75,13 @@ front:
pop3: false
pop3s: false
manageSieve: false
nodePorts:
smtp: 31025
nodeSelector:
node-role.kubernetes.io/worker: "true"
tolerations: []
tls:
certmanager:
enabled: true
dkim:
enabled: true

View File

@ -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-services
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 <your-public-ip> (gray cloud, not orange)
# 5. Add MX record:
# @ MX 10 mail.dvirlabs.com

View File

@ -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-services
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 → <node-ip>:30025
# - 587 → <node-ip>:30587
# - 465 → <node-ip>:30465
# - 993 → <node-ip>:30993
# - 143 → <node-ip>:30143
# 3. Update DNS (turn OFF Cloudflare proxy):
# mail.dvirlabs.com A <your-public-ip> (gray cloud, not orange)
# 4. Add MX record:
# @ MX 10 mail.dvirlabs.com

View File

@ -0,0 +1,54 @@
## SnappyMail - Custom values for dvirlabs.com
## Override default chart values here
## Namespace
namespace: mail-services
## Image configuration
image:
repository: djmaze/snappymail
tag: latest
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-services.svc.cluster.local
port: 993
secure: true
smtp:
host: stalwart.mail-services.svc.cluster.local
port: 587
secure: true
## Resource allocation
resources:
requests:
memory: "256Mi"
cpu: "200m"
limits:
memory: "1Gi"
cpu: "1000m"

View File

@ -0,0 +1,54 @@
## Stalwart Mail Server - Custom values for dvirlabs.com
## Override default chart values here
## Namespace
namespace: mail-services
## Image configuration
image:
repository: stalwartlabs/stalwart
tag: v0.13.0
pullPolicy: IfNotPresent
## Persistence - using NFS storage
persistence:
enabled: true
storageClass: nfs-client
accessMode: ReadWriteOnce
size: 30Gi # 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-admin.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"

View File

@ -0,0 +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

21
old/mailu.yaml Normal file
View File

@ -0,0 +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