mailcow dttb: спам-фикс, SSL, апдейт 2026-05c, BIMI+подпись, Roundcube, сбор почты

- фикс входящего спама: No-SNAT на OpenWrt (видел все письма как 10.0.0.1)
- SSL mail-портов: cert из NPM + cron-синхрон на Proxmox
- апдейт mailcow 2026-01 -> 2026-05c; урок: forward-zone unbound обязателен (RKN режет рекурсию)
- логотип UI, BIMI-SVG (Tiny PS) + хостинг, HTML-подпись
- Roundcube на /rc (bind-mount, public_html)
- внешний сбор почты Яндексом (IMAP/POP3)
- snippets: sync-mailcow-cert.sh, dttb-mail-branding/

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
dttb
2026-06-28 01:43:19 +03:00
parent b7bd90ae87
commit 58fd3fa17a
17 changed files with 502 additions and 2 deletions

View File

@@ -0,0 +1,50 @@
#!/bin/bash
# sync-mailcow-cert.sh
# Копирует LE-сертификат mail.dttb.ru из NPM (LXC 103) в mailcow (VM 107)
# и перезагружает почтовые сервисы ТОЛЬКО при изменении сертификата.
# Причина: mailcow с SKIP_LETS_ENCRYPT=y не продлевает cert сам; cert владеет NPM.
# История: cert на mail-портах протух 2026-06-02, чинили вручную 2026-06-27.
set -euo pipefail
NPM_CTID=103
NPM_DIR="/data/compose/2/letsencrypt/live/npm-106"
MC_HOST="root@10.0.0.107"
MC_KEY="/root/.ssh/mailcow_sync"
MC_SSL="/opt/mailcow-dockerized/data/assets/ssl"
SSHMC="ssh -i $MC_KEY -o StrictHostKeyChecking=no -o ConnectTimeout=10 $MC_HOST"
TMP=$(mktemp -d); trap 'rm -rf "$TMP"' EXIT
pct exec "$NPM_CTID" -- cat "$NPM_DIR/fullchain.pem" > "$TMP/cert.pem"
pct exec "$NPM_CTID" -- cat "$NPM_DIR/privkey.pem" > "$TMP/key.pem"
# sanity-проверки
openssl x509 -in "$TMP/cert.pem" -noout >/dev/null 2>&1 || { echo "$(date '+%F %T') ERR: битый cert из NPM"; exit 1; }
[ -s "$TMP/key.pem" ] || { echo "$(date '+%F %T') ERR: пустой key из NPM"; exit 1; }
CPUB=$(openssl x509 -in "$TMP/cert.pem" -noout -pubkey | openssl md5)
KPUB=$(openssl pkey -in "$TMP/key.pem" -pubout 2>/dev/null | openssl md5)
[ "$CPUB" = "$KPUB" ] || { echo "$(date '+%F %T') ERR: cert и key не пара"; exit 1; }
NEW=$(openssl x509 -in "$TMP/cert.pem" -noout -fingerprint -sha256)
CUR=$($SSHMC "openssl x509 -in $MC_SSL/cert.pem -noout -fingerprint -sha256" 2>/dev/null || echo none)
if [ "$NEW" = "$CUR" ]; then
echo "$(date '+%F %T') cert не изменился — пропуск"
exit 0
fi
echo "$(date '+%F %T') обнаружен новый cert — деплой"
scp -i "$MC_KEY" -o StrictHostKeyChecking=no "$TMP/cert.pem" "$TMP/key.pem" "$MC_HOST:/tmp/"
$SSHMC "
set -e
cd /opt/mailcow-dockerized
TS=\$(date +%Y%m%d-%H%M%S)
cp $MC_SSL/cert.pem $MC_SSL/cert.pem.bak-\$TS
cp $MC_SSL/key.pem $MC_SSL/key.pem.bak-\$TS
mv /tmp/cert.pem $MC_SSL/cert.pem
mv /tmp/key.pem $MC_SSL/key.pem
chmod 644 $MC_SSL/cert.pem; chmod 600 $MC_SSL/key.pem
docker compose exec -T postfix-mailcow postfix reload >/dev/null 2>&1 || docker compose restart postfix-mailcow
docker compose exec -T dovecot-mailcow dovecot reload >/dev/null 2>&1 || docker compose restart dovecot-mailcow
docker compose exec -T nginx-mailcow nginx -s reload >/dev/null 2>&1 || true
"
echo "$(date '+%F %T') задеплоен: $NEW"