Files
NewSzxcn-Email/deploy/README.md
T
2026-08-03 22:39:51 +08:00

8.3 KiB
Raw Permalink Blame History

NewSzxcn Email Docker 部署说明

一键安装与更新

推荐直接使用仓库根目录的管理脚本:

curl -fsSL https://raw.githubusercontent.com/zxyszx/NewSzxcn-Email/main/install.sh | sudo bash

后续操作:

sudo newszxcn-email update
sudo newszxcn-email status
sudo newszxcn-email logs
sudo newszxcn-email rollback

一键安装会把配置和数据放在 /opt/newszxcn-email,并部署内部 Watchtower 更新服务。该服务不映射公网端口,仅接受带随机令牌的容器内请求;后台“立即更新”也只允许超级管理员执行。

首次安装会依次询问防火墙模式、邮件服务器域名、管理员用户名/密码和 Web 部署方式。自动 Web 模式会把容器绑定到 127.0.0.1:8088,配置宿主机 Nginx,并使用官方 acme.sh 申请和续期证书。自定义管理员密码最少 6 位,留空则生成 12 位密码。

最简单部署:单容器镜像版

服务器上不需要源码构建,只要 docker-compose.yml.env 即可。

cd deploy
cp .env.example .env
# 修改 LANQIN_PUBLIC_HOSTNAME / LANQIN_PUBLIC_BASE_URL / LANQIN_ADMIN_USERNAME / LANQIN_ADMIN_PASSWORD
docker compose pull
docker compose up -d

也可以使用脚本:

cd deploy
bash install.sh

第一次执行会生成 .env 并提示你修改配置;修改完成后再次执行 bash install.sh

默认只启动一个业务容器:

lanqin-email

容器内部包含:

  • Go API
  • Web 静态站点
  • Nginx
  • Postfix
  • Dovecot
  • Rspamd

常用命令:

# 查看日志
docker compose logs -f lanqin-email

# 更新镜像并重启
docker compose pull
docker compose up -d

# 停止
docker compose down

GHCR 镜像权限

默认镜像:

ghcr.io/zxyszx/newszxcn-email:latest
ghcr.io/zxyszx/newszxcn-email-api:latest
ghcr.io/zxyszx/newszxcn-email-web:latest
ghcr.io/zxyszx/newszxcn-email-postfix:latest
ghcr.io/zxyszx/newszxcn-email-dovecot:latest
ghcr.io/zxyszx/newszxcn-email-rspamd:latest

如果拉取时报:

unauthorized

说明 GHCR Package 还是私有,二选一:

  1. 到 GitHub Packages 把镜像改成 Public。
  2. 在服务器登录 GHCR
echo "<github_token>" | docker login ghcr.io -u <github_user> --password-stdin

本地源码构建

如果你是在完整源码仓库里本机构建,使用 build override

cd deploy
cp .env.example .env
docker compose -f docker-compose.yml -f docker-compose.build.yml up -d --build

这样会使用 deploy/all-in-one/Dockerfile 构建单容器镜像。

可选:多容器调试部署

如果需要分别查看 Postfix / Dovecot / Rspamd 日志,可以使用 stack 编排。

拉取镜像版:

cd deploy
docker compose -f docker-compose.stack.yml up -d

源码构建版:

cd deploy
docker compose -f docker-compose.stack.yml -f docker-compose.stack.build.yml up -d --build

DNS

进入 Web 管理后台后,在域名管理中查看每个域名需要配置的:

  • MX
  • SPF TXT
  • DKIM TXT
  • DMARC TXT

配置完成后点击“检测”。

邮件服务边界

  • Postfix 读取 /data/lanqin.db 中的 domainsmailboxesaliases
  • Dovecot 读取同一个 SQLite 数据库进行邮箱认证,并使用 /var/mail/vhosts 作为 Maildir 根目录。
  • 第三方客户端可使用 IMAP SSL 993、POP3 SSL 995、SMTP SSL 465 或 Submission 587
  • Rspamd 通过 milter 接入 Postfix,负责 DKIM 签名和垃圾邮件标记。
  • Rspamd 会周期性从 SQLite 导出域名 DKIM 私钥到容器内 /var/lib/rspamd/dkim
  • Go API 是 Webmail 和管理后台入口;浏览器不直接连接 SMTP/IMAP/POP3。
  • Go API 会读取 LANQIN_MAILDIR_ROOT=/var/mail/vhosts,周期扫描 Maildir,把 Postfix/Dovecot 入站邮件同步成 Webmail 索引。
  • 第三方客户端可通过 LanQin API 提供的 SMTP 465/587 发信;Webmail/API 和第三方客户端的“已发送”都由 API 写入,外发投递进入发送队列并由 API worker relay/retry,客户端后续 IMAP APPEND 到 Sent 会按 Message-ID 去重。
  • 用户可在个人邮箱管理中接入外部 IMAP 账号;默认关闭,可在后台“系统设置 > 外部 IMAP”开启并配置密钥/OAuth。本地存储模式会同步到 LanQin,远端直连模式每次从远端读取。启用前必须配置外部 IMAP 密码加密密钥,默认不允许连接 localhost / 内网 / link-local IMAP 主机。Gmail / Microsoft 365 / Outlook OAuth2 需要在对应控制台配置回调地址:/api/external-imap-oauth/gmail/callback/api/external-imap-oauth/outlook/callback
  • send-as v1 支持本人邮箱、启用的别名转发 source 指向本人邮箱,或数据库表 send_as_grants 中显式授权的地址。

