延伸阅读:基于 FRP 的 Mailu 邮件服务器内网穿透部署
基本条件
- 具备至少1G内存的可公网访问的服务器,可通过25端口发送和接受信息(通过telnet可验证);
- 拥有自己的域名,可自行配置dns服务;
- 已安装 docker compose,可访问 GitHub 上的镜像下载服务。
验证端口可访问性方法(首先确认ufw等防火墙开放25端口):
1
2
|
telnet smtp.qq.com 25 # 验证可发送
telnet 1.1.1.1(你的服务器ip) 25 # 验证可接收
|
出现 Connected 代表端口开放。
mailu配置
本教程基于 mailu 2024.06 版本。
配置文件生成
使用官网提供的配置文件生成服务.
其中,关键选项配置为:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
Choose how you wish to handle security TLS certificates:
$$letsencrypt$$
Enable Web email client:
$$roundcube$$
Enable oletools.
IPv4 listen address:
服务器IP
Public hostnames:
你准备设定的邮件服务域名,如`mail.hlmg.tech`
|
设置完成后在服务器新建/mailu文件夹,并在其中下载保存yml与env文件。
配置文件修改
docker-compose.yml
修改front容器,保留25,80,465,993端口的映射,并将80端口的映射修改为本地端口以备后续配置反向代理,添加日志服务,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
front:
image: ${DOCKER_ORG:-ghcr.io/mailu}/${DOCKER_PREFIX:-}nginx:${MAILU_VERSION:-2024.06}
restart: always
env_file: mailu.env
logging:
driver: journald
options:
tag: mailu-front
ports:
- "127.0.0.1:9198:80"
- "服务器ip:25:25"
- "服务器ip:465:465"
- "服务器ip:993:993"
networks:
- default
- webmail
volumes:
- "/mailu/certs:/certs"
- "/mailu/overrides/nginx:/overrides:ro"
depends_on:
- resolver
dns:
- 192.168.203.254
# 下面是额外添加的日志服务,为fail2ban准备
logging:
driver: journald
options:
tag: mailu-front
|
同样的,在admin中添加日志服务:
1
2
3
4
|
logging:
driver: journald
options:
tag: mailu-admin
|
mailu.env
这里给出我认为比较关键的选项:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
###################################
# Mail settings
###################################
# Welcome email, enable and set a topic and body if you wish to send welcome emails to all users.
WELCOME=true
WELCOME_SUBJECT=Welcome to your new hlmg.tech email account
WELCOME_BODY=Welcome to your new mailu on hlmg.tech email account, if you can read this, then it is configured properly!
# Maildir Compression
# choose compression-method, default: none (value: gz, bz2, zstd)
COMPRESSION=zstd
# change compression-level, default: 6 (value: 1-9)
COMPRESSION_LEVEL=6
###################################
# Advanced settings
###################################
# 要求非网页登陆方式仅可通过token登陆,增强安全性,token在网页端的admin->认证令牌界面可配置。
AUTH_REQUIRE_TOKENS=true
LD_PRELOAD=
# /usr/lib/libhardened_malloc.so # 如果你的服务器支持avx2(x86_64)或Ircpc(arm)指令集可开启该项,使用`cat /proc/cpuinfo | grep avx2` 查看,若不支持,必须保持留空
# Timezone for the Mailu containers. See this link for all possible values https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
TZ=Asia/Shanghai
# 配置初始化管理员帐号
INITIAL_ADMIN_ACCOUNT=admin
INITIAL_ADMIN_DOMAIN=hlmg.tech
INITIAL_ADMIN_PW="2Su2aHdX59SXZhCnFDQe"
INITIAL_ADMIN_MODE=ifmissing
|
启动mailu服务
为网页端服务设置反向代理,提供https(使用caddy实现),以下是Caddyfile中的相关部分。
1
2
3
4
|
mail.hlmg.tech {
encode zstd gzip
reverse_proxy localhost:9198
}
|
在 /mailu目录下启动服务,调试时先不加-d以观察日志:
启动服务后,访问设置的邮件服务域名,登陆admin进行进一步配置。
进入管理->邮件域->点如下位置查看dns配置信息,该图右上角的“新域”可以添加新邮件用户:

点击 Download zonefile 下载dns配置文件,删去其中的如下配置:
1
2
3
4
|
_imap._tcp.hlmg.tech. 600 IN SRV 0 0 0 .
_pop3._tcp.hlmg.tech. 600 IN SRV 0 0 0 .
_submission._tcp.hlmg.tech. 600 IN SRV 0 0 0 .
_pop3s._tcp.hlmg.tech. 600 IN SRV 10 1 995 mail.hlmg.tech.
|
进入域名的dns管理页面,以cloudflare为例,在如下位置导入dns配置即可:

