Skip to content

Commit b1c088a

Browse files
Merge pull request #6718 from mailcow/staging
Update 2025-09
2 parents 527f27d + 1c43833 commit b1c088a

File tree

78 files changed

+4813
-1701
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+4813
-1701
lines changed

.github/workflows/close_old_issues_and_prs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
pull-requests: write
1515
steps:
1616
- name: Mark/Close Stale Issues and Pull Requests 🗑️
17-
uses: actions/stale@v9.1.0
17+
uses: actions/stale@v10.0.0
1818
with:
1919
repo-token: ${{ secrets.STALE_ACTION_PAT }}
2020
days-before-stale: 60

.github/workflows/image_builds.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ jobs:
2727
- "watchdog-mailcow"
2828
runs-on: ubuntu-latest
2929
steps:
30-
- uses: actions/checkout@v4
30+
- uses: actions/checkout@v5
3131
- name: Setup Docker
3232
run: |
3333
curl -sSL https://get.docker.com/ | CHANNEL=stable sudo sh

.github/workflows/pr_to_nightly.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ jobs:
88
runs-on: ubuntu-latest
99
steps:
1010
- name: Checkout repository
11-
uses: actions/checkout@v4
11+
uses: actions/checkout@v5
1212
with:
1313
fetch-depth: 0
1414
- name: Run the Action
15-
uses: devops-infra/action-pull-request@v0.6.0
15+
uses: devops-infra/action-pull-request@v0.6.1
1616
with:
1717
github_token: ${{ secrets.PRTONIGHTLY_ACTION_PAT }}
1818
title: Automatic PR to nightly from ${{ github.event.repository.updated_at}}

.github/workflows/rebuild_backup_image.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
packages: write
1414
steps:
1515
- name: Checkout
16-
uses: actions/checkout@v4
16+
uses: actions/checkout@v5
1717

1818
- name: Set up QEMU
1919
uses: docker/setup-qemu-action@v3

.github/workflows/update_postscreen_access_list.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
runs-on: ubuntu-latest
1616
steps:
1717
- name: Checkout
18-
uses: actions/checkout@v4
18+
uses: actions/checkout@v5
1919

2020
- name: Generate postscreen_access.cidr
2121
run: |

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,4 @@ refresh_images.sh
7575
update_diffs/
7676
create_cold_standby.sh
7777
!data/conf/nginx/mailcow_auth.conf
78+
data/conf/postfix/postfix-tlspol

README.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,6 @@ A big thank you to everyone supporting us on GitHub Sponsors—your contribution
2323
<a href="https://www.maehdros.com/" target=_blank><img
2424
src="https://avatars.githubusercontent.com/u/173894712" height="58"
2525
/></a>
26-
<a href="https://macarne.com/" target=_blank><img
27-
src="https://avatars.githubusercontent.com/u/149550368?s=200&v=4" height="58"
28-
/></a>
2926

3027
### 50$/Month Sponsors
3128
<a href="https://github.com/vnukhr" target=_blank><img

