Skip to content
Draft
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions deploy/compose/unbound.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ services:
cache_from:
- type=registry,ref=ghcr.io/jeboehm/mailserver-unbound:buildcache
restart: on-failure:5
cap_add:
- NET_BIND_SERVICE
security_opt:
- no-new-privileges
read_only: false
6 changes: 4 additions & 2 deletions deploy/kustomize/unbound/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,14 @@ spec:
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
ports:
- name: dns
containerPort: 5353
containerPort: 53
protocol: UDP
- name: dns-tcp
containerPort: 5353
containerPort: 53
protocol: TCP
livenessProbe:
exec:
Expand Down
4 changes: 2 additions & 2 deletions deploy/kustomize/unbound/network-policy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ spec:
- podSelector: {}
ports:
- protocol: UDP
port: 5353 # DNS
port: 53 # DNS
- protocol: TCP
port: 5353 # DNS TCP
port: 53 # DNS TCP
9 changes: 8 additions & 1 deletion docs/UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ Upgrade guide for docker-mailserver.

Before upgrading, ensure you have updated `docker-compose.yml` and `docker-compose.production.yml` files.

## v6.0 to v6.1

- **Unbound port change and capability requirement (breaking)**: Unbound now listens on port `53` (UDP/TCP) instead of `5353`.
- Compose: the `unbound` service now requires `cap_add: [NET_BIND_SERVICE]` to bind <1024 as non-root.
- Kubernetes: the `unbound` deployment exposes containerPorts `53/TCP` and `53/UDP` and adds the `NET_BIND_SERVICE` capability.
- Rspamd and internal components should use `unbound:53`. Any hardcoded `:5353` must be updated.
- If you previously customized Postfix to use `127.0.0.1:5353`, remove that customization. Postfix and other services should resolve via standard port 53.

## v5.x to v6.0

Deployment on Kubernetes is now a first class citizen. You can use the `kustomization.yaml` file to deploy the mailserver to your Kubernetes cluster.
Expand All @@ -21,7 +29,6 @@ The Helm chart has been deprecated and archived.
- **Mail Submission**: Mail submission is now only possible on port 587.

### MDA (Mail Delivery Agent)

- **Base Image**: Changed to `dovecot/dovecot`. This image is no longer based on Alpine Linux.
- **TLS Certificate Paths**: Updated to `/etc/dovecot/tls/tls.crt` and `/etc/dovecot/tls/tls.key`. A Diffie-Hellman file is no longer required.
- **Mail Storage**: Now mounted to `/srv/vmail` instead of `/var/vmail`.
Expand Down
22 changes: 21 additions & 1 deletion target/mta/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,27 @@ RUN apk --no-cache add \
postconf smtpd_error_sleep_time=10s && \
postconf smtpd_soft_error_limit=3 && \
postconf smtpd_hard_error_limit=5 && \
newaliases
newaliases && \
# enable postscreen on port 25 and supporting services
sed -i 's/^smtp\s\+inet\s\+n\s\+-\s\+y\s\+-\s\+-\s\+smtpd/smtp inet n - y - 1 postscreen/' /etc/postfix/master.cf && \
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cursoragent change that directly in master.cf in the rootfs folder

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Taking a look!

Open in Cursor Open in Web

printf '%s\n' \
'smtpd pass - - y - - smtpd' \
'dnsblog unix - - y - 0 dnsblog' \
'tlsproxy unix - - y - 0 tlsproxy' \
>> /etc/postfix/master.cf && \
postconf postscreen_dnsbl_sites='bl.spamcop.net*2' && \
postconf postscreen_dnsbl_threshold=2 && \
postconf postscreen_dnsbl_action=enforce && \
echo "submission inet n - n - - smtpd" >> /etc/postfix/master.cf && \
echo " -o syslog_name=postfix/submission" >> /etc/postfix/master.cf && \
echo " -o smtpd_tls_security_level=encrypt" >> /etc/postfix/master.cf && \
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cursoragent change that directly in master.cf in the rootfs folder

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Taking a look!

Open in Cursor Open in Web

