Files
mail-server/compose.yaml
eSlider 5a46ba4b33 feat(mail-admin): read-only account view for mail.produktor.io (#74)
- admin/: Go stdlib-only HTTP viewer, lists accounts from
  config/postfix-accounts.cf with per-mailbox message counts (INBOX and
  total, same numbers doveadm reports) and storage; quota from
  dovecot-quotas.cf; Basic Auth from .env; offline tests vs fixtures
  (go test -race ./...)
- compose: mail-admin service, build admin/Dockerfile, publishes
  127.0.0.1:19945 / 172.17.0.1:19945; config and mail-data mounted :ro,
  no docker socket
- NPM proxy host 66: location /admin/ -> 172.17.0.1:19945
- README: account admin section
2026-09-01 15:07:55 +01:00

91 lines
3.4 KiB
YAML

services:
mailserver:
image: docker.io/mailserver/docker-mailserver:latest
container_name: mailserver
hostname: mail.produktor.io
ports:
- "25:25"
- "465:465"
- "587:587"
- "143:143"
- "993:993"
volumes:
- ./data/mail-data/:/var/mail/
- ./data/mail-state/:/var/mail-state/
- ./data/mail-logs/:/var/log/mail/
- ./config/:/tmp/docker-mailserver/
# fail2ban: never ban the docker bridge gateway / host LAN (self-DoS guard)
- ./config/fail2ban/ignoreip.conf:/etc/fail2ban/jail.d/ignoreip.local:ro
- ./tls/letsencrypt/mail.produktor.io:/etc/letsencrypt/live/mail.produktor.io:ro
- /etc/localtime:/etc/localtime:ro
environment:
- ENABLE_SPAMASSASSIN=1
- ENABLE_CLAMAV=0
- ENABLE_FAIL2BAN=1
- ENABLE_POP3=0
- SSL_TYPE=letsencrypt
- PERMIT_DOCKER=none
- ONE_DIR=1
- SPOOF_PROTECTION=1
cap_add:
- NET_ADMIN
- SYS_PTRACE
restart: unless-stopped
# Webmail UI (Roundcube) — https://mail.produktor.io (NPM proxy host 66 -> 172.17.0.1:19944)
# IMAP STARTTLS 143 / SMTP submission STARTTLS 587 against the DMS container (same compose network).
# Host must be mail.produktor.io (not the container alias `mailserver`): the DMS cert is CN/SAN
# mail.produktor.io and PHP's TLS peer-name verification rejects the bare container name.
# Docker's embedded DNS resolves mail.produktor.io to the mailserver container inside the network.
webmail:
image: docker.io/roundcube/roundcubemail:latest
container_name: webmail
restart: unless-stopped
depends_on:
- mailserver
ports:
- "127.0.0.1:19944:80"
- "172.17.0.1:19944:80"
volumes:
# sqlite (addressbook, settings) survives container recreation
- ./data/roundcube/db:/var/www/db
environment:
- ROUNDCUBEMAIL_DB_TYPE=sqlite
- ROUNDCUBEMAIL_DEFAULT_HOST=tls://mail.produktor.io
- ROUNDCUBEMAIL_DEFAULT_PORT=143
- ROUNDCUBEMAIL_SMTP_SERVER=tls://mail.produktor.io
- ROUNDCUBEMAIL_SMTP_PORT=587
- ROUNDCUBEMAIL_SMTP_AUTH=LOGIN
- ROUNDCUBEMAIL_USERNAME_DOMAIN=produktor.io
- ROUNDCUBEMAIL_SKIN=elastic
- ROUNDCUBEMAIL_DES_KEY=${ROUNDCUBEMAIL_DES_KEY:?set ROUNDCUBEMAIL_DES_KEY in .env}
# Account admin (read-only view) — https://mail.produktor.io/admin/ (NPM proxy
# host 66, location /admin/ -> 172.17.0.1:19945).
# Lists the accounts from config/postfix-accounts.cf with per-mailbox message
# counts (INBOX / total) and storage, computed the same way doveadm reports
# them: every file in a mailbox's cur/ or new/ directory is one message.
# Read-only: config and mail data are mounted with :ro, no docker socket.
mail-admin:
build:
context: ./admin
image: mail-admin:local
container_name: mail-admin
restart: unless-stopped
depends_on:
- mailserver
ports:
- "127.0.0.1:19945:8080"
- "172.17.0.1:19945:8080"
volumes:
- ./config/:/config/:ro
- ./data/mail-data/:/var/mail/:ro
environment:
- MAIL_ADMIN_LISTEN=:8080
- MAIL_ADMIN_BASE_PATH=/admin
- MAIL_ADMIN_ACCOUNTS=/config/postfix-accounts.cf
- MAIL_ADMIN_QUOTAS=/config/dovecot-quotas.cf
- MAIL_ADMIN_MAILDIR=/var/mail
- MAIL_ADMIN_USER=${MAIL_ADMIN_USER:?set MAIL_ADMIN_USER in .env}
- MAIL_ADMIN_PASSWORD=${MAIL_ADMIN_PASSWORD:?set MAIL_ADMIN_PASSWORD in .env}