实战 -- 使用docker镜像快速实现全功能邮件系统的升级迁移

公司要把相关所有的业务迁移到云主机上。当然,邮件服务器也是迁移的对象之一。这个邮件服务器主机作用是客服及业务部门收发对外公布的邮件。量不是很大,但功能要求完整。之前的邮件系统还是2010年搭的,用的是postfix + extmail,这次迁移到云主机上,当然想到了使用现有的docker镜像。因为使用docker ,只要应用配置和数据做合理的分离,就可以有很好的便携性,所有云主机,只要支持docker ,随便迁,可以在分钟及实现业务在各云主机厂商之间迁移。这次mail系统的升级迁移使用了 hardware/mailserver镜像,作者还在做不断的更新,功能做得很全面,文档也写得非常好,捐赠链接给的是bitcoin address(捐不起),不过就是他了。

首先来谈谈用现有docker镜像来搭建应用的好处

  1. 现有docker mail镜像使用人数多
    我使用了hardware/mailserver这个docker mail镜像,在github上的star数是408,有这么多技术人员使用,相关配置问题、安全问题都可能已经被发现并解决了。

  2. 现有的docker mail 镜像功能全面
    镜像包括了如下功能 ,正如作者所说,是一个全功能邮件服务器

  3. 安装配置简单
    作者已经帮我们几乎完成的所有的配置工作,只要跟据自己的需求,稍作修改就可以完成整个 full-featured mail server 的搭建工作。几步就可以完成。

  4. 轻量
    整个mailserver 需要的配置仅仅为如下(当然,做为企业服务器,我们会根据需求,把配置拉高:

  5. 配置、数据与docker mail镜像实现了很好的分离,方便迁移
    可以轻松的做到你的配置及数据是与docker mail 镜像是分离的,也就是说,只有备份一个 docker-compose.yml 文件及/run/docker/目录 ,就可以轻松实现mailserver 在云主机上的迁移。

再来说说服务器的硬件配置

我的服务器配置如下:
服务器:Ucloud 云主机
配置: 4Core , 16G, 300G SSD
系统: Ubuntu 16.04_LTS

再来说说docker mail 镜像安装配置

hardware/mailserver 镜像github链接:
下面的内容都是根据上面链接中的readme.md文件内容整理翻译过来,具体操作可能是以我自己的安装实践为基础。

  • 在Ubuntu16.04LTS上安装docker

    1
    2
    3
    4
    5
    6
    7
    #!/bin/bash
    apt-get update
    apt-get install -y apt-transport-https ca-certificates
    apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D
    echo "deb https://apt.dockerproject.org/repo ubuntu-xenial main" > /etc/apt/sources.list.d/docker.list
    apt-get update
    apt-get install -y docker-engine
  • 确认下面的端口在服务器上没有被占用,如有占用,请把相应的服务停掉并删除掉:

  • 增加相应的DNS记录

    1. 增加mailserver的 A记录(以xxx.com为例,xxx.com是你的域名):
      mx IN 100 A xxx.xxx.xxx.xxx
    2. 把 xxx.com的 mx 记录指向mx.xxx.com
      @ IN 100 MX 10 mx.xxx.com.
    3. 增加 SPF DKIM 记录(推荐),我只加了spf记录:
      @ IN 100 TXT “v=spf1 a mx -all”
      上面是增加了一个spf的txtDNS记录,意思是只有在xxx.com中有A记录及mx记录的服务器IP都是全法的邮件服务器IP。
    4. 设置postfixadmin/webmail/spam 三个域名(在同一台机器上,下文会说明这三个域名的作用)
      postfixadmin IN 100 CNAME mx.xxx.com.
      webmail IN 100 CNAME mx.xxx.com.
      spam IN 100 CNAME mx.xxx.com.
  • 下载 docker-compose.sample.yml

    1
    wget https://github.com/hardware/mailserver/blob/master/docker-compose.sample.yml
  • 配置 docker-compose.yml
    把上面的wget 下来的文件mv 为 docker-compose.yml
    相关主机的配置都在这个文件中,你可以通过这个配置,完成大部份的配置,

  1. mailserver镜像的配置:
  2. postfixadmin镜像的配置,postfixadmin 是一个用来管理虚拟域和虚拟用户的php web前台
  3. rainloop镜像的配置,rainloop是一个webmail,或都说是一个WEB版的MUA,后面可以接你自己的SMTP服务器,还可以接其它的SMTP服务器。好象也是用php写的,界面清爽,功能全面,非常好用(这里只是介绍一下,不用改什么)。
  4. nginx 配置,不用改什么,但后面要用docker exec命令进行配置站点及copy https证书。
  5. mariadb 镜像的配置:
    更改相应的root及postfix用户的密码,数据库名可以是postfix
  6. 一个注意点:
    大家看到,所有的镜像都会mount一个volumes到本地磁盘的/mnt/docker分区的一个目录中,这个就是相关独立的配置及数据目录 ,建议把/mnt或是/mnt/docker放到一个独立的磁盘分区上,这就是你所有mailserver的独立配置及数据。它与docker 镜像是可以分离的,这样就可以非常方便的实现这多个docker镜像的的迁移操作,都不用去分别备份这些docker 镜像,只要备份/mnt/docker目录和docker-compose.yml文件就可以了。我是这么操作的:
    1
    2
    3
    4
    5
    #默认系统上的/mnt是不用的
    rm /mnt
    #/data是服务器上一个独立的磁盘分区,300G SSD
    ln -s /data /mnt
    #这样,数据其实就都在/data/docker目录下了
  • 用docker-compose及上面的docker-compose.yml文件,把这个镜像组给下载并启动起来:
  1. 先安装docker-compose来下载并启动这个镜像组[docker-compose是一个python工具来定义和运行多个容器](https://docs.docker.com/compose/):

    1
    2
    3
    4
    5
    #我使用pip3来安装docker-compose
    apt-get install python3-pip
    pip3 install --upgrade pip
    pip3 install -U docker-compose
    #安装完后,我的docker-compose版本是 1.17.1,上面说过了,如果版本过低,就运行不了上面的docker-compose.yml文件
  2. 下载并启动镜像组:

    1
    2
    3
    4
    5
    6
    #下载的时间会比较长,建议用tmux开个虚拟终端
    tmux
    docker-compose up -d
    #可能是几个小时后,不用一直开着电脑连着服务器
    tmux attach
    #查看镜像组下载是否完成,是否已经启动

如果docker 镜像组已经成功启动,说明你已经成功了一大半了。下面是启动的各个镜像名。

  • 在nginx镜像上设置反向代理
  1. 设置postfixadmin的nginx反向代理:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    docker exec -ti nginx ngxproxy

    Welcome to ngxproxy utility.
    We're about to create a new virtual host (AKA server block).

    Name: postfixadmin
    Domain: postfixadmin.xxx.com
    Webroot (default is /):
    Container: postfixadmin
    Port (default is 80): 8888
    #请确保在/mnt/docker/nginx/certs目录下,有你的证书和私钥,可以自己生成一个,也可以用aliyun或godaddy上申请的证书。cert.pem是证书文件,privkey.pem是你的私钥文件。如果没有,可以选择n,不影响使用,只是无法用https访问,只能用http访问,仅此而以。
    HTTPS [y/n]: y
    Certificate path: /certs/cert.pem
    Certificate key path: /certs/privkey.pem
    Secure headers [y/n]: y
    Enable HSTS header ? [y/n]: n # Use with caution
    Max body size in MB (integer/null): null

    Done! postfixadmin.conf has been generated.
    Reload nginx now? [y/n]: y
    nginx successfully reloaded.
  2. 生成 rainloop 的nginx反向代理配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    docker exec -ti nginx ngxproxy

    Welcome to ngxproxy utility.
    We're about to create a new virtual host (AKA server block).

    Name: rainloop
    Domain: webmail.xxx.com
    Webroot (default is /):
    Container: rainloop
    Port (default is 80): 8888
    #下面的都一样。我的证书是一个通配符证书,所以xxx.com下的所有子域名都可用,如果不是,可能要换成相应的域名证书文件
    HTTPS [y/n]: y
    Certificate path: /certs/cert.pem
    Certificate key path: /certs/privkey.pem
    Secure headers [y/n]: y
    Enable HSTS header ? [y/n]: n # Use with caution
    Max body size in MB (integer/null): null

    Done! postfixadmin.conf has been generated.
    Reload nginx now? [y/n]: y
    nginx successfully reloaded.
  3. 生成rspamd 的nginx反向代理配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    docker exec -ti nginx ngxproxy

    Welcome to ngxproxy utility.
    We're about to create a new virtual host (AKA server block).

    Name: rspamd
    Domain: spam.xxx.com
    Webroot (default is /):
    Container: mailserver
    Port (default is 80): 11334
    HTTPS [y/n]: y
    Certificate path: /certs/cert.pem
    Certificate key path: /certs/privkey.pem
    Secure headers [y/n]: y
    Enable HSTS header ? [y/n]: n # Use with caution
    Max body size in MB (integer/null): null

    Done! postfixadmin.conf has been generated.
    Reload nginx now? [y/n]: y
    nginx successfully reloaded.
  • 初始化配置 Postfixadmin
  1. 用浏览器访问
    https://postfixadmin.xxx.com/setup.php
    生成密码hash,并在命令行运行如下命令:

    1
    2
    3
    4
    docker exec -ti postfixadmin setup

    > Postfixadmin setup hash : ffdeb741c58db70d060ddb170af4623a:54e0ac9a55d69c5e53d214c7ad7f1e3df40a3caa
    Setup done.
  2. 访问 https://postfixadmin.xxx.com用你的管理员帐号登录,进行虚拟邮件域及邮箱的创建。

  • 初始化配置 rainloop
  1. 用济器访问:
    https://webmail.xxx.com/?admin
  2. 用默认的 admin 12345 登录,在域名–添加域名配置你的对应域名邮件服务器的连接方式。比如xxx.com是配置在mailserver这个docker镜像上的,你就可以这么配置,记得测试一下。如下图:
  3. 在增加域名后,就可以访问https://webmail.xxx.com/用对应域名的帐号比如 wuying@xxx.com登录了。登录后,你就可以象用outlook一样用这个webmail了。效果图如下,是不是很好有啊?
  • rspamd 垃圾邮件前端WEB的访问
    访问https://spam.xxx.com,登录后效果图如下,是不是很赞?

  • 最后,恭喜你,你已经完成了一个全功能邮件服务器的配置。你可以用下面的命令查看相关docker 容器的日志:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    root@appweb02:~# docker logs -f mailserver
    [INFO] No Let's encrypt live directory found
    [INFO] Using /var/mail/ssl/selfsigned/ folder
    [INFO] Creating DKIM keys for domain xxx.com
    [INFO] Override : smtpd_banner = $myhostname ESMTP xxx MailServer
    [INFO] Override : inet_protocols = ipv4
    [INFO] Override : delay_notice_recipient = wuying@xxx.com
    [INFO] Override : delay_warning_time = 2h
    [INFO] Custom Postfix configuration file loaded
    [INFO] MariaDB hostname not found in /etc/hosts
    [INFO] Container IP found, adding a new record in /etc/hosts
    [INFO] Redis hostname not found in /etc/hosts
    [INFO] Container IP found, adding a new record in /etc/hosts
    [INFO] ClamAV is enabled
    [INFO] Fetchmail forwarding is disabled
    [INFO] Automatic GPG encryption is disabled
    [INFO] ManageSieve protocol is enabled
    [INFO] DKIM/ARC signing is enabled
    [INFO] Greylisting policy is enabled
    [INFO] Ratelimiting policy is enabled
    [INFO] POP3 protocol is disabled
    [INFO] Unbound DNS resolver is enabled

更详细的信息,大家可以访问 https://github.com/hardware/mailserver

坚持原创技术分享,您的支持将鼓励我继续创作!