fix(setup-script): ZMS-252 Install script updates (#847)

* Switches to latest tagged release for repo checkouts

Replaces hardcoded commit hashes with a function that checks out
the latest tagged release for each repository. Improves deployment flow
by automatically tracking stable upstream releases.

* Enforces supported architectures in install scripts

Adds explicit architecture detection and validation to setup scripts,
restricting them to amd64, arm64, and armhf. Updates repository
configuration to use detected architecture for package sources,
improving compatibility and preventing installation on unsupported systems.

* Updates npm install flags for improved dependency handling

Replaces deprecated and less explicit npm install flags with
--omit=dev and --omit=optional to better control installed
dependencies and align with modern npm practices. Reduces
potential for installing unnecessary packages and improves
script reliability.

* Reformats SSL certificate issuance command by placing each argument
on a separate line, enhancing readability and simplifying future
modifications.

* Updates Node.js and MongoDB to latest major versions

Ensures compatibility and access to new features by moving to Node.js 22 and MongoDB 8.0. Prepares environment for current ecosystem dependencies and future-proofing.

* add ending line

* fix typos, improve consistency, fix npm install script, make it more modern

* improve consistency

---------

Co-authored-by: Joosep Jõeleht <joosep@zone.ee>
Co-authored-by: Nikolai Ovtsinnikov <nikolai@zone.ee>
This commit is contained in:
Joosep Jõeleht 2025-08-01 10:31:16 +03:00 committed by GitHub
parent 4adfce07c3
commit c209b3af26
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 51 additions and 38 deletions

View file

@ -198,8 +198,8 @@ There is a slight difference between domainname and hostname.
${ORANGE}Simplest case${NC}: ${ORANGE}Simplest case${NC}:
One server serves everything: company website, emails, webmails. One server serves everything: company website, emails, webmails.
One ip address, and domainname is the same az hostname. One ip address, and domainname is the same as hostname.
Eg. amazme.com Eg. amazeme.com
${GREEN}More general case${NC}: ${GREEN}More general case${NC}:
The domainname is part of the email address: The domainname is part of the email address:
@ -210,11 +210,11 @@ name is: `hostname`
On larger organizations, the company homepage is independent from On larger organizations, the company homepage is independent from
the mail servers. Or the webmail servers. the mail servers. Or the webmail servers.
Eg. the company homepage is amazme.com [11.22.33.44], Eg. the company homepage is amazeme.com [11.22.33.44],
the mail server is mail.amazme.com [11.22.33.43] the mail server is mail.amazeme.com [11.22.33.43]
So domainname = amazme.com So domainname = amazeme.com
hostname = mail.amazme.com hostname = mail.amazeme.com
${RED}IP address${NC} case: ${RED}IP address${NC} case:
You can call this script with ip address instead of domain name: You can call this script with ip address instead of domain name:
@ -236,7 +236,7 @@ function hook_script {
git --git-dir=/var/opt/$1.git --work-tree=\"/opt/$1\" checkout "\$3" -f git --git-dir=/var/opt/$1.git --work-tree=\"/opt/$1\" checkout "\$3" -f
cd \"/opt/$1\" cd \"/opt/$1\"
rm -rf package-lock.json rm -rf package-lock.json
npm install --production --no-optional --no-package-lock --no-audit --ignore-scripts --no-shrinkwrap --progress=false npm install --omit=dev --omit=optional --no-package-lock --no-audit --ignore-scripts --no-shrinkwrap --progress=false
sudo $SYSTEMCTL_PATH restart $1 || echo \"Failed restarting service\"" > "/var/opt/$1.git/hooks/update" sudo $SYSTEMCTL_PATH restart $1 || echo \"Failed restarting service\"" > "/var/opt/$1.git/hooks/update"
chmod +x "/var/opt/$1.git/hooks/update" chmod +x "/var/opt/$1.git/hooks/update"
} }
@ -284,4 +284,14 @@ echo "/var/log/${SERVICE_NAME}/${SERVICE_NAME}.log {
} }
export -f log_script export -f log_script
function get_latest_release_commit {
REPO_NAME="$1"
GIT_DIR="/var/opt/${REPO_NAME}.git"
git --git-dir="$GIT_DIR" fetch --tags
LATEST_TAG=$(git --git-dir="$GIT_DIR" describe --tags $(git --git-dir="$GIT_DIR" rev-list --tags --max-count=1))
LATEST_COMMIT=$(git --git-dir="$GIT_DIR" rev-list -n 1 "$LATEST_TAG")
echo "$LATEST_COMMIT"
}
export -f get_latest_release_commit