导入dns完成后,稍等一段时间即可尝试发送、接收邮件验证基本功能是否正常。
如果有条件,可为服务器设置rDNS,以进一步增强邮件服务器的可信程度。
mailu备份
至此,邮件服务器已可供使用,通过web和imap均可访问,mailu是基于文件的邮件服务器,备份可通过restic+rclone备份整个 /mailu 文件夹完成。
配置fail2ban缓解攻击
在官网fail2ban配置基础上,针对我受到的攻击进行了一些修改:
首先安装fail2ban和ipset,并按照上述docker-compose.yml中的参考添加日志部分:
1
|
apt install fail2ban ipset -y
|
新增配置文件 /etc/fail2ban/filter.d/bad-auth-bots.conf:
1
2
3
4
5
6
7
8
9
10
|
# vim /etc/fail2ban/filter.d/bad-auth-bots.conf
# Fail2Ban configuration file for mailu-front log file
[Definition]
failregex = ^.* mailu-front\[\d+\]: .* Info: Disconnected: Connection closed:.*user=<>, rip=<HOST>,.*$
^.* mailu-front\[\d+\]: .* client login failed: \"AUTH not supported\" while in http auth state, client: <HOST>, server: .*$
^.* mailu-front\[\d+\]: .* SSL_do_handshake\(\) failed \(SSL: error:.*while in starttls state, client: <HOST>.*$
ignoreregex =
journalmatch = CONTAINER_TAG=mailu-front
|
新增配置文件 /etc/fail2ban/jail.d/bad-auth-bots.conf:
1
2
3
4
5
6
7
8
9
10
|
# vim /etc/fail2ban/jail.d/bad-auth-bots.conf
[bad-auth-bots]
enabled = true
backend = systemd
filter = bad-auth-bots
bantime = 604800
findtime = 3600
maxretry = 3
action = docker-action-net
ignoreip = x.x.x.x/24 # 可添加忽略ip
|
新增配置文件 /etc/fail2ban/action.d/docker-action-net.conf:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
# vim /etc/fail2ban/action.d/docker-action-net.conf
[Definition]
actionstart = ipset --create f2b-bad-auth-bots nethash
iptables -I DOCKER-USER -m set --match-set f2b-bad-auth-bots src -p tcp -m tcp --dport 25 -j DROP
iptables -I DOCKER-USER -m set --match-set f2b-bad-auth-bots src -p tcp -m tcp --dport 465 -j DROP
iptables -I DOCKER-USER -m set --match-set f2b-bad-auth-bots src -p tcp -m tcp --dport 993 -j DROP
actionstop = iptables -D DOCKER-USER -m set --match-set f2b-bad-auth-bots src -p tcp -m tcp --dport 25 -j DROP
iptables -D DOCKER-USER -m set --match-set f2b-bad-auth-bots src -p tcp -m tcp --dport 465 -j DROP
iptables -D DOCKER-USER -m set --match-set f2b-bad-auth-bots src -p tcp -m tcp --dport 993 -j DROP
ipset --destroy f2b-bad-auth-bots
actionban = ipset add -exist f2b-bad-auth-bots <ip>/24
actionunban = ipset del -exist f2b-bad-auth-bots <ip>/24
|
新增配置文件 /etc/fail2ban/filter.d/bad-auth.conf:
1
2
3
4
5
6
|
# vim /etc/fail2ban/filter.d/bad-auth.conf
[Definition]
failregex = ^.*: Authentication attempt from <HOST> has been rate-limited\.$
ignoreregex =
journalmatch = CONTAINER_TAG=mailu-admin
|
新增配置文件 /etc/fail2ban/jail.d/bad-auth.conf:
1
2
3
4
5
6
7
8
9
10
|
# vim /etc/fail2ban/jail.d/bad-auth.conf
[bad-auth]
enabled = true
backend = systemd
filter = bad-auth
bantime = 604800
findtime = 3600
maxretry = 3
action = docker-action
|
新增配置文件 /etc/fail2ban/action.d/docker-action.conf:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
# vim /etc/fail2ban/action.d/docker-action.conf
[Definition]
actionstart = ipset --create f2b-bad-auth iphash
iptables -I DOCKER-USER -m set --match-set f2b-bad-auth src -j DROP
actionstop = iptables -D DOCKER-USER -m set --match-set f2b-bad-auth src -j DROP
ipset --destroy f2b-bad-auth
actionban = ipset add -exist f2b-bad-auth <ip>
actionunban = ipset del -exist f2b-bad-auth <ip>
|
修改配置文件使得fail2ban在docker后启动:
1
|
systemctl edit fail2ban
|
在其中修改以下内容:
1
2
|
[Unit]
After=docker.service
|
重启fail2ban服务以应用更改:
1
|
systemctl restart fail2ban
|
查看当前fail2ban状态:
1
2
3
|
fail2ban-client status
fail2ban-client status bad-auth-bots
fail2ban-client status bad-auth
|
参考