echo " -o smtpd_sasl_auth_enable=yes" >> /etc/postfix/master.cf && \
echo " -o smtpd_tls_auth_only=yes" >> /etc/postfix/master.cf && \
echo " -o smtpd_reject_unlisted_recipient=no" >> /etc/postfix/master.cf && \
echo " -o smtpd_sender_restrictions=reject_sender_login_mismatch,permit_sasl_authenticated,reject" >> /etc/postfix/master.cf && \
echo " -o smtpd_relay_restrictions=" >> /etc/postfix/master.cf && \
echo " -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject" >> /etc/postfix/master.cf && \
echo " -o milter_macro_daemon_name=ORIGINATING" >> /etc/postfix/master.cf
COPY --from=dockerize /bin/dockerize /usr/local/bin/dockerize
COPY rootfs/ /

Expand Down
20 changes: 20 additions & 0 deletions target/mta/rootfs/usr/local/bin/init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,23 @@ dockerize \
-template /etc/postfix/mysql-recipient-access.cf.templ:/etc/postfix/mysql-recipient-access.cf \
-template /etc/postfix/mysql-email-submission.cf.templ:/etc/postfix/mysql-email-submission.cf \
/bin/true

# Configure resolver for Postfix to use $UNBOUND_DNS_ADDRESS
# Accept formats like "host:port" or "ip:port"; default port 53 if omitted
if [ -n "${UNBOUND_DNS_ADDRESS}" ]; then
UNBOUND_DNS_HOST=$(echo "${UNBOUND_DNS_ADDRESS}" | cut -d: -f1)
UNBOUND_DNS_PORT=$(echo "${UNBOUND_DNS_ADDRESS}" | cut -s -d: -f2)
if [ -z "${UNBOUND_DNS_PORT}" ]; then
UNBOUND_DNS_PORT=53
fi

# Resolve hostname to IP if necessary
UNBOUND_DNS_IP=$(getent hosts "${UNBOUND_DNS_HOST}" | awk '{print $1}' | head -n1)
if [ -z "${UNBOUND_DNS_IP}" ]; then
UNBOUND_DNS_IP=${UNBOUND_DNS_HOST}
fi

mkdir -p /var/spool/postfix/etc
echo "nameserver ${UNBOUND_DNS_IP}" > /var/spool/postfix/etc/resolv.conf
# glibc resolv.conf does not support custom port; rely on Unbound standard port 53
fi
2 changes: 1 addition & 1 deletion target/unbound/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ RUN chown -R unbound:unbound /etc/unbound && \
COPY --chown=unbound:unbound rootfs/ /
USER unbound

EXPOSE 5353/tcp 5353/udp
EXPOSE 53/TCP 53/UDP
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

protocol in lowercase

HEALTHCHECK CMD /usr/local/bin/healthcheck.sh
2 changes: 1 addition & 1 deletion target/unbound/rootfs/etc/unbound/unbound.conf
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
server:
chroot: ""
username: ""
port: 5353
port: 53
trust-anchor-file: "/etc/unbound/root.key"

do-ip6: no
Expand Down
17 changes: 8 additions & 9 deletions target/unbound/rootfs/usr/local/bin/healthcheck.sh
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
#!/bin/sh
set -e

# Test DNS resolution using dig
if ! dig @127.0.0.1 -p 5353 github.com >/dev/null 2>&1; then
echo "Healthcheck failed: DNS resolution test failed"
exit 1
# UDP check
if ! dig @127.0.0.1 -p 53 github.com +time=2 +tries=1 +short >/dev/null 2>&1; then
echo "Healthcheck failed: dig UDP to 127.0.0.1:53"
exit 1
fi

# Test UDP connectivity (unbound typically uses UDP for DNS)
if ! dig @127.0.0.1 -p 5353 +tcp github.com >/dev/null 2>&1; then
echo "Healthcheck failed: TCP DNS resolution test failed"
exit 1
# TCP check (no nc dependency)
if ! dig +tcp @127.0.0.1 -p 53 github.com +time=2 +tries=1 +short >/dev/null 2>&1; then
echo "Healthcheck failed: dig TCP to 127.0.0.1:53"
exit 1
fi

echo "Healthcheck passed"

exit 0
3 changes: 1 addition & 2 deletions test/bats/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ ENV MYSQL_HOST=db \
MDA_IMAPS_ADDRESS=mda:31993 \
MTA_SMTP_ADDRESS=mta:25 \
MTA_SMTP_SUBMISSION_ADDRESS=mta:587 \
RELAYHOST=false \
UNBOUND_DNS_ADDRESS=unbound:5353 \
UNBOUND_DNS_ADDRESS=unbound:53 \
WAITSTART_TIMEOUT=1m \
WEB_HTTP_ADDRESS=web:8080

Expand Down
Loading