Mail Server Series — Part 14
After going through the previous 13 parts, we now have a fully working, containerized mail system built on Docker. In this final article, we’ll step back and look at the whole picture:
- Review the overall architecture
- Summarize the mail flow (inbound / outbound / archive)
-Organize an operations checklist (what you should watch daily / weekly / monthly) - List security hardening points
- Talk about future expansion and optimization ideas
This part is less about commands, and more about helping you “own” the system as a long-term platform.
1. Final Architecture Overview
Let’s quickly recap the main components and their roles. All of them are running in Docker, connected via the intranet-net network, and protected by iptables on the host.
1.1 Core Services
- Postfix (
postfixcontainer)- Handles SMTP (port 25, 587)
- Uses MySQL (MariaDB) for virtual domains and users
- Integrates with Amavis + SpamAssassin + ClamAV as a content filter
- Uses PostfixAdmin’s database as the source of virtual users/domains
- Sends a copy of all mail to Piler via
transport(archive.local -> smtp:[172.18.0.1]:2525)
- Dovecot (
dovecotcontainer)- Provides POP3/POP3S (110/995), IMAP/IMAPS (143/993), LMTP (24), ManageSieve (4190)
- Uses MySQL (same Postfix DB) for user authentication
- Stores user mail under
/var/vmail(mounted from host) - Implements quota, per-user spam learning via remote
spamcto SpamAssassin - Supports SNI certificates via shared Let’s Encrypt paths
- MariaDB (
maildbcontainer)- Stores Postfix/PostfixAdmin DB (
postfixDB) - Stores SpamAssassin Bayes / TxRep / user prefs (
sa40DB) - Stores Piler metadata (
pilerDB)
- Stores Postfix/PostfixAdmin DB (
1.2 Security and Content Filtering
- SpamAssassin (
spamassassincontainer)- Runs
spamdon port 783 - Uses MySQL Bayes + TxRep (per-user learning)
- Dovecot’s Sieve scripts send learned HAM/SPAM to
spamc -L ham/spam - Combines global rules + per-user scoring
- Runs
- ClamAV (
clamavcontainer)- Runs
clamdlistening on port 3310 - Maintains virusDB under
/var/lib/clamav - Freshclam runs in the same container to update signatures
- Runs
- Amavis (
amaviscontainer)- Listens on 10024/10026 for content filtering
- Integrates with ClamAV (
clamdscan) and SpamAssassin (spamd) - Verifies DKIM, and signs outbound mail for
it.demo.tw - Provides policy banks for inbound/outbound, with different threshold and behavior
1.3 Management, Archive, and Web Access
- PostfixAdmin (
mailsetupcontainer)- Web management interface for domains, mailboxes, aliases
- Uses MariaDB (
postfixDB) and is reverse proxied viamailsetup.it.demo.tw - Only exposed through Apache reverse proxy with HTTPS
- Piler + Manticore + Memcached (
piler,manticore,memcachedcontainers)- Piler archives all messages (inbound/outbound), storing bodies in
/var/piler/store - Manticore provides full-text search with Chinese support (ICU + CJK n-gram)
- Piler-Web integrates with Dovecot IMAP for user authentication; permission model is based on
X-Envelope-Toheaders - Access via
https://archive.it.demo.tw/
- Piler archives all messages (inbound/outbound), storing bodies in
- Roundcube Webmail (
webmailcontainer)- Webmail with IMAP over TLS (
tls://it.demo.tw:143), SMTP submission (tls://it.demo.tw:587) - Uses
managesieveplugin to manage Sieve rules on Dovecot (4190) - Reverse proxied via
https://webmail.it.demo.tw/
- Webmail with IMAP over TLS (
- piler-milter (
pilermiltercontainer)- A Sendmail::PMilter Perl milter
- Adds
X-Envelope-From/X-Envelope-Toheaders for each envelope recipient - Helps Piler identify per-user authorization for archive browsing
- Apache Reverse Proxy (
wwwappcontainer)- Public entry point for:
it.demo.tw(dummy landing)mail.it.demo.tw(optional)mailsetup.it.demo.tw(PostfixAdmin)webmail.it.demo.tw(Roundcube)archive.it.demo.tw(Piler)
- Manages all Let’s Encrypt certificates through
certbot - Hosts ACME HTTP-01 challenge directories
- Public entry point for:
2. Mail Flow Summary (End-to-End)
2.1 Inbound Flow (Internet → User Mailbox + Archive)
- Remote mail server connects to
postfix :25. - Postfix checks:
- HELO, sender, recipient restrictions
- Virtual domain / mailbox via MySQL
- Milter (piler-milter) to inject
X-Envelope-To
- Postfix passes mail to Amavis via
content_filter = smtp-amavis:[amavis]:10024. - Amavis:
- Scans with ClamAV
- Runs SpamAssassin (Bayes + TxRep)
- Applies policies, modifies headers (e.g., spam score)
- Cleaned mail returns from Amavis to Postfix via port
10025. - Postfix delivers:
- Main copy:
lmtp:inet:dovecot:24→ Dovecot →/var/vmail/... - Archive copy: via
transporttoarchive.local -> smtp:[172.18.0.1]:2525→ Piler
- Main copy:
- Piler stores and indexes message into Manticore; user can later search via
archive.it.demo.tw.
2.2 Outbound Flow (User → Internet + Archive)
- User sends via:
- Outlook / Thunderbird →
postfix :587(submission, TLS required) - Roundcube →
postfix :587fromwebmail
- Outlook / Thunderbird →
- Submission in Postfix:
- Requires SASL auth (
dovecotas SASL backend) - Validates sender matches login (
reject_authenticated_sender_login_mismatch)
- Requires SASL auth (
- Postfix sends to Amavis via
smtp-amavis:[amavis]:10026(policy bankORIGINATING) - Amavis:
- Applies spam check (for outgoing spam)
- Adds DKIM signature for
it.demo.tw
- Amavis returns via
10027to Postfix, then Postfix relays to the Internet. - Again,
always_bcc = piler@archive.localensures every outbound mail is archived.
3. Operations Checklist (Daily / Weekly / Monthly)
3.1 Daily Checks
- Mail flow health
- Log in to Roundcube, send/receive a test mail (internal + external address)
- Check in Piler whether the message appears in the archive
- Container health
docker psto ensure all containers (postfix, dovecot, amavis, spamassassin, clamav, piler, manticore, webmail, mailsetup, wwwapp, maildb, memcached, pilermilter) are up- Check critical logs:
/opt/docker/mail/postfix/log/postfix.log/opt/docker/mail/dovecot/log/dovecot.log/opt/docker/mail/amavis/log/amavis.log/opt/docker/mail/spamassassin/log/spamd.log / sa-learn.log/opt/docker/mail/clamav/log/clamd.log/opt/docker/mail/piler/piler_etc/piler.log(or wherever Piler logs)
- Disk space
- Check space on:
/opt/docker/mail/dovecot/usermail(user mailboxes)/opt/docker/mail/piler/piler_store(archive store)/opt/docker/mail/piler/piler_manticore(Manticore data)
- Check space on:
3.2 Weekly Checks
- SpamAssassin rules & Bayes DB
- Confirm
sa-update/sa-compileare running via cron (in Amavis container) - Check Bayes DB growth and whether auto-learning is working
- Confirm
- ClamAV
- Check
freshclamlogs, ensure virus DB updates regularly
- Check
- Piler & Manticore
- Run several search tests, including Chinese keywords
- Confirm tag / note / audit features are working as expected
- Let’s Encrypt Renewal Dry Run
- Check
renewssl.shlogs - Optionally run a manual dry run:
certbot renew --dry-run
- Check
3.3 Monthly / Quarterly Tasks
- Full backup
- MariaDB backups:
postfix,sa40,piler
- File backups:
/var/vmail(Dovecot mailstore)/var/piler/store(archive)/etc-equivalent config directories under/opt/docker(postfix, dovecot, amavis, spamassassin, piler, manticore, webmail, apache, etc.)
- MariaDB backups:
- Security review
- Confirm firewall rules (iptables / DOCKER-USER) are still correct
- Review admin accounts in PostfixAdmin and Piler
- Check that there are no unknown user accounts or suspicious login attempts
- Capacity planning
- How fast is
/var/vmailand/var/piler/storegrowing? - Do you need larger disks, or retention policy adjustment in Piler?
- How fast is
4. Security Hardening Checklist
You already implemented many secure practices. Here is a concise checklist for future review:
- TLS Everywhere
- Let’s Encrypt certificates for:
it.demo.tw,mail.it.demo.twwebmail.it.demo.tw,mailsetup.it.demo.tw,archive.it.demo.tw
- Postfix: enforce TLS on submission (
587) and SMTPS (465) - Dovecot: IMAPS (
993) and POP3S (995) enabled; disable plaintext auth without TLS
- Let’s Encrypt certificates for:
- Authentication and Authorization
- Postfix uses Dovecot as SASL provider; invalid logins are rejected
smtpd_sender_login_mapsensures that authenticated user cannot spoof another “From” address- Piler and Roundcube both rely on IMAP auth to keep account control centralized
- Network Isolation
- Use
intranet-netfor internal container traffic - Limit host firewall to:
- Allow necessary ports from Internet (25, 443, 587/465 if needed)
- Allow internal traffic from
172.18.0.0/16to host where needed (e.g., Roundcube → Dovecot, Apache → containers) - Drop everything else by default
- Use
- DKIM + SPF + DMARC
- Amavis signs outbound mail with DKIM for
it.demo.tw - Configure SPF record for
it.demo.twin DNS - Configure DMARC policy and monitor reports for your domain reputation
- Amavis signs outbound mail with DKIM for
- Log Retention and Auditing
- Syslog + file logs with logrotate (especially for Dovecot, Postfix, Amavis, Piler, Manticore)
- Piler’s audit log allows you to trace who opened which message and when, which is important for compliance
5. Future Expansion Ideas
Once this platform is stable, there are many directions for further improvement.
5.1 High Availability
- Multi-node deployment
- Run Postfix + Dovecot on two hosts with a shared storage backend (or object storage)
- Use a load balancer / keepalived / HAProxy in front of SMTP/IMAP/Web
- DB and search HA
- Migrate MariaDB to a replicated setup (Galera/primary-standby)
- Use Manticore clustering for index redundancy
5.2 Multi-Domain and Multi-Company
- You already use Postfix virtual domains; it’s easy to:
- Add more domains in PostfixAdmin
- Use Dovecot`s SQL auth to serve different domains from the same infrastructure
- For each new domain:
- Add DNS: MX/SPF/DKIM/DMARC
- Add virtual domain in PostfixAdmin
- Generate new DKIM key in Amavis (if required)
5.3 Deeper Integration
- Integration with company SSO / LDAP
- Use OpenLDAP / AD as the user source
- Map LDAP attributes to mailboxes and aliases
- Dovecot and Postfix both have LDAP auth support configs
- Monitoring & Alerting
- Integrate with Prometheus + Grafana / Zabbix to monitor:
- MX latency, queue length, rejection rate, spam ratio, ClamAV stats, SA stats
- Add alert rules for:
- Queue backlog too high
- Disk usage over threshold
- Containers down or restarts too often
- Integrate with Prometheus + Grafana / Zabbix to monitor:
5.4 User Self-Service Improvements
- Roundcube plugins:
- Password change integration (if you store passwords in SQL/LDAP)
- Two-factor authentication plugin
- Piler:
- Better role-based access for managers / auditors
- Department-based access control through Piler’s user/group features
6. Closing Thoughts
In this 14-part series, we went from raw Docker images to a production-grade mail system with:
- Full SMTP/IMAP stack (Postfix + Dovecot)
- Centralized virtual user/domain management (PostfixAdmin + MariaDB)
- Spam filtering + virus scanning (SpamAssassin + ClamAV + Amavis)
- Full mail archiving and search with Chinese support (Piler + Manticore + piler-milter)
- Modern web frontends (Roundcube, Piler Web UI)
- Proper TLS certificates and reverse proxy (Apache + Certbot)
The goal of this series isn’t just to “spin up a mail server,” but to build a platform you can understand, maintain, and extend over years.