View file

@ -5,15 +5,15 @@ OURNAME=01_install_commits.sh
apt-get update apt-get update
apt-get install -y lsb-release ca-certificates curl gnupg apt-get install -y lsb-release ca-certificates curl gnupg
NODE_MAJOR="20" NODE_MAJOR="22"
MONGODB="7.0" MONGODB="8.0"
CODENAME=`lsb_release -c -s` CODENAME=`lsb_release -c -s`
WILDDUCK_COMMIT="9a204f5751ad2bd80baaa3abca95f334fbdf0757"
ZONEMTA_COMMIT="0df73a3946eae0964a166b3015d3ed558d9d024f" # zone-mta-template
WEBMAIL_COMMIT="093cc641782c1a9ca4f498b24ebded23873cb390"
WILDDUCK_ZONEMTA_COMMIT="1f4fad5ba771ce381ef0543e8c9c49ee25e4a6f2"
WILDDUCK_HARAKA_COMMIT="91745b5af70e1d3dfd0fac22d9550f893662ad70"
HARAKA_VERSION="3.0.5" HARAKA_VERSION="3.0.5"
ARCHITECTURE=$(dpkg --print-architecture)
if [ "$ARCHITECTURE" != "amd64" ] && [ "$ARCHITECTURE" != "arm64" ] && [ "$ARCHITECTURE" != "armhf" ]; then
handle_error "1" "Unsupported architecture: $ARCHITECTURE. Only amd64, arm64, and armhf are supported."
fi
echo -e "\n-- Executing ${ORANGE}${OURNAME}${NC} subscript --" echo -e "\n-- Executing ${ORANGE}${OURNAME}${NC} subscript --"

View file

@ -2,12 +2,12 @@
OURNAME=02_install_prerequisites.sh OURNAME=02_install_prerequisites.sh
# No $AUT_SAFETY variable present, so we have not sourced install_variables.sh yet # No $AUT_SAFETY variable present, so we have not sourced 00_install_global_functions_variables.sh yet
if [ -z ${AUT_SAFETY+x} ] if [ -z ${AUT_SAFETY+x} ]
then then
echo "this script ${RED}called directly${NC}, and not from the main ./install.sh script" echo "this script ${RED}called directly${NC}, and not from the main ./install.sh script"
echo "initializing common variables ('install_variables.sh')" echo "initializing common variables ('00_install_global_functions_variables.sh')"
source "$INSTALLDIR/install_variables.sh" source "$INSTALLDIR/00_install_global_functions_variables.sh"
fi fi
echo -e "\n-- Executing ${ORANGE}${OURNAME}${NC} subscript --" echo -e "\n-- Executing ${ORANGE}${OURNAME}${NC} subscript --"

View file

@ -2,13 +2,13 @@
OURNAME=03_install_check_running_services.sh OURNAME=03_install_check_running_services.sh
# No $AUT_SAFETY variable present, so we have not sourced install_variables.sh yet # No $AUT_SAFETY variable present, so we have not sourced 00_install_global_functions_variables.sh yet
# check if $AUT_SAFETY is unset (as opposed to empty "" string) # check if $AUT_SAFETY is unset (as opposed to empty "" string)
if [ -z ${AUT_SAFETY+x} ] if [ -z ${AUT_SAFETY+x} ]
then then
echo "this script ${RED}called directly${NC}, and not from the main ./install.sh script" echo "this script ${RED}called directly${NC}, and not from the main ./install.sh script"
echo "initializing common variables ('install_variables.sh')" echo "initializing common variables ('00_install_global_functions_variables.sh')"
source "$INSTALLDIR/install_variables.sh" source "$INSTALLDIR/00_install_global_functions_variables.sh"
fi fi
echo -e "\n\n-- Executing ${ORANGE}${OURNAME}${NC} subscript --" echo -e "\n\n-- Executing ${ORANGE}${OURNAME}${NC} subscript --"

