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}