Skip to main content
Version: 1.2

Single server

info

Before proceeding, ensure that Java 21 or later is installed on your system. See the Java installation guide for instructions.

This page installs MSH Zimbra Rules on a single Zimbra server. The server runs all three services:

ComponentService unitDefault portPurpose
msh-zr-webmsh-zr-web.service7081Web admin UI, holds the rules and settings
msh-zr-nodemsh-zr-node.service7082Receives the rules and settings from the web admin for the milter on this host
msh-zr-miltermsh-zr-milter.service7080Milter engine (processes mail for the Zimbra MTA)

All three run as the unprivileged msh user from /opt/msh-zr. For a Zimbra installation with several MTA servers, see Web admin server and MTA servers instead.

Commands​

Here are the commands needed to install and start the application services. They can be invoked one by one in the terminal. If you would like to have a description of each command, please refer to the Description section below.

sudo useradd --system --no-create-home --shell /usr/sbin/nologin --home /opt/msh-zr msh
sudo tar zxvf msh-zr-<VERSION>.tgz -C /opt
sudo sh /opt/msh-zr/lib/fixperms.sh
sudo systemctl link /opt/msh-zr/lib/msh-zr-node.service /opt/msh-zr/lib/msh-zr-milter.service /opt/msh-zr/lib/msh-zr-web.service
sudo systemctl daemon-reload
sudo systemctl enable msh-zr-node.service msh-zr-milter.service msh-zr-web.service
sudo systemctl start msh-zr-node.service msh-zr-milter.service msh-zr-web.service

Description​

Add the msh system user.

  • --system - creates a system account (no password, no interactive login)
  • --no-create-home - won't auto-create /home/msh, since /opt/msh-zr is its home
  • --shell /usr/sbin/nologin - prevents login
  • --home /opt/msh-zr - sets /opt/msh-zr as its "home"
  • msh - username
sudo useradd --system --no-create-home --shell /usr/sbin/nologin --home /opt/msh-zr msh

Extract the msh-zr-<VERSION>.tgz package to the /opt system directory. This creates /opt/msh-zr.

sudo tar zxvf msh-zr-<VERSION>.tgz -C /opt

Run the fixperms.sh script, which secures the application installation by:

  1. Ensuring proper ownership (msh user/group)
  2. Restricting directory access (750)
  3. Restricting file access (640, making files non-executable by default)
  4. Explicitly making only the necessary scripts executable (750)
  5. Making the node's token and certificate files readable by the msh user only (600)
sudo sh /opt/msh-zr/lib/fixperms.sh

Create symbolic links for the three unit files, allowing the system to recognize and manage the services.

sudo systemctl link /opt/msh-zr/lib/msh-zr-node.service /opt/msh-zr/lib/msh-zr-milter.service /opt/msh-zr/lib/msh-zr-web.service

Reload systemd to apply changes from the newly linked service files.

sudo systemctl daemon-reload

Enable the services to start automatically on system boot.

sudo systemctl enable msh-zr-node.service msh-zr-milter.service msh-zr-web.service

Start the services. The order does not matter.

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

On its first start the node creates its access token (etc/node.token) and its HTTPS certificate (etc/node.p12, with its password in etc/node.p12.password). The web admin reads the token from the same directory and connects to the node by itself.

Verify​

Check the current status of the services to verify they are running correctly (press q to exit).

systemctl status msh-zr-node.service msh-zr-milter.service msh-zr-web.service

Verify the line for each of them:

Active: active (running)

Live logs (launcher and application output both reach the journal):

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

The same output is also appended to /opt/msh-zr/var/log/node.out, /opt/msh-zr/var/log/milter.out and /opt/msh-zr/var/log/web.out.

First login​

Open the web admin UI in your browser:

http://<host>:7081

(or https://<host>:7081 if you enabled HTTPS below). The first login uses the seeded admin / admin account. Change the password immediately on the Access Control page.

Then open the Servers page. It lists This server with the state Up to date once the web admin has sent it the settings, usually within a few seconds. Until a server is listed, the Dashboard shows the notice No server is configured, so rules are not applied to any mail.

Next, set up the Directory service so the web admin can read users and groups from the Zimbra LDAP.

note

The milter listens on all interfaces (0.0.0.0:7080) and the node on 0.0.0.0:7082. If the host is reachable from untrusted networks, restrict the ports with a firewall (e.g. ufw): only the MTA on this host needs 7080, only the web admin needs 7082, and only administrators need 7081. See Ports and firewall.

The web UI serves plain HTTP by default, which sends the administrator password in clear text over the network. Enabling HTTPS is recommended. To serve HTTPS you need a PKCS12 keystore in etc/. The keystore is host-specific and contains a private key, so it is always created on the server itself and never shipped in the package.

Generate a self-signed certificate (good for an internal admin UI; browsers warn until the certificate is trusted):

sudo -u msh /opt/msh-zr/bin/gen-cert -host mail.example.com -pass 'choose-a-password'

Then set the two values it prints in etc/config.cf:

/opt/msh-zr/etc/config.cf
WEB_SSL_KEYSTORE=etc/keystore.p12
WEB_SSL_KEYSTORE_PASSWORD=choose-a-password

To use a real certificate (CA / Let's Encrypt) instead, convert it to PKCS12 and point the same two settings at it:

sudo openssl pkcs12 -export \
-in fullchain.pem -inkey privkey.pem \
-name msh-zr-web -out /opt/msh-zr/etc/keystore.p12
sudo chown msh:msh /opt/msh-zr/etc/keystore.p12
sudo chmod 640 /opt/msh-zr/etc/keystore.p12

Restart the web service to apply the change:

sudo systemctl restart msh-zr-web.service

When a keystore is configured, the web UI serves HTTPS on the same port (7081 by default). If the keystore path is set but the file is missing, the launcher logs a warning and falls back to HTTP.

The launcher hands the password to the web app through the environment, not on the command line, so it does not show in the process list, and the web app masks passwords, secrets, keys and tokens as ****** in its startup log (see Logs).

This certificate is for the web admin only. The node always serves HTTPS with the certificate it created itself, and the web admin trusts it by the fingerprint it saw when the server was added.

What's next​