View file

@ -27,14 +27,14 @@ node_key_url="https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key"
local_node_key="${keyring}/nodesource.gpg" local_node_key="${keyring}/nodesource.gpg"
curl -fsSL $node_key_url | gpg --dearmor | tee $local_node_key >/dev/null curl -fsSL $node_key_url | gpg --dearmor | tee $local_node_key >/dev/null
echo "deb [signed-by=${local_node_key}] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" > /etc/apt/sources.list.d/nodesource.list echo "deb [arch=${ARCHITECTURE} signed-by=${local_node_key}] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" > /etc/apt/sources.list.d/nodesource.list
echo "deb-src [signed-by=${local_node_key}] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" >> /etc/apt/sources.list.d/nodesource.list echo "deb-src [arch=${ARCHITECTURE} signed-by=${local_node_key}] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" >> /etc/apt/sources.list.d/nodesource.list
# mongodb # mongodb
mongo_key_url="https://pgp.mongodb.com/server-${MONGODB}.asc" mongo_key_url="https://pgp.mongodb.com/server-${MONGODB}.asc"
local_mongo_key="${keyring}/mongodb-server-${MONGODB}.gpg" local_mongo_key="${keyring}/mongodb-server-${MONGODB}.gpg"
curl -fsSL $mongo_key_url | gpg --dearmor | tee ${local_mongo_key} >/dev/null curl -fsSL $mongo_key_url | gpg --dearmor | tee ${local_mongo_key} >/dev/null
echo "deb [ arch=amd64,arm64 signed-by=${local_mongo_key} ] https://repo.mongodb.org/apt/ubuntu ${CODENAME}/mongodb-org/${MONGODB} multiverse" > /etc/apt/sources.list.d/mongodb-org-${MONGODB}.list echo "deb [ arch=${ARCHITECTURE} signed-by=${local_mongo_key} ] https://repo.mongodb.org/apt/ubuntu ${CODENAME}/mongodb-org/${MONGODB} multiverse" > /etc/apt/sources.list.d/mongodb-org-${MONGODB}.list
# rspamd # rspamd
rspamd_key_url="https://rspamd.com/apt-stable/gpg.key" rspamd_key_url="https://rspamd.com/apt-stable/gpg.key"

View file

@ -29,7 +29,7 @@ echo "deploy ALL = (root) NOPASSWD: $SYSTEMCTL_PATH restart wildduck" >> /etc/su
# checkout files from git to working directory # checkout files from git to working directory
mkdir -p /opt/wildduck mkdir -p /opt/wildduck
git --git-dir=/var/opt/wildduck.git --work-tree=/opt/wildduck checkout "$WILDDUCK_COMMIT" git --git-dir=/var/opt/wildduck.git --work-tree=/opt/wildduck checkout $(get_latest_release_commit "wildduck")
cp -r /opt/wildduck/config /etc/wildduck cp -r /opt/wildduck/config /etc/wildduck
mv /etc/wildduck/default.toml /etc/wildduck/wildduck.toml mv /etc/wildduck/default.toml /etc/wildduck/wildduck.toml
@ -55,7 +55,7 @@ sed -i -e "s/localhost:3000/$HOSTNAME/g;s/localhost/$HOSTNAME/g;s/2587/587/g" /e
sed -i -e "s/secret value/$SRS_SECRET/g;s/#loopSecret/loopSecret/g" /etc/wildduck/sender.toml sed -i -e "s/secret value/$SRS_SECRET/g;s/#loopSecret/loopSecret/g" /etc/wildduck/sender.toml
cd /opt/wildduck cd /opt/wildduck
npm install --production --unsafe-perm --no-optional --no-package-lock --no-audit --ignore-scripts --no-shrinkwrap npm install --omit=dev --omit=optional --no-package-lock --no-audit --ignore-scripts --no-shrinkwrap
chown -R deploy:deploy /var/opt/wildduck.git chown -R deploy:deploy /var/opt/wildduck.git
chown -R deploy:deploy /opt/wildduck chown -R deploy:deploy /opt/wildduck

View file

