Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
15 changes: 7 additions & 8 deletions deploy/kustomize/unbound/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,20 @@ spec:
- secretRef:
name: secret-config-env
securityContext:
allowPrivilegeEscalation: false
runAsUser: 100
runAsGroup: 101
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
- CHOWN
- SETUID
- SETGID
ports:
- name: dns
containerPort: 5353
containerPort: 53
protocol: UDP
- name: dns-tcp
containerPort: 5353
containerPort: 53
protocol: TCP
livenessProbe:
exec:
Expand All @@ -67,8 +69,5 @@ spec:
cpu: 50m
memory: 32Mi
securityContext:
fsGroup: 101
fsGroupChangePolicy: OnRootMismatch
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
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
3 changes: 3 additions & 0 deletions target/mta/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ RUN apk --no-cache add \
postconf smtpd_error_sleep_time=10s && \
postconf smtpd_soft_error_limit=3 && \
postconf smtpd_hard_error_limit=5 && \
postconf postscreen_dnsbl_sites='bl.spamcop.net*2' && \
postconf postscreen_dnsbl_threshold=2 && \
postconf postscreen_dnsbl_action=enforce && \
newaliases
COPY --from=dockerize /bin/dockerize /usr/local/bin/dockerize
COPY rootfs/ /
Expand Down
6 changes: 4 additions & 2 deletions target/mta/rootfs/etc/postfix/master.cf
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
smtp inet n - n - - smtpd
#smtp inet n - n - 1 postscreen
smtp inet n - y - 1 postscreen
smtpd pass - - y - - smtpd
dnsblog unix - - y - 0 dnsblog
tlsproxy unix - - y - 0 tlsproxy
pickup unix n - n 60 1 pickup
cleanup unix n - n - 0 cleanup
qmgr unix n - n 300 1 qmgr
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
8 changes: 3 additions & 5 deletions target/unbound/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ LABEL maintainer="https://github.com/jeboehm/docker-mailserver"
LABEL vendor="https://github.com/jeboehm/docker-mailserver"
LABEL de.ressourcenkonflikt.docker-mailserver.autoheal="true"

RUN chown -R unbound:unbound /etc/unbound && \
apk add --no-cache bind-tools
COPY --chown=unbound:unbound rootfs/ /
USER unbound
RUN apk add --no-cache bind-tools
COPY rootfs/ /

EXPOSE 5353/tcp 5353/udp
EXPOSE 53/tcp 53/udp
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