Initial commit - production deployment

This commit is contained in:
2026-01-21 17:17:16 +01:00
commit c23d00dd92
2289 changed files with 638440 additions and 0 deletions

View File

@@ -0,0 +1,198 @@
# Mailu Migration Guide: From Kustomize to Helm
This document outlines the migration process from the Kustomize-based Mailu deployment to the Helm-based deployment.
## Overview
The Mailu email server has been migrated from a Kustomize-based deployment to a Helm chart-based deployment. This change provides better maintainability, easier upgrades, and standardized configuration management.
## Key Changes
### 1. Service Names
- **Old**: `mailu-smtp`, `email-smtp`, `mailu-front`, `mailu-admin`, `mailu-imap`, `mailu-antispam`
- **New**: `mailu-postfix`, `mailu-front`, `mailu-admin`, `mailu-dovecot`, `mailu-rspamd`
### 2. Configuration Method
- **Old**: Individual YAML manifests with Kustomize overlays
- **New**: Helm chart with values files for environment-specific configuration
### 3. Directory Structure
- **Old**: `infrastructure/platform/mail/mailu/{base,overlays/{dev,prod}}`
- **New**: `infrastructure/platform/mail/mailu-helm/{dev,prod}`
### 4. Ingress Configuration
- **Old**: Ingress resources created as part of the Kustomize setup
- **New**: Built-in ingress disabled in Helm chart to work with existing ingress controller
## Updated Service References
The following configurations have been updated to use the new Helm service names:
## Ingress Configuration
The Mailu Helm chart has been configured to work with your existing ingress setup:
- **ingress.enabled: false**: Disables the chart's built-in Ingress creation
- **tlsFlavorOverride: notls**: Tells Mailu's internal NGINX not to enforce TLS, as your Ingress handles TLS termination
- **realIpHeader: X-Forwarded-For**: Ensures Mailu's NGINX logs and processes the correct client IPs from behind your Ingress
- **realIpFrom: 0.0.0.0/0**: Trusts all proxies (restrict to your Ingress pod CIDR for security)
### Required Ingress Resource
You need to create an Ingress resource to route traffic to Mailu. Here's an example:
```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: mailu-ingress
namespace: bakery-ia # Same as Mailu's namespace
annotations:
kubernetes.io/ingress.class: nginx # Or your Ingress class
nginx.ingress.kubernetes.io/proxy-body-size: "100m" # Allow larger email attachments
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" # For long connections
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true" # Redirect HTTP to HTTPS
# If using Cert-Manager: cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
tls:
- hosts:
- mail.bakery-ia.dev # or mail.bakewise.ai for prod
secretName: mail-tls-secret # Your TLS Secret
rules:
- host: mail.bakery-ia.dev # or mail.bakewise.ai for prod
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: mailu-front-http # Mailu's front service (check with kubectl get svc -n bakery-ia)
port:
number: 80
```
Apply it: `kubectl apply -f ingress.yaml`.
This routes all traffic from https://mail.[domain]/ to Mailu's internal NGINX, which proxies to webmail (/webmail), admin (/admin), etc.
## Updated Service References
The following configurations have been updated to use the new Helm service names:
### Common ConfigMap
- `SMTP_HOST` changed from `email-smtp.bakery-ia.svc.cluster.local` to `mailu-postfix.bakery-ia.svc.cluster.local`
### SigNoz Configuration
- `signoz_smtp_host` changed from `email-smtp.bakery-ia.svc.cluster.local` to `mailu-postfix.bakery-ia.svc.cluster.local`
- `smtp_smarthost` changed from `email-smtp.bakery-ia.svc.cluster.local:587` to `mailu-postfix.bakery-ia.svc.cluster.local:587`
## Deployment Process
### Prerequisites
1. Helm 3.x installed
2. Access to Kubernetes cluster
3. Namespace `bakery-ia` exists
### Deployment Commands
#### For Development:
```bash
# Add Mailu Helm repository
helm repo add mailu https://mailu.github.io/helm-charts/
helm repo update
# Install Mailu for development
helm upgrade --install mailu-dev mailu/mailu \
--namespace bakery-ia \
--create-namespace \
--values infrastructure/platform/mail/mailu-helm/values.yaml \
--values infrastructure/platform/mail/mailu-helm/dev/values.yaml
```
#### For Production:
```bash
# Add Mailu Helm repository
helm repo add mailu https://mailu.github.io/helm-charts/
helm repo update
# Install Mailu for production
helm upgrade --install mailu-prod mailu/mailu \
--namespace bakery-ia \
--create-namespace \
--values infrastructure/platform/mail/mailu-helm/values.yaml \
--values infrastructure/platform/mail/mailu-helm/prod/values.yaml
```
## Critical Configuration Preservation
All critical configurations from the original Kustomize setup have been preserved:
- Domain and hostname settings
- External SMTP relay configuration (Mailgun)
- Redis integration with shared cluster
- Database connection settings
- TLS certificate management
- Resource limits and requests
- Network policies
- Storage configuration (10Gi PVC)
## Rollback Procedure
If rollback to the Kustomize setup is needed:
1. Uninstall the Helm release:
```bash
helm uninstall mailu-dev -n bakery-ia # or mailu-prod
```
2. Revert the configuration changes in `infrastructure/environments/common/configs/configmap.yaml` and `infrastructure/monitoring/signoz/signoz-values-prod.yaml`
3. Deploy the old Kustomize manifests:
```bash
kubectl apply -k infrastructure/platform/mail/mailu/overlays/dev
# or
kubectl apply -k infrastructure/platform/mail/mailu/overlays/prod
```
## Verification Steps
After deployment, verify the following:
1. Check that all Mailu pods are running:
```bash
kubectl get pods -n bakery-ia | grep mailu
```
2. Verify SMTP connectivity from other services:
```bash
# Test from a pod in the same namespace
kubectl run test-smtp --image=curlimages/curl -n bakery-ia --rm -it -- \
nc -zv mailu-postfix.bakery-ia.svc.cluster.local 587
```
3. Check that notification service can send emails:
```bash
kubectl logs -n bakery-ia deployment/notification-service | grep -i smtp
```
4. Verify web interface accessibility:
```bash
kubectl port-forward -n bakery-ia svc/mailu-front 8080:80
# Then visit http://localhost:8080/admin
```
## Known Issues
1. During migration, existing email data should be backed up before uninstalling the old deployment
2. DNS records may need to be updated to point to the new service endpoints
3. Some custom configurations may need to be reapplied after Helm installation
## Support
For issues with the new Helm-based deployment:
1. Check the [official Mailu Helm chart documentation](https://github.com/Mailu/helm-charts)
2. Review Helm release status: `helm status mailu-[dev|prod] -n bakery-ia`
3. Check pod logs: `kubectl logs -n bakery-ia deployment/[mailu-postfix|mailu-front|etc.]`
4. Verify network connectivity between services

View File

@@ -0,0 +1,171 @@
# Mailu Helm Chart for Bakery-IA
This directory contains the Helm chart configuration for Mailu, replacing the previous Kustomize-based setup.
## Overview
The Mailu email server is now deployed using the official Mailu Helm chart instead of Kustomize manifests. This provides better maintainability, easier upgrades, and standardized configuration. The setup is configured to work behind your existing Ingress controller (NGINX), with the internal Mailu NGINX acting as a proxy for services like webmail while your existing Ingress handles traffic routing, TLS termination, and forwarding to Mailu's internal NGINX on HTTP (port 80).
## Directory Structure
```
mailu-helm/
├── values.yaml # Base configuration values
├── dev/
│ └── values.yaml # Development-specific overrides
├── prod/
│ └── values.yaml # Production-specific overrides
└── mailu-ingress.yaml # Sample ingress configuration for use with existing ingress
```
## Critical Configuration Preservation
The following critical configurations from the original Kustomize setup have been preserved:
- **Domain settings**: Domain and hostnames for both dev and prod
- **External relay**: Mailgun SMTP relay configuration
- **Redis integration**: Connection to shared Redis cluster (database 15)
- **Database settings**: PostgreSQL connection details
- **Resource limits**: CPU and memory requests/limits matching original setup
- **Network policies**: Security policies restricting access to authorized services
- **Storage**: 10Gi persistent volume for mail data
- **Ingress configuration**: Built-in ingress disabled to work with existing ingress
## Deployment
### Prerequisites
1. Helm 3.x installed
2. Kubernetes cluster with storage provisioner
3. Ingress controller (NGINX) - already deployed in your cluster
4. Cert-manager for TLS certificates (optional, depends on your ingress setup)
5. External SMTP relay account (Mailgun)
### Deployment Commands
#### For Development:
```bash
helm repo add mailu https://mailu.github.io/helm-charts/
helm repo update
helm install mailu-dev mailu/mailu \
--namespace bakery-ia \
--create-namespace \
--values mailu-helm/values.yaml \
--values mailu-helm/dev/values.yaml
```
#### For Production:
```bash
helm repo add mailu https://mailu.github.io/helm-charts/
helm repo update
helm install mailu-prod mailu/mailu \
--namespace bakery-ia \
--create-namespace \
--values mailu-helm/values.yaml \
--values mailu-helm/prod/values.yaml
```
### Upgrading
To upgrade to a newer version of the Mailu Helm chart:
```bash
helm repo update
helm upgrade mailu-dev mailu/mailu \
--namespace bakery-ia \
--values mailu-helm/values.yaml \
--values mailu-helm/dev/values.yaml
```
## Ingress Configuration
The Mailu Helm chart is configured to work with your existing Ingress setup:
- **ingress.enabled: false**: Disables the chart's built-in Ingress creation
- **tlsFlavorOverride: notls**: Tells Mailu's internal NGINX not to enforce TLS, as your Ingress handles TLS termination
- **realIpHeader: X-Forwarded-For**: Ensures Mailu's NGINX logs and processes the correct client IPs from behind your Ingress
- **realIpFrom: 0.0.0.0/0**: Trusts all proxies (restrict to your Ingress pod CIDR for security)
### Required Ingress Resource
You need to create an Ingress resource to route traffic to Mailu. Here's an example:
```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: mailu-ingress
namespace: bakery-ia # Same as Mailu's namespace
annotations:
kubernetes.io/ingress.class: nginx # Or your Ingress class
nginx.ingress.kubernetes.io/proxy-body-size: "100m" # Allow larger email attachments
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" # For long connections
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true" # Redirect HTTP to HTTPS
# If using Cert-Manager: cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
tls:
- hosts:
- mail.bakery-ia.dev # or mail.bakewise.ai for prod
secretName: mail-tls-secret # Your TLS Secret
rules:
- host: mail.bakery-ia.dev # or mail.bakewise.ai for prod
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: mailu-front-http # Mailu's front service (check with kubectl get svc -n bakery-ia)
port:
number: 80
```
Apply it: `kubectl apply -f ingress.yaml`.
This routes all traffic from https://mail.[domain]/ to Mailu's internal NGINX, which proxies to webmail (/webmail), admin (/admin), etc.
## Configuration Details
### Environment-Specific Values
- **Development** (`dev/values.yaml`):
- Domain: `bakery-ia.local`
- No TLS enforcement internally (handled by ingress)
- Disabled antivirus to save resources
- Debug logging level
- **Production** (`prod/values.yaml`):
- Domain: `bakewise.ai`
- No TLS enforcement internally (handled by ingress)
- Enabled antivirus
- Warning logging level
### Secrets Management
Sensitive values like passwords and API keys should be managed through Kubernetes secrets rather than being stored in the values files. The Helm chart supports referencing existing secrets for:
- Database passwords
- Redis passwords
- External relay credentials
- Mailu secret key
## Integration with Notification Service
The notification service continues to connect to Mailu via the internal service name `mailu-postfix.bakery-ia.svc.cluster.local` on port 587 with STARTTLS.
## Access Information
- **Admin Panel**: `https://mail.[domain]/admin`
- **Webmail**: `https://mail.[domain]/webmail`
- **SMTP**: `mail.[domain]:587` (STARTTLS) - handled via separate TCP services if needed
- **IMAP**: `mail.[domain]:993` (SSL/TLS) - handled via separate TCP services if needed
## Migration Notes
When migrating from the Kustomize setup to Helm:
1. Ensure all existing PVCs are preserved during migration
2. Export any existing mail data before migration if needed
3. Update any hardcoded service references in other deployments
4. Verify that network policies still allow necessary communications
5. Configure your existing ingress to route traffic to the Mailu services

View File

@@ -0,0 +1,38 @@
# CoreDNS ConfigMap patch to forward external DNS queries to Unbound for DNSSEC validation
# This is required for Mailu Admin which requires DNSSEC-validating DNS resolver
#
# Apply with: kubectl apply -f coredns-unbound-patch.yaml
# Then restart CoreDNS: kubectl rollout restart deployment coredns -n kube-system
#
# Note: The Unbound service IP (10.104.127.213) may change when the cluster is recreated.
# The setup script will automatically update this based on the actual Unbound service IP.
apiVersion: v1
kind: ConfigMap
metadata:
name: coredns
namespace: kube-system
data:
Corefile: |
.:53 {
errors
health {
lameduck 5s
}
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
forward . UNBOUND_SERVICE_IP {
max_concurrent 1000
}
cache 30 {
disable success cluster.local
disable denial cluster.local
}
loop
reload
loadbalance
}

View File

@@ -0,0 +1,94 @@
# Mailgun SMTP Credentials Secret for Mailu
#
# This secret stores Mailgun credentials for outbound email relay.
# Mailu uses Mailgun as an external SMTP relay to send all outbound emails.
#
# ============================================================================
# HOW TO CONFIGURE:
# ============================================================================
#
# 1. Go to https://www.mailgun.com and create an account
#
# 2. Add and verify your domain:
# - For dev: bakery-ia.dev
# - For prod: bakewise.ai
#
# 3. Go to Domain Settings > SMTP credentials in Mailgun dashboard
#
# 4. Note your SMTP credentials:
# - SMTP hostname: smtp.mailgun.org
# - Port: 587 (TLS/STARTTLS)
# - Username: typically postmaster@yourdomain.com
# - Password: your Mailgun SMTP password (NOT the API key)
#
# 5. Base64 encode your credentials:
# echo -n 'postmaster@bakewise.ai' | base64
# echo -n 'your-mailgun-smtp-password' | base64
#
# 6. Replace the placeholder values below with your encoded credentials
#
# 7. Apply this secret:
# kubectl apply -f mailgun-credentials-secret.yaml -n bakery-ia
#
# ============================================================================
# IMPORTANT NOTES:
# ============================================================================
#
# - Use the SMTP password from Mailgun, NOT the API key
# - The username format is: postmaster@yourdomain.com
# - For sandbox domains, Mailgun requires adding authorized recipients
# - Production domains need DNS verification (SPF, DKIM records)
#
# ============================================================================
# DNS RECORDS REQUIRED FOR MAILGUN:
# ============================================================================
#
# Add these DNS records to your domain for proper email delivery:
#
# 1. SPF Record (TXT):
# Name: @
# Value: v=spf1 include:mailgun.org ~all
#
# 2. DKIM Records (TXT):
# Mailgun will provide two DKIM keys to add as TXT records
# (check your Mailgun domain settings for exact values)
#
# 3. MX Records (optional, only if receiving via Mailgun):
# Priority 10: mxa.mailgun.org
# Priority 10: mxb.mailgun.org
#
# ============================================================================
---
apiVersion: v1
kind: Secret
metadata:
name: mailu-mailgun-credentials
namespace: bakery-ia
labels:
app: mailu
component: external-relay
annotations:
description: "Mailgun SMTP credentials for Mailu external relay"
type: Opaque
stringData:
# ============================================================================
# REPLACE THESE VALUES WITH YOUR MAILGUN CREDENTIALS
# ============================================================================
#
# Option 1: Use stringData (plain text - Kubernetes will encode automatically)
# This is easier for initial setup but shows credentials in the file
#
RELAY_USERNAME: "postmaster@sandboxc1bff891532b4f0c83056a68ae080b4c.mailgun.org"
RELAY_PASSWORD: "2e47104abadad8eb820d00042ea6d5eb-77c6c375-89c7ea55"
#
# ============================================================================
# ALTERNATIVE: Use pre-encoded values (more secure for version control)
# ============================================================================
# Comment out stringData above and uncomment data below:
#
# data:
# # Base64 encoded values
# # echo -n 'postmaster@bakewise.ai' | base64
# RELAY_USERNAME: cG9zdG1hc3RlckBiYWtld2lzZS5haQ==
# # echo -n 'your-password' | base64
# RELAY_PASSWORD: WU9VUl9NQUlMR1VOX1NNVFBfUEFTU1dPUkQ=

View File

@@ -0,0 +1,34 @@
# Mailu Admin Credentials Secret
# This secret stores the initial admin account password for Mailu
#
# The password is used by the Helm chart's initialAccount feature to create
# the admin user automatically during deployment.
#
# IMPORTANT: Replace the base64-encoded password before applying!
#
# To generate a secure password and encode it:
# PASSWORD=$(openssl rand -base64 16 | tr -d '/+=' | head -c 16)
# echo -n "$PASSWORD" | base64
#
# To apply this secret:
# kubectl apply -f mailu-admin-credentials-secret.yaml -n bakery-ia
#
# After deployment, you can log in to the Mailu admin panel at:
# https://mail.<domain>/admin
# Username: admin@<domain>
# Password: <the password you set>
#
apiVersion: v1
kind: Secret
metadata:
name: mailu-admin-credentials
namespace: bakery-ia
labels:
app.kubernetes.io/name: mailu
app.kubernetes.io/component: admin
type: Opaque
data:
# Base64-encoded password
# Example: "changeme123" = Y2hhbmdlbWUxMjM=
# IMPORTANT: Replace with your own secure password!
password: "Y2hhbmdlbWUxMjM="

View File

@@ -0,0 +1,26 @@
# Self-signed TLS certificate secret for Mailu Front
# This is required by the Mailu Helm chart even when TLS is disabled (tls.flavor: notls)
# The Front pod mounts this secret for internal certificate handling
#
# For production, replace with proper certificates from cert-manager or Let's Encrypt
# This script generates a self-signed certificate valid for 365 days
#
# To regenerate manually:
# openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
# -keyout tls.key -out tls.crt \
# -subj "/CN=mail.bakery-ia.dev/O=bakery-ia"
# kubectl create secret tls mailu-certificates \
# --cert=tls.crt --key=tls.key -n bakery-ia
apiVersion: v1
kind: Secret
metadata:
name: mailu-certificates
namespace: bakery-ia
labels:
app.kubernetes.io/name: mailu
app.kubernetes.io/component: certificates
type: kubernetes.io/tls
data:
# Generated certificate for mail.bakery-ia.dev
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURRekNDQWl1Z0F3SUJBZ0lVVWg1Rlg5cWlPRDdkc2FmVi9KemlKWWh1WUZJd0RRWUpLb1pJaHZjTkFRRUwKQlFBd01URWJNQmtHQTFVRUF3d1NiV0ZwYkM1aVlXdGxjbmt0YVdFdVpHVjJNUkl3RUFZRFZRUUtEQWxDWVd0bApjbmtnU1VFd0hoY05Nall3TVRFNU1qQTBOakkwV2hjTk1qY3dNVEU1TWpBME5qSTBXakF4TVJzd0dRWURWUVFECkRCSnRZV2xzTG1KaGEyVnllUzFwWVM1a1pYWXhFakFRQmdOVkJBb01DVUpoYTJWeWVTQkpRVENDQVNJd0RRWUoKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTDJlbXM2YW5DSjV5N0JQNm9KdTQ2TldQSXJ3Zlg3Mgp3WmgxZERJaVlIMmNsalBESldsb3ROU0JFTngxUkZZSEc3Z0VSRVk1MHpFQ3UwSC9Vc0YzRFlPTFhobkYwdVRXCkNSTmJFRjFoYjZNT2lqanVmOWJHKzdsVkJ5NmZkMXZRTzJpOTA1VktxRTdEZllraWIwVkpxN0duVUo5RWFtOFgKSWxTaUphY1F6Mm11WXd6QjBPN3hZeVV3VFFWTDcvSnRNTWs5ZjZDY1ZENXFRMGJuWEJNM2hqcVVGWTlnbEF5dApZZHBUUUhPdms1WXgrZk1nL2JZVlBjQ0VhZFhVVkhBdHoxYlJybGIwenlMc3FXeHd2OXlWN0pCM210TkNmbFdsCkRCWWRIb3J0ZlROTHVSNFhhRTNXT2pnbzkwT1ltbi9PYll6Mld0SXUwMnp5MkhrTnBNYUFvVmtDQXdFQUFhTlQKTUZFd0hRWURWUjBPQkJZRUZMS2hPc254WnpXQ1RyMFFuSTdjaE1hbWtTb2pNQjhHQTFVZEl3UVlNQmFBRkxLaApPc254WnpXQ1RyMFFuSTdjaE1hbWtTb2pNQThHQTFVZEV3RUIvd1FGTUFNQkFmOHdEUVlKS29aSWh2Y05BUUVCCkJRQURnZ0VCQUFMQ3hGV1VnY3Z3ZVpoRjFHdlNnR3R3VW9WakJtcG1GYnFPMC93S2lqMlhDRmZ6L0FqanZaOHMKOGVIUEc5Z3crbjlpaGNSN016Q2V5ZldRd1FsaTBXZkcySzBvUDFGeUxoYU9aMlhtdU9nNnhNRG5EVzBVZWtqMwpCYWdHc3RFVXpqQlR1UlJ3WS9uck5vb1ZCOVFoYnhoeW9mbXkrVzVmczhZMDNTZG9paTFpWG1iSEhaemMyL21ICmF2UDE0Z3BzWUNDZVl6aklyWm05WWE4Rzhpc2tYelNnZU0vSEhpRzhJOWhKRkJYaHRYYWRjeGkvbU5hNHRKcWgKM1crTEIzaEQ4NFVkZ3MrR3pCZ0hHdnIwdWxMMTQvaUxVRXFySXZaWjN2VTlvNlZ4MlBvRjQ3cjBQNXpOZXVTNwpkRk5xT3JJT2phSm5yMXFVb0tMeWd3RUhqdVRNbUk0PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQzlucHJPbXB3aWVjdXcKVCtxQ2J1T2pWanlLOEgxKzlzR1lkWFF5SW1COW5KWXp3eVZwYUxUVWdSRGNkVVJXQnh1NEJFUkdPZE14QXJ0QgovMUxCZHcyRGkxNFp4ZExrMWdrVFd4QmRZVytqRG9vNDduL1d4dnU1VlFjdW4zZGIwRHRvdmRPVlNxaE93MzJKCkltOUZTYXV4cDFDZlJHcHZGeUpVb2lXbkVNOXBybU1Nd2REdThXTWxNRTBGUysveWJUREpQWCtnbkZRK2FrTkcKNTF3VE40WTZsQldQWUpRTXJXSGFVMEJ6cjVPV01mbnpJUDIyRlQzQWhHblYxRlJ3TGM5VzBhNVc5TThpN0tscwpjTC9jbGV5UWQ1clRRbjVWcFF3V0hSNks3WDB6UzdrZUYyaE4xam80S1BkRG1KcC96bTJNOWxyU0x0TnM4dGg1CkRhVEdnS0ZaQWdNQkFBRUNnZ0VBSW51TFQzTVNYYnFrYmdXNmNjblVuOGw0N1JOYTN4SGtsdU1WSkdEWUJ6L0kKbU5VdUlvTW1EMWNCUi9ZVFhVbWhvczh6MDBtRXZHN3d1c25CdE9qL2ppSjBGRi9EUUZZa0JGOFZGTVk1VlArNQo1eXlJRnZqTW9pRnlVdW93L0lOYnFtcUs1YVZVQWk3T3ozZHhvTG9LL1IyZUxiaDFXb3BzZGRPZTRValBUenBVCnU1TVl4NXlMVnVZc1A3U09TSHRrd2UvMDN5RFJLckl2V3k1QlBtYzJRVEhUcEJPVUJHNC9DcFJWR1ozZjhLa0QKN2QrNlZlNzd1TWV1eERPOG1HZ1paNTRpd0NuMStYR2NFcVFVR1Z1WngrcVpodVhTZks0ajR3eWVtbndlRUFCdgptTlNZSXQ2OG91SSs0cEFyV1ZONEFjaXhWRUxIV1d6MDRYTm56WFUyNFFLQmdRRDBlc0JZenVkRzJaU2t5SWJRCnU4SXhwT2RzRjRnU1lpekNkMTNLQktGbm9obTFrVzlYemRmS3ZObnJxcFRPRnJIYkRXUTdpaUhKM2NqVjlBVTUKTlEwMVUzWXY0SzhkdWtnb2MvRUFhbnQvRjhvMG5qc0pJZ2Z2WTFuUHNPVFVFcGtRQk1QSGpraGpyM3FBNkh4dgp4b0I2OEdVdU1OVHRkQitBV0Y0dXR1T2JoUUtCZ1FER2pnNmJnbGpXRVR4TnhBalQxc21reEpzQ2xmbFFteXRmCmNiaDVWempzdGNad2lLSjh1b0xjT0d4b05HWDJIaGJRQU5wRWhUR3FuMEZIbGxFc1BYbXBoeUJVY01JUFZTWEkKRUlLeU9kL3ZMYjhjWG9ydDZMaDNNS0FoakVLbExENVZOcDhXbVlQM3dCVE1ia3BrM0NDdWxDSEJLcEJXV2Y2NgpQWFp0RUZKa3hRS0JnQjNSTHM1bUJhME5jbVNhbEY2MjE1dG9hbFV6bFlQd2QxY01hZUx1cDZUVkQxK21xamJDClF6UlZ6aHBCQnI4UDQ0YzgzZUdwR2kvZG5kWUNXZlM5Tkt3eFRyUE9LbTFzdjhvM1FjaDBORFd1K0Jsc3h2UjUKTXhDT1JIRGhPVGRvUVVURDRBRGhxSkNINFdBQmV0UERHUDVsZldHaDBRWlk2RktsOUc2c0haeGxBb0dBWnlLLwpIN1B6WlM2S3ZuSkhpNUlVSjh3Z0lKVzZiVTVNbDBWQTUzYVJFUlBTd2YyWE9XYkFOcGZ3WjZoZ0ZobkhDOENGCm4vWDN1SU1FcTZTL0FWWGxibFBNVFZCTTNSNERoQXBmZVNocTA1aFZudXpWQ1lOSzNrNlp2eE5XUXVuYWJ2VHkKYWhEUDVjOFdmcUlEYnFTUkxWMndzdC9qSFplZG95dnQ2ZlVDZDJrQ2dZRUFsbzRZelRabC8vays0WGlpeHVMQQpnZ2ZieTBoS3M1QWlLcFY0Q3pVZVE1Y0tZT2k5SXpvQzJMckxTWCtVckgvd0w3MGdCRzZneUNSZ1dLaW1RbmFWCnRZTy8xM1NyUFVnbm51R2o2Q0I1YUVreXYyTGFPVmV2WEZFcmlFbWQ1cWJKSXJYMENmZ1FuRnI2dm5RZDRwUFMKOGRVMkdhaDRiNVdNSjVJdzgwU3BjR0k9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K

View File

@@ -0,0 +1,171 @@
# Development-tuned Mailu configuration
global:
# Using Unbound DNS for DNSSEC validation (required by Mailu admin)
# Unbound service is available at unbound-dns.bakery-ia.svc.cluster.local
# Static ClusterIP configured in unbound-helm/values.yaml
custom_dns_servers: "10.96.53.53" # Unbound DNS static ClusterIP
# Redis configuration - use built-in Mailu Redis (no authentication needed)
externalRedis:
enabled: false
# Component-specific DNS configuration
# Admin requires DNSSEC validation - use Unbound DNS (forwards cluster.local to kube-dns)
admin:
dnsPolicy: "None"
dnsConfig:
nameservers:
- "10.96.53.53" # Unbound DNS static ClusterIP (forwards cluster.local to kube-dns)
searches:
- "bakery-ia.svc.cluster.local"
- "svc.cluster.local"
- "cluster.local"
options:
- name: ndots
value: "5"
# RSPAMD needs Unbound for DNSSEC validation (DKIM/SPF/DMARC checks)
# Using ClusterFirst with search domains + Kubernetes DNS which can forward to Unbound
rspamd:
dnsPolicy: "ClusterFirst"
# Domain configuration for dev
# NOTE: Using .dev TLD instead of .local because email-validator library
# rejects .local domains as "special-use or reserved names" (RFC 6761)
domain: "bakery-ia.dev"
hostnames:
- "mail.bakery-ia.dev"
# Initial admin account for dev environment
# Password is stored in mailu-admin-credentials secret
initialAccount:
enabled: true
username: "admin"
domain: "bakery-ia.dev"
existingSecret: "mailu-admin-credentials"
existingSecretPasswordKey: "password"
mode: "ifmissing"
# External relay configuration for dev (Mailgun)
# All outbound emails will be relayed through Mailgun SMTP
# To configure:
# 1. Register at mailgun.com and verify your domain (bakery-ia.dev)
# 2. Get your SMTP credentials from Mailgun dashboard
# 3. Update the secret in configs/mailgun-credentials-secret.yaml
# 4. Apply the secret: kubectl apply -f configs/mailgun-credentials-secret.yaml -n bakery-ia
externalRelay:
host: "[smtp.mailgun.org]:587"
# Credentials loaded from Kubernetes secret
secretName: "mailu-mailgun-credentials"
usernameKey: "RELAY_USERNAME"
passwordKey: "RELAY_PASSWORD"
# Environment-specific configurations
persistence:
enabled: true
# Development: use default storage class
storageClass: "standard"
size: "5Gi"
# Resource optimizations for development
resources:
admin:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
front:
requests:
cpu: "50m"
memory: "64Mi"
limits:
cpu: "200m"
memory: "128Mi"
postfix:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "300m"
memory: "256Mi"
dovecot:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "300m"
memory: "256Mi"
rspamd:
requests:
cpu: "50m"
memory: "64Mi"
limits:
cpu: "200m"
memory: "128Mi"
webmail:
requests:
cpu: "50m"
memory: "64Mi"
limits:
cpu: "200m"
memory: "128Mi"
clamav:
requests:
cpu: "100m"
memory: "256Mi"
limits:
cpu: "300m"
memory: "512Mi"
replicaCount: 1 # Single replica for development
# Security settings
secretKey: "generate-strong-key-here-for-development"
# Ingress configuration for development - disabled to use with existing ingress
ingress:
enabled: false # Disable chart's Ingress; use existing one
tls: false # Disable TLS in chart since ingress handles it
tlsFlavorOverride: notls # No TLS on internal NGINX; expect external proxy to handle TLS
realIpHeader: X-Forwarded-For # Header for client IP from your Ingress
realIpFrom: 0.0.0.0/0 # Trust all proxies (restrict to your Ingress pod CIDR for security)
path: /
pathType: ImplementationSpecific
# TLS flavor for dev (may use self-signed)
tls:
flavor: "notls" # Disable TLS for development
# Welcome message (disabled in dev)
welcomeMessage:
enabled: false
# Log level for dev
logLevel: "DEBUG"
# Development-specific overrides
env:
DEBUG: "true"
LOG_LEVEL: "INFO"
# Disable or simplify monitoring in development
monitoring:
enabled: false
# Network Policy for dev
networkPolicy:
enabled: true
ingressController:
namespace: ingress-nginx
podSelector: |
matchLabels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/component: controller
monitoring:
namespace: monitoring
podSelector: |
matchLabels:
app: signoz-prometheus

View File

@@ -0,0 +1,31 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: mailu-ingress
namespace: bakery-ia
labels:
app.kubernetes.io/name: mailu
app.kubernetes.io/component: ingress
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "100m"
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- mail.bakery-ia.dev
secretName: bakery-dev-tls-cert
rules:
- host: mail.bakery-ia.dev
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: mailu-front # Helm release name 'mailu' + component 'front'
port:
number: 80

View File

@@ -0,0 +1,164 @@
# Production-tuned Mailu configuration
global:
# Using Kubernetes cluster DNS for name resolution
custom_dns_servers: "10.96.0.10" # Kubernetes cluster DNS IP
# Redis configuration - use built-in Mailu Redis (no authentication needed for internal)
externalRedis:
enabled: false
# DNS configuration for production
# Use Kubernetes DNS (ClusterFirst) which forwards to Unbound via CoreDNS
# This is configured automatically by the mailu-helm Tilt resource
admin:
dnsPolicy: "ClusterFirst"
rspamd:
dnsPolicy: "ClusterFirst"
# Domain configuration for production
domain: "bakewise.ai"
hostnames:
- "mail.bakewise.ai"
# Initial admin account for production environment
# Password is stored in mailu-admin-credentials secret
initialAccount:
enabled: true
username: "admin"
domain: "bakewise.ai"
existingSecret: "mailu-admin-credentials"
existingSecretPasswordKey: "password"
mode: "ifmissing"
# External relay configuration for production (Mailgun)
# All outbound emails will be relayed through Mailgun SMTP
# To configure:
# 1. Register at mailgun.com and verify your domain (bakewise.ai)
# 2. Get your SMTP credentials from Mailgun dashboard
# 3. Update the secret in configs/mailgun-credentials-secret.yaml
# 4. Apply the secret: kubectl apply -f configs/mailgun-credentials-secret.yaml -n bakery-ia
externalRelay:
host: "[smtp.mailgun.org]:587"
# Credentials loaded from Kubernetes secret
secretName: "mailu-mailgun-credentials"
usernameKey: "RELAY_USERNAME"
passwordKey: "RELAY_PASSWORD"
# Environment-specific configurations
persistence:
enabled: true
# Production: use microk8s-hostpath or longhorn
storageClass: "longhorn" # Assuming Longhorn is available in production
size: "20Gi" # Larger storage for production email volume
# Resource allocations for production
resources:
admin:
requests:
cpu: "200m"
memory: "256Mi"
limits:
cpu: "1"
memory: "512Mi"
front:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
postfix:
requests:
cpu: "200m"
memory: "256Mi"
limits:
cpu: "1"
memory: "512Mi"
dovecot:
requests:
cpu: "200m"
memory: "256Mi"
limits:
cpu: "1"
memory: "512Mi"
rspamd:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
clamav:
requests:
cpu: "200m"
memory: "512Mi"
limits:
cpu: "1"
memory: "1Gi"
replicaCount: 1 # Can be increased in production as needed
# Security settings
secretKey: "generate-strong-key-here-for-production"
# Ingress configuration for production - disabled to use with existing ingress
ingress:
enabled: false # Disable chart's Ingress; use existing one
tls: false # Disable TLS in chart since ingress handles it
tlsFlavorOverride: notls # No TLS on internal NGINX; expect external proxy to handle TLS
realIpHeader: X-Forwarded-For # Header for client IP from your Ingress
realIpFrom: 0.0.0.0/0 # Trust all proxies (restrict to your Ingress pod CIDR for security)
path: /
pathType: ImplementationSpecific
# TLS flavor for production (uses Let's Encrypt)
tls:
flavor: "cert"
# Welcome message (enabled in production)
welcomeMessage:
enabled: true
subject: "Welcome to Bakewise.ai Email Service"
body: "Welcome to our email service. Please change your password and update your profile."
# Log level for production
logLevel: "WARNING"
# Enable antivirus in production
antivirus:
enabled: true
flavor: "clamav"
# Production-specific settings
env:
DEBUG: "false"
LOG_LEVEL: "WARNING"
TLS_FLAVOR: "cert"
REDIS_PASSWORD: "secure-redis-password"
# Enable monitoring in production
monitoring:
enabled: true
# Production-specific security settings
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
# Network policies for production
networkPolicy:
enabled: true
ingressController:
namespace: ingress-nginx
podSelector: |
matchLabels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/component: controller
monitoring:
namespace: monitoring
podSelector: |
matchLabels:
app: signoz-prometheus

View File

@@ -0,0 +1,269 @@
#!/bin/bash
# =============================================================================
# Mailu Production Deployment Script
# =============================================================================
# This script automates the deployment of Mailu mail server for production.
# It handles:
# 1. Unbound DNS deployment (for DNSSEC validation)
# 2. CoreDNS configuration (forward to Unbound)
# 3. TLS certificate secret creation
# 4. Admin credentials secret creation
# 5. Mailu Helm deployment (admin user created automatically via initialAccount)
#
# Usage:
# ./deploy-mailu-prod.sh [--domain DOMAIN] [--admin-password PASSWORD]
#
# Example:
# ./deploy-mailu-prod.sh --domain bakewise.ai --admin-password 'SecurePass123!'
# =============================================================================
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Default values
DOMAIN="${DOMAIN:-bakewise.ai}"
ADMIN_PASSWORD="${ADMIN_PASSWORD:-}"
NAMESPACE="bakery-ia"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
MAILU_HELM_DIR="$(dirname "$SCRIPT_DIR")"
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
--domain)
DOMAIN="$2"
shift 2
;;
--admin-password)
ADMIN_PASSWORD="$2"
shift 2
;;
--help)
echo "Usage: $0 [--domain DOMAIN] [--admin-password PASSWORD]"
echo ""
echo "Options:"
echo " --domain Domain for Mailu (default: bakewise.ai)"
echo " --admin-password Password for admin@DOMAIN user"
echo ""
exit 0
;;
*)
echo -e "${RED}Unknown option: $1${NC}"
exit 1
;;
esac
done
print_step() {
echo -e "\n${BLUE}==>${NC} ${GREEN}$1${NC}"
}
print_warning() {
echo -e "${YELLOW}WARNING:${NC} $1"
}
print_error() {
echo -e "${RED}ERROR:${NC} $1"
}
print_success() {
echo -e "${GREEN}${NC} $1"
}
# =============================================================================
# Step 0: Prerequisites Check
# =============================================================================
print_step "Step 0: Checking prerequisites..."
if ! command -v kubectl &> /dev/null; then
print_error "kubectl not found. Please install kubectl."
exit 1
fi
if ! command -v helm &> /dev/null; then
print_error "helm not found. Please install helm."
exit 1
fi
if ! kubectl get namespace "$NAMESPACE" &>/dev/null; then
print_warning "Namespace $NAMESPACE does not exist. Creating..."
kubectl create namespace "$NAMESPACE"
fi
print_success "Prerequisites check passed"
# =============================================================================
# Step 1: Deploy Unbound DNS Resolver
# =============================================================================
print_step "Step 1: Deploying Unbound DNS resolver..."
if kubectl get deployment unbound -n "$NAMESPACE" &>/dev/null; then
print_success "Unbound already deployed"
else
helm upgrade --install unbound "$MAILU_HELM_DIR/../../networking/dns/unbound-helm" \
-n "$NAMESPACE" \
-f "$MAILU_HELM_DIR/../../networking/dns/unbound-helm/values.yaml" \
-f "$MAILU_HELM_DIR/../../networking/dns/unbound-helm/prod/values.yaml" \
--timeout 5m \
--wait
print_success "Unbound deployed"
fi
# Wait for Unbound to be ready
kubectl wait --for=condition=ready pod -l app.kubernetes.io/name=unbound -n "$NAMESPACE" --timeout=120s
# Get Unbound service IP
UNBOUND_IP=$(kubectl get svc unbound-dns -n "$NAMESPACE" -o jsonpath='{.spec.clusterIP}')
echo "Unbound DNS service IP: $UNBOUND_IP"
# =============================================================================
# Step 2: Configure CoreDNS to Forward to Unbound
# =============================================================================
print_step "Step 2: Configuring CoreDNS for DNSSEC validation..."
# Check current CoreDNS forward configuration
CURRENT_FORWARD=$(kubectl get configmap coredns -n kube-system -o jsonpath='{.data.Corefile}' | grep -o 'forward \. [0-9.]*' | awk '{print $3}' || echo "")
if [ "$CURRENT_FORWARD" != "$UNBOUND_IP" ]; then
echo "Updating CoreDNS to forward to Unbound ($UNBOUND_IP)..."
kubectl patch configmap coredns -n kube-system --type merge -p "{
\"data\": {
\"Corefile\": \".:53 {\\n errors\\n health {\\n lameduck 5s\\n }\\n ready\\n kubernetes cluster.local in-addr.arpa ip6.arpa {\\n pods insecure\\n fallthrough in-addr.arpa ip6.arpa\\n ttl 30\\n }\\n prometheus :9153\\n forward . $UNBOUND_IP {\\n max_concurrent 1000\\n }\\n cache 30 {\\n disable success cluster.local\\n disable denial cluster.local\\n }\\n loop\\n reload\\n loadbalance\\n}\\n\"
}
}"
# Restart CoreDNS
kubectl rollout restart deployment coredns -n kube-system
kubectl rollout status deployment coredns -n kube-system --timeout=60s
print_success "CoreDNS configured to forward to Unbound"
else
print_success "CoreDNS already configured for Unbound"
fi
# =============================================================================
# Step 3: Create TLS Certificate Secret
# =============================================================================
print_step "Step 3: Creating TLS certificate secret..."
if kubectl get secret mailu-certificates -n "$NAMESPACE" &>/dev/null; then
print_success "TLS certificate secret already exists"
else
TEMP_DIR=$(mktemp -d)
cd "$TEMP_DIR"
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout tls.key -out tls.crt \
-subj "/CN=mail.$DOMAIN/O=$DOMAIN" 2>/dev/null
kubectl create secret tls mailu-certificates \
--cert=tls.crt \
--key=tls.key \
-n "$NAMESPACE"
rm -rf "$TEMP_DIR"
print_success "TLS certificate secret created"
fi
# =============================================================================
# Step 4: Create Admin Credentials Secret
# =============================================================================
print_step "Step 4: Creating admin credentials secret..."
if kubectl get secret mailu-admin-credentials -n "$NAMESPACE" &>/dev/null; then
print_success "Admin credentials secret already exists"
# Retrieve existing password for summary output
if [ -z "$ADMIN_PASSWORD" ]; then
ADMIN_PASSWORD=$(kubectl get secret mailu-admin-credentials -n "$NAMESPACE" -o jsonpath='{.data.password}' | base64 -d)
fi
else
if [ -z "$ADMIN_PASSWORD" ]; then
# Generate a random password
ADMIN_PASSWORD=$(openssl rand -base64 16 | tr -d '/+=' | head -c 16)
echo -e "${YELLOW}Generated admin password: $ADMIN_PASSWORD${NC}"
echo -e "${YELLOW}Please save this password securely!${NC}"
fi
kubectl create secret generic mailu-admin-credentials \
--from-literal=password="$ADMIN_PASSWORD" \
-n "$NAMESPACE"
print_success "Admin credentials secret created"
fi
# =============================================================================
# Step 5: Deploy Mailu via Helm
# =============================================================================
print_step "Step 5: Deploying Mailu via Helm..."
# Add Mailu Helm repository
helm repo add mailu https://mailu.github.io/helm-charts 2>/dev/null || true
helm repo update mailu
# Deploy Mailu
helm upgrade --install mailu mailu/mailu \
-n "$NAMESPACE" \
-f "$MAILU_HELM_DIR/values.yaml" \
-f "$MAILU_HELM_DIR/prod/values.yaml" \
--timeout 10m
print_success "Mailu Helm release deployed (admin user will be created automatically)"
# =============================================================================
# Step 6: Wait for Pods to be Ready
# =============================================================================
print_step "Step 6: Waiting for Mailu pods to be ready..."
echo "This may take 5-10 minutes (ClamAV takes time to initialize)..."
# Wait for admin pod first (it's the key dependency)
kubectl wait --for=condition=ready pod -l app.kubernetes.io/component=admin -n "$NAMESPACE" --timeout=300s || {
print_error "Admin pod failed to start. Checking logs..."
kubectl logs -n "$NAMESPACE" -l app.kubernetes.io/component=admin --tail=50
exit 1
}
print_success "Admin pod is ready"
# Show pod status
echo ""
echo "Mailu Pod Status:"
kubectl get pods -n "$NAMESPACE" | grep mailu
print_success "Admin user created automatically via Helm initialAccount"
# =============================================================================
# Summary
# =============================================================================
echo ""
echo "=============================================="
echo -e "${GREEN}Mailu Deployment Complete!${NC}"
echo "=============================================="
echo ""
echo "Admin Credentials:"
echo " Email: admin@$DOMAIN"
echo " Password: $ADMIN_PASSWORD"
echo ""
echo "Access URLs (configure Ingress/DNS first):"
echo " Admin Panel: https://mail.$DOMAIN/admin"
echo " Webmail: https://mail.$DOMAIN/webmail"
echo " SMTP: mail.$DOMAIN:587 (STARTTLS)"
echo " IMAP: mail.$DOMAIN:993 (SSL)"
echo ""
echo "Next Steps:"
echo " 1. Configure DNS records (A, MX, SPF, DMARC)"
echo " 2. Get DKIM key: kubectl exec -n $NAMESPACE deployment/mailu-admin -- cat /dkim/$DOMAIN.dkim.pub"
echo " 3. Add DKIM TXT record to DNS"
echo " 4. Configure Ingress for mail.$DOMAIN"
echo ""
echo "To check pod status:"
echo " kubectl get pods -n $NAMESPACE | grep mailu"
echo ""

