Server installation
Before proceeding, ensure that Java 21 or later is installed on your system. See the Java installation guide for instructions.
MSH Zimbra Rules ships as a single package, msh-zr-<VERSION>.tgz, that unpacks to /opt/msh-zr and contains two systemd services:
| Component | Service unit | Default port | Purpose |
|---|---|---|---|
msh-zr-milter | msh-zr-milter.service | 7080 | Milter engine (processes mail for the Zimbra MTA) |
msh-zr-web | msh-zr-web.service | 7081 | Web admin UI |
Both services run as the unprivileged msh user and share one database at /opt/msh-zr/etc/msh-zr.db. The web UI writes the configuration the milter reads.
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-milter.service
sudo systemctl link /opt/msh-zr/lib/msh-zr-web.service
sudo systemctl daemon-reload
sudo systemctl enable msh-zr-milter.service msh-zr-web.service
sudo systemctl start 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:
- Ensuring proper ownership (msh user/group)
- Restricting directory access (750)
- Restricting file access (640, making files non-executable by default)
- Explicitly making only the necessary scripts executable (750)
sudo sh /opt/msh-zr/lib/fixperms.sh
Create symbolic links for the msh-zr-milter.service and msh-zr-web.service unit files, allowing the system to recognize and manage the services.
sudo systemctl link /opt/msh-zr/lib/msh-zr-milter.service
sudo systemctl link /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-milter.service msh-zr-web.service
Manually start the services for immediate activation.
sudo systemctl start msh-zr-milter.service msh-zr-web.service
Verify
Check the current status of the services to verify they are running correctly (press q to exit).
systemctl status msh-zr-milter.service
systemctl status msh-zr-web.service
Verify the line:
Active: active (running)
Live logs (launcher and application output both reach the journal):
journalctl -u msh-zr-milter.service -f
journalctl -u msh-zr-web.service -f
The same output is also appended to /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.
The milter listens on all interfaces (0.0.0.0:7080). If the host is reachable from untrusted networks, restrict ports 7080 and 7081 with a firewall (e.g. ufw) so that only the MTA can reach the milter and only administrators can reach the web UI.
Enable HTTPS for the web UI (recommended)
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:
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.
What's next
- Zimbra configuration - wire the milter into the Zimbra MTA so mail flows through it
- Troubleshooting starting services - diagnostic steps if the services do not run