mirror of
https://github.com/mailcow/mailcow-dockerized.git
synced 2026-02-18 07:06:24 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba0349a911 | ||
|
|
8caf09cd80 |
@@ -12,7 +12,7 @@ jobs:
|
||||
- name: Send message
|
||||
uses: thollander/actions-comment-pull-request@v3.0.1
|
||||
with:
|
||||
github-token: ${{ secrets.CHECKIFPRISSTAGING_ACTION_PAT }}
|
||||
GITHUB_TOKEN: ${{ secrets.CHECKIFPRISSTAGING_ACTION_PAT }}
|
||||
message: |
|
||||
Thanks for contributing!
|
||||
|
||||
|
||||
2
.github/workflows/pr_to_nightly.yml
vendored
2
.github/workflows/pr_to_nightly.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Run the Action
|
||||
uses: devops-infra/action-pull-request@v0.6.0
|
||||
uses: devops-infra/action-pull-request@v0.5.5
|
||||
with:
|
||||
github_token: ${{ secrets.PRTONIGHTLY_ACTION_PAT }}
|
||||
title: Automatic PR to nightly from ${{ github.event.repository.updated_at}}
|
||||
|
||||
12
.github/workflows/rebuild_backup_image.yml
vendored
12
.github/workflows/rebuild_backup_image.yml
vendored
@@ -9,8 +9,6 @@ on:
|
||||
jobs:
|
||||
docker_image_build:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
packages: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
@@ -21,13 +19,11 @@ jobs:
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to GHCR
|
||||
if: github.event_name != 'pull_request'
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
username: ${{ secrets.BACKUPIMAGEBUILD_ACTION_DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.BACKUPIMAGEBUILD_ACTION_DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v6
|
||||
@@ -36,4 +32,4 @@ jobs:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
file: data/Dockerfiles/backup/Dockerfile
|
||||
push: true
|
||||
tags: ghcr.io/mailcow/backup:latest
|
||||
tags: mailcow/backup:latest
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -47,9 +47,7 @@ data/conf/sogo/custom-theme.js
|
||||
data/conf/sogo/plist_ldap
|
||||
data/conf/sogo/sieve.creds
|
||||
data/conf/sogo/cron.creds
|
||||
data/conf/sogo/custom-fulllogo.svg
|
||||
data/conf/sogo/custom-shortlogo.svg
|
||||
data/conf/sogo/custom-fulllogo.png
|
||||
data/conf/sogo/sogo-full.svg
|
||||
data/gitea/
|
||||
data/gogs/
|
||||
data/hooks/dovecot/*
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
FROM alpine:3.21
|
||||
FROM alpine:3.20
|
||||
|
||||
LABEL maintainer = "The Infrastructure Company GmbH <info@servercow.de>"
|
||||
|
||||
|
||||
RUN apk upgrade --no-cache \
|
||||
&& apk add --update --no-cache \
|
||||
bash \
|
||||
@@ -14,7 +15,7 @@ RUN apk upgrade --no-cache \
|
||||
tini \
|
||||
tzdata \
|
||||
python3 \
|
||||
acme-tiny
|
||||
acme-tiny --repository=http://dl-cdn.alpinelinux.org/alpine/edge/community/
|
||||
|
||||
COPY acme.sh /srv/acme.sh
|
||||
COPY functions.sh /srv/functions.sh
|
||||
|
||||
@@ -138,7 +138,7 @@ log_f "Resolver OK"
|
||||
log_f "Waiting for domain table..."
|
||||
while [[ -z ${DOMAIN_TABLE} ]]; do
|
||||
curl --silent http://nginx.${COMPOSE_PROJECT_NAME}_mailcow-network/ >/dev/null 2>&1
|
||||
DOMAIN_TABLE=$(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SHOW TABLES LIKE 'domain'" -Bs)
|
||||
DOMAIN_TABLE=$(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SHOW TABLES LIKE 'domain'" -Bs)
|
||||
[[ -z ${DOMAIN_TABLE} ]] && sleep 10
|
||||
done
|
||||
log_f "OK" no_date
|
||||
@@ -231,7 +231,7 @@ while true; do
|
||||
|
||||
#########################################
|
||||
# IP and webroot challenge verification #
|
||||
SQL_DOMAINS=$(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT domain FROM domain WHERE backupmx=0 and active=1" -Bs)
|
||||
SQL_DOMAINS=$(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT domain FROM domain WHERE backupmx=0 and active=1" -Bs)
|
||||
if [[ ! $? -eq 0 ]]; then
|
||||
log_f "Failed to read SQL domains, retrying in 1 minute..."
|
||||
sleep 1m
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
FROM debian:bookworm-slim
|
||||
|
||||
RUN apt update && apt install pigz -y --no-install-recommends
|
||||
RUN apt update && apt install pigz
|
||||
@@ -1,99 +1,14 @@
|
||||
FROM alpine:3.21 AS builder
|
||||
|
||||
WORKDIR /src
|
||||
ENV CLAMD_VERSION=1.4.2
|
||||
|
||||
RUN apk upgrade --no-cache \
|
||||
&& apk add --update --no-cache \
|
||||
g++ \
|
||||
gcc \
|
||||
gdb \
|
||||
make \
|
||||
cmake \
|
||||
py3-pytest \
|
||||
python3 \
|
||||
valgrind \
|
||||
bzip2-dev \
|
||||
check-dev \
|
||||
curl-dev \
|
||||
json-c-dev \
|
||||
libmilter-dev \
|
||||
libxml2-dev \
|
||||
linux-headers \
|
||||
ncurses-dev \
|
||||
openssl-dev \
|
||||
pcre2-dev \
|
||||
zlib-dev \
|
||||
cargo \
|
||||
rust
|
||||
|
||||
RUN wget -P /src https://www.clamav.net/downloads/production/clamav-${CLAMD_VERSION}.tar.gz \
|
||||
&& tar xzfv /src/clamav-${CLAMD_VERSION}.tar.gz \
|
||||
&& cd /src/clamav-${CLAMD_VERSION} \
|
||||
&& cmake . \
|
||||
-D CMAKE_BUILD_TYPE="Release" \
|
||||
-D CMAKE_INSTALL_PREFIX="/usr" \
|
||||
-D CMAKE_INSTALL_LIBDIR="/usr/lib" \
|
||||
-D APP_CONFIG_DIRECTORY="/etc/clamav" \
|
||||
-D DATABASE_DIRECTORY="/var/lib/clamav" \
|
||||
-D ENABLE_CLAMONACC=OFF \
|
||||
-D ENABLE_EXAMPLES=OFF \
|
||||
-D ENABLE_MILTER=ON \
|
||||
-D ENABLE_MAN_PAGES=OFF \
|
||||
-D ENABLE_STATIC_LIB=OFF \
|
||||
-D ENABLE_JSON_SHARED=ON \
|
||||
&& cmake --build . \
|
||||
&& make DESTDIR="/clamav" -j$(($(nproc) - 1)) install \
|
||||
&& rm -r "/clamav/usr/lib/pkgconfig/" \
|
||||
&& sed -e "s|^\(Example\)|\# \1|" \
|
||||
-e "s|.*\(LocalSocket\) .*|\1 /tmp/clamd.sock|" \
|
||||
-e "s|.*\(TCPSocket\) .*|\1 3310|" \
|
||||
-e "s|.*\(TCPAddr\) .*|#\1 0.0.0.0|" \
|
||||
-e "s|.*\(User\) .*|\1 clamav|" \
|
||||
-e "s|^\#\(LogFile\) .*|\1 /var/log/clamav/clamd.log|" \
|
||||
-e "s|^\#\(LogTime\).*|\1 yes|" \
|
||||
"/clamav/etc/clamav/clamd.conf.sample" > "/clamav/etc/clamav/clamd.conf" \
|
||||
&& sed -e "s|^\(Example\)|\# \1|" \
|
||||
-e "s|.*\(DatabaseOwner\) .*|\1 clamav|" \
|
||||
-e "s|^\#\(UpdateLogFile\) .*|\1 /var/log/clamav/freshclam.log|" \
|
||||
-e "s|^\#\(NotifyClamd\).*|\1 /etc/clamav/clamd.conf|" \
|
||||
-e "s|^\#\(ScriptedUpdates\).*|\1 yes|" \
|
||||
"/clamav/etc/clamav/freshclam.conf.sample" > "/clamav/etc/clamav/freshclam.conf" \
|
||||
&& sed -e "s|^\(Example\)|\# \1|" \
|
||||
-e "s|.*\(MilterSocket\) .*|\1 inet:7357|" \
|
||||
-e "s|.*\(User\) .*|\1 clamav|" \
|
||||
-e "s|^\#\(LogFile\) .*|\1 /var/log/clamav/milter.log|" \
|
||||
-e "s|^\#\(LogTime\).*|\1 yes|" \
|
||||
-e "s|.*\(\ClamdSocket\) .*|\1 unix:/tmp/clamd.sock|" \
|
||||
"/clamav/etc/clamav/clamav-milter.conf.sample" > "/clamav/etc/clamav/clamav-milter.conf" || exit 1
|
||||
|
||||
|
||||
FROM alpine:3.21
|
||||
FROM alpine:3.20
|
||||
|
||||
LABEL maintainer = "The Infrastructure Company GmbH <info@servercow.de>"
|
||||
|
||||
RUN apk upgrade --no-cache \
|
||||
&& apk add --update --no-cache \
|
||||
tzdata \
|
||||
rsync \
|
||||
bind-tools \
|
||||
bash \
|
||||
tini \
|
||||
json-c \
|
||||
libbz2 \
|
||||
libcurl \
|
||||
libmilter \
|
||||
libxml2 \
|
||||
ncurses-libs \
|
||||
pcre2 \
|
||||
zlib \
|
||||
libgcc \
|
||||
&& addgroup -S "clamav" && \
|
||||
adduser -D -G "clamav" -h "/var/lib/clamav" -s "/bin/false" -S "clamav" && \
|
||||
install -d -m 755 -g "clamav" -o "clamav" "/var/log/clamav" && \
|
||||
chown -R clamav:clamav /var/lib/clamav
|
||||
|
||||
COPY --from=builder "/clamav" "/"
|
||||
rsync \
|
||||
clamav \
|
||||
bind-tools \
|
||||
bash \
|
||||
tini
|
||||
|
||||
# init
|
||||
COPY clamd.sh /clamd.sh
|
||||
|
||||
@@ -91,7 +91,6 @@ done
|
||||
) &
|
||||
BACKGROUND_TASKS+=($!)
|
||||
|
||||
echo "$(clamd -V) is starting... please wait a moment."
|
||||
nice -n10 clamd &
|
||||
BACKGROUND_TASKS+=($!)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM alpine:3.21
|
||||
FROM alpine:3.20
|
||||
|
||||
LABEL maintainer = "The Infrastructure Company GmbH <info@servercow.de>"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM alpine:3.21
|
||||
FROM alpine:3.20
|
||||
|
||||
LABEL maintainer="The Infrastructure Company GmbH <info@servercow.de>"
|
||||
|
||||
@@ -65,7 +65,7 @@ RUN addgroup -g 5000 vmail \
|
||||
perl-par-packer \
|
||||
perl-parse-recdescent \
|
||||
perl-lockfile-simple \
|
||||
libproc2 \
|
||||
libproc \
|
||||
perl-readonly \
|
||||
perl-regexp-common \
|
||||
perl-sys-meminfo \
|
||||
|
||||
@@ -15,6 +15,6 @@ if ! [[ ${MAX_AGE} =~ ${NUM_REGEXP} ]] ; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TO_DELETE=$(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT COUNT(id) FROM quarantine WHERE created < NOW() - INTERVAL ${MAX_AGE//[!0-9]/} DAY" -BN)
|
||||
mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "DELETE FROM quarantine WHERE created < NOW() - INTERVAL ${MAX_AGE//[!0-9]/} DAY"
|
||||
TO_DELETE=$(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT COUNT(id) FROM quarantine WHERE created < NOW() - INTERVAL ${MAX_AGE//[!0-9]/} DAY" -BN)
|
||||
mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "DELETE FROM quarantine WHERE created < NOW() - INTERVAL ${MAX_AGE//[!0-9]/} DAY"
|
||||
echo "Deleted ${TO_DELETE} items from quarantine table (max age is ${MAX_AGE//[!0-9]/} days)"
|
||||
|
||||
@@ -414,15 +414,15 @@ printenv | sed 's/^\(.*\)$/export \1/g' > /source_env.sh
|
||||
|
||||
# Clean stopped imapsync jobs
|
||||
rm -f /tmp/imapsync_busy.lock
|
||||
IMAPSYNC_TABLE=$(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SHOW TABLES LIKE 'imapsync'" -Bs)
|
||||
[[ ! -z ${IMAPSYNC_TABLE} ]] && mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "UPDATE imapsync SET is_running='0'"
|
||||
IMAPSYNC_TABLE=$(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SHOW TABLES LIKE 'imapsync'" -Bs)
|
||||
[[ ! -z ${IMAPSYNC_TABLE} ]] && mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "UPDATE imapsync SET is_running='0'"
|
||||
|
||||
# Envsubst maildir_gc
|
||||
echo "$(envsubst < /usr/local/bin/maildir_gc.sh)" > /usr/local/bin/maildir_gc.sh
|
||||
|
||||
# GUID generation
|
||||
while [[ ${VERSIONS_OK} != 'OK' ]]; do
|
||||
if [[ ! -z $(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "SELECT 'OK' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = \"${DBNAME}\" AND TABLE_NAME = 'versions'") ]]; then
|
||||
if [[ ! -z $(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "SELECT 'OK' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = \"${DBNAME}\" AND TABLE_NAME = 'versions'") ]]; then
|
||||
VERSIONS_OK=OK
|
||||
else
|
||||
echo "Waiting for versions table to be created..."
|
||||
@@ -433,11 +433,11 @@ PUBKEY_MCRYPT=$(doveconf -P 2> /dev/null | grep -i mail_crypt_global_public_key
|
||||
if [ -f ${PUBKEY_MCRYPT} ]; then
|
||||
GUID=$(cat <(echo ${MAILCOW_HOSTNAME}) /mail_crypt/ecpubkey.pem | sha256sum | cut -d ' ' -f1 | tr -cd "[a-fA-F0-9.:/] ")
|
||||
if [ ${#GUID} -eq 64 ]; then
|
||||
mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF
|
||||
mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF
|
||||
REPLACE INTO versions (application, version) VALUES ("GUID", "${GUID}");
|
||||
EOF
|
||||
else
|
||||
mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF
|
||||
mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF
|
||||
REPLACE INTO versions (application, version) VALUES ("GUID", "INVALID");
|
||||
EOF
|
||||
fi
|
||||
|
||||
@@ -8,8 +8,7 @@ from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
from email.utils import COMMASPACE, formatdate
|
||||
import jinja2
|
||||
from jinja2 import TemplateError
|
||||
from jinja2.sandbox import SandboxedEnvironment
|
||||
from jinja2 import Template
|
||||
import json
|
||||
import redis
|
||||
import time
|
||||
@@ -81,22 +80,17 @@ try:
|
||||
if len(meta_query) == 0:
|
||||
return
|
||||
msg_count = len(meta_query)
|
||||
env = SandboxedEnvironment()
|
||||
if r.get('Q_HTML'):
|
||||
try:
|
||||
template = env.from_string(r.get('Q_HTML'))
|
||||
except Exception:
|
||||
print("Error: Cannot parse quarantine template, falling back to default template.")
|
||||
with open('/templates/quarantine.tpl') as file_:
|
||||
template = env.from_string(file_.read())
|
||||
else:
|
||||
try:
|
||||
template = Template(r.get('Q_HTML'))
|
||||
except:
|
||||
print("Error: Cannot parse quarantine template, falling back to default template.")
|
||||
with open('/templates/quarantine.tpl') as file_:
|
||||
template = env.from_string(file_.read())
|
||||
try:
|
||||
html = template.render(meta=meta_query, username=rcpt, counter=msg_count, hostname=mailcow_hostname, quarantine_acl=quarantine_acl)
|
||||
except (jinja2.exceptions.SecurityError, TemplateError) as ex:
|
||||
print(f"SecurityError or TemplateError in template rendering: {ex}")
|
||||
return
|
||||
template = Template(file_.read())
|
||||
else:
|
||||
with open('/templates/quarantine.tpl') as file_:
|
||||
template = Template(file_.read())
|
||||
html = template.render(meta=meta_query, username=rcpt, counter=msg_count, hostname=mailcow_hostname, quarantine_acl=quarantine_acl)
|
||||
text = html2text.html2text(html)
|
||||
count = 0
|
||||
while count < 15:
|
||||
@@ -171,4 +165,4 @@ try:
|
||||
notify_rcpt(record['rcpt'], record['counter'], record['quarantine_acl'], attrs['quarantine_category'])
|
||||
|
||||
finally:
|
||||
os.unlink(pidfile)
|
||||
os.unlink(pidfile)
|
||||
|
||||
@@ -6,7 +6,7 @@ from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
from email.utils import COMMASPACE, formatdate
|
||||
import jinja2
|
||||
from jinja2.sandbox import SandboxedEnvironment
|
||||
from jinja2 import Template
|
||||
import redis
|
||||
import time
|
||||
import json
|
||||
@@ -23,7 +23,7 @@ else:
|
||||
|
||||
while True:
|
||||
try:
|
||||
r = redis.StrictRedis(host='redis', decode_responses=True, port=6379, db=0, username='quota_notify', password='')
|
||||
r = redis.StrictRedis(host='redis', decode_responses=True, port=6379, db=0, password=os.environ['REDISPASS'])
|
||||
r.ping()
|
||||
except Exception as ex:
|
||||
print('%s - trying again...' % (ex))
|
||||
@@ -33,24 +33,16 @@ while True:
|
||||
|
||||
if r.get('QW_HTML'):
|
||||
try:
|
||||
env = SandboxedEnvironment()
|
||||
template = env.from_string(r.get('QW_HTML'))
|
||||
except Exception:
|
||||
print("Error: Cannot parse quota template, falling back to default template.")
|
||||
template = Template(r.get('QW_HTML'))
|
||||
except:
|
||||
print("Error: Cannot parse quarantine template, falling back to default template.")
|
||||
with open('/templates/quota.tpl') as file_:
|
||||
env = SandboxedEnvironment()
|
||||
template = env.from_string(file_.read())
|
||||
template = Template(file_.read())
|
||||
else:
|
||||
with open('/templates/quota.tpl') as file_:
|
||||
env = SandboxedEnvironment()
|
||||
template = env.from_string(file_.read())
|
||||
|
||||
try:
|
||||
html = template.render(username=username, percent=percent)
|
||||
except (jinja2.exceptions.SecurityError, jinja2.TemplateError) as ex:
|
||||
print(f"SecurityError or TemplateError in template rendering: {ex}")
|
||||
sys.exit(1)
|
||||
template = Template(file_.read())
|
||||
|
||||
html = template.render(username=username, percent=percent)
|
||||
text = html2text.html2text(html)
|
||||
|
||||
try:
|
||||
@@ -99,4 +91,4 @@ except:
|
||||
try:
|
||||
sys.stderr.close()
|
||||
except:
|
||||
pass
|
||||
pass
|
||||
|
||||
@@ -38,13 +38,8 @@ filter f_replica {
|
||||
not match("User has no mail_replica in userdb" value("MESSAGE"));
|
||||
not match("Error: sync: Unknown user in remote" value("MESSAGE"));
|
||||
};
|
||||
filter f_dovecot_auth_try {
|
||||
not match("- trying the next passdb" value("MESSAGE")) and
|
||||
not match("- trying the next userdb" value("MESSAGE"));
|
||||
};
|
||||
log {
|
||||
source(s_dgram);
|
||||
filter(f_dovecot_auth_try);
|
||||
filter(f_replica);
|
||||
destination(d_stdout);
|
||||
filter(f_mail);
|
||||
|
||||
@@ -38,13 +38,8 @@ filter f_replica {
|
||||
not match("User has no mail_replica in userdb" value("MESSAGE"));
|
||||
not match("Error: sync: Unknown user in remote" value("MESSAGE"));
|
||||
};
|
||||
filter f_dovecot_auth_try {
|
||||
not match("- trying the next passdb" value("MESSAGE")) and
|
||||
not match("- trying the next userdb" value("MESSAGE"));
|
||||
};
|
||||
log {
|
||||
source(s_dgram);
|
||||
filter(f_dovecot_auth_try);
|
||||
filter(f_replica);
|
||||
destination(d_stdout);
|
||||
filter(f_mail);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM alpine:3.21
|
||||
FROM alpine:3.20
|
||||
|
||||
LABEL maintainer = "The Infrastructure Company GmbH <info@servercow.de>"
|
||||
|
||||
|
||||
@@ -85,10 +85,11 @@ def refreshF2bregex():
|
||||
f2bregex[3] = r'warning: .*\[([0-9a-f\.:]+)\]: SASL .+ authentication failed: (?!.*Connection lost to authentication server).+'
|
||||
f2bregex[4] = r'warning: non-SMTP command from .*\[([0-9a-f\.:]+)]:.+'
|
||||
f2bregex[5] = r'NOQUEUE: reject: RCPT from \[([0-9a-f\.:]+)].+Protocol error.+'
|
||||
f2bregex[6] = r'\w+\([^,]+,([0-9a-f\.:]+),<[^>]+>\): Password mismatch \(SHA1 of given password: [a-f0-9]+\)'
|
||||
f2bregex[7] = r'\w+\([^,]+,([0-9a-f\.:]+),<[^>]+>\): unknown user \(SHA1 of given password: [a-f0-9]+\)'
|
||||
f2bregex[8] = r'SOGo.+ Login from \'([0-9a-f\.:]+)\' for user .+ might not have worked'
|
||||
f2bregex[9] = r'([0-9a-f\.:]+) \"GET \/SOGo\/.* HTTP.+\" 403 .+'
|
||||
f2bregex[6] = r'-login: Disconnected.+ \(auth failed, .+\): user=.*, method=.+, rip=([0-9a-f\.:]+),'
|
||||
f2bregex[7] = r'-login: Aborted login.+ \(auth failed .+\): user=.+, rip=([0-9a-f\.:]+), lip.+'
|
||||
f2bregex[8] = r'-login: Aborted login.+ \(tried to use disallowed .+\): user=.+, rip=([0-9a-f\.:]+), lip.+'
|
||||
f2bregex[9] = r'SOGo.+ Login from \'([0-9a-f\.:]+)\' for user .+ might not have worked'
|
||||
f2bregex[10] = r'([0-9a-f\.:]+) \"GET \/SOGo\/.* HTTP.+\" 403 .+'
|
||||
r.set('F2B_REGEX', json.dumps(f2bregex, ensure_ascii=False))
|
||||
else:
|
||||
try:
|
||||
|
||||
@@ -7,7 +7,7 @@ def includes_conf(env, template_vars):
|
||||
listen_plain = "listen_plain.active"
|
||||
listen_ssl = "listen_ssl.active"
|
||||
|
||||
server_name_config = f"server_name {template_vars['MAILCOW_HOSTNAME']} autodiscover.* autoconfig.* {' '.join(template_vars['ADDITIONAL_SERVER_NAMES'])};"
|
||||
server_name_config = f"server_name {template_vars['MAILCOW_HOSTNAME']} autodiscover.* autoconfig.* {template_vars['ADDITIONAL_SERVER_NAMES']};"
|
||||
listen_plain_config = f"listen {template_vars['HTTP_PORT']};"
|
||||
listen_ssl_config = f"listen {template_vars['HTTPS_PORT']};"
|
||||
if not template_vars['DISABLE_IPv6']:
|
||||
@@ -42,24 +42,20 @@ def nginx_conf(env, template_vars):
|
||||
|
||||
def prepare_template_vars():
|
||||
ipv4_network = os.getenv("IPV4_NETWORK", "172.22.1")
|
||||
additional_server_names = os.getenv("ADDITIONAL_SERVER_NAMES", "")
|
||||
trusted_proxies = os.getenv("TRUSTED_PROXIES", "")
|
||||
|
||||
template_vars = {
|
||||
'IPV4_NETWORK': ipv4_network,
|
||||
'TRUSTED_PROXIES': [item.strip() for item in trusted_proxies.split(",") if item.strip()],
|
||||
'TRUSTED_NETWORK': os.getenv("TRUSTED_NETWORK", False),
|
||||
'SKIP_RSPAMD': os.getenv("SKIP_RSPAMD", "n").lower() in ("y", "yes"),
|
||||
'SKIP_SOGO': os.getenv("SKIP_SOGO", "n").lower() in ("y", "yes"),
|
||||
'NGINX_USE_PROXY_PROTOCOL': os.getenv("NGINX_USE_PROXY_PROTOCOL", "n").lower() in ("y", "yes"),
|
||||
'MAILCOW_HOSTNAME': os.getenv("MAILCOW_HOSTNAME", ""),
|
||||
'ADDITIONAL_SERVER_NAMES': [item.strip() for item in additional_server_names.split(",") if item.strip()],
|
||||
'ADDITIONAL_SERVER_NAMES': os.getenv("ADDITIONAL_SERVER_NAMES", "").replace(',', ' '),
|
||||
'HTTP_PORT': os.getenv("HTTP_PORT", "80"),
|
||||
'HTTPS_PORT': os.getenv("HTTPS_PORT", "443"),
|
||||
'SOGOHOST': os.getenv("SOGOHOST", ipv4_network + ".248"),
|
||||
'RSPAMDHOST': os.getenv("RSPAMDHOST", "rspamd-mailcow"),
|
||||
'PHPFPMHOST': os.getenv("PHPFPMHOST", "php-fpm-mailcow"),
|
||||
'DISABLE_IPv6': os.getenv("DISABLE_IPv6", "n").lower() in ("y", "yes"),
|
||||
'HTTP_REDIRECT': os.getenv("HTTP_REDIRECT", "n").lower() in ("y", "yes"),
|
||||
}
|
||||
|
||||
ssl_dir = '/etc/ssl/mail/'
|
||||
|
||||
@@ -8,13 +8,13 @@ until ping ${PHPFPMHOST} -c1 > /dev/null; do
|
||||
echo "Waiting for PHP..."
|
||||
sleep 1
|
||||
done
|
||||
if ! printf "%s\n" "${SKIP_SOGO}" | grep -E '^([yY][eE][sS]|[yY])+$' >/dev/null; then
|
||||
if printf "%s\n" "${SKIP_SOGO}" | grep -E '^([yY][eE][sS]|[yY])+$' >/dev/null; then
|
||||
until ping ${SOGOHOST} -c1 > /dev/null; do
|
||||
echo "Waiting for SOGo..."
|
||||
sleep 1
|
||||
done
|
||||
fi
|
||||
if ! printf "%s\n" "${SKIP_RSPAMD}" | grep -E '^([yY][eE][sS]|[yY])+$' >/dev/null; then
|
||||
if printf "%s\n" "${SKIP_RSPAMD}" | grep -E '^([yY][eE][sS]|[yY])+$' >/dev/null; then
|
||||
until ping ${RSPAMDHOST} -c1 > /dev/null; do
|
||||
echo "Waiting for Rspamd..."
|
||||
sleep 1
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM alpine:3.21
|
||||
FROM alpine:3.20
|
||||
|
||||
LABEL maintainer = "The Infrastructure Company GmbH <info@servercow.de>"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM php:8.2-fpm-alpine3.21
|
||||
FROM php:8.2-fpm-alpine3.20
|
||||
|
||||
LABEL maintainer = "The Infrastructure Company GmbH <info@servercow.de>"
|
||||
|
||||
@@ -13,7 +13,7 @@ ARG MEMCACHED_PECL_VERSION=3.2.0
|
||||
# renovate: datasource=github-tags depName=phpredis/phpredis versioning=semver-coerced extractVersion=(?<version>.*)$
|
||||
ARG REDIS_PECL_VERSION=6.1.0
|
||||
# renovate: datasource=github-tags depName=composer/composer versioning=semver-coerced extractVersion=(?<version>.*)$
|
||||
ARG COMPOSER_VERSION=2.8.6
|
||||
ARG COMPOSER_VERSION=2.6.6
|
||||
|
||||
RUN apk add -U --no-cache autoconf \
|
||||
aspell-dev \
|
||||
|
||||
@@ -81,7 +81,7 @@ if [ ${SQL_CHANGED} -eq 1 ]; then
|
||||
fi
|
||||
|
||||
# Check mysql tz import (master and slave)
|
||||
TZ_CHECK=$(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT CONVERT_TZ('2019-11-02 23:33:00','Europe/Berlin','UTC') AS time;" -BN 2> /dev/null)
|
||||
TZ_CHECK=$(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT CONVERT_TZ('2019-11-02 23:33:00','Europe/Berlin','UTC') AS time;" -BN 2> /dev/null)
|
||||
if [[ -z ${TZ_CHECK} ]] || [[ "${TZ_CHECK}" == "NULL" ]]; then
|
||||
SQL_FULL_TZINFO_IMPORT_RETURN=$(curl --silent --insecure -XPOST https://dockerapi.${COMPOSE_PROJECT_NAME}_mailcow-network/containers/${CONTAINER_ID}/exec -d '{"cmd":"system", "task":"mysql_tzinfo_to_sql"}' --silent -H 'Content-type: application/json')
|
||||
echo "MySQL mysql_tzinfo_to_sql - debug output:"
|
||||
@@ -120,11 +120,11 @@ if [[ "${MASTER}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||
while read line
|
||||
do
|
||||
DOMAIN_ARR+=("$line")
|
||||
done < <(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT domain FROM domain" -Bs)
|
||||
done < <(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT domain FROM domain" -Bs)
|
||||
while read line
|
||||
do
|
||||
DOMAIN_ARR+=("$line")
|
||||
done < <(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT alias_domain FROM alias_domain" -Bs)
|
||||
done < <(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT alias_domain FROM alias_domain" -Bs)
|
||||
|
||||
if [[ ! -z ${DOMAIN_ARR} ]]; then
|
||||
for domain in "${DOMAIN_ARR[@]}"; do
|
||||
@@ -146,13 +146,13 @@ if [[ "${MASTER}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||
VALIDATED_IPS=$(array_by_comma ${VALIDATED_API_ALLOW_FROM_ARR[*]})
|
||||
if [[ ! -z ${VALIDATED_IPS} ]]; then
|
||||
if [[ ${API_KEY} != "invalid" ]] && [[ ! -z ${API_KEY} ]]; then
|
||||
mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF
|
||||
mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF
|
||||
DELETE FROM api WHERE access = 'rw';
|
||||
INSERT INTO api (api_key, active, allow_from, access) VALUES ("${API_KEY}", "1", "${VALIDATED_IPS}", "rw");
|
||||
EOF
|
||||
fi
|
||||
if [[ ${API_KEY_READ_ONLY} != "invalid" ]] && [[ ! -z ${API_KEY_READ_ONLY} ]]; then
|
||||
mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF
|
||||
mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF
|
||||
DELETE FROM api WHERE access = 'ro';
|
||||
INSERT INTO api (api_key, active, allow_from, access) VALUES ("${API_KEY_READ_ONLY}", "1", "${VALIDATED_IPS}", "ro");
|
||||
EOF
|
||||
@@ -161,7 +161,7 @@ EOF
|
||||
fi
|
||||
|
||||
# Create events (master only, STATUS for event on slave will be SLAVESIDE_DISABLED)
|
||||
mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF
|
||||
mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF
|
||||
DROP EVENT IF EXISTS clean_spamalias;
|
||||
DELIMITER //
|
||||
CREATE EVENT clean_spamalias
|
||||
|
||||
@@ -395,7 +395,7 @@ EOF
|
||||
|
||||
if [ ! -f /opt/postfix/conf/dns_blocklists.cf ]; then
|
||||
cat <<EOF > /opt/postfix/conf/dns_blocklists.cf
|
||||
# This file can be edited.
|
||||
# This file can be edited.
|
||||
# Delete this file and restart postfix container to revert any changes.
|
||||
postscreen_dnsbl_sites = wl.mailspike.net=127.0.0.[18;19;20]*-2
|
||||
hostkarma.junkemailfilter.com=127.0.0.1*-2
|
||||
@@ -403,6 +403,7 @@ postscreen_dnsbl_sites = wl.mailspike.net=127.0.0.[18;19;20]*-2
|
||||
list.dnswl.org=127.0.[0..255].1*-4
|
||||
list.dnswl.org=127.0.[0..255].2*-6
|
||||
list.dnswl.org=127.0.[0..255].3*-8
|
||||
ix.dnsbl.manitu.net*2
|
||||
bl.spamcop.net*2
|
||||
bl.suomispam.net*2
|
||||
hostkarma.junkemailfilter.com=127.0.0.2*3
|
||||
@@ -416,10 +417,6 @@ postscreen_dnsbl_sites = wl.mailspike.net=127.0.0.[18;19;20]*-2
|
||||
bl.mailspike.net=127.0.0.[10;11;12]*4
|
||||
EOF
|
||||
fi
|
||||
|
||||
# Remove discontinued DNSBLs from existing dns_blocklists.cf
|
||||
sed -i '/ix\.dnsbl\.manitu\.net\*2/d' /opt/postfix/conf/dns_blocklists.cf # Nixspam
|
||||
|
||||
DNSBL_CONFIG=$(grep -v '^#' /opt/postfix/conf/dns_blocklists.cf | grep '\S')
|
||||
|
||||
if [ ! -z "$DNSBL_CONFIG" ]; then
|
||||
@@ -510,11 +507,6 @@ chgrp -R postdrop /var/spool/postfix/public
|
||||
chgrp -R postdrop /var/spool/postfix/maildrop
|
||||
postfix set-permissions
|
||||
|
||||
# Checking if there is a leftover of a crashed postfix container before starting a new one
|
||||
if [ -e /var/spool/postfix/pid/master.pid ]; then
|
||||
rm -rf /var/spool/postfix/pid/master.pid
|
||||
fi
|
||||
|
||||
# Check Postfix configuration
|
||||
postconf -c /opt/postfix/conf > /dev/null
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
autorestart=true
|
||||
startsecs=10
|
||||
|
||||
[eventlistener:processes]
|
||||
command=/usr/local/sbin/stop-supervisor.sh
|
||||
|
||||
@@ -2,7 +2,7 @@ FROM debian:bookworm-slim
|
||||
LABEL maintainer="The Infrastructure Company GmbH <info@servercow.de>"
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
ARG RSPAMD_VER=rspamd_3.11.1-1~ab0b44951
|
||||
ARG RSPAMD_VER=rspamd_3.10.2-1~b8a232043
|
||||
ARG CODENAME=bookworm
|
||||
ENV LC_ALL=C
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ LABEL maintainer="The Infrastructure Company GmbH <info@servercow.de>"
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
ARG DEBIAN_VERSION=bookworm
|
||||
ARG SOGO_DEBIAN_REPOSITORY=https://packagingv2.sogo.nu/sogo-nightly-debian/
|
||||
ARG SOGO_DEBIAN_REPOSITORY=http://www.axis.cz/linux/debian
|
||||
# renovate: datasource=github-releases depName=tianon/gosu versioning=semver-coerced extractVersion=^(?<version>.*)$
|
||||
ARG GOSU_VERSION=1.17
|
||||
ENV LC_ALL=C
|
||||
@@ -33,8 +33,9 @@ RUN echo "Building from repository $SOGO_DEBIAN_REPOSITORY" \
|
||||
&& gosu nobody true \
|
||||
&& mkdir /usr/share/doc/sogo \
|
||||
&& touch /usr/share/doc/sogo/empty.sh \
|
||||
&& wget -O- https://keys.openpgp.org/vks/v1/by-fingerprint/74FFC6D72B925A34B5D356BDF8A27B36A6E2EAE9 | gpg --dearmor | apt-key add - \
|
||||
&& echo "deb [trusted=yes] ${SOGO_DEBIAN_REPOSITORY} ${DEBIAN_VERSION} main" > /etc/apt/sources.list.d/sogo.list \
|
||||
&& wget http://www.axis.cz/linux/debian/axis-archive-keyring.deb -O /tmp/axis-archive-keyring.deb \
|
||||
&& apt install -y /tmp/axis-archive-keyring.deb \
|
||||
&& echo "deb [trusted=yes] ${SOGO_DEBIAN_REPOSITORY} ${DEBIAN_VERSION} sogo-v5" > /etc/apt/sources.list.d/sogo.list \
|
||||
&& apt-get update && apt-get install -y --no-install-recommends \
|
||||
sogo \
|
||||
sogo-activesync \
|
||||
|
||||
@@ -14,11 +14,11 @@ do
|
||||
done
|
||||
|
||||
# Wait for updated schema
|
||||
DBV_NOW=$(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT version FROM versions WHERE application = 'db_schema';" -BN)
|
||||
DBV_NOW=$(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT version FROM versions WHERE application = 'db_schema';" -BN)
|
||||
DBV_NEW=$(grep -oE '\$db_version = .*;' init_db.inc.php | sed 's/$db_version = //g;s/;//g' | cut -d \" -f2)
|
||||
while [[ "${DBV_NOW}" != "${DBV_NEW}" ]]; do
|
||||
echo "Waiting for schema update..."
|
||||
DBV_NOW=$(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT version FROM versions WHERE application = 'db_schema';" -BN)
|
||||
DBV_NOW=$(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT version FROM versions WHERE application = 'db_schema';" -BN)
|
||||
DBV_NEW=$(grep -oE '\$db_version = .*;' init_db.inc.php | sed 's/$db_version = //g;s/;//g' | cut -d \" -f2)
|
||||
sleep 5
|
||||
done
|
||||
@@ -27,10 +27,10 @@ echo "DB schema is ${DBV_NOW}"
|
||||
# Recreate view
|
||||
if [[ "${MASTER}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||
echo "We are master, preparing sogo_view..."
|
||||
mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "DROP VIEW IF EXISTS sogo_view"
|
||||
mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "DROP VIEW IF EXISTS sogo_view"
|
||||
while [[ ${VIEW_OK} != 'OK' ]]; do
|
||||
mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF
|
||||
CREATE VIEW sogo_view (c_uid, domain, c_name, c_password, c_cn, mail, aliases, ad_aliases, ext_acl, kind, multiple_bookings) AS
|
||||
mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF
|
||||
CREATE VIEW sogo_view (c_uid, domain, c_name, c_password, c_cn, mail, aliases, ad_aliases, ext_acl, kind, multiple_bookings) AS
|
||||
SELECT
|
||||
mailbox.username,
|
||||
mailbox.domain,
|
||||
@@ -59,7 +59,7 @@ WHERE
|
||||
GROUP BY
|
||||
mailbox.username;
|
||||
EOF
|
||||
if [[ ! -z $(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "SELECT 'OK' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'sogo_view'") ]]; then
|
||||
if [[ ! -z $(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "SELECT 'OK' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'sogo_view'") ]]; then
|
||||
VIEW_OK=OK
|
||||
else
|
||||
echo "Will retry to setup SOGo view in 3s..."
|
||||
@@ -68,7 +68,7 @@ EOF
|
||||
done
|
||||
else
|
||||
while [[ ${VIEW_OK} != 'OK' ]]; do
|
||||
if [[ ! -z $(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "SELECT 'OK' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'sogo_view'") ]]; then
|
||||
if [[ ! -z $(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "SELECT 'OK' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'sogo_view'") ]]; then
|
||||
VIEW_OK=OK
|
||||
else
|
||||
echo "Waiting for SOGo view to be created by master..."
|
||||
@@ -81,12 +81,12 @@ fi
|
||||
if [[ "${MASTER}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||
echo "We are master, preparing _sogo_static_view..."
|
||||
while [[ ${STATIC_VIEW_OK} != 'OK' ]]; do
|
||||
if [[ ! -z $(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "SELECT 'OK' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '_sogo_static_view'") ]]; then
|
||||
if [[ ! -z $(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "SELECT 'OK' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '_sogo_static_view'") ]]; then
|
||||
STATIC_VIEW_OK=OK
|
||||
echo "Updating _sogo_static_view content..."
|
||||
# If changed, also update init_db.inc.php
|
||||
mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "REPLACE INTO _sogo_static_view (c_uid, domain, c_name, c_password, c_cn, mail, aliases, ad_aliases, ext_acl, kind, multiple_bookings) SELECT c_uid, domain, c_name, c_password, c_cn, mail, aliases, ad_aliases, ext_acl, kind, multiple_bookings from sogo_view;"
|
||||
mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "DELETE FROM _sogo_static_view WHERE c_uid NOT IN (SELECT username FROM mailbox WHERE active = '1')"
|
||||
mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "REPLACE INTO _sogo_static_view (c_uid, domain, c_name, c_password, c_cn, mail, aliases, ad_aliases, ext_acl, kind, multiple_bookings) SELECT c_uid, domain, c_name, c_password, c_cn, mail, aliases, ad_aliases, ext_acl, kind, multiple_bookings from sogo_view;"
|
||||
mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "DELETE FROM _sogo_static_view WHERE c_uid NOT IN (SELECT username FROM mailbox WHERE active = '1')"
|
||||
else
|
||||
echo "Waiting for database initialization..."
|
||||
sleep 3
|
||||
@@ -94,7 +94,7 @@ if [[ "${MASTER}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||
done
|
||||
else
|
||||
while [[ ${STATIC_VIEW_OK} != 'OK' ]]; do
|
||||
if [[ ! -z $(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "SELECT 'OK' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '_sogo_static_view'") ]]; then
|
||||
if [[ ! -z $(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "SELECT 'OK' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '_sogo_static_view'") ]]; then
|
||||
STATIC_VIEW_OK=OK
|
||||
else
|
||||
echo "Waiting for database initialization by master..."
|
||||
@@ -107,9 +107,9 @@ fi
|
||||
# Recreate password update trigger
|
||||
if [[ "${MASTER}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||
echo "We are master, preparing update trigger..."
|
||||
mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "DROP TRIGGER IF EXISTS sogo_update_password"
|
||||
mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "DROP TRIGGER IF EXISTS sogo_update_password"
|
||||
while [[ ${TRIGGER_OK} != 'OK' ]]; do
|
||||
mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF
|
||||
mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF
|
||||
DELIMITER -
|
||||
CREATE TRIGGER sogo_update_password AFTER UPDATE ON _sogo_static_view
|
||||
FOR EACH ROW
|
||||
@@ -119,7 +119,7 @@ END;
|
||||
-
|
||||
DELIMITER ;
|
||||
EOF
|
||||
if [[ ! -z $(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "SELECT 'OK' FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME = 'sogo_update_password'") ]]; then
|
||||
if [[ ! -z $(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "SELECT 'OK' FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME = 'sogo_update_password'") ]]; then
|
||||
TRIGGER_OK=OK
|
||||
else
|
||||
echo "Will retry to setup SOGo password update trigger in 3s"
|
||||
@@ -216,7 +216,7 @@ while read -r line gal
|
||||
line=${line} envsubst < /etc/sogo/plist_ldap >> /var/lib/sogo/GNUstep/Defaults/sogod.plist
|
||||
echo " </array>
|
||||
</dict>" >> /var/lib/sogo/GNUstep/Defaults/sogod.plist
|
||||
done < <(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT domain, CASE gal WHEN '1' THEN 'YES' ELSE 'NO' END AS gal FROM domain;" -B -N)
|
||||
done < <(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT domain, CASE gal WHEN '1' THEN 'YES' ELSE 'NO' END AS gal FROM domain;" -B -N)
|
||||
|
||||
# Generate footer
|
||||
echo ' </dict>
|
||||
@@ -240,8 +240,8 @@ chmod 600 /var/lib/sogo/GNUstep/Defaults/sogod.plist
|
||||
# fi
|
||||
#fi
|
||||
|
||||
# Rename custom logo, if any
|
||||
[[ -f /etc/sogo/sogo-full.svg ]] && mv /etc/sogo/sogo-full.svg /etc/sogo/custom-fulllogo.svg
|
||||
# Copy logo, if any
|
||||
[[ -f /etc/sogo/sogo-full.svg ]] && cp /etc/sogo/sogo-full.svg /usr/lib/GNUstep/SOGo/WebServerResources/img/sogo-full.svg
|
||||
|
||||
# Rsync web content
|
||||
echo "Syncing web content with named volume"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM alpine:3.21
|
||||
FROM alpine:3.20
|
||||
|
||||
LABEL maintainer = "The Infrastructure Company GmbH <info@servercow.de>"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM alpine:3.21
|
||||
FROM alpine:3.20
|
||||
|
||||
LABEL maintainer = "The Infrastructure Company GmbH <info@servercow.de>"
|
||||
|
||||
|
||||
@@ -132,9 +132,9 @@ fi
|
||||
|
||||
# Connect to the DB server and store output in vars
|
||||
if [[ -n $socket ]]; then
|
||||
ConnectionResult=$(mariadb --skip-ssl ${optfile} ${socket} ${user} -e "show slave ${connection} status\G" 2>&1)
|
||||
ConnectionResult=$(mysql ${optfile} ${socket} ${user} -e "show slave ${connection} status\G" 2>&1)
|
||||
else
|
||||
ConnectionResult=$(mariadb --skip-ssl ${optfile} ${host} ${port} ${user} -e "show slave ${connection} status\G" 2>&1)
|
||||
ConnectionResult=$(mysql ${optfile} ${host} ${port} ${user} -e "show slave ${connection} status\G" 2>&1)
|
||||
fi
|
||||
|
||||
if [ -z "`echo "${ConnectionResult}" |grep Slave_IO_State`" ]; then
|
||||
|
||||
@@ -234,7 +234,7 @@ external_checks() {
|
||||
diff_c=0
|
||||
THRESHOLD=${EXTERNAL_CHECKS_THRESHOLD}
|
||||
# Reduce error count by 2 after restarting an unhealthy container
|
||||
GUID=$(mariadb --skip-ssl -u${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT version FROM versions WHERE application = 'GUID'" -BN)
|
||||
GUID=$(mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT version FROM versions WHERE application = 'GUID'" -BN)
|
||||
trap "[ ${err_count} -gt 1 ] && err_count=$(( ${err_count} - 2 ))" USR1
|
||||
while [ ${err_count} -lt ${THRESHOLD} ]; do
|
||||
err_c_cur=${err_count}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
-----BEGIN DH PARAMETERS-----
|
||||
MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
|
||||
+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
|
||||
87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
|
||||
YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
|
||||
7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
|
||||
ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
|
||||
MIIBCAKCAQEA9iHB0CRDhV8wfBgqnmvuJpl0fzL3qL75R4ZvQHlfMNLrxuIz2x9D
|
||||
9zcDhPcBTVzV5Ay0AAkke4wP6r6wDQqXqBP4Y8IOkYAyLh3jM40jfHQzQt+5JdQl
|
||||
ond3kiscBsFOch/vMfSLMu3lAb0YhPNTvrxhMz7LcVAWYl82swASupdiKR+MgaQr
|
||||
XsugpmDKsHW60VmIM9B7K9Y+rNHwvMWkmISd0KxA8oOy1WJvsVEissMALZDE3c4w
|
||||
2xHmO2lXxgEx3aez28736t4m/KW3g9Zr31a1M0KusmfY//fGkPk4NUrLBOS2xrgp
|
||||
Y/rG1qSBdcVyerM0Ki93qCyHKYu4ene0OwIBAg==
|
||||
-----END DH PARAMETERS-----
|
||||
|
||||
@@ -278,7 +278,6 @@ imap_max_line_length = 2 M
|
||||
#auth_cache_negative_ttl = 0
|
||||
#auth_cache_ttl = 30 s
|
||||
#auth_cache_size = 2 M
|
||||
auth_verbose_passwords = sha1:6
|
||||
service replicator {
|
||||
process_min_avail = 1
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[mysqld]
|
||||
character-set-client-handshake = FALSE
|
||||
character-set-server = utf8mb4
|
||||
collation-server = utf8mb4_general_ci
|
||||
collation-server = utf8mb4_unicode_ci
|
||||
#innodb_file_per_table = TRUE
|
||||
#innodb_file_format = barracuda
|
||||
#innodb_large_prefix = TRUE
|
||||
@@ -20,7 +20,7 @@ thread_cache_size = 8
|
||||
query_cache_type = 0
|
||||
query_cache_size = 0
|
||||
max_heap_table_size = 48M
|
||||
thread_stack = 256K
|
||||
thread_stack = 192K
|
||||
skip-host-cache
|
||||
skip-name-resolve
|
||||
log-warnings = 0
|
||||
|
||||
@@ -41,80 +41,25 @@ http {
|
||||
https https;
|
||||
}
|
||||
|
||||
{% if HTTP_REDIRECT %}
|
||||
# HTTP to HTTPS redirect
|
||||
server {
|
||||
root /web;
|
||||
listen {{ HTTP_PORT }} default_server;
|
||||
listen [::]:{{ HTTP_PORT }} default_server;
|
||||
|
||||
server_name {{ MAILCOW_HOSTNAME }} autodiscover.* autoconfig.* {{ ADDITIONAL_SERVER_NAMES | join(' ') }};
|
||||
|
||||
if ( $request_uri ~* "%0A|%0D" ) { return 403; }
|
||||
location ^~ /.well-known/acme-challenge/ {
|
||||
allow all;
|
||||
default_type "text/plain";
|
||||
}
|
||||
location / {
|
||||
return 301 https://$host$uri$is_args$args;
|
||||
}
|
||||
}
|
||||
{%endif%}
|
||||
|
||||
# Default Server Name
|
||||
# Default
|
||||
server {
|
||||
listen 127.0.0.1:65510; # sogo-auth verify internal
|
||||
|
||||
{% if not HTTP_REDIRECT %}
|
||||
listen {{ HTTP_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%};
|
||||
{%endif%}
|
||||
listen {{ HTTPS_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%} ssl;
|
||||
|
||||
{% if not DISABLE_IPv6 %}
|
||||
{% if not HTTP_REDIRECT %}
|
||||
listen [::]:{{ HTTP_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%};
|
||||
{%endif%}
|
||||
listen [::]:{{ HTTPS_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%} ssl;
|
||||
{%endif%}
|
||||
|
||||
http2 on;
|
||||
|
||||
ssl_certificate /etc/ssl/mail/cert.pem;
|
||||
ssl_certificate_key /etc/ssl/mail/key.pem;
|
||||
|
||||
server_name {{ MAILCOW_HOSTNAME }} autodiscover.* autoconfig.*;
|
||||
server_name {{ MAILCOW_HOSTNAME }} autodiscover.* autoconfig.* {{ ADDITIONAL_SERVER_NAMES }};
|
||||
|
||||
include /etc/nginx/includes/sites-default.conf;
|
||||
}
|
||||
|
||||
# Additional Server Names
|
||||
{% for SERVER_NAME in ADDITIONAL_SERVER_NAMES %}
|
||||
server {
|
||||
listen 127.0.0.1:65510; # sogo-auth verify internal
|
||||
|
||||
{% if not HTTP_REDIRECT %}
|
||||
listen {{ HTTP_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%};
|
||||
{%endif%}
|
||||
listen {{ HTTPS_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%} ssl;
|
||||
|
||||
{% if not DISABLE_IPv6 %}
|
||||
{% if not HTTP_REDIRECT %}
|
||||
listen [::]:{{ HTTP_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%};
|
||||
{%endif%}
|
||||
listen [::]:{{ HTTPS_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%} ssl;
|
||||
{%endif%}
|
||||
|
||||
http2 on;
|
||||
|
||||
ssl_certificate /etc/ssl/mail/cert.pem;
|
||||
ssl_certificate_key /etc/ssl/mail/key.pem;
|
||||
|
||||
server_name {{ SERVER_NAME }};
|
||||
|
||||
include /etc/nginx/includes/sites-default.conf;
|
||||
}
|
||||
{% endfor %}
|
||||
|
||||
# rspamd dynmaps:
|
||||
server {
|
||||
listen 8081;
|
||||
@@ -161,18 +106,12 @@ http {
|
||||
|
||||
{% for cert in valid_cert_dirs %}
|
||||
server {
|
||||
{% if not HTTP_REDIRECT %}
|
||||
listen {{ HTTP_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%};
|
||||
{%endif%}
|
||||
listen {{ HTTPS_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%} ssl;
|
||||
|
||||
{% if not DISABLE_IPv6 %}
|
||||
{% if not HTTP_REDIRECT %}
|
||||
listen [::]:{{ HTTP_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%};
|
||||
{%endif%}
|
||||
listen [::]:{{ HTTPS_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%} ssl;
|
||||
{%endif%}
|
||||
|
||||
http2 on;
|
||||
|
||||
ssl_certificate {{ cert.cert_path }}cert.pem;
|
||||
|
||||
@@ -52,12 +52,10 @@ set_real_ip_from 10.0.0.0/8;
|
||||
set_real_ip_from 172.16.0.0/12;
|
||||
set_real_ip_from 192.168.0.0/16;
|
||||
set_real_ip_from fc00::/7;
|
||||
{% for TRUSTED_PROXY in TRUSTED_PROXIES %}
|
||||
set_real_ip_from {{ TRUSTED_PROXY }};
|
||||
{% endfor %}
|
||||
{% if not NGINX_USE_PROXY_PROTOCOL %}
|
||||
{% if not TRUSTED_NETWORK %}
|
||||
real_ip_header X-Forwarded-For;
|
||||
{% else %}
|
||||
set_real_ip_from {{ TRUSTED_NETWORK }};
|
||||
real_ip_header proxy_protocol;
|
||||
{% endif %}
|
||||
real_ip_recursive on;
|
||||
@@ -139,22 +137,13 @@ location ~ /(?:m|M)ail/(?:c|C)onfig-v1.1.xml {
|
||||
|
||||
{% if not SKIP_RSPAMD %}
|
||||
location /rspamd/ {
|
||||
location /rspamd/auth {
|
||||
# proxy_pass is not inherited
|
||||
proxy_pass http://{{ RSPAMDHOST }}:11334/auth;
|
||||
proxy_intercept_errors on;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Forwarded-For {% if not NGINX_USE_PROXY_PROTOCOL %}$proxy_add_x_forwarded_for{% else %}$proxy_protocol_addr{%endif%};
|
||||
proxy_set_header X-Real-IP {% if not NGINX_USE_PROXY_PROTOCOL %}$remote_addr{% else %}$proxy_protocol_addr{%endif%};
|
||||
proxy_redirect off;
|
||||
error_page 401 /_rspamderror.php;
|
||||
}
|
||||
|
||||
proxy_pass http://{{ RSPAMDHOST }}:11334/;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Forwarded-For {% if not NGINX_USE_PROXY_PROTOCOL %}$proxy_add_x_forwarded_for{% else %}$proxy_protocol_addr{%endif%};
|
||||
proxy_set_header X-Real-IP {% if not NGINX_USE_PROXY_PROTOCOL %}$remote_addr{% else %}$proxy_protocol_addr{%endif%};
|
||||
proxy_redirect off;
|
||||
proxy_intercept_errors on;
|
||||
error_page 401 /_rspamderror.php;
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
|
||||
@@ -162,9 +162,10 @@ transport_maps = pcre:/opt/postfix/conf/custom_transport.pcre,
|
||||
proxy:mysql:/opt/postfix/conf/sql/mysql_relay_ne.cf,
|
||||
proxy:mysql:/opt/postfix/conf/sql/mysql_transport_maps.cf
|
||||
smtp_sasl_auth_soft_bounce = no
|
||||
postscreen_discard_ehlo_keywords = chunking, silent-discard, smtputf8, dsn
|
||||
smtpd_discard_ehlo_keywords = chunking, silent-discard, smtputf8
|
||||
postscreen_discard_ehlo_keywords = silent-discard, dsn, chunking
|
||||
smtpd_discard_ehlo_keywords = chunking, silent-discard
|
||||
compatibility_level = 3.7
|
||||
smtputf8_enable = no
|
||||
# Define protocols for SMTPS and submission service
|
||||
submission_smtpd_tls_mandatory_protocols = >=TLSv1.2
|
||||
smtps_smtpd_tls_mandatory_protocols = >=TLSv1.2
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Whitelist generated by Postwhite v3.4 on Sat Mar 1 00:19:29 UTC 2025
|
||||
# Whitelist generated by Postwhite v3.4 on Wed Jan 1 00:18:52 UTC 2025
|
||||
# https://github.com/stevejenkins/postwhite/
|
||||
# 2000 total rules
|
||||
# 2014 total rules
|
||||
2a00:1450:4000::/36 permit
|
||||
2a01:111:f400::/48 permit
|
||||
2a01:111:f403:8000::/50 permit
|
||||
@@ -8,13 +8,6 @@
|
||||
2a01:111:f403::/49 permit
|
||||
2a01:111:f403:c000::/51 permit
|
||||
2a01:111:f403:f000::/52 permit
|
||||
2a01:b747:3000:200::/56 permit
|
||||
2a01:b747:3001:200::/56 permit
|
||||
2a01:b747:3002:200::/56 permit
|
||||
2a01:b747:3003:200::/56 permit
|
||||
2a01:b747:3004:200::/56 permit
|
||||
2a01:b747:3005:200::/56 permit
|
||||
2a01:b747:3006:200::/56 permit
|
||||
2a02:a60:0:5::/64 permit
|
||||
2c0f:fb50:4000::/36 permit
|
||||
2.207.151.53 permit
|
||||
@@ -26,6 +19,11 @@
|
||||
8.20.114.31 permit
|
||||
8.25.194.0/23 permit
|
||||
8.25.196.0/23 permit
|
||||
8.39.54.0/23 permit
|
||||
8.39.54.250/31 permit
|
||||
8.40.222.0/23 permit
|
||||
8.40.222.250/31 permit
|
||||
10.162.0.0/16 permit
|
||||
12.130.86.238 permit
|
||||
13.110.208.0/21 permit
|
||||
13.110.209.0/24 permit
|
||||
@@ -41,9 +39,7 @@
|
||||
17.57.156.0/24 permit
|
||||
17.58.0.0/16 permit
|
||||
17.142.0.0/15 permit
|
||||
18.97.0.8/30 permit
|
||||
18.97.1.184/29 permit
|
||||
18.97.2.64/26 permit
|
||||
17.143.234.140/30 permit
|
||||
18.156.89.250 permit
|
||||
18.157.243.190 permit
|
||||
18.194.95.56 permit
|
||||
@@ -102,7 +98,6 @@
|
||||
27.123.206.76/30 permit
|
||||
27.123.206.80/28 permit
|
||||
31.25.48.222 permit
|
||||
31.47.251.17 permit
|
||||
34.195.217.107 permit
|
||||
34.212.163.75 permit
|
||||
34.215.104.144 permit
|
||||
@@ -115,7 +110,6 @@
|
||||
35.191.0.0/16 permit
|
||||
35.205.92.9 permit
|
||||
35.242.169.159 permit
|
||||
37.188.97.188 permit
|
||||
37.218.248.47 permit
|
||||
37.218.249.47 permit
|
||||
37.218.251.62 permit
|
||||
@@ -291,9 +285,6 @@
|
||||
64.207.219.13 permit
|
||||
64.207.219.14 permit
|
||||
64.207.219.15 permit
|
||||
64.207.219.24 permit
|
||||
64.207.219.25 permit
|
||||
64.207.219.26 permit
|
||||
64.207.219.71 permit
|
||||
64.207.219.72 permit
|
||||
64.207.219.73 permit
|
||||
@@ -303,9 +294,6 @@
|
||||
64.207.219.77 permit
|
||||
64.207.219.78 permit
|
||||
64.207.219.79 permit
|
||||
64.207.219.88 permit
|
||||
64.207.219.89 permit
|
||||
64.207.219.90 permit
|
||||
64.207.219.135 permit
|
||||
64.207.219.136 permit
|
||||
64.207.219.137 permit
|
||||
@@ -460,7 +448,6 @@
|
||||
69.171.244.0/23 permit
|
||||
70.37.151.128/25 permit
|
||||
70.42.149.35 permit
|
||||
72.3.185.0/24 permit
|
||||
72.14.192.0/18 permit
|
||||
72.21.192.0/19 permit
|
||||
72.21.217.142 permit
|
||||
@@ -521,9 +508,6 @@
|
||||
72.30.239.228/31 permit
|
||||
72.30.239.244/30 permit
|
||||
72.30.239.248/31 permit
|
||||
72.32.154.0/24 permit
|
||||
72.32.217.0/24 permit
|
||||
72.32.243.0/24 permit
|
||||
72.52.72.32/28 permit
|
||||
74.6.128.0/24 permit
|
||||
74.6.129.0/24 permit
|
||||
@@ -639,7 +623,6 @@
|
||||
89.22.108.0/24 permit
|
||||
91.211.240.0/22 permit
|
||||
94.169.2.0/23 permit
|
||||
94.236.119.0/26 permit
|
||||
94.245.112.0/27 permit
|
||||
94.245.112.10/31 permit
|
||||
95.131.104.0/21 permit
|
||||
@@ -1138,7 +1121,6 @@
|
||||
103.28.42.0/24 permit
|
||||
103.151.192.0/23 permit
|
||||
103.168.172.128/27 permit
|
||||
103.237.104.0/22 permit
|
||||
104.43.243.237 permit
|
||||
104.44.112.128/25 permit
|
||||
104.47.0.0/17 permit
|
||||
@@ -1353,8 +1335,6 @@
|
||||
130.61.9.72 permit
|
||||
130.162.39.83 permit
|
||||
130.211.0.0/22 permit
|
||||
130.248.172.0/24 permit
|
||||
130.248.173.0/24 permit
|
||||
131.253.30.0/24 permit
|
||||
131.253.121.0/26 permit
|
||||
132.145.13.209 permit
|
||||
@@ -1478,8 +1458,6 @@
|
||||
159.135.224.0/20 permit
|
||||
159.135.228.10 permit
|
||||
159.183.0.0/16 permit
|
||||
159.183.68.71 permit
|
||||
159.183.79.38 permit
|
||||
160.1.62.192 permit
|
||||
161.38.192.0/20 permit
|
||||
161.38.204.0/22 permit
|
||||
@@ -1498,6 +1476,9 @@
|
||||
163.114.135.16 permit
|
||||
164.152.23.32 permit
|
||||
164.177.132.168/30 permit
|
||||
165.173.128.0/24 permit
|
||||
165.173.180.250/31 permit
|
||||
165.173.182.250/31 permit
|
||||
166.78.68.0/22 permit
|
||||
166.78.68.221 permit
|
||||
166.78.69.169 permit
|
||||
@@ -1526,6 +1507,12 @@
|
||||
168.245.12.252 permit
|
||||
168.245.46.9 permit
|
||||
168.245.127.231 permit
|
||||
169.148.129.0/24 permit
|
||||
169.148.131.0/24 permit
|
||||
169.148.142.10 permit
|
||||
169.148.144.0/25 permit
|
||||
169.148.144.10 permit
|
||||
169.148.146.0/23 permit
|
||||
170.10.128.0/24 permit
|
||||
170.10.129.0/24 permit
|
||||
170.10.132.56/29 permit
|
||||
@@ -1566,7 +1553,6 @@
|
||||
183.240.219.64/29 permit
|
||||
185.4.120.0/22 permit
|
||||
185.12.80.0/22 permit
|
||||
185.28.196.0/22 permit
|
||||
185.58.84.93 permit
|
||||
185.80.93.204 permit
|
||||
185.80.93.227 permit
|
||||
@@ -1632,7 +1618,6 @@
|
||||
192.18.139.154 permit
|
||||
192.18.145.36 permit
|
||||
192.18.152.58 permit
|
||||
192.28.128.0/18 permit
|
||||
192.29.103.128/25 permit
|
||||
192.30.252.0/22 permit
|
||||
192.161.144.0/20 permit
|
||||
@@ -1673,7 +1658,6 @@
|
||||
198.244.60.0/22 permit
|
||||
198.245.80.0/20 permit
|
||||
198.245.81.0/24 permit
|
||||
199.15.212.0/22 permit
|
||||
199.15.213.187 permit
|
||||
199.15.226.37 permit
|
||||
199.16.156.0/22 permit
|
||||
@@ -1988,6 +1972,9 @@
|
||||
2603:1030:20e:3::23c permit
|
||||
2603:1030:b:3::152 permit
|
||||
2603:1030:c02:8::14 permit
|
||||
2607:13c0:0001:0000:0000:0000:0000:7000/116 permit
|
||||
2607:13c0:0002:0000:0000:0000:0000:1000/116 permit
|
||||
2607:13c0:0004:0000:0000:0000:0000:0000/116 permit
|
||||
2607:f8b0:4000::/36 permit
|
||||
2620:109:c003:104::/64 permit
|
||||
2620:109:c003:104::215 permit
|
||||
|
||||
@@ -2,11 +2,6 @@
|
||||
|
||||
cat <<EOF > /redis.conf
|
||||
requirepass $REDISPASS
|
||||
user quota_notify on nopass ~QW_* -@all +get +hget +ping
|
||||
EOF
|
||||
|
||||
if [ -n "$REDISMASTERPASS" ]; then
|
||||
echo "masterauth $REDISMASTERPASS" >> /redis.conf
|
||||
fi
|
||||
|
||||
exec redis-server /redis.conf
|
||||
|
||||
@@ -3,7 +3,6 @@ dns {
|
||||
}
|
||||
map_watch_interval = 30s;
|
||||
task_timeout = 30s;
|
||||
enable_mime_utf = true;
|
||||
disable_monitoring = true;
|
||||
# In case a task times out (like DNS lookup), soft reject the message
|
||||
# instead of silently accepting the message without further processing.
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.2 KiB |
@@ -1,44 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
|
||||
<!ENTITY st0 "fill:#50BD37;">
|
||||
]>
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="640px" height="350px" viewBox="78.712 58.488 640 350" style="enable-background:new 78.712 58.488 640 350;"
|
||||
xml:space="preserve">
|
||||
<path style="&st0;" d="M648.541,145.679c-9.947,0-17.009-7.278-17.009-17.048c0-9.777,7.062-17.057,17.009-17.057
|
||||
c10.024,0,17.086,7.279,17.086,17.057C665.627,138.401,658.565,145.679,648.541,145.679z M648.511,94.893
|
||||
c-19.693,0-33.679,14.4-33.679,33.738c0,19.33,13.985,33.729,33.679,33.729c19.822,0,33.808-14.4,33.808-33.729
|
||||
C682.318,109.293,668.333,94.893,648.511,94.893z M648.482,179.843c-29.889,0-51.123-21.868-51.123-51.212
|
||||
c0-29.353,21.234-51.209,51.123-51.209c30.082,0,51.307,21.856,51.307,51.209C699.789,157.975,678.564,179.843,648.482,179.843z
|
||||
M648.442,58.488c-40.929,0-69.995,29.946-69.995,70.143c0,40.189,29.066,70.125,69.995,70.125c41.194,0,70.27-29.937,70.27-70.125
|
||||
C718.712,88.434,689.637,58.488,648.442,58.488z M158.166,183.902l-21.018-5.008c-19.131-4.396-28.849-9.413-28.849-23.21
|
||||
c0-15.684,15.99-21.965,30.419-21.965c14.667,0,25.382,7.329,31.693,18.737c0.02,0.048,0.051,0.097,0.09,0.157
|
||||
c0.127,0.247,0.276,0.484,0.403,0.731l0.03-0.02c1.985,3.002,5.323,5.008,8.919,5.008c6.122,0,10.558-4.425,10.558-10.547
|
||||
c0-2.341-0.504-4.82-1.601-6.688c-10.764-18.302-28.513-26.192-48.838-26.192c-27.594,0-54.262,13.797-54.262,44.218
|
||||
c0,27.921,27.605,36.079,37.64,38.578l20.069,4.71c15.368,3.763,27.912,8.791,27.912,23.517c0,16.938-17.561,23.943-34.499,23.943
|
||||
c-17.245,0-30.015-9.37-38.814-22.37h-0.01c-1.956-3-4.988-4.328-8.702-4.328c-5.984,0-10.805,5.185-10.587,11.162
|
||||
c0.098,2.438,0.909,4.637,2.153,6.405c13.787,20.633,33.728,28.41,55.96,28.41c28.543,0,57.085-13.143,57.085-45.132
|
||||
C193.918,203.325,178.551,188.613,158.166,183.902z M298.479,250.312c-33.866,0-55.199-25.403-55.199-58.331
|
||||
c0-32.939,21.333-58.343,55.199-58.343c34.192,0,55.516,25.403,55.516,58.343C353.996,224.91,332.672,250.312,298.479,250.312z
|
||||
M298.479,114.823c-45.471,0-77.777,32.93-77.777,77.158c0,44.217,32.306,77.146,77.777,77.146
|
||||
c45.786,0,78.093-32.929,78.093-77.146C376.572,147.753,344.266,114.823,298.479,114.823z M518.715,234.312
|
||||
c-0.771,0.74-1.549,1.472-2.399,2.175c-1.106,1.014-2.391,2.112-3.854,3.208c-8.829,6.391-19.979,10.094-33.017,10.094
|
||||
c-33.876,0-55.198-25.402-55.198-58.332c0-32.939,21.322-58.342,55.198-58.342c34.183,0,55.506,25.403,55.506,58.342
|
||||
C534.951,208.653,529.135,223.774,518.715,234.312z M468.097,317.938c2.528,0,5.146-0.168,7.863-0.504
|
||||
c5.018-0.631,9.588-0.909,13.729-0.909c19.24,0.109,29.036,5.7,34.943,12.158c5.895,6.499,8.168,15.311,8.158,22.796
|
||||
c0.01,3.586-0.555,6.795-1.177,8.721c-2.944,8.93-8.888,15.002-17.996,19.576c-9.035,4.484-21.095,6.777-33.707,6.757
|
||||
c-4.514,0-9.105-0.288-13.639-0.831c-8.573-0.987-19.911-4.671-28.13-11.093c-4.138-3.199-6.458-6.991-8.858-11.485
|
||||
c-2.379-4.514-2.783-9.748-2.783-16.442v-0.742c0-12.346,4.84-20.544,11.051-26.5c3.07-2.904,5.69-5.064,7.99-6.438
|
||||
c0.366-0.218,0.438-0.416,0.755-0.593C452.39,316.014,459.684,317.968,468.097,317.938z M479.445,114.301
|
||||
c-45.471,0-77.786,32.929-77.786,77.157c0,29.887,14.765,54.598,38.378,67.489c-0.314,0.314-0.621,0.641-0.916,0.966
|
||||
c-6.104,6.687-9.226,15.25-9.236,23.913c-0.008,3.821,0.624,7.741,1.977,11.494c-3.062,1.956-6.717,4.634-10.46,8.147
|
||||
c-9.026,8.408-18.734,22.541-19.021,42.097c-0.01,0.454-0.01,0.829-0.01,1.118c-0.01,10.071,2.379,19.157,6.459,26.774
|
||||
c6.133,11.466,15.683,19.445,25.539,24.77c9.917,5.334,20.257,8.166,29.273,9.274c5.373,0.643,10.826,0.988,16.268,0.988
|
||||
c15.151-0.02,30.261-2.578,43.409-9.019c13.085-6.34,24.333-17.253,29.192-32.562c1.443-4.553,2.212-9.719,2.231-15.428
|
||||
c-0.02-11.595-3.349-25.759-13.767-37.452c-10.421-11.734-27.654-19.566-51.288-19.459c-5.138,0-10.606,0.356-16.426,1.078
|
||||
c-1.877,0.227-3.596,0.334-5.166,0.334c-7.239-0.048-10.872-2.053-13.036-4.098c-2.133-2.084-3.2-4.839-3.229-8.058
|
||||
c-0.01-3.28,1.284-6.727,3.467-9.078c2.231-2.332,5.008-3.91,9.846-3.97c0.436,0,0.9,0.01,1.374,0.05
|
||||
c3.101,0.216,6.112,0.325,9.037,0.325c24.188,0.047,42.38-7.448,54.756-17.759c12.415-10.312,18.971-22.854,22.071-32.76l-0.04-0.01
|
||||
c3.37-8.899,5.197-18.715,5.197-29.166C557.539,147.229,525.234,114.301,479.445,114.301z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 4.4 KiB |
@@ -1,16 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
|
||||
<!ENTITY st0 "fill:#50BD37;">
|
||||
]>
|
||||
<svg version="1.1" id="SOGo" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="140.263px" height="140.269px" viewBox="499.737 0 140.263 140.269"
|
||||
style="enable-background:new 499.737 0 140.263 140.269;" xml:space="preserve">
|
||||
<path style="&st0;" d="M569.697,87.024c-9.928,0-16.975-7.264-16.975-17.017c0-9.757,7.047-17.022,16.975-17.022
|
||||
c10.006,0,17.054,7.265,17.054,17.022C586.751,79.76,579.703,87.024,569.697,87.024z M569.667,36.335
|
||||
c-19.657,0-33.614,14.372-33.614,33.673c0,19.294,13.955,33.667,33.614,33.667c19.787,0,33.745-14.372,33.745-33.667
|
||||
C603.411,50.707,589.454,36.335,569.667,36.335z M569.639,121.123c-29.833,0-51.025-21.825-51.025-51.115
|
||||
c0-29.296,21.192-51.111,51.025-51.111c30.025,0,51.213,21.815,51.213,51.111C620.852,99.298,599.664,121.123,569.639,121.123z
|
||||
M569.602,0c-40.854,0-69.864,29.889-69.864,70.007c0,40.112,29.01,69.993,69.864,69.993c41.116,0,70.136-29.88,70.136-69.993
|
||||
C639.737,29.889,610.719,0,569.602,0z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.3 KiB |
@@ -409,7 +409,7 @@ paths:
|
||||
description: a list of domains for which a dkim key should be generated
|
||||
type: string
|
||||
key_size:
|
||||
description: the key size (1024, 2048, 3072 or 4096)
|
||||
description: the key size (1024 or 2048)
|
||||
type: number
|
||||
type: object
|
||||
summary: Generate DKIM Key
|
||||
|
||||
@@ -166,9 +166,6 @@ if (isset($_SESSION['mailcow_cc_role'])) {
|
||||
if (substr($result['recipient_map_old'], 0, 1) == '@') {
|
||||
$result['recipient_map_old'] = substr($result['recipient_map_old'], 1);
|
||||
}
|
||||
if (substr($result['recipient_map_new'], 0, 1) == '@') {
|
||||
$result['recipient_map_new'] = substr($result['recipient_map_new'], 1);
|
||||
}
|
||||
$template = 'edit/recipient_map.twig';
|
||||
$template_data = ['map' => $map];
|
||||
}
|
||||
|
||||
@@ -270,9 +270,6 @@ function recipient_map($_action, $_data = null, $attr = null) {
|
||||
$old_dest = substr($old_dest, 1);
|
||||
}
|
||||
$new_dest = strtolower(trim($_data['recipient_map_new']));
|
||||
if (substr($new_dest, 0, 1) == '@') {
|
||||
$new_dest = substr($new_dest, 1);
|
||||
}
|
||||
$active = intval($_data['active']);
|
||||
if (is_valid_domain_name($old_dest)) {
|
||||
$old_dest_sane = '@' . idn_to_ascii($old_dest, 0, INTL_IDNA_VARIANT_UTS46);
|
||||
@@ -288,13 +285,7 @@ function recipient_map($_action, $_data = null, $attr = null) {
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if (is_valid_domain_name($new_dest)) {
|
||||
$new_dest_sane = '@' . idn_to_ascii($new_dest, 0, INTL_IDNA_VARIANT_UTS46);
|
||||
}
|
||||
elseif (filter_var($new_dest, FILTER_VALIDATE_EMAIL)) {
|
||||
$new_dest_sane = $new_dest;
|
||||
}
|
||||
else {
|
||||
if (!filter_var($new_dest, FILTER_VALIDATE_EMAIL)) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
|
||||
@@ -317,7 +308,7 @@ function recipient_map($_action, $_data = null, $attr = null) {
|
||||
(:old_dest, :new_dest, :active)");
|
||||
$stmt->execute(array(
|
||||
':old_dest' => $old_dest_sane,
|
||||
':new_dest' => $new_dest_sane,
|
||||
':new_dest' => $new_dest,
|
||||
':active' => $active
|
||||
));
|
||||
$_SESSION['return'][] = array(
|
||||
@@ -334,9 +325,6 @@ function recipient_map($_action, $_data = null, $attr = null) {
|
||||
$active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
|
||||
$new_dest = (!empty($_data['recipient_map_new'])) ? $_data['recipient_map_new'] : $is_now['recipient_map_new'];
|
||||
$old_dest = (!empty($_data['recipient_map_old'])) ? $_data['recipient_map_old'] : $is_now['recipient_map_old'];
|
||||
if (substr($new_dest, 0, 1) == '@') {
|
||||
$new_dest = substr($new_dest, 1);
|
||||
}
|
||||
if (substr($old_dest, 0, 1) == '@') {
|
||||
$old_dest = substr($old_dest, 1);
|
||||
}
|
||||
@@ -363,13 +351,7 @@ function recipient_map($_action, $_data = null, $attr = null) {
|
||||
);
|
||||
continue;
|
||||
}
|
||||
if (is_valid_domain_name($new_dest)) {
|
||||
$new_dest_sane = '@' . idn_to_ascii($new_dest, 0, INTL_IDNA_VARIANT_UTS46);
|
||||
}
|
||||
elseif (filter_var($new_dest, FILTER_VALIDATE_EMAIL)) {
|
||||
$new_dest_sane = $new_dest;
|
||||
}
|
||||
else {
|
||||
if (!filter_var($new_dest, FILTER_VALIDATE_EMAIL)) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
|
||||
@@ -396,7 +378,7 @@ function recipient_map($_action, $_data = null, $attr = null) {
|
||||
WHERE `id`= :id");
|
||||
$stmt->execute(array(
|
||||
':old_dest' => $old_dest_sane,
|
||||
':new_dest' => $new_dest_sane,
|
||||
':new_dest' => $new_dest,
|
||||
':active' => $active,
|
||||
':id' => $id
|
||||
));
|
||||
|
||||
@@ -240,11 +240,8 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||
if (strlen($dkimdata['pubkey']) < 391) {
|
||||
$dkimdata['length'] = "1024";
|
||||
}
|
||||
elseif (strlen($dkimdata['pubkey']) < 564) {
|
||||
$dkimdata['length'] = "2048";
|
||||
}
|
||||
elseif (strlen($dkimdata['pubkey']) < 736) {
|
||||
$dkimdata['length'] = "3072";
|
||||
$dkimdata['length'] = "2048";
|
||||
}
|
||||
elseif (strlen($dkimdata['pubkey']) < 1416) {
|
||||
$dkimdata['length'] = "4096";
|
||||
|
||||
@@ -2275,25 +2275,9 @@ function cors($action, $data = null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
function getBaseURL($protocol = null) {
|
||||
// Get current server name
|
||||
$host = strtolower($_SERVER['SERVER_NAME']);
|
||||
|
||||
// craft allowed server name list
|
||||
$mailcow_hostname = strtolower(getenv("MAILCOW_HOSTNAME"));
|
||||
$additional_server_names = strtolower(getenv("ADDITIONAL_SERVER_NAMES")) ?: "";
|
||||
$additional_server_names = preg_replace('/\s+/', '', $additional_server_names);
|
||||
$allowed_server_names = $additional_server_names !== "" ? explode(',', $additional_server_names) : array();
|
||||
array_push($allowed_server_names, $mailcow_hostname);
|
||||
|
||||
// Fallback to MAILCOW HOSTNAME if current server name is not in allowed list
|
||||
if (!in_array($host, $allowed_server_names)) {
|
||||
$host = $mailcow_hostname;
|
||||
}
|
||||
|
||||
if (!isset($protocol)) {
|
||||
$protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http';
|
||||
}
|
||||
function getBaseURL() {
|
||||
$protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http';
|
||||
$host = $_SERVER['HTTP_HOST'];
|
||||
$base_url = $protocol . '://' . $host;
|
||||
|
||||
return $base_url;
|
||||
|
||||
@@ -869,7 +869,7 @@
|
||||
"recipient_map": "Mapa příjemce",
|
||||
"recipient_map_info": "Mapy příjemců slouží k nahrazení cílové adresy zprávy před doručením.",
|
||||
"recipient_map_new": "Nový přijemce",
|
||||
"recipient_map_new_info": "Cílová adresa mapy příjemce musí být emailová adresa nebo název domény.",
|
||||
"recipient_map_new_info": "Cílová adresa mapy příjemce musí být platná emailová adresa.",
|
||||
"recipient_map_old": "Původní příjemce",
|
||||
"recipient_map_old_info": "Původní příjemce musí být platná emailová adresa nebo název domény.",
|
||||
"recipient_maps": "Mapy příjemců",
|
||||
@@ -1307,4 +1307,4 @@
|
||||
"session_token": "Token formuláře není platný: Token mismatch",
|
||||
"session_ua": "Token formuláře není platný: User-Agent validation error"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -706,7 +706,7 @@
|
||||
"recipient_map": "Modtagerkort",
|
||||
"recipient_map_info": "Modtagerkort bruges til at erstatte destinationsadressen i en meddelelse, før den leveres.",
|
||||
"recipient_map_new": "Ny modtager",
|
||||
"recipient_map_new_info": "Modtagerkortdestination skal være gyldige e-mail-adresser eller et domænenavn.",
|
||||
"recipient_map_new_info": "Modtagerkortdestination skal være en gyldig e-mail-adresse.",
|
||||
"recipient_map_old": "Original modtager",
|
||||
"recipient_map_old_info": "En modtager kortlægger den originale destination, skal være gyldige e-mail-adresser eller et domænenavn.",
|
||||
"recipient_maps": "Modtagerkort",
|
||||
@@ -1089,4 +1089,4 @@
|
||||
"first": "Først"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -881,7 +881,7 @@
|
||||
"recipient_map": "Empfängerumschreibung",
|
||||
"recipient_map_info": "Empfängerumschreibung ersetzen den Empfänger einer E-Mail vor dem Versand.",
|
||||
"recipient_map_new": "Neuer Empfänger",
|
||||
"recipient_map_new_info": "Der neue Empfänger muss eine E-Mail-Adresse oder ein Domainname sein.",
|
||||
"recipient_map_new_info": "Der neue Empfänger muss eine E-Mail-Adresse sein.",
|
||||
"recipient_map_old": "Original-Empfänger",
|
||||
"recipient_map_old_info": "Der originale Empfänger muss eine E-Mail-Adresse oder ein Domainname sein.",
|
||||
"recipient_maps": "Empfängerumschreibungen",
|
||||
@@ -1336,4 +1336,4 @@
|
||||
"hour": "Nachrichten / Stunde",
|
||||
"day": "Nachrichten / Tag"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -887,9 +887,9 @@
|
||||
"recipient_map": "Recipient map",
|
||||
"recipient_map_info": "Recipient maps are used to replace the destination address on a message before it is delivered.",
|
||||
"recipient_map_new": "New recipient",
|
||||
"recipient_map_new_info": "Recipient map destination must be a valid email addresses or a domain name.",
|
||||
"recipient_map_new_info": "Recipient map destination must be a valid email address.",
|
||||
"recipient_map_old": "Original recipient",
|
||||
"recipient_map_old_info": "A recipient maps original destination must be a valid email addresses or a domain name.",
|
||||
"recipient_map_old_info": "A recipient maps original destination must be valid email addresses or a domain name.",
|
||||
"recipient_maps": "Recipient maps",
|
||||
"relay_all": "Relay all recipients",
|
||||
"relay_unknown": "Relay unknown mailboxes",
|
||||
@@ -1336,4 +1336,4 @@
|
||||
"session_token": "Form token invalid: Token mismatch",
|
||||
"session_ua": "Form token invalid: User-Agent validation error"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,9 +24,7 @@
|
||||
"protocol_access": "Cambiar protocolo de acceso",
|
||||
"quarantine_category": "Cambiar categoría de las notificaciones de cuarentena",
|
||||
"domain_relayhost": "Cambiar relayhost por un dominio",
|
||||
"extend_sender_acl": "Permitir extender la ACL del remitente por direcciones externas",
|
||||
"pw_reset": "Permitir el reset de la contraseña del usario mailcow",
|
||||
"sogo_access": "Permitir la gestión del acceso a SOGo"
|
||||
"extend_sender_acl": "Permitir extender la ACL del remitente por direcciones externas"
|
||||
},
|
||||
"add": {
|
||||
"activate_filter_warn": "Todos los demás filtros se desactivarán cuando este filtro se active.",
|
||||
@@ -97,10 +95,7 @@
|
||||
"app_password": "Añadir contraseña para la app",
|
||||
"public_comment": "Comentarios públicos",
|
||||
"disable_login": "Desactivar login (el correo entrante seguirá activo)",
|
||||
"comment_info": "Los comentarios privados no son visibles al usuario, mientras que los comentarios públicos aparecerán sobre la información general del usuario",
|
||||
"dry": "Simular la sincronización",
|
||||
"private_comment": "Comentario privado",
|
||||
"app_passwd_protocols": "Protocolos autorizados para la contraseña de la aplicación"
|
||||
"comment_info": "Los comentarios privados no son visibles al usuario, mientras que los comentarios públicos aparecerán sobre la información general del usuario"
|
||||
},
|
||||
"admin": {
|
||||
"access": "Acceso",
|
||||
@@ -544,7 +539,7 @@
|
||||
"recipient_map": "Regla de destinatario",
|
||||
"recipient_map_info": "Las reglas de destinatarios se utilizan para reemplazar la dirección de destino en un mensaje antes de que se entregue.",
|
||||
"recipient_map_new": "Destinatario nuevo",
|
||||
"recipient_map_new_info": "El destino de la regla debe ser una dirección de correo electrónico válida o un nombre de dominio.",
|
||||
"recipient_map_new_info": "El destino de la regla debe ser una dirección de correo válida.",
|
||||
"recipient_map_old": "Destinatario original",
|
||||
"recipient_map_old_info": "El destino original de una regla de destinatario debe ser una dirección de correo electrónico válida o un nombre de dominio.",
|
||||
"recipient_maps": "Reglas de destinatario",
|
||||
@@ -782,4 +777,4 @@
|
||||
"fuzzy_learn_error": "Error aprendiendo hash: %s",
|
||||
"ip_invalid": "IP inválida omitida: %s"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -607,7 +607,7 @@
|
||||
"recipient_map": "Vastaanottajien yhdistämis määritykset",
|
||||
"recipient_map_info": "Vastaanottajan karttoja käytetään korvaamaan viestin kohde osoite ennen sen toimittamista.",
|
||||
"recipient_map_new": "Uusi vastaanottaja",
|
||||
"recipient_map_new_info": "Vastaanottajan yhdistämis kartan kohteen on oltava kelvollinen sähköposti osoite tai verkkotunnus alueen nimi.",
|
||||
"recipient_map_new_info": "Vastaanottajan yhdistämis kartan kohteen on oltava kelvollinen sähköposti osoite.",
|
||||
"recipient_map_old": "Alkuperäinen vastaanottaja",
|
||||
"recipient_map_old_info": "Vastaanottajan yhdistämis määritysten alkuperäisen kohteen on oltava kelvollinen sähköposti osoite tai verkkotunnus alueen nimi.",
|
||||
"recipient_maps": "Vastaanottajien yhdistämis määritykset",
|
||||
@@ -906,4 +906,4 @@
|
||||
"last": "Edellinen"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -834,7 +834,7 @@
|
||||
"recipient_map": "Carte du destinataire",
|
||||
"recipient_map_info": "Les cartes des destinataires sont utilisées pour remplacer l’adresse de destination d’un message avant sa livraison.",
|
||||
"recipient_map_new": "Nouveau destinataire",
|
||||
"recipient_map_new_info": "La destination de la carte du destinataire doit être une adresse de courriel valide ou un nom de domaine.",
|
||||
"recipient_map_new_info": "La destination de la carte du destinataire doit être une adresse de courriel valide.",
|
||||
"recipient_map_old": "Destinataire original",
|
||||
"recipient_map_old_info": "Une carte de destination originale doit être une adresse de courriel valide ou un nom de domaine.",
|
||||
"recipient_maps": "Cartes des bénéficiaires",
|
||||
@@ -1335,4 +1335,4 @@
|
||||
"hour": "msgs / heure",
|
||||
"day": "msgs / jour"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -822,9 +822,9 @@
|
||||
"recipient_map": "Recipient map",
|
||||
"recipient_map_info": "Recipient maps are used to replace the destination address on a message before it is delivered.",
|
||||
"recipient_map_new": "New recipient",
|
||||
"recipient_map_new_info": "Recipient map destination must be a valid email addresses or a domain name.",
|
||||
"recipient_map_new_info": "Recipient map destination must be a valid email address.",
|
||||
"recipient_map_old": "Original recipient",
|
||||
"recipient_map_old_info": "A recipient maps original destination must be a valid email addresses or a domain name.",
|
||||
"recipient_map_old_info": "A recipient maps original destination must be valid email addresses or a domain name.",
|
||||
"recipient_maps": "Recipient maps",
|
||||
"relay_all": "Trasmettere a tutti i destinatari",
|
||||
"remove": "Rimuovi",
|
||||
@@ -1306,4 +1306,4 @@
|
||||
},
|
||||
"decimal": "."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -887,7 +887,7 @@
|
||||
"recipient_map": "受信者マップ",
|
||||
"recipient_map_info": "受信者マップは、メッセージが配信される前に宛先アドレスを置き換えるために使用されます。",
|
||||
"recipient_map_new": "新しい受信者",
|
||||
"recipient_map_new_info": "受信者マップの宛先は有効なメールアドレスまたはドメイン名である必要があります。",
|
||||
"recipient_map_new_info": "受信者マップの宛先は有効なメールアドレスである必要があります。",
|
||||
"recipient_map_old": "元の受信者",
|
||||
"recipient_map_old_info": "受信者マップの元の宛先は有効なメールアドレスまたはドメイン名である必要があります。",
|
||||
"recipient_maps": "受信者マップ",
|
||||
|
||||
@@ -25,11 +25,7 @@
|
||||
"syncjobs": "동기화 작업",
|
||||
"tls_policy": "TLS 정책",
|
||||
"unlimited_quota": "메일에 무제한 할당",
|
||||
"domain_desc": "도메인 설명 변경",
|
||||
"pw_reset": "mailcow 사용자 비밀번호 재설정 허용",
|
||||
"domain_relayhost": "도메인의 릴레이 호스트 변경",
|
||||
"mailbox_relayhost": "메일함의 릴레이 호스트 변경",
|
||||
"quarantine_category": "검역소 알림 카테고리 변경"
|
||||
"domain_desc": "도메인 설명 변경"
|
||||
},
|
||||
"add": {
|
||||
"activate_filter_warn": "활성화가 체크되어 있으면 모든 다른 필터들은 비활성화됩니다.",
|
||||
@@ -105,9 +101,7 @@
|
||||
"timeout2": "로컬 호스트 연결 시간 초과",
|
||||
"username": "사용자명",
|
||||
"validate": "확인하기",
|
||||
"validation_success": "성공적으로 확인됨",
|
||||
"tags": "태그",
|
||||
"app_passwd_protocols": "앱 비밀번호에 대해 허용되는 프로토콜"
|
||||
"validation_success": "성공적으로 확인됨"
|
||||
},
|
||||
"admin": {
|
||||
"access": "접근",
|
||||
@@ -201,7 +195,7 @@
|
||||
"link": "Link",
|
||||
"loading": "잠시만 기다려주세요...",
|
||||
"logo_info": "이미지 크기는 상단 탐색 막대의 경우 40px, 시작 페이지의 경우 최대 너비 250px로 조정됩니다. 확장 가능한 그래픽을 권장합니다.",
|
||||
"lookup_mx": "목적지가 MX 이름과 일치하는 정규 표현식입니다. (<code>.*\\.google\\.com</code>를 사용하여 이 홉을 통해 google.com으로 끝나는 모든 메일을 대상으로 하는 MX로 라우팅합니다.)",
|
||||
"lookup_mx": "MX와 목적지 일치 (.outlook.com이 홉을 통해서 MX *.outlook.com을 대상으로 하는 모든 메일을 라우트한다.)",
|
||||
"main_name": "\"mailcow UI\" 이름",
|
||||
"merged_vars_hint": "회색으로 표시된 행은 <code>vars.(local.)php</code> 에서 병합되었고 이는 수정할 수 없습니다.",
|
||||
"message": "메세지",
|
||||
@@ -307,53 +301,7 @@
|
||||
"username": "사용자 이름",
|
||||
"validate_license_now": "라이선스 서버와 GUID 확인",
|
||||
"verify": "확인",
|
||||
"yes": "✓",
|
||||
"domain_admin": "도메인 관리자",
|
||||
"f2b_filter": "정규식 필터",
|
||||
"f2b_manage_external": "외부에서 Fail2Ban 관리",
|
||||
"f2b_max_ban_time": "최대 차단 시간(초)",
|
||||
"f2b_regex_info": "고려되는 로그: SOGo, Postfix, Dovecot, PHP-FPM.",
|
||||
"html": "HTML",
|
||||
"oauth2_apps": "OAuth2 앱",
|
||||
"oauth2_add_client": "OAuth2 클라이언트 추가",
|
||||
"optional": "선택 사항",
|
||||
"options": "옵션",
|
||||
"password_length": "비밀번호 길이",
|
||||
"password_policy_chars": "하나 이상의 알파벳 문자를 포함해야 합니다.",
|
||||
"password_policy_length": "최소 암호 길이가 %d입니다.",
|
||||
"password_policy_numbers": "숫자 하나 이상을 포함해야 합니다.",
|
||||
"password_policy_special_chars": "특수 문자를 포함해야 합니다.",
|
||||
"password_reset_info": "복구 이메일이 제공되지 않으면 이 기능을 사용할 수 없습니다.",
|
||||
"password_reset_settings": "비밀번호 복구 설정",
|
||||
"password_reset_tmpl_html": "HTML 템플릿",
|
||||
"password_reset_tmpl_text": "Text 템플릿",
|
||||
"password_settings": "비밀번호 설정",
|
||||
"queue_unban": "차단 해제",
|
||||
"restore_template": "기본 템플릿을 복원하려면 비워둡니다.",
|
||||
"service": "서비스",
|
||||
"success": "성공",
|
||||
"dkim_overwrite_key": "기존 DKIM 키 덮어쓰기",
|
||||
"f2b_ban_time_increment": "차단 시간은 차단될 때마다 증가합니다.",
|
||||
"password_policy": "비밀번호 정책",
|
||||
"quarantine_max_score": "메일의 스팸 점수가 이 값보다 높으면 알림을 삭제합니다:<br><small>기본값: 9999.0</small>",
|
||||
"f2b_manage_external_info": "Fail2ban은 차단 목록을 유지하지만 트래픽을 차단하는 규칙을 능동적으로 설정하지는 않습니다. 트래픽을 외부에서 차단하려면 아래 생성된 차단 목록을 사용하세요.",
|
||||
"password_policy_lowerupper": "소문자 및 대문자를 포함해야 합니다.",
|
||||
"transport_test_rcpt_info": "• null@hosted.mailcow.de 을 사용하여 해외 목적지로 릴레이를 테스트하세요.",
|
||||
"ip_check_disabled": "IP 확인이 비활성화됩니다. 아래에서 활성화할 수 있습니다<br> <strong>시스템 > 구성 > 옵션 > 사용자 정의</strong>",
|
||||
"logo_normal_label": "일반",
|
||||
"logo_dark_label": "다크 모드의 경우 반전",
|
||||
"convert_html_to_text": "HTML을 일반 텍스트로 변환",
|
||||
"copy_to_clipboard": "클립보드에 텍스트가 복사되었습니다!",
|
||||
"cors_settings": "CORS 설정",
|
||||
"rsettings_preset_4": "도메인에 대해 Rspamd 비활성화",
|
||||
"ip_check": "IP 확인",
|
||||
"admins": "관리자",
|
||||
"admins_ldap": "LDAP 관리자",
|
||||
"api_read_only": "읽기 전용 액세스",
|
||||
"api_read_write": "읽기-쓰기 액세스",
|
||||
"is_mx_based": "MX 기반",
|
||||
"login_time": "로그인 시간",
|
||||
"ip_check_opt_in": "외부 IP 주소 확인을 위해 타사 서비스 <strong>ipv4.mailcow.email</strong> 및 <strong>ipv6.mailcow.email</strong>을 사용하도록 설정합니다."
|
||||
"yes": "✓"
|
||||
},
|
||||
"danger": {
|
||||
"access_denied": "접근이 거부되거나 잘못된 데이터 양식",
|
||||
@@ -467,30 +415,7 @@
|
||||
"username_invalid": "%s는 사용지 이름으로 사용할 수 없습니다.",
|
||||
"validity_missing": "유효 기간을 지정해주세요.",
|
||||
"value_missing": "모든 값을 입력해주세요.",
|
||||
"yotp_verification_failed": "Yubico OTP 검증 실패: %s",
|
||||
"dkim_domain_or_sel_exists": "“%s\"에 대한 DKIM 키가 존재하며 덮어쓰지 않습니다.",
|
||||
"img_size_exceeded": "이미지가 최대 파일 크기를 초과합니다.",
|
||||
"invalid_reset_token": "잘못된 리셋 토큰",
|
||||
"nginx_reload_failed": "Nginx 리로드 실패: %s",
|
||||
"password_reset_na": "현재 비밀번호 복구를 사용할 수 없습니다. 관리자에게 문의하세요.",
|
||||
"reset_f2b_regex": "정규식 필터를 제때 재설정하지 못했습니다. 다시 시도하거나 몇 초 더 기다렸다가 웹사이트를 다시 로드하세요.",
|
||||
"template_exists": "템플릿 %s이(가) 이미 존재합니다.",
|
||||
"template_id_invalid": "템플릿 ID %s가 잘못되었습니다.",
|
||||
"template_name_invalid": "템플릿 이름이 잘못되었습니다.",
|
||||
"tfa_token_invalid": "TFA 토큰이 유효하지 않습니다.",
|
||||
"to_invalid": "수신자가 비어 있지 않아야 합니다.",
|
||||
"webauthn_authenticator_failed": "선택한 인증기를 찾을 수 없습니다.",
|
||||
"webauthn_username_failed": "선택한 인증기가 다른 계정에 속해 있습니다.",
|
||||
"demo_mode_enabled": "데모 모드가 활성화됨",
|
||||
"recovery_email_failed": "복구 이메일을 보낼 수 없습니다. 관리자에게 문의하세요.",
|
||||
"password_reset_invalid_user": "사서함을 찾을 수 없거나 복구 이메일이 설정되어 있지 않습니다.",
|
||||
"webauthn_publickey_failed": "선택한 인증기에 대한 공개 키가 저장되지 않았습니다.",
|
||||
"fido2_verification_failed": "FIDO2 인증 실패: %s",
|
||||
"extended_sender_acl_denied": "외부 발신자 주소를 설정하는 ACL 누락",
|
||||
"img_dimensions_exceeded": "이미지가 최대 이미지 크기를 초과합니다.",
|
||||
"reset_token_limit_exceeded": "토큰 재설정 한도를 초과했습니다. 나중에 다시 시도해 주세요.",
|
||||
"cors_invalid_method": "잘못된 허용 메서드를 지정했습니다.",
|
||||
"cors_invalid_origin": "잘못된 허용 원본을 지정했습니다."
|
||||
"yotp_verification_failed": "Yubico OTP 검증 실패: %s"
|
||||
},
|
||||
"debug": {
|
||||
"chart_this_server": "Chart (this server)",
|
||||
@@ -509,24 +434,7 @@
|
||||
"uptime": "Uptime",
|
||||
"started_on": "Started on",
|
||||
"static_logs": "Static logs",
|
||||
"system_containers": "System & Containers",
|
||||
"current_time": "시스템 시간",
|
||||
"no_update_available": "시스템이 최신 버전입니다.",
|
||||
"architecture": "아키텍처",
|
||||
"container_running": "실행 중",
|
||||
"container_disabled": "컨테이너 중지 또는 비활성화",
|
||||
"container_stopped": "중지됨",
|
||||
"online_users": "온라인 사용자",
|
||||
"service": "서비스",
|
||||
"success": "성공",
|
||||
"show_ip": "공인 IP 표시",
|
||||
"timezone": "시간대",
|
||||
"update_available": "사용 가능한 업데이트가 있습니다.",
|
||||
"update_failed": "업데이트를 확인할 수 없습니다",
|
||||
"username": "사용자 이름",
|
||||
"memory": "메모리",
|
||||
"error_show_ip": "공인 IP 주소를 확인할 수 없습니다",
|
||||
"login_time": "시간"
|
||||
"system_containers": "System & Containers"
|
||||
},
|
||||
"diagnostics": {
|
||||
"cname_from_a": "Value derived from A/AAAA record. This is supported as long as the record points to the correct resource.",
|
||||
@@ -634,13 +542,7 @@
|
||||
"title": "Edit object",
|
||||
"unchanged_if_empty": "If unchanged leave blank",
|
||||
"username": "Username",
|
||||
"validate_save": "Validate and save",
|
||||
"allow_from_smtp": "다음 IP만 <b>SMTP</b>를 사용하도록 허용합니다.",
|
||||
"allow_from_smtp_info": "모든 발신자를 허용하려면 비워둡니다.<br>IPv4/IPv6 주소 및 네트워크.",
|
||||
"allowed_protocols": "허용된 프로토콜",
|
||||
"app_passwd_protocols": "앱 비밀번호에 대해 허용되는 프로토콜",
|
||||
"acl": "ACL (권한)",
|
||||
"admin": "관리자 수정"
|
||||
"validate_save": "Validate and save"
|
||||
},
|
||||
"footer": {
|
||||
"cancel": "Cancel",
|
||||
@@ -658,14 +560,13 @@
|
||||
"header": {
|
||||
"administration": "Configuration & Details",
|
||||
"apps": "Apps",
|
||||
"debug": "정보",
|
||||
"debug": "System Information",
|
||||
"email": "E-Mail",
|
||||
"mailcow_config": "Configuration",
|
||||
"quarantine": "Quarantine",
|
||||
"restart_netfilter": "Restart netfilter",
|
||||
"restart_sogo": "Restart SOGo",
|
||||
"user_settings": "User Settings",
|
||||
"mailcow_system": "시스템"
|
||||
"user_settings": "User Settings"
|
||||
},
|
||||
"info": {
|
||||
"awaiting_tfa_confirmation": "Awaiting TFA confirmation",
|
||||
@@ -772,9 +673,9 @@
|
||||
"recipient_map": "Recipient map",
|
||||
"recipient_map_info": "Recipient maps are used to replace the destination address on a message before it is delivered.",
|
||||
"recipient_map_new": "New recipient",
|
||||
"recipient_map_new_info": "Recipient map destination must be a valid email addresses or a domain name.",
|
||||
"recipient_map_new_info": "Recipient map destination must be a valid email address.",
|
||||
"recipient_map_old": "Original recipient",
|
||||
"recipient_map_old_info": "A recipient maps original destination must be a valid email addresses or a domain name.",
|
||||
"recipient_map_old_info": "A recipient maps original destination must be valid email addresses or a domain name.",
|
||||
"recipient_maps": "Recipient maps",
|
||||
"relay_all": "모든 수신자에게 릴레이",
|
||||
"remove": "Remove",
|
||||
@@ -1116,25 +1017,5 @@
|
||||
"quota_exceeded_scope": "Domain quota exceeded: Only unlimited mailboxes can be created in this domain scope.",
|
||||
"session_token": "Form token invalid: Token mismatch",
|
||||
"session_ua": "Form token invalid: User-Agent validation error"
|
||||
},
|
||||
"datatables": {
|
||||
"collapse_all": "모두 접기",
|
||||
"decimal": ".",
|
||||
"emptyTable": "테이블에 사용 가능한 데이터가 없습니다.",
|
||||
"expand_all": "모두 펼치기",
|
||||
"infoEmpty": "0개 항목 중 0개부터 0개까지 표시",
|
||||
"infoFiltered": "(_MAX_ 총 항목에서 필터링됨)",
|
||||
"thousands": ",",
|
||||
"lengthMenu": "_MENU_ 항목 표시",
|
||||
"loadingRecords": "로딩 중...",
|
||||
"processing": "잠시만 기다려 주세요...",
|
||||
"search": "검색:",
|
||||
"zeroRecords": "일치하는 레코드가 없습니다.",
|
||||
"paginate": {
|
||||
"first": "처음",
|
||||
"last": "마지막",
|
||||
"next": "다음",
|
||||
"previous": "이전"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -764,7 +764,7 @@
|
||||
"recipient_map": "Ontvanger-map",
|
||||
"recipient_map_info": "Ontvanger-maps worden gebruikt om het doeladres van een bericht te vervangen voordat het in een mailbox terecht komt.",
|
||||
"recipient_map_new": "Nieuwe ontvanger",
|
||||
"recipient_map_new_info": "De bestemming van een ontvanger-map dient een geldig mailadres of domeinnaam te zijn.",
|
||||
"recipient_map_new_info": "De bestemming van een ontvanger-map dient een geldig mailadres te zijn.",
|
||||
"recipient_map_old": "Oorspronkelijke ontvanger",
|
||||
"recipient_map_old_info": "De oorspronkelijke bestemming van een ontvanger-map dient een geldig mailadres of domeinnaam te zijn.",
|
||||
"recipient_maps": "Ontvanger-maps",
|
||||
@@ -1165,4 +1165,4 @@
|
||||
"search": "Zoeken:",
|
||||
"zeroRecords": "Geen overeenkomsten gevonden"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -882,7 +882,7 @@
|
||||
"recipient_map": "Mapa do destinatário",
|
||||
"recipient_map_info": "Os mapas de destinatários são usados para substituir o endereço de destino em uma mensagem antes que ela seja entregue.",
|
||||
"recipient_map_new": "Novo destinatário",
|
||||
"recipient_map_new_info": "O destino do mapa do destinatário deve ser um endereço de e-mail válido ou um nome de domínio.",
|
||||
"recipient_map_new_info": "O destino do mapa do destinatário deve ser um endereço de e-mail válido.",
|
||||
"recipient_map_old": "Destinatário original",
|
||||
"recipient_map_old_info": "O destino original do mapa de um destinatário deve ser um endereço de e-mail válido ou um nome de domínio.",
|
||||
"recipient_maps": "Mapas de destinatários",
|
||||
@@ -1330,4 +1330,4 @@
|
||||
"session_token": "Token de formulário inválido: incompatibilidade de token",
|
||||
"session_ua": "Token de formulário inválido: erro de validação do agente de usuário"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -789,7 +789,7 @@
|
||||
"recipient_map": "Hartă destinatar",
|
||||
"recipient_map_info": "Hărțile destinatarilor sunt folosite pentru a înlocui adresa de destinație a unui mesaj înainte de a fi livrat.",
|
||||
"recipient_map_new": "Destinatar nou",
|
||||
"recipient_map_new_info": "Destinația hărții destinatarului trebuie să fie adrese de email valide sau nume de domeniu.",
|
||||
"recipient_map_new_info": "Destinația hărții destinatarului trebuie să fie o adresă de email validă.",
|
||||
"recipient_map_old": "Destinatar original",
|
||||
"recipient_map_old_info": "Destinația originală a hărților destinatarilor trebuie să fie adrese de email valide sau nume de domeniu.",
|
||||
"recipient_maps": "Hărți destinatar",
|
||||
@@ -1208,4 +1208,4 @@
|
||||
"expand_all": "Expandează tot",
|
||||
"decimal": ","
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -887,7 +887,7 @@
|
||||
"recipient_map": "Перезапись получателя",
|
||||
"recipient_map_info": "Перезапись получателя используются для замены получателя в сообщении до его доставки.",
|
||||
"recipient_map_new": "Перезапись на",
|
||||
"recipient_map_new_info": "Должен быть действующим почтовым ящиком или доменом.",
|
||||
"recipient_map_new_info": "Должен быть действующим почтовым ящиком.",
|
||||
"recipient_map_old": "Получатель",
|
||||
"recipient_map_old_info": "Должен быть действующим почтовым ящиком или доменом.",
|
||||
"recipient_maps": "Перезапись получателя",
|
||||
@@ -1336,4 +1336,4 @@
|
||||
"session_token": "Неверный токен формы: несоответствие токена",
|
||||
"session_ua": "Неверный токен формы: ошибка проверки User-Agent"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -822,7 +822,7 @@
|
||||
"recipient_map": "Mapa príjemcu",
|
||||
"recipient_map_info": "Mapy príjemcov sú používané ako náhrada cieľovej adresy u správy pred doručením.",
|
||||
"recipient_map_new": "Nový príjemca",
|
||||
"recipient_map_new_info": "Mapový cieľ príjemcu musí byť platná emailová adresa alebo meno domény.",
|
||||
"recipient_map_new_info": "Mapový cieľ príjemcu musí byť platná emailová adresa.",
|
||||
"recipient_map_old": "Originálny príjemca",
|
||||
"recipient_map_old_info": "Originálny cieľ mapy príjemcu musí byť platná emailová adresa alebo meno domény.",
|
||||
"recipient_maps": "Mapy príjemcov",
|
||||
@@ -1256,4 +1256,4 @@
|
||||
"session_token": "Formulárový token neplatný: Tokenová nezhoda",
|
||||
"session_ua": "Formulárový token neplatný: User-Agent validation error"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -726,7 +726,7 @@
|
||||
"recipient_map": "Mottagaromskrivning",
|
||||
"recipient_map_info": "En omskrivning av mottagaradressen används för att ersätta destinationsadressen i ett meddelande innan den levereras.",
|
||||
"recipient_map_new": "Ny mottagare",
|
||||
"recipient_map_new_info": "Den ursprungliga mottagaren måste vara en giltiga e-postadresser eller ett domännamn.",
|
||||
"recipient_map_new_info": "Den ursprungliga mottagaren måste vara en giltig e-postadress.",
|
||||
"recipient_map_old": "Ursprunglig mottagaren",
|
||||
"recipient_map_old_info": "Den ursprungliga mottagaren måste vara en giltiga e-postadresser eller ett domännamn.",
|
||||
"recipient_maps": "Skriv om mottagaradressen",
|
||||
@@ -1110,4 +1110,4 @@
|
||||
"session_token": "Formulär-nyckeln är ogiltig: Nyckeln matchar inte",
|
||||
"session_ua": "Formulär-nyckeln är ogiltig: User-Agenten kunde inte valideras"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,12 +72,7 @@ elseif (isset($_GET['login'])) {
|
||||
// only check for admin-login on sogo GUI requests
|
||||
elseif (isset($_SERVER['HTTP_X_ORIGINAL_URI']) && strcasecmp(substr($_SERVER['HTTP_X_ORIGINAL_URI'], 0, 9), "/SOGo/so/") === 0) {
|
||||
// this is an nginx auth_request call, we check for existing sogo-sso session variables
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/vars.inc.php';
|
||||
if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/inc/vars.local.inc.php')) {
|
||||
include_once $_SERVER['DOCUMENT_ROOT'] . '/inc/vars.local.inc.php';
|
||||
}
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/sessions.inc.php';
|
||||
|
||||
session_start();
|
||||
// extract email address from "/SOGo/so/user@domain/xy"
|
||||
$url_parts = explode("/", $_SERVER['HTTP_X_ORIGINAL_URI']);
|
||||
$email_list = array(
|
||||
|
||||
@@ -117,8 +117,6 @@
|
||||
<select data-style="btn btn-light btn-sm" class="form-control" id="key_size" name="key_size" title="{{ lang.admin.dkim_key_length }}" required>
|
||||
<option data-subtext="bits">1024</option>
|
||||
<option data-subtext="bits">2048</option>
|
||||
<option data-subtext="bits">3072</option>
|
||||
<option data-subtext="bits">4096</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -235,7 +235,7 @@ function recursiveBase64StrToArrayBuffer(obj) {
|
||||
$(".totp-authenticator-selection").click(function(){
|
||||
$(".totp-authenticator-selection").removeClass("active");
|
||||
$(this).addClass("active");
|
||||
|
||||
|
||||
var id = $(this).children('input').first().val();
|
||||
$("#totp_selected_id").val(id);
|
||||
|
||||
@@ -244,7 +244,7 @@ function recursiveBase64StrToArrayBuffer(obj) {
|
||||
if ($('.totp-authenticator-selection').length == 1 &&
|
||||
$('#pending_tfa_tab_yubi_otp').length == 0 &&
|
||||
$('.webauthn-authenticator-selection').length == 0){
|
||||
|
||||
|
||||
// select default if only one authenticator exists
|
||||
$('.totp-authenticator-selection').addClass("active");
|
||||
|
||||
@@ -257,7 +257,7 @@ function recursiveBase64StrToArrayBuffer(obj) {
|
||||
$('#pending_tfa_tab_totp').on('shown.bs.tab', function() {
|
||||
// autofocus
|
||||
setTimeout(function() { $("#collapseTotpTFA").find('input[name="token"]').focus(); }, 200);
|
||||
});
|
||||
});
|
||||
// validate Yubi OTP tfa
|
||||
if ($('.webauthn-authenticator-selection').length == 0){
|
||||
// autofocus
|
||||
@@ -276,10 +276,10 @@ function recursiveBase64StrToArrayBuffer(obj) {
|
||||
$(".webauthn-authenticator-selection").click(function(){
|
||||
$(".webauthn-authenticator-selection").removeClass("active");
|
||||
$(this).addClass("active");
|
||||
|
||||
|
||||
var id = $(this).children('input').first().val();
|
||||
$("#webauthn_selected_id").val(id);
|
||||
|
||||
|
||||
var webauthn_status_auth = document.getElementById('webauthn_status_auth');
|
||||
webauthn_status_auth.style.setProperty('display', 'flex', 'important');
|
||||
var webauthn_return_code = document.getElementById('webauthn_return_code');
|
||||
@@ -302,7 +302,7 @@ function recursiveBase64StrToArrayBuffer(obj) {
|
||||
console.log(json);
|
||||
if (json.success === false) throw new Error();
|
||||
if (json.type === "error") throw new Error(json.msg);
|
||||
|
||||
|
||||
recursiveBase64StrToArrayBuffer(json);
|
||||
return json;
|
||||
}).then(getCredentialArgs => {
|
||||
@@ -329,7 +329,7 @@ function recursiveBase64StrToArrayBuffer(obj) {
|
||||
webauthn_return_code.style.setProperty('display', 'block', 'important');
|
||||
webauthn_return_code.innerHTML = lang_tfa.error_code + ': ' + err + ' ' + lang_tfa.reload_retry;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
$('#ConfirmTFAModal').on('hidden.bs.modal', function(){
|
||||
// cancel pending login
|
||||
@@ -540,7 +540,7 @@ function recursiveBase64StrToArrayBuffer(obj) {
|
||||
Version: <a href="{{ mailcow_info.git_project_url }}/releases/tag/{{ mailcow_info.version_tag }}" target="_blank">{{ mailcow_info.version_tag }}
|
||||
</a>
|
||||
</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if mailcow_cc_username and mailcow_info.mailcow_branch|lower == "nightly" and mailcow_info.version_tag|default %}
|
||||
<span class="version">
|
||||
🛠️🐮 + 🐋 = 💕
|
||||
@@ -549,14 +549,6 @@ function recursiveBase64StrToArrayBuffer(obj) {
|
||||
<span style="text-align:right;display:block;">Build: {{ mailcow_info.git_commit_date }}</span>
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if mailcow_cc_username and mailcow_info.mailcow_branch|lower == "legacy" and mailcow_info.version_tag|default %}
|
||||
<span class="version">
|
||||
⚰️🐮 + 🐋 = 💕
|
||||
Legacy: <a href="{{ mailcow_info.git_project_url }}/commit/{{ mailcow_info.git_commit }}" target="_blank">{{ mailcow_info.version_tag }}
|
||||
</a><br>
|
||||
<span style="text-align:right;display:block;">Build: {{ mailcow_info.git_commit_date }}</span>
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -103,8 +103,6 @@
|
||||
<select data-style="btn btn-light" class="form-control" id="key_size" name="key_size">
|
||||
<option value="1024" data-subtext="bits" {% if template.attributes.key_size == 1024 %} selected{% endif %}>1024</option>
|
||||
<option value="2048" data-subtext="bits" {% if template.attributes.key_size == 2048 %} selected{% endif %}>2048</option>
|
||||
<option value="3072" data-subtext="bits" {% if template.attributes.key_size == 3072 %} selected{% endif %}>3072</option>
|
||||
<option value="4096" data-subtext="bits" {% if template.attributes.key_size == 4096 %} selected{% endif %}>4096</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -490,8 +490,6 @@
|
||||
<select data-style="btn btn-light" class="form-control" id="key_size" name="key_size">
|
||||
<option data-subtext="bits" value="1024">1024</option>
|
||||
<option data-subtext="bits" value="2048" selected>2048</option>
|
||||
<option data-subtext="bits" value="3072">3072</option>
|
||||
<option data-subtext="bits" value="4096">4096</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@@ -630,8 +628,6 @@
|
||||
<select data-style="btn btn-light" class="form-control" id="key_size" name="key_size">
|
||||
<option data-subtext="bits">1024</option>
|
||||
<option data-subtext="bits" selected>2048</option>
|
||||
<option data-subtext="bits">3072</option>
|
||||
<option data-subtext="bits">4096</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@@ -847,8 +843,6 @@
|
||||
<select data-style="btn btn-light" class="form-control" id="key_size2" name="key_size">
|
||||
<option data-subtext="bits">1024</option>
|
||||
<option data-subtext="bits" selected>2048</option>
|
||||
<option data-subtext="bits">3072</option>
|
||||
<option data-subtext="bits">4096</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
services:
|
||||
|
||||
unbound-mailcow:
|
||||
image: ghcr.io/mailcow/unbound:1.24
|
||||
image: mailcow/unbound:1.23
|
||||
environment:
|
||||
- TZ=${TZ}
|
||||
- SKIP_UNBOUND_HEALTHCHECK=${SKIP_UNBOUND_HEALTHCHECK:-n}
|
||||
@@ -17,7 +17,7 @@ services:
|
||||
- unbound
|
||||
|
||||
mysql-mailcow:
|
||||
image: mariadb:10.11
|
||||
image: mariadb:10.5
|
||||
depends_on:
|
||||
- unbound-mailcow
|
||||
- netfilter-mailcow
|
||||
@@ -42,8 +42,8 @@ services:
|
||||
- mysql
|
||||
|
||||
redis-mailcow:
|
||||
image: redis:7.4.6-alpine
|
||||
entrypoint: ["/bin/sh","/redis-conf.sh"]
|
||||
image: redis:7-alpine
|
||||
entrypoint: /redis-conf.sh
|
||||
volumes:
|
||||
- redis-vol-1:/data/
|
||||
- ./data/conf/redis/redis-conf.sh:/redis-conf.sh:z
|
||||
@@ -55,7 +55,6 @@ services:
|
||||
environment:
|
||||
- TZ=${TZ}
|
||||
- REDISPASS=${REDISPASS}
|
||||
- REDISMASTERPASS=${REDISMASTERPASS:-}
|
||||
sysctls:
|
||||
- net.core.somaxconn=4096
|
||||
networks:
|
||||
@@ -65,7 +64,7 @@ services:
|
||||
- redis
|
||||
|
||||
clamd-mailcow:
|
||||
image: ghcr.io/mailcow/clamd:1.70
|
||||
image: mailcow/clamd:1.66
|
||||
restart: always
|
||||
depends_on:
|
||||
unbound-mailcow:
|
||||
@@ -84,7 +83,7 @@ services:
|
||||
- clamd
|
||||
|
||||
rspamd-mailcow:
|
||||
image: ghcr.io/mailcow/rspamd:2.1
|
||||
image: mailcow/rspamd:1.99
|
||||
stop_grace_period: 30s
|
||||
depends_on:
|
||||
- dovecot-mailcow
|
||||
@@ -117,7 +116,7 @@ services:
|
||||
- rspamd
|
||||
|
||||
php-fpm-mailcow:
|
||||
image: ghcr.io/mailcow/phpfpm:1.93
|
||||
image: mailcow/phpfpm:1.92
|
||||
command: "php-fpm -d date.timezone=${TZ} -d expose_php=0"
|
||||
depends_on:
|
||||
- redis-mailcow
|
||||
@@ -175,7 +174,6 @@ services:
|
||||
- DEMO_MODE=${DEMO_MODE:-n}
|
||||
- WEBAUTHN_ONLY_TRUSTED_VENDORS=${WEBAUTHN_ONLY_TRUSTED_VENDORS:-n}
|
||||
- CLUSTERMODE=${CLUSTERMODE:-}
|
||||
- ADDITIONAL_SERVER_NAMES=${ADDITIONAL_SERVER_NAMES:-}
|
||||
restart: always
|
||||
networks:
|
||||
mailcow-network:
|
||||
@@ -183,7 +181,7 @@ services:
|
||||
- phpfpm
|
||||
|
||||
sogo-mailcow:
|
||||
image: ghcr.io/mailcow/sogo:1.129
|
||||
image: mailcow/sogo:1.128
|
||||
environment:
|
||||
- DBNAME=${DBNAME}
|
||||
- DBUSER=${DBUSER}
|
||||
@@ -208,9 +206,6 @@ services:
|
||||
- ./data/conf/sogo/:/etc/sogo/:z
|
||||
- ./data/web/inc/init_db.inc.php:/init_db.inc.php:z
|
||||
- ./data/conf/sogo/custom-favicon.ico:/usr/lib/GNUstep/SOGo/WebServerResources/img/sogo.ico:z
|
||||
- ./data/conf/sogo/custom-shortlogo.svg:/usr/lib/GNUstep/SOGo/WebServerResources/img/sogo-compact.svg:z
|
||||
- ./data/conf/sogo/custom-fulllogo.svg:/usr/lib/GNUstep/SOGo/WebServerResources/img/sogo-full.svg:z
|
||||
- ./data/conf/sogo/custom-fulllogo.png:/usr/lib/GNUstep/SOGo/WebServerResources/img/sogo-logo.png:z
|
||||
- ./data/conf/sogo/custom-theme.js:/usr/lib/GNUstep/SOGo/WebServerResources/js/theme.js:z
|
||||
- ./data/conf/sogo/custom-sogo.js:/usr/lib/GNUstep/SOGo/WebServerResources/js/custom-sogo.js:z
|
||||
- mysql-socket-vol-1:/var/run/mysqld/
|
||||
@@ -234,7 +229,7 @@ services:
|
||||
- sogo
|
||||
|
||||
dovecot-mailcow:
|
||||
image: ghcr.io/mailcow/dovecot:2.34-legacy
|
||||
image: mailcow/dovecot:2.3
|
||||
depends_on:
|
||||
- mysql-mailcow
|
||||
- netfilter-mailcow
|
||||
@@ -321,7 +316,7 @@ services:
|
||||
- dovecot
|
||||
|
||||
postfix-mailcow:
|
||||
image: ghcr.io/mailcow/postfix:1.80
|
||||
image: mailcow/postfix:1.78
|
||||
depends_on:
|
||||
mysql-mailcow:
|
||||
condition: service_started
|
||||
@@ -377,7 +372,7 @@ services:
|
||||
- php-fpm-mailcow
|
||||
- sogo-mailcow
|
||||
- rspamd-mailcow
|
||||
image: ghcr.io/mailcow/nginx:1.03
|
||||
image: mailcow/nginx:1.01
|
||||
dns:
|
||||
- ${IPV4_NETWORK:-172.22.1}.254
|
||||
environment:
|
||||
@@ -389,14 +384,11 @@ services:
|
||||
- SKIP_SOGO=${SKIP_SOGO:-n}
|
||||
- SKIP_RSPAMD=${SKIP_RSPAMD:-n}
|
||||
- DISABLE_IPv6=${DISABLE_IPv6:-n}
|
||||
- HTTP_REDIRECT=${HTTP_REDIRECT:-n}
|
||||
- PHPFPMHOST=${PHPFPMHOST:-}
|
||||
- SOGOHOST=${SOGOHOST:-}
|
||||
- RSPAMDHOST=${RSPAMDHOST:-}
|
||||
- REDISHOST=${REDISHOST:-}
|
||||
- IPV4_NETWORK=${IPV4_NETWORK:-172.22.1}
|
||||
- NGINX_USE_PROXY_PROTOCOL=${NGINX_USE_PROXY_PROTOCOL:-n}
|
||||
- TRUSTED_PROXIES=${TRUSTED_PROXIES:-}
|
||||
volumes:
|
||||
- ./data/web:/web:ro,z
|
||||
- ./data/conf/rspamd/dynmaps:/dynmaps:ro,z
|
||||
@@ -419,7 +411,7 @@ services:
|
||||
condition: service_started
|
||||
unbound-mailcow:
|
||||
condition: service_healthy
|
||||
image: ghcr.io/mailcow/acme:1.92
|
||||
image: mailcow/acme:1.91
|
||||
dns:
|
||||
- ${IPV4_NETWORK:-172.22.1}.254
|
||||
environment:
|
||||
@@ -457,7 +449,7 @@ services:
|
||||
- acme
|
||||
|
||||
netfilter-mailcow:
|
||||
image: ghcr.io/mailcow/netfilter:1.62
|
||||
image: mailcow/netfilter:1.60
|
||||
stop_grace_period: 30s
|
||||
restart: always
|
||||
privileged: true
|
||||
@@ -477,7 +469,7 @@ services:
|
||||
- /lib/modules:/lib/modules:ro
|
||||
|
||||
watchdog-mailcow:
|
||||
image: ghcr.io/mailcow/watchdog:2.07
|
||||
image: mailcow/watchdog:2.06
|
||||
dns:
|
||||
- ${IPV4_NETWORK:-172.22.1}.254
|
||||
tmpfs:
|
||||
@@ -549,7 +541,7 @@ services:
|
||||
- watchdog
|
||||
|
||||
dockerapi-mailcow:
|
||||
image: ghcr.io/mailcow/dockerapi:2.11
|
||||
image: mailcow/dockerapi:2.10
|
||||
security_opt:
|
||||
- label=disable
|
||||
restart: always
|
||||
@@ -569,7 +561,7 @@ services:
|
||||
- dockerapi
|
||||
|
||||
olefy-mailcow:
|
||||
image: ghcr.io/mailcow/olefy:1.14
|
||||
image: mailcow/olefy:1.13
|
||||
restart: always
|
||||
environment:
|
||||
- TZ=${TZ}
|
||||
|
||||
@@ -26,7 +26,7 @@ for bin in openssl curl docker git awk sha1sum grep cut; do
|
||||
done
|
||||
|
||||
# Check Docker Version (need at least 24.X)
|
||||
docker_version=$(docker version --format '{{.Server.Version}}' | cut -d '.' -f 1)
|
||||
docker_version=$(docker -v | grep -oP '\d+\.\d+\.\d+' | head -n 1 | cut -d '.' -f 1)
|
||||
|
||||
if [[ $docker_version -lt 24 ]]; then
|
||||
echo -e "\e[31mCannot find Docker with a Version higher or equals 24.0.0\e[0m"
|
||||
@@ -181,15 +181,11 @@ if [[ ${SKIP_BRANCH} != y ]]; then
|
||||
echo "Available Branches:"
|
||||
echo "- master branch (stable updates) | default, recommended [1]"
|
||||
echo "- nightly branch (unstable updates, testing) | not-production ready [2]"
|
||||
echo "- legacy branch (supported until February 2026) | deprecated, security updates only [3]"
|
||||
sleep 1
|
||||
|
||||
while [ -z "${MAILCOW_BRANCH}" ]; do
|
||||
read -r -p "Choose the Branch with it's number [1/2/3] " branch
|
||||
read -r -p "Choose the Branch with it's number [1/2] " branch
|
||||
case $branch in
|
||||
[3])
|
||||
MAILCOW_BRANCH="legacy"
|
||||
;;
|
||||
[2])
|
||||
MAILCOW_BRANCH="nightly"
|
||||
;;
|
||||
@@ -271,9 +267,6 @@ HTTP_BIND=
|
||||
HTTPS_PORT=443
|
||||
HTTPS_BIND=
|
||||
|
||||
# Redirect HTTP connections to HTTPS - y/n
|
||||
HTTP_REDIRECT=n
|
||||
|
||||
# ------------------------------
|
||||
# Other bindings
|
||||
# ------------------------------
|
||||
@@ -538,10 +531,6 @@ case ${git_branch} in
|
||||
mailcow_git_version=$(git rev-parse --short $(git rev-parse @{upstream}))
|
||||
mailcow_last_git_version=""
|
||||
;;
|
||||
legacy)
|
||||
mailcow_git_version=$(git rev-parse --short $(git rev-parse @{upstream}))
|
||||
mailcow_last_git_version=""
|
||||
;;
|
||||
*)
|
||||
mailcow_git_version=$(git rev-parse --short HEAD)
|
||||
mailcow_last_git_version=""
|
||||
|
||||
@@ -10,6 +10,46 @@ echo "If this script is run automatically by cron or a timer AND you are using b
|
||||
echo "The snapshots of your backup destination should run AFTER the cold standby script finished to ensure consistent snapshots."
|
||||
echo
|
||||
|
||||
function docker_garbage() {
|
||||
IMGS_TO_DELETE=()
|
||||
|
||||
for container in $(grep -oP "image: \Kmailcow.+" docker-compose.yml); do
|
||||
|
||||
REPOSITORY=${container/:*}
|
||||
TAG=${container/*:}
|
||||
V_MAIN=${container/*.}
|
||||
V_SUB=${container/*.}
|
||||
EXISTING_TAGS=$(docker images | grep ${REPOSITORY} | awk '{ print $2 }')
|
||||
|
||||
for existing_tag in ${EXISTING_TAGS[@]}; do
|
||||
|
||||
V_MAIN_EXISTING=${existing_tag/*.}
|
||||
V_SUB_EXISTING=${existing_tag/*.}
|
||||
|
||||
# Not an integer
|
||||
[[ ! ${V_MAIN_EXISTING} =~ ^[0-9]+$ ]] && continue
|
||||
[[ ! ${V_SUB_EXISTING} =~ ^[0-9]+$ ]] && continue
|
||||
|
||||
if [[ ${V_MAIN_EXISTING} == "latest" ]]; then
|
||||
echo "Found deprecated label \"latest\" for repository ${REPOSITORY}, it should be deleted."
|
||||
IMGS_TO_DELETE+=(${REPOSITORY}:${existing_tag})
|
||||
elif [[ ${V_MAIN_EXISTING} -lt ${V_MAIN} ]]; then
|
||||
echo "Found tag ${existing_tag} for ${REPOSITORY}, which is older than the current tag ${TAG} and should be deleted."
|
||||
IMGS_TO_DELETE+=(${REPOSITORY}:${existing_tag})
|
||||
elif [[ ${V_SUB_EXISTING} -lt ${V_SUB} ]]; then
|
||||
echo "Found tag ${existing_tag} for ${REPOSITORY}, which is older than the current tag ${TAG} and should be deleted."
|
||||
IMGS_TO_DELETE+=(${REPOSITORY}:${existing_tag})
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
done
|
||||
|
||||
if [[ ! -z ${IMGS_TO_DELETE[*]} ]]; then
|
||||
docker rmi ${IMGS_TO_DELETE[*]}
|
||||
fi
|
||||
}
|
||||
|
||||
function preflight_local_checks() {
|
||||
if [[ -z "${REMOTE_SSH_KEY}" ]]; then
|
||||
>&2 echo -e "\e[31mREMOTE_SSH_KEY is not set\e[0m"
|
||||
@@ -99,11 +139,11 @@ EOF
|
||||
|
||||
if [ $? = 0 ]; then
|
||||
COMPOSE_COMMAND="docker compose"
|
||||
echo "INFO: Using native docker compose on remote"
|
||||
echo "DEBUG: Using native docker compose on remote"
|
||||
|
||||
elif [ $? = 1 ]; then
|
||||
COMPOSE_COMMAND="docker-compose"
|
||||
echo "INFO: Using standalone docker compose on remote"
|
||||
echo "DEBUG: Using standalone docker compose on remote"
|
||||
|
||||
else
|
||||
echo -e "\e[31mCannot find any Docker Compose on remote, exiting...\e[0m"
|
||||
@@ -284,7 +324,7 @@ echo "OK"
|
||||
-i "${REMOTE_SSH_KEY}" \
|
||||
${REMOTE_SSH_HOST} \
|
||||
-p ${REMOTE_SSH_PORT} \
|
||||
${COMPOSE_COMMAND} -f "${SCRIPT_DIR}/../docker-compose.yml" pull --quiet 2>&1 ; then
|
||||
${COMPOSE_COMMAND} -f "${SCRIPT_DIR}/../docker-compose.yml" pull --no-parallel --quiet 2>&1 ; then
|
||||
>&2 echo -e "\e[31m[ERR]\e[0m - Could not pull images on remote"
|
||||
fi
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
DEBIAN_DOCKER_IMAGE="ghcr.io/mailcow/backup:latest"
|
||||
DEBIAN_DOCKER_IMAGE="mailcow/backup:latest"
|
||||
|
||||
if [[ ! -z ${MAILCOW_BACKUP_LOCATION} ]]; then
|
||||
BACKUP_LOCATION="${MAILCOW_BACKUP_LOCATION}"
|
||||
|
||||
111
update.sh
111
update.sh
@@ -36,19 +36,13 @@ docker_garbage() {
|
||||
IMGS_TO_DELETE=()
|
||||
|
||||
declare -A IMAGES_INFO
|
||||
COMPOSE_IMAGES=($(grep -oP "image: \K(ghcr\.io/)?mailcow.+" "${SCRIPT_DIR}/docker-compose.yml"))
|
||||
COMPOSE_IMAGES=($(grep -oP "image: \Kmailcow.+" "${SCRIPT_DIR}/docker-compose.yml"))
|
||||
|
||||
for existing_image in $(docker images --format "{{.ID}}:{{.Repository}}:{{.Tag}}" | grep -E '(mailcow/|ghcr\.io/mailcow/)'); do
|
||||
for existing_image in $(docker images --format "{{.ID}}:{{.Repository}}:{{.Tag}}" | grep 'mailcow/'); do
|
||||
ID=$(echo "$existing_image" | cut -d ':' -f 1)
|
||||
REPOSITORY=$(echo "$existing_image" | cut -d ':' -f 2)
|
||||
TAG=$(echo "$existing_image" | cut -d ':' -f 3)
|
||||
|
||||
if [[ "$REPOSITORY" == "mailcow/backup" || "$REPOSITORY" == "ghcr.io/mailcow/backup" ]]; then
|
||||
if [[ "$TAG" != "<none>" ]]; then
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ " ${COMPOSE_IMAGES[@]} " =~ " ${REPOSITORY}:${TAG} " ]]; then
|
||||
continue
|
||||
else
|
||||
@@ -63,7 +57,7 @@ docker_garbage() {
|
||||
echo " ${IMAGES_INFO[$id]} ($id)"
|
||||
done
|
||||
|
||||
if [ -z "$FORCE" ]; then
|
||||
if [ ! $FORCE ]; then
|
||||
read -r -p "Do you want to delete them to free up some space? [y/N] " response
|
||||
if [[ "$response" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||
docker rmi ${IMGS_TO_DELETE[*]}
|
||||
@@ -177,7 +171,7 @@ remove_obsolete_nginx_ports() {
|
||||
detect_docker_compose_command(){
|
||||
if ! [[ "${DOCKER_COMPOSE_VERSION}" =~ ^(native|standalone)$ ]]; then
|
||||
if docker compose > /dev/null 2>&1; then
|
||||
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
|
||||
if docker compose version --short | grep -e "^2." -e "^v2." > /dev/null 2>&1; then
|
||||
DOCKER_COMPOSE_VERSION=native
|
||||
COMPOSE_COMMAND="docker compose"
|
||||
echo -e "\e[33mFound Docker Compose Plugin (native).\e[0m"
|
||||
@@ -187,12 +181,12 @@ if ! [[ "${DOCKER_COMPOSE_VERSION}" =~ ^(native|standalone)$ ]]; then
|
||||
echo -e "\e[33mNotice: You'll have to update this Compose Version via your Package Manager manually!\e[0m"
|
||||
else
|
||||
echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m"
|
||||
echo -e "\e[31mPlease update/install manually regarding to this doc site: https://docs.mailcow.email/install/\e[0m"
|
||||
echo -e "\e[31mPlease update/install it manually regarding to this doc site: https://docs.mailcow.email/install/\e[0m"
|
||||
exit 1
|
||||
fi
|
||||
elif docker-compose > /dev/null 2>&1; then
|
||||
if ! [[ $(alias docker-compose 2> /dev/null) ]] ; then
|
||||
if docker-compose version --short | grep -e "^[2-9]\." -e "^[1-9][0-9]\." > /dev/null 2>&1; then
|
||||
if docker-compose version --short | grep "^2." > /dev/null 2>&1; then
|
||||
DOCKER_COMPOSE_VERSION=standalone
|
||||
COMPOSE_COMMAND="docker-compose"
|
||||
echo -e "\e[33mFound Docker Compose Standalone.\e[0m"
|
||||
@@ -202,7 +196,7 @@ if ! [[ "${DOCKER_COMPOSE_VERSION}" =~ ^(native|standalone)$ ]]; then
|
||||
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"
|
||||
else
|
||||
echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m"
|
||||
echo -e "\e[31mPlease update/install manually regarding to this doc site: https://docs.mailcow.email/install/\e[0m"
|
||||
echo -e "\e[31mPlease update/install regarding to this doc site: https://docs.mailcow.email/install/\e[0m"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
@@ -358,7 +352,6 @@ adapt_new_options() {
|
||||
"SPAMHAUS_DQS_KEY"
|
||||
"SKIP_UNBOUND_HEALTHCHECK"
|
||||
"DISABLE_NETFILTER_ISOLATION_RULE"
|
||||
"HTTP_REDIRECT"
|
||||
)
|
||||
|
||||
sed -i --follow-symlinks '$a\' mailcow.conf
|
||||
@@ -644,13 +637,7 @@ adapt_new_options() {
|
||||
echo '# Prevent netfilter from setting an iptables/nftables rule to isolate the mailcow docker network - y/n' >> mailcow.conf
|
||||
echo '# CAUTION: Disabling this may expose container ports to other neighbors on the same subnet, even if the ports are bound to localhost' >> mailcow.conf
|
||||
echo 'DISABLE_NETFILTER_ISOLATION_RULE=n' >> mailcow.conf
|
||||
fi
|
||||
elif [[ ${option} == "HTTP_REDIRECT" ]]; then
|
||||
if ! grep -q ${option} mailcow.conf; then
|
||||
echo "Adding new option \"${option}\" to mailcow.conf"
|
||||
echo '# Redirect HTTP connections to HTTPS - y/n' >> mailcow.conf
|
||||
echo 'HTTP_REDIRECT=n' >> mailcow.conf
|
||||
fi
|
||||
fi
|
||||
elif ! grep -q ${option} mailcow.conf; then
|
||||
echo "Adding new option \"${option}\" to mailcow.conf"
|
||||
echo "${option}=n" >> mailcow.conf
|
||||
@@ -716,50 +703,6 @@ migrate_solr_config_options() {
|
||||
fi
|
||||
}
|
||||
|
||||
detect_major_update() {
|
||||
if [ ${BRANCH} == "master" ]; then
|
||||
# Array with major versions
|
||||
# Add major versions here
|
||||
MAJOR_VERSIONS=(
|
||||
"2025-02"
|
||||
"2025-03"
|
||||
)
|
||||
|
||||
current_version=""
|
||||
if [[ -f "${SCRIPT_DIR}/data/web/inc/app_info.inc.php" ]]; then
|
||||
current_version=$(grep 'MAILCOW_GIT_VERSION' ${SCRIPT_DIR}/data/web/inc/app_info.inc.php | sed -E 's/.*MAILCOW_GIT_VERSION="([^"]+)".*/\1/')
|
||||
fi
|
||||
if [[ -z "$current_version" ]]; then
|
||||
return 1
|
||||
fi
|
||||
release_url="https://github.com/mailcow/mailcow-dockerized/releases/tag"
|
||||
|
||||
updates_to_apply=()
|
||||
|
||||
for version in "${MAJOR_VERSIONS[@]}"; do
|
||||
if [[ "$current_version" < "$version" ]]; then
|
||||
updates_to_apply+=("$version")
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ ${#updates_to_apply[@]} -gt 0 ]]; then
|
||||
echo -e "\e[33m\nMAJOR UPDATES to be applied:\e[0m"
|
||||
for update in "${updates_to_apply[@]}"; do
|
||||
echo "$update - $release_url/$update"
|
||||
done
|
||||
|
||||
echo -e "\nPlease read the release notes before proceeding."
|
||||
read -p "Do you want to proceed with the update? [y/n] " response
|
||||
if [[ "${response}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||
echo "Proceeding with the update..."
|
||||
else
|
||||
echo "Update canceled. Exiting."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
############## End Function Section ##############
|
||||
|
||||
# Check permissions
|
||||
@@ -895,12 +838,8 @@ while (($#)); do
|
||||
echo -e "\e[32mRunning in Developer mode...\e[0m"
|
||||
DEV=y
|
||||
;;
|
||||
--legacy)
|
||||
CURRENT_BRANCH="$(cd "${SCRIPT_DIR}"; git rev-parse --abbrev-ref HEAD)"
|
||||
NEW_BRANCH="legacy"
|
||||
;;
|
||||
--help|-h)
|
||||
echo './update.sh [-c|--check, --check-tags, --ours, --gc, --nightly, --prefetch, --skip-start, --skip-ping-check, --stable, --legacy, -f|--force, -d|--dev, -h|--help]
|
||||
echo './update.sh [-c|--check, --check-tags, --ours, --gc, --nightly, --prefetch, --skip-start, --skip-ping-check, --stable, -f|--force, -d|--dev, -h|--help]
|
||||
|
||||
-c|--check - Check for updates and exit (exit codes => 0: update available, 3: no updates)
|
||||
--check-tags - Check for newer tags and exit (exit codes => 0: newer tag available, 3: no newer tag)
|
||||
@@ -910,8 +849,7 @@ while (($#)); do
|
||||
--prefetch - Only prefetch new images and exit (useful to prepare updates)
|
||||
--skip-start - Do not start mailcow after update
|
||||
--skip-ping-check - Skip ICMP Check to public DNS resolvers (Use it only if you'\''ve blocked any ICMP Connections to your mailcow machine)
|
||||
--stable - Switch your mailcow updates to the stable (master) branch. Default unless you changed it with --nightly or --legacy.
|
||||
--legacy - Switch your mailcow updates to the legacy branch. The legacy branch will only recieve security updates until February 2026.
|
||||
--stable - Switch your mailcow updates to the stable (master) branch. Default unless you changed it with --nightly.
|
||||
-f|--force - Force update, do not ask questions
|
||||
-d|--dev - Enables Developer Mode (No Checkout of update.sh for tests)
|
||||
'
|
||||
@@ -1317,11 +1255,6 @@ if ! [ "$NEW_BRANCH" ]; then
|
||||
sleep 1
|
||||
echo -e "\e[33mTo change that run the update.sh Script one time with the --stable parameter to switch to stable builds.\e[0m"
|
||||
|
||||
elif [ "${BRANCH}" == "legacy" ]; then
|
||||
echo -e "\e[31mYou are receiving legacy updates. The legacy branch will only recieve security updates until February 2026.\e[0m"
|
||||
sleep 1
|
||||
echo -e "\e[33mTo change that run the update.sh Script one time with the --stable parameter to switch to stable builds.\e[0m"
|
||||
|
||||
else
|
||||
echo -e "\e[33mYou are receiving updates from an unsupported branch.\e[0m"
|
||||
sleep 1
|
||||
@@ -1384,29 +1317,6 @@ elif [ "$NEW_BRANCH" == "nightly" ] && [ "$CURRENT_BRANCH" != "nightly" ]; then
|
||||
fi
|
||||
git fetch origin
|
||||
git checkout -f "${BRANCH}"
|
||||
elif [ "$NEW_BRANCH" == "legacy" ] && [ "$CURRENT_BRANCH" != "legacy" ]; then
|
||||
echo -e "\e[33mYou are about to switch your mailcow Updates to the legacy branch.\e[0m"
|
||||
sleep 1
|
||||
echo -e "\e[33mBefore you do: Please take a backup of all components to ensure that no Data is lost...\e[0m"
|
||||
sleep 1
|
||||
echo -e "\e[31mWARNING: A switch to stable or nightly is possible any time.\e[0m"
|
||||
read -r -p "Are you sure you want to continue upgrading to the legacy branch? [y/N] " response
|
||||
if [[ ! "${response}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||
echo "OK. If you prepared yourself for that please run the update.sh Script with the --legacy parameter again to trigger this process here."
|
||||
exit 0
|
||||
fi
|
||||
BRANCH=$NEW_BRANCH
|
||||
DIFF_DIRECTORY=update_diffs
|
||||
DIFF_FILE=${DIFF_DIRECTORY}/diff_before_upgrade_to_legacy_$(date +"%Y-%m-%d-%H-%M-%S")
|
||||
mv diff_before_upgrade* ${DIFF_DIRECTORY}/ 2> /dev/null
|
||||
if ! git diff-index --quiet HEAD; then
|
||||
echo -e "\e[32mSaving diff to ${DIFF_FILE}...\e[0m"
|
||||
mkdir -p ${DIFF_DIRECTORY}
|
||||
git diff "${BRANCH}" --stat > "${DIFF_FILE}"
|
||||
git diff "${BRANCH}" >> "${DIFF_FILE}"
|
||||
fi
|
||||
git fetch origin
|
||||
git checkout -f "${BRANCH}"
|
||||
fi
|
||||
|
||||
if [ ! "$DEV" ]; then
|
||||
@@ -1428,7 +1338,6 @@ if [ ! "$FORCE" ]; then
|
||||
echo "OK, exiting."
|
||||
exit 0
|
||||
fi
|
||||
detect_major_update
|
||||
migrate_docker_nat
|
||||
fi
|
||||
|
||||
|
||||
Reference in New Issue
Block a user