feat: self-hosted postfix

This commit is contained in:
2026-01-24 08:43:50 +01:00
parent e46cb018fd
commit eeed88eba4
16 changed files with 2830 additions and 652 deletions

30
docker/postfix/Dockerfile Normal file
View File

@@ -0,0 +1,30 @@
FROM debian:bookworm-slim
# install oostfix and OpenDKIM
RUN apt-get update && apt-get install -y \
postfix \
opendkim \
opendkim-tools \
mailutils \
ca-certificates \
netcat-openbsd \
&& rm -rf /var/lib/apt/lists/*
# create OpenDKIM paths
RUN mkdir -p /etc/opendkim/keys && \
chown -R opendkim:opendkim /etc/opendkim && \
chmod 700 /etc/opendkim/keys
# copy config
COPY postfix-main.cf /etc/postfix/main.cf
COPY opendkim.conf /etc/opendkim.conf
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
EXPOSE 25
HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \
CMD echo "QUIT" | nc -w 5 localhost 25 | grep -q "220" || exit 1
ENTRYPOINT ["/entrypoint.sh"]

View File

@@ -0,0 +1,90 @@
#!/bin/bash
set -e
# environment variables
MAIL_DOMAIN="${MAIL_DOMAIN:-example.com}"
MAIL_HOSTNAME="${MAIL_HOSTNAME:-mail.example.com}"
DKIM_SELECTOR="${DKIM_SELECTOR:-mail}"
echo "Setting up postfix for domain: ${MAIL_DOMAIN}"
echo "Hostname: ${MAIL_HOSTNAME}"
# configure postfix domain
postconf -e "myhostname=${MAIL_HOSTNAME}"
postconf -e "mydomain=${MAIL_DOMAIN}"
postconf -e "myorigin=\$mydomain"
postconf -e "mydestination=\$myhostname, localhost.\$mydomain, localhost"
# create OpenDKIM key folder for domain
DKIM_KEY_DIR="/etc/opendkim/keys/${MAIL_DOMAIN}"
mkdir -p "${DKIM_KEY_DIR}"
# generate DKIM keys if they don't exist
if [ ! -f "${DKIM_KEY_DIR}/${DKIM_SELECTOR}.private" ]; then
echo "Generating DKIM keys for ${MAIL_DOMAIN}..."
opendkim-genkey -b 2048 -d "${MAIL_DOMAIN}" -D "${DKIM_KEY_DIR}" -s "${DKIM_SELECTOR}" -v
chown -R opendkim:opendkim "${DKIM_KEY_DIR}"
chmod 600 "${DKIM_KEY_DIR}/${DKIM_SELECTOR}.private"
echo ""
echo "============================================"
echo "DKIM PUBLIC KEY - ADD THIS TO YOUR DNS:"
echo "============================================"
echo "Record Type: TXT"
echo "Name: ${DKIM_SELECTOR}._domainkey.${MAIL_DOMAIN}"
echo ""
cat "${DKIM_KEY_DIR}/${DKIM_SELECTOR}.txt"
echo ""
echo "============================================"
echo ""
else
echo "Using existing DKIM keys"
fi
# configure OpenDKIM KeyTable
cat > /etc/opendkim/KeyTable << EOF
${DKIM_SELECTOR}._domainkey.${MAIL_DOMAIN} ${MAIL_DOMAIN}:${DKIM_SELECTOR}:${DKIM_KEY_DIR}/${DKIM_SELECTOR}.private
EOF
# configure OpenDKIM SigningTable
cat > /etc/opendkim/SigningTable << EOF
*@${MAIL_DOMAIN} ${DKIM_SELECTOR}._domainkey.${MAIL_DOMAIN}
EOF
# configure OpenDKIM TrustedHosts
cat > /etc/opendkim/TrustedHosts << EOF
127.0.0.1
localhost
${MAIL_DOMAIN}
*.${MAIL_DOMAIN}
172.16.0.0/12
192.168.0.0/16
10.0.0.0/8
EOF
# set permissions
chown -R opendkim:opendkim /etc/opendkim
chmod 600 /etc/opendkim/KeyTable
chmod 600 /etc/opendkim/SigningTable
# create postfix spool folders
mkdir -p /var/spool/postfix/pid
chown root:root /var/spool/postfix
chown root:root /var/spool/postfix/pid
# start OpenDKIM in background
echo "Starting OpenDKIM..."
opendkim -f &
# wait for OpenDKIM to start
sleep 2
# copy DNS config to postfix chroot
mkdir -p /var/spool/postfix/etc
cp /etc/resolv.conf /var/spool/postfix/etc/
cp /etc/services /var/spool/postfix/etc/
cp /etc/hosts /var/spool/postfix/etc/
# start postfix in foreground
echo "Starting Postfix..."
postfix start-fg

View File

@@ -0,0 +1,30 @@
# OpenDKIM configuration for email signing
# log to syslog
Syslog yes
SyslogSuccess yes
LogWhy yes
# required for verification
Canonicalization relaxed/simple
# sign mode (s=sign, v=verify)
Mode sv
# sign subdomains
SubDomains no
# key configuration (will be set by entrypoint)
KeyTable /etc/opendkim/KeyTable
SigningTable refile:/etc/opendkim/SigningTable
ExternalIgnoreList refile:/etc/opendkim/TrustedHosts
InternalHosts refile:/etc/opendkim/TrustedHosts
# socket for postfix connection
Socket inet:8891@localhost
# user
UserID opendkim
# permissions
RequireSafeKeys false

View File

@@ -0,0 +1,50 @@
# Postfix main configuration for newsletter sending
# Domain and hostname will be set by entrypoint script
smtpd_banner = $myhostname ESMTP
biff = no
append_dot_mydomain = no
readme_directory = no
# TLS parameters (for outbound connections)
smtp_tls_security_level = may
smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt
# Network settings
inet_interfaces = all
inet_protocols = ipv4
# Relay settings (don't relay for others)
relayhost =
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 172.16.0.0/12 192.168.0.0/16 10.0.0.0/8
# Message size limit (10MB)
message_size_limit = 10240000
# Queue settings
maximal_queue_lifetime = 5d
bounce_queue_lifetime = 5d
# Security settings
smtpd_helo_required = yes
disable_vrfy_command = yes
smtpd_helo_restrictions =
permit_mynetworks,
reject_invalid_helo_hostname,
reject_non_fqdn_helo_hostname,
permit
smtpd_recipient_restrictions =
permit_mynetworks,
reject_unauth_destination,
permit
# OpenDKIM integration
milter_default_action = accept
milter_protocol = 6
smtpd_milters = inet:localhost:8891
non_smtpd_milters = inet:localhost:8891
# Notify on bounces
notify_classes = bounce, delay, resource, software