2c7f0da3d8
Generate the relay config from the environment at container start (build/postfix-config.sh, run from entrypoint.sh): - smtps 465 (implicit TLS) primary + optional submission 587 (STARTTLS), chroot=n so smtpd reaches the sasldb2/sender map under /data. - Cyrus SASL against the panel-maintained sasldb2; realm left implicit so the authenticated name equals the bare login in smtpd_sender_login_maps. - reject_sender_login_mismatch + relay/recipient restrictions with no permit_mynetworks: credentials-only, open relay impossible (spec 5, 5.1). - TLS cert/key from TLS_CERT_FILE/TLS_KEY_FILE; daily postfix reload picks up renewed certs (postfix-cert-reload.sh under supervisord, spec 5.2). - anvil level-1 rate limit from env (spec 5 p.5). - Milter chain with per-milter action: OpenDKIM strict (tempfail), journal fail-open (accept) so monitoring never blocks the relay (spec 7.3). Two integration fixes found on the server: - postconf -F '*/*/chroot=n': Debian's chrooted delivery agent can't read /etc/resolv.conf, so MX lookups failed and mail never left. - entrypoint sets /run/opendkim and /run/selfpost to group selfpost + setgid, and the journal stub chmods its socket 0660, so postfix can connect to both milter sockets (strict OpenDKIM was milter-rejecting all mail otherwise). Verified on selfpost.example.com: gofmt/vet/test green, image builds; container e2e — 465 auth+send DKIM-signed (d=domain,s=selfpost), 587 STARTTLS auth, cross-domain sender 553, list-mode per-address binding, unauth relay 554, real outbound delivery reaching the recipient MX over TLS. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
111 lines
3.5 KiB
Plaintext
111 lines
3.5 KiB
Plaintext
; SelfPost process supervision (spec 4).
|
|
;
|
|
; Start ORDER is enforced by priority=: OpenDKIM, then the panel (which opens
|
|
; the journal-milter socket), then the Postfix wrapper — which additionally
|
|
; blocks until both milter sockets are ready before starting Postfix.
|
|
;
|
|
; If any managed process exhausts its restart retries (FATAL), the crashexit
|
|
; event listener brings the whole container down so Docker's restart policy can
|
|
; recreate it cleanly, rather than lingering with a dead component.
|
|
|
|
[supervisord]
|
|
nodaemon=true
|
|
user=root
|
|
logfile=/dev/null
|
|
logfile_maxbytes=0
|
|
pidfile=/run/supervisord.pid
|
|
loglevel=info
|
|
|
|
; The control socket is reachable by the shared `selfpost` group so the panel
|
|
; (running as the unprivileged `panel` user) can ask supervisord to send
|
|
; OpenDKIM a reload signal after it rewrites the DKIM tables (spec 6.2). It is
|
|
; still unreachable by world; only root and the two SelfPost services are in the
|
|
; group. No HTTP auth is configured because access is gated by socket
|
|
; permissions, not the network.
|
|
[unix_http_server]
|
|
file=/run/supervisor.sock
|
|
chown=root:selfpost
|
|
chmod=0770
|
|
|
|
[rpcinterface:supervisor]
|
|
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
|
|
|
|
[supervisorctl]
|
|
serverurl=unix:///run/supervisor.sock
|
|
|
|
[program:opendkim]
|
|
command=/usr/sbin/opendkim -f -x /etc/opendkim.conf
|
|
priority=100
|
|
autostart=true
|
|
autorestart=true
|
|
startretries=3
|
|
stdout_logfile=/dev/stdout
|
|
stdout_logfile_maxbytes=0
|
|
stderr_logfile=/dev/stderr
|
|
stderr_logfile_maxbytes=0
|
|
|
|
[program:panel]
|
|
command=/usr/local/bin/panel
|
|
user=panel
|
|
priority=200
|
|
autostart=true
|
|
autorestart=true
|
|
startretries=3
|
|
stdout_logfile=/dev/stdout
|
|
stdout_logfile_maxbytes=0
|
|
stderr_logfile=/dev/stderr
|
|
stderr_logfile_maxbytes=0
|
|
|
|
[program:postfix]
|
|
command=/usr/local/bin/postfix-wrapper.sh
|
|
priority=300
|
|
autostart=true
|
|
autorestart=true
|
|
startretries=3
|
|
stdout_logfile=/dev/stdout
|
|
stdout_logfile_maxbytes=0
|
|
stderr_logfile=/dev/stderr
|
|
stderr_logfile_maxbytes=0
|
|
|
|
; One-shot reload helper (spec 5.2, 7.2.12). The panel runs unprivileged and
|
|
; cannot run `postfix reload` itself, and it cannot signal the Postfix master
|
|
; directly: `postfix start-fg` forks a separate master process, so a signal to
|
|
; the supervised foreground process never reaches it (unlike OpenDKIM, which
|
|
; runs in the foreground as the supervised process itself). Instead the panel
|
|
; asks supervisord — over the group-accessible control socket — to run this
|
|
; program, which executes the canonical `postfix reload` as root. autostart is
|
|
; off (it only runs on demand) and a fast, clean exit is expected, so it never
|
|
; trips the crashexit listener.
|
|
[program:postfix-reload]
|
|
command=/usr/sbin/postfix reload
|
|
autostart=false
|
|
autorestart=false
|
|
startsecs=0
|
|
startretries=1
|
|
exitcodes=0
|
|
stdout_logfile=/dev/stdout
|
|
stdout_logfile_maxbytes=0
|
|
stderr_logfile=/dev/stderr
|
|
stderr_logfile_maxbytes=0
|
|
|
|
; Periodic TLS-certificate refresh (spec 5.2 p.4). Runs a daily `postfix reload`
|
|
; so certificates the reverse-proxy renews in the read-only mount are picked up.
|
|
; Long-running (it loops), runs as root so it can reload Postfix, and never exits
|
|
; non-zero, so it neither trips the crashexit listener nor needs restarting.
|
|
[program:cert-reload]
|
|
command=/usr/local/bin/postfix-cert-reload.sh
|
|
priority=400
|
|
autostart=true
|
|
autorestart=true
|
|
startsecs=0
|
|
stdout_logfile=/dev/stdout
|
|
stdout_logfile_maxbytes=0
|
|
stderr_logfile=/dev/stderr
|
|
stderr_logfile_maxbytes=0
|
|
|
|
[eventlistener:crashexit]
|
|
command=/usr/local/bin/crashexit.py
|
|
events=PROCESS_STATE_FATAL
|
|
stderr_logfile=/dev/stderr
|
|
stderr_logfile_maxbytes=0
|