一、部署方式
1、手动安装
git拉取项目
$ git clone https://github.com/zone-eu/wildduck.git
$ cd wildduck
安装依赖
从 npm 安装依赖项
$ npm install --production
要使用默认配置文件,请运行以下命令:
node server.js
或者,如果您想用自己的配置选项覆盖默认配置选项,请运行以下命令(自定义配置文件将与默认配置文件合并,因此请仅指定您要更改的值):
node server.js --config=/etc/wildduck.toml
调用API创建用户,发送邮件,api接口如下
https://docs.wildduck.email/docs/category/wildduck-api
2、docker镜像安装
使用docker拉取镜像
docker pull ghcr.io/zone-eu/wildduck
运行
该镜像配置为使用默认配置文件
docker run ghcr.io/zone-eu/wildduck
由于容器内部缺少mongodb某些配置项,此操作很可能会失败。要将自定义配置选项/文件传递给 Docker 镜像中的 WildDuck,可以使用以下两种策略:redislocalhost
1)使用wild-config传递APPCONF_*环境变量以配置选项
要设置自定义mongo主机redis,并配置FQDN用于接收电子邮件的域名:
FQDN='example.com'
MAIL_DOMAIN='mail.example.com'
docker run \
-e APPCONF_dbs_mongo='mongodb://mongo:27017/' \
-e APPCONF_dbs_redis='redis://redis:6379/3' \
-e APPCONF_smtp_setup_hostname=$FQDN \
-e APPCONF_log_gelf_hostname=$FQDN \
-e APPCONF_imap_setup_hostname=$FQDN \
-e APPCONF_emailDomain=$MAIL_DOMAIN \
ghcr.io/zone-eu/wildduck
2)使用自定义配置文件挂载 Docker 卷:
/wildduck/config要替换Docker 镜像中的默认配置文件夹( )。
docker run -v '/config/from/host:/wildduck/config' ghcr.io/zone-eu/wildduck
3、git拉取wildduck-docker版,docker内网部署
基于前面踩坑,内网缺少应该DNS解析,所以我们要先安装应该解析工具 dnsmasq
前置工具安装
安装 dnsmasq
sudo apt update
sudo apt install -y dnsmasq
配一份本地域解析(把 IP 换成你的 VM IP)
sudo tee /etc/dnsmasq.d/wildduck.conf >/dev/null <<'EOF'
address=/test.mail.com/192.168.77.78
host-record=mail.test.mail.com,192.168.77.78
mx-host=test.mail.com,mail.test.mail.com,10
EOF
sudo systemctl restart dnsmasq
让 ZoneMTA 容器使用这个 DNS
最简单是在 doker-compose.yml 里给 zonemta 服务加:
dns:
- 192.168.77.78
然后重建:
sudo docker compose up -d --force-recreate
这样 test.mail.com(自己定义的) 的 MX 就能被查到,ZoneMTA 才能把邮件投递回你本机的 Haraka/WildDuck,Bob(用户) 的 INBOX 才会出现邮件。
内网部署访问的架构
Windows(宿主机)
└── Apifox
|
| HTTP (REST API)
v
VM 虚拟机(Linux)
├── WildDuck API : 3000
├── WildDuck SMTP : 587
├── MongoDB
├── Redis
└── Haraka (SMTP)
项目部署
1)项目拉取
git clone https://github.com/nodemailer/wildduck-dockerized/tree/master
cd wildduck-dockerized
运行./setup.sh
会让你设置主机名和邮箱域名
2)镜像拉取
我VM上网络不好,每次拉取不了,我才用的策略是,把项目所需要的docker镜像列出来,放到txt文件中
然后我再到windows的powershell中是docker pull命令拉取,再打包tar文件夹,再通过VM共享文件夹传到VM中,再使用docker解压运行
(这个过程是我让GPT帮我写命令的)
traefik:3.3.4
redis:alpine
ghcr.io/zone-eu/haraka-plugin-wildduck:5.8.22
mongo
ghcr.io/zone-eu/wildduck:1.45.5
ghcr.io/zone-eu/zonemta-wildduck:1.32.20
nodemailer/wildduck-webmail:latest
nodemailer/rspamd
3)运行
镜像拉取后就可以运行了
docker-compose up -d
这个时候遇到了的一个问题,在 docker-compose 里要把宿主机上的
/opt/wildduck/wildduck-dockerized/config/rspamd/worker-normal.conf
挂载成容器里的一个文件 /etc/rspamd/worker-normal.conf
但 Docker 发现宿主机的这个路径现在不是文件(很可能被创建成了目录),于是报:not a directory / 目录挂文件 类型不匹配。
config/rspamd/worker-normal.conf这个目录是开始不存在的,是docker自己创建的,所以用不了,在我们项目中实际上对应的是default-config
Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: error mounting "/opt/wildduck/wildduck-dockerized/config/rspamd/worker-normal.conf" to rootfs at "/etc/rspamd/worker-normal.conf": mount src=/opt/wildduck/wildduck-dockerized/config/rspamd/worker-normal.conf, dst=/etc/rspamd/worker-normal.conf, dstFd=/proc/thread-self/fd/11, flags=MS_BIND|MS_REC: not a directory: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type
所以我们只需要把default-config下面的目录复制到config下即可
cd /opt/wildduck/wildduck-dockerized
docker-compose down 停止容器
sudo rm -rf config 删除
mkdir -p config 创建
cp -a default-config/* config/ 复制
然后确认目标文件已经是"普通文件":
ls -l config/rspamd/worker-normal.conf
然后我们继续运行容器docker-compose up -d,继续报错
Error response from daemon: failed to set up container networking: driver failed programming external connectivity on endpoint wildduck-dockerized-traefik-1 (ffd7d0691d26d3525ed504b6cba5b7a08436fed122b129ba80dfe772fccd8163): Bind for 0.0.0.0:80 failed: port is already allocated
这个报错是因为我之前也部署过应该邮件系统,它的docker镜像一直在运行,所以它把邮件和网址访问所需要的端口都占用了,比如80,8080,3000,所以我们只需要把他停止就行了
还有一个坑,就是WildDuck 的 API 并不在 3000,而是在 8080,而此时8080被占用了,所以我们需要在docker-compose.yml中配置
在 docker-compose.yml 里把 wildduck 的端口发布改成:
ports:
- "18080:8080"
重启
sudo docker compose restart wildduck
4)创建账号
ok到这里说明你已经越过重重障碍和bug,现在我们只需要用apifox调用api创建账号
我们之前在setup中填写的域名是test.mail.com(实际上内网注册好像随便填的)
创建账号需要root权限的key,怎么找看下面
cd /opt/wildduck/wildduck-dockerized
sudo grep -RniE "accessToken" config dynamic_conf default-config 2>/dev/null | head -n 50
这样就可以找到X-Access-Token了,我们创建账号都需要在head中带上它
创建 alice
curl -sS -X POST "http://192.168.77.78:18080/users" \
-H "Content-Type: application/json" \
-H "X-Access-Token: ROOT_TOKEN" \
-d '{"username":"alice","password":"123456","address":"alice@test.local"}'
创建 bob
curl -sS -X POST "http://192.168.77.78:18080/users" \
-H "Content-Type: application/json" \
-H "X-Access-Token: ROOT_TOKEN" \
-d '{"username":"bob","password":"123456","address":"bob@test.local"}'
申请用户的X-Access-Token
POST http://192.168.77.78:18080/authenticate
{
"username": "alice@test.mail.com",
"password": "123456",
"token": true,
"scope": "master"
}
response
{
"success": true,
"id": "...",
"username": "bob",
"address": "bob@test.mail.com",
"scope": "master",
"token": "xxxxxxxxxxxx"
...
}
这些用户id,token都要记录,因为后续发收邮件都需要用到,可以在Apifox配置环境变量
5)发送邮件
alice 发给 bob
POST /users/{aliceId}/submit
Header:
X-Access-Token: <aliceToken>
Body:
{
"to": [{ "address": "bob@test.mail.com" }],
"subject": "hi",
"text": "alice -> bob"
}
6)查看邮件
bob 读 INBOX
GET /users/{bobId}/mailboxes(找 \Inbox 的Id)
GET /users/{bobId}/mailboxes/{inboxId}/messages(找messageId)
GET /users/{bobId}/mailboxes/{inboxId}/messages/{messageId}
每个请求 Header:
X-Access-Token: