From 35f9ffd5124095cd6f2348c8ee1a83daf8bf33e1 Mon Sep 17 00:00:00 2001 From: Haitao Pan Date: Wed, 3 Dec 2025 13:24:40 +0800 Subject: [PATCH] add base-images: mail-stack --- deploy/base-images/mail-stack/README.md | 39 +++++++++++++++ .../mail-stack/chasquid/Dockerfile | 14 ++++++ .../chasquid/config/chasquid.conf.tmpl | 11 ++++ .../mail-stack/chasquid/entrypoint.sh | 22 ++++++++ .../mail-stack/docker-compose.yaml | 50 +++++++++++++++++++ .../base-images/mail-stack/dovecot/Dockerfile | 16 ++++++ .../dovecot/config/10-master.conf.tmpl | 3 ++ .../dovecot/config/dovecot.conf.tmpl | 8 +++ .../mail-stack/dovecot/config/local.conf.tmpl | 14 ++++++ .../mail-stack/dovecot/entrypoint.sh | 17 +++++++ 10 files changed, 194 insertions(+) create mode 100644 deploy/base-images/mail-stack/README.md create mode 100644 deploy/base-images/mail-stack/chasquid/Dockerfile create mode 100644 deploy/base-images/mail-stack/chasquid/config/chasquid.conf.tmpl create mode 100755 deploy/base-images/mail-stack/chasquid/entrypoint.sh create mode 100644 deploy/base-images/mail-stack/docker-compose.yaml create mode 100644 deploy/base-images/mail-stack/dovecot/Dockerfile create mode 100644 deploy/base-images/mail-stack/dovecot/config/10-master.conf.tmpl create mode 100644 deploy/base-images/mail-stack/dovecot/config/dovecot.conf.tmpl create mode 100644 deploy/base-images/mail-stack/dovecot/config/local.conf.tmpl create mode 100755 deploy/base-images/mail-stack/dovecot/entrypoint.sh diff --git a/deploy/base-images/mail-stack/README.md b/deploy/base-images/mail-stack/README.md new file mode 100644 index 0000000..1db5c4b --- /dev/null +++ b/deploy/base-images/mail-stack/README.md @@ -0,0 +1,39 @@ +# Mail Stack – Chasquid + Dovecot + Certbot (Split Containers) + +架构图 +``` + INBOUND EMAIL + ↓ 25 (SMTP) + +-----------+ +INTERNET →→→→→ | chasquid | →→→ outbound relay (optional) + +-----------+ + ↑ 587 (STARTTLS) | 465 (TLS) + | | +CLIENTS -----------------+ + \----→ dovecot →→ IMAP 993 / POP SSL 995 + ↑ + chasquid → dovecot-auth → 用户认证 +``` + +# Mail Stack: Chasquid + Dovecot + Certbot + +This stack provides: + +- SMTP (25) +- Submission (587) +- SMTPS (465) +- IMAPS (993) + +Certbot (TLS) and nginx (ACME validation) use **official images**. + + +Certbot (TLS) and nginx (ACME validation) use **official images**. + +## Start + +docker compose up -d + +## Initialize user: + +docker exec chasquid chasquid-util domain-add svc.plus +docker exec chasquid chasquid-util user-add admin@svc.plus diff --git a/deploy/base-images/mail-stack/chasquid/Dockerfile b/deploy/base-images/mail-stack/chasquid/Dockerfile new file mode 100644 index 0000000..4b61c6a --- /dev/null +++ b/deploy/base-images/mail-stack/chasquid/Dockerfile @@ -0,0 +1,14 @@ +FROM alpine:3.20 + +RUN apk add --no-cache chasquid bash ca-certificates tzdata openssl shadow + +WORKDIR /chasquid + +COPY config/ /etc/chasquid-tmpl/ +COPY entrypoint.sh /entrypoint.sh + +RUN chmod +x /entrypoint.sh + +EXPOSE 25 465 587 + +ENTRYPOINT ["/entrypoint.sh"] diff --git a/deploy/base-images/mail-stack/chasquid/config/chasquid.conf.tmpl b/deploy/base-images/mail-stack/chasquid/config/chasquid.conf.tmpl new file mode 100644 index 0000000..d465328 --- /dev/null +++ b/deploy/base-images/mail-stack/chasquid/config/chasquid.conf.tmpl @@ -0,0 +1,11 @@ +hostname = "{{MAIL_HOSTNAME}}" + +submission_address = ":587" +smtps_address = ":465" + +dovecot_auth = true + +tls { + cert_file = "/etc/chasquid/certs/fullchain.pem" + key_file = "/etc/chasquid/certs/privkey.pem" +} diff --git a/deploy/base-images/mail-stack/chasquid/entrypoint.sh b/deploy/base-images/mail-stack/chasquid/entrypoint.sh new file mode 100755 index 0000000..f468cb2 --- /dev/null +++ b/deploy/base-images/mail-stack/chasquid/entrypoint.sh @@ -0,0 +1,22 @@ +#!/bin/bash +set -e + +MAIL_HOSTNAME=${MAIL_HOSTNAME:-smtp.svc.plus} +CERT_DIR="/etc/letsencrypt/live/$MAIL_HOSTNAME" +CERT_DST="/etc/chasquid/certs" + +mkdir -p $CERT_DST + +while [[ ! -f "$CERT_DIR/fullchain.pem" ]]; do + echo "[chasquid] Waiting for TLS cert..." + sleep 3 +done + +ln -sf $CERT_DIR/fullchain.pem $CERT_DST/fullchain.pem +ln -sf $CERT_DIR/privkey.pem $CERT_DST/privkey.pem +chmod 640 $CERT_DST/* || true + +envsubst < /etc/chasquid-tmpl/chasquid.conf.tmpl > /etc/chasquid/chasquid.conf + +echo "[chasquid] Starting..." +exec chasquid diff --git a/deploy/base-images/mail-stack/docker-compose.yaml b/deploy/base-images/mail-stack/docker-compose.yaml new file mode 100644 index 0000000..856dbf2 --- /dev/null +++ b/deploy/base-images/mail-stack/docker-compose.yaml @@ -0,0 +1,50 @@ +version: "3.9" + +services: + + nginx: + image: nginx:alpine + volumes: + - ./certbot/www:/var/www/certbot + - letsencrypt:/etc/letsencrypt + - ./nginx-default.conf:/etc/nginx/conf.d/default.conf + ports: + - "80:80" + restart: unless-stopped + + certbot: + image: certbot/certbot:latest + command: certonly --webroot -w /var/www/certbot \ + -d smtp.svc.plus \ + --non-interactive --agree-tos \ + -m admin@svc.plus + volumes: + - ./certbot/www:/var/www/certbot + - letsencrypt:/etc/letsencrypt + depends_on: + - nginx + + chasquid: + build: ./chasquid + environment: + MAIL_HOSTNAME: smtp.svc.plus + volumes: + - letsencrypt:/etc/letsencrypt + ports: + - "25:25" + - "465:465" + - "587:587" + restart: unless-stopped + + dovecot: + build: ./dovecot + environment: + MAIL_HOSTNAME: smtp.svc.plus + volumes: + - letsencrypt:/etc/letsencrypt + ports: + - "993:993" + restart: unless-stopped + +volumes: + letsencrypt: diff --git a/deploy/base-images/mail-stack/dovecot/Dockerfile b/deploy/base-images/mail-stack/dovecot/Dockerfile new file mode 100644 index 0000000..a7031f4 --- /dev/null +++ b/deploy/base-images/mail-stack/dovecot/Dockerfile @@ -0,0 +1,16 @@ +FROM alpine:3.20 + +RUN apk add --no-cache \ + dovecot dovecot-lmtpd dovecot-pigeonhole-plugin \ + bash ca-certificates tzdata openssl + +WORKDIR /dovecot + +COPY config/ /etc/dovecot-tmpl/ +COPY entrypoint.sh /entrypoint.sh + +RUN chmod +x /entrypoint.sh + +EXPOSE 993 + +ENTRYPOINT ["/entrypoint.sh"] diff --git a/deploy/base-images/mail-stack/dovecot/config/10-master.conf.tmpl b/deploy/base-images/mail-stack/dovecot/config/10-master.conf.tmpl new file mode 100644 index 0000000..9ded90a --- /dev/null +++ b/deploy/base-images/mail-stack/dovecot/config/10-master.conf.tmpl @@ -0,0 +1,3 @@ +protocol imap { + mail_plugins = $mail_plugins +} diff --git a/deploy/base-images/mail-stack/dovecot/config/dovecot.conf.tmpl b/deploy/base-images/mail-stack/dovecot/config/dovecot.conf.tmpl new file mode 100644 index 0000000..4f6c660 --- /dev/null +++ b/deploy/base-images/mail-stack/dovecot/config/dovecot.conf.tmpl @@ -0,0 +1,8 @@ +protocols = imap pop3 +ssl = required + +ssl_cert = /etc/dovecot/dovecot.conf +envsubst < /etc/dovecot-tmpl/local.conf.tmpl > /etc/dovecot/local.conf +envsubst < /etc/dovecot-tmpl/10-master.conf.tmpl > /etc/dovecot/conf.d/10-master.conf + +echo "[dovecot] Starting..." +exec dovecot -F