§2027-10-02

WildDuck uses ZoneMTA as its outbound mail relay, and ZoneMTA is responsible for handling the DKIM (DomainKeys Identified Mail) signing of the outgoing emails.

Here's a breakdown of the process:

#! /bin/bash

OURNAME=09_install_zone_mta.sh

# ${ORANGE} is Orange color
echo -e "\n-- Executing ${ORANGE}${OURNAME}${NC} subscript --"


#### ZoneMTA ####

# $ grep -r 'SYSTEMCTL_PATH=' . --> to find where it was defined
# It is defined in 06_install_enable_services.sh byt the following line
# SYSTEMCTL_PATH=`command -v systemctl`
# ./06_install_enable_services.sh:SYSTEMCTL_PATH=`command -v systemctl`

# clear previous install
if [ -f "/etc/systemd/system/zone-mta.service" ]
then
    # grep -r SYSTEMCTL_PATH . --> to find out where it is defined
    $SYSTEMCTL_PATH stop zone-mta || true
    # ||: This operator is a logical OR. It means "execute the next command only if the previous command fails." I
    # true: This is a command that always succeeds (returns an exit status of 0)
    # even it fails to stop, keeps on going
    $SYSTEMCTL_PATH disable zone-mta || true
    rm -rf /etc/systemd/system/zone-mta.service
fi
rm -rf /var/opt/zone-mta.git
rm -rf /var/opt/zonemta-wildduck.git
rm -rf /opt/zone-mta
rm -rf /etc/zone-mta

# fresh install
cd /var/opt
git clone --bare https://github.com/zone-eu/zone-mta-template.git zone-mta.git
git clone --bare https://github.com/nodemailer/zonemta-wildduck.git

# create update hooks so we can later deploy to this location
# hook_script defined in 00_install_global_functions_variables.sh
 
echo "#!/bin/bash
git --git-dir=/var/opt/zonemta-wildduck.git --work-tree=/opt/zone-mta/plugins/wildduck checkout "\$3" -f
cd /opt/zone-mta/plugins/wildduck
rm -rf package-lock.json
npm install --production --no-optional --no-package-lock --no-audit --ignore-scripts --no-shrinkwrap --progress=false
sudo $SYSTEMCTL_PATH restart zone-mta || echo \"Failed restarting service\"" > "/var/opt/zonemta-wildduck.git/hooks/update"
chmod +x "/var/opt/zonemta-wildduck.git/hooks/update"

# allow deploy user to restart zone-mta service
echo "deploy ALL = (root) NOPASSWD: $SYSTEMCTL_PATH restart zone-mta" >> /etc/sudoers.d/zone-mta

# checkout files from git to working directory
mkdir -p /opt/zone-mta
git --git-dir=/var/opt/zone-mta.git --work-tree=/opt/zone-mta checkout "$ZONEMTA_COMMIT"

mkdir -p /opt/zone-mta/plugins/wildduck
git --git-dir=/var/opt/zonemta-wildduck.git --work-tree=/opt/zone-mta/plugins/wildduck checkout "$WILDDUCK_ZONEMTA_COMMIT"

cp -r /opt/zone-mta/config /etc/zone-mta
sed -i -e 's/port=2525/port=587/g;s/host="127.0.0.1"/host="0.0.0.0"/g;s/authentication=false/authentication=true/g' /etc/zone-mta/interfaces/feeder.toml
rm -rf /etc/zone-mta/plugins/dkim.toml
echo '# @include "/etc/wildduck/dbs.toml"' > /etc/zone-mta/dbs-production.toml
echo 'user="wildduck"

echo "[[default]]
address=\"0.0.0.0\"
name=\"$HOSTNAME\"" > /etc/zone-mta/pools.toml

echo "[\"modules/zonemta-loop-breaker\"]
enabled=\"sender\"
secret=\"$ZONEMTA_SECRET\"
algo=\"md5\"" > /etc/zone-mta/plugins/loop-breaker.toml

