How we got from upstream Mail-in-a-Box v76 to a working custom fork on Ubuntu 24.04 LTS (noble)
v76-base in the fork)
noble-php83-py312-rspamd
Upstream v76 supports Ubuntu 22.04 only. Running it on 24.04 fails in several independent places, any one of which stops the install:
| Blocker | Where | What happens on 24.04 |
|---|---|---|
| OS version gate | setup/preflight.sh |
Refuses anything but 22.04 |
| PHP 8.0 from ppa:ondrej/php | setup/system.sh, setup/functions.sh |
Third-party PPA for an EOL PHP; 24.04 ships 8.3 |
| PEP 668 | setup/questions.sh, setup/management.sh |
noble's pip 24.0 refuses pip3 install into the system Python: error: externally-managed-environment |
cryptography==37.0.2 |
setup/management.sh |
No wheel for Python 3.12; pip falls back to a source build needing an old Rust toolchain |
| SpamAssassin 4.0 | setup/spamassassin.sh |
Major version jump; /etc/default/spamassassin no longer exists; spampd's embedding of SpamAssassin untested against 4.0 |
| Hard-coded php8.0 paths | nginx config, backup code, tools | Every PHP page returns an error; backups abort |
systemctl link |
setup/management.sh, setup/munin.sh |
systemd 255 refuses to enable the unit — management daemon never starts at boot |
The goal was the smallest diff from v76 that runs correctly on 24.04 — not a rewrite. The plan was worked in phases:
| Phase | Work |
|---|---|
| 1 | Preflight gate, trivial package fixes, remove PPAs |
| 2 | Python daemon on 3.12 via uv |
| 3 | PHP 8.3, remove Z-Push |
| 4 | Fresh Nextcloud 33 install |
| 5a | Rspamd for spam + greylisting (OpenDKIM/OpenDMARC kept) |
| — | Sandbox mode, test harness, and fixes found by testing |
Two decisions shaped everything else:
OpenDKIM and OpenDMARC stayed exactly as v76 had them. Rspamd can do DKIM signing, but moving
it means rewriting key generation in management/dns_update.py and validation in
management/status_checks.py. DKIM decides whether Gmail accepts your mail, so that change
was deferred to a later, unhurried "Phase 5b". The successful Gmail/Outlook tests confirm this held
up.
Every change was tested by actually installing it. A static read of the code found the obvious problems. A real install in an Ubuntu 24.04 container found eight more that would have stopped or silently broken a live box.
setup/preflight.sh and setup/bootstrap.sh now accept exactly Ubuntu
24.04 — an exact match, not "24.04 or newer". A box should refuse to install on an untested release
rather than half-work.
| Repository | v76 | Fork | Why |
|---|---|---|---|
ppa:ondrej/php |
Yes (PHP 8.0) | Removed | noble ships PHP 8.3 with every module needed |
ppa:duplicity-team/duplicity-release-git |
Yes | Removed | noble ships duplicity 2.1.4 in main |
| Rspamd project repo | No | Added | Needed to replace SpamAssassin smoothly |
The Rspamd repository is the only third-party source left. Its signing key is pinned by fingerprint and
apt-pinned so it can supply only the rspamd package. Setting
RSPAMD_PACKAGE_SOURCE=ubuntu uses Ubuntu's package instead and leaves no third-party repositories
at all. The choice is saved in /etc/mailinabox.conf so a later re-run of setup can't
silently switch.
| Package | Change | Reason |
|---|---|---|
ntp |
Removed | On noble it's a transitional package pulling in ntpsec, which fights systemd-timesyncd. MIAB never configured it. |
libmagic1 |
→ libmagic1t64 | Renamed in noble's 64-bit time_t transition. The old name still resolves, but naming the real package is safer. |
bind9-host, bind9-dnsutils |
Added to base packages | v76 only installed host from the network checks, so a box that skipped them had no DNS tools. |
python3 |
Installed at start | tools/editconf.py and setup/migrate.py use python3 and run before anything else installs it. |
Every package name was checked against the real noble package indexes before any code was changed. Highlights include Postfix jumping to 3.8.6, Dovecot to 2.3.21, and nsd to 4.8.0.
nsd 4.8: nsd jumped five minor versions. setup/dns.sh now runs
nsd-checkconf on the generated config straight after install, so an unsupported directive fails
immediately with a precise message rather than as a mysterious service failure later.
PHP_VER=8.0 → PHP_VER=8.3 in setup/functions.sh. All required
modules exist in noble's stock archive. Roundcube 1.6.15 supports PHP 8.3 without changes.
Changing the variable was not enough. v76 had 8.0 written directly into files that never
read the variable, causing every PHP page to fail and backups to abort. Setup now records
PHP_VERSION=8.3 in /etc/mailinabox.conf. A new helper reads it, and the nginx
template uses a placeholder that is filled in when the web config is generated.
Ubuntu 24.04's pip enforces PEP 668, preventing installation into the system Python. Furthermore, v76
pinned cryptography==37.0.2 which has no wheel for Python 3.12, causing pip to attempt a source
build.
uv installs its own CPython, so the management daemon never touches the system Python at all[cite:
2]. The installer changed from pip install --upgrade to uv sync --frozen using a
lockfile (management/uv.lock) to guarantee reproducibility.
Unpinning resolved to cryptography 50.0.1. All functions were tested directly (Loading certificate chains, validity checks, CSRs, TOTP two-factor codes, QR code generation) and passed.
Nextcloud was updated from 26.0.13 to 33.0.9 to support PHP 8.3 and the updated
user_external app. The upgrade ladder was removed since a fresh install doesn't need
it.
Finding: Nextcloud login no longer needs PHP's IMAP extension, it uses cURL's built-in imap support, preparing the ground well for Ubuntu 26.04 which drops ext/imap from PHP core.
Keeping SpamAssassin looked safer but wasn't. noble ships SpamAssassin 4.0.0, and the v76 config no longer exists. Rspamd with Postfix and Dovecot is a very widely used, well-documented setup.
| v76 component | Job | Replaced by |
|---|---|---|
| spampd + spamassassin | Spam scoring | Rspamd, connected to Postfix as a milter |
| postgrey | Greylisting | Rspamd's greylist module |
| razor, pyzor | Shared spam signatures | Rspamd's fuzzy hashing and reputation |
| dovecot-antispam | Learn from Spam-folder moves | Dovecot IMAPSieve + rspamc |
| libmail-dkim-perl | DKIM checks inside SpamAssassin | Rspamd's own DKIM checks |
| — | — | redis-server (new data store) |
Rspamd checks mail while the sender is still connected, enabling immediate greylisting rejections without needing a separate daemon.
Z-Push was removed completely rather than carried forward to PHP 8.3, including its config, nginx locations, and autodiscover subdomains. The general CalDAV/CardDAV proxy in nginx stays.
Each of these was found by installing the fork in a real Ubuntu 24.04 container, not by reading code.
| # | Bug | What would have happened |
|---|---|---|
| 1 | php8.0-fpm.sock hard-coded in nginx | Every PHP page fails |
| 2 | systemctl link on a unit already in /lib/systemd/system | systemd 255 refuses to enable it; management daemon never starts |
| 3 | Both classifier-bayes.conf and statistic.conf in Rspamd's local.d | Rspamd refuses to start |
| 4 | postgrey still installed by mail-postfix.sh | Two greylisting systems running; postgrey doing the work |
| 5 | Redis data-folder permissions set in the wrong order | Redis fails at next reboot; spam filtering silently degrades |
| 6 | Redis blocked from /home by its systemd lockdown | Redis won't start at all |
| 7 | fail2ban won't start if /var/log/auth.log doesn't exist yet | No brute-force protection on a fresh box |
| 8 | tr < /dev/urandom | head with set -o pipefail | Setup exits with code 141 (broken pipe) |
| 9 | boto3 missing from the daemon's environment | Admin panel returns HTTP 500 |
| 10 | sievec doesn't read plugin settings on its own | Spam-learning scripts can't be compiled |
| 11 | resolved.conf missing on minimal images | Setup crashes |
The self-test checks that internal-only services aren't reachable from the internet. Dovecot quota-status (port 12340) and munin-node (port 4949) were changed to listen on localhost only, resolving issues that existed in v76.
A sandbox mode was created allowing installation of the full box on a local VM/container with no public DNS, Let's Encrypt, or outbound port 25. The test harness runs 88 distinct checks covering services, ports, config validity, DNS, TLS, and mail flow (spam headers, greylisting, training).
Backups via duplicity need to be tested end-to-end to confirm they fully backup and restore properly with the new b2sdk/boto3 UV environment. Also deferred is moving DKIM signing and DMARC into Rspamd (Phase 5b), and testing for Ubuntu 26.04.