Debian 13(trixie)を保ったまま Dovecot 2.4 → 2.3(Debian 12版)にダウングレードする手順

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)/

(1) apt で Dovecot 2.3(Bookworm)に入れ替え

1-1. Bookworm リポジトリを併設

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

1-2. Pinning(dovecot* を Bookworm 優先 / trixie 抑止)

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

1-3. メタデータ更新と候補確認

sudo apt-get update
apt-cache policy dovecot-core | sed -n '1,40p'

1-4. 2.3 を導入(停止→導入→ホールド)

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で、古いバージョンをインストールすためのオプションを付加するよう求められるかもしれません。
指示に応じて下さい。

(2) /etc/dovecot の設定を 2.3(Debian 12)用に入れ替え

前提条件

ポリシー

  • 現行(2.4向け)ファイル名ファイル名.debian13 に退避。
  • 2.3向け ファイル名.debian12ファイル名 に昇格(rename)。
  • .ucf-dist は維持(触らない)。
  • conf.d を含め再帰処理。base が無いが .debian12 がある場合は新規昇格

2-1. 一括入れ替え(再帰・新規昇格込み)

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)
'

2-2. 2.4 専用(2.3 非対応)の設定を退避

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

2-3. 設定検証 → 起動

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) になっていれば成功です。

任意: FTS (Xapian) を 2.3 で有効化

  1. プラグイン導入(Bookworm から)
sudo apt-get install -y -t bookworm dovecot-fts-xapian
  1. mail_plugins に fts を追加
sudo sed -i 's/^mail_plugins = \(.*\)$/mail_plugins = \1 fts/' /etc/dovecot/conf.d/10-mail.conf
  1. 2.3 互換の 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

ロールバック(バグ解消後の2.4 へ復帰することを想定)

# 設定を .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

付録: ワンファイル自動化スクリプト(任意)

A. Dovecot 2.3 導入・固定(bookworm 追加 + pinning + 安全導入)

#!/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}"

B. /etc/dovecot 設定スワップ(conf.d を含む再帰・新規昇格対応)

#!/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 は変更していません。"