_modules/scripts/core.sh

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
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!!!!!!
5+
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'
15+
16+
caller="${BASH_SOURCE[1]##*/}"
17+
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 echo "Cannot find ${bin}, exiting..."; exit 1; fi
21+
done
22+
23+
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
24+
# This will also cover sort
25+
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
26+
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
27+
}
28+
29+
get_docker_version(){
30+
# Check Docker Version (need at least 24.X)
31+
docker_version=$(docker version --format '{{.Server.Version}}' | cut -d '.' -f 1)
32+
}
33+
34+
get_compose_type(){
35+
if docker compose > /dev/null 2>&1; then
36+
if docker compose version --short | grep -e "^2." -e "^v2." > /dev/null 2>&1; then
37+
COMPOSE_VERSION=native
38+
COMPOSE_COMMAND="docker compose"
39+
if [[ "$caller" == "update.sh" ]]; then
40+
sed -i 's/^DOCKER_COMPOSE_VERSION=.*/DOCKER_COMPOSE_VERSION=native/' "$SCRIPT_DIR/mailcow.conf"
41+
fi
42+
echo -e "\e[33mFound Docker Compose Plugin (native).\e[0m"
43+
echo -e "\e[33mSetting the DOCKER_COMPOSE_VERSION Variable to native\e[0m"
44+
sleep 2
45+
echo -e "\e[33mNotice: You'll have to update this Compose Version via your Package Manager manually!\e[0m"
46+
else
47+
echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m"
48+
echo -e "\e[31mPlease update/install it manually regarding to this doc site: https://docs.mailcow.email/install/\e[0m"
49+
exit 1
50+
fi
51+
elif docker-compose > /dev/null 2>&1; then
52+
if ! [[ $(alias docker-compose 2> /dev/null) ]] ; then
53+
if docker-compose version --short | grep "^2." > /dev/null 2>&1; then
54+
COMPOSE_VERSION=standalone
55+
COMPOSE_COMMAND="docker-compose"
56+
if [[ "$caller" == "update.sh" ]]; then
57+
sed -i 's/^DOCKER_COMPOSE_VERSION=.*/DOCKER_COMPOSE_VERSION=standalone/' "$SCRIPT_DIR/mailcow.conf"
58+
fi
59+
echo -e "\e[33mFound Docker Compose Standalone.\e[0m"
60+
echo -e "\e[33mSetting the DOCKER_COMPOSE_VERSION Variable to standalone\e[0m"
61+
sleep 2
62+
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"
63+
else
64+
echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m"
65+
echo -e "\e[31mPlease update/install manually regarding to this doc site: https://docs.mailcow.email/install/\e[0m"
66+
exit 1
67+
fi
68+
fi
69+
else
70+
echo -e "\e[31mCannot find Docker Compose.\e[0m"
71+
echo -e "\e[31mPlease install it regarding to this doc site: https://docs.mailcow.email/install/\e[0m"
72+
exit 1
73+
fi
74+
}
75+
76+
detect_bad_asn() {
77+
echo -e "\e[33mDetecting if your IP is listed on Spamhaus Bad ASN List...\e[0m"
78+
response=$(curl --connect-timeout 15 --max-time 30 -s -o /dev/null -w "%{http_code}" "https://asn-check.mailcow.email")
79+
if [ "$response" -eq 503 ]; then
80+
if [ -z "$SPAMHAUS_DQS_KEY" ]; then
81+
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"
82+
echo -e "\e[33mmailcow did not detected a value for the variable SPAMHAUS_DQS_KEY inside mailcow.conf!\e[0m"
83+
sleep 2
84+
echo ""
85+
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"
86+
echo -e "\e[33mOnce done, enter your DQS API key in mailcow.conf and mailcow will do the rest for you!\e[0m"
87+
echo ""
88+
sleep 2
89+
else
90+
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"
91+
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"
92+
fi
93+
elif [ "$response" -eq 200 ]; then
94+
echo -e "\e[33mCheck completed! Your IP is \e[32mclean\e[0m"
95+
elif [ "$response" -eq 429 ]; then
96+
echo -e "\e[33mCheck completed! \e[31mYour IP seems to be rate limited on the ASN Check service... please try again later!\e[0m"
97+
else
98+
echo -e "\e[31mCheck failed! \e[0mMaybe a DNS or Network problem?\e[0m"
99+
fi
100+
}
101+
102+
check_online_status() {
103+
CHECK_ONLINE_DOMAINS=('https://github.com' 'https://hub.docker.com')
104+
for domain in "${CHECK_ONLINE_DOMAINS[@]}"; do
105+
if timeout 6 curl --head --silent --output /dev/null ${domain}; then
106+
return 0
107+
fi
108+
done
109+
return 1
110+
}
111+
112+
prefetch_images() {
113+
[[ -z ${BRANCH} ]] && { echo -e "\e[33m\nUnknown branch...\e[0m"; exit 1; }
114+
git fetch origin #${BRANCH}
115+
while read image; do
116+
RET_C=0
117+
until docker pull "${image}"; do
118+
RET_C=$((RET_C + 1))
119+
echo -e "\e[33m\nError pulling $image, retrying...\e[0m"
120+
[ ${RET_C} -gt 3 ] && { echo -e "\e[31m\nToo many failed retries, exiting\e[0m"; exit 1; }
121+
sleep 1
122+
done
123+
done < <(git show "origin/${BRANCH}:docker-compose.yml" | grep "image:" | awk '{ gsub("image:","", $3); print $2 }')
124+
}
125+
126+
docker_garbage() {
127+
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/../.." && pwd )"
128+
IMGS_TO_DELETE=()
129+
130+
declare -A IMAGES_INFO
131+
COMPOSE_IMAGES=($(grep -oP "image: \K(ghcr\.io/)?mailcow.+" "${SCRIPT_DIR}/docker-compose.yml"))
132+
133+
for existing_image in $(docker images --format "{{.ID}}:{{.Repository}}:{{.Tag}}" | grep -E '(mailcow/|ghcr\.io/mailcow/)'); do
134+
ID=$(echo "$existing_image" | cut -d ':' -f 1)
135+
REPOSITORY=$(echo "$existing_image" | cut -d ':' -f 2)
136+
TAG=$(echo "$existing_image" | cut -d ':' -f 3)
137+
138+
if [[ "$REPOSITORY" == "mailcow/backup" || "$REPOSITORY" == "ghcr.io/mailcow/backup" ]]; then
139+
if [[ "$TAG" != "<none>" ]]; then
140+
continue
141+
fi
142+
fi
143+
144+
if [[ " ${COMPOSE_IMAGES[@]} " =~ " ${REPOSITORY}:${TAG} " ]]; then
145+
continue
146+
else
147+
IMGS_TO_DELETE+=("$ID")
148+
IMAGES_INFO["$ID"]="$REPOSITORY:$TAG"
149+
fi
150+
done
151+
152+
if [[ ! -z ${IMGS_TO_DELETE[*]} ]]; then
153+
echo "The following unused mailcow images were found:"
154+
for id in "${IMGS_TO_DELETE[@]}"; do
155+
echo " ${IMAGES_INFO[$id]} ($id)"
156+
done
157+
158+
if [ -z "$FORCE" ]; then
159+
read -r -p "Do you want to delete them to free up some space? [y/N] " response
160+
if [[ "$response" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
161+
docker rmi ${IMGS_TO_DELETE[*]}
162+
else
163+
echo "OK, skipped."
164+
fi
165+
else
166+
echo "Running in forced mode! Force removing old mailcow images..."
167+
docker rmi ${IMGS_TO_DELETE[*]}
168+
fi
169+
echo -e "\e[32mFurther cleanup...\e[0m"
170+
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\""
171+
fi
172+
}
173+
174+
in_array() {
175+
local e match="$1"
176+
shift
177+
for e; do [[ "$e" == "$match" ]] && return 0; done
178+
return 1
179+
}
180+
181+
detect_major_update() {
182+
if [ ${BRANCH} == "master" ]; then
183+
# Array with major versions
184+
# Add major versions here
185+
MAJOR_VERSIONS=(
186+
"2025-02"
187+
"2025-03"
188+
"2025-08"
189+
)
190+
191+
current_version=""
192+
if [[ -f "${SCRIPT_DIR}/data/web/inc/app_info.inc.php" ]]; then
193+
current_version=$(grep 'MAILCOW_GIT_VERSION' ${SCRIPT_DIR}/data/web/inc/app_info.inc.php | sed -E 's/.*MAILCOW_GIT_VERSION="([^"]+)".*/\1/')
194+
fi
195+
if [[ -z "$current_version" ]]; then
196+
return 1
197+
fi
198+
release_url="https://github.com/mailcow/mailcow-dockerized/releases/tag"
199+
200+
updates_to_apply=()
201+
202+
for version in "${MAJOR_VERSIONS[@]}"; do
203+
if [[ "$current_version" < "$version" ]]; then
204+
updates_to_apply+=("$version")
205+
fi
206+
done
207+
208+
if [[ ${#updates_to_apply[@]} -gt 0 ]]; then
209+
echo -e "\e[33m\nMAJOR UPDATES to be applied:\e[0m"
210+
for update in "${updates_to_apply[@]}"; do
211+
echo "$update - $release_url/$update"
212+
done
213+
214+
echo -e "\nPlease read the release notes before proceeding."
215+
read -p "Do you want to proceed with the update? [y/n] " response
216+
if [[ "${response}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
217+
echo "Proceeding with the update..."
218+
else
219+
echo "Update canceled. Exiting."
220+
exit 1
221+
fi
222+
fi
223+
fi
224+
}

0 commit comments

Comments
 (0)