# zpush — Exchange ActiveSync gateway (Z-Push, AGPLv3) in front of host- # Stalwart. Gives "Exchange" accounts on iOS/Android native Mail/Calendar # two-way mail+calendar+contacts sync. EAS 14.1: covers native mobile # clients, NOT the Outlook mobile app (requires EAS 16.1) and not new # Outlook for Windows (no EAS at all). Credentials pass through to Stalwart # per-request (mailbox password or app password) — the pod stores only sync # state, which is disposable (devices resync after a wipe). # # replicas MUST stay 1: Z-Push's FILE state machine is not multi-writer-safe # (same constraint family as the portal/operator session pinning). apiVersion: v1 kind: PersistentVolumeClaim metadata: name: zpush-state namespace: dezky-apps labels: app.kubernetes.io/name: zpush app.kubernetes.io/part-of: dezky spec: accessModes: [ReadWriteOnce] storageClassName: local-path resources: requests: storage: 1Gi --- apiVersion: apps/v1 kind: Deployment metadata: name: zpush namespace: dezky-apps labels: app.kubernetes.io/name: zpush app.kubernetes.io/part-of: dezky spec: replicas: 1 # Recreate, not RollingUpdate: the state PVC is RWO and the state machine # must never have two writers. strategy: type: Recreate selector: matchLabels: app.kubernetes.io/name: zpush template: metadata: labels: app.kubernetes.io/name: zpush spec: containers: - name: zpush # CI pins this to the commit SHA at deploy time; :latest is the fallback. image: git.lastcloud.io/ronnibaslund/dezky/zpush:latest imagePullPolicy: IfNotPresent ports: - name: http containerPort: 80 env: # Host-Stalwart reached via the selectorless Services pinning the # cni0 gateway address (see mail-autodiscovery.yaml). - name: CALDAV_SERVER value: stalwart-http.dezky-apps.svc.cluster.local - name: CALDAV_PORT value: "8080" # Host-Stalwart only exposes implicit-TLS IMAPS/SMTPS (no plain # 143/587) — hence /ssl with novalidate-cert (the cert names # mail.dezky.eu, not the cluster service) and the ssl:// prefix. - name: IMAP_SERVER value: stalwart-imaps.dezky-apps.svc.cluster.local - name: IMAP_PORT value: "993" - name: IMAP_OPTIONS value: /ssl/novalidate-cert - name: SMTP_SERVER value: ssl://stalwart-smtps.dezky-apps.svc.cluster.local - name: SMTP_PORT value: "465" # Hostname EAS autodiscover responses point devices at. - name: ZPUSH_HOST value: mail.dezky.eu # Outlook-schema (mail) autodiscover POSTs proxied to Stalwart. - name: MAIL_AUTODISCOVER_UPSTREAM value: http://stalwart-http.dezky-apps.svc.cluster.local:8080 volumeMounts: - name: state mountPath: /var/lib/z-push resources: requests: cpu: 100m memory: 192Mi limits: memory: 512Mi readinessProbe: tcpSocket: port: http initialDelaySeconds: 5 periodSeconds: 15 livenessProbe: tcpSocket: port: http initialDelaySeconds: 15 periodSeconds: 30 volumes: - name: state persistentVolumeClaim: claimName: zpush-state --- apiVersion: v1 kind: Service metadata: name: zpush namespace: dezky-apps labels: app.kubernetes.io/name: zpush spec: selector: app.kubernetes.io/name: zpush ports: - name: http port: 80 targetPort: http --- # EAS endpoint on mail.dezky.eu. Path-scoped: everything else on the host # (CalDAV well-knowns, /dav) keeps routing to Stalwart via the mail-dav # Ingress. NO redirect middleware — EAS is POST-heavy and devices don't # follow 301s (same reasoning as the autodiscover Ingress). No cert-manager # annotation either: the mail-dav Ingress already owns the Certificate that # keeps mail-dezky-eu-traefik-tls fresh; we only reference the secret. apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: zpush-eas namespace: dezky-apps annotations: traefik.ingress.kubernetes.io/router.entrypoints: web,websecure spec: ingressClassName: traefik tls: - hosts: - mail.dezky.eu secretName: mail-dezky-eu-traefik-tls rules: - host: mail.dezky.eu http: paths: - path: /Microsoft-Server-ActiveSync pathType: Prefix backend: service: name: zpush port: number: 80