Skip to main content

Update

Everything host-local lives in /opt/msh-zr/etc/: your configuration (config.cf), the database (msh-zr.db) and the HTTPS keystore (keystore.p12). Exclude etc/ from the extraction so the update replaces the code (jars, launchers, lib/defaults.cf, service units) while leaving your configuration and database untouched.

Mail flow during the update

warning

While msh-zr-milter.service is stopped, Postfix cannot reach the milter and falls back to milter_default_action. With the recommended accept (see Zimbra configuration) mail keeps flowing, but no rules are applied - messages arriving during the update are delivered without signatures, disclaimers, blocking or any other action, and nothing is logged about them. The window is usually only a few seconds, but if your rules matter for security (blocked senders, attachment filtering, quarantine), do not rely on it being empty.

If unfiltered mail during the update is not acceptable, temporarily switch the default action to tempfail for the duration. Postfix then answers every incoming message with 451 4.7.1 Service unavailable - try again later while the milter is down: sending mail servers keep the message in their own queue and retry (typically within 5-15 minutes), and locally injected mail stays in Zimbra's queue. Nothing is lost, only delayed. Users sending from the Zimbra web client during those seconds see the same 451 error and have to resend.

Before stopping the services, as the zimbra user (sudo su - zimbra):

zmprov ms $(zmhostname) zimbraMtaMilterDefaultAction tempfail
zmmtactl reload

Wait until Postfix has picked up the change before you stop the milter - check with postconf milter_default_action until it reports tempfail.

After the update, once msh-zr-milter.service is running again, switch back:

zmprov ms $(zmhostname) zimbraMtaMilterDefaultAction accept
zmmtactl reload

Deferred messages are delivered as soon as the sending servers retry; run mailq on the Zimbra host to see anything still waiting locally.

info

Stopping the whole MTA instead (zmmtactl stop) also prevents unfiltered mail, but it additionally pauses outbound delivery and rejects connections at the TCP level, so tempfail is the less disruptive option.

Commands

sudo systemctl stop msh-zr-web.service msh-zr-milter.service
sudo tar zxvf msh-zr-<VERSION>.tgz -C /opt --exclude='msh-zr/etc/*'
sudo sh /opt/msh-zr/lib/fixperms.sh
sudo systemctl daemon-reload
sudo systemctl start msh-zr-milter.service msh-zr-web.service

Description

Stop both services. From this point until the milter is started again, mail is handled according to milter_default_action (see Mail flow during the update).

sudo systemctl stop msh-zr-web.service msh-zr-milter.service

Unpack the new package over the existing tree, keeping the live etc/ directory as-is.

sudo tar zxvf msh-zr-<VERSION>.tgz -C /opt --exclude='msh-zr/etc/*'

Re-apply ownership and permissions.

sudo sh /opt/msh-zr/lib/fixperms.sh

Reload systemd to pick up any changes to the service unit files.

sudo systemctl daemon-reload

Start the services again. If you switched milter_default_action to tempfail for the update, set it back to accept now.

sudo systemctl start msh-zr-milter.service msh-zr-web.service

Verify

The web application applies any pending database migrations on startup, so the schema is upgraded automatically the first time the new version runs. Watch the logs to confirm a clean start:

journalctl -u msh-zr-web.service -f
journalctl -u msh-zr-milter.service -f

Then open the web admin UI and check that the new version is running.

Additional resources