public
nobgit
read
NobMail
Based on mailcow: dockerized
Languages
Repository composition by tracked source files.
PHP
49%
JavaScript
35%
HTML
9%
CSS
4%
Shell
2%
Python
1%
Lua
0%
Perl
0%
Ruby
0%
SCSS
0%
Create file
Wiki Documentation
Clone
https://nobgit.com/orgs/nobgit/nobmail.git
ssh://[email protected]:2222/orgs/nobgit/nobmail.git
Trace
_modules/scripts/core.sh
Trace helps you understand code history line by line. See who changed each line, when it changed, and which commit introduced it.
Author
Date
Commit
Line
Code
1
#!/usr/bin/env bash
2
# _modules/scripts/core.sh
3
# THIS SCRIPT IS DESIGNED TO BE RUNNING BY MAILCOW SCRIPTS ONLY!
4
# DO NOT, AGAIN, NOT TRY TO RUN THIS SCRIPT STANDALONE!!!!!!
6
# ANSI color for red errors
7
RED='\e[31m'
8
GREEN='\e[32m'
9
YELLOW='\e[33m'
10
BLUE='\e[34m'
11
MAGENTA='\e[35m'
12
LIGHT_RED='\e[91m'
13
LIGHT_GREEN='\e[92m'
14
NC='\e[0m'
16
caller="${BASH_SOURCE[1]##*/}"
18
get_installed_tools(){
19
for bin in openssl curl docker git awk sha1sum grep cut jq; do
20
if [[ -z $(command -v ${bin}) ]]; then
21
echo "Error: Cannot find command '${bin}'. Cannot proceed."
22
echo "Solution: Please review system requirements and install requirements. Then, re-run the script."
23
echo "See System Requirements: https://docs.mailcow.email/getstarted/install/"
24
echo "Exiting..."
25
exit 1
26
fi
27
done
29
if grep --help 2>&1 | head -n 1 | grep -q -i "busybox"; then echo -e "${LIGHT_RED}BusyBox grep detected, please install gnu grep, \"apk add --no-cache --upgrade grep\"${NC}"; exit 1; fi
30
# This will also cover sort
31
if cp --help 2>&1 | head -n 1 | grep -q -i "busybox"; then echo -e "${LIGHT_RED}BusyBox cp detected, please install coreutils, \"apk add --no-cache --upgrade coreutils\"${NC}"; exit 1; fi
32
if sed --help 2>&1 | head -n 1 | grep -q -i "busybox"; then echo -e "${LIGHT_RED}BusyBox sed detected, please install gnu sed, \"apk add --no-cache --upgrade sed\"${NC}"; exit 1; fi
33
}
35
get_docker_version(){
36
# Check Docker Version (need at least 24.X)
37
docker_version=$(docker version --format '{{.Server.Version}}' | cut -d '.' -f 1)
38
}
40
get_compose_type(){
41
if docker compose > /dev/null 2>&1; then
42
if docker compose version --short | grep -e "^[2-9]\." -e "^v[2-9]\." -e "^[1-9][0-9]\." -e "^v[1-9][0-9]\." > /dev/null 2>&1; then
43
COMPOSE_VERSION=native
44
COMPOSE_COMMAND="docker compose"
45
if [[ "$caller" == "update.sh" ]]; then
46
sed -i 's/^DOCKER_COMPOSE_VERSION=.*/DOCKER_COMPOSE_VERSION=native/' "$SCRIPT_DIR/mailcow.conf"
47
fi
48
echo -e "\e[33mFound Docker Compose Plugin (native).\e[0m"
49
echo -e "\e[33mSetting the DOCKER_COMPOSE_VERSION Variable to native\e[0m"
50
sleep 2
51
echo -e "\e[33mNotice: You'll have to update this Compose Version via your Package Manager manually!\e[0m"
52
else
53
echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m"
54
echo -e "\e[31mPlease update/install it manually regarding to this doc site: https://docs.mailcow.email/install/\e[0m"
55
exit 1
56
fi
57
elif docker-compose > /dev/null 2>&1; then
58
if ! [[ $(alias docker-compose 2> /dev/null) ]] ; then
59
if docker-compose version --short | grep -e "^[2-9]\." -e "^[1-9][0-9]\." > /dev/null 2>&1; then
60
COMPOSE_VERSION=standalone
61
COMPOSE_COMMAND="docker-compose"
62
if [[ "$caller" == "update.sh" ]]; then
63
sed -i 's/^DOCKER_COMPOSE_VERSION=.*/DOCKER_COMPOSE_VERSION=standalone/' "$SCRIPT_DIR/mailcow.conf"
64
fi
65
echo -e "\e[33mFound Docker Compose Standalone.\e[0m"
66
echo -e "\e[33mSetting the DOCKER_COMPOSE_VERSION Variable to standalone\e[0m"
67
sleep 2
68
echo -e "\e[33mNotice: For an automatic update of docker-compose please use the update_compose.sh scripts located at the helper-scripts folder.\e[0m"
69
else
70
echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m"
71
echo -e "\e[31mPlease update/install manually regarding to this doc site: https://docs.mailcow.email/install/\e[0m"
72
exit 1
73
fi
74
fi
75
else
76
echo -e "\e[31mCannot find Docker Compose.\e[0m"
77
echo -e "\e[31mPlease install it regarding to this doc site: https://docs.mailcow.email/install/\e[0m"
78
exit 1
79
fi
80
}
82
detect_bad_asn() {
83
echo -e "\e[33mDetecting if your IP is listed on Spamhaus Bad ASN List...\e[0m"
84
response=$(curl --connect-timeout 15 --max-time 30 -s -o /dev/null -w "%{http_code}" "https://asn-check.mailcow.email")
85
if [ "$response" -eq 503 ]; then
86
if [ -z "$SPAMHAUS_DQS_KEY" ]; then
87
echo -e "\e[33mYour server's public IP uses an AS that is blocked by Spamhaus to use their DNS public blocklists for Postfix.\e[0m"
88
echo -e "\e[33mmailcow did not detected a value for the variable SPAMHAUS_DQS_KEY inside mailcow.conf!\e[0m"
89
sleep 2
90
echo ""
91
echo -e "\e[33mTo use the Spamhaus DNS Blocklists again, you will need to create a FREE account for their Data Query Service (DQS) at: https://www.spamhaus.com/free-trial/sign-up-for-a-free-data-query-service-account\e[0m"
92
echo -e "\e[33mOnce done, enter your DQS API key in mailcow.conf and mailcow will do the rest for you!\e[0m"
93
echo ""
94
sleep 2
95
else
96
echo -e "\e[33mYour server's public IP uses an AS that is blocked by Spamhaus to use their DNS public blocklists for Postfix.\e[0m"
97
echo -e "\e[32mmailcow detected a Value for the variable SPAMHAUS_DQS_KEY inside mailcow.conf. Postfix will use DQS with the given API key...\e[0m"
98
fi
99
elif [ "$response" -eq 200 ]; then
100
echo -e "\e[33mCheck completed! Your IP is \e[32mclean\e[0m"
101
elif [ "$response" -eq 429 ]; then
102
echo -e "\e[33mCheck completed! \e[31mYour IP seems to be rate limited on the ASN Check service... please try again later!\e[0m"
103
else
104
echo -e "\e[31mCheck failed! \e[0mMaybe a DNS or Network problem?\e[0m"
105
fi
106
}
108
check_online_status() {
109
CHECK_ONLINE_DOMAINS=('https://github.com' 'https://hub.docker.com')
110
for domain in "${CHECK_ONLINE_DOMAINS[@]}"; do
111
if timeout 6 curl --head --silent --output /dev/null ${domain}; then
112
return 0
113
fi
114
done
115
return 1
116
}
118
prefetch_images() {
119
[[ -z ${BRANCH} ]] && { echo -e "\e[33m\nUnknown branch...\e[0m"; exit 1; }
120
git fetch origin #${BRANCH}
121
while read image; do
122
RET_C=0
123
until docker pull "${image}"; do
124
RET_C=$((RET_C + 1))
125
echo -e "\e[33m\nError pulling $image, retrying...\e[0m"
126
[ ${RET_C} -gt 3 ] && { echo -e "\e[31m\nToo many failed retries, exiting\e[0m"; exit 1; }
127
sleep 1
128
done
129
done < <(git show "origin/${BRANCH}:docker-compose.yml" | grep "image:" | awk '{ gsub("image:","", $3); print $2 }')
130
}
132
docker_garbage() {
133
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/../.." && pwd )"
134
IMGS_TO_DELETE=()
136
declare -A IMAGES_INFO
137
COMPOSE_IMAGES=($(grep -oP "image: \K(ghcr\.io/)?mailcow.+" "${SCRIPT_DIR}/docker-compose.yml"))
139
for existing_image in $(docker images --format "{{.ID}}:{{.Repository}}:{{.Tag}}" | grep -E '(mailcow/|ghcr\.io/mailcow/)'); do
140
ID=$(echo "$existing_image" | cut -d ':' -f 1)
141
REPOSITORY=$(echo "$existing_image" | cut -d ':' -f 2)
142
TAG=$(echo "$existing_image" | cut -d ':' -f 3)
144
if [[ "$REPOSITORY" == "mailcow/backup" || "$REPOSITORY" == "ghcr.io/mailcow/backup" ]]; then
145
if [[ "$TAG" != "<none>" ]]; then
146
continue
147
fi
148
fi
150
if [[ " ${COMPOSE_IMAGES[@]} " =~ " ${REPOSITORY}:${TAG} " ]]; then
151
continue
152
else
153
IMGS_TO_DELETE+=("$ID")
154
IMAGES_INFO["$ID"]="$REPOSITORY:$TAG"
155
fi
156
done
158
if [[ ! -z ${IMGS_TO_DELETE[*]} ]]; then
159
echo "The following unused mailcow images were found:"
160
for id in "${IMGS_TO_DELETE[@]}"; do
161
echo " ${IMAGES_INFO[$id]} ($id)"
162
done
164
if [ -z "$FORCE" ]; then
165
read -r -p "Do you want to delete them to free up some space? [y/N] " response
166
if [[ "$response" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
167
docker rmi ${IMGS_TO_DELETE[*]}
168
else
169
echo "OK, skipped."
170
fi
171
else
172
echo "Running in forced mode! Force removing old mailcow images..."
173
docker rmi ${IMGS_TO_DELETE[*]}
174
fi
175
echo -e "\e[32mFurther cleanup...\e[0m"
176
echo "If you want to cleanup further garbage collected by Docker, please make sure all containers are up and running before cleaning your system by executing \"docker system prune\""
177
fi
178
}
180
in_array() {
181
local e match="$1"
182
shift
183
for e; do [[ "$e" == "$match" ]] && return 0; done
184
return 1
185
}
187
detect_major_update() {
188
if [ ${BRANCH} == "master" ]; then
189
# Array with major versions
190
# Add major versions here
191
MAJOR_VERSIONS=(
192
"2025-02"
193
"2025-03"
194
"2025-09"
195
)
197
current_version=""
198
if [[ -f "${SCRIPT_DIR}/data/web/inc/app_info.inc.php" ]]; then
199
current_version=$(grep 'MAILCOW_GIT_VERSION' ${SCRIPT_DIR}/data/web/inc/app_info.inc.php | sed -E 's/.*MAILCOW_GIT_VERSION="([^"]+)".*/\1/')
200
fi
201
if [[ -z "$current_version" ]]; then
202
return 1
203
fi
204
release_url="https://github.com/mailcow/mailcow-dockerized/releases/tag"
206
updates_to_apply=()
208
for version in "${MAJOR_VERSIONS[@]}"; do
209
if [[ "$current_version" < "$version" ]]; then
210
updates_to_apply+=("$version")
211
fi
212
done
214
if [[ ${#updates_to_apply[@]} -gt 0 ]]; then
215
echo -e "\e[33m\nMAJOR UPDATES to be applied:\e[0m"
216
for update in "${updates_to_apply[@]}"; do
217
echo "$update - $release_url/$update"
218
done
220
echo -e "\nPlease read the release notes before proceeding."
221
read -p "Do you want to proceed with the update? [y/n] " response
222
if [[ "${response}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
223
echo "Proceeding with the update..."
224
else
225
echo "Update canceled. Exiting."
226
exit 1
227
fi
228
fi
229
fi
230
}