#!/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. Mailu Helm deployment # 5. Admin user creation # # 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: Deploy Mailu via Helm # ============================================================================= print_step "Step 4: 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" # ============================================================================= # Step 5: Wait for Pods to be Ready # ============================================================================= print_step "Step 5: 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 # ============================================================================= # Step 6: Create Admin User # ============================================================================= print_step "Step 6: Creating admin user..." 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 exec -n "$NAMESPACE" deployment/mailu-admin -- \ flask mailu admin admin "$DOMAIN" "$ADMIN_PASSWORD" 2>/dev/null || { print_warning "Admin user may already exist or failed to create" } print_success "Admin user configured" # ============================================================================= # 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 ""