Sign inSign up

ricariel/postfix

By ricariel

•Updated about 11 hours ago

Image
0

50K+

ricariel/postfix repository overview

⁠Docker Postfix

Docker Pulls Image Size License

A flexible and modern Docker image for a Postfix mail server, based on Debian Trixie.

⁠Features

  • Debian Trixie: Built on a modern base image with Postfix 3.10.x.
  • Flexible Configuration: Configure any Postfix parameter via POSTFIX_* environment variables — no config files to edit.
  • Secure by Default: Enables submission (587) and smtps (465) with TLS and SASL authentication out of the box.
  • Database Integration: Includes postfix-ldap and postfix-mysql for user lookups, virtual mailboxes and aliases.
  • Extensible: Drop additional scripts into docker-entrypoint.d/ to extend the startup sequence.
  • Automated Maintenance: Runs postfix check and postfix upgrade-configuration on every start.
  • Container-ready: Logs to stdout, exposes a HEALTHCHECK, handles signals for graceful shutdown.

⁠Quickstart

docker run -d --name postfix \
  -e POSTFIX_myhostname=mail.example.com \
  -e POSTFIX_mydomain=example.com \
  -e POSTFIX_mynetworks="127.0.0.0/8" \
  -p 25:25 \
  -p 587:587 \
  -p 465:465 \
  ricariel/postfix

⁠Startup Sequence

On container start, the entrypoint executes all scripts inside /docker-entrypoint.d/ in lexicographic order via run-parts, then starts Postfix:

ScriptPurpose
10-copyCopies LDAP .cf files from /config/ldap/ into /etc/postfix/ldap/
20-setup-masterUncomments and enables submission (587) and smtps (465) in master.cf
25-postconfTranslates all POSTFIX_* environment variables into main.cf settings
30-maintenanceClears stale PID files, runs postfix check and postfix upgrade-configuration
99-endSignals the end of initialisation

Custom scripts added via derived images are sorted into this sequence by their filename prefix.

⁠Configuration

⁠Environment Variables
⁠ENTRYPOINT_QUIET_LOGS

Suppresses the startup log output of the entrypoint script itself. Postfix's own logs (via maillog_file) are unaffected.

-e ENTRYPOINT_QUIET_LOGS=1
⁠POSTFIX_* — Postfix main.cf settings

Every environment variable with the POSTFIX_ prefix is applied to /etc/postfix/main.cf at startup. The prefix is stripped; the remainder is used as the Postfix parameter name (case-sensitive).

Set a value:

-e POSTFIX_myhostname=mail.example.com
-e POSTFIX_mynetworks="127.0.0.0/8 10.0.0.0/8"

Delete / disable a setting (empty value comments it out in main.cf):

-e POSTFIX_relayhost=
⁠Reference: commonly used POSTFIX_* variables

Core identity

VariablePostfix parameterExample value
POSTFIX_myhostnamemyhostnamesmtp.example.com
POSTFIX_mydomainmydomainexample.com
POSTFIX_mydestinationmydestination$myhostname
POSTFIX_myoriginmyorigin$mydomain

Network

VariablePostfix parameterExample value
POSTFIX_inet_interfacesinet_interfacesall
POSTFIX_inet_protocolsinet_protocolsall
POSTFIX_mynetworksmynetworks127.0.0.0/8 10.0.0.0/8

Security note: Keep mynetworks as narrow as possible. Hosts listed here can relay mail without authentication.

Relay

VariablePostfix parameterExample value
POSTFIX_relayhostrelayhost[smtp.relay.com]:587
POSTFIX_virtual_transportvirtual_transportlmtp:dovecot:24

Virtual domains and mailboxes

VariablePostfix parameterDescription
POSTFIX_virtual_mailbox_domainsvirtual_mailbox_domainsDomains hosted on this server
POSTFIX_virtual_mailbox_mapsvirtual_mailbox_mapsMap addresses to mailbox paths
POSTFIX_virtual_alias_mapsvirtual_alias_mapsForwarding and alias map

TLS — inbound (smtpd)

VariablePostfix parameterExample value
POSTFIX_smtpd_tls_cert_filesmtpd_tls_cert_file/etc/postfix/certs/tls.crt
POSTFIX_smtpd_tls_key_filesmtpd_tls_key_file/etc/postfix/certs/tls.key
POSTFIX_smtpd_tls_security_levelsmtpd_tls_security_levelmay
POSTFIX_smtpd_tls_protocolssmtpd_tls_protocols>=TLSv1.2
POSTFIX_smtpd_tls_mandatory_protocolssmtpd_tls_mandatory_protocols>=TLSv1.2
POSTFIX_smtpd_tls_cipherssmtpd_tls_ciphershigh
POSTFIX_smtpd_tls_loglevelsmtpd_tls_loglevel1
POSTFIX_smtpd_tls_session_cache_databasesmtpd_tls_session_cache_databasebtree:/var/spool/postfix/smtpd_scache

