1
0
mirror of https://github.com/mailcow/mailcow-dockerized.git synced 2024-12-21 01:49:22 +02:00

Merge remote-tracking branch 'origin/staging' into nightly

This commit is contained in:
FreddleSpl0it 2024-12-05 14:33:41 +01:00
commit a41bb55c83
No known key found for this signature in database
GPG Key ID: 00E14E7634F4BEC5
69 changed files with 959 additions and 690 deletions

1
.github/FUNDING.yml vendored
View File

@ -1 +1,2 @@
github: mailcow
custom: ["https://www.servercow.de/mailcow?lang=en#sal"]

View File

@ -4,9 +4,9 @@ exec 5>&1
# Do not attempt to write to slave
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
export REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT}"
export REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} -a ${REDISPASS} --no-auth-warning"
else
export REDIS_CMDLINE="redis-cli -h redis -p 6379"
export REDIS_CMDLINE="redis-cli -h redis -p 6379 -a ${REDISPASS} --no-auth-warning"
fi
until [[ $(${REDIS_CMDLINE} PING) == "PONG" ]]; do

View File

@ -124,7 +124,7 @@ case "$SUCCESS" in
;;
*) # non-zero is non-fun
log_f "Failed to obtain certificate ${CERT} for domains '${CERT_DOMAINS[*]}'"
redis-cli -h redis SET ACME_FAIL_TIME "$(date +%s)"
redis-cli -h redis -a ${REDISPASS} --no-auth-warning SET ACME_FAIL_TIME "$(date +%s)"
exit 100${SUCCESS}
;;
esac

View File

@ -34,9 +34,9 @@ async def lifespan(app: FastAPI):
# Init redis client
if os.environ['REDIS_SLAVEOF_IP'] != "":
redis_client = redis = await aioredis.from_url(f"redis://{os.environ['REDIS_SLAVEOF_IP']}:{os.environ['REDIS_SLAVEOF_PORT']}/0")
redis_client = redis = await aioredis.from_url(f"redis://{os.environ['REDIS_SLAVEOF_IP']}:{os.environ['REDIS_SLAVEOF_PORT']}/0", password=os.environ['REDISPASS'])
else:
redis_client = redis = await aioredis.from_url("redis://redis-mailcow:6379/0")
redis_client = redis = await aioredis.from_url("redis://redis-mailcow:6379/0", password=os.environ['REDISPASS'])
# Init docker clients
sync_docker_client = docker.DockerClient(base_url='unix://var/run/docker.sock', version='auto')

View File

@ -2,7 +2,7 @@
source /source_env.sh
MAX_AGE=$(redis-cli --raw -h redis-mailcow GET Q_MAX_AGE)
MAX_AGE=$(redis-cli --raw -h redis-mailcow -a ${REDISPASS} --no-auth-warning GET Q_MAX_AGE)
if [[ -z ${MAX_AGE} ]]; then
echo "Max age for quarantine items not defined"

View File

@ -14,9 +14,9 @@ done
# Do not attempt to write to slave
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT}"
REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} -a ${REDISPASS} --no-auth-warning"
else
REDIS_CMDLINE="redis-cli -h redis -p 6379"
REDIS_CMDLINE="redis-cli -h redis -p 6379 -a ${REDISPASS} --no-auth-warning"
fi
until [[ $(${REDIS_CMDLINE} PING) == "PONG" ]]; do

View File

@ -31,7 +31,7 @@ try:
while True:
try:
r = redis.StrictRedis(host='redis', decode_responses=True, port=6379, db=0)
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))

View File

@ -23,7 +23,7 @@ else:
while True:
try:
r = redis.StrictRedis(host='redis', decode_responses=True, port=6379, db=0)
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))

View File

@ -4,9 +4,9 @@ source /source_env.sh
# Do not attempt to write to slave
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT}"
REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} -a ${REDISPASS} --no-auth-warning"
else
REDIS_CMDLINE="redis-cli -h redis -p 6379"
REDIS_CMDLINE="redis-cli -h redis -p 6379 -a ${REDISPASS} --no-auth-warning"
fi
# Is replication active?

View File

@ -20,6 +20,7 @@ destination d_redis_ui_log {
host("`REDIS_SLAVEOF_IP`")
persist-name("redis1")
port(`REDIS_SLAVEOF_PORT`)
auth("`REDISPASS`")
command("LPUSH" "DOVECOT_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
);
};
@ -28,6 +29,7 @@ destination d_redis_f2b_channel {
host("`REDIS_SLAVEOF_IP`")
persist-name("redis2")
port(`REDIS_SLAVEOF_PORT`)
auth("`REDISPASS`")
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
);
};

View File

@ -20,6 +20,7 @@ destination d_redis_ui_log {
host("redis-mailcow")
persist-name("redis1")
port(6379)
auth("`REDISPASS`")
command("LPUSH" "DOVECOT_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
);
};
@ -28,6 +29,7 @@ destination d_redis_f2b_channel {
host("redis-mailcow")
persist-name("redis2")
port(6379)
auth("`REDISPASS`")
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
);
};

View File

@ -10,9 +10,9 @@ catch_non_zero() {
source /source_env.sh
# Do not attempt to write to slave
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT}"
REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} -a ${REDISPASS} --no-auth-warning"
else
REDIS_CMDLINE="redis-cli -h redis -p 6379"
REDIS_CMDLINE="redis-cli -h redis -p 6379 -a ${REDISPASS} --no-auth-warning"
fi
catch_non_zero "${REDIS_CMDLINE} LTRIM ACME_LOG 0 ${LOG_LINES}"
catch_non_zero "${REDIS_CMDLINE} LTRIM POSTFIX_MAILLOG 0 ${LOG_LINES}"

View File

@ -434,9 +434,9 @@ if __name__ == '__main__':
redis_slaveof_ip = os.getenv('REDIS_SLAVEOF_IP', '')
redis_slaveof_port = os.getenv('REDIS_SLAVEOF_PORT', '')
if "".__eq__(redis_slaveof_ip):
r = redis.StrictRedis(host=os.getenv('IPV4_NETWORK', '172.22.1') + '.249', decode_responses=True, port=6379, db=0)
r = redis.StrictRedis(host=os.getenv('IPV4_NETWORK', '172.22.1') + '.249', decode_responses=True, port=6379, db=0, password=os.environ['REDISPASS'])
else:
r = redis.StrictRedis(host=redis_slaveof_ip, decode_responses=True, port=redis_slaveof_port, db=0)
r = redis.StrictRedis(host=redis_slaveof_ip, decode_responses=True, port=redis_slaveof_port, db=0, password=os.environ['REDISPASS'])
r.ping()
pubsub = r.pubsub()
except Exception as ex:

View File

@ -0,0 +1,18 @@
FROM nginx:alpine
LABEL maintainer "The Infrastructure Company GmbH <info@servercow.de>"
ENV PIP_BREAK_SYSTEM_PACKAGES=1
RUN apk add --no-cache nginx \
python3 \
py3-pip && \
pip install --upgrade pip && \
pip install Jinja2
RUN mkdir -p /etc/nginx/includes
COPY ./bootstrap.py /
COPY ./docker-entrypoint.sh /
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]

View File

@ -0,0 +1,76 @@
import os
import subprocess
from jinja2 import Environment, FileSystemLoader
def sites_default_conf(env, template_vars):
config_name = "sites-default.conf"
template = env.get_template(f"{config_name}.j2")
config = template.render(template_vars)
with open(f"/etc/nginx/includes/{config_name}", "w") as f:
f.write(config)
def nginx_conf(env, template_vars):
config_name = "nginx.conf"
template = env.get_template(f"{config_name}.j2")
config = template.render(template_vars)
with open(f"/etc/nginx/{config_name}", "w") as f:
f.write(config)
def prepare_template_vars():
template_vars = {
'IPV4_NETWORK': os.getenv("IPV4_NETWORK", "172.22.1"),
'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': os.getenv("ADDITIONAL_SERVER_NAMES", "").replace(',', ' '),
'HTTP_PORT': os.getenv("HTTP_PORT", "80"),
'HTTPS_PORT': os.getenv("HTTPS_PORT", "443"),
'SOGOHOST': os.getenv("SOGOHOST", "sogo-mailcow"),
'RSPAMDHOST': os.getenv("RSPAMDHOST", "rspamd-mailcow"),
'PHPFPMHOST': os.getenv("PHPFPMHOST", "php-fpm-mailcow"),
}
ssl_dir = '/etc/ssl/mail/'
template_vars['valid_cert_dirs'] = []
for d in os.listdir(ssl_dir):
full_path = os.path.join(ssl_dir, d)
if not os.path.isdir(full_path):
continue
cert_path = os.path.join(full_path, 'cert.pem')
key_path = os.path.join(full_path, 'key.pem')
domains_path = os.path.join(full_path, 'domains')
if os.path.isfile(cert_path) and os.path.isfile(key_path) and os.path.isfile(domains_path):
with open(domains_path, 'r') as file:
domains = file.read().strip()
domains_list = domains.split()
if domains_list and template_vars["MAILCOW_HOSTNAME"] not in domains_list:
template_vars['valid_cert_dirs'].append({
'cert_path': full_path + '/',
'domains': domains
})
return template_vars
def main():
env = Environment(loader=FileSystemLoader('./etc/nginx/conf.d'))
# Render config
print("Render config")
template_vars = prepare_template_vars()
sites_default_conf(env, template_vars)
nginx_conf(env, template_vars)
# Validate config
print("Validate config")
subprocess.run(["nginx", "-qt"])
if __name__ == "__main__":
main()

View File

@ -0,0 +1,26 @@
#!/bin/sh
until ping ${REDISHOST} -c1 > /dev/null; do
echo "Waiting for Redis..."
sleep 1
done
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
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
until ping ${RSPAMDHOST} -c1 > /dev/null; do
echo "Waiting for Rspamd..."
sleep 1
done
fi
python3 /bootstrap.py
exec "$@"

View File

@ -16,7 +16,7 @@ else
REDIS_HOST="redis"
REDIS_PORT="6379"
fi
REDIS_CMDLINE="redis-cli -h ${REDIS_HOST} -p ${REDIS_PORT}"
REDIS_CMDLINE="redis-cli -h ${REDIS_HOST} -p ${REDIS_PORT} -a ${REDISPASS} --no-auth-warning"
until [[ $(${REDIS_CMDLINE} PING) == "PONG" ]]; do
echo "Waiting for Redis..."
@ -26,7 +26,7 @@ done
# Set redis session store
echo -n '
session.save_handler = redis
session.save_path = "tcp://'${REDIS_HOST}':'${REDIS_PORT}'"
session.save_path = "tcp://'${REDIS_HOST}':'${REDIS_PORT}'?auth='${REDISPASS}'"
' > /usr/local/etc/php/conf.d/session_store.ini
# Check mysql_upgrade (master and slave)

View File

@ -20,6 +20,7 @@ destination d_redis_ui_log {
host("`REDIS_SLAVEOF_IP`")
persist-name("redis1")
port(`REDIS_SLAVEOF_PORT`)
auth("`REDISPASS`")
command("LPUSH" "POSTFIX_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
);
};
@ -28,6 +29,7 @@ destination d_redis_f2b_channel {
host("`REDIS_SLAVEOF_IP`")
persist-name("redis2")
port(`REDIS_SLAVEOF_PORT`)
auth("`REDISPASS`")
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
);
};

View File

@ -20,6 +20,7 @@ destination d_redis_ui_log {
host("redis-mailcow")
persist-name("redis1")
port(6379)
auth("`REDISPASS`")
command("LPUSH" "POSTFIX_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
);
};
@ -28,6 +29,7 @@ destination d_redis_f2b_channel {
host("redis-mailcow")
persist-name("redis2")
port(6379)
auth("`REDISPASS`")
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
);
};

View File

@ -56,27 +56,29 @@ if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
cat <<EOF > /etc/rspamd/local.d/redis.conf
read_servers = "redis:6379";
write_servers = "${REDIS_SLAVEOF_IP}:${REDIS_SLAVEOF_PORT}";
password = "${REDISPASS}";
timeout = 10;
EOF
until [[ $(redis-cli -h redis-mailcow PING) == "PONG" ]]; do
until [[ $(redis-cli -h redis-mailcow -a ${REDISPASS} --no-auth-warning PING) == "PONG" ]]; do
echo "Waiting for Redis @redis-mailcow..."
sleep 2
done
until [[ $(redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} PING) == "PONG" ]]; do
until [[ $(redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} -a ${REDISPASS} --no-auth-warning PING) == "PONG" ]]; do
echo "Waiting for Redis @${REDIS_SLAVEOF_IP}..."
sleep 2
done
redis-cli -h redis-mailcow SLAVEOF ${REDIS_SLAVEOF_IP} ${REDIS_SLAVEOF_PORT}
redis-cli -h redis-mailcow -a ${REDISPASS} --no-auth-warning SLAVEOF ${REDIS_SLAVEOF_IP} ${REDIS_SLAVEOF_PORT}
else
cat <<EOF > /etc/rspamd/local.d/redis.conf
servers = "redis:6379";
password = "${REDISPASS}";
timeout = 10;
EOF
until [[ $(redis-cli -h redis-mailcow PING) == "PONG" ]]; do
until [[ $(redis-cli -h redis-mailcow -a ${REDISPASS} --no-auth-warning PING) == "PONG" ]]; do
echo "Waiting for Redis slave..."
sleep 2
done
redis-cli -h redis-mailcow SLAVEOF NO ONE
redis-cli -h redis-mailcow -a ${REDISPASS} --no-auth-warning SLAVEOF NO ONE
fi
# Provide additional lua modules

View File

@ -22,6 +22,7 @@ destination d_redis_ui_log {
host("`REDIS_SLAVEOF_IP`")
persist-name("redis1")
port(`REDIS_SLAVEOF_PORT`)
auth("`REDISPASS`")
command("LPUSH" "SOGO_LOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
);
};
@ -30,6 +31,7 @@ destination d_redis_f2b_channel {
host("`REDIS_SLAVEOF_IP`")
persist-name("redis2")
port(`REDIS_SLAVEOF_PORT`)
auth("`REDISPASS`")
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
);
};

View File

@ -22,6 +22,7 @@ destination d_redis_ui_log {
host("redis-mailcow")
persist-name("redis1")
port(6379)
auth("`REDISPASS`")
command("LPUSH" "SOGO_LOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
);
};
@ -30,6 +31,7 @@ destination d_redis_f2b_channel {
host("redis-mailcow")
persist-name("redis2")
port(6379)
auth("`REDISPASS`")
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
);
};

View File