@ -25,7 +25,7 @@ echo "#!/bin/bash
git --git-dir=/var/opt/haraka-plugin-wildduck.git --work-tree=/opt/haraka/plugins/wildduck checkout "\$3" -f git --git-dir=/var/opt/haraka-plugin-wildduck.git --work-tree=/opt/haraka/plugins/wildduck checkout "\$3" -f
cd /opt/haraka/plugins/wildduck cd /opt/haraka/plugins/wildduck
rm -rf package-lock.json rm -rf package-lock.json
npm install --production --no-optional --no-package-lock --no-audit --ignore-scripts --no-shrinkwrap --progress=false npm install --omit=dev --omit=optional --no-package-lock --no-audit --ignore-scripts --no-shrinkwrap --progress=false
sudo $SYSTEMCTL_PATH restart haraka || echo \"Failed restarting service\"" > "/var/opt/haraka-plugin-wildduck.git/hooks/update" sudo $SYSTEMCTL_PATH restart haraka || echo \"Failed restarting service\"" > "/var/opt/haraka-plugin-wildduck.git/hooks/update"
chmod +x "/var/opt/haraka-plugin-wildduck.git/hooks/update" chmod +x "/var/opt/haraka-plugin-wildduck.git/hooks/update"
@ -33,17 +33,17 @@ chmod +x "/var/opt/haraka-plugin-wildduck.git/hooks/update"
echo "deploy ALL = (root) NOPASSWD: $SYSTEMCTL_PATH restart haraka" >> /etc/sudoers.d/wildduck echo "deploy ALL = (root) NOPASSWD: $SYSTEMCTL_PATH restart haraka" >> /etc/sudoers.d/wildduck
cd cd
npm install --production --no-optional --no-package-lock --no-audit --no-shrinkwrap --unsafe-perm -g Haraka@$HARAKA_VERSION npm install --omit=dev --omit=optional --no-package-lock --no-audit --no-shrinkwrap -g Haraka@$HARAKA_VERSION
haraka -i /opt/haraka haraka -i /opt/haraka
cd /opt/haraka cd /opt/haraka
npm install --production --no-optional --no-package-lock --no-audit --no-shrinkwrap --unsafe-perm --save haraka-plugin-rspamd haraka-plugin-redis Haraka@$HARAKA_VERSION npm install --omit=dev --omit=optional --no-package-lock --no-audit --no-shrinkwrap --save haraka-plugin-rspamd haraka-plugin-redis Haraka@$HARAKA_VERSION
# Haraka WildDuck plugin. Install as separate repo as it can be edited more easily later # Haraka WildDuck plugin. Install as separate repo as it can be edited more easily later
mkdir -p plugins/wildduck mkdir -p plugins/wildduck
git --git-dir=/var/opt/haraka-plugin-wildduck.git --work-tree=/opt/haraka/plugins/wildduck checkout "$WILDDUCK_HARAKA_COMMIT" git --git-dir=/var/opt/haraka-plugin-wildduck.git --work-tree=/opt/haraka/plugins/wildduck checkout $(get_latest_release_commit "haraka-plugin-wildduck")
cd plugins/wildduck cd plugins/wildduck
npm install --production --no-optional --no-package-lock --no-audit --ignore-scripts --no-shrinkwrap --unsafe-perm --progress=false npm install --omit=dev --omit=optional --no-package-lock --no-audit --ignore-scripts --no-shrinkwrap --progress=false
cd /opt/haraka cd /opt/haraka
mv config/plugins config/plugins.bak mv config/plugins config/plugins.bak

View file

