2025/8/15
本書は (1) apt での安全なバイナリ入れ替え と (2) /etc/dovecot 配下の設定入れ替え の二部構成です。すべて コピー&ペースト で実行できます。
2025/8/15時点のDebian 13で起きているDovecot不具合は、(1)バイナリによるものと(2)/etc/dovecot 配下の設定によるものとに分かれると考えています。本書の
(1) apt でのバイナリダウングレードは一般的な記述ですが、
(2) /etc/dovecot 配下の設定入れ替えは環境に強く依存します。
/etc/dovecot配下の設定は、Debian 12 (Bookworm) 時代のものをそっくり元に戻せるのであれば、マニュアルで作業した方が楽だと思います。
sudo mkdir -p /root/backup-dovecot-$(date +%Y%m%d-%H%M%S)
sudo cp -a /etc/dovecot /root/backup-dovecot-$(date +%Y%m%d-%H%M%S)/
sudo tee /etc/apt/sources.list.d/bookworm.list >/dev/null <<'EOF'
deb http://deb.debian.org/debian bookworm main contrib non-free non-free-firmware
deb http://security.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware
deb http://deb.debian.org/debian bookworm-updates main contrib non-free non-free-firmware
EOF
sudo tee /etc/apt/preferences.d/dovecot23.pref >/dev/null <<'EOF'
Package: dovecot*
Pin: release n=bookworm
Pin-Priority: 1001
Package: dovecot*
Pin: release n=trixie
Pin-Priority: -1
EOF
sudo apt-get update
apt-cache policy dovecot-core | sed -n '1,40p'
sudo systemctl stop dovecot || true
sudo apt-get install -y -t bookworm \
dovecot-core dovecot-imapd dovecot-pop3d dovecot-sieve
sudo apt-mark hold dovecot-core dovecot-imapd dovecot-pop3d dovecot-sieve
/usr/sbin/dovecot --version
ここの、apt-get install -y -t bookwormで、古いバージョンをインストールすためのオプションを付加するよう求められるかもしれません。
指示に応じて下さい。
前提条件 ポリシー:
ファイル名.debian12
として残されていることを前提としています。ファイル名.debian12
に変更して下さい。ファイル名.debian13
としてバックアップしつつ、一時的に2.3向けの ファイル名.debian12
を正規の設定ファイルに戻すことを狙っています。
ファイル名
→ ファイル名.debian13
に退避。ファイル名.debian12
→ ファイル名
に昇格(rename)。.ucf-dist
は維持(触らない)。conf.d
を含め再帰処理。base が無いが .debian12 がある場合は新規昇格。
sudo systemctl stop dovecot || true
# 既存 base を .debian13 に退避し、.debian12 を現行に昇格
sudo bash -c '
while IFS= read -r -d "" base; do
[[ "$base" == *.ucf-dist || "$base" == *.debian12 || "$base" == *.debian13 ]] && continue
[[ "$base" == *~ || "$base" == *.bak || "$base" == *.orig ]] && continue
f12="${base}.debian12"; f13="${base}.debian13"
[[ -e "$f12" ]] || continue
dst13="$f13"; [[ -e "$dst13" ]] && dst13="${f13}.$(date +%Y%m%d-%H%M%S)"
mv -- "$base" "$dst13"
mv -- "$f12" "$base"
done < <(find /etc/dovecot -type f -print0)
'
# base が無いが *.debian12 があるものは新規昇格
sudo bash -c '
while IFS= read -r -d "" f12; do
base="${f12%.debian12}"
[[ -e "$base" ]] && continue
[[ "$base" == *.ucf-dist ]] && continue
mv -- "$f12" "$base"
done < <(find /etc/dovecot -type f -name "*.debian12" -print0)
'
for f in \
/etc/dovecot/conf.d/10-metrics.conf \
/etc/dovecot/conf.d/30-dict-server.conf \
/etc/dovecot/conf.d/90-fts.conf
do
[ -f "$f" ] && sudo mv "$f" "$f.debian13"
done
sudo dovecot -n
sudo systemctl start dovecot
sudo systemctl --no-pager status dovecot
/usr/sbin/dovecot --version
doveconf -n | sed -n '1,120p'
ss -lntp | grep -E ':(110|143|993|995)\b'
journalctl -u dovecot -b -n 100 --no-pager
バージョンが 2.3.x、サービス状態が active (running) になっていれば成功です。
sudo apt-get install -y -t bookworm dovecot-fts-xapian
fts
を追加sudo sed -i 's/^mail_plugins = \(.*\)$/mail_plugins = \1 fts/' /etc/dovecot/conf.d/10-mail.conf
90-fts.conf
sudo tee /etc/dovecot/conf.d/90-fts.conf >/dev/null <<'EOF'
plugin {
fts = xapian
fts_autoindex = yes
# fts_autoindex_exclude = \Trash
# fts_autoindex_exclude2 = \Junk
}
EOF
sudo dovecot -n
sudo systemctl restart dovecot
# 設定を .debian13 に戻し、現行を .debian12 に退避して保全
sudo bash -c '
while IFS= read -r -d "" base; do
[[ "$base" == *.ucf-dist || "$base" == *.debian12 || "$base" == *.debian13 ]] && continue
f12="${base}.debian12"; f13="${base}.debian13"
[[ -e "$f13" ]] || continue
dst12="$f12"; [[ -e "$dst12" ]] && dst12="${f12}.$(date +%Y%m%d-%H%M%S)"
mv -- "$base" "$dst12"
mv -- "$f13" "$base"
done < <(find /etc/dovecot -type f -print0)
'
# apt を trixie 優先に戻す
sudo apt-mark unhold dovecot-core dovecot-imapd dovecot-pop3d dovecot-sieve
sudo rm -f /etc/apt/preferences.d/dovecot23.pref
sudo rm -f /etc/apt/sources.list.d/bookworm.list
sudo apt-get update
sudo apt-get install -y -t trixie dovecot-core dovecot-imapd dovecot-pop3d dovecot-sieve
sudo systemctl restart dovecot
#!/usr/bin/env bash
# dovecot23_downgrade_onefile.sh
set -euo pipefail
BOOKWORM_VER="1:2.3.19.1+dfsg1-2.1+deb12u1"
PKGS=(dovecot-core dovecot-imapd dovecot-pop3d dovecot-sieve)
RED="\033[31m"; YEL="\033[33m"; GRN="\033[32m"; NC="\033[0m"
if [[ $EUID -ne 0 ]]; then echo -e "${RED}Run as root${NC}"; exit 1; fi
. /etc/os-release
[[ "${VERSION_CODENAME:-}" != trixie ]] && echo -e "${YEL}WARN: non-trixie${NC}"
[[ -d /etc/dovecot ]] && cp -a /etc/dovecot/. /root/backup-dovecot-$(date +%Y%m%d-%H%M%S)/ || true
cat >/etc/apt/sources.list.d/bookworm.list <<'EOF'
deb http://deb.debian.org/debian bookworm main contrib non-free non-free-firmware
deb http://security.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware
deb http://deb.debian.org/debian bookworm-updates main contrib non-free non-free-firmware
EOF
mkdir -p /etc/apt/preferences.d
cat >/etc/apt/preferences.d/dovecot23.pref <<'EOF'
Package: dovecot*
Pin: release n=bookworm
Pin-Priority: 1001
Package: dovecot*
Pin: release n=trixie
Pin-Priority: -1
EOF
apt-get update -y
systemctl stop dovecot 2>/dev/null || true
apt-get install -y -t bookworm \
"dovecot-core=${BOOKWORM_VER}" \
"dovecot-imapd=${BOOKWORM_VER}" \
"dovecot-pop3d=${BOOKWORM_VER}" \
"dovecot-sieve=${BOOKWORM_VER}"
apt-mark hold "${PKGS[@]}" || true
/usr/sbin/dovecot --version || true
echo -e "${GRN}Done.${NC}"
#!/usr/bin/env bash
# dovecot_swap_configs_to_debian12.sh
set -euo pipefail
TARGET_DIR="/etc/dovecot"; DRY_RUN=0; REVERT=0
usage(){ cat <<'EOS'
Usage: sudo ./dovecot_swap_configs_to_debian12.sh [--dry-run|-n] [--revert]
forward (default): base -> .debian13, .debian12 -> base(新規昇格あり)
--revert: base -> .debian12, .debian13 -> base
EOS
}
ts(){ date +%Y%m%d-%H%M%S; } ; log(){ printf "%s\n" "$*"; }
is_backup_like(){ f="$1"; [[ "$f" == *~ || "$f" == *.bak || "$f" == *.orig ]]; }
move(){ src="$1"; dst="$2"; if [[ $DRY_RUN -eq 1 ]]; then log "[DRY-RUN] mv -- '$src' '$dst'"; else mv -- "$src" "$dst"; log "[OK] mv -- '$src' '$dst'"; fi }
ensure_bak(){ want="$1"; [[ -e "$want" ]] && echo "${want}.$(ts)" || echo "$want"; }
forward_swap_existing(){
while IFS= read -r -d '' base; do
[[ "$base" == *.ucf-dist || "$base" == *.debian12 || "$base" == *.debian13 ]] && continue
is_backup_like "$base" && continue
f12="${base}.debian12"; f13="${base}.debian13"
[[ -e "$f12" ]] || continue
dst13="$(ensure_bak "$f13")"; move "$base" "$dst13"; move "$f12" "$base"
done < <(find "$TARGET_DIR" -type f -print0)
}
forward_promote_missing(){
while IFS= read -r -d '' f12; do
base="${f12%.debian12}"; [[ -e "$base" ]] && continue
[[ "$base" == *.ucf-dist ]] && continue
move "$f12" "$base"
done < <(find "$TARGET_DIR" -type f -name '*.debian12' -print0)
}
revert_swap(){
while IFS= read -r -d '' base; do
[[ "$base" == *.ucf-dist || "$base" == *.debian12 || "$base" == *.debian13 ]] && continue
is_backup_like "$base" && continue
f12="${base}.debian12"; f13="${base}.debian13"; [[ -e "$f13" ]] || continue
dst12="$(ensure_bak "$f12")"; move "$base" "$dst12"; move "$f13" "$base"
done < <(find "$TARGET_DIR" -type f -print0)
}
while [[ $# -gt 0 ]]; do case "$1" in -n|--dry-run) DRY_RUN=1; shift;; --revert) REVERT=1; shift;; -h|--help) usage; exit 0;; *) echo "Unknown: $1"; usage; exit 1;; esac; done
[[ $EUID -ne 0 ]] && { echo "Run as root"; exit 1; }
[[ -d "$TARGET_DIR" ]] || { echo "Not found: $TARGET_DIR"; exit 1; }
log "[INFO] TARGET_DIR=$TARGET_DIR DRY_RUN=$DRY_RUN MODE=$([[ $REVERT -eq 1 ]] && echo revert || echo forward)"
if [[ $REVERT -eq 1 ]]; then revert_swap; else forward_swap_existing; forward_promote_missing; fi
log "[DONE] .ucf-dist は変更していません。"