@ -40,9 +40,9 @@ done
# Do not attempt to write to slave
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT}"
REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} -a ${REDISPASS} --no-auth-warning"
else
REDIS_CMDLINE="redis-cli -h redis -p 6379"
REDIS_CMDLINE="redis-cli -h redis -p 6379 -a ${REDISPASS} --no-auth-warning"
fi
until [[ $(${REDIS_CMDLINE} PING) == "PONG" ]]; do
@ -330,7 +330,7 @@ redis_checks() {
touch /tmp/redis-mailcow; echo "$(tail -50 /tmp/redis-mailcow)" > /tmp/redis-mailcow
host_ip=$(get_container_ip redis-mailcow)
err_c_cur=${err_count}
/usr/lib/nagios/plugins/check_tcp -4 -H redis-mailcow -p 6379 -E -s "PING\n" -q "QUIT" -e "PONG" 2>> /tmp/redis-mailcow 1>&2; err_count=$(( ${err_count} + $? ))
/usr/lib/nagios/plugins/check_tcp -4 -H redis-mailcow -p 6379 -E -s "AUTH ${REDISPASS}\nPING\n" -q "QUIT" -e "PONG" 2>> /tmp/redis-mailcow 1>&2; err_count=$(( ${err_count} + $? ))
[ ${err_c_cur} -eq ${err_count} ] && [ ! $((${err_count} - 1)) -lt 0 ] && err_count=$((${err_count} - 1)) diff_c=1
[ ${err_c_cur} -ne ${err_count} ] && diff_c=$(( ${err_c_cur} - ${err_count} ))
progress "Redis" ${THRESHOLD} $(( ${THRESHOLD} - ${err_count} )) ${diff_c}
@ -503,12 +503,12 @@ dovecot_repl_checks() {
err_count=0
diff_c=0
THRESHOLD=${DOVECOT_REPL_THRESHOLD}
D_REPL_STATUS=$(redis-cli -h redis -r GET DOVECOT_REPL_HEALTH)
D_REPL_STATUS=$(redis-cli -h redis -a ${REDISPASS} --no-auth-warning -r GET DOVECOT_REPL_HEALTH)
# Reduce error count by 2 after restarting an unhealthy container
trap "[ ${err_count} -gt 1 ] && err_count=$(( ${err_count} - 2 ))" USR1
while [ ${err_count} -lt ${THRESHOLD} ]; do
err_c_cur=${err_count}
D_REPL_STATUS=$(redis-cli --raw -h redis GET DOVECOT_REPL_HEALTH)
D_REPL_STATUS=$(redis-cli --raw -h redis -a ${REDISPASS} --no-auth-warning GET DOVECOT_REPL_HEALTH)
if [[ "${D_REPL_STATUS}" != "1" ]]; then
err_count=$(( ${err_count} + 1 ))
fi
@ -578,19 +578,19 @@ ratelimit_checks() {
err_count=0
diff_c=0
THRESHOLD=${RATELIMIT_THRESHOLD}
RL_LOG_STATUS=$(redis-cli -h redis LRANGE RL_LOG 0 0 | jq .qid)
RL_LOG_STATUS=$(redis-cli -h redis -a ${REDISPASS} --no-auth-warning LRANGE RL_LOG 0 0 | jq .qid)
# Reduce error count by 2 after restarting an unhealthy container
trap "[ ${err_count} -gt 1 ] && err_count=$(( ${err_count} - 2 ))" USR1
while [ ${err_count} -lt ${THRESHOLD} ]; do
err_c_cur=${err_count}
RL_LOG_STATUS_PREV=${RL_LOG_STATUS}
RL_LOG_STATUS=$(redis-cli -h redis LRANGE RL_LOG 0 0 | jq .qid)
RL_LOG_STATUS=$(redis-cli -h redis -a ${REDISPASS} --no-auth-warning LRANGE RL_LOG 0 0 | jq .qid)
if [[ ${RL_LOG_STATUS_PREV} != ${RL_LOG_STATUS} ]]; then
err_count=$(( ${err_count} + 1 ))
echo 'Last 10 applied ratelimits (may overlap with previous reports).' > /tmp/ratelimit
echo 'Full ratelimit buckets can be emptied by deleting the ratelimit hash from within mailcow UI (see /debug -> Protocols -> Ratelimit):' >> /tmp/ratelimit
echo >> /tmp/ratelimit
redis-cli --raw -h redis LRANGE RL_LOG 0 10 | jq . >> /tmp/ratelimit
redis-cli --raw -h redis -a ${REDISPASS} --no-auth-warning LRANGE RL_LOG 0 10 | jq . >> /tmp/ratelimit
fi
[ ${err_c_cur} -eq ${err_count} ] && [ ! $((${err_count} - 1)) -lt 0 ] && err_count=$((${err_count} - 1)) diff_c=1
[ ${err_c_cur} -ne ${err_count} ] && diff_c=$(( ${err_c_cur} - ${err_count} ))
@ -673,7 +673,7 @@ acme_checks() {
err_count=0
diff_c=0
THRESHOLD=${ACME_THRESHOLD}
ACME_LOG_STATUS=$(redis-cli -h redis GET ACME_FAIL_TIME)
ACME_LOG_STATUS=$(redis-cli -h redis -a ${REDISPASS} --no-auth-warning GET ACME_FAIL_TIME)
if [[ -z "${ACME_LOG_STATUS}" ]]; then
${REDIS_CMDLINE} SET ACME_FAIL_TIME 0
ACME_LOG_STATUS=0
@ -685,7 +685,7 @@ acme_checks() {
ACME_LOG_STATUS_PREV=${ACME_LOG_STATUS}
ACME_LC=0
until [[ ! -z ${ACME_LOG_STATUS} ]] || [ ${ACME_LC} -ge 3 ]; do
ACME_LOG_STATUS=$(redis-cli -h redis GET ACME_FAIL_TIME 2> /dev/null)
ACME_LOG_STATUS=$(redis-cli -h redis -a ${REDISPASS} --no-auth-warning GET ACME_FAIL_TIME 2> /dev/null)
sleep 3
ACME_LC=$((ACME_LC+1))
done

View File

@ -20,7 +20,7 @@ thread_cache_size = 8
query_cache_type = 0
query_cache_size = 0
max_heap_table_size = 48M
thread_stack = 128K
thread_stack = 192K
skip-host-cache
skip-name-resolve
log-warnings = 0

View File

@ -1,3 +0,0 @@
map_hash_max_size 256;
map_hash_bucket_size 256;

View File

@ -1,19 +0,0 @@
server {
listen 8081;
listen [::]:8081;
index index.php index.html;
server_name _;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /dynmaps;
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass phpfpm:9001;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}

View File

@ -1,242 +0,0 @@
include /etc/nginx/mime.types;
charset utf-8;
override_charset on;
server_tokens off;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
ssl_ecdh_curve X25519:X448:secp384r1:secp256k1;
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
ssl_session_tickets off;
add_header Strict-Transport-Security "max-age=15768000;";
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Permitted-Cross-Domain-Policies none;
add_header Referrer-Policy strict-origin;
index index.php index.html;
client_max_body_size 0;
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied off;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_min_length 256;
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript application/vnd.ms-fontobject application/x-font-ttf font/opentype image/svg+xml image/x-icon;
location ~ ^/(fonts|js|css|img)/ {
expires max;
add_header Cache-Control public;
}
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
fastcgi_hide_header X-Powered-By;
absolute_redirect off;
root /web;
location / {
try_files $uri $uri/ @strip-ext;
}
location /qhandler {
rewrite ^/qhandler/(.*)/(.*) /qhandler.php?action=$1&hash=$2;
}
location /edit {
rewrite ^/edit/(.*)/(.*) /edit.php?$1=$2;
}
location @strip-ext {
rewrite ^(.*)$ $1.php last;
}
location ~ ^/api/v1/(.*)$ {
try_files $uri $uri/ /json_api.php?query=$1&$args;
}
location ^~ /.well-known/acme-challenge/ {
allow all;
default_type "text/plain";
}
# If behind reverse proxy, forwards the correct IP
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;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
rewrite ^/.well-known/caldav$ /SOGo/dav/ permanent;
rewrite ^/.well-known/carddav$ /SOGo/dav/ permanent;
location ^~ /principals {
return 301 /SOGo/dav;
}
location ^~ /inc/lib/ {
deny all;
return 403;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass phpfpm:9002;
fastcgi_index index.php;
include /etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_read_timeout 3600;
fastcgi_send_timeout 3600;
}
location /rspamd/ {
location /rspamd/auth {
# proxy_pass is not inherited
proxy_pass http://rspamd:11334/auth;
proxy_intercept_errors on;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_redirect off;
error_page 401 /_rspamderror.php;
}
proxy_pass http://rspamd:11334/;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_redirect off;
}
location ~* ^/Autodiscover/Autodiscover.xml {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass phpfpm:9002;
include /etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
try_files /autodiscover.php =404;
}
location ~* ^/Autodiscover/Autodiscover.json {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass phpfpm:9002;
include /etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
try_files /autodiscover-json.php =404;
}
location ~ /(?:m|M)ail/(?:c|C)onfig-v1.1.xml {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass phpfpm:9002;
include /etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
try_files /autoconfig.php =404;
}
location /sogo-auth-verify {
internal;
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_set_header Content-Length "";
proxy_pass http://127.0.0.1:65510/sogo-auth;
proxy_pass_request_body off;
}
location ^~ /Microsoft-Server-ActiveSync {
include /etc/nginx/conf.d/includes/sogo_proxy_auth.conf;
include /etc/nginx/conf.d/sogo_eas.active;
proxy_connect_timeout 75;
proxy_send_timeout 3600;
proxy_read_timeout 3600;
proxy_buffer_size 128k;
proxy_buffers 64 512k;
proxy_busy_buffers_size 512k;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
client_body_buffer_size 512k;
client_max_body_size 0;
}
location ^~ /SOGo {
location ~* ^/SOGo/so/.*\.(xml|js|html|xhtml)$ {
include /etc/nginx/conf.d/includes/sogo_proxy_auth.conf;
include /etc/nginx/conf.d/sogo.active;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header x-webobjects-server-protocol HTTP/1.0;
proxy_set_header x-webobjects-remote-host $remote_addr;
proxy_set_header x-webobjects-server-name $server_name;
proxy_set_header x-webobjects-server-url $client_req_scheme://$http_host;
proxy_set_header x-webobjects-server-port $server_port;
proxy_hide_header Content-Type;
add_header Content-Type text/plain;
break;
}
include /etc/nginx/conf.d/includes/sogo_proxy_auth.conf;
include /etc/nginx/conf.d/sogo.active;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header x-webobjects-server-protocol HTTP/1.0;
proxy_set_header x-webobjects-remote-host $remote_addr;
proxy_set_header x-webobjects-server-name $server_name;
proxy_set_header x-webobjects-server-url $client_req_scheme://$http_host;
proxy_set_header x-webobjects-server-port $server_port;
proxy_buffer_size 128k;
proxy_buffers 64 512k;
proxy_busy_buffers_size 512k;
proxy_send_timeout 3600;
proxy_read_timeout 3600;
client_body_buffer_size 128k;
client_max_body_size 0;
break;
}
location ~* /sogo$ {
return 301 $client_req_scheme://$http_host/SOGo;
}
location /SOGo.woa/WebServerResources/ {
alias /usr/lib/GNUstep/SOGo/WebServerResources/;
}
location /.woa/WebServerResources/ {
alias /usr/lib/GNUstep/SOGo/WebServerResources/;
}
location /SOGo/WebServerResources/ {
alias /usr/lib/GNUstep/SOGo/WebServerResources/;
}
location (^/SOGo/so/ControlPanel/Products/[^/]*UI/Resources/.*\.(jpg|png|gif|css|js)$) {
alias /usr/lib/GNUstep/SOGo/$1.SOGo/Resources/$2;
}
include /etc/nginx/conf.d/site.*.custom;
error_page 502 @awaitingupstream;
location @awaitingupstream {
rewrite ^(.*)$ /_status.502.html break;
}
location ~ ^/cache/(.*)$ {
try_files $uri $uri/ /resource.php?file=$1;
}

View File

@ -1,8 +0,0 @@
auth_request /sogo-auth-verify;
auth_request_set $user $upstream_http_x_user;
auth_request_set $auth $upstream_http_x_auth;
auth_request_set $auth_type $upstream_http_x_auth_type;
proxy_set_header x-webobjects-remote-user "$user";
proxy_set_header Authorization "$auth";
proxy_set_header x-webobjects-auth-type "$auth_type";

View File

@ -1,23 +0,0 @@
server {
listen 9082 ssl http2;
ssl_certificate /etc/ssl/mail/cert.pem;
ssl_certificate_key /etc/ssl/mail/key.pem;
index mailcowauth.php;
server_name _;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /mailcowauth;
client_max_body_size 10M;
location ~ \.php$ {
client_max_body_size 10M;
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass phpfpm:9001;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}

View File

@ -1,19 +0,0 @@
server {
listen 9081;
index index.php index.html;
server_name _;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /meta_exporter;
client_max_body_size 10M;
location ~ \.php$ {
client_max_body_size 10M;
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass phpfpm:9001;
fastcgi_index pipe.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}

View File

@ -0,0 +1,142 @@
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
# map-size.conf:
map_hash_max_size 256;
map_hash_bucket_size 256;
# site.conf:
proxy_cache_path /tmp levels=1:2 keys_zone=sogo:10m inactive=24h max_size=1g;
server_names_hash_max_size 512;
server_names_hash_bucket_size 128;
map $http_x_forwarded_proto $client_req_scheme {
default $scheme;
https https;
}
# Default
server {
listen 127.0.0.1:65510; # sogo-auth verify internal
listen {{ HTTP_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%};
listen [::]:{{ HTTP_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%};
listen {{ HTTPS_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%} ssl;
listen [::]:{{ HTTPS_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%} ssl;
http2 on;
ssl_certificate /etc/ssl/mail/cert.pem;
ssl_certificate_key /etc/ssl/mail/key.pem;
server_name {{ MAILCOW_HOSTNAME }} autodiscover.* autoconfig.* {{ ADDITIONAL_SERVER_NAMES }};
include /etc/nginx/includes/sites-default.conf;
}
# rspamd dynmaps:
server {
listen 8081;
listen [::]:8081;
index index.php index.html;
server_name _;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /dynmaps;
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass {{ PHPFPMHOST }}:9001;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
# rspamd meta_exporter:
server {
listen 9081;
index index.php index.html;
server_name _;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /meta_exporter;
client_max_body_size 10M;
location ~ \.php$ {
client_max_body_size 10M;
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass {{ PHPFPMHOST }}:9001;
fastcgi_index pipe.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
server {
listen 9082 ssl http2;
ssl_certificate /etc/ssl/mail/cert.pem;
ssl_certificate_key /etc/ssl/mail/key.pem;
index mailcowauth.php;
server_name _;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /mailcowauth;
client_max_body_size 10M;
location ~ \.php$ {
client_max_body_size 10M;
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass phpfpm:9001;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
{% for cert in valid_cert_dirs %}
server {
listen {{ HTTP_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%};
listen [::]:{{ HTTP_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%};
listen {{ HTTPS_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%} ssl;
listen [::]:{{ HTTPS_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%} ssl;
http2 on;
ssl_certificate {{ cert.cert_path }}cert.pem;
ssl_certificate_key {{ cert.cert_path }}key.pem;
server_name {{ cert.domains }};
include /etc/nginx/includes/sites-default.conf;
}
{% endfor %}
}

View File

@ -1,10 +0,0 @@
proxy_cache_path /tmp levels=1:2 keys_zone=sogo:10m inactive=24h max_size=1g;
server_names_hash_max_size 512;
server_names_hash_bucket_size 128;
map $http_x_forwarded_proto $client_req_scheme {
default $scheme;
https https;
}
include /etc/nginx/conf.d/sites.active;

View File

@ -0,0 +1,276 @@
include /etc/nginx/mime.types;
charset utf-8;
override_charset on;
server_tokens off;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
ssl_ecdh_curve X25519:X448:secp384r1:secp256k1;
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
ssl_session_tickets off;
add_header Strict-Transport-Security "max-age=15768000;";
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Permitted-Cross-Domain-Policies none;
add_header Referrer-Policy strict-origin;
index index.php index.html;
client_max_body_size 0;
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied off;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_min_length 256;
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript application/vnd.ms-fontobject application/x-font-ttf font/opentype image/svg+xml image/x-icon;
location ~ ^/(fonts|js|css|img)/ {
expires max;
add_header Cache-Control public;
}
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
fastcgi_hide_header X-Powered-By;
absolute_redirect off;
root /web;
# If behind reverse proxy, forwards the correct IP
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;
{% 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;
location @strip-ext {
rewrite ^(.*)$ $1.php last;
}
location ^~ /inc/lib/ {
deny all;
return 403;
}
location ^~ /.well-known/acme-challenge/ {
allow all;
default_type "text/plain";
}
rewrite ^/.well-known/caldav$ /SOGo/dav/ permanent;
rewrite ^/.well-known/carddav$ /SOGo/dav/ permanent;
location / {
try_files $uri $uri/ @strip-ext;
}
location /qhandler {
rewrite ^/qhandler/(.*)/(.*) /qhandler.php?action=$1&hash=$2;
}
location /edit {
rewrite ^/edit/(.*)/(.*) /edit.php?$1=$2;
}
location ~ ^/api/v1/(.*)$ {
try_files $uri $uri/ /json_api.php?query=$1&$args;
}
location ~ ^/cache/(.*)$ {
try_files $uri $uri/ /resource.php?file=$1;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass {{ PHPFPMHOST }}:9002;
fastcgi_index index.php;
include /etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_read_timeout 3600;
fastcgi_send_timeout 3600;
}
location ~* ^/Autodiscover/Autodiscover.xml {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass {{ PHPFPMHOST }}:9002;
include /etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
try_files /autodiscover.php =404;
}
location ~* ^/Autodiscover/Autodiscover.json {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass {{ PHPFPMHOST }}:9002;
include /etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
try_files /autodiscover-json.php =404;
}
location ~ /(?:m|M)ail/(?:c|C)onfig-v1.1.xml {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass {{ PHPFPMHOST }}:9002;
include /etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
try_files /autoconfig.php =404;
}
{% if not SKIP_RSPAMD %}
location /rspamd/ {
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 %}
{% if not SKIP_SOGO %}
location ^~ /principals {
return 301 /SOGo/dav;
}
location /sogo-auth-verify {
internal;
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_set_header Content-Length "";
proxy_pass http://127.0.0.1:65510/sogo-auth;
proxy_pass_request_body off;
}
location ^~ /Microsoft-Server-ActiveSync {
auth_request /sogo-auth-verify;
auth_request_set $user $upstream_http_x_user;
auth_request_set $auth $upstream_http_x_auth;
auth_request_set $auth_type $upstream_http_x_auth_type;
proxy_set_header x-webobjects-remote-user "$user";
proxy_set_header Authorization "$auth";
proxy_set_header x-webobjects-auth-type "$auth_type";
proxy_pass http://{{ SOGOHOST }}:20000/SOGo/Microsoft-Server-ActiveSync;
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_connect_timeout 75;
proxy_send_timeout 3600;
proxy_read_timeout 3600;
proxy_buffer_size 128k;
proxy_buffers 64 512k;
proxy_busy_buffers_size 512k;
proxy_set_header Host $http_host;
client_body_buffer_size 512k;
client_max_body_size 0;
}
location ^~ /SOGo {
location ~* ^/SOGo/so/.*\.(xml|js|html|xhtml)$ {
auth_request /sogo-auth-verify;
auth_request_set $user $upstream_http_x_user;
auth_request_set $auth $upstream_http_x_auth;
auth_request_set $auth_type $upstream_http_x_auth_type;
proxy_set_header x-webobjects-remote-user "$user";
proxy_set_header Authorization "$auth";
proxy_set_header x-webobjects-auth-type "$auth_type";
proxy_pass http://{{ SOGOHOST }}:20000;
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_set_header Host $http_host;
proxy_set_header x-webobjects-server-protocol HTTP/1.0;
proxy_set_header x-webobjects-remote-host $remote_addr;
proxy_set_header x-webobjects-server-name $server_name;
proxy_set_header x-webobjects-server-url $client_req_scheme://$http_host;
proxy_set_header x-webobjects-server-port $server_port;
proxy_hide_header Content-Type;
add_header Content-Type text/plain;
break;
}
auth_request /sogo-auth-verify;
auth_request_set $user $upstream_http_x_user;
auth_request_set $auth $upstream_http_x_auth;
auth_request_set $auth_type $upstream_http_x_auth_type;
proxy_set_header x-webobjects-remote-user "$user";
proxy_set_header Authorization "$auth";
proxy_set_header x-webobjects-auth-type "$auth_type";
proxy_pass http://{{ SOGOHOST }}:20000;
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_set_header Host $http_host;
proxy_set_header x-webobjects-server-protocol HTTP/1.0;
proxy_set_header x-webobjects-remote-host $remote_addr;
proxy_set_header x-webobjects-server-name $server_name;
proxy_set_header x-webobjects-server-url $client_req_scheme://$http_host;
proxy_set_header x-webobjects-server-port $server_port;
proxy_buffer_size 128k;
proxy_buffers 64 512k;
proxy_busy_buffers_size 512k;
proxy_send_timeout 3600;
proxy_read_timeout 3600;
client_body_buffer_size 128k;
client_max_body_size 0;
break;
}
location ~* /sogo$ {
return 301 $client_req_scheme://$http_host/SOGo;
}
location /SOGo.woa/WebServerResources/ {
alias /usr/lib/GNUstep/SOGo/WebServerResources/;
}
location /.woa/WebServerResources/ {
alias /usr/lib/GNUstep/SOGo/WebServerResources/;
}
location /SOGo/WebServerResources/ {
alias /usr/lib/GNUstep/SOGo/WebServerResources/;
}
location (^/SOGo/so/ControlPanel/Products/[^/]*UI/Resources/.*\.(jpg|png|gif|css|js)$) {
alias /usr/lib/GNUstep/SOGo/$1.SOGo/Resources/$2;
}
{% endif %}
include /etc/nginx/conf.d/site.*.custom;
error_page 502 @awaitingupstream;
location @awaitingupstream {
rewrite ^(.*)$ /_status.502.html break;
}
location ~* \.php$ {
return 404;
}
location ~* \.twig$ {
return 404;
}

View File

@ -1,2 +0,0 @@
listen ${HTTP_PORT};
listen [::]:${HTTP_PORT};

View File

@ -1,3 +0,0 @@
listen ${HTTPS_PORT} ssl;
listen [::]:${HTTPS_PORT} ssl;
http2 on;

View File

@ -1 +0,0 @@
echo "server_name ${MAILCOW_HOSTNAME} autodiscover.* autoconfig.* $(echo ${ADDITIONAL_SERVER_NAMES} | tr ',' ' ');"

View File

@ -1,38 +0,0 @@
echo '
server {
listen 127.0.0.1:65510;
include /etc/nginx/conf.d/listen_plain.active;
include /etc/nginx/conf.d/listen_ssl.active;
ssl_certificate /etc/ssl/mail/cert.pem;
ssl_certificate_key /etc/ssl/mail/key.pem;
include /etc/nginx/conf.d/server_name.active;
include /etc/nginx/conf.d/includes/site-defaults.conf;
}
';
for cert_dir in /etc/ssl/mail/*/ ; do
if [[ ! -f ${cert_dir}domains ]] || [[ ! -f ${cert_dir}cert.pem ]] || [[ ! -f ${cert_dir}key.pem ]]; then
continue
fi
# do not create vhost for default-certificate. the cert is already in the default server listen
domains="$(cat ${cert_dir}domains | sed -e 's/^[[:space:]]*//')"
case "${domains}" in
"") continue;;
"${MAILCOW_HOSTNAME}"*) continue;;
esac
echo -n '
server {
include /etc/nginx/conf.d/listen_ssl.active;
ssl_certificate '${cert_dir}'cert.pem;
ssl_certificate_key '${cert_dir}'key.pem;
';
echo -n '
server_name '${domains}';
include /etc/nginx/conf.d/includes/site-defaults.conf;
}
';
done

View File

@ -1 +0,0 @@
proxy_pass http://${IPV4_NETWORK}.248:20000;

View File

@ -1,5 +0,0 @@
if printf "%s\n" "${SKIP_SOGO}" | grep -E '^([yY][eE][sS]|[yY])+$' >/dev/null; then
echo "return 410;"
else
echo "proxy_pass http://${IPV4_NETWORK}.248:20000/SOGo/Microsoft-Server-ActiveSync;"
fi

View File

@ -1,6 +1,6 @@
# Whitelist generated by Postwhite v3.4 on Fri Nov 1 00:18:49 UTC 2024
# Whitelist generated by Postwhite v3.4 on Sun Dec 1 00:21:36 UTC 2024
# https://github.com/stevejenkins/postwhite/
# 2013 total rules
# 1971 total rules
2a00:1450:4000::/36 permit
2a01:111:f400::/48 permit
2a01:111:f403:8000::/50 permit
@ -19,8 +19,7 @@
8.20.114.31 permit
8.25.194.0/23 permit
8.25.196.0/23 permit
8.39.54.0/23 permit
8.40.222.0/23 permit
10.162.0.0/16 permit
12.130.86.238 permit
13.110.208.0/21 permit
13.110.209.0/24 permit
@ -31,9 +30,11 @@
15.200.21.50 permit
15.200.44.248 permit
15.200.201.185 permit
17.41.0.0/16 permit
17.57.155.0/24 permit
17.57.156.0/24 permit
17.58.0.0/16 permit
17.142.0.0/15 permit
17.143.234.140/30 permit
18.156.89.250 permit
18.157.243.190 permit
@ -116,7 +117,6 @@
40.233.64.216 permit
40.233.83.78 permit
40.233.88.28 permit
43.228.184.0/22 permit
44.206.138.57 permit
44.217.45.156 permit
44.236.56.93 permit
@ -325,7 +325,6 @@
65.110.161.77 permit
65.123.29.213 permit
65.123.29.220 permit
65.154.166.0/24 permit
65.212.180.36 permit
66.102.0.0/20 permit
66.119.150.192/26 permit
@ -1114,10 +1113,8 @@
98.139.245.212/31 permit
99.78.197.208/28 permit
99.83.190.102 permit
103.2.140.0/22 permit
103.9.96.0/22 permit
103.28.42.0/24 permit
103.47.204.0/22 permit
103.151.192.0/23 permit
103.168.172.128/27 permit
104.43.243.237 permit
@ -1285,9 +1282,6 @@
117.120.16.0/21 permit
119.42.242.52/31 permit
119.42.242.156 permit
121.244.91.48 permit
121.244.91.52 permit
122.15.156.182 permit
123.126.78.64/29 permit
124.108.96.24/31 permit
124.108.96.28/31 permit
@ -1348,19 +1342,7 @@
134.170.141.64/26 permit
134.170.143.0/24 permit
134.170.174.0/24 permit
135.84.80.0/24 permit
135.84.81.0/24 permit
135.84.82.0/24 permit
135.84.83.0/24 permit
135.84.216.0/22 permit
136.143.160.0/24 permit
136.143.161.0/24 permit
136.143.162.0/24 permit
136.143.178.49 permit
136.143.182.0/23 permit
136.143.184.0/24 permit
136.143.188.0/24 permit
136.143.190.0/23 permit
136.147.128.0/20 permit
136.147.135.0/24 permit
136.147.176.0/20 permit
@ -1375,7 +1357,6 @@
139.138.46.219 permit
139.138.57.55 permit
139.138.58.119 permit
139.167.79.86 permit
139.180.17.0/24 permit
140.238.148.191 permit
141.148.159.229 permit
@ -1410,6 +1391,7 @@
146.20.215.0/24 permit
146.20.215.182 permit
146.88.28.0/24 permit
147.154.32.0/25 permit
147.243.1.47 permit
147.243.1.48 permit
147.243.1.153 permit
@ -1450,7 +1432,6 @@
157.151.208.65 permit
157.255.1.64/29 permit
158.101.211.207 permit
158.120.80.0/21 permit
158.247.16.0/20 permit
159.92.154.0/24 permit
159.92.155.0/24 permit
@ -1478,6 +1459,11 @@
161.38.204.0/22 permit
161.71.32.0/19 permit
161.71.64.0/20 permit
162.88.4.0/23 permit
162.88.8.0/24 permit
162.88.24.0/24 permit
162.88.25.0/24 permit
162.88.36.0/24 permit
162.247.216.0/22 permit
163.47.180.0/22 permit
163.114.130.16 permit
@ -1486,7 +1472,6 @@
163.114.135.16 permit
164.152.23.32 permit
164.177.132.168/30 permit
165.173.128.0/24 permit
166.78.68.0/22 permit
166.78.68.221 permit
166.78.69.169 permit
@ -1515,12 +1500,6 @@
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
170.10.68.0/22 permit
170.10.128.0/24 permit
170.10.129.0/24 permit
170.10.132.56/29 permit
@ -1626,6 +1605,7 @@
192.18.139.154 permit
192.18.145.36 permit
192.18.152.58 permit
192.29.103.128/25 permit
192.30.252.0/22 permit
192.161.144.0/20 permit
192.162.87.0/24 permit
@ -1651,14 +1631,6 @@
195.234.109.226 permit
195.245.230.0/23 permit
198.2.128.0/18 permit
198.2.128.0/24 permit
198.2.132.0/22 permit
198.2.136.0/23 permit
198.2.145.0/24 permit
198.2.177.0/24 permit
198.2.178.0/23 permit
198.2.180.0/24 permit
198.2.186.0/23 permit
198.21.0.0/21 permit
198.37.144.0/20 permit
198.37.152.186 permit
@ -1678,15 +1650,7 @@
199.16.156.0/22 permit
199.33.145.1 permit
199.33.145.32 permit
199.34.22.36 permit
199.59.148.0/22 permit
199.67.80.2 permit
199.67.80.20 permit
199.67.82.2 permit
199.67.82.20 permit
199.67.84.0/24 permit
199.67.86.0/24 permit
199.67.88.0/24 permit
199.101.161.130 permit
199.101.162.0/25 permit
199.122.120.0/21 permit
@ -1698,7 +1662,6 @@
202.165.102.47 permit
202.177.148.100 permit
202.177.148.110 permit
203.31.36.0/22 permit
203.32.4.25 permit
203.55.21.0/24 permit
203.81.17.0/24 permit
@ -1744,19 +1707,13 @@
204.92.114.187 permit
204.92.114.203 permit
204.92.114.204/31 permit
204.141.32.0/23 permit
204.141.42.0/23 permit
204.220.160.0/21 permit
204.220.168.0/21 permit
204.220.176.0/20 permit
204.232.168.0/24 permit
205.139.110.0/24 permit
205.201.128.0/20 permit
205.201.131.128/25 permit
205.201.134.128/25 permit
205.201.136.0/23 permit
205.201.137.229 permit
205.201.139.0/24 permit
205.207.104.0/22 permit
205.220.167.17 permit
205.220.167.98 permit
@ -1784,7 +1741,6 @@
207.46.132.128/27 permit
207.46.198.0/25 permit
207.46.200.0/27 permit
207.58.147.64/28 permit
207.67.38.0/24 permit
207.67.98.192/27 permit
207.68.176.0/26 permit
@ -1831,6 +1787,8 @@
208.74.204.5 permit
208.74.204.9 permit
208.75.120.0/22 permit
208.76.62.0/24 permit
208.76.63.0/24 permit
208.82.237.96/29 permit
208.82.237.104/31 permit
208.82.238.96/29 permit
@ -1930,7 +1888,6 @@
213.199.177.0/26 permit
216.17.150.242 permit
216.17.150.251 permit
216.22.15.224/27 permit
216.24.224.0/20 permit
216.39.60.154/31 permit
216.39.60.156/30 permit
@ -1973,7 +1930,10 @@
216.136.162.65 permit
216.136.162.120/29 permit
216.136.168.80/28 permit
216.139.64.0/19 permit
216.145.221.0/24 permit
216.146.32.0/24 permit
216.146.33.0/24 permit
216.198.0.0/18 permit
216.203.30.55 permit
216.203.33.178/31 permit
@ -1999,8 +1959,6 @@
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:f8b0:4000::/36 permit
2620:109:c003:104::/64 permit
2620:109:c003:104::215 permit

7
data/conf/redis/redis-conf.sh Executable file
View File

@ -0,0 +1,7 @@
#!/bin/sh
cat <<EOF > /redis.conf
requirepass $REDISPASS
EOF
exec redis-server /redis.conf

View File

@ -25,6 +25,7 @@ catch (PDOException $e) {
// Init Redis
$redis = new Redis();
$redis->connect('redis-mailcow', 6379);
$redis->auth(getenv("REDISPASS"));
function parse_email($email) {
if(!filter_var($email, FILTER_VALIDATE_EMAIL)) return false;

View File

@ -4,6 +4,7 @@ ini_set('error_reporting', 0);
$redis = new Redis();
$redis->connect('redis-mailcow', 6379);
$redis->auth(getenv("REDISPASS"));
function in_net($addr, $net) {
$net = explode('/', $net);

View File

@ -24,6 +24,7 @@ catch (PDOException $e) {
// Init Redis
$redis = new Redis();
$redis->connect('redis-mailcow', 6379);
$redis->auth(getenv("REDISPASS"));
// Functions
function parse_email($email) {

View File

@ -14,6 +14,7 @@ try {
else {
$redis->connect('redis-mailcow', 6379);
}
$redis->auth(getenv("REDISPASS"));
}
catch (Exception $e) {
exit;

View File

@ -24,6 +24,7 @@ catch (PDOException $e) {
// Init Redis
$redis = new Redis();
$redis->connect('redis-mailcow', 6379);
$redis->auth(getenv("REDISPASS"));
// Functions
function parse_email($email) {

View File

@ -7,6 +7,7 @@ try {
else {
$redis->connect('redis-mailcow', 6379);
}
$redis->auth(getenv("REDISPASS"));
}
catch (Exception $e) {
exit;

View File

@ -106,7 +106,7 @@ $template_data = [
'all_domains' => $all_domains,
'mailboxes' => $mailboxes,
'f2b_data' => $f2b_data,
'f2b_banlist_url' => getBaseUrl() . "/api/v1/get/fail2ban/banlist/" . $f2b_data['banlist_id'],
'f2b_banlist_url' => getBaseUrl() . "/f2b-banlist?id=" . $f2b_data['banlist_id'],
'q_data' => quarantine('settings'),
'qn_data' => quota_notification('get'),
'pw_reset_data' => reset_password('get_notification'),

View File

@ -19,6 +19,7 @@ try {
else {
$redis->connect('redis-mailcow', 6379);
}
$redis->auth(getenv("REDISPASS"));
}
catch (Exception $e) {
exit;

11
data/web/f2b-banlist.php Normal file
View File

@ -0,0 +1,11 @@
<?php
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php';
if (isset($_GET['id'])) {
header('Content-Type: text/plain');
echo fail2ban('banlist', 'get', $_GET['id']);
} else {
header('HTTP/1.1 404 Not Found');
exit;
}

View File

@ -26,7 +26,7 @@ function dkim($_action, $_data = null, $privkey = false) {
);
continue;
}
if (!ctype_alnum(str_replace(['-', '_'], '', $dkim_selector))) {
if (!ctype_alnum(str_replace(['-', '_', '.'], '', $dkim_selector))) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data),
@ -188,7 +188,7 @@ function dkim($_action, $_data = null, $privkey = false) {
return false;
}
}
if (!ctype_alnum($dkim_selector)) {
if (!ctype_alnum(str_replace(['-', '_', '.'], '', $dkim_selector))) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data),

View File

@ -2917,6 +2917,8 @@ function reset_password($action, $data = null) {
':username' => $username
));
update_sogo_static_view($username);
$_SESSION['return'][] = array(
'type' => 'success',
'log' => array(__FUNCTION__, $action, $_data_log),

View File

@ -3440,7 +3440,12 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
'old_maildir' => $domain . '/' . $old_local_part,
'new_maildir' => $domain . '/' . $new_local_part
);
docker('post', 'dovecot-mailcow', 'exec', $exec_fields);
if (getenv("CLUSTERMODE") == "replication") {
// broadcast to each dovecot container
docker('broadcast', 'dovecot-mailcow', 'exec', $exec_fields);
} else {
docker('post', 'dovecot-mailcow', 'exec', $exec_fields);
}
// rename username in sogo
$exec_fields = array(

View File

@ -3,7 +3,7 @@ function init_db_schema() {
try {
global $pdo;
$db_version = "15082024_1212";
$db_version = "20112024_1105";
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
@ -111,6 +111,10 @@ function init_db_schema() {
"c_name" => "VARCHAR(255) NOT NULL",
"c_password" => "VARCHAR(255) NOT NULL DEFAULT ''",
"c_cn" => "VARCHAR(255)",
"c_l" => "VARCHAR(255)",
"c_o" => "VARCHAR(255)",
"c_ou" => "VARCHAR(255)",
"c_telephonenumber" => "VARCHAR(255)",
"mail" => "VARCHAR(255) NOT NULL",
// TODO -> use TEXT and check if SOGo login breaks on empty aliases
"aliases" => "TEXT NOT NULL",

View File

@ -66,6 +66,7 @@ try {
else {
$redis->connect('redis-mailcow', 6379);
}
$redis->auth(getenv("REDISPASS"));
}
catch (Exception $e) {
// Stop when redis is not available

View File

@ -692,8 +692,8 @@ jQuery(function($){
} else if (item.attributes.rl_frame === "d"){
item.attributes.rl_frame = lang_rl.day;
}
item.attributes.rl_value = escapeHtml(item.attributes.rl_value);
item.attributes.rl_value = (!item.attributes.rl_value) ? "∞" : escapeHtml(item.attributes.rl_value);
item.attributes.ratelimit = item.attributes.rl_value + " " + item.attributes.rl_frame;
if (item.template.toLowerCase() == "default"){
item.action = '<div class="btn-group">' +
@ -817,14 +817,8 @@ jQuery(function($){
}
},
{
title: 'rl_frame',
data: 'attributes.rl_frame',
defaultContent: '',
class: 'none',
},
{
title: 'rl_value',
data: 'attributes.rl_value',
title: lang_edit.ratelimit,
data: 'attributes.ratelimit',
defaultContent: '',
class: 'none',
},
@ -893,7 +887,10 @@ jQuery(function($){
item.quota.value = humanFileSize(item.quota_used) + "/" + item.quota.value;
item.max_quota_for_mbox = humanFileSize(item.max_quota_for_mbox);
item.last_mail_login = item.last_imap_login + '/' + item.last_pop3_login + '/' + item.last_smtp_login + '/' + item.last_sso_login;
item.last_mail_login = (item.attributes.imap_access == 1 ? '<div class="text-start badge bg-info mb-2" style="min-width: 70px;">IMAP @ ' + unix_time_format(Number(item.last_imap_login)) + '</div><br>' : '') +
(item.attributes.pop3_access == 1 ? '<div class="text-start badge bg-info mb-2" style="min-width: 70px;">POP3 @ ' + unix_time_format(Number(item.last_pop3_login)) + '</div><br>' : '') +
(item.attributes.smtp_access == 1 ? '<div class="text-start badge bg-info mb-2" style="min-width: 70px;">SMTP @ ' + unix_time_format(Number(item.last_smtp_login)) + '</div><br>' : '') +
'<div class="text-start badge bg-info" style="min-width: 70px;">SSO @ ' + unix_time_format(Number(item.last_sso_login)) + '</div>';
/*
if (!item.rl) {
item.rl = '∞';
@ -1009,14 +1006,7 @@ jQuery(function($){
data: 'last_mail_login',
searchable: false,
defaultContent: '',
responsivePriority: 7,
render: function (data, type) {
res = data.split("/");
return '<div class="text-start badge bg-info mb-2" style="min-width: 70px;">IMAP @ ' + unix_time_format(Number(res[0])) + '</div><br>' +
'<div class="text-start badge bg-info mb-2" style="min-width: 70px;">POP3 @ ' + unix_time_format(Number(res[1])) + '</div><br>' +
'<div class="text-start badge bg-info mb-2" style="min-width: 70px;">SMTP @ ' + unix_time_format(Number(res[2])) + '</div><br>' +
'<div class="text-start badge bg-info" style="min-width: 70px;">SSO @ ' + unix_time_format(Number(res[3])) + '</div>';
}
responsivePriority: 7
},
{
title: lang.last_pw_change,
@ -1191,7 +1181,8 @@ jQuery(function($){
} else if (item.attributes.rl_frame === "d"){
item.attributes.rl_frame = lang_rl.day;
}
item.attributes.rl_value = escapeHtml(item.attributes.rl_value);
item.attributes.rl_value = (!item.attributes.rl_value) ? "∞" : escapeHtml(item.attributes.rl_value);
item.attributes.ratelimit = item.attributes.rl_value + " " + item.attributes.rl_frame;
item.attributes.quota = humanFileSize(item.attributes.quota);
@ -1336,14 +1327,8 @@ jQuery(function($){
}
},
{
title: "rl_frame",
data: 'attributes.rl_frame',
defaultContent: '',
class: 'none',
},
{
title: 'rl_value',
data: 'attributes.rl_value',
title: lang_edit.ratelimit,
data: 'attributes.ratelimit',
defaultContent: '',
class: 'none',
},

View File

@ -510,16 +510,6 @@ if (isset($_GET['query'])) {
$_SESSION['challenge'] = $WebAuthn->getChallenge();
return;
break;
case "fail2ban":
if (!isset($_SESSION['mailcow_cc_role'])){
switch ($object) {
case 'banlist':
header('Content-Type: text/plain');
echo fail2ban('banlist', 'get', $extra);
break;
}
}
break;
}
if (isset($_SESSION['mailcow_cc_role'])) {
switch ($category) {
@ -1431,10 +1421,6 @@ if (isset($_GET['query'])) {
break;
case "fail2ban":
switch ($object) {
case 'banlist':
header('Content-Type: text/plain');
echo fail2ban('banlist', 'get', $extra);
break;
default:
$data = fail2ban('get');
process_get_return($data);

View File

@ -207,7 +207,7 @@
"include_exclude_info": "Par défaut - sans sélection - <b>toutes les boîte de réception</b> sont adressées",
"includes": "Inclure ces destinataires",
"last_applied": "Dernière application",
"license_info": "Une licence n’est pas requise, mais contribue au développement.<br><a href=\"https://www.servercow.de/mailcow?lang=en#sal\" target=\"_blank\" alt=\"SAL order\">Enregistrer votre GUID ici</a> or <a href=\"https://www.servercow.de/mailcow?lang=en#support\" target=\"_blank\" alt=\"Support order\">acheter le support pour votre intallation Mailcow.</a>",
"license_info": "Une licence n’est pas requise, mais contribue au développement.<br><a href=\"https://www.servercow.de/mailcow?lang=en#sal\" target=\"_blank\" alt=\"SAL order\">Enregistrer votre GUID ici</a> ou <a href=\"https://www.servercow.de/mailcow?lang=en#support\" target=\"_blank\" alt=\"Support order\">acheter le support pour votre installation Mailcow.</a>",
"link": "Lien",
"loading": "Veuillez patienter…",
"logo_info": "Votre image sera redimensionnée à une hauteur de 40 pixels pour la barre de navigation du haut et à un maximum de 250 pixels en largeur pour la page d'accueil. Un graphique extensible est fortement recommandé.",

View File

@ -14,6 +14,7 @@
"prohibited": "Запрещено правилами ACL",
"protocol_access": "Настройка разрешенных протоколов",
"pushover": "Pushover API",
"pw_reset": "Разрешить пользователям mailcow восстановление паролей",
"quarantine": "Карантин - действия",
"quarantine_attachments": "Карантин - вложения",
"quarantine_category": "Категория уведомлений о спаме",
@ -28,8 +29,7 @@
"spam_score": "Политика фильтрации спама",
"syncjobs": "Задания синхронизации",
"tls_policy": "Политика шифрования",
"unlimited_quota": "Неограниченная квота для почтовых ящиков",
"pw_reset": "Разрешить сброс пароля пользователей mailcow"
"unlimited_quota": "Неограниченная квота для почтовых ящиков"
},
"add": {
"activate_filter_warn": "Активация этого фильтра отключит все остальные фильтры этого типа.",
@ -42,13 +42,14 @@
"alias_domain": "Псевдоним домена",
"alias_domain_info": "<small>Действительные имена доменов, раздёленные запятыми.</small>",
"app_name": "Название приложения",
"app_passwd_protocols": "Разрешенные протоколы для пароля приложения",
"app_password": "Добавить пароль приложения",
"automap": "Автоматическое слияние папок (\"Sent items\", \"Sent\" => \"Sent\" etc.)",
"backup_mx_options": "Параметры резервного MX",
"bcc_dest_format": "Место назначения BCC должно быть единственным действительным адресом электронной почты.<br>Если вам нужно отправить копию на несколько адресов - используйте псевдоним.",
"comment_info": "Приватный комментарий не виден пользователям, а публичный - отображается рядом с псевдонимом в личном кабинете пользователя.",
"custom_params": "Пользовательские параметры",
"custom_params_hint": "Верно: --param=xy, не верно: --param xy",
"custom_params_hint": "Верно: --param=xy, неверно: --param xy",
"delete1": "Удаление из источника после завершения",
"delete2": "Удаление писем по месту назначения, которые не находятся на исходном",
"delete2duplicates": "Удаление дубликатов по назначению",
@ -58,6 +59,7 @@
"domain": "Домен",
"domain_matches_hostname": "Домен %s соответствует имени хоста",
"domain_quota_m": "Квота домена (MiB)",
"dry": "Имитировать синхронизацию",
"enc_method": "Метод шифрования",
"exclude": "Исключить объекты (regex)",
"full_name": "Полное имя",
@ -89,7 +91,7 @@
"relay_all_info": "↪<small>Если вы решите <b>не</b> ретранслировать всех получателей, вам нужно будет добавить (\"слепой\") почтовый адрес для каждого получателя, которого следует ретранслировать.</small>",
"relay_domain": "Ретрансляция этого домена",
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Инфо</div> Вы можете настроить собственный транспорт для домена. Если такой настройки нет, то доставка будет выполнена на основе MX записей.",
"relay_unknown_only": "Ретрансляция только не существующих почтовых ящиков. Почта к существующим почтовым ящикам будут доставляться локально.",
"relay_unknown_only": "Ретрансляция только несуществующих почтовых ящиков. Почта существующих почтовых ящиков будут доставляться локально.",
"relayhost_wrapped_tls_info": "Пожалуйста <b>не</b> используйте TLS порты (в основном это 465 порт).<br>\r\nИспользуйте любой <b>не</b> TLS порт который поддерживает STARTTLS. А для защиты от downgrate атак - настройке принудительную политику TLS.",
"select": "Пожалуйста, выберите...",
"select_domain": "Пожалуйста, сначала выберите домен",
@ -99,6 +101,7 @@
"subscribeall": "Подписаться на все папки и подпапки",
"syncjob": "Добавить задание синхронизации",
"syncjob_hint": "Пароли к вашему аккаунту будут сохранены на сервере в виде простого текста!",
"tags": "Теги",
"target_address": "Владельцы псевдонима",
"target_address_info": "<small>Адреса почтовых ящиков, разделенные запятыми.</small>",
"target_domain": "Целевой домен",
@ -106,10 +109,7 @@
"timeout2": "Тайм-аут для подключения к локальному хосту",
"username": "Имя пользователя",
"validate": "Проверить",
"validation_success": "Проверка прошла успешно",
"tags": "Теги",
"app_passwd_protocols": "Разрешенные протоколы для пароля приложения",
"dry": "Имитировать синхронизацию"
"validation_success": "Проверка прошла успешно"
},
"admin": {
"access": "Настройки доступа",
@ -135,6 +135,8 @@
"admins": "Администраторы",
"admins_ldap": "Администраторы LDAP",
"advanced_settings": "Расширенные настройки",
"allowed_methods": "Access-Control-Allow-Methods",
"allowed_origins": "Access-Control-Allow-Origin",
"api_allow_from": "Список IP-адресов для доступа к API (разделенных запятой или новой строкой)",
"api_info": "API находится в стадии разработки. Документация находится по адресу <a href=\"/api\">/api</a>",
"api_key": "Ключ API",
@ -151,6 +153,8 @@
"change_logo": "Изменить логотип",
"configuration": "Глобальные настройки",
"convert_html_to_text": "Сконвертировать HTML в обычный текст",
"copy_to_clipboard": "Текст скопирован в буфер обмена!",
"cors_settings": "Настройки CORS",
"credentials_transport_warning": "<b>Предупреждение</b>: добавление новой записи перезапишет учетные данные для всех записей с таким же <i>следующим хостом</i>.",
"customer_id": "ID клиента",
"customize": "Персонализация",
@ -179,10 +183,14 @@
"empty": "Пусто",
"excludes": "Исключает этих получателей",
"f2b_ban_time": "Время бана (в секундах)",
"f2b_ban_time_increment": "Время бана увеличивается с каждым баном",
"f2b_blacklist": "Черный список подсетей/хостов",
"f2b_filter": "Правила фильтрации с помощью регулярных выражений",
"f2b_list_info": "Хосты или подсети, занесенные в черный список, всегда будут перевешивать объекты из белого списка. <b>Обновление списка займет несколько секунд.</b>",
"f2b_manage_external": "Внешнее управление Fail2Ban",
"f2b_manage_external_info": "Fail2ban по-прежнему будет вести банлист, но не будет активно устанавливать правила для блокировки трафика. Используйте сгенерированный ниже банлист для внешнего блокирования трафика.",
"f2b_max_attempts": "Максимальное количество попыток",
"f2b_max_ban_time": "Максимальное время блокировки",
"f2b_netban_ipv4": "Размер подсети IPv4 для применения бана (8-32)",
"f2b_netban_ipv6": "Размер подсети IPv6 для применения бана (8-128)",
"f2b_parameters": "Настройки Fail2ban",
@ -208,14 +216,19 @@
"include_exclude": "Включить/Исключить",
"include_exclude_info": "По умолчанию - без выбора - <b>все почтовые ящики</b> адресованы",
"includes": "Включить этих получателей",
"ip_check": "Проверить IP",
"ip_check_disabled": "Проверка IP-адресов отключена. Вы можете включить её в разделе <br> <strong>Система > Конфигурация > Параметры > Персонализация</strong>.",
"ip_check_opt_in": "Согласие на использование сторонних служб <strong>ipv4.mailcow.email</strong> и <strong>ipv6.mailcow.email</strong> для разрешения внешних IP-адресов.",
"is_mx_based": "На основе MX",
"last_applied": "Посл. применение",
"license_info": "Лицензия не обязательна, но её приобретение помогает дальнейшему развитию mailcow.<br><a href=\"https://www.servercow.de/mailcow?lang=en#sal\" target=\"_blank\" alt=\"SAL order\">Зарегистрируйте свой GUID здесь</a> или <a href=\"https://www.servercow.de/mailcow?lang=en#support\" target=\"_blank\" alt=\"Заказать поддержку\">приобретите поддержку для вашей установки mailcow.</a>",
"license_info": "Лицензия необязательна, но её приобретение помогает дальнейшему развитию mailcow.<br><a href=\"https://www.servercow.de/mailcow?lang=en#sal\" target=\"_blank\" alt=\"SAL order\">Зарегистрируйте свой GUID здесь</a> или <a href=\"https://www.servercow.de/mailcow?lang=en#support\" target=\"_blank\" alt=\"Заказать поддержку\">приобретите поддержку для вашей установки mailcow.</a>",
"link": "Ссылка",
"loading": "Пожалуйста, подождите...",
"login_time": "Время входа",
"logo_info": "Ваше изображение будет масштабироваться до высоты 40px для верхней панели навигации и до 250px ширины для стартовой страницы. <br>Рекомендуется использовать векторную графику, на пример: .svg.",
"lookup_mx": "Назначение на основе резовинга MX записи по регулярному выражению (<code>.*\\.example\\.com$</code> для маршрутизации всей почты через этот хост, если MX заканчивающийся на example.com)",
"logo_dark_label": "Инвертированный для темного режима",
"logo_info": "Ваше изображение будет масштабироваться до высоты 40px для верхней панели навигации и до 250px ширины для стартовой страницы. <br>Рекомендуется использовать векторную графику, например: .svg.",
"logo_normal_label": "Обычный",
"lookup_mx": "Назначение - регулярное выражение для сопоставления с именем MX (<code>.*\\.google\\.com</code> для направления всей почты, адресованной MX, заканчивающейся на google.com, через этот хоп)",
"main_name": "Название для \"mailcow UI\"",
"merged_vars_hint": "Серым цветом выделены строки полученные из <code>vars.(local.)inc.php</code>, они не могут быть изменены.",
"message": "Сообщение",
@ -225,15 +238,16 @@
"no_active_bans": "В данный момент нет забаненных подсетей/хостов",
"no_new_rows": "Нет доступных строк",
"no_record": "Нет записей",
"oauth2_client_id": "ID клиента",
"oauth2_apps": "Приложения OAuth2",
"oauth2_add_client": "Добавить клиента OAuth2",
"oauth2_apps": "Приложения OAuth2",
"oauth2_client_id": "ID клиента",
"oauth2_client_secret": "Секретный ключ пользователя",
"oauth2_info": "Реализация OAuth2 поддерживает предоставления кодов авторизации и выдает токены продления сессии.<br>\r\nСервер также автоматически выдает новый токен продления сессии, после того, как предыдущий был использован.<br><br>\r\n&#8226; Scope по умолчанию: <i>profile</i>. Только пользователи почтовых аккаунтов могут проходить аутентификацию через OAuth2. Если параметр области не указан, он возвращается к <i>profile</i>.<br>\r\n&#8226; Параметр <i>state</i> должен быть отправлен клиентом как часть запроса для авторизации.<br><br>\r\nПути для запросов OAuth2 API: <br>\r\n<ul>\r\n <li>Authorization endpoint: <code>/oauth/authorize</code></li>\r\n <li>Token endpoint: <code>/oauth/token</code></li>\r\n <li>Resource page: <code>/oauth/profile</code></li>\r\n</ul>\r\nГенерирование нового клиентского секрета не приводит к истечению существующих кодов авторизации, но они не смогут обновить свой токен.<br><br>\r\nОтзыв клиентских токенов приведет к немедленному прекращению всех активных сеансов. Все клиенты должны будут пройти повторную аутентификацию.",
"oauth2_redirect_uri": "Переадресация URI",
"oauth2_renew_secret": "Сгенерировать новый ключ клиента",
"oauth2_revoke_tokens": "Отозвать все клиентские токены",
"optional": "опционально",
"options": "Параметры",
"password": "Пароль",
"password_length": "Минимальная длина пароля",
"password_policy": "Политика паролей",
@ -243,6 +257,11 @@
"password_policy_numbers": "Должен содержать цифру",
"password_policy_special_chars": "Должны содержать специальный символ",
"password_repeat": "Подтверждение пароля (повтор)",
"password_reset_info": "Если получатель не указан, использование данной функции недоступно.",
"password_reset_settings": "Параметры восстановления паролей",
"password_reset_tmpl_html": "Шаблон в виде HTML",
"password_reset_tmpl_text": "Шаблон в виде обычного текста",
"password_settings": "Параметры паролей",
"priority": "Приоритет",
"private_key": "Закрытый ключ",
"quarantine": "Карантин",
@ -250,7 +269,7 @@
"quarantine_exclude_domains": "Исключить домены и псевдонимы доменов",
"quarantine_max_age": "Максимальный период хранения в днях<br><small>Значение должно быть равно или больше 1 дня.</small>",
"quarantine_max_score": "Не уведомлять о спаме, если оценка письма выше, чем:<br><small>По умолчанию 9999.0</small>",
"quarantine_max_size": "Максимальный размер в MiB (письма большего размера не будет сохранены):<br><small>0 означает, что карантин <b>отключён</b>.</small>",
"quarantine_max_size": "Максимальный размер в MiB (письма большего размера не будут сохранены):<br><small>0 означает, что карантин <b>отключён</b>.</small>",
"quarantine_notification_html": "Шаблон уведомления:<br><small>Оставьте пустым, чтобы восстановить шаблон по умолчанию.</small>",
"quarantine_notification_sender": "Email-адрес для отправки уведомления",
"quarantine_notification_subject": "Тема письма",
@ -259,6 +278,7 @@
"quarantine_release_format_att": "Как вложение",
"quarantine_release_format_raw": "Оригинальное письмо",
"quarantine_retention_size": "Количество писем, сохраняемых в карантине на аккаунт:<br><small>0 означает, что карантин <b>отключён</b>.</small>",
"queue_unban": "разблокировать",
"quota_notification_html": "Шаблон уведомления:<br><small>Оставьте пустым, чтобы восстановить шаблон по умолчанию.</small>",
"quota_notification_sender": "Email-адрес для отправки уведомления",
"quota_notification_subject": "Тема письма",
@ -267,7 +287,7 @@
"quota_notifications_vars": "{{percent}} равно текущей квоте пользователя<br>{{username}} - имя почтового аккаунта",
"r_active": "Включенные ограничения",
"r_inactive": "Отключенные ограничения",
"r_info": "Не активные (серые) элементы списка ограничений - это не валидные ограничения, и они не могут быть перемещены. <br>Вы можете добавить новые элементы в <code>inc/vars.local.inc.php</code> чтобы иметь возможность настраивать их.",
"r_info": "Неактивные (серые) элементы списка ограничений - это некорректные ограничения, и они не могут быть перемещены. <br>Вы можете добавить новые элементы в <code>inc/vars.local.inc.php</code> чтобы иметь возможность настраивать их.",
"rate_name": "Название очереди",
"recipients": "Получатели",
"refresh": "Обновить",
@ -282,6 +302,8 @@
"remove_row": "Удалить строку",
"reset_default": "Восстановить по умолчанию",
"reset_limit": "Удалить хэш",
"reset_password_vars": "<code>{{link}}</code> Сгенерированная ссылка для восстановление пароля<br><code>{{username}}</code> Имя почтового ящика пользователя, запросившего восстановление пароля<br><code>{{username2}}</code> Имя почтового ящика для восстановления<br><code>{{date}}</code> Дата запроса на восстановление пароля<br><code>{{token_lifetime}}</code> Срок действия токена в минутах<br><code>{{hostname}}</code> Имя хоста mailcow",
"restore_template": "Оставьте пустым, чтобы восстановить шаблон по умолчанию.",
"routing": "Маршрутизация",
"rsetting_add_rule": "Добавить правило",
"rsetting_content": "Содержание правила",
@ -290,14 +312,14 @@
"rsetting_none": "Нет доступных правил",
"rsettings_insert_preset": "Вставить пример \"%s\"",
"rsettings_preset_1": "Отключить все, кроме DKIM и ограничения скорости для аутентифицированных пользователей",
"rsettings_preset_2": "Не проверять письма на спам Postmaster",
"rsettings_preset_2": "Не проверять письма Postmaster на спам",
"rsettings_preset_3": "Разрешить только определённых отправителей для почтового ящика (использование только в качестве внутреннего почтового ящика)",
"rsettings_preset_4": "Отключить Rspamd для домена",
"rspamd_com_settings": "Имена правил будут сгенерированы на основе их ID.<br> Инструкция доступна на сайте <a href=\"https://rspamd.com/doc/configuration/settings.html#settings-structure\" target=\"_blank\">документация Rspamd user settings</a>, заготовленные шаблоны:",
"rspamd_global_filters": "Глобальные правила фильтрации",
"rspamd_global_filters_agree": "Я понимаю, что я делаю, и буду осторожен!",
"rspamd_global_filters_info": "Глобальные правила фильтрации содержат различные виды глобальных черных и белых списков.",
"rspamd_global_filters_regex": "Названия фильтров отражают их предназначение. Все правила должены состоять из регулярных выражений в формате \"/pattern/options\" (на пример: <code>/.+@domain\\.tld/i</code>).<br>\r\nНесмотря на то, что перед сохранением правил выполняется проверка регулярных выражений, функциональность Rspamds может быть нарушена, если будет использован<br>\r\n некорректный синтаксис. Будьте внимательны при написании правил.<br>Электронные письма от адресов электронной почты, проходящие по регулярным выражениям черных списков, будут отклонены без сохранения в карантин.<br>\r\n Rspamd попытается прочитать содержимое правил при их изменении. Но, если что, вы можете <a href=\"\" data-toggle=\"modal\" data-container=\"rspamd-mailcow\" data-target=\"#RestartContainer\">перезапустить Rspamd</a>, чтобы принять последние изменения принудительно.",
"rspamd_global_filters_regex": "Названия фильтров отражают их предназначение. Все правила должены состоять из регулярных выражений в формате \"/pattern/options\" (например: <code>/.+@domain\\.tld/i</code>).<br>\r\nНесмотря на то, что перед сохранением правил выполняется проверка регулярных выражений, функциональность Rspamds может быть нарушена, если будет использован<br>\r\n некорректный синтаксис. Будьте внимательны при написании правил.<br>Электронные письма от адресов электронной почты, проходящие по регулярным выражениям черных списков, будут отклонены без сохранения в карантин.<br>\r\n Rspamd попытается прочитать содержимое правил при их изменении. Но, если что, вы можете <a href=\"\" data-toggle=\"modal\" data-container=\"rspamd-mailcow\" data-target=\"#RestartContainer\">перезапустить Rspamd</a>, чтобы принять последние изменения принудительно.",
"rspamd_settings_map": "Правила Rspamd",
"sal_level": "Уровень Муу",
"save": "Сохранить изменения",
@ -337,19 +359,7 @@
"username": "Имя пользователя",
"validate_license_now": "Получить лицензию на основе GUID с сервера лицензий",
"verify": "Проверить",
"yes": "&#10003;",
"queue_unban": "разблокировать",
"f2b_ban_time_increment": "Время бана увеличивается с каждым баном",
"f2b_max_ban_time": "Максимальное время блокировки",
"allowed_origins": "Access-Control-Allow-Origin",
"cors_settings": "Настройки CORS",
"allowed_methods": "Access-Control-Allow-Methods",
"ip_check": "Проверить IP",
"ip_check_disabled": "Проверка IP отключена. Вы можете включить его в разделе <br> <strong>Система > Конфигурация > Параметры > Настроить</strong>.",
"ip_check_opt_in": "Согласие на использование сторонних служб <strong>ipv4.mailcow.email</strong> и <strong>ipv6.mailcow.email</strong> для разрешения внешних IP-адресов.",
"f2b_manage_external": "Внешнее управление Fail2Ban",
"f2b_manage_external_info": "Fail2ban по-прежнему будет вести банлист, но не будет активно устанавливать правила для блокировки трафика. Используйте сгенерированный ниже банлист для внешнего блокирования трафика.",
"copy_to_clipboard": "Текст скопирован в буфер обмена!"
"yes": "&#10003;"
},
"danger": {
"access_denied": "Доступ запрещён, или указаны неверные данные",
@ -365,7 +375,10 @@
"bcc_exists": "Для типов %s уже существует карта BCC %s",
"bcc_must_be_email": "Назначение BCC %s не является правильным адресом электронной почты",
"comment_too_long": "Комментарий слишком длинный, придел 160 символов",
"cors_invalid_method": "Указан недопустимый метод разрешения",
"cors_invalid_origin": "Указан неверный Allow-Origin",
"defquota_empty": "Квота по умолчанию не может быть 0.",
"demo_mode_enabled": "Демонстрационный режим включен",
"description_invalid": "Недопустимое описание ресурса %s",
"dkim_domain_or_sel_exists": "Ключ DKIM для \"%s\" уже существует",
"dkim_domain_or_sel_invalid": "DKIM домен или селектор недопустимы для %s",
@ -375,20 +388,23 @@
"domain_not_empty": "Нельзя удалить непустой домен %s",
"domain_not_found": "Домен %s не найден",
"domain_quota_m_in_use": "Квота домена должна быть больше или равна %s MiB",
"extra_acl_invalid": "Адрес внешнего отправителя \"%s\" не валидный.",
"extra_acl_invalid_domain": "Адрес внешнего отправителя \"%s\" не валидный домен",
"extended_sender_acl_denied": "отсутствует ACL для установки внешних адресов отправителей",
"extra_acl_invalid": "Адрес внешнего отправителя \"%s\" некорректен",
"extra_acl_invalid_domain": "Адрес внешнего отправителя \"%s\" содержит некорректный домен",
"fido2_verification_failed": "Ошибка валидации FIDO2: %s",
"file_open_error": "Файл не может быть открыт на запись",
"filter_type": "Неверный тип фильтра",
"from_invalid": "Отправитель не может быть пустым",
"global_filter_write_error": "Ошибка записи фильтра в файл: %s",
"global_map_invalid": "Идентификатор глобального правила %s не валидный",
"global_map_invalid": "Недопустимый идентификатор глобального правила %s",
"global_map_write_error": "Не удалось создать глобальное правило ID %s: %s",
"goto_empty": "Псевдоним должен содержать по крайней мере один валидный адрес владельца",
"goto_empty": "Псевдоним должен содержать по крайней мере один действующий адрес владельца",
"goto_invalid": "Недопустимый основной адрес %s",
"ham_learn_error": "Ошибка при обучении полезной почты: %s",
"imagick_exception": "Ошибка в Imagick при чтении изображения",
"img_dimensions_exceeded": "Разрешение изображения превышает допустимое значение",
"img_invalid": "Невозможно проверить файл изображения",
"img_size_exceeded": "Изображение превышает допустимый размер файла",
"img_tmp_missing": "Невозможно проверить файл изображения: временный файл не найден",
"invalid_bcc_map_type": "Неверный тип правила BCC",
"invalid_destination": "Назначение \"%s\" указано неверно",
@ -397,8 +413,9 @@
"invalid_mime_type": "Неверный mime type",
"invalid_nexthop": "Формат следующего хоста неверен",
"invalid_nexthop_authenticated": "Следующий хост существует с разными данными авторизации, пожалуйста, обновите существующие данные авторизации сначала для этого хоста.",
"invalid_recipient_map_new": "Новый получатель: %s не валидный",
"invalid_recipient_map_old": "Первоначальный получатель: %s не валидный",
"invalid_recipient_map_new": "Недопустимый новый получатель: %s",
"invalid_recipient_map_old": "Недопустимый исходный получатель: %s",
"invalid_reset_token": "Неверный токен восстановления",
"ip_list_empty": "Список разрешенных IP адресов не может быть пустым",
"is_alias": "%s уже известен как псевдоним адреса",
"is_alias_or_mailbox": "%s уже известен как псевдоним или почтовый аккаунт",
@ -418,7 +435,7 @@
"max_quota_in_use": "Квота почтового аккаунта должна быть больше или равна %d MiB",
"maxquota_empty": "Максимальная квота почтового аккаунта не должна быть 0.",
"mysql_error": "Ошибка в MySQL: %s",
"network_host_invalid": "Сеть или хост: %s не валидный",
"network_host_invalid": "Недопустимые сеть или хост: %s",
"next_hop_interferes": "%s пересекается с %s",
"next_hop_interferes_any": "Существующий хост пересекается с %s",
"nginx_reload_failed": "Обновление конфигурации Nginx не удалось: %s",
@ -428,6 +445,8 @@
"password_complexity": "Пароль не соответствует требованиям",
"password_empty": "Пароль не может быть пустым",
"password_mismatch": "Введенные пароли не совпадают",
"password_reset_invalid_user": "Почтовый ящик не найден или не задан адрес электронной почты для восстановления",
"password_reset_na": "Восстановление пароля в настоящее время недоступно. Пожалуйста, свяжитесь с вашим администратором.",
"policy_list_from_exists": "Запись с указанным именем уже существует",
"policy_list_from_invalid": "Запись имеет недопустимый формат",
"private_key_error": "Ошибка приватного ключа: %s",
@ -436,17 +455,19 @@
"pushover_token": "Токен Pushover указан в неверном формате",
"quota_not_0_not_numeric": "Размер квоты должен быть больше или равен нулю",
"recipient_map_entry_exists": "Правило перезаписи \"%s\" уже существует",
"recovery_email_failed": "Не удалось отправить письмо для восстановления. Пожалуйста, свяжитесь с вашим администратором.",
"redis_error": "Ошибка в Redis: %s",
"relayhost_invalid": "Правило %s не валидное",
"relayhost_invalid": "Недопустимое правило %s",
"release_send_failed": "Сообщение не может быть восстановлено: %s",
"reset_f2b_regex": "Сброс фильтров не был выполнен за отведённый промежуток времени, пожалуйста, повторите попытку или подождите еще несколько секунд и перезагрузите веб страницу.",
"reset_token_limit_exceeded": "Превышен лимит запросов на восстановление. Пожалуйста, попробуйте ещё раз позже.",
"resource_invalid": "Недопустимое имя ресурса",
"rl_timeframe": "Не верный временной интервал для лимита отправки",
"rspamd_ui_pw_length": "Длина пароля должна составлять не менее 6 символов для Rspamd UI",
"script_empty": "Скрипт не может быть пустым",
"sender_acl_invalid": "Недопустимое значение ACL для: %s",
"set_acl_failed": "Не удалось установить ACL",
"settings_map_invalid": "Правило ID: %s не валидное",
"settings_map_invalid": "Недопустимое правило ID %s",
"sieve_error": "Ошибка в синтаксисе Sieve: %s",
"spam_learn_error": "Ошибка при обучении спам фильтра: %s",
"subject_empty": "Тема письма не может быть пустой",
@ -454,34 +475,67 @@
"targetd_not_found": "Основной домен %s не найден",
"targetd_relay_domain": "Целевой домен %s уже является домен ретрансляции",
"temp_error": "Временная ошибка",
"text_empty": "Текст не должен быть пустым",
"template_exists": "Шаблон %s уже существует",
"template_id_invalid": "Недопустимое значение ID шаблона: %s",
"template_name_invalid": "Недопустимое название шаблона",
"text_empty": "Текст не может быть пустым",
"tfa_token_invalid": "Неправильный TFA токен",
"tls_policy_map_dest_invalid": "Недопустимое значение назначения политики",
"tls_policy_map_entry_exists": "Правило политики шифрования \"%s\" уже существует",
"tls_policy_map_parameter_invalid": "Недопустимое значение параметра политики",
"to_invalid": "Получатель не может быть пустым",
"totp_verification_failed": "Ошибка валидации TOTP",
"transport_dest_exists": "Назначение для отправки \"%s\" уже существует",
"webauthn_verification_failed": "Ошибка валидации WebAuthn: %s",
"unknown": "Произошла неизвестная ошибка",
"unknown_tfa_method": "Неизвестный метод TFA",
"unlimited_quota_acl": "Неограниченная квота запрещена политикой доступа",
"username_invalid": "Имя пользователя %s нельзя использовать",
"validity_missing": "Пожалуйста, назначьте срок действия",
"value_missing": "Пожалуйста заполните все поля",
"yotp_verification_failed": "Ошибка валидации Yubico OTP: %s",
"cors_invalid_method": "Указан недопустимый метод разрешения",
"demo_mode_enabled": "Демонстрационный режим включен",
"cors_invalid_origin": "Указан неверный Allow-Origin"
"webauthn_authenticator_failed": "Выбранный аутентификатор не был найден",
"webauthn_publickey_failed": "Для выбранного аутентификатора не был сохранен открытый ключ",
"webauthn_username_failed": "Выбранный аутентификатор принадлежит другой учетной записи",
"webauthn_verification_failed": "Ошибка валидации WebAuthn: %s",
"yotp_verification_failed": "Ошибка валидации Yubico OTP: %s"
},
"datatables": {
"collapse_all": "Свернуть все",
"decimal": ",",
"emptyTable": "В таблице отсутствуют данные",
"expand_all": "Развернуть все",
"info": "Показаны записи с _START_ по _END_ из _TOTAL_",
"infoEmpty": "Показано 0 записей",
"infoFiltered": "(отфильтровано из _MAX_ всех записей)",
"infoPostFix": "",
"lengthMenu": "Показать _MENU_ записей",
"loadingRecords": "Загрузка...",
"processing": "Пожалуйста, подождите...",
"search": "Поиск:",
"thousands": " ",
"zeroRecords": "Не найдено соответствующих записей",
"paginate": {
"first": "Первая",
"last": "Последняя",
"next": "Следующая",
"previous": "Предыдущая"
},
"aria": {
"sortAscending": ": активируйте для сортировки столбца по возрастанию",
"sortDescending": ": активируйте для сортировки столбца по убыванию"
}
},
"debug": {
"architecture": "Архитектура",
"chart_this_server": "Диаграмма (текущий сервер)",
"containers_info": "Статус контейнеров Docker",
"container_running": "Работающий",
"container_disabled": "Контейнер остановлен или отключен",
"container_running": "Работающий",
"container_stopped": "Остановлен",
"containers_info": "Статус контейнеров Docker",
"cores": "яд.",
"current_time": "Системное время",
"disk_usage": "Использование дискового пространства",
"docs": "Проиндексировано объектов",
"error_show_ip": "Не удалось определить публичные IP-адреса",
"external_logs": "Внешние журналы",
"history_all_servers": "История (все серверы)",
"in_memory_logs": "Журналы контейнеров",
@ -490,9 +544,12 @@
"log_info": "<p><b>Журналы контейнеров</b> mailcow сохраняются в Redis, и раз в минуту строки журнала за пределами <code>LOG_LINES (%d)</code> удаляются, чтобы уменьшить нагрузку на сервер.\r\n <br>Сами журналы контейнеров не сохраняются после перезагрузки контейнера. Все контейнеры дополнительно пишут логи в службу Docker, и, следовательно, используют драйвер логирования по умолчанию. Журналы контейнеров предусмотрены только для отладки мелких проблем. Для других задач, пожалуйста, настройте драйвер логирования Docker самостоятельно.</p>\r\n <p><b>Внешние журналы</b> собираются через API приложений.</p>\r\n <p><b>Статические журналы</b> &ndash; это, в основном, журналы активности, которые не записываются в Dockerd, но все равно должны быть постоянными (за исключением журналов API).</p>",
"login_time": "Время входа",
"logs": "Журналы",
"memory": "Память",
"no_update_available": "Система обновлена до последней версии",
"online_users": "Подключено пользователей",
"restart_container": "Перезапустить",
"service": "Сервис",
"show_ip": "Показать публичные IP-адреса",
"size": "Индексы занимают",
"solr_dead": "Solr не запущен. Если вы включили Solf в файле настроек <code>mailcow.conf</code> и это сообщение отображается более получаса, скорее всего Solr сломан.",
"solr_status": "Состояние Solr",
@ -500,10 +557,13 @@
"started_on": "Запущен в",
"static_logs": "Статические журналы",
"success": "Успех",
"no_update_available": "Система обновлена до последней версии",
"system_containers": "Система и контейнеры",
"timezone": "Часовой пояс",
"update_available": "Доступно обновление",
"update_failed": "Не удалось проверить наличие обновлений",
"uptime": "Время работы",
"username": "Имя пользователя"
"username": "Имя пользователя",
"wip": "В настоящее время идёт разработка"
},
"diagnostics": {
"cname_from_a": "Значение, полученное из записи A/AAAA. Это поддерживается до тех пор, пока запись указывает на правильный ресурс.",
@ -514,7 +574,7 @@
"dns_records_name": "Название",
"dns_records_status": "Статус",
"dns_records_type": "Тип",
"optional": "Эта запись не обязательна."
"optional": "Эта запись необязательна."
},
"edit": {
"acl": "ACL (Список прав)",
@ -527,6 +587,7 @@
"allowed_protocols": "Разрешённые протоколы",
"app_name": "Название приложения",
"app_passwd": "Пароль приложения",
"app_passwd_protocols": "Разрешенные протоколы для пароля приложения",
"automap": "Автоматическое слияние папок (\"Sent items\", \"Sent\" => \"Sent\" etc.)",
"backup_mx_options": "Параметры резервного копирования MX",
"bcc_dest_format": "Назначением для правила BCC должен быть единственный действительный адрес электронной почты.",
@ -534,6 +595,7 @@
"client_secret": "Секретный ключ пользователя",
"comment_info": "Приватный комментарий не виден пользователям, а публичный - отображается рядом с псевдонимом в личном кабинете пользователя",
"created_on": "Дата создания",
"custom_attributes": "Пользовательские атрибуты",
"delete1": "Удаление из источника после завершения",
"delete2": "Удаление писем по месту назначения, которые не находятся на исходном",
"delete2duplicates": "Удаление дубликатов по назначению",
@ -542,6 +604,19 @@
"disable_login": "Вход в систему запрещен",
"domain": "Изменение домена",
"domain_admin": "Изменение администратора домена",
"domain_footer": "Нижний колонтитул домена",
"domain_footer_html": "HTML нижний колонтитул",
"domain_footer_info": "Нижние колонтитулы на уровне домена добавляются ко всем исходящим электронным письмам, связанным с адресом в этом домене. <br> Для нижнего колонтитула можно использовать следующие переменные:",
"domain_footer_info_vars": {
"auth_user": "{= auth_user =} - Аутентифицированное имя пользователя, указанное MTA",
"custom": "{= foo =} - Если почтовый ящик имеет пользовательский атрибут \"foo\" со значением \"bar\", он возвращает \"bar\".",
"from_addr": "{= from_addr =} - Из адресной части envelope",
"from_domain": "{= from_domain =} - из доменной части envelope",
"from_name": "{= from_name =} - Из названия envelope, например, для \"Mailcow &lt;moo@mailcow.tld&gt;\" возвращается \"Mailcow\"",
"from_user": "{= from_user =} - Из пользовательской части envelope, например, для \"moo@mailcow.tld\" возвращается \"moo\""
},
"domain_footer_plain": "ПРОСТОЙ нижний колонтитул",
"domain_footer_skip_replies": "Ignore footer on reply e-mails",
"domain_quota": "Квота домена",
"domains": "Домены",
"dont_check_sender_acl": "Отключить проверку отправителя для домена %s и псевдонимов домена",
@ -550,9 +625,9 @@
"exclude": "Исключить объекты (regex)",
"extended_sender_acl": "Внешние адреса почты",
"extended_sender_acl_info": "Для внешних доменов должен быть импортирован или сгенерирован доменный ключ DKIM с соответствующей записью TXT в домене, если внешний домен использует DMARC.<br>\r\n Не забудьте добавить этот сервер к соответствующей записи SPF TXT внешнего домена.<br>\r\n Добавление домена из списка внешних адресов в mailcow автоматически удалит соответствующие записи из внешних адресов пользователей.<br>\r\n Чтобы разрешить пользователю отправку от имени *@domain.tld, укажите @domain.tld.",
"footer_exclude": "Исключить из нижнего колонтитула",
"force_pw_update": "Требовать смены пароля при следующем входе в систему",
"force_pw_update_info": "Пользователь должен будет войти в %s и сменить свой пароль. mailcow OAuth2, SOGo, EAS, IMAP/POP3 и SMTP будут не доступны до смены пароля.",
"footer_exclude": "Исключить из нижнего колонтитула",
"full_name": "Полное имя",
"gal": "GAL - Глобальная адресная книга",
"gal_info": "GAL содержит все объекты домена и не подлежит редактированию. Информация о занятости в SOGo будет отсутствовать для домена, если данная функция будет отключена! <b>Требуется перезапустить SOGo, чтобы применить изменения.</b>",
@ -566,6 +641,11 @@
"mailbox": "Изменение почтового аккаунта",
"mailbox_quota_def": "Квота по умолчанию",
"mailbox_relayhost_info": "Применяется только к почтовому ящику и личным псевдонимам, вне зависимости от настроек маршрутизации на уровне домена.",
"mailbox_rename": "Переименовать почтовый ящик",
"mailbox_rename_agree": "Я сделал резервную копию.",
"mailbox_rename_alias": "Автоматически создать псевдоним",
"mailbox_rename_title": "Новое имя локального почтового ящика",
"mailbox_rename_warning": "ВАЖНО! Перед переименованием почтового ящика создайте резервную копию.",
"max_aliases": "Максимум псевдонимов",
"max_mailboxes": "Максимум почтовых ящиков",
"max_quota": "Максимальная квота почтового аккаунта (MiB)",
@ -574,9 +654,10 @@
"mbox_rl_info": "Этот лимит применяется к SASL логину пользователя и соответствует любому адресу отправителя, используемому зарегистрированным пользователем. Лимит скорости почтового аккаунта перекрывает лимит скорости для всего домена.",
"mins_interval": "Интервал (в минутах)",
"multiple_bookings": "Несколько бронирований",
"none_inherit": "Отсутствует / Наследуется",
"nexthop": "Следующий хост",
"none_inherit": "Отсутствует / Наследуется",
"password": "Пароль",
"password_recovery_email": "Адрес для восстановления пароля",
"password_repeat": "Подтверждение пароля (повтор)",
"previous": "Предыдущая страница",
"private_comment": "Приватный комментарий",
@ -587,6 +668,7 @@
"pushover_only_x_prio": "Получать уведомления только об письмах с высоким приоритетом [<code>X-Priority: 1</code>]",
"pushover_sender_array": "Получать уведомления от списка адресов электронной почты <small>(envelop-from разделенные запятыми)</small>:",
"pushover_sender_regex": "Получать уведомления от отправителей, удовлетворяющих regex-выражению:",
"pushover_sound": "Звук уведомления",
"pushover_text": "Текст уведомления",
"pushover_title": "Заголовок уведомления",
"pushover_vars": "Когда фильтрация по отправителю не определена, уведомления будут доставлятся от всех отправителей.<br>Можно использовать обычный фильтр по отправителю и расширенный regex-фильтр, а также оба сразу.<br>Пожалуйста, ознакомьтесь с <a href=\"https://pushover.net/privacy\">Pushover Privacy Policy</a> перед использованием шаблонов для текста и заголовка",
@ -600,7 +682,7 @@
"relay_all_info": "↪<small>Если вы решите <b>не</b> ретранслировать всех получателей, вам нужно будет добавить (\"слепой\") почтовый аккаунт для каждого получателя, которого следует ретранслировать.</small>",
"relay_domain": "Ретрансляция этого домена",
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Инфо</div> Вы можете настроить собственный транспорт для домена. Если такой настройки нет, то доставка будет выполнена на основе MX записей.",
"relay_unknown_only": "Ретрансляция только не существующих почтовых ящиков. Почта к существующим почтовым ящикам будут доставляться локально.",
"relay_unknown_only": "Ретрансляция только несуществующих почтовых ящиков. Почта к существующим почтовым ящикам будут доставляться локально.",
"relayhost": "Маршрутизация на основе отправителя",
"remove": "Удалить",
"resource": "Ресурс",
@ -612,6 +694,8 @@
"sieve_desc": "Краткое описание",
"sieve_type": "Тип фильтра",
"skipcrossduplicates": "Пропускать повторяющиеся сообщения в папках",
"sogo_access": "Прямая переадресация в SOGo",
"sogo_access_info": "После входа в систему пользователь автоматически перенаправляется в SOGo.",
"sogo_visible": "Отображать псевдоним в SOGo",
"sogo_visible_info": "Влияет только на объекты, которые могут отображаться в SOGo (персональные или общие псевдонимы, указывающие как минимум на один локальный почтовый аккаунт). Учтите, что если функция отключена, у пользователей не будет возможности выбрать адрес псевдонима в качестве отправителя в SOGo.",
"spam_alias": "Создать или изменить временные (спам) псевдонимы",
@ -627,23 +711,7 @@
"title": "Изменение объекта",
"unchanged_if_empty": "Если без изменений - оставьте пустым",
"username": "Имя пользователя",
"validate_save": "Подтвердить и сохранить",
"sogo_access": "Прямая переадресация в SOGo",
"sogo_access_info": "После входа в систему пользователь автоматически перенаправляется в SOGo.",
"app_passwd_protocols": "Разрешенные протоколы для пароля приложения",
"domain_footer_info": "Нижние колонтитулы на уровне домена добавляются ко всем исходящим электронным письмам, связанным с адресом в этом домене. <br> Для нижнего колонтитула можно использовать следующие переменные:",
"domain_footer_info_vars": {
"from_name": "{= from_name =} - Из названия envelope, например, для \"Mailcow &lt;moo@mailcow.tld&gt;\" возвращается \"Mailcow\"",
"auth_user": "{= auth_user =} - Аутентифицированное имя пользователя, указанное MTA",
"from_user": "{= from_user =} - Из пользовательской части envelope, например, для \"moo@mailcow.tld\" возвращается \"moo\"",
"from_addr": "{= from_addr =} - Из адресной части envelope",
"from_domain": "{= from_domain =} - из доменной части envelope",
"custom": "{= foo =} - Если почтовый ящик имеет пользовательский атрибут \"foo\" со значением \"bar\", он возвращает \"bar\"."
},
"domain_footer": "Нижний колонтитул домена",
"domain_footer_html": "HTML нижний колонтитул",
"domain_footer_plain": "ПРОСТОЙ нижний колонтитул",
"custom_attributes": "Пользовательские атрибуты"
"validate_save": "Подтвердить и сохранить"
},
"fido2": {
"confirm": "Подтвердить",
@ -678,10 +746,10 @@
"header": {
"administration": "Настройка сервера",
"apps": "Приложения",
"debug": "Состояние сервера",
"debug": "Информация",
"email": "E-Mail",
"mailcow_system": "Система",
"mailcow_config": "Конфигурация",
"mailcow_system": "Система",
"quarantine": "Карантин",
"restart_netfilter": "Перезапустить netfilter",
"restart_sogo": "Перезапустить SOGo",
@ -693,12 +761,19 @@
"session_expires": "Ваш сеанс закончится примерно через 15 секунд"
},
"login": {
"back_to_mailcow": "Вернуться к mailcow",
"delayed": "Вход был отложен на %s секунд.",
"fido2_webauthn": "FIDO2/WebAuthn Login",
"forgot_password": "> Забыли пароль?",
"invalid_pass_reset_token": "Токен восстановления пароля недействителен или срок его действия истек.<br>Пожалуйста, запросите новую ссылку для восстановления пароля.",
"login": "Войти",
"mobileconfig_info": "Пожалуйста, войдите в систему как пользователь почтового аккаунта для загрузки профиля подключения Apple.",
"new_password": "Новый пароль",
"new_password_confirm": "Повторите новый пароль",
"other_logins": "Вход с помощью ключа",
"password": "Пароль",
"request_reset_password": "Запросить восстановление пароля",
"reset_password": "Восстановление пароля",
"username": "Имя пользователя"
},
"mailbox": {
@ -716,6 +791,7 @@
"add_mailbox": "Добавить почтовый аккаунт",
"add_recipient_map_entry": "Добавить перезапись получателя",
"add_resource": "Добавить ресурс",
"add_template": "Добавить шаблон",
"add_tls_policy_map": "Добавить политику TLS",
"address_rewriting": "Перезапись адресов",
"alias": "Псевдоним",
@ -740,12 +816,12 @@
"bcc_to_rcpt": "Переключиться на тип \"получатель\"",
"bcc_to_sender": "Переключиться на тип \"отправитель\"",
"bcc_type": "Тип BCC",
"booking_null": "Всегда показывать как свободный",
"booking_0_short": "Всегда свободнен",
"booking_custom": "Лимит на количество бронирований",
"booking_custom_short": "Жесткий лимит",
"booking_ltnull": "Неограниченный, занят при бронировании",
"booking_lt0_short": "Неограниченный лимит",
"booking_ltnull": "Неограниченный, занят при бронировании",
"booking_null": "Всегда показывать как свободный",
"catch_all": "Catch-all",
"created_on": "Дата создания",
"daily": "Раз в день",
@ -760,6 +836,7 @@
"domain_aliases": "Псевдонимы доменов",
"domain_quota": "Квота",
"domain_quota_total": "Квота домена",
"domain_templates": "Шаблоны доменов",
"domains": "Домены",
"edit": "Изменить",
"empty": "Пусто",
@ -787,6 +864,7 @@
"mailbox_defaults_info": "Установите настройки по умолчанию для новых почтовых аккаунтов.",
"mailbox_defquota": "Квота по умолчанию",
"mailbox_quota": "Макс. квота почт. ящика",
"mailbox_templates": "Шаблоны почтовых ящиков",
"mailboxes": "Почтовые ящики",
"max_aliases": "Максимум псевдонимов",
"max_mailboxes": "Максимум почтовых ящиков",
@ -814,16 +892,17 @@
"recipient_map_new": "Перезапись на",
"recipient_map_new_info": "Должен быть действующим почтовым ящиком.",
"recipient_map_old": "Получатель",
"recipient_map_old_info": "Должен быть валидный почтовым ящиком или доменом.",
"recipient_map_old_info": "Должен быть действующим почтовым ящиком или доменом.",
"recipient_maps": "Перезапись получателя",
"relay_all": "Ретрансляция всех получателей",
"relay_unknown": "Ретрансляция неизвестных получателей",
"remove": "Удалить",
"resources": "Ресурсы",
"running": "В процессе",
"sender": "Отправитель",
"set_postfilter": "Использовать как постфильтр",
"set_prefilter": "Использовать как предварительный фильтр",
"sieve_info": "Вы можете сохранить несколько фильтров для каждого пользователя, но только один предварительный фильтр и один постфильтр могут быть активными одновременно.<br>\r\n Каждый фильтр будет обработан в описанном порядке. Не сломанный скрипт, не <code>keep;</code> не остановит обработку дальнейших скриптов.<br><br>Global sieve prefilter &#8226; Prefilter &#8226; User scripts &#8226; Postfilter &#8226; Global sieve postfilter",
"sieve_info": "Вы можете сохранить несколько фильтров для каждого пользователя, но только один предварительный фильтр и один постфильтр могут быть активными одновременно.<br>\r\n Каждый фильтр будет обработан в описанном порядке. Ни сломанный скрипт, ни <code>keep;</code> не остановит обработку дальнейших скриптов.<br><br>Global sieve prefilter &#8226; Prefilter &#8226; User scripts &#8226; Postfilter &#8226; Global sieve postfilter",
"sieve_preset_1": "Discard mail with probable dangerous file types",
"sieve_preset_2": "Always mark the e-mail of a specific sender as seen",
"sieve_preset_3": "Discard silently, stop all further sieve processing",
@ -831,7 +910,7 @@
"sieve_preset_5": "Auto responder (vacation)",
"sieve_preset_6": "Reject mail with response",
"sieve_preset_7": "Redirect and keep/drop",
"sieve_preset_8": "Discard message sent to an alias address the sender is part of",
"sieve_preset_8": "Переслать письмо от определенного отправителя, пометить его как прочитанное и поместить в подпапку",
"sieve_preset_header": "Пожалуйста, ознакомьтесь с примерами ниже. Для более подробной информации прочитайте <a href=\"https://en.wikipedia.org/wiki/Sieve_(mail_filtering_language)\" target=\"_blank\">Sieve Wikipedia</a>.",
"sogo_visible": "Отображать псевдоним в SOGo",
"sogo_visible_n": "Не отображать псевдоним в SOGo",
@ -840,25 +919,27 @@
"stats": "Статистика",
"status": "Статус",
"sync_jobs": "Задания синхронизации",
"syncjob_EXIT_AUTHENTICATION_FAILURE": "Ошибка авторизации",
"syncjob_EXIT_AUTHENTICATION_FAILURE_USER1": "Неправильное имя пользователя или пароль",
"syncjob_EXIT_CONNECTION_FAILURE": "Ошибка связи с сервером",
"syncjob_EXIT_CONNECTION_FAILURE_HOST1": "Не удалось подключиться к удаленному серверу",
"syncjob_EXIT_OVERQUOTA": "Целевой почтовый ящик превысил квоту",
"syncjob_EXIT_TLS_FAILURE": "Ошибка установки шифрованного соединения",
"syncjob_EX_OK": "Успешно",
"syncjob_check_log": "Проверить журнал",
"syncjob_last_run_result": "Результат последнего запуска",
"syncjob_EX_OK": "Успешно",
"syncjob_EXIT_CONNECTION_FAILURE": "Ошибка связи с сервером",
"syncjob_EXIT_TLS_FAILURE": "Ошибка установки шифрованного соединения",
"syncjob_EXIT_AUTHENTICATION_FAILURE": "Ошибка авторизации",
"syncjob_EXIT_OVERQUOTA": "Целевой почтовый ящик превысил квоту",
"syncjob_EXIT_CONNECTION_FAILURE_HOST1": "Не удалось подключиться к удаленному серверу",
"syncjob_EXIT_AUTHENTICATION_FAILURE_USER1": "Неправильное имя пользователя или пароль",
"table_size": "Размер таблицы",
"table_size_show_n": "Отображать %s полей",
"target_address": "Владельцы псевдонима",
"target_domain": "Целевой домен",
"template": "Шаблон",
"templates": "Шаблоны",
"tls_enforce_in": "Принудительный TLS (входящие)",
"tls_enforce_out": "Принудительный TLS (исходящие)",
"tls_map_dest": "Назначение",
"tls_map_dest_info": "пример: example.org, .example.org, [mail.example.org]:25",
"tls_map_parameters": "Параметры",
"tls_map_parameters_info": "Оставьте поле пустым или укажите параметры, на пример: protocols=!SSLv2 ciphers=medium exclude=3DES",
"tls_map_parameters_info": "Оставьте поле пустым или укажите параметры, например: protocols=!SSLv2 ciphers=medium exclude=3DES",
"tls_map_policy": "Политика",
"tls_policy_maps": "Правила TLS",
"tls_policy_maps_enforced_tls": "Для исходящих сообщений от пользователей с включенной принудительной политикой шифрования исходящих соединений не описанные глобальной политикой,<br>\r\n будут применены значения по умолчанию, указанные в <code>smtp_tls_mandatory_protocols</code> и <code>smtp_tls_mandatory_ciphers</code>.",
@ -933,14 +1014,27 @@
"type": "Тип"
},
"queue": {
"queue_manager": "Очередь на отправку"
"ays": "Пожалуйста, подтвердите, что вы хотите удалить все элементы из текущей очереди.",
"delete": "Удалить все",
"deliver_mail": "Доставить",
"deliver_mail_legend": "Попытаться повторно доставить выбранные письма.",
"flush": "Обработать очередь",
"hold_mail": "Отложить",
"hold_mail_legend": "Удержать выбранные сообщения. (Предотвратить дальнейшие попытки доставки)",
"info": "Очередь отправки почты содержит все письма, которые ожидают доставки. Если письмо надолго задерживается в почтовой очереди, оно автоматически удаляется системой.<br>Сообщение об ошибке в соответствующих письмах содержит информацию о том, почему письмо не удалось доставить.",
"legend": "Описание действий с почтовой очередью:",
"queue_manager": "Очередь на отправку",
"show_message": "Показать сообщение",
"unhold_mail": "Высвободить",
"unhold_mail_legend": "Освобождает выбранные письма для доставки. (Требуется предварительное удержание)",
"unban": "освободить очередь"
},
"ratelimit": {
"day": "сообщений / день",
"disabled": "Отключен",
"second": "сообщений / секунду",
"minute": "сообщений / минуту",
"hour": "сообщений / час",
"day": "сообщений / день"
"minute": "сообщений / минуту",
"second": "сообщений / секунду"
},
"start": {
"help": "Справка",
@ -966,6 +1060,7 @@
"bcc_deleted": "Правила BCC удалены: %s",
"bcc_edited": "Правило BCC %s отредактировано",
"bcc_saved": "Правило BCC сохранено",
"cors_headers_edited": "Настройки CORS сохранены",
"db_init_complete": "Инициализация базы данных завершена",
"delete_filter": "Фильтр ID %s удалён",
"delete_filters": "Фильтры удалены: %s",
@ -974,19 +1069,23 @@
"dkim_added": "DKIM ключ сохранён",
"dkim_duplicated": "DKIM ключи для домена %s были скопированы в %s",
"dkim_removed": "DKIM ключ %s удалён",
"domain_add_dkim_available": "DKIM ключ уже существует",
"domain_added": "Добавлен домен %s",
"domain_admin_added": "Администратор домена %s добавлен",
"domain_admin_modified": "Сохранить изменения администратора домена %s",
"domain_admin_removed": "Администратор домена %s удалён",
"domain_footer_modified": "Изменения в нижнем колонтитуле домена %s сохранены",
"domain_modified": "Сохранить изменения домена %s",
"domain_removed": "Домен %s удалён",
"dovecot_restart_success": "Dovecot перезапущен успешно",
"eas_reset": "Кеш ActiveSync для пользователя %s был сброшен",
"f2b_banlist_refreshed": "Идентификатор банлиста был успешно обновлен.",
"f2b_modified": "Изменения параметров Fail2ban сохранены",
"forwarding_host_added": "Перенаправление узла %s добавлено",
"forwarding_host_removed": "Перенаправление узла %s удалено",
"global_filter_written": "Фильтр успешно записан в файл",
"hash_deleted": "Хеш удалён",
"ip_check_opt_in_modified": "Параметры проверки IP успешно обновлены",
"item_deleted": "Обьект %s удалён",
"item_released": "Письмо %s восстановлено из карантина",
"items_deleted": "Обьекты %s удалены",
@ -997,14 +1096,17 @@
"mailbox_added": "Почтовый аккаунт %s добавлен",
"mailbox_modified": "Изменения почтового аккаунта %s сохранены",
"mailbox_removed": "Почтовый аккаунт %s удалён",
"mailbox_renamed": "Почтовый аккаунт %s был переименован в %s",
"nginx_reloaded": "Обновление конфигурация Nginx закончено",
"object_modified": "Изменения объекта %s сохранены",
"password_changed_success": "Пароль был успешно изменен",
"password_policy_saved": "Политика паролей сохранена",
"pushover_settings_edited": "Настройки сохранены, пожалуйста, выполните проверку доступа",
"qlearn_spam": "Письмо ID %s было изучено как спам и удалено",
"queue_command_success": "Команда выполнена успешно",
"recipient_map_entry_deleted": "Правило перезаписи получателя ID %s было удалено",
"recipient_map_entry_saved": "Правило перезаписи получателя \"%s\" было сохранено",
"recovery_email_sent": "Письмо для восстановления пароля отправлено на %s",
"relayhost_added": "Промежуточный узел %s добавлен",
"relayhost_removed": "Промежуточный узел %s удалён",
"reset_main_logo": "Восстановить логотип по умолчанию",
@ -1017,6 +1119,9 @@
"settings_map_added": "Правило добавлено",
"settings_map_removed": "Правило ID %s удалено",
"sogo_profile_reset": "Профиль пользователя SOGo %s сброшен",
"template_added": "Шаблон %s добавлен",
"template_modified": "Изменения шаблона %s сохранены",
"template_removed": "Шаблон ID %s удален",
"tls_policy_map_entry_deleted": "Политика TLS ID %s удалено",
"tls_policy_map_entry_saved": "Политика TLS \"%s\" сохранена",
"ui_texts": "Изменения текстов UI сохранены",
@ -1024,13 +1129,11 @@
"verified_fido2_login": "Авторизация FIDO2 пройдена",
"verified_totp_login": "Авторизация TOTP пройдена",
"verified_webauthn_login": "Авторизация WebAuthn пройдена",
"verified_yotp_login": "Авторизация Yubico OTP пройдена",
"cors_headers_edited": "Настройки CORS сохранены",
"domain_footer_modified": "Изменения в нижнем колонтитуле домена %s сохранены",
"f2b_banlist_refreshed": "Идентификатор банлиста был успешно обновлен."
"verified_yotp_login": "Авторизация Yubico OTP пройдена"
},
"tfa": {
"api_register": "%s использует Yubico Cloud API. Пожалуйста, получите ключ API для вашего ключа <a href=\"https://upgrade.yubico.com/getapikey/\" target=\"_blank\">здесь</a>",
"authenticators": "Аутентификаторы",
"confirm": "Подтвердите",
"confirm_totp_token": "Пожалуйста, подтвердите изменения, введя сгенерированный код",
"delete_tfa": "Отключить TFA",
@ -1049,11 +1152,12 @@
"tfa": "Двухфакторная проверка подлинности",
"tfa_token_invalid": "Неправильный TFA токен",
"totp": "OTP (Authy, Google Authenticator и др.)",
"webauthn": "WebAuthn аутентификация",
"u2f_deprecated": "Похоже, что ваш ключ был зарегистрирован с использованием устаревшего метода U2F. Мы деактивируем для вас двухфакторную аутентификацию и удалим ваш ключ.",
"u2f_deprecated_important": "Пожалуйста, зарегистрируйте ваш ключ в панели администратора с помощью нового метода WebAuthn.",
"waiting_usb_auth": "<i>Ожидание устройства USB...</i><br><br>Пожалуйста, нажмите кнопку на USB устройстве сейчас.",
"waiting_usb_register": "<i>Ожидание устройства USB...</i><br><br>Пожалуйста, введите пароль выше и подтвердите регистрацию, нажав кнопку на USB устройстве.",
"yubi_otp": "Yubico OTP аутентификация",
"u2f_deprecated": "Похоже, что ваш ключ был зарегистрирован с использованием устаревшего метода U2F. Мы деактивируем для вас двухфакторную аутентификацию и удалим ваш ключ."
"webauthn": "WebAuthn аутентификация",
"yubi_otp": "Yubico OTP аутентификация"
},
"user": {
"action": "Действия",
@ -1070,13 +1174,17 @@
"alias_valid_until": "Действителен до",
"aliases_also_send_as": "Разрешено отправлять письма от имени",
"aliases_send_as_all": "Разрешено отправлять письма от любого имени для домена и его псевдонимов",
"allowed_protocols": "Разрешенные протоколы",
"app_hint": "Пароли приложений - это альтернативные пароли для авторизации в IMAP, SMTP, CalDAV, CardDAV и EAS. При этом имя пользователя остается неизменным. <br>SOGo недоступен через пароли приложений.",
"app_name": "Название приложения",
"app_passwds": "Пароли приложений",
"apple_connection_profile": "Профиль подключения Apple",
"apple_connection_profile_complete": "Этот профиль включает настройки IMAP и SMTP, а также CalDAV (календарей) и CardDAV (контактов) для устройства Apple.",
"apple_connection_profile_mailonly": "Этот профиль включает только настройки IMAP и SMTP для устройства Apple.",
"apple_connection_profile_with_app_password": "Новый пароль приложения генерируется и добавляется в профиль, поэтому при настройке устройства не требуется вводить пароль. Не предоставляйте доступ к файлу, поскольку он предоставляет полный доступ к вашему почтовому ящику.",
"attribute": "Атрибут",
"change_password": "Изменить пароль",
"change_password_hint_app_passwords": "В вашей учетной записи есть %d паролей приложений, которые не будут изменены. Чтобы управлять ими, перейдите на вкладку \"Пароли приложений\".",
"clear_recent_successful_connections": "Очистить историю успешных подключений",
"client_configuration": "Показать руководство по настройке почтовых клиентов и смартфонов",
"create_app_passwd": "Создать новый пароль",
@ -1087,6 +1195,7 @@
"delete_ays": "Пожалуйста, подтвердите удаление",
"direct_aliases": "Личные псевдонимы",
"direct_aliases_desc": "На личные псевдонимы распространяются фильтры нежелательной почты и параметры политики TLS.",
"direct_protocol_access": "Этот пользователь почтового ящика имеет <b>прямой, внешний доступ</b> к следующим протоколам и приложениям. Эта настройка контролируется вашим администратором. Для предоставления доступа к отдельным протоколам и приложениям могут быть созданы пароли приложений.<br> Кнопка \"Вход в веб-почту\" обеспечивает единый вход в SOGo и всегда доступна.",
"eas_reset": "Сбросить кеш ActiveSync устройств",
"eas_reset_help": "Во многих случаях сброс кеша устройств помогает восстановить повреждённый профиль ActiveSync.<br><b>Внимание:</b> все письма, календари и контакты будут загружены заново на все ваши устройства!",
"eas_reset_now": "Сбросить кеш сейчас",
@ -1131,15 +1240,18 @@
"password": "Пароль",
"password_now": "Текущий пароль (подтверждение изменения)",
"password_repeat": "Подтверждение пароля (повтор)",
"password_reset_info": "If no email for password recovery is provided, this function cannot be used.",
"pushover_evaluate_x_prio": "Установить высокий приоритет уведомлений для писем с высоким приоритетом [<code>X-Priority: 1</code>]",
"pushover_info": "Настройки Push-уведомления будут применяться ко всей почте <b>%s</b> (за исключением спама), включая псевдонимы (личные, общие и тегированные).",
"pushover_only_x_prio": "Получать уведомления только о письмах с высоким приоритетом [<code>X-Priority: 1</code>]",
"pushover_sender_array": "Получать уведомления от списка адресов электронной почты <small>(envelop-from, разделённые запятыми)</small>:",
"pushover_sender_regex": "Получать уведомления от отправителей, удовлетворяющих regex-выражению:",
"pushover_sound": "Звук уведомления",
"pushover_text": "Текст уведомления",
"pushover_title": "Заголовок уведомления",
"pushover_vars": "Когда фильтрация по отправителю не определена, уведомения будут доставлятся от всех отправителей.<br>Можно использовать обычный фильтр по отправителю и расширенный regex-фильтр, а также оба сразу.<br>Пожалуйста, ознакомьтесь с <a href=\"https://pushover.net/privacy\">Pushover Privacy Policy</a> перед использованием шаблонов для текста и заголовка",
"pushover_verify": "Проверить доступ",
"pw_recovery_email": "Адрес для восстановления пароля",
"q_add_header": "Нежелательная почта",
"q_all": "Все категории",
"q_reject": "Отклонённая почта",
@ -1180,15 +1292,15 @@
"spamfilter_yellow": "Жёлтый: эти письма могут быть спамом, будут доставлены в папку \"Спам\"",
"status": "Статус",
"sync_jobs": "Задания синхронизации",
"syncjob_EXIT_AUTHENTICATION_FAILURE": "Ошибка авторизации",
"syncjob_EXIT_AUTHENTICATION_FAILURE_USER1": "Неправильное имя пользователя или пароль",
"syncjob_EXIT_CONNECTION_FAILURE": "Ошибка связи с сервером",
"syncjob_EXIT_CONNECTION_FAILURE_HOST1": "Не удалось подключиться к удаленному серверу",
"syncjob_EXIT_OVERQUOTA": "Целевой почтовый ящик превысил квоту",
"syncjob_EXIT_TLS_FAILURE": "Ошибка установки шифрованного соединения",
"syncjob_EX_OK": "Успешно",
"syncjob_check_log": "Проверить журнал",
"syncjob_last_run_result": "Результат",
"syncjob_EX_OK": "Успешно",
"syncjob_EXIT_CONNECTION_FAILURE": "Ошибка связи с сервером",
"syncjob_EXIT_TLS_FAILURE": "Ошибка установки шифрованного соединения",
"syncjob_EXIT_AUTHENTICATION_FAILURE": "Ошибка авторизации",
"syncjob_EXIT_OVERQUOTA": "Целевой почтовый ящик превысил квоту",
"syncjob_EXIT_CONNECTION_FAILURE_HOST1": "Не удалось подключиться к удаленному серверу",
"syncjob_EXIT_AUTHENTICATION_FAILURE_USER1": "Неправильное имя пользователя или пароль",
"tag_handling": "Обработка тегированной почты",
"tag_help_example": "Пример тегированного адреса электронной почты: <code>ich<b>+Facebook</b>@example.org</code>",
"tag_help_explain": "Переместить в подпапку: будет создана новая подпапка в INBOX с именем тега, например: \"INBOX/Facebook\".<br>\r\n Добавить к теме письма: имя тега будет добавлено к теме письма, например: \"[Facebook] My News\".",
@ -1203,20 +1315,15 @@
"tls_policy_warning": "<strong>Предупреждение:</strong> Если вы включите принудительное шифрованние почты, вы можете столкнуться с потерей писем.<br>Сообщения, которые не соответствуют политике, будут отбрасываться с сообщением почтовым сервером о серьёзном сбое.<br>Этот параметр применяется к вашему основному адресу электронной почты (логину), всем личным псевдонимам и псевдонимам доменов. Подразумеваются только псевдонимы <b>с одним почтовым ящиком</b>, как получатель.",
"user_settings": "Настройки пользователя",
"username": "Имя пользователя",
"value": "Значение",
"verify": "Проверить",
"waiting": "В ожидании",
"week": "неделю",
"weekly": "Раз в неделю",
"weeks": "недели",
"year": "год",
"years": "лет",
"allowed_protocols": "Разрешенные протоколы",
"apple_connection_profile_with_app_password": "Новый пароль приложения генерируется и добавляется в профиль, поэтому при настройке устройства не требуется вводить пароль. Не предоставляйте доступ к файлу, поскольку он предоставляет полный доступ к вашему почтовому ящику.",
"direct_protocol_access": "Этот пользователь почтового ящика имеет <b>прямой, внешний доступ</b> к следующим протоколам и приложениям. Эта настройка контролируется вашим администратором. Для предоставления доступа к отдельным протоколам и приложениям могут быть созданы пароли приложений.<br> Кнопка \"веб-почту\" обеспечивает единый вход в SOGo и всегда доступна.",
"with_app_password": "с паролем приложения",
"change_password_hint_app_passwords": "В вашей учетной записи есть {{number_of_app_passwords}} паролей приложений, которые не будут изменены. Чтобы управлять ими, перейдите на вкладку \"Пароли приложений\".",
"attribute": "Атрибут",
"value": "Значение"
"year": "год",
"years": "лет"
},
"warning": {
"cannot_delete_self": "Вы не можете удалить сами себя",
@ -1230,10 +1337,5 @@
"quota_exceeded_scope": "Квота домена превышена: могут быть созданы только почтовые ящики без лимита.",
"session_token": "Неверный токен формы: несоответствие токена",
"session_ua": "Неверный токен формы: ошибка проверки User-Agent"
},
"datatables": {
"collapse_all": "Свернуть все",
"expand_all": "Развернуть все",
"infoPostFix": ""
}
}

View File

@ -41,6 +41,7 @@ $template_data = [
'mailboxes' => $mailboxes,
'lang_mailbox' => json_encode($lang['mailbox']),
'lang_rl' => json_encode($lang['ratelimit']),
'lang_edit' => json_encode($lang['edit']),
'lang_datatables' => json_encode($lang['datatables']),
];

View File

@ -99,7 +99,7 @@
{% endif %}
<form class="form-inline" data-id="f2b_banlist" role="form" method="post">
<div class="input-group mb-3">
<input type="text" class="form-control" aria-label="Banlist url" value="{{ f2b_banlist_url}}" id="banlist_url">
<input type="text" class="form-control" aria-label="Banlist url" value="{{ f2b_banlist_url }}" id="banlist_url">
{% if is_https %}
<button class="btn btn-secondary" type="button" onclick="copyToClipboard('banlist_url')"><i class="bi bi-clipboard"></i></button>
{% endif %}

View File

@ -68,6 +68,7 @@
var acl = '{{ acl_json|raw }}';
var lang = {{ lang_mailbox|raw }};
var lang_rl = {{ lang_rl|raw }};
var lang_edit = {{ lang_edit|raw }};
var lang_datatables = {{ lang_datatables|raw }};
var csrf_token = '{{ csrf_token }}';
var pagination_size = Math.trunc('{{ pagination_size }}');

View File

@ -43,8 +43,10 @@ services:
redis-mailcow:
image: redis:7-alpine
entrypoint: /redis-conf.sh
volumes:
- redis-vol-1:/data/
- ./data/conf/redis/redis-conf.sh:/redis-conf.sh:z
restart: always
depends_on:
- netfilter-mailcow
@ -52,6 +54,7 @@ services:
- "${REDIS_PORT:-127.0.0.1:7654}:6379"
environment:
- TZ=${TZ}
- REDISPASS=${REDISPASS}
sysctls:
- net.core.somaxconn=4096
networks:
@ -80,7 +83,7 @@ services:
- clamd
rspamd-mailcow:
image: mailcow/rspamd:1.98
image: mailcow/rspamd:1.99
stop_grace_period: 30s
depends_on:
- dovecot-mailcow
@ -91,6 +94,7 @@ services:
- IPV6_NETWORK=${IPV6_NETWORK:-fd4d:6169:6c63:6f77::/64}
- REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
- REDISPASS=${REDISPASS}
- SPAMHAUS_DQS_KEY=${SPAMHAUS_DQS_KEY:-}
volumes:
- ./data/hooks/rspamd:/hooks:Z
@ -112,7 +116,7 @@ services:
- rspamd
php-fpm-mailcow:
image: mailcow/phpfpm:1.91.1
image: mailcow/phpfpm:1.92
command: "php-fpm -d date.timezone=${TZ} -d expose_php=0"
depends_on:
- redis-mailcow
@ -147,6 +151,7 @@ services:
environment:
- REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
- REDISPASS=${REDISPASS}
- LOG_LINES=${LOG_LINES:-9999}
- TZ=${TZ}
- DBNAME=${DBNAME}
@ -193,7 +198,7 @@ services:
- phpfpm
sogo-mailcow:
image: mailcow/sogo:nightly-20241112
image: mailcow/sogo:nightly-20241205
environment:
- DBNAME=${DBNAME}
- DBUSER=${DBUSER}
@ -210,6 +215,7 @@ services:
- MASTER=${MASTER:-y}
- REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
- REDISPASS=${REDISPASS}
dns:
- ${IPV4_NETWORK:-172.22.1}.254
volumes:
@ -240,7 +246,7 @@ services:
- sogo
dovecot-mailcow:
image: mailcow/dovecot:nightly-20241112
image: mailcow/dovecot:nightly-20241205
depends_on:
- mysql-mailcow
- netfilter-mailcow
@ -282,6 +288,7 @@ services:
- MASTER=${MASTER:-y}
- REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
- REDISPASS=${REDISPASS}
- COMPOSE_PROJECT_NAME=${COMPOSE_PROJECT_NAME:-mailcow-dockerized}
- FLATCURVE_EXPERIMENTAL=${FLATCURVE_EXPERIMENTAL:-n}
ports:
@ -324,7 +331,7 @@ services:
- dovecot
postfix-mailcow:
image: mailcow/postfix:1.77
image: mailcow/postfix:1.78
depends_on:
mysql-mailcow:
condition: service_started
@ -346,6 +353,7 @@ services:
- DBPASS=${DBPASS}
- REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
- REDISPASS=${REDISPASS}
- MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME}
- SPAMHAUS_DQS_KEY=${SPAMHAUS_DQS_KEY:-}
cap_add:
@ -375,33 +383,26 @@ services:
nginx-mailcow:
depends_on:
- sogo-mailcow
- php-fpm-mailcow
- redis-mailcow
image: nginx:mainline-alpine
- php-fpm-mailcow
- sogo-mailcow
- rspamd-mailcow
image: mailcow/nginx:1.00
dns:
- ${IPV4_NETWORK:-172.22.1}.254
command: /bin/sh -c "envsubst < /etc/nginx/conf.d/templates/listen_plain.template > /etc/nginx/conf.d/listen_plain.active &&
envsubst < /etc/nginx/conf.d/templates/listen_ssl.template > /etc/nginx/conf.d/listen_ssl.active &&
envsubst < /etc/nginx/conf.d/templates/sogo.template > /etc/nginx/conf.d/sogo.active &&
. /etc/nginx/conf.d/templates/server_name.template.sh > /etc/nginx/conf.d/server_name.active &&
. /etc/nginx/conf.d/templates/sites.template.sh > /etc/nginx/conf.d/sites.active &&
. /etc/nginx/conf.d/templates/sogo_eas.template.sh > /etc/nginx/conf.d/sogo_eas.active &&
nginx -qt &&
until ping phpfpm -c1 > /dev/null; do sleep 1; done &&
until ping sogo -c1 > /dev/null; do sleep 1; done &&
until ping redis -c1 > /dev/null; do sleep 1; done &&
until ping rspamd -c1 > /dev/null; do sleep 1; done &&
exec nginx -g 'daemon off;'"
environment:
- HTTPS_PORT=${HTTPS_PORT:-443}
- HTTP_PORT=${HTTP_PORT:-80}
- MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME}
- IPV4_NETWORK=${IPV4_NETWORK:-172.22.1}
- ADDITIONAL_SERVER_NAMES=${ADDITIONAL_SERVER_NAMES:-}
- TZ=${TZ}
- SKIP_SOGO=${SKIP_SOGO:-n}
- ALLOW_ADMIN_EMAIL_LOGIN=${ALLOW_ADMIN_EMAIL_LOGIN:-n}
- ADDITIONAL_SERVER_NAMES=${ADDITIONAL_SERVER_NAMES:-}
- SKIP_RSPAMD=${SKIP_RSPAMD:-n}
- PHPFPMHOST=${PHPFPMHOST:-php-fpm-mailcow}
- SOGOHOST=${SOGOHOST:-sogo-mailcow}
- RSPAMDHOST=${RSPAMDHOST:-rspamd-mailcow}
- REDISHOST=${REDISHOST:-redis-mailcow}
- IPV4_NETWORK=${IPV4_NETWORK:-172.22.1}
volumes:
- ./data/web:/web:ro,z
- ./data/conf/rspamd/dynmaps:/dynmaps:ro,z
@ -428,7 +429,7 @@ services:
condition: service_started
unbound-mailcow:
condition: service_healthy
image: mailcow/acme:1.90
image: mailcow/acme:1.91
dns:
- ${IPV4_NETWORK:-172.22.1}.254
environment:
@ -451,6 +452,7 @@ services:
- TZ=${TZ}
- REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
- REDISPASS=${REDISPASS}
- SNAT_TO_SOURCE=${SNAT_TO_SOURCE:-n}
- SNAT6_TO_SOURCE=${SNAT6_TO_SOURCE:-n}
volumes:
@ -465,7 +467,7 @@ services:
- acme
netfilter-mailcow:
image: mailcow/netfilter:1.59
image: mailcow/netfilter:1.60
stop_grace_period: 30s
restart: always
privileged: true
@ -477,6 +479,7 @@ services:
- SNAT6_TO_SOURCE=${SNAT6_TO_SOURCE:-n}
- REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
- REDISPASS=${REDISPASS}
- MAILCOW_REPLICA_IP=${MAILCOW_REPLICA_IP:-}
- DISABLE_NETFILTER_ISOLATION_RULE=${DISABLE_NETFILTER_ISOLATION_RULE:-n}
network_mode: "host"
@ -484,7 +487,7 @@ services:
- /lib/modules:/lib/modules:ro
watchdog-mailcow:
image: mailcow/watchdog:2.05
image: mailcow/watchdog:2.06
dns:
- ${IPV4_NETWORK:-172.22.1}.254
tmpfs:
@ -530,6 +533,7 @@ services:
- HTTPS_PORT=${HTTPS_PORT:-443}
- REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
- REDISPASS=${REDISPASS}
- EXTERNAL_CHECKS_THRESHOLD=${EXTERNAL_CHECKS_THRESHOLD:-1}
- NGINX_THRESHOLD=${NGINX_THRESHOLD:-5}
- UNBOUND_THRESHOLD=${UNBOUND_THRESHOLD:-5}
@ -555,7 +559,7 @@ services:
- watchdog
dockerapi-mailcow:
image: mailcow/dockerapi:2.09
image: mailcow/dockerapi:2.10
security_opt:
- label=disable
restart: always
@ -566,6 +570,7 @@ services:
- TZ=${TZ}
- REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
- REDISPASS=${REDISPASS}
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:

View File

@ -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 -v | grep -oP '\d+\.\d+\.\d+' | 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"
@ -264,6 +264,12 @@ DBUSER=mailcow
DBPASS=$(LC_ALL=C </dev/urandom tr -dc A-Za-z0-9 2> /dev/null | head -c 28)
DBROOT=$(LC_ALL=C </dev/urandom tr -dc A-Za-z0-9 2> /dev/null | head -c 28)
# ------------------------------
# REDIS configuration
# ------------------------------
REDISPASS=$(LC_ALL=C </dev/urandom tr -dc A-Za-z0-9 2> /dev/null | head -c 28)
# ------------------------------
# HTTP/S Bindings
# ------------------------------

View File

@ -204,7 +204,7 @@ fi
# Trigger a Redis save for a consistent Redis copy
echo -ne "\033[1mRunning redis-cli save... \033[0m"
docker exec $(docker ps -qf name=redis-mailcow) redis-cli save
docker exec $(docker ps -qf name=redis-mailcow) redis-cli -a ${REDISPASS} --no-auth-warning save
# Syncing volumes related to compose project
# Same here: make sure destination exists

View File

@ -119,7 +119,7 @@ function backup() {
${DEBIAN_DOCKER_IMAGE} /bin/tar --warning='no-file-ignored' --use-compress-program="pigz --rsyncable -p ${THREADS}" -Pcvpf /backup/backup_crypt.tar.gz /crypt
;;&
redis|all)
docker exec $(docker ps -qf name=redis-mailcow) redis-cli save
docker exec $(docker ps -qf name=redis-mailcow) redis-cli -a ${REDISPASS} --no-auth-warning save
docker run --name mailcow-backup --rm \
-v ${BACKUP_LOCATION}/mailcow-${DATE}:/backup:z \
-v $(docker volume ls -qf name=^${CMPS_PRJ}_redis-vol-1$):/redis:ro,z \

View File

@ -101,11 +101,11 @@ if [[ ${NC_PURGE} == "y" ]]; then
echo -e "\033[33mNot purging anything...\033[0m"
exit 1
fi
docker exec -it $(docker ps -f name=redis-mailcow -q) /bin/sh -c ' cat <<EOF | redis-cli
docker exec -it $(docker ps -f name=redis-mailcow -q) /bin/sh -c "cat <<EOF | redis-cli -a ${REDISPASS} --no-auth-warning
SELECT 10
FLUSHDB
EOF
'
"
if [ -d ./data/web/nextcloud/config ]; then
mv ./data/web/nextcloud/config/ ./data/conf/nextcloud-config-folder-$(date +%s).bak
fi

View File

@ -15,15 +15,15 @@ if [[ "$response" =~ ^(yes|y)$ ]]; then
docker stop ${RSPAMD_ID}
echo "LUA will return nil when it succeeds or print a warning/error when it fails."
echo "Deleting all RS* keys - if any"
docker exec -it ${REDIS_ID} redis-cli EVAL "for _,k in ipairs(redis.call('keys', ARGV[1])) do redis.call('del', k) end" 0 'RS*'
docker exec -it ${REDIS_ID} redis-cli -a ${REDISPASS} --no-auth-warning EVAL "for _,k in ipairs(redis.call('keys', ARGV[1])) do redis.call('del', k) end" 0 'RS*'
echo "Deleting all BAYES* keys - if any"
docker exec -it ${REDIS_ID} redis-cli EVAL "for _,k in ipairs(redis.call('keys', ARGV[1])) do redis.call('del', k) end" 0 'BAYES*'
docker exec -it ${REDIS_ID} redis-cli -a ${REDISPASS} --no-auth-warning EVAL "for _,k in ipairs(redis.call('keys', ARGV[1])) do redis.call('del', k) end" 0 'BAYES*'
echo "Deleting all learned* keys - if any"
docker exec -it ${REDIS_ID} redis-cli EVAL "for _,k in ipairs(redis.call('keys', ARGV[1])) do redis.call('del', k) end" 0 'learned*'
docker exec -it ${REDIS_ID} redis-cli -a ${REDISPASS} --no-auth-warning EVAL "for _,k in ipairs(redis.call('keys', ARGV[1])) do redis.call('del', k) end" 0 'learned*'
echo "Deleting all fuzzy* keys - if any"
docker exec -it ${REDIS_ID} redis-cli EVAL "for _,k in ipairs(redis.call('keys', ARGV[1])) do redis.call('del', k) end" 0 'fuzzy*'
docker exec -it ${REDIS_ID} redis-cli -a ${REDISPASS} --no-auth-warning EVAL "for _,k in ipairs(redis.call('keys', ARGV[1])) do redis.call('del', k) end" 0 'fuzzy*'
echo "Deleting all tRFANN* keys - if any"
docker exec -it ${REDIS_ID} redis-cli EVAL "for _,k in ipairs(redis.call('keys', ARGV[1])) do redis.call('del', k) end" 0 'tRFANN*'
docker exec -it ${REDIS_ID} redis-cli -a ${REDISPASS} --no-auth-warning EVAL "for _,k in ipairs(redis.call('keys', ARGV[1])) do redis.call('del', k) end" 0 'tRFANN*'
echo "Starting Rspamd container"
docker start ${RSPAMD_ID}
fi

View File

@ -288,9 +288,9 @@ fix_broken_dnslist_conf() {
# Check if the file contains the autogenerated comment
if grep -q "# Autogenerated by mailcow" "$file"; then
# Ask the user if custom changes were made
echo -e "\e[91mWARNING!!! \e[31mAn old version of dns_blocklists.cnf has been detected which may cause a broken postfix upon startup (see: https://github.com/mailcow/mailcow-dockerized/issues/6143)...\e[0m"
echo -e "\e[91mWARNING!!! \e[31mAn old version of dns_blocklists.cf has been detected which may cause a broken postfix upon startup (see: https://github.com/mailcow/mailcow-dockerized/issues/6143)...\e[0m"
echo -e "\e[31mIf you have any custom settings in there you might copy it away and adapt the changes after the file is regenerated...\e[0m"
read -p "Do you want to delete the file now and let mailcow regenerate it properly? " response
read -p "Do you want to delete the file now and let mailcow regenerate it properly? [y/n]" response
if [[ "${response}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
rm "$file"
echo -e "\e[32mdns_blocklists.cf has been deleted and will be properly regenerated"
@ -540,6 +540,7 @@ CONFIG_ARRAY=(
"SPAMHAUS_DQS_KEY"
"SKIP_UNBOUND_HEALTHCHECK"
"DISABLE_NETFILTER_ISOLATION_RULE"
"REDISPASS"
)
detect_bad_asn
@ -832,6 +833,14 @@ for option in "${CONFIG_ARRAY[@]}"; do
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}" == "REDISPASS" ]]; then
if ! grep -q "${option}" mailcow.conf; then
echo "Adding new option \"${option}\" to mailcow.conf"
echo -e '\n# ------------------------------' >> mailcow.conf
echo '# REDIS configuration' >> mailcow.conf
echo -e '# ------------------------------\n' >> mailcow.conf
echo "REDISPASS=$(LC_ALL=C </dev/urandom tr -dc A-Za-z0-9 2> /dev/null | head -c 28)" >> mailcow.conf
fi
elif ! grep -q "${option}" mailcow.conf; then
echo "Adding new option \"${option}\" to mailcow.conf"
echo "${option}=n" >> mailcow.conf