View File

@@ -0,0 +1,235 @@
# Base Mailu Helm values for Bakery-IA
# Preserves critical configurations from the original Kustomize setup
# Global DNS configuration for DNSSEC validation
global:
# Using Unbound DNS resolver directly for DNSSEC validation
# Unbound service is available at unbound-dns.bakery-ia.svc.cluster.local
# Static ClusterIP configured in unbound-helm/values.yaml
custom_dns_servers: "10.96.53.53" # Unbound DNS static ClusterIP
# Domain configuration
domain: "DOMAIN_PLACEHOLDER"
hostnames:
- "mail.DOMAIN_PLACEHOLDER"
# Mailu version to match the original setup
mailuVersion: "2024.06"
# Secret key for authentication cookies
secretKey: "cb61b934d47029a64117c0e4110c93f66bbcf5eaa15c84c42727fad78f7"
# Timezone
timezone: "Etc/UTC"
# Postmaster configuration
postmaster: "admin"
# Initial admin account configuration
# This creates an admin user as part of the Helm deployment
# Credentials can be provided directly or via Kubernetes secret
initialAccount:
enabled: true
username: "admin"
domain: "" # Set in environment-specific values (dev/prod)
password: "" # Leave empty to use existingSecret
existingSecret: "mailu-admin-credentials"
existingSecretPasswordKey: "password"
mode: "ifmissing" # Only create if account doesn't exist
# TLS configuration
tls:
flavor: "notls" # Disable TLS for development
# Limits configuration
limits:
messageSizeLimitInMegabytes: 50
authRatelimit:
ip: "60/hour"
user: "100/day"
messageRatelimit:
value: "200/day"
# External relay configuration (Mailgun)
# Mailu will relay all outbound emails through Mailgun SMTP
# Credentials are loaded from Kubernetes secret for security
externalRelay:
host: "[smtp.mailgun.org]:587"
# Use existing secret for credentials (recommended for security)
secretName: "mailu-mailgun-credentials"
usernameKey: "RELAY_USERNAME"
passwordKey: "RELAY_PASSWORD"
# Webmail configuration
webmail:
enabled: true
type: "roundcube"
# Antivirus and antispam configuration
antivirus:
enabled: false # Disabled in dev to save resources
antispam:
enabled: true
flavor: "rspamd"
# Welcome message
welcomeMessage:
enabled: false # Disabled during development
# Logging
logLevel: "INFO"
# Network configuration
subnet: "10.42.0.0/16"
# Redis configuration - using internal Redis (built-in)
externalRedis:
enabled: false
# host: "redis-service.bakery-ia.svc.cluster.local"
# port: 6380
adminQuotaDbId: 15
adminRateLimitDbId: 15
rspamdDbId: 15
# Database configuration - using default SQLite (built-in)
externalDatabase:
enabled: false
# type: "postgresql"
# host: "postgres-service.bakery-ia.svc.cluster.local"
# port: 5432
# database: "mailu"
# username: "mailu"
# password: "E8Kz47YmVzDlHGs1M9wAbJzxcKnGONCT"
# Persistence configuration
persistence:
single_pvc: true
size: 10Gi
storageClass: ""
accessModes: [ReadWriteOnce]
# Ingress configuration - disabled to use with existing ingress
ingress:
enabled: false # Disable chart's Ingress; use existing one
tls: false # Disable TLS in chart since ingress handles it
tlsFlavorOverride: notls # No TLS on internal NGINX; expect external proxy to handle TLS
realIpHeader: X-Forwarded-For # Header for client IP from your Ingress
realIpFrom: 0.0.0.0/0 # Trust all proxies (restrict to your Ingress pod CIDR for security)
path: /
pathType: ImplementationSpecific
# Optional: Enable PROXY protocol for mail protocols if your Ingress supports TCP proxying
proxyProtocol:
smtp: false
smtps: false
submission: false
imap: false
imaps: false
pop3: false
pop3s: false
manageSieve: false
# Front configuration
front:
image:
tag: "2024.06"
replicaCount: 1
service:
type: ClusterIP
ports:
http: 80
https: 443
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 200m
memory: 256Mi
# Admin configuration
admin:
image:
tag: "2024.06"
replicaCount: 1
service:
type: ClusterIP
port: 80
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 300m
memory: 512Mi
# Postfix configuration
postfix:
image:
tag: "2024.06"
replicaCount: 1
service:
type: ClusterIP
ports:
smtp: 25
submission: 587
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
# Dovecot configuration
dovecot:
image:
tag: "2024.06"
replicaCount: 1
service:
type: ClusterIP
ports:
imap: 143
imaps: 993
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
# Rspamd configuration
rspamd:
image:
tag: "2024.06"
replicaCount: 1
service:
type: ClusterIP
ports:
rspamd: 11333
rspamd-admin: 11334
resources:
requests:
cpu: 200m
memory: 512Mi
limits:
cpu: 1000m
memory: 1Gi
# Network Policy
networkPolicy:
enabled: true
ingressController:
namespace: ingress-nginx
podSelector: |
matchLabels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/component: controller
# DNS Policy Configuration
# Use Kubernetes DNS (ClusterFirst) for internal service resolution
# DNSSEC validation for email is handled by rspamd component
# Note: For production with DNSSEC needs, configure CoreDNS to forward to Unbound
dnsPolicy: "ClusterFirst"