echo "[wildduck]
enabled=[\"receiver\", \"sender\"]

# which interfaces this plugin applies to
interfaces=[\"feeder\"]

# optional hostname to be used in headers
# defaults to os.hostname()
hostname=\"$HOSTNAME\"

# SRS settings for forwarded emails

[wildduck.srs]
    # Handle rewriting of forwarded emails
    enabled=true
    # SRS secret value. Must be the same as in the MX side
    secret=\"$SRS_SECRET\"
    # SRS domain, must resolve back to MX
    rewriteDomain=\"$MAILDOMAIN\"

[wildduck.dkim]
# share config with WildDuck installation
# @include \"/etc/wildduck/dkim.toml\"
" > /etc/zone-mta/plugins/wildduck.toml

cd /opt/zone-mta/keys
# Many registrar limits dns TXT fields to 255 char. 1024bit is almost too long:-\
openssl genrsa -out "$MAILDOMAIN-dkim.pem" 1024
chmod 400 "$MAILDOMAIN-dkim.pem"
openssl rsa -in "$MAILDOMAIN-dkim.pem" -out "$MAILDOMAIN-dkim.cert" -pubout
DKIM_DNS="v=DKIM1;k=rsa;p=$(grep -v -e '^-' $MAILDOMAIN-dkim.cert | tr -d "\n")"

DKIM_JSON=`DOMAIN="$MAILDOMAIN" SELECTOR="$DKIM_SELECTOR" node -e 'console.log(JSON.stringify({
  domain: process.env.DOMAIN,
  selector: process.env.SELECTOR,
  description: "Default DKIM key for "+process.env.DOMAIN,
  privateKey: fs.readFileSync("/opt/zone-mta/keys/"+process.env.DOMAIN+"-dkim.pem", "UTF-8")
}))'`

cd /opt/zone-mta
npm install --production --no-optional --no-package-lock --no-audit --ignore-scripts --no-shrinkwrap --unsafe-perm

cd /opt/zone-mta/plugins/wildduck
npm install --production --no-optional --no-package-lock --no-audit --ignore-scripts --no-shrinkwrap --unsafe-perm

chown -R deploy:deploy /var/opt/zone-mta.git
chown -R deploy:deploy /var/opt/zonemta-wildduck.git
chown -R deploy:deploy /opt/zone-mta
chown -R wildduck:wildduck /etc/zone-mta

# Ensure required files and permissions
echo "d /opt/zone-mta 0755 deploy deploy
d /etc/zone-mta 0755 wildduck wildduck" > /etc/tmpfiles.d/zone-mta.conf
log_script "zone-mta"

echo '[Unit]
Description=Zone Mail Transport Agent
Conflicts=sendmail.service exim.service postfix.service
After=mongod.service redis.service

[Service]
Environment="NODE_ENV=production"
WorkingDirectory=/opt/zone-mta
ExecStart=/usr/bin/node index.js --config="/etc/zone-mta/zonemta.toml"
ExecReload=/bin/kill -HUP $MAINPID
Type=simple
Restart=always
SyslogIdentifier=zone-mta

[Install]
WantedBy=multi-user.target' > /etc/systemd/system/zone-mta.service

$SYSTEMCTL_PATH enable zone-mta.service

$ sudo systemctl cat zone-mta.service 
# /etc/systemd/system/zone-mta.service
[Unit]
Description=Zone Mail Transport Agent
Conflicts=sendmail.service exim.service postfix.service
After=mongod.service redis.service

[Service]
Environment="NODE_ENV=production"
WorkingDirectory=/opt/zone-mta
ExecStart=/usr/bin/node index.js --config="/etc/zone-mta/zonemta.toml"
ExecReload=/bin/kill -HUP $MAINPID
Type=simple
Restart=always
SyslogIdentifier=zone-mta

[Install]
WantedBy=multi-user.target
$ cat /etc/zone-mta/zonemta.toml
user="wildduck"
group="wildduck"
# This is the main config file

name="ZoneMTA"

# Process identifier
ident="zone-mta"

# Run as the following user. Only use this if the application starts up as root
#user="zonemta"
#group="zonemta"

[log]
# Logging options
# @include "log.toml"

[dbs]
# MongoDB and Redis connection options
@include "dbs-{env}.toml"

[queue]
# @include "queue.toml"

[dns]
# @include "dns.toml"

[api]
port=12080

[smtpInterfaces]
# @include "interfaces/*.toml"

[plugins]
# @include "plugins/*.toml"

[pools]
# @include "pools.toml"

[zones]
# @include "zones/*.toml"

[domainConfig]
# @include "domains.toml"
alexlai@mail:/etc/zone-mta$ cat dbs-production.toml
# @include "/etc/wildduck/dbs.toml"
@include "/etc/wildduck/dbs.toml"
$ cat /etc/wildduck/dbs.toml 
# mongodb connection string for the main database
# mongo="mongodb://127.0.0.1:27017/wildduck"
mongo="mongodb://siteRootAdmin:b23258585@redisMongo03.yushei.com.tw:27017,redisMongo04.yushei.com.tw:27017,redisMongo05.yushei.com.tw:27017/YuSheiWildduck?authSource=admin&replicaSet=ys20220318"

# redis connection string to connect to a single master (see below for Sentinel example)
#redis="redis://127.0.0.1:6379/3"

# WildDuck allows using different kind of data in different databases
# If you do not provide a database config value, then main database connection
# is used for everything
# You can either use a database name (uses shared connection) or a configutaion
# url (creates a separate connection) for each databases

# Optional database name or connection url for GridFS if you do not want to
# use the main db for storing attachments. Useful if you want
# to use a different mount folder or storage engine
#gridfs="wildduck"

# Optional database name or connection url for users collection if you do not want to
# use the main db for storing user/address data. Useful if you want
# to use a different mount folder or storage engine
#users="wildduck"

# Optional database name or connection url for ZoneMTA queue database. This is
# used to push outbound emails to the sending queue
sender="zone-mta"

#queued="mail"

[redis]
host="127.0.0.1"
port=6379
db=3

## Connect to Redis Sentinel instead of single master
# [redis]
# name="mymaster"
# password=""
# db=3
# [[redis.sentinels]]
#   host="54.36.85.113"
#   port=26379
# [[redis.sentinels]]
#   host="54.36.85.114"
#   port=26379
# [[redis.sentinels]]
#   host="54.36.85.115"
#   port=26379

And sudo systemctl restart zonemta.service error message

░ The job identifier is 9325.
Oct 28 11:02:10 mail zone-mta[7130]: [/etc/zone-mta/zonemta.toml] /etc/zone-mta/zonemta.toml: /etc/zone-mta/dbs-production.toml: Expected "#", "'", "[", "\"", "\n", "\r", [ \t], [A-Za-z0-9_\-] or end of input but "@" found.
Oct 28 11:02:10 mail systemd[1]: zone-mta.service: Main process exited, code=exited, status=1/FAILURE