Merge branch 'code/majorrig/wiki-dovecot-lda-dupes'
This commit is contained in:
commit
fda2d35ea5
3 changed files with 113 additions and 0 deletions
|
|
@ -16,6 +16,7 @@ Practical fixes for common Linux, networking, and application problems.
|
|||
- [firewalld: Mail Ports Wiped After Reload](networking/firewalld-mail-ports-reset.md)
|
||||
- [Dovecot IMAP Clients Fail to Sync: vsz_limit OOM from a Bloated Index Log](networking/dovecot-imap-oom-vsz-limit-bloated-index.md)
|
||||
- [Postfix header_checks Can't Act on Milter-Added Headers (Use Sieve)](networking/postfix-header-checks-vs-milter-headers.md)
|
||||
- [Dovecot Phantom Mailboxes from .dovecot.lda-dupes (mail_home Overlapping the Maildir Root)](networking/dovecot-mail-home-maildir-root-phantom-mailboxes.md)
|
||||
- [Tailscale SSH: Unexpected Re-Authentication Prompt](networking/tailscale-ssh-reauth-prompt.md)
|
||||
- [iOS Tailscale Clients Report HostName="localhost" — Breaks /etc/hosts Generators](networking/tailscale-status-json-hostname-localhost-ios.md)
|
||||
- [rsync over Tailscale: Hung in TCP Teardown After Transfer Completes](networking/rsync-tailscale-teardown-stall.md)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,111 @@
|
|||
---
|
||||
title: "Dovecot Phantom Mailboxes from .dovecot.lda-dupes (mail_home Overlapping the Maildir Root)"
|
||||
domain: troubleshooting
|
||||
category: networking
|
||||
tags: [dovecot, maildir, mail_home, sieve, lda-dupes, duplicate-database, pigeonhole, phantom-mailbox]
|
||||
status: published
|
||||
created: 2026-06-07
|
||||
updated: 2026-06-07
|
||||
---
|
||||
# Dovecot Phantom Mailboxes from `.dovecot.lda-dupes` (mail_home Overlapping the Maildir Root)
|
||||
|
||||
Dovecot starts logging errors like this on mailbox LIST, and `doveadm mailbox list` grows phantom mailboxes named after Dovecot's own control files:
|
||||
|
||||
```
|
||||
imap(user@example.com): Error: maildir: stat(/var/vmail/example.com/user/.dovecot.lda-dupes/tmp) failed: Not a directory
|
||||
```
|
||||
|
||||
```
|
||||
$ doveadm mailbox list -u user@example.com
|
||||
INBOX
|
||||
…
|
||||
dovecot
|
||||
dovecot.lda-dupes
|
||||
dovecot.lda-dupes.locks
|
||||
```
|
||||
|
||||
> Hit on **majormail** (2026-06-07), the day after switching the global spam Sieve to `redirect`. Mail delivery was unaffected — purely log noise plus phantom folders a client could see on `LIST "*"`.
|
||||
|
||||
## Why
|
||||
|
||||
The LDA/Sieve **duplicate database** (`.dovecot.lda-dupes`, plus a `.dovecot.lda-dupes.locks` lock dir) is created in the user's **home** directory. Per the Dovecot maintainer, its location strictly follows the user's home — it is *not* separately configurable.
|
||||
|
||||
If `mail_home` (the userdb `home` field) is set equal to the **maildir root** (`mail_path`), those control files get written *inside* the mail store:
|
||||
|
||||
```
|
||||
mail_path = /var/vmail/%{user|domain}/%{user|username} # maildir root
|
||||
userdb static { fields { home = /var/vmail/%{user|domain}/%{user|username} } } # SAME path — the bug
|
||||
```
|
||||
|
||||
The maildir++ layout treats every `.`-prefixed entry in the root as a mailbox folder. So:
|
||||
|
||||
- `.dovecot.lda-dupes` (a **file**) → lister stats `.dovecot.lda-dupes/tmp` → **"Not a directory"** (cosmetic, logged every LIST).
|
||||
- `.dovecot.lda-dupes.locks` (a **directory**) → opened as a maildir, auto-populated with `cur/new/tmp/dovecot-uidlist/dovecot.index.log`, and exposed as a real phantom mailbox.
|
||||
|
||||
The trigger is anything that exercises duplicate tracking — Sieve `redirect` (loop-guard), `vacation`, or the `duplicate` test. A pure `fileinto` setup never creates the db, which is why the error can appear suddenly after a Sieve change.
|
||||
|
||||
## How to confirm
|
||||
|
||||
```bash
|
||||
# Phantom mailboxes named after the control files:
|
||||
doveadm mailbox list -u user@example.com | grep -E '^dovecot'
|
||||
|
||||
# Is home the SAME as the maildir root? (the root cause)
|
||||
doveadm user user@example.com | grep -E 'home|mail_path'
|
||||
# home /var/vmail/example.com/user <- equals mail_path == bug
|
||||
# mail_path /var/vmail/example.com/user
|
||||
|
||||
# The offending control files living inside the maildir root:
|
||||
ls -la /var/vmail/example.com/user/.dovecot.lda-dupes*
|
||||
# -rw------- … .dovecot.lda-dupes (regular file — the dedup db)
|
||||
# drwx------ … .dovecot.lda-dupes.locks (dir — the lock dir, mis-listed)
|
||||
```
|
||||
|
||||
## Fix
|
||||
|
||||
Point `home` at a path **separate from the maildir root**. The cleanest low-risk option is a **non-dotted subdir** of the user dir, so `mail_path` stays put and **no mail migration** is needed (a dotted name would just become another phantom folder):
|
||||
|
||||
```diff
|
||||
userdb static {
|
||||
fields {
|
||||
uid = vmail
|
||||
gid = vmail
|
||||
- home = /var/vmail/%{user|domain}/%{user|username}
|
||||
+ home = /var/vmail/%{user|domain}/%{user|username}/home
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then deploy and clean up the stale artifacts:
|
||||
|
||||
```bash
|
||||
# 1. Deploy the config change, restart/reload Dovecot.
|
||||
|
||||
# 2. Confirm home moved:
|
||||
doveadm user user@example.com | grep home # -> /var/vmail/example.com/user/home
|
||||
|
||||
# 3. Remove the stale dupe-db + the cached list index from the maildir root
|
||||
# (all regenerable):
|
||||
cd /var/vmail/example.com/user/
|
||||
rm -rf .dovecot.lda-dupes .dovecot.lda-dupes.locks dovecot.list.index dovecot.list.index.log
|
||||
|
||||
# 4. Pre-create the new home (so the first dupe-db write can't fail):
|
||||
install -d -o vmail -g vmail -m 700 /var/vmail/example.com/user/home
|
||||
|
||||
# 5. Verify:
|
||||
doveadm mailbox list -u user@example.com | grep -E '^dovecot' || echo CLEAN
|
||||
```
|
||||
|
||||
The duplicate db now regenerates under `…/user/home/`, where the maildir lister never looks.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **`mail_home` follows userdb.** A userdb-returned `home` field overrides the global `mail_home` setting, so fix it where userdb defines it (here, `userdb static { fields { home = … } }`).
|
||||
- **What else keys off `~`:** personal Sieve (`~/.dovecot.sieve`, `~/sieve`), `mail_attribute_dict`, and some quota backends. Before moving home, confirm none of those hold live data in the old location (`ls -a` the maildir root). A *global* spam Sieve at a fixed path (`/etc/dovecot/sieve/global/…`) is unaffected.
|
||||
- **Indexes** default to `mail_path`, not home, so moving home doesn't touch `dovecot.index*`.
|
||||
- **Don't trust a local-injection test** to exercise Sieve `redirect`: Postfix `cleanup` header_checks may intercept it first, and `dovecot-lda` may not apply the same before-script as LMTP. Verify the relocation at the authoritative level (`doveadm user` home), since the db location is home-relative by design.
|
||||
|
||||
## Related
|
||||
|
||||
- [[postfix-header-checks-vs-milter-headers]] — the spam-routing migration that introduced the Sieve `redirect` (and thus the dupe db) on majormail.
|
||||
- Upstream: Dovecot mailing-list thread "Change location where .dovecot.lda-dupes* file/dir are created" — maintainer confirms the db follows the user's home.
|
||||
|
|
@ -82,6 +82,7 @@ updated: 2026-05-15T09:00
|
|||
* [firewalld: Mail Ports Wiped After Reload](05-troubleshooting/networking/firewalld-mail-ports-reset.md)
|
||||
* [Dovecot IMAP Clients Fail to Sync: vsz_limit OOM from a Bloated Index Log](05-troubleshooting/networking/dovecot-imap-oom-vsz-limit-bloated-index.md)
|
||||
* [Postfix header_checks Can't Act on Milter-Added Headers (Use Sieve)](05-troubleshooting/networking/postfix-header-checks-vs-milter-headers.md)
|
||||
* [Dovecot Phantom Mailboxes from .dovecot.lda-dupes (mail_home Overlapping the Maildir Root)](05-troubleshooting/networking/dovecot-mail-home-maildir-root-phantom-mailboxes.md)
|
||||
* [Tailscale SSH: Unexpected Re-Authentication Prompt](05-troubleshooting/networking/tailscale-ssh-reauth-prompt.md)
|
||||
* [ssh.socket Unreachable After Reboot (Tailscale Race Condition)](05-troubleshooting/networking/ssh-socket-tailscale-race-condition.md)
|
||||
* [Fail2ban & UFW Rule Bloat Cleanup](05-troubleshooting/networking/fail2ban-ufw-rule-bloat-cleanup.md)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue