Mailu是一个简单但功能齐全的邮件服务器,通过一套Docker镜像来组织服务。当然它是自由软件。该项目提供了一个易于设置、易于维护和功能齐全的邮件服务器,同时不提供专有软件中经常出现的无关功能。
建议以开发者给出的文档为主要参考,本文仅作为补充。本文安装的版本是1.9稳定版。写下本文时,podman-compose还不能正确解析mailu的docker-compose.yml
文件中的子网设置部分,因此除非后续podman-compose更新解决这一问题,否则不要用podman来替代docker。安装docker的方法此处略过。
配置DNS
访问域名供应商或者DNS服务供应商。向DNS中添加A类记录。a.b.c.d
是服务器的地址。
mail.mydomain.com. IN A a.b.c.d
再添加一条MX类记录,指向服务器mail.mydomain.com
。
mydomain.com. IN MX 10 mail.mydomain.com.
再访问VPS供应商,写入一条rDNS记录。rDNS记录是从IP地址a.b.c.d
到域名mail.mydomain.com
的反向解析,因此需要通过VPS供应商来设置。
配置防火墙
通过SSH连接到服务器后,首先配置防火墙。可以选择安装ufw来间接配置或者直接配置iptables,我觉得ufw更加方便。配置防火墙需要以root身份或使用sudo。
ufw自带了根据应用预设的防火墙配置,需要打开其中的OpenSSH
、Nginx Full
、Mail submission
、SMTP
、POP3
、POP3S
、IMAP
、IMAPS
。注意OpenSSH
一定要打开,否则会和服务器丢失连接,如果修改过SSH的端口,也要记得打开相应端口。除了以上预设配置外,需要额外开启端口465
用于TLS的SMTP通信、端口587
用于STARTLS的SMTP通信,端口5432
用于Mailu从其容器中访问Postgresql。ufw添加规则的方法如下。
添加预设规则(如Mail submission
):
sudo ufw allow "Mail submission"
打开指定端口(如465
)的TCP功能:
sudo ufw allow 465/tcp
添加后使用以下命令查看规则。
sudo ufw status numbered
根据以上命令列出的规则编号删除规则。比如删除11号规则:
sudo ufw delete 11
以上命令删除多个规则时,不能一次填写多个编号。由于删除规则后规则编号会变化,需要重新查看规则编号,修改后再次执行以上命令。
设置好规则后激活生效。
sudo ufw enable
安装和配置Postgresql
为了方便,我也使用docker来安装postgresql数据库管理软件。以下的配置里Postgresql的容器和Mailu的容器运行在同一个服务器上。
使用docker时需要以root身份或使用sudo,本文中的docker相关操作都通过sudo运行。为了方便之后的配置,这里最好使用默认端口号5432。注意替换POSTGRES_PASSWORD=your-password
部分。
sudo docker run -it --name postgresql-default --restart always -e POSTGRES_PASSWORD=your-password -v /srv/postgresql-data:/var/lib/postgresql/data -e POSTGRES_INITDB_ARGS="--data-checksums" -p 5432:5432 postgres
连接到docker中配置数据库
sudo docker exec -it postgresql-default psql -U postgres -d postgres
之后创建mailu用户和相应的数据库。注意替换my_secure_pass
部分。
postgres=# create user mailu;
postgres=# alter user mailu password 'my_secure_pass';
postgres=# create database mailu owner mailu;
postgres=# \c mailu
mailu=# create extension citext;
mailu=# \q
注意记录数据库用户mailu的密码。由于Mailu服务的各个容器位于另一个子网中,为了Mailu能够顺利访问数据库,需要设置Postgresql的访问权限。
在当前目录创建pg_hba.conf
文件,其中的内容类似于:
# TYPE DATABASE USER ADDRESS METHOD
# "local" is for Unix domain socket connections only
local all all trust
# IPv4 local connections:
host all all 127.0.0.1/32 trust
# IPv6 local connections:
host all all ::1/128 trust
# Allow replication connections from localhost, by a user with the
# replication privilege.
local replication all trust
host replication all 127.0.0.1/32 trust
host replication all ::1/128 trust
host mailu mailu 172.17.0.0/16 md5
注意将类似host all all all scram-sha-256
的部分删除,阻止其他远程访问请求。限定除了本机通信外(如127.0.0.1/32
和::1/128
),只有用户mailu
能从Docker的网段172.17.0.0/16
访问数据库mailu
。
然后将配置文件覆盖到Postgresql的容器中并重启数据库。
sudo docker cp ~/pg_hba.conf postgresql-default:/var/lib/postgresql/data/pg_hba.conf
sudo docker restart postgresql-default
为了验证数据库可用,可以尝试在服务器的Shell中尝试连接到数据库。
psql -U mailu -d mailu -h 127.0.0.1
生成Mailu配置文件
Mailu的开发者们提供了一个Web应用来生成配置文件。开发者提供了配置建议,非常方便。需要注意的是 TLS certificates 、Database preferences 和 IPv4 listen address 选项。
由于我打算使用外置的Nginx服务器作为反向代理,因此 TLS certificates 可以选择 mail
或者 mail-letsencrypt
。这两个选项意味着将Web的TLS交给反向代理服务器来处理,Mailu的Web服务只需处理HTTP协议的通信,而IMAP、POP、SMTP的TLS还是由Mailu来处理。选项 mail
意味着使用手动安装的证书,需要在 Mailu storage path 项目里填写的目录下创建 certs
文件夹,并在其中安装证书文件cert.pem
和密钥文件key.pem
。当然也可以在之后生成的mailu.env
文件中通过变量TLS_CERT_FILENAME
和TLS_KEYPAIR_FILENAME
来更改这两个文件的名称。如果选择mail-letsencrypt
,则Mailu服务会自动申请并安装证书。服务器上没有其他占用80和443端口的服务时,可以不使用反向代理,此时这里可以选择letsencrypt
。
如果和我一样使用外置的Postgresql数据库管理软件,则在Database preferences中选择postgresql
并填写上一步里配置的信息即可。注意在数据库的地址栏中要填写数据库的真实地址,不要填写127.0.0.1
。也不要添加端口号,如果在地址里添加了端口号(如1.1.1.1:5432
),会导致后续解析数据库地址时出错,因此之前配置数据库时建议不要更改默认端口。
Mailu的开发者建议在 IPv4 listen address 中填写实际的IPv4地址。注意在此处填写实际IPv4地址时,Nginx的配置需要做针对性修改,在下文中将会说明。
为了方便使用,我选择安装了WebUI(对应选项WebMail
)和管理员后台AdminUI。在WebMail
处可以根据喜好选择两种不同风格的UI。
根据提示填写完所有信息后,点击生成按钮。此时根据跳转后页面中Step1的提示,创建项目文件夹并下载生成的配置文件docker-compose.yml
和mailu.env
。此时先不要按Step3操作。
配置Nginx服务器
由于服务器上会运行各不相同的服务,相应的配置也千差万别,因此本节仅说明配置Nginx作为反向代理时可能出错的地方。如果不想使用反向代理,可以直接跳过这一节。
首先修改之前生成并下载到本地的配置文件docker-compose.yml
。找到# Core services
部分,修改容器中的80
和443
在服务器上对应的端口,比如我改为了8080
和8443
。这样就不会和监听80
和443
端口的Nginx冲突。修改后的ports
前两行如下:
ports:
- "x.x.x.x:8080:80"
- "x.x.x.x:8443:443"
修改mailu.env
文件中的REAL_IP_HEADER
和REAL_IP_FROM
部分。x.x.x.x
替换为服务器真实IPv4地址。
REAL_IP_HEADER=X-Real-IP
REAL_IP_FROM=x.x.x.x
此处给出Nginx配置文件的一种写法,更多的配置模板请参考文档。修改Nginx配置后需要重新加载Nginx服务。
server {
listen 443 ssl http2 reuseport;
server_name mail.yourdomain.com;
charset utf-8;
# ssl
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:40m;
ssl_session_timeout 5m;
ssl_session_tickets off;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
add_header Strict-Transport-Security "max-age=63072000";
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header WL-Proxy-SSL true;
proxy_set_header X-Forwarded-For $remote_addr;
client_max_body_size 64M;
proxy_pass http://a.b.c.d:8080;
}
}
server_name
处需要根据之前的DNS记录填写,ssl_certificate
和ssl_certificate_key
处需要填写SSL证书的路径。如果还没有证书,可以通过acme.sh获取证书。此处略过获取证书的过程。
location
中的proxy_set_header
参照以上例子填写即可。但需要特别注意proxy_pass
后需要填写服务器的真实IPv4地址,而不能填写127.0,0,1
之类的地址,后续遇到502错误时可以重点检查此处的信息是否填写正确。
安装和运行Mailu容器
确认配置文件无误后按照Step3的提示进入项目目录并启动服务。
cd /srv/mailu
sudo docker-compose -p mailu up -d
服务启动后添加管理员用户,以adminuser
为例。
sudo docker-compose -p mailu exec admin flask mailu admin adminuser yourdomain.com PASSWORD
参照Step3的说明,PASSWORD
处的初始密码可以在之后进入管理界面修改。如果在添加用户这一步报错,并提示无法访问Postgresql,需要检查Postgresql的访问设置pg_hba.conf
和防火墙的设置。先关闭Mailu服务。
sudo docker-compose -p mailu down
修改相关设置后重启服务。
sudo docker-compose -p mailu up -d
如果添加用户过程中出现过错误,需要删除Postgresql中的数据库mailu
并按照上文中的方法新建数据库mailu
,否则会遇到Postgresql找不到域(Domain)的错误。
之后可以添加一个普通用户(比如myuser
)来测试收发邮件是否正常。
sudo docker-compose exec admin flask mailu user myuser yourdomain.com 'password123'
用网页访问mail.mydomain.com,登陆后即可测试相关功能。
维护服务器
后续维护和功能设置可以参考文档。