feat(mail): Z-Push Exchange ActiveSync gateway for mobile clients
Wraps Stalwart in EAS so iOS/Android native Mail/Calendar 'Exchange' accounts get two-way mail+calendar+contacts sync (BackendCombined: IMAP + CalDAV /dav/cal/%l/ + CardDAV, credentials pass through). - services/zpush: Z-Push 2.6.4 (AGPLv3, see LICENSE-NOTES.md) on php:8.2-apache-bookworm (trixie dropped libc-client); PHP 8 sysv sprintf fatal sed-patched; autodiscover dispatcher answers mobilesync schema, proxies outlook schema to Stalwart unchanged - prod: zpush Deployment (replicas:1, Recreate — file sync state), /Microsoft-Server-ActiveSync Ingress on mail.dezky.eu (no redirect, POST-heavy), autodiscover.dezky.eu repointed to the dispatcher, selectorless stalwart-imaps/-smtps Services (host-Stalwart is implicit-TLS only: 993/465, no plain 143/587 — verified on node1) - CI: build+deploy zpush like the other apps EAS tops out at 14.1: covers native mobile clients, NOT the Outlook mobile app (needs 16.1) and not new Outlook for Windows (no EAS).
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
# dezky EAS gateway — Z-Push (AGPLv3) wrapping Stalwart in Exchange
|
||||
# ActiveSync so "Exchange" accounts on iOS/Android native Mail/Calendar get
|
||||
# two-way mail + calendar + contacts sync. Z-Push talks to Stalwart with the
|
||||
# client's own Basic credentials (mailbox password or app password) over
|
||||
# IMAP/CalDAV/CardDAV — this container stores no secrets, only sync state.
|
||||
#
|
||||
# Z-Push 2.6.x speaks EAS up to 14.1. That covers native mobile clients but
|
||||
# NOT the Outlook mobile app (Microsoft enforces EAS >= 16.1 there since
|
||||
# March 2026) and not new Outlook for Windows (no EAS at all). See
|
||||
# LICENSE-NOTES.md for the AGPL source-offer obligation.
|
||||
|
||||
ARG ZPUSH_VERSION=2.6.4
|
||||
|
||||
FROM alpine/git AS source
|
||||
ARG ZPUSH_VERSION
|
||||
RUN git clone --depth 1 --branch ${ZPUSH_VERSION} \
|
||||
https://github.com/EGroupware/z-push.git /z-push
|
||||
|
||||
# php:8.2 — the imap extension lives in PHP core through 8.3 and moved to
|
||||
# PECL in 8.4; stay on a version where docker-php-ext-install still works.
|
||||
# Pinned to the bookworm base: Debian trixie dropped the (upstream-dead)
|
||||
# uw-imap libc-client packages the imap extension compiles against.
|
||||
FROM php:8.2-apache-bookworm
|
||||
ARG ZPUSH_VERSION
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
libc-client2007e-dev libkrb5-dev libicu-dev \
|
||||
&& docker-php-ext-configure imap --with-kerberos --with-imap-ssl \
|
||||
&& docker-php-ext-install -j"$(nproc)" imap intl sysvshm sysvsem \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY --from=source /z-push/src/ /usr/share/z-push/
|
||||
|
||||
# Main config: keep the 50+ upstream defaults, patch only what we change.
|
||||
# The greps make the build fail loudly if an upstream config rename ever
|
||||
# makes a sed miss instead of shipping a silently unconfigured gateway.
|
||||
# (USE_FULLEMAIL_FOR_LOGIN is already true in the EGroupware fork.)
|
||||
RUN sed -i \
|
||||
-e "s|define('TIMEZONE', '');|define('TIMEZONE', 'Europe/Copenhagen');|" \
|
||||
-e "s|define('BACKEND_PROVIDER', '');|define('BACKEND_PROVIDER', 'BackendCombined');|" \
|
||||
/usr/share/z-push/config.php \
|
||||
&& grep -q "define('BACKEND_PROVIDER', 'BackendCombined')" /usr/share/z-push/config.php \
|
||||
&& grep -q "define('USE_FULLEMAIL_FOR_LOGIN', true)" /usr/share/z-push/config.php
|
||||
|
||||
# PHP 8 fix (upstream Z-Push 2.6.4 bug): sem_get()/shm_attach() return
|
||||
# objects instead of resources since PHP 8.0 and this debug log line
|
||||
# sprintf's them — a fatal TypeError on every request. The rest of the
|
||||
# provider only compares the handles against false, which is PHP 8-safe.
|
||||
RUN sed -i \
|
||||
's|sprintf("%s(): Initialized mutexid %s and memid %s.", $class, $this->mutexid, $this->memid)|sprintf("%s(): Initialized shared memory mutex and segment.", $class)|' \
|
||||
/usr/share/z-push/backend/ipcsharedmemory/ipcsharedmemoryprovider.php \
|
||||
&& grep -q "Initialized shared memory mutex and segment" \
|
||||
/usr/share/z-push/backend/ipcsharedmemory/ipcsharedmemoryprovider.php
|
||||
|
||||
# Backend + autodiscover configs are small files — full replacements.
|
||||
COPY config/caldav.config.php /usr/share/z-push/backend/caldav/config.php
|
||||
COPY config/carddav.config.php /usr/share/z-push/backend/carddav/config.php
|
||||
COPY config/imap.config.php /usr/share/z-push/backend/imap/config.php
|
||||
COPY config/combined.config.php /usr/share/z-push/backend/combined/config.php
|
||||
COPY config/autodiscover.config.php /usr/share/z-push/autodiscover/config.php
|
||||
|
||||
# Schema-sniffing autodiscover dispatcher (mobilesync → Z-Push, outlook
|
||||
# schema → proxied to Stalwart). Lives inside autodiscover/ because
|
||||
# autodiscover.php resolves its requires relative to that directory.
|
||||
COPY autodiscover-router.php /usr/share/z-push/autodiscover/router.php
|
||||
|
||||
COPY apache/zpush.conf /etc/apache2/conf-available/zpush.conf
|
||||
COPY php/zpush.ini /usr/local/etc/php/conf.d/zpush.ini
|
||||
RUN a2enconf zpush \
|
||||
&& mkdir -p /var/lib/z-push/state /var/log/z-push \
|
||||
&& chown -R www-data:www-data /var/lib/z-push /var/log/z-push \
|
||||
&& echo "${ZPUSH_VERSION}" > /usr/share/z-push/DEZKY_PINNED_VERSION
|
||||
|
||||
VOLUME /var/lib/z-push
|
||||
EXPOSE 80
|
||||
Reference in New Issue
Block a user