@ -30,7 +30,7 @@ echo "#!/bin/bash
git --git-dir=/var/opt/zonemta-wildduck.git --work-tree=/opt/zone-mta/plugins/wildduck checkout "\$3" -f git --git-dir=/var/opt/zonemta-wildduck.git --work-tree=/opt/zone-mta/plugins/wildduck checkout "\$3" -f
cd /opt/zone-mta/plugins/wildduck cd /opt/zone-mta/plugins/wildduck
rm -rf package-lock.json rm -rf package-lock.json
npm install --production --no-optional --no-package-lock --no-audit --ignore-scripts --no-shrinkwrap --progress=false npm install --omit=dev --omit=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" 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" chmod +x "/var/opt/zonemta-wildduck.git/hooks/update"
@ -39,10 +39,10 @@ echo "deploy ALL = (root) NOPASSWD: $SYSTEMCTL_PATH restart zone-mta" >> /etc/su
# checkout files from git to working directory # checkout files from git to working directory
mkdir -p /opt/zone-mta mkdir -p /opt/zone-mta
git --git-dir=/var/opt/zone-mta.git --work-tree=/opt/zone-mta checkout "$ZONEMTA_COMMIT" git --git-dir=/var/opt/zone-mta.git --work-tree=/opt/zone-mta checkout $(get_latest_release_commit "zone-mta")
mkdir -p /opt/zone-mta/plugins/wildduck 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" git --git-dir=/var/opt/zonemta-wildduck.git --work-tree=/opt/zone-mta/plugins/wildduck checkout $(get_latest_release_commit "zonemta-wildduck")
cp -r /opt/zone-mta/config /etc/zone-mta 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 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
@ -100,10 +100,10 @@ DKIM_JSON=`DOMAIN="$MAILDOMAIN" SELECTOR="$DKIM_SELECTOR" node -e 'console.log(J
}))'` }))'`
cd /opt/zone-mta cd /opt/zone-mta
npm install --production --no-optional --no-package-lock --no-audit --ignore-scripts --no-shrinkwrap --unsafe-perm npm install --omit=dev --omit=optional --no-package-lock --no-audit --ignore-scripts --no-shrinkwrap
cd /opt/zone-mta/plugins/wildduck cd /opt/zone-mta/plugins/wildduck
npm install --production --no-optional --no-package-lock --no-audit --ignore-scripts --no-shrinkwrap --unsafe-perm npm install --omit=dev --omit=optional --no-package-lock --no-audit --ignore-scripts --no-shrinkwrap
chown -R deploy:deploy /var/opt/zone-mta.git chown -R deploy:deploy /var/opt/zone-mta.git
chown -R deploy:deploy /var/opt/zonemta-wildduck.git chown -R deploy:deploy /var/opt/zonemta-wildduck.git

View file

@ -29,7 +29,7 @@ echo "deploy ALL = (root) NOPASSWD: $SYSTEMCTL_PATH restart wildduck-webmail" >>
# checkout files from git to working directory # checkout files from git to working directory
mkdir -p /opt/wildduck-webmail mkdir -p /opt/wildduck-webmail
git --git-dir=/var/opt/wildduck-webmail.git --work-tree=/opt/wildduck-webmail checkout "$WEBMAIL_COMMIT" git --git-dir=/var/opt/wildduck-webmail.git --work-tree=/opt/wildduck-webmail checkout $(get_latest_release_commit "wildduck-webmail")
cp /opt/wildduck-webmail/config/default.toml /etc/wildduck/wildduck-webmail.toml cp /opt/wildduck-webmail/config/default.toml /etc/wildduck/wildduck-webmail.toml
sed -i -e "s/localhost/$HOSTNAME/g;s/999/99/g;s/2587/587/g;s/proxy=false/proxy=true/g;s/domains=.*/domains=[\"$MAILDOMAIN\"]/g" /etc/wildduck/wildduck-webmail.toml sed -i -e "s/localhost/$HOSTNAME/g;s/999/99/g;s/2587/587/g;s/proxy=false/proxy=true/g;s/domains=.*/domains=[\"$MAILDOMAIN\"]/g" /etc/wildduck/wildduck-webmail.toml

View file

@ -25,7 +25,10 @@ echo '#!/bin/bash
echo "OK"' > /usr/local/bin/reload-services.sh echo "OK"' > /usr/local/bin/reload-services.sh
chmod +x /usr/local/bin/reload-services.sh chmod +x /usr/local/bin/reload-services.sh
~/.acme.sh/acme.sh --issue --nginx --server letsencrypt \ ~/.acme.sh/acme.sh \
--issue \
--nginx \
--server letsencrypt \
-d "$HOSTNAME" \ -d "$HOSTNAME" \
--key-file /etc/wildduck/certs/privkey.pem \ --key-file /etc/wildduck/certs/privkey.pem \
--fullchain-file /etc/wildduck/certs/fullchain.pem \ --fullchain-file /etc/wildduck/certs/fullchain.pem \