邮件客户端 TLS 证书

Web 站点可以由宿主机 Nginx / 宝塔反代到容器 80,但 SMTP/IMAP/POP3 端口不会使用 Web 反代的证书。 此时可在 .env 调整 Web 端口绑定,避免与宿主机 Nginx 的 80/443 冲突:

LANQIN_HTTP_BIND=127.0.0.1:8088

宿主机 Nginx 再反向代理到 http://127.0.0.1:8088。容器内 Web 服务只监听 HTTP,公网 HTTPS 由宿主机 Nginx 或宝塔终止。 如果第三方客户端连接 993/995 时提示证书是 localhost,说明 Dovecot 仍在使用容器自带的测试证书。LanQin API 的 SMTP 465/587 submission 不会使用自签测试证书;启用前必须配置可读的真实证书。

生产环境请把域名证书挂载进容器,并在 .env 指向证书文件:

LANQIN_TLS_CERT_FILE=/certs/fullchain.pem
LANQIN_TLS_KEY_FILE=/certs/privkey.pem
LANQIN_SUBMISSION_ADDR=:587
LANQIN_SUBMISSION_TLS_ADDR=:465

单容器示例:

services:
  lanqin-email:
    volumes:
      - ./data:/data
      - ./mail:/var/mail/vhosts
      - ./dkim:/var/lib/rspamd/dkim
      - ./certs:/certs:ro

证书域名必须覆盖 LANQIN_PUBLIC_HOSTNAME。更新后执行:

docker compose up -d --force-recreate

SMTP 发信排查

单容器部署时,Webmail 发信默认提交给同容器内的 Postfix:

LANQIN_SMTP_HOST=127.0.0.1
LANQIN_SMTP_PORT=25
LANQIN_SMTP_REQUIRE_TLS=false

如需把上游服务商或 DSN 处理器的最终送达、退信、投诉、拒收事件写回开放 API,请设置:

LANQIN_DELIVERY_WEBHOOK_SECRET=replace-with-a-long-random-secret

回调地址、签名算法和事件格式见仓库中的 docs/API.mddocs/openapi.json。该接口未配置密钥时返回 503

如需把状态变化主动推送到集成方,可额外设置:

LANQIN_STATUS_WEBHOOK_URL=https://integration.example.com/hooks/lanqin
LANQIN_STATUS_WEBHOOK_SECRET=replace-with-another-long-random-secret
LANQIN_STATUS_WEBHOOK_ALLOW_PRIVATE_HOSTS=false

事件先写入 SQLite outbox,再由后台 worker 投递;非 2xx 响应会按退避策略重试,最多 10 次。默认只允许公网 HTTPS,禁止重定向、URL 用户信息和私网/本机目标。只有可信内网或本地测试才应开启 LANQIN_STATUS_WEBHOOK_ALLOW_PRIVATE_HOSTS

Split stack 使用 docker-compose.stack.yml 时,API 容器默认会把 LANQIN_SMTP_HOST 覆盖为 postfix,让 Webmail 和 SMTP 提交都 relay 到 Postfix service。只有改用外部 SMTP 时才需要在 .env 明确填写 LANQIN_STACK_SMTP_HOST / LANQIN_STACK_SMTP_PORT

如果发送队列里出现 relay 失败,通常是 Postfix 会话被中断或外部 SMTP 配置错误。优先检查:

docker compose exec lanqin-email supervisorctl status
docker compose exec lanqin-email postconf -M smtp/inet
# SMTP 提交 465/587 由 LanQin API 提供,不再由 Postfix 监听。
docker compose exec lanqin-email sqlite3 /data/lanqin.db "select key,value from system_settings where key like 'smtp%' order by key;"
docker compose exec lanqin-email sqlite3 /data/lanqin.db "select status,attempt_count,last_error from send_queue order by created_at desc limit 10;"
docker compose logs --tail=200 lanqin-email

确认后台“系统设置”里没有把本机 Postfix 的 SMTP Require TLS 打开;本机 127.0.0.1:25 必须保持 TLS=false。

生产注意

  • 建议在服务器或边缘网关配置 HTTPS。
  • 云厂商通常默认封禁 25 端口,需要单独申请解封。
  • SQLite 适合 V1 单机部署;多节点部署前迁移到 PostgreSQL,并把 Postfix/Dovecot maps 改为 PostgreSQL。