From 3c9d0c9d577a3ac8a159a34c7851b14cd6d4ecb1 Mon Sep 17 00:00:00 2001 From: Peter Date: Thu, 27 Feb 2025 10:58:23 +0100 Subject: [PATCH 01/15] use ghcr.io for backupimage (#6333) * use ghcr.io for backup image * backup script: use renamed script + improved build of image --------- Co-authored-by: DerLinkman --- .github/workflows/rebuild_backup_image.yml | 14 +++++++++----- data/Dockerfiles/backup/Dockerfile | 2 +- helper-scripts/backup_and_restore.sh | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/.github/workflows/rebuild_backup_image.yml b/.github/workflows/rebuild_backup_image.yml index bf5caddf0..111b055de 100644 --- a/.github/workflows/rebuild_backup_image.yml +++ b/.github/workflows/rebuild_backup_image.yml @@ -9,6 +9,8 @@ on: jobs: docker_image_build: runs-on: ubuntu-latest + permissions: + packages: write steps: - name: Checkout uses: actions/checkout@v4 @@ -19,17 +21,19 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - name: Login to Docker Hub + - name: Login to GHCR + if: github.event_name != 'pull_request' uses: docker/login-action@v3 with: - username: ${{ secrets.BACKUPIMAGEBUILD_ACTION_DOCKERHUB_USERNAME }} - password: ${{ secrets.BACKUPIMAGEBUILD_ACTION_DOCKERHUB_TOKEN }} + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push - uses: docker/build-push-action@v6 + uses: docker/build-push-action@v5 with: context: . platforms: linux/amd64,linux/arm64 file: data/Dockerfiles/backup/Dockerfile push: true - tags: mailcow/backup:latest + tags: ghcr.io/mailcow/backup:latest \ No newline at end of file diff --git a/data/Dockerfiles/backup/Dockerfile b/data/Dockerfiles/backup/Dockerfile index 61c8bbe58..6234e725b 100644 --- a/data/Dockerfiles/backup/Dockerfile +++ b/data/Dockerfiles/backup/Dockerfile @@ -1,3 +1,3 @@ FROM debian:bookworm-slim -RUN apt update && apt install pigz \ No newline at end of file +RUN apt update && apt install pigz -y --no-install-recommends \ No newline at end of file diff --git a/helper-scripts/backup_and_restore.sh b/helper-scripts/backup_and_restore.sh index 581a84091..0cb37fce3 100755 --- a/helper-scripts/backup_and_restore.sh +++ b/helper-scripts/backup_and_restore.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -DEBIAN_DOCKER_IMAGE="mailcow/backup:latest" +DEBIAN_DOCKER_IMAGE="ghcr.io/mailcow/backup:latest" if [[ ! -z ${MAILCOW_BACKUP_LOCATION} ]]; then BACKUP_LOCATION="${MAILCOW_BACKUP_LOCATION}" From a4c2cf4c67fa4a73ca4d933e675a8c58c00618ba Mon Sep 17 00:00:00 2001 From: DerLinkman Date: Thu, 27 Feb 2025 11:44:52 +0100 Subject: [PATCH 02/15] scripts: adapted new docker image names to docker_garbage function + removed dup --- helper-scripts/_cold-standby.sh | 40 --------------------------------- update.sh | 16 ++++++++++--- 2 files changed, 13 insertions(+), 43 deletions(-) diff --git a/helper-scripts/_cold-standby.sh b/helper-scripts/_cold-standby.sh index e2e5f1556..9e7362ec6 100755 --- a/helper-scripts/_cold-standby.sh +++ b/helper-scripts/_cold-standby.sh @@ -10,46 +10,6 @@ echo "If this script is run automatically by cron or a timer AND you are using b echo "The snapshots of your backup destination should run AFTER the cold standby script finished to ensure consistent snapshots." echo -function docker_garbage() { - IMGS_TO_DELETE=() - - for container in $(grep -oP "image: \Kmailcow.+" docker-compose.yml); do - - REPOSITORY=${container/:*} - TAG=${container/*:} - V_MAIN=${container/*.} - V_SUB=${container/*.} - EXISTING_TAGS=$(docker images | grep ${REPOSITORY} | awk '{ print $2 }') - - for existing_tag in ${EXISTING_TAGS[@]}; do - - V_MAIN_EXISTING=${existing_tag/*.} - V_SUB_EXISTING=${existing_tag/*.} - - # Not an integer - [[ ! ${V_MAIN_EXISTING} =~ ^[0-9]+$ ]] && continue - [[ ! ${V_SUB_EXISTING} =~ ^[0-9]+$ ]] && continue - - if [[ ${V_MAIN_EXISTING} == "latest" ]]; then - echo "Found deprecated label \"latest\" for repository ${REPOSITORY}, it should be deleted." - IMGS_TO_DELETE+=(${REPOSITORY}:${existing_tag}) - elif [[ ${V_MAIN_EXISTING} -lt ${V_MAIN} ]]; then - echo "Found tag ${existing_tag} for ${REPOSITORY}, which is older than the current tag ${TAG} and should be deleted." - IMGS_TO_DELETE+=(${REPOSITORY}:${existing_tag}) - elif [[ ${V_SUB_EXISTING} -lt ${V_SUB} ]]; then - echo "Found tag ${existing_tag} for ${REPOSITORY}, which is older than the current tag ${TAG} and should be deleted." - IMGS_TO_DELETE+=(${REPOSITORY}:${existing_tag}) - fi - - done - - done - - if [[ ! -z ${IMGS_TO_DELETE[*]} ]]; then - docker rmi ${IMGS_TO_DELETE[*]} - fi -} - function preflight_local_checks() { if [[ -z "${REMOTE_SSH_KEY}" ]]; then >&2 echo -e "\e[31mREMOTE_SSH_KEY is not set\e[0m" diff --git a/update.sh b/update.sh index 9cfb02fd1..27972e82a 100755 --- a/update.sh +++ b/update.sh @@ -36,13 +36,23 @@ docker_garbage() { IMGS_TO_DELETE=() declare -A IMAGES_INFO - COMPOSE_IMAGES=($(grep -oP "image: \Kmailcow.+" "${SCRIPT_DIR}/docker-compose.yml")) + # Erfasse alle in docker-compose verwendeten Images (sowohl mailcow/... als auch ghcr.io/mailcow/...) + COMPOSE_IMAGES=($(grep -oP "image: \K(ghcr\.io/)?mailcow.+" "${SCRIPT_DIR}/docker-compose.yml")) - for existing_image in $(docker images --format "{{.ID}}:{{.Repository}}:{{.Tag}}" | grep 'mailcow/'); do + # Durchlaufe alle vorhandenen Images, die mailcow/ oder ghcr.io/mailcow/ beinhalten + for existing_image in $(docker images --format "{{.ID}}:{{.Repository}}:{{.Tag}}" | grep -E '(mailcow/|ghcr\.io/mailcow/)'); do ID=$(echo "$existing_image" | cut -d ':' -f 1) REPOSITORY=$(echo "$existing_image" | cut -d ':' -f 2) TAG=$(echo "$existing_image" | cut -d ':' -f 3) + # Für das Image mailcow/backup: nur löschen, wenn es untagged ist (TAG gleich "") + if [[ "$REPOSITORY" == "mailcow/backup" || "$REPOSITORY" == "ghcr.io/mailcow/backup" ]]; then + if [[ "$TAG" != "" ]]; then + continue + fi + fi + + # Überspringe Images, die in der docker-compose.yml verwendet werden if [[ " ${COMPOSE_IMAGES[@]} " =~ " ${REPOSITORY}:${TAG} " ]]; then continue else @@ -57,7 +67,7 @@ docker_garbage() { echo " ${IMAGES_INFO[$id]} ($id)" done - if [ ! $FORCE ]; then + if [ -z "$FORCE" ]; then read -r -p "Do you want to delete them to free up some space? [y/N] " response if [[ "$response" =~ ^([yY][eE][sS]|[yY])+$ ]]; then docker rmi ${IMGS_TO_DELETE[*]} From 5296085189fd6ca6938734a0a112b53d41b9adc0 Mon Sep 17 00:00:00 2001 From: DerLinkman Date: Thu, 27 Feb 2025 11:47:08 +0100 Subject: [PATCH 03/15] update.sh: corrected typos inside update.sh --- update.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/update.sh b/update.sh index 27972e82a..838899f8b 100755 --- a/update.sh +++ b/update.sh @@ -36,23 +36,19 @@ docker_garbage() { IMGS_TO_DELETE=() declare -A IMAGES_INFO - # Erfasse alle in docker-compose verwendeten Images (sowohl mailcow/... als auch ghcr.io/mailcow/...) COMPOSE_IMAGES=($(grep -oP "image: \K(ghcr\.io/)?mailcow.+" "${SCRIPT_DIR}/docker-compose.yml")) - # Durchlaufe alle vorhandenen Images, die mailcow/ oder ghcr.io/mailcow/ beinhalten for existing_image in $(docker images --format "{{.ID}}:{{.Repository}}:{{.Tag}}" | grep -E '(mailcow/|ghcr\.io/mailcow/)'); do ID=$(echo "$existing_image" | cut -d ':' -f 1) REPOSITORY=$(echo "$existing_image" | cut -d ':' -f 2) TAG=$(echo "$existing_image" | cut -d ':' -f 3) - # Für das Image mailcow/backup: nur löschen, wenn es untagged ist (TAG gleich "") if [[ "$REPOSITORY" == "mailcow/backup" || "$REPOSITORY" == "ghcr.io/mailcow/backup" ]]; then if [[ "$TAG" != "" ]]; then continue fi fi - # Überspringe Images, die in der docker-compose.yml verwendet werden if [[ " ${COMPOSE_IMAGES[@]} " =~ " ${REPOSITORY}:${TAG} " ]]; then continue else From 4bd267515ac9c08ae967c0a20315b32b5cf595b6 Mon Sep 17 00:00:00 2001 From: milkmaker Date: Sat, 1 Mar 2025 13:32:21 +0100 Subject: [PATCH 04/15] update postscreen_access.cidr (#6345) --- data/conf/postfix/postscreen_access.cidr | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/data/conf/postfix/postscreen_access.cidr b/data/conf/postfix/postscreen_access.cidr index 69be54247..c6ed2be93 100644 --- a/data/conf/postfix/postscreen_access.cidr +++ b/data/conf/postfix/postscreen_access.cidr @@ -1,6 +1,6 @@ -# Whitelist generated by Postwhite v3.4 on Sat Feb 1 00:18:03 UTC 2025 +# Whitelist generated by Postwhite v3.4 on Sat Mar 1 00:19:29 UTC 2025 # https://github.com/stevejenkins/postwhite/ -# 1984 total rules +# 2000 total rules 2a00:1450:4000::/36 permit 2a01:111:f400::/48 permit 2a01:111:f403:8000::/50 permit @@ -8,6 +8,13 @@ 2a01:111:f403::/49 permit 2a01:111:f403:c000::/51 permit 2a01:111:f403:f000::/52 permit +2a01:b747:3000:200::/56 permit +2a01:b747:3001:200::/56 permit +2a01:b747:3002:200::/56 permit +2a01:b747:3003:200::/56 permit +2a01:b747:3004:200::/56 permit +2a01:b747:3005:200::/56 permit +2a01:b747:3006:200::/56 permit 2a02:a60:0:5::/64 permit 2c0f:fb50:4000::/36 permit 2.207.151.53 permit @@ -19,7 +26,6 @@ 8.20.114.31 permit 8.25.194.0/23 permit 8.25.196.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 @@ -35,7 +41,9 @@ 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.97.0.8/30 permit +18.97.1.184/29 permit +18.97.2.64/26 permit 18.156.89.250 permit 18.157.243.190 permit 18.194.95.56 permit @@ -283,6 +291,9 @@ 64.207.219.13 permit 64.207.219.14 permit 64.207.219.15 permit +64.207.219.24 permit +64.207.219.25 permit +64.207.219.26 permit 64.207.219.71 permit 64.207.219.72 permit 64.207.219.73 permit @@ -292,6 +303,9 @@ 64.207.219.77 permit 64.207.219.78 permit 64.207.219.79 permit +64.207.219.88 permit +64.207.219.89 permit +64.207.219.90 permit 64.207.219.135 permit 64.207.219.136 permit 64.207.219.137 permit @@ -1464,6 +1478,8 @@ 159.135.224.0/20 permit 159.135.228.10 permit 159.183.0.0/16 permit +159.183.68.71 permit +159.183.79.38 permit 160.1.62.192 permit 161.38.192.0/20 permit 161.38.204.0/22 permit From 81803836f073b355f7d86f703e2265c3c365ff0a Mon Sep 17 00:00:00 2001 From: milkmaker Date: Mon, 3 Mar 2025 22:49:23 +0100 Subject: [PATCH 05/15] [Web] Updated lang.ko-kr.json (#6350) Co-authored-by: dongsu8142 --- data/web/lang/lang.ko-kr.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/data/web/lang/lang.ko-kr.json b/data/web/lang/lang.ko-kr.json index 27b028cd4..4bc14ab69 100644 --- a/data/web/lang/lang.ko-kr.json +++ b/data/web/lang/lang.ko-kr.json @@ -25,7 +25,10 @@ "syncjobs": "동기화 작업", "tls_policy": "TLS 정책", "unlimited_quota": "메일에 무제한 할당", - "domain_desc": "도메인 설명 변경" + "domain_desc": "도메인 설명 변경", + "pw_reset": "mailcow 사용자 비밀번호 재설정 허용", + "domain_relayhost": "도메인의 릴레이 호스트 변경", + "mailbox_relayhost": "메일함의 릴레이 호스트 변경" }, "add": { "activate_filter_warn": "활성화가 체크되어 있으면 모든 다른 필터들은 비활성화됩니다.", From 79f4cf40211afc9c5010acb3c888a96bfff44a17 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 5 Mar 2025 16:35:46 +0100 Subject: [PATCH 06/15] chore(deps): update docker/build-push-action action to v6 (#6334) --- .github/workflows/rebuild_backup_image.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rebuild_backup_image.yml b/.github/workflows/rebuild_backup_image.yml index 111b055de..adf69eb35 100644 --- a/.github/workflows/rebuild_backup_image.yml +++ b/.github/workflows/rebuild_backup_image.yml @@ -30,7 +30,7 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: . platforms: linux/amd64,linux/arm64 From 0435766c171f6ede78c6b57e15ac543bb42a5a64 Mon Sep 17 00:00:00 2001 From: milkmaker Date: Wed, 5 Mar 2025 17:43:37 +0100 Subject: [PATCH 07/15] [Web] Updated lang.ko-kr.json (#6353) Co-authored-by: dongsu8142 --- data/web/lang/lang.ko-kr.json | 88 ++++++++++++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 7 deletions(-) diff --git a/data/web/lang/lang.ko-kr.json b/data/web/lang/lang.ko-kr.json index 4bc14ab69..546ccdfcc 100644 --- a/data/web/lang/lang.ko-kr.json +++ b/data/web/lang/lang.ko-kr.json @@ -28,7 +28,8 @@ "domain_desc": "도메인 설명 변경", "pw_reset": "mailcow 사용자 비밀번호 재설정 허용", "domain_relayhost": "도메인의 릴레이 호스트 변경", - "mailbox_relayhost": "메일함의 릴레이 호스트 변경" + "mailbox_relayhost": "메일함의 릴레이 호스트 변경", + "quarantine_category": "검역소 알림 카테고리 변경" }, "add": { "activate_filter_warn": "활성화가 체크되어 있으면 모든 다른 필터들은 비활성화됩니다.", @@ -104,7 +105,9 @@ "timeout2": "로컬 호스트 연결 시간 초과", "username": "사용자명", "validate": "확인하기", - "validation_success": "성공적으로 확인됨" + "validation_success": "성공적으로 확인됨", + "tags": "태그", + "app_passwd_protocols": "앱 비밀번호에 대해 허용되는 프로토콜" }, "admin": { "access": "접근", @@ -304,7 +307,50 @@ "username": "사용자 이름", "validate_license_now": "라이선스 서버와 GUID 확인", "verify": "확인", - "yes": "✓" + "yes": "✓", + "domain_admin": "도메인 관리자", + "f2b_filter": "정규식 필터", + "f2b_manage_external": "외부에서 Fail2Ban 관리", + "f2b_max_ban_time": "최대 차단 시간(초)", + "f2b_regex_info": "고려되는 로그: SOGo, Postfix, Dovecot, PHP-FPM.", + "html": "HTML", + "oauth2_apps": "OAuth2 앱", + "oauth2_add_client": "OAuth2 클라이언트 추가", + "optional": "선택 사항", + "options": "옵션", + "password_length": "비밀번호 길이", + "password_policy_chars": "하나 이상의 알파벳 문자를 포함해야 합니다.", + "password_policy_length": "최소 암호 길이가 %d입니다.", + "password_policy_numbers": "숫자 하나 이상을 포함해야 합니다.", + "password_policy_special_chars": "특수 문자를 포함해야 합니다.", + "password_reset_info": "복구 이메일이 제공되지 않으면 이 기능을 사용할 수 없습니다.", + "password_reset_settings": "비밀번호 복구 설정", + "password_reset_tmpl_html": "HTML 템플릿", + "password_reset_tmpl_text": "Text 템플릿", + "password_settings": "비밀번호 설정", + "queue_unban": "차단 해제", + "restore_template": "기본 템플릿을 복원하려면 비워둡니다.", + "service": "서비스", + "success": "성공", + "dkim_overwrite_key": "기존 DKIM 키 덮어쓰기", + "f2b_ban_time_increment": "차단 시간은 차단될 때마다 증가합니다.", + "password_policy": "비밀번호 정책", + "quarantine_max_score": "메일의 스팸 점수가 이 값보다 높으면 알림을 삭제합니다:
기본값: 9999.0", + "f2b_manage_external_info": "Fail2ban은 차단 목록을 유지하지만 트래픽을 차단하는 규칙을 능동적으로 설정하지는 않습니다. 트래픽을 외부에서 차단하려면 아래 생성된 차단 목록을 사용하세요.", + "password_policy_lowerupper": "소문자 및 대문자를 포함해야 합니다.", + "transport_test_rcpt_info": "• null@hosted.mailcow.de 을 사용하여 해외 목적지로 릴레이를 테스트하세요.", + "ip_check_disabled": "IP 확인이 비활성화됩니다. 아래에서 활성화할 수 있습니다
시스템 > 구성 > 옵션 > 사용자 정의", + "logo_normal_label": "일반", + "logo_dark_label": "다크 모드의 경우 반전", + "convert_html_to_text": "HTML을 일반 텍스트로 변환", + "copy_to_clipboard": "클립보드에 텍스트가 복사되었습니다!", + "cors_settings": "CORS 설정", + "rsettings_preset_4": "도메인에 대해 Rspamd 비활성화", + "ip_check": "IP 확인", + "admins": "관리자", + "admins_ldap": "LDAP 관리자", + "api_read_only": "읽기 전용 액세스", + "api_read_write": "읽기-쓰기 액세스" }, "danger": { "access_denied": "접근이 거부되거나 잘못된 데이터 양식", @@ -418,7 +464,28 @@ "username_invalid": "%s는 사용지 이름으로 사용할 수 없습니다.", "validity_missing": "유효 기간을 지정해주세요.", "value_missing": "모든 값을 입력해주세요.", - "yotp_verification_failed": "Yubico OTP 검증 실패: %s" + "yotp_verification_failed": "Yubico OTP 검증 실패: %s", + "dkim_domain_or_sel_exists": "“%s\"에 대한 DKIM 키가 존재하며 덮어쓰지 않습니다.", + "img_size_exceeded": "이미지가 최대 파일 크기를 초과합니다.", + "invalid_reset_token": "잘못된 리셋 토큰", + "nginx_reload_failed": "Nginx 리로드 실패: %s", + "password_reset_na": "현재 비밀번호 복구를 사용할 수 없습니다. 관리자에게 문의하세요.", + "reset_f2b_regex": "정규식 필터를 제때 재설정하지 못했습니다. 다시 시도하거나 몇 초 더 기다렸다가 웹사이트를 다시 로드하세요.", + "template_exists": "템플릿 %s이(가) 이미 존재합니다.", + "template_id_invalid": "템플릿 ID %s가 잘못되었습니다.", + "template_name_invalid": "템플릿 이름이 잘못되었습니다.", + "tfa_token_invalid": "TFA 토큰이 유효하지 않습니다.", + "to_invalid": "수신자가 비어 있지 않아야 합니다.", + "webauthn_authenticator_failed": "선택한 인증기를 찾을 수 없습니다.", + "webauthn_username_failed": "선택한 인증기가 다른 계정에 속해 있습니다.", + "demo_mode_enabled": "데모 모드가 활성화됨", + "recovery_email_failed": "복구 이메일을 보낼 수 없습니다. 관리자에게 문의하세요.", + "password_reset_invalid_user": "사서함을 찾을 수 없거나 복구 이메일이 설정되어 있지 않습니다.", + "webauthn_publickey_failed": "선택한 인증기에 대한 공개 키가 저장되지 않았습니다.", + "fido2_verification_failed": "FIDO2 인증 실패: %s", + "extended_sender_acl_denied": "외부 발신자 주소를 설정하는 ACL 누락", + "img_dimensions_exceeded": "이미지가 최대 이미지 크기를 초과합니다.", + "reset_token_limit_exceeded": "토큰 재설정 한도를 초과했습니다. 나중에 다시 시도해 주세요." }, "debug": { "chart_this_server": "Chart (this server)", @@ -437,7 +504,9 @@ "uptime": "Uptime", "started_on": "Started on", "static_logs": "Static logs", - "system_containers": "System & Containers" + "system_containers": "System & Containers", + "current_time": "시스템 시간", + "no_update_available": "시스템이 최신 버전입니다." }, "diagnostics": { "cname_from_a": "Value derived from A/AAAA record. This is supported as long as the record points to the correct resource.", @@ -563,13 +632,14 @@ "header": { "administration": "Configuration & Details", "apps": "Apps", - "debug": "System Information", + "debug": "정보", "email": "E-Mail", "mailcow_config": "Configuration", "quarantine": "Quarantine", "restart_netfilter": "Restart netfilter", "restart_sogo": "Restart SOGo", - "user_settings": "User Settings" + "user_settings": "User Settings", + "mailcow_system": "시스템" }, "info": { "awaiting_tfa_confirmation": "Awaiting TFA confirmation", @@ -1020,5 +1090,9 @@ "quota_exceeded_scope": "Domain quota exceeded: Only unlimited mailboxes can be created in this domain scope.", "session_token": "Form token invalid: Token mismatch", "session_ua": "Form token invalid: User-Agent validation error" + }, + "datatables": { + "collapse_all": "모두 접기", + "decimal": "." } } From 03565df48dd5dd818899e8794cbef4ac1e6029c4 Mon Sep 17 00:00:00 2001 From: milkmaker Date: Fri, 7 Mar 2025 21:37:31 +0100 Subject: [PATCH 08/15] [Web] Updated lang.ko-kr.json (#6356) Co-authored-by: dongsu8142 --- data/web/lang/lang.ko-kr.json | 54 +++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/data/web/lang/lang.ko-kr.json b/data/web/lang/lang.ko-kr.json index 546ccdfcc..9e281584b 100644 --- a/data/web/lang/lang.ko-kr.json +++ b/data/web/lang/lang.ko-kr.json @@ -201,7 +201,7 @@ "link": "Link", "loading": "잠시만 기다려주세요...", "logo_info": "이미지 크기는 상단 탐색 막대의 경우 40px, 시작 페이지의 경우 최대 너비 250px로 조정됩니다. 확장 가능한 그래픽을 권장합니다.", - "lookup_mx": "MX와 목적지 일치 (.outlook.com이 홉을 통해서 MX *.outlook.com을 대상으로 하는 모든 메일을 라우트한다.)", + "lookup_mx": "목적지가 MX 이름과 일치하는 정규 표현식입니다. (.*\\.google\\.com를 사용하여 이 홉을 통해 google.com으로 끝나는 모든 메일을 대상으로 하는 MX로 라우팅합니다.)", "main_name": "\"mailcow UI\" 이름", "merged_vars_hint": "회색으로 표시된 행은 vars.(local.)php 에서 병합되었고 이는 수정할 수 없습니다.", "message": "메세지", @@ -350,7 +350,10 @@ "admins": "관리자", "admins_ldap": "LDAP 관리자", "api_read_only": "읽기 전용 액세스", - "api_read_write": "읽기-쓰기 액세스" + "api_read_write": "읽기-쓰기 액세스", + "is_mx_based": "MX 기반", + "login_time": "로그인 시간", + "ip_check_opt_in": "외부 IP 주소 확인을 위해 타사 서비스 ipv4.mailcow.emailipv6.mailcow.email을 사용하도록 설정합니다." }, "danger": { "access_denied": "접근이 거부되거나 잘못된 데이터 양식", @@ -485,7 +488,9 @@ "fido2_verification_failed": "FIDO2 인증 실패: %s", "extended_sender_acl_denied": "외부 발신자 주소를 설정하는 ACL 누락", "img_dimensions_exceeded": "이미지가 최대 이미지 크기를 초과합니다.", - "reset_token_limit_exceeded": "토큰 재설정 한도를 초과했습니다. 나중에 다시 시도해 주세요." + "reset_token_limit_exceeded": "토큰 재설정 한도를 초과했습니다. 나중에 다시 시도해 주세요.", + "cors_invalid_method": "잘못된 허용 메서드를 지정했습니다.", + "cors_invalid_origin": "잘못된 허용 원본을 지정했습니다." }, "debug": { "chart_this_server": "Chart (this server)", @@ -506,7 +511,22 @@ "static_logs": "Static logs", "system_containers": "System & Containers", "current_time": "시스템 시간", - "no_update_available": "시스템이 최신 버전입니다." + "no_update_available": "시스템이 최신 버전입니다.", + "architecture": "아키텍처", + "container_running": "실행 중", + "container_disabled": "컨테이너 중지 또는 비활성화", + "container_stopped": "중지됨", + "online_users": "온라인 사용자", + "service": "서비스", + "success": "성공", + "show_ip": "공인 IP 표시", + "timezone": "시간대", + "update_available": "사용 가능한 업데이트가 있습니다.", + "update_failed": "업데이트를 확인할 수 없습니다", + "username": "사용자 이름", + "memory": "메모리", + "error_show_ip": "공인 IP 주소를 확인할 수 없습니다", + "login_time": "시간" }, "diagnostics": { "cname_from_a": "Value derived from A/AAAA record. This is supported as long as the record points to the correct resource.", @@ -614,7 +634,13 @@ "title": "Edit object", "unchanged_if_empty": "If unchanged leave blank", "username": "Username", - "validate_save": "Validate and save" + "validate_save": "Validate and save", + "allow_from_smtp": "다음 IP만 SMTP를 사용하도록 허용합니다.", + "allow_from_smtp_info": "모든 발신자를 허용하려면 비워둡니다.
IPv4/IPv6 주소 및 네트워크.", + "allowed_protocols": "허용된 프로토콜", + "app_passwd_protocols": "앱 비밀번호에 대해 허용되는 프로토콜", + "acl": "ACL (권한)", + "admin": "관리자 수정" }, "footer": { "cancel": "Cancel", @@ -1093,6 +1119,22 @@ }, "datatables": { "collapse_all": "모두 접기", - "decimal": "." + "decimal": ".", + "emptyTable": "테이블에 사용 가능한 데이터가 없습니다.", + "expand_all": "모두 펼치기", + "infoEmpty": "0개 항목 중 0개부터 0개까지 표시", + "infoFiltered": "(_MAX_ 총 항목에서 필터링됨)", + "thousands": ",", + "lengthMenu": "_MENU_ 항목 표시", + "loadingRecords": "로딩 중...", + "processing": "잠시만 기다려 주세요...", + "search": "검색:", + "zeroRecords": "일치하는 레코드가 없습니다.", + "paginate": { + "first": "처음", + "last": "마지막", + "next": "다음", + "previous": "이전" + } } } From 86df78255d8bc558ddcf23bfae0d2ef8313072ed Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Mar 2025 11:39:19 +0100 Subject: [PATCH 09/15] chore(deps): update dependency composer/composer to v2.8.6 (#5719) Signed-off-by: milkmaker Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- data/Dockerfiles/phpfpm/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/Dockerfiles/phpfpm/Dockerfile b/data/Dockerfiles/phpfpm/Dockerfile index 038c586a8..f5ae3fbd7 100644 --- a/data/Dockerfiles/phpfpm/Dockerfile +++ b/data/Dockerfiles/phpfpm/Dockerfile @@ -13,7 +13,7 @@ ARG MEMCACHED_PECL_VERSION=3.2.0 # renovate: datasource=github-tags depName=phpredis/phpredis versioning=semver-coerced extractVersion=(?.*)$ ARG REDIS_PECL_VERSION=6.1.0 # renovate: datasource=github-tags depName=composer/composer versioning=semver-coerced extractVersion=(?.*)$ -ARG COMPOSER_VERSION=2.6.6 +ARG COMPOSER_VERSION=2.8.6 RUN apk add -U --no-cache autoconf \ aspell-dev \ From 0860a7503e29cf268a58e1a593367ea8f9f9816d Mon Sep 17 00:00:00 2001 From: DerLinkman Date: Mon, 10 Mar 2025 11:56:12 +0100 Subject: [PATCH 10/15] os: updated alpine containers to 3.21 --- data/Dockerfiles/acme/Dockerfile | 4 ++-- data/Dockerfiles/dockerapi/Dockerfile | 2 +- data/Dockerfiles/dovecot/Dockerfile | 4 ++-- data/Dockerfiles/netfilter/Dockerfile | 2 +- data/Dockerfiles/olefy/Dockerfile | 2 +- data/Dockerfiles/phpfpm/Dockerfile | 2 +- data/Dockerfiles/unbound/Dockerfile | 2 +- data/Dockerfiles/watchdog/Dockerfile | 2 +- docker-compose.yml | 16 ++++++++-------- 9 files changed, 18 insertions(+), 18 deletions(-) diff --git a/data/Dockerfiles/acme/Dockerfile b/data/Dockerfiles/acme/Dockerfile index 8aa16ad58..5b7378c7b 100644 --- a/data/Dockerfiles/acme/Dockerfile +++ b/data/Dockerfiles/acme/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.20 +FROM alpine:3.21 LABEL maintainer = "The Infrastructure Company GmbH " @@ -15,7 +15,7 @@ RUN apk upgrade --no-cache \ tini \ tzdata \ python3 \ - acme-tiny --repository=http://dl-cdn.alpinelinux.org/alpine/edge/community/ + acme-tiny COPY acme.sh /srv/acme.sh COPY functions.sh /srv/functions.sh diff --git a/data/Dockerfiles/dockerapi/Dockerfile b/data/Dockerfiles/dockerapi/Dockerfile index bbd4542e6..872764317 100644 --- a/data/Dockerfiles/dockerapi/Dockerfile +++ b/data/Dockerfiles/dockerapi/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.20 +FROM alpine:3.21 LABEL maintainer = "The Infrastructure Company GmbH " diff --git a/data/Dockerfiles/dovecot/Dockerfile b/data/Dockerfiles/dovecot/Dockerfile index 1c35639e9..6b846cec8 100644 --- a/data/Dockerfiles/dovecot/Dockerfile +++ b/data/Dockerfiles/dovecot/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.20 +FROM alpine:3.21 LABEL maintainer="The Infrastructure Company GmbH " @@ -65,7 +65,7 @@ RUN addgroup -g 5000 vmail \ perl-par-packer \ perl-parse-recdescent \ perl-lockfile-simple \ - libproc \ + libproc2 \ perl-readonly \ perl-regexp-common \ perl-sys-meminfo \ diff --git a/data/Dockerfiles/netfilter/Dockerfile b/data/Dockerfiles/netfilter/Dockerfile index 86f9e3f69..57dbd6e94 100644 --- a/data/Dockerfiles/netfilter/Dockerfile +++ b/data/Dockerfiles/netfilter/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.20 +FROM alpine:3.21 LABEL maintainer = "The Infrastructure Company GmbH " diff --git a/data/Dockerfiles/olefy/Dockerfile b/data/Dockerfiles/olefy/Dockerfile index 3b2729134..845b125f6 100644 --- a/data/Dockerfiles/olefy/Dockerfile +++ b/data/Dockerfiles/olefy/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.20 +FROM alpine:3.21 LABEL maintainer = "The Infrastructure Company GmbH " diff --git a/data/Dockerfiles/phpfpm/Dockerfile b/data/Dockerfiles/phpfpm/Dockerfile index f5ae3fbd7..4ba8349f9 100644 --- a/data/Dockerfiles/phpfpm/Dockerfile +++ b/data/Dockerfiles/phpfpm/Dockerfile @@ -1,4 +1,4 @@ -FROM php:8.2-fpm-alpine3.20 +FROM php:8.2-fpm-alpine3.21 LABEL maintainer = "The Infrastructure Company GmbH " diff --git a/data/Dockerfiles/unbound/Dockerfile b/data/Dockerfiles/unbound/Dockerfile index 7e4f18dec..4903750ed 100644 --- a/data/Dockerfiles/unbound/Dockerfile +++ b/data/Dockerfiles/unbound/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.20 +FROM alpine:3.21 LABEL maintainer = "The Infrastructure Company GmbH " diff --git a/data/Dockerfiles/watchdog/Dockerfile b/data/Dockerfiles/watchdog/Dockerfile index f8aa262bb..a55a97a4c 100644 --- a/data/Dockerfiles/watchdog/Dockerfile +++ b/data/Dockerfiles/watchdog/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.20 +FROM alpine:3.21 LABEL maintainer = "The Infrastructure Company GmbH " diff --git a/docker-compose.yml b/docker-compose.yml index 4c470f5bd..7ddbd1240 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ services: unbound-mailcow: - image: ghcr.io/mailcow/unbound:1.23 + image: ghcr.io/mailcow/unbound:1.24 environment: - TZ=${TZ} - SKIP_UNBOUND_HEALTHCHECK=${SKIP_UNBOUND_HEALTHCHECK:-n} @@ -117,7 +117,7 @@ services: - rspamd php-fpm-mailcow: - image: ghcr.io/mailcow/phpfpm:1.92 + image: ghcr.io/mailcow/phpfpm:1.93 command: "php-fpm -d date.timezone=${TZ} -d expose_php=0" depends_on: - redis-mailcow @@ -234,7 +234,7 @@ services: - sogo dovecot-mailcow: - image: ghcr.io/mailcow/dovecot:2.31 + image: ghcr.io/mailcow/dovecot:2.32 depends_on: - mysql-mailcow - netfilter-mailcow @@ -419,7 +419,7 @@ services: condition: service_started unbound-mailcow: condition: service_healthy - image: ghcr.io/mailcow/acme:1.91 + image: ghcr.io/mailcow/acme:1.92 dns: - ${IPV4_NETWORK:-172.22.1}.254 environment: @@ -457,7 +457,7 @@ services: - acme netfilter-mailcow: - image: ghcr.io/mailcow/netfilter:1.61 + image: ghcr.io/mailcow/netfilter:1.62 stop_grace_period: 30s restart: always privileged: true @@ -477,7 +477,7 @@ services: - /lib/modules:/lib/modules:ro watchdog-mailcow: - image: ghcr.io/mailcow/watchdog:2.06 + image: ghcr.io/mailcow/watchdog:2.07 dns: - ${IPV4_NETWORK:-172.22.1}.254 tmpfs: @@ -549,7 +549,7 @@ services: - watchdog dockerapi-mailcow: - image: ghcr.io/mailcow/dockerapi:2.10 + image: ghcr.io/mailcow/dockerapi:2.11 security_opt: - label=disable restart: always @@ -569,7 +569,7 @@ services: - dockerapi olefy-mailcow: - image: ghcr.io/mailcow/olefy:1.13 + image: ghcr.io/mailcow/olefy:1.14 restart: always environment: - TZ=${TZ} From 2f93f1d0c5b9642190c1358a03038be4c3f4bb43 Mon Sep 17 00:00:00 2001 From: DerLinkman Date: Mon, 10 Mar 2025 16:45:57 +0100 Subject: [PATCH 11/15] os: fixes for newer mariadb-client versions (especially on alpine 3.21) --- data/Dockerfiles/acme/Dockerfile | 1 - data/Dockerfiles/acme/acme.sh | 4 +-- data/Dockerfiles/dovecot/clean_q_aged.sh | 4 +-- data/Dockerfiles/dovecot/docker-entrypoint.sh | 10 +++---- data/Dockerfiles/phpfpm/docker-entrypoint.sh | 12 ++++---- data/Dockerfiles/sogo/bootstrap-sogo.sh | 28 +++++++++---------- .../watchdog/check_mysql_slavestatus.sh | 4 +-- data/Dockerfiles/watchdog/watchdog.sh | 2 +- 8 files changed, 32 insertions(+), 33 deletions(-) diff --git a/data/Dockerfiles/acme/Dockerfile b/data/Dockerfiles/acme/Dockerfile index 5b7378c7b..f6e990e57 100644 --- a/data/Dockerfiles/acme/Dockerfile +++ b/data/Dockerfiles/acme/Dockerfile @@ -2,7 +2,6 @@ FROM alpine:3.21 LABEL maintainer = "The Infrastructure Company GmbH " - RUN apk upgrade --no-cache \ && apk add --update --no-cache \ bash \ diff --git a/data/Dockerfiles/acme/acme.sh b/data/Dockerfiles/acme/acme.sh index 64a4d1765..a6766efd0 100755 --- a/data/Dockerfiles/acme/acme.sh +++ b/data/Dockerfiles/acme/acme.sh @@ -138,7 +138,7 @@ log_f "Resolver OK" log_f "Waiting for domain table..." while [[ -z ${DOMAIN_TABLE} ]]; do curl --silent http://nginx.${COMPOSE_PROJECT_NAME}_mailcow-network/ >/dev/null 2>&1 - DOMAIN_TABLE=$(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SHOW TABLES LIKE 'domain'" -Bs) + DOMAIN_TABLE=$(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SHOW TABLES LIKE 'domain'" -Bs) [[ -z ${DOMAIN_TABLE} ]] && sleep 10 done log_f "OK" no_date @@ -231,7 +231,7 @@ while true; do ######################################### # IP and webroot challenge verification # - SQL_DOMAINS=$(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT domain FROM domain WHERE backupmx=0 and active=1" -Bs) + SQL_DOMAINS=$(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT domain FROM domain WHERE backupmx=0 and active=1" -Bs) if [[ ! $? -eq 0 ]]; then log_f "Failed to read SQL domains, retrying in 1 minute..." sleep 1m diff --git a/data/Dockerfiles/dovecot/clean_q_aged.sh b/data/Dockerfiles/dovecot/clean_q_aged.sh index 3fa8a7ddb..ebedc8999 100755 --- a/data/Dockerfiles/dovecot/clean_q_aged.sh +++ b/data/Dockerfiles/dovecot/clean_q_aged.sh @@ -15,6 +15,6 @@ if ! [[ ${MAX_AGE} =~ ${NUM_REGEXP} ]] ; then exit 1 fi -TO_DELETE=$(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT COUNT(id) FROM quarantine WHERE created < NOW() - INTERVAL ${MAX_AGE//[!0-9]/} DAY" -BN) -mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "DELETE FROM quarantine WHERE created < NOW() - INTERVAL ${MAX_AGE//[!0-9]/} DAY" +TO_DELETE=$(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT COUNT(id) FROM quarantine WHERE created < NOW() - INTERVAL ${MAX_AGE//[!0-9]/} DAY" -BN) +mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "DELETE FROM quarantine WHERE created < NOW() - INTERVAL ${MAX_AGE//[!0-9]/} DAY" echo "Deleted ${TO_DELETE} items from quarantine table (max age is ${MAX_AGE//[!0-9]/} days)" diff --git a/data/Dockerfiles/dovecot/docker-entrypoint.sh b/data/Dockerfiles/dovecot/docker-entrypoint.sh index af67579f1..9a4e2f252 100755 --- a/data/Dockerfiles/dovecot/docker-entrypoint.sh +++ b/data/Dockerfiles/dovecot/docker-entrypoint.sh @@ -414,15 +414,15 @@ printenv | sed 's/^\(.*\)$/export \1/g' > /source_env.sh # Clean stopped imapsync jobs rm -f /tmp/imapsync_busy.lock -IMAPSYNC_TABLE=$(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SHOW TABLES LIKE 'imapsync'" -Bs) -[[ ! -z ${IMAPSYNC_TABLE} ]] && mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "UPDATE imapsync SET is_running='0'" +IMAPSYNC_TABLE=$(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SHOW TABLES LIKE 'imapsync'" -Bs) +[[ ! -z ${IMAPSYNC_TABLE} ]] && mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "UPDATE imapsync SET is_running='0'" # Envsubst maildir_gc echo "$(envsubst < /usr/local/bin/maildir_gc.sh)" > /usr/local/bin/maildir_gc.sh # GUID generation while [[ ${VERSIONS_OK} != 'OK' ]]; do - if [[ ! -z $(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "SELECT 'OK' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = \"${DBNAME}\" AND TABLE_NAME = 'versions'") ]]; then + if [[ ! -z $(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "SELECT 'OK' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = \"${DBNAME}\" AND TABLE_NAME = 'versions'") ]]; then VERSIONS_OK=OK else echo "Waiting for versions table to be created..." @@ -433,11 +433,11 @@ PUBKEY_MCRYPT=$(doveconf -P 2> /dev/null | grep -i mail_crypt_global_public_key if [ -f ${PUBKEY_MCRYPT} ]; then GUID=$(cat <(echo ${MAILCOW_HOSTNAME}) /mail_crypt/ecpubkey.pem | sha256sum | cut -d ' ' -f1 | tr -cd "[a-fA-F0-9.:/] ") if [ ${#GUID} -eq 64 ]; then - mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF + mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF REPLACE INTO versions (application, version) VALUES ("GUID", "${GUID}"); EOF else - mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF + mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF REPLACE INTO versions (application, version) VALUES ("GUID", "INVALID"); EOF fi diff --git a/data/Dockerfiles/phpfpm/docker-entrypoint.sh b/data/Dockerfiles/phpfpm/docker-entrypoint.sh index e6510de7a..0d09ac5fc 100755 --- a/data/Dockerfiles/phpfpm/docker-entrypoint.sh +++ b/data/Dockerfiles/phpfpm/docker-entrypoint.sh @@ -81,7 +81,7 @@ if [ ${SQL_CHANGED} -eq 1 ]; then fi # Check mysql tz import (master and slave) -TZ_CHECK=$(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT CONVERT_TZ('2019-11-02 23:33:00','Europe/Berlin','UTC') AS time;" -BN 2> /dev/null) +TZ_CHECK=$(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT CONVERT_TZ('2019-11-02 23:33:00','Europe/Berlin','UTC') AS time;" -BN 2> /dev/null) if [[ -z ${TZ_CHECK} ]] || [[ "${TZ_CHECK}" == "NULL" ]]; then SQL_FULL_TZINFO_IMPORT_RETURN=$(curl --silent --insecure -XPOST https://dockerapi.${COMPOSE_PROJECT_NAME}_mailcow-network/containers/${CONTAINER_ID}/exec -d '{"cmd":"system", "task":"mysql_tzinfo_to_sql"}' --silent -H 'Content-type: application/json') echo "MySQL mysql_tzinfo_to_sql - debug output:" @@ -120,11 +120,11 @@ if [[ "${MASTER}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then while read line do DOMAIN_ARR+=("$line") - done < <(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT domain FROM domain" -Bs) + done < <(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT domain FROM domain" -Bs) while read line do DOMAIN_ARR+=("$line") - done < <(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT alias_domain FROM alias_domain" -Bs) + done < <(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT alias_domain FROM alias_domain" -Bs) if [[ ! -z ${DOMAIN_ARR} ]]; then for domain in "${DOMAIN_ARR[@]}"; do @@ -146,13 +146,13 @@ if [[ "${MASTER}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then VALIDATED_IPS=$(array_by_comma ${VALIDATED_API_ALLOW_FROM_ARR[*]}) if [[ ! -z ${VALIDATED_IPS} ]]; then if [[ ${API_KEY} != "invalid" ]] && [[ ! -z ${API_KEY} ]]; then - mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF + mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF DELETE FROM api WHERE access = 'rw'; INSERT INTO api (api_key, active, allow_from, access) VALUES ("${API_KEY}", "1", "${VALIDATED_IPS}", "rw"); EOF fi if [[ ${API_KEY_READ_ONLY} != "invalid" ]] && [[ ! -z ${API_KEY_READ_ONLY} ]]; then - mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF + mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF DELETE FROM api WHERE access = 'ro'; INSERT INTO api (api_key, active, allow_from, access) VALUES ("${API_KEY_READ_ONLY}", "1", "${VALIDATED_IPS}", "ro"); EOF @@ -161,7 +161,7 @@ EOF fi # Create events (master only, STATUS for event on slave will be SLAVESIDE_DISABLED) - mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF + mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF DROP EVENT IF EXISTS clean_spamalias; DELIMITER // CREATE EVENT clean_spamalias diff --git a/data/Dockerfiles/sogo/bootstrap-sogo.sh b/data/Dockerfiles/sogo/bootstrap-sogo.sh index 9cf36a805..dcf91b499 100755 --- a/data/Dockerfiles/sogo/bootstrap-sogo.sh +++ b/data/Dockerfiles/sogo/bootstrap-sogo.sh @@ -14,11 +14,11 @@ do done # Wait for updated schema -DBV_NOW=$(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT version FROM versions WHERE application = 'db_schema';" -BN) +DBV_NOW=$(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT version FROM versions WHERE application = 'db_schema';" -BN) DBV_NEW=$(grep -oE '\$db_version = .*;' init_db.inc.php | sed 's/$db_version = //g;s/;//g' | cut -d \" -f2) while [[ "${DBV_NOW}" != "${DBV_NEW}" ]]; do echo "Waiting for schema update..." - DBV_NOW=$(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT version FROM versions WHERE application = 'db_schema';" -BN) + DBV_NOW=$(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT version FROM versions WHERE application = 'db_schema';" -BN) DBV_NEW=$(grep -oE '\$db_version = .*;' init_db.inc.php | sed 's/$db_version = //g;s/;//g' | cut -d \" -f2) sleep 5 done @@ -27,9 +27,9 @@ echo "DB schema is ${DBV_NOW}" # Recreate view if [[ "${MASTER}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then echo "We are master, preparing sogo_view..." - mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "DROP VIEW IF EXISTS sogo_view" + mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "DROP VIEW IF EXISTS sogo_view" while [[ ${VIEW_OK} != 'OK' ]]; do - mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF + mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF CREATE VIEW sogo_view (c_uid, domain, c_name, c_password, c_cn, mail, aliases, ad_aliases, ext_acl, kind, multiple_bookings) AS SELECT mailbox.username, @@ -59,7 +59,7 @@ WHERE GROUP BY mailbox.username; EOF - if [[ ! -z $(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "SELECT 'OK' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'sogo_view'") ]]; then + if [[ ! -z $(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "SELECT 'OK' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'sogo_view'") ]]; then VIEW_OK=OK else echo "Will retry to setup SOGo view in 3s..." @@ -68,7 +68,7 @@ EOF done else while [[ ${VIEW_OK} != 'OK' ]]; do - if [[ ! -z $(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "SELECT 'OK' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'sogo_view'") ]]; then + if [[ ! -z $(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "SELECT 'OK' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'sogo_view'") ]]; then VIEW_OK=OK else echo "Waiting for SOGo view to be created by master..." @@ -81,12 +81,12 @@ fi if [[ "${MASTER}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then echo "We are master, preparing _sogo_static_view..." while [[ ${STATIC_VIEW_OK} != 'OK' ]]; do - if [[ ! -z $(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "SELECT 'OK' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '_sogo_static_view'") ]]; then + if [[ ! -z $(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "SELECT 'OK' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '_sogo_static_view'") ]]; then STATIC_VIEW_OK=OK echo "Updating _sogo_static_view content..." # If changed, also update init_db.inc.php - mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "REPLACE INTO _sogo_static_view (c_uid, domain, c_name, c_password, c_cn, mail, aliases, ad_aliases, ext_acl, kind, multiple_bookings) SELECT c_uid, domain, c_name, c_password, c_cn, mail, aliases, ad_aliases, ext_acl, kind, multiple_bookings from sogo_view;" - mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "DELETE FROM _sogo_static_view WHERE c_uid NOT IN (SELECT username FROM mailbox WHERE active = '1')" + mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "REPLACE INTO _sogo_static_view (c_uid, domain, c_name, c_password, c_cn, mail, aliases, ad_aliases, ext_acl, kind, multiple_bookings) SELECT c_uid, domain, c_name, c_password, c_cn, mail, aliases, ad_aliases, ext_acl, kind, multiple_bookings from sogo_view;" + mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "DELETE FROM _sogo_static_view WHERE c_uid NOT IN (SELECT username FROM mailbox WHERE active = '1')" else echo "Waiting for database initialization..." sleep 3 @@ -94,7 +94,7 @@ if [[ "${MASTER}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then done else while [[ ${STATIC_VIEW_OK} != 'OK' ]]; do - if [[ ! -z $(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "SELECT 'OK' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '_sogo_static_view'") ]]; then + if [[ ! -z $(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "SELECT 'OK' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '_sogo_static_view'") ]]; then STATIC_VIEW_OK=OK else echo "Waiting for database initialization by master..." @@ -107,9 +107,9 @@ fi # Recreate password update trigger if [[ "${MASTER}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then echo "We are master, preparing update trigger..." - mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "DROP TRIGGER IF EXISTS sogo_update_password" + mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "DROP TRIGGER IF EXISTS sogo_update_password" while [[ ${TRIGGER_OK} != 'OK' ]]; do - mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF + mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF DELIMITER - CREATE TRIGGER sogo_update_password AFTER UPDATE ON _sogo_static_view FOR EACH ROW @@ -119,7 +119,7 @@ END; - DELIMITER ; EOF - if [[ ! -z $(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "SELECT 'OK' FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME = 'sogo_update_password'") ]]; then + if [[ ! -z $(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "SELECT 'OK' FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME = 'sogo_update_password'") ]]; then TRIGGER_OK=OK else echo "Will retry to setup SOGo password update trigger in 3s" @@ -216,7 +216,7 @@ while read -r line gal line=${line} envsubst < /etc/sogo/plist_ldap >> /var/lib/sogo/GNUstep/Defaults/sogod.plist echo " " >> /var/lib/sogo/GNUstep/Defaults/sogod.plist -done < <(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT domain, CASE gal WHEN '1' THEN 'YES' ELSE 'NO' END AS gal FROM domain;" -B -N) +done < <(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT domain, CASE gal WHEN '1' THEN 'YES' ELSE 'NO' END AS gal FROM domain;" -B -N) # Generate footer echo ' diff --git a/data/Dockerfiles/watchdog/check_mysql_slavestatus.sh b/data/Dockerfiles/watchdog/check_mysql_slavestatus.sh index ed4f0db4d..4788b9b70 100755 --- a/data/Dockerfiles/watchdog/check_mysql_slavestatus.sh +++ b/data/Dockerfiles/watchdog/check_mysql_slavestatus.sh @@ -132,9 +132,9 @@ fi # Connect to the DB server and store output in vars if [[ -n $socket ]]; then - ConnectionResult=$(mysql ${optfile} ${socket} ${user} -e "show slave ${connection} status\G" 2>&1) + ConnectionResult=$(mariadb --skip-ssl ${optfile} ${socket} ${user} -e "show slave ${connection} status\G" 2>&1) else - ConnectionResult=$(mysql ${optfile} ${host} ${port} ${user} -e "show slave ${connection} status\G" 2>&1) + ConnectionResult=$(mariadb --skip-ssl ${optfile} ${host} ${port} ${user} -e "show slave ${connection} status\G" 2>&1) fi if [ -z "`echo "${ConnectionResult}" |grep Slave_IO_State`" ]; then diff --git a/data/Dockerfiles/watchdog/watchdog.sh b/data/Dockerfiles/watchdog/watchdog.sh index dac0335fb..9d6f6609f 100755 --- a/data/Dockerfiles/watchdog/watchdog.sh +++ b/data/Dockerfiles/watchdog/watchdog.sh @@ -234,7 +234,7 @@ external_checks() { diff_c=0 THRESHOLD=${EXTERNAL_CHECKS_THRESHOLD} # Reduce error count by 2 after restarting an unhealthy container - GUID=$(mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT version FROM versions WHERE application = 'GUID'" -BN) + GUID=$(mariadb --skip-ssl -u${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT version FROM versions WHERE application = 'GUID'" -BN) trap "[ ${err_count} -gt 1 ] && err_count=$(( ${err_count} - 2 ))" USR1 while [ ${err_count} -lt ${THRESHOLD} ]; do err_c_cur=${err_count} From 18acbc7a4c68e7b31a6d5aa94ffb7d4ee2d9f577 Mon Sep 17 00:00:00 2001 From: DerLinkman Date: Tue, 11 Mar 2025 12:35:13 +0100 Subject: [PATCH 12/15] cold-standby: changed texts + removed --no-parallel for pull --- helper-scripts/_cold-standby.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/helper-scripts/_cold-standby.sh b/helper-scripts/_cold-standby.sh index 9e7362ec6..bfda3ba94 100755 --- a/helper-scripts/_cold-standby.sh +++ b/helper-scripts/_cold-standby.sh @@ -99,11 +99,11 @@ EOF if [ $? = 0 ]; then COMPOSE_COMMAND="docker compose" - echo "DEBUG: Using native docker compose on remote" + echo "INFO: Using native docker compose on remote" elif [ $? = 1 ]; then COMPOSE_COMMAND="docker-compose" - echo "DEBUG: Using standalone docker compose on remote" + echo "INFO: Using standalone docker compose on remote" else echo -e "\e[31mCannot find any Docker Compose on remote, exiting...\e[0m" @@ -284,7 +284,7 @@ echo "OK" -i "${REMOTE_SSH_KEY}" \ ${REMOTE_SSH_HOST} \ -p ${REMOTE_SSH_PORT} \ - ${COMPOSE_COMMAND} -f "${SCRIPT_DIR}/../docker-compose.yml" pull --no-parallel --quiet 2>&1 ; then + ${COMPOSE_COMMAND} -f "${SCRIPT_DIR}/../docker-compose.yml" pull --quiet 2>&1 ; then >&2 echo -e "\e[31m[ERR]\e[0m - Could not pull images on remote" fi From 062539b7d7ba3dcb883816ceb888c4f082a18364 Mon Sep 17 00:00:00 2001 From: "Marvin A. Ruder" Date: Tue, 11 Mar 2025 15:30:46 +0100 Subject: [PATCH 13/15] dkim: Add support for 3072 and 4096 bit RSA keys (#6365) * dkim: Add support for 3072 and 4096 bit RSA keys Signed-off-by: Marvin A. Ruder * php: added missing ; in dkim function * php: make 4096 DKIM default * db: update schema to set dkim 4096 as default * Revert "db: update schema to set dkim 4096 as default" This reverts commit 790b40a69563722513cda540ba34e3ae30874e05. * Revert "php: make 4096 DKIM default" This reverts commit 7e643376c7e11d23b0dae95ae59a2a5cc195e057. --------- Signed-off-by: Marvin A. Ruder Co-authored-by: DerLinkman --- data/web/api/openapi.yaml | 2 +- data/web/inc/functions.dkim.inc.php | 5 ++++- data/web/templates/admin/tab-config-dkim.twig | 2 ++ data/web/templates/edit/domain-templates.twig | 2 ++ data/web/templates/modals/mailbox.twig | 6 ++++++ 5 files changed, 15 insertions(+), 2 deletions(-) diff --git a/data/web/api/openapi.yaml b/data/web/api/openapi.yaml index 969aa7707..7fb4af308 100644 --- a/data/web/api/openapi.yaml +++ b/data/web/api/openapi.yaml @@ -409,7 +409,7 @@ paths: description: a list of domains for which a dkim key should be generated type: string key_size: - description: the key size (1024 or 2048) + description: the key size (1024, 2048, 3072 or 4096) type: number type: object summary: Generate DKIM Key diff --git a/data/web/inc/functions.dkim.inc.php b/data/web/inc/functions.dkim.inc.php index 8b1766a20..e7e411730 100644 --- a/data/web/inc/functions.dkim.inc.php +++ b/data/web/inc/functions.dkim.inc.php @@ -240,9 +240,12 @@ function dkim($_action, $_data = null, $privkey = false) { if (strlen($dkimdata['pubkey']) < 391) { $dkimdata['length'] = "1024"; } - elseif (strlen($dkimdata['pubkey']) < 736) { + elseif (strlen($dkimdata['pubkey']) < 564) { $dkimdata['length'] = "2048"; } + elseif (strlen($dkimdata['pubkey']) < 736) { + $dkimdata['length'] = "3072"; + } elseif (strlen($dkimdata['pubkey']) < 1416) { $dkimdata['length'] = "4096"; } diff --git a/data/web/templates/admin/tab-config-dkim.twig b/data/web/templates/admin/tab-config-dkim.twig index 85c6dc6ae..ec77139ed 100644 --- a/data/web/templates/admin/tab-config-dkim.twig +++ b/data/web/templates/admin/tab-config-dkim.twig @@ -117,6 +117,8 @@ diff --git a/data/web/templates/edit/domain-templates.twig b/data/web/templates/edit/domain-templates.twig index 825e6674d..d4612a198 100644 --- a/data/web/templates/edit/domain-templates.twig +++ b/data/web/templates/edit/domain-templates.twig @@ -103,6 +103,8 @@ diff --git a/data/web/templates/modals/mailbox.twig b/data/web/templates/modals/mailbox.twig index 0f1b23a7e..76f54ec31 100644 --- a/data/web/templates/modals/mailbox.twig +++ b/data/web/templates/modals/mailbox.twig @@ -490,6 +490,8 @@ @@ -628,6 +630,8 @@ @@ -843,6 +847,8 @@ From 2a15914324655af826255762722b5368ad623b2d Mon Sep 17 00:00:00 2001 From: FreddleSpl0it Date: Fri, 14 Mar 2025 11:22:57 +0100 Subject: [PATCH 14/15] Fix major update prompt --- update.sh | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/update.sh b/update.sh index 838899f8b..b99dffe71 100755 --- a/update.sh +++ b/update.sh @@ -724,7 +724,13 @@ detect_major_update() { "2025-02" ) - current_version=$(git describe --tags $(git rev-list --tags --max-count=1)) + current_version="" + if [[ -f "${SCRIPT_DIR}/data/web/inc/app_info.inc.php" ]]; then + current_version=$(grep 'MAILCOW_GIT_VERSION' ${SCRIPT_DIR}/data/web/inc/app_info.inc.php | sed -E 's/.*MAILCOW_GIT_VERSION="([^"]+)".*/\1/') + fi + if [[ -z "$current_version" ]]; then + return 1 + fi release_url="https://github.com/mailcow/mailcow-dockerized/releases/tag" updates_to_apply=() @@ -741,8 +747,7 @@ detect_major_update() { echo "$update - $release_url/$update" done - echo -e "\n⚠️ Please read the release notes before proceeding.\n" - + echo -e "\nPlease read the release notes before proceeding." read -p "Do you want to proceed with the update? [y/n] " response if [[ "${response}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then echo "Proceeding with the update..." From 463e3ab78c8c43095239dea4853467a7899df8f3 Mon Sep 17 00:00:00 2001 From: DerLinkman Date: Fri, 14 Mar 2025 12:18:59 +0100 Subject: [PATCH 15/15] rspamd: update rspamd to 3.11.1 (#6374) --- data/Dockerfiles/rspamd/Dockerfile | 2 +- docker-compose.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data/Dockerfiles/rspamd/Dockerfile b/data/Dockerfiles/rspamd/Dockerfile index 248312094..ac5c0f2a0 100644 --- a/data/Dockerfiles/rspamd/Dockerfile +++ b/data/Dockerfiles/rspamd/Dockerfile @@ -2,7 +2,7 @@ FROM debian:bookworm-slim LABEL maintainer="The Infrastructure Company GmbH " ARG DEBIAN_FRONTEND=noninteractive -ARG RSPAMD_VER=rspamd_3.11.0-2~90a175b45 +ARG RSPAMD_VER=rspamd_3.11.1-1~ab0b44951 ARG CODENAME=bookworm ENV LC_ALL=C diff --git a/docker-compose.yml b/docker-compose.yml index 4c470f5bd..5a42c4101 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -84,7 +84,7 @@ services: - clamd rspamd-mailcow: - image: ghcr.io/mailcow/rspamd:2.0 + image: ghcr.io/mailcow/rspamd:2.1 stop_grace_period: 30s depends_on: - dovecot-mailcow