Dovecot ACL + shared namespace (shared/%%u/), acl_shared_dict in mail-state, idempotent user-patches.sh grants info@ read-only (lookup read) on every mailbox of ano@, andriy.oblivantsev@, postmaster@ and pre-subscribes the shared folders so Roundcube's subscribed folder list shows them. Delivery and passwords untouched; other accounts see no shared folders.
mail-server
Docker Compose mail stack for mail.produktor.io on arc-01, based on
docker-mailserver (DMS).
| Service | Container | Ports |
|---|---|---|
| Mail server (DMS) | mailserver |
25 (SMTP), 465 (SMTPS), 587 (Submission STARTTLS), 143 (IMAP STARTTLS), 993 (IMAPS) |
| Webmail (Roundcube) | webmail |
127.0.0.1:19944 / 172.17.0.1:19944 (HTTP, behind NPM) |
| Account admin | — (removed) | — |
Accounts
Source of truth is file-based: config/postfix-accounts.cf (SHA512-CRYPT
hashes). Current mailboxes:
info@produktor.ioandriy.oblivantsev@produktor.ioano@produktor.iopostmaster@produktor.iopostman@produktor.io
Passwords live in .env (INFO_PASSWORD, ANDRIY_PASSWORD; ano@ uses
GATOR_MAIL_PASS in the gator repo .env). Do not commit .env.
Web UI (Roundcube)
Webmail runs as the webmail service (official roundcube/roundcubemail
image) and is reachable at https://mail.produktor.io (alias
https://webmail.produktor.io) via Nginx Proxy Manager (proxy host 66 →
172.17.0.1:19944, Let's Encrypt).
Login: any mailbox address from the table above + its real password. The UI
shows one mailbox per login; the account list is the postfix-accounts.cf
file (see Accounts).
Since the shared-mailbox setup (below) info@ additionally sees every other
mailbox under Shared/ and can read them — one login covers the whole
account list.
Connection details used by the webmail (IMAP/SMTP):
- IMAP:
mail.produktor.io:143STARTTLS (or:993SSL) - SMTP submission:
mail.produktor.io:587STARTTLS, AUTH required
Host note: the webmail must connect to the DMS container via the FQDN
mail.produktor.io (Docker embedded DNS resolves it to the mailserver
container inside the compose network). Connecting to the bare container alias
mailserver fails TLS peer-name verification, because the DMS certificate is
issued for mail.produktor.io.
Manage
docker compose up -d # start mailserver + webmail
docker compose logs -f webmail # webmail logs
docker exec webmail sh # shell into webmail
The webmail stores its sqlite database (addressbook, settings) in
data/roundcube/db/. ROUNDCUBEMAIL_DES_KEY (session encryption) must be set
in .env — compose fails without it.
Shared mailboxes (единый вход info@)
info@produktor.io can read all mailboxes (ano@, andriy.oblivantsev@,
postmaster@) as read-only shared folders — one login in Roundcube covers the
whole account list. Delivery is unchanged (no aliases, no redirects); other
accounts keep their own passwords and full rights.
How it works (Dovecot 2.3 ACL + shared namespace):
config/dovecot.cf(→/etc/dovecot/local.conf) enables theaclplugin, adds a shared namespaceshared/%%u/(list=children, read index per reader viaINDEXPVT), and pointsacl_shared_dictto/var/lib/dovecot/db/shared-mailboxes.db(persistent viamail-state).config/user-patches.shre-applies read-only (lr) ACLs from each shared owner's mailboxes touser=info@produktor.ioviadoveadm acl set— the only way Dovecot records the share in the shared dictionary — and pre-subscribes the shared folders forinfo@. DMS runs it on the first start of each container instance (plaindocker compose restartskips the setup step by design); ACLs, the shared dict and subscriptions persist inmail-state/maildirs, so nothing is lost on restarts. Idempotent — safe to run manually:docker exec mailserver /bin/bash /tmp/docker-mailserver/user-patches.sh.
Upgrade behavior (image :latest): the config survives container recreation
because both files live in the mounted config/. On image upgrade the
entrypoint re-applies dovecot.cf and runs user-patches.sh again on the new
container's first start, so ACLs and subscriptions are recreated. The only
state kept outside the repo is shared-mailboxes.db (inside
data/mail-state/); if it is lost, the next (re)creation rebuilds it via
doveadm acl set.
Limitation (Dovecot semantics): new mailboxes created by an owner after the
last start do not inherit the share (no ACL inheritance); they appear for
info@ after the next container start.
Reverse proxy (NPM)
mail.produktor.io is a proxy host in Nginx Proxy Manager (provider container,
see the gitea repo): forward http://172.17.0.1:19944, Let's Encrypt cert
(SAN: mail.produktor.io, webmail.produktor.io), SSL forced, HTTP/2.
TLS
DMS uses a Let's Encrypt certificate for mail.produktor.io mounted from
tls/letsencrypt/mail.produktor.io/ (SSL_TYPE=letsencrypt).