TLS — outbound (smtp)

VariablePostfix parameterExample value
POSTFIX_smtp_tls_cert_filesmtp_tls_cert_file/etc/postfix/certs/tls.crt
POSTFIX_smtp_tls_key_filesmtp_tls_key_file/etc/postfix/certs/tls.key
POSTFIX_smtp_tls_security_levelsmtp_tls_security_leveldane
POSTFIX_smtp_tls_protocolssmtp_tls_protocols>=TLSv1.2
POSTFIX_smtp_tls_loglevelsmtp_tls_loglevel1
POSTFIX_smtp_tls_policy_mapssmtp_tls_policy_mapsMTA-STS socketmap URI
POSTFIX_smtp_dns_support_levelsmtp_dns_support_leveldnssec (required for DANE)
POSTFIX_smtp_tls_session_cache_databasesmtp_tls_session_cache_databasebtree:/var/spool/postfix/smtp_scache

SASL authentication via Dovecot

VariablePostfix parameterExample value
POSTFIX_smtpd_sasl_typesmtpd_sasl_typedovecot
POSTFIX_smtpd_sasl_pathsmtpd_sasl_pathinet:dovecot:8745
POSTFIX_smtpd_sasl_auth_enablesmtpd_sasl_auth_enableyes
POSTFIX_smtpd_tls_auth_onlysmtpd_tls_auth_onlyyes

Milter integration (Rspamd, ClamAV-milter, etc.)

VariablePostfix parameterExample value
POSTFIX_smtpd_milterssmtpd_miltersinet:rspamd:11332
POSTFIX_non_smtpd_miltersnon_smtpd_miltersinet:rspamd:11332
POSTFIX_milter_default_actionmilter_default_actionaccept

Rate limiting

VariablePostfix parameterExample value
POSTFIX_smtpd_client_connection_rate_limitsmtpd_client_connection_rate_limit50
POSTFIX_smtpd_client_message_rate_limitsmtpd_client_message_rate_limit100
POSTFIX_smtpd_client_recipient_rate_limitsmtpd_client_recipient_rate_limit50
POSTFIX_anvil_rate_time_unitanvil_rate_time_unit60s

Miscellaneous

VariablePostfix parameterExample value
POSTFIX_message_size_limitmessage_size_limit52428800 (50 MB)
POSTFIX_maillog_filemaillog_file/dev/stdout
POSTFIX_masquerade_domainsmasquerade_domainsexample.com

For the full list of Postfix parameters, see the Postfix documentation⁠.

⁠Ports
PortProtocolPurpose
25/tcpSMTPServer-to-server mail transfer (inbound MX)
587/tcpSubmissionAuthenticated client mail submission (STARTTLS + SASL)
465/tcpSMTPSLegacy wrapper-mode TLS for older clients (SASL)
⁠Volumes and Mounts
⁠/config/ldap/

Mount a directory containing Postfix LDAP lookup table configuration files (.cf files). They are copied into /etc/postfix/ldap/ at startup by 10-copy.

docker run -d --name postfix \
  -v /path/to/ldap-configs:/config/ldap:ro \
  ...
  ricariel/postfix

Example main.cf references:

virtual_mailbox_maps  = ldap:/etc/postfix/ldap/virtual_mailbox.cf
virtual_alias_maps    = ldap:/etc/postfix/ldap/aliases.cf
smtpd_sender_login_maps = ldap:/etc/postfix/ldap/sender_login.cf

A minimal LDAP lookup file looks like this:

server_host     = ldaps://ldap.example.com:636
bind            = yes
bind_dn         = cn=postfix,ou=services,dc=example,dc=com
bind_pw         = secret
search_base     = ou=users,dc=example,dc=com
query_filter    = (mail=%s)
result_attribute = mail
⁠TLS certificates

Mount your certificate and key files and point Postfix to them via environment variables:

docker run -d --name postfix \
  -v /etc/letsencrypt/live/smtp.example.com:/etc/postfix/certs:ro \
  -e POSTFIX_smtpd_tls_cert_file=/etc/postfix/certs/fullchain.pem \
  -e POSTFIX_smtpd_tls_key_file=/etc/postfix/certs/privkey.pem \
  ...
  ricariel/postfix
⁠Mail spool

Postfix stores its mail queue under /var/spool/postfix/. For persistence across container restarts (e.g. to avoid losing queued messages on restart), mount a volume:

-v postfix-spool:/var/spool/postfix
⁠SQL lookup tables

In addition to LDAP, postfix-mysql is included for MySQL/MariaDB-based setups. See example_sql_map.md⁠ for example database schemas and query configurations covering virtual mailboxes, aliases, forwarding, and catch-all rules.

⁠Extending the Image

⁠Adding custom startup scripts

Any executable file placed in /docker-entrypoint.d/ of a derived image is automatically executed at startup. Use the numeric prefix to control execution order relative to the built-in scripts (10, 20, 25, 30, 99).

FROM ricariel/postfix

# Runs between 25-postconf and 30-maintenance
COPY --chmod=755 28-my-custom-setup.sh /docker-entrypoint.d/

The ONBUILD instruction in this image's Dockerfile automatically copies docker-entrypoint.d/* from the child image's build context, so no explicit COPY is needed if you place the scripts in the same directory.

⁠Overriding the default command

The default CMD is postfix start-fg. You can override it for debugging:

docker run --rm -it ricariel/postfix bash

⁠Docker Compose Example

services:
  postfix:
    image: ricariel/postfix
    restart: unless-stopped
    ports:
      - "25:25"
      - "587:587"
      - "465:465"
    volumes:
      - ./ldap:/config/ldap:ro
      - ./certs:/etc/postfix/certs:ro
      - postfix-spool:/var/spool/postfix
    environment:
      POSTFIX_myhostname: smtp.example.com
      POSTFIX_mydomain: example.com
      POSTFIX_mynetworks: "127.0.0.0/8"
      POSTFIX_virtual_mailbox_domains: "example.com"
      POSTFIX_virtual_transport: "lmtp:dovecot:24"
      POSTFIX_smtpd_tls_cert_file: /etc/postfix/certs/tls.crt
      POSTFIX_smtpd_tls_key_file: /etc/postfix/certs/tls.key
      POSTFIX_smtpd_tls_security_level: may
      POSTFIX_smtpd_sasl_type: dovecot
      POSTFIX_smtpd_sasl_path: "inet:dovecot:8745"
      POSTFIX_smtpd_sasl_auth_enable: "yes"
      POSTFIX_smtpd_milters: "inet:rspamd:11332"
      POSTFIX_non_smtpd_milters: "inet:rspamd:11332"
      POSTFIX_maillog_file: /dev/stdout

volumes:
  postfix-spool:

⁠Postfix Version Notes (3.8 → 3.10)

This image ships Postfix 3.10.x (Debian Trixie). If you are migrating from a Bookworm-based setup (Postfix 3.7.x), be aware of the following behavioral changes introduced across releases 3.8–3.10:

⁠Breaking changes (3.9)
ChangeImpact
permit_naked_ip_address, check_relay_domains, reject_maps_rbl removedPostfix refuses to start if any of these appear in smtpd_*_restrictions. Remove them from your config.
/usr/lib/postfix/configure-instance.sh is now internal-onlyThe script exits with code 1 when called directly. Postfix invokes it automatically as part of start-fg. Do not call it from entrypoint scripts.
smtpd_forbid_unauth_pipelining = yes now defaultClients that pipeline SMTP commands without RFC 2920 authorization are immediately disconnected. Affects broken senders.
Bare newline / SMTP smuggling defenses enabled by defaultNon-$mynetworks clients that do not send proper <CR><LF>.<CR><LF> will stall.
MySQL charset changed from latin1 → utf8mb4Existing postfix-mysql lookup tables may need charset conversion.
⁠TLS hardening (3.8)
  • "Export" and "low" cipher grades are silently promoted to "medium". Weak ciphers (3DES, RC4, SEED, IDEA, RC2, RC5) are no longer negotiated.
  • TLS renegotiation is unconditionally disabled.
  • postconf now warns if a # comment appears on the same line as a parameter value — move inline comments to their own line.
⁠Improvements (3.10)
  • OpenSSL 3.5 post-quantum cryptography support for outbound TLS.
  • Queue IDs are included in abnormal connection closure logs (better container log parsing).
  • SASL failure logs now include the mechanism name.
  • MySQL/PostgreSQL map connections reconnect immediately after a single failure (previously all queries were blocked for 60 seconds).

⁠License

This project is licensed under the MIT License. See the LICENSE⁠ file for details.

Tag summary

Content type

Image

Digest

sha256:061f7574b…

Size

96.7 MB

Last updated

about 11 hours ago

docker pull ricariel/postfix