[后端]邮件服务器搭建之virtual_users

背景

在上一篇讲到了安装完postfix之后,我们再服务器上有有了收发邮件的能力。 然而因为我们只是做了一点微小的工作,功能并不够强大。只能使用root@example.com这个邮箱来进行收发。因为这时候邮件地址还是和linux服务器上的用户一一对应的。并不能满足笔者的需求。笔者需要的是能够随意使用在本域下的任意邮箱的呀,所以本文就来探究如何在前篇的基础上扩充邮件服务,使之具有承载虚拟用户的能力。

原理分析

postfix只是个MTA服务软件,并不是一个真正的MDA软件。postfix只是简单将收到的邮件发给对应用户组下的邮件目录中,以文件形式存储下来。如果邮箱地址对应的不是一个linux存在的用户,那么邮件就会被退回。如果需要很多虚拟用户的话,就需要另寻他路了,这里我们用dovecot来充当MDA的角色,来进行对虚拟用户的操纵,并投递到相应虚拟用户的目录中。而虚拟用户的账号、别称数据需要mysql来进行存储。既然用mysql来进行存储,就要有账号管理的应用(注意dovecot只是从数据库中读取虚拟用户的数据传递给postfix使用,并不能很方便的创建和管理虚拟用户的数据),这时候我们就可以使用postfixadmin来进行管理了。
因此本文所涉及到的是4个应用
postfix(MTA) 负责邮件的传输
dovecot(MDA) 负责从mysql中读取数据,转发给postfix提供虚拟用户的数据用以路由与验证。
mysql(database) 负责存储用户数据。
postfixadmin 负责账号的创建与管理,只是存储数据库的数据,并不参与到邮件的转发工作中。

操作步骤

  • step1 配置服务器用户
    为了安全起见,我们要新配置一个用户来管理这个邮件的收发,我们叫vmail好了。
$ groupadd -g 5000 vmail   #组号为5000,组名为vamil
$ useradd -u 5000 -g vmail -s /usr/bin/nologin -d /home/vmail -m vmail  #用户号为5000,属于用户组vmail,没有登录shell的权限,主目录为/home/vmail并自动创建,最后这个用户就叫vamil了。
  • step2 使用postfixadmin配置虚拟域名以及虚拟用户
$ apt-get install postfixadmin 

安装完以后,phpadmin就会弹出一个配置向导来给我们进行配置。跟着操作来就好了,一般用默认配置就好了。postfixadmin会在数据库中创建一个名字为postfixadmin的用户,同时创建一个相应的名字为postfixadmin的数据库。接着其就会自己进行配置和初始化了。
可以在安装记录的提示中看到数据库创建的提示和配置文件所在目录

granting access to database postfixadmin for postfixadmin@localhost: success.
Creating config file /etc/dbconfig-common/postfixadmin.conf with new version
Creating config file /etc/postfixadmin/dbconfig.inc.php with new version

这样我们就基本安装好了postfixadmin,接着我们就可以从web的方式在网页上进行配置了。postfixadmin的目web配置文件在/usr/share/postfixadmin/目录下,我们要把其映射web服务器的可访问目录下。如果是用apache那么就自动配置好了,只要访问yourdomain/postfixadmin/index.php就好了,然而笔者用的nginx,所以要自己额外映射一发。我们新开一个端口映射到域名下,那么我们访问https://yourdomain:1234/index.php就可以了
在/etc/nginx/sites-available目录下新建一个yourdomain_1234_postfixadmin

server {
        listen 1234;
        listen [::]:1234;

        server_name yourdomain;

        root /usr/share/postfixadmin;
        index index.html;

        location ~ \.php$ {
            include snippets/fastcgi-php.conf;
            fastcgi_pass unix:/run/php/php7.0-fpm.sock;
        }

        location / {
                try_files $uri $uri/ =404;
        }
}

然后配置一下重启nginx就好了

$ cd /etc/nginx/sites-enabled
$ ln -s ../sites-available/st0rm23.com_3789_postfixadmin
$ nginx -t
$ /etc/init.d/nginx restart

完了以后,访问一下先访问一下https://yourdomain:1234/setup.php,看是否都配置成功。
笔者就悲伤的发现mysql这一块失败了

Error: Can't connect to database
Please edit the $CONF['database_*'] parameters in config.inc.php.

看了一下原因,原来是我使用的是mysqli而不是mysql,然后我在dbconfig.inc.php里面改了一下type类型就就可以正常使用了。

修好以后,又发现初始化数据库的时候执行失败了,找了一下原因,是因为postfixadmin的bug,日期的地方默认值填的是0,然而数据库版本使用的strict模式,就执行失败了(后来postfixadmin修了这个bug,然而笔者做的时候,这个bug修好了只在issue里面,还没有release出来)。于是笔者就手工修改了mysql去掉了严格模式。
在/etc/mysql/conf.d/目录下新建一个disable_strict_mode.cnf文件,输入

[mysqld]
sql_mode=IGNORE_SPACE,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

保存后,使用/etc/init.d/mysql restart重启加载配置就好了。这样重新刷新setup.php文件就可以发现数据库都加载好了。配置好密码后,就愉快地访问你的链接吧https://yourdomain:1234/index.php

  • setup3 使用postadmin的web界面进行配置虚拟用户
    在经过上一步之后,我们就可以从web界面进行配置了,那么登录到https://yourdomain:1234/index.php就可以看到下述界面。

    QQ截图20161126115438.png

    进去之后可以添加域和虚拟用户。先创建一个hello@example.com的账号进行后续使用

  • setup4 配置dovecot以及相应的sasl
    我们如果要接受来自外域的邮件,我们还要配置一个dovecot来管理外部邮件到虚拟用户的映射。注意在前几步中,我们只是添加postfixadmin来管理虚拟用户,然而邮件是外域接受并传递到虚拟用户这个过程并没有被实现。所以我们就需要用dovecot来实现这个过程。

先安装一下dovecot相关的包

$ apt-get install dovecot-common
$ apt-get install dovecot-pop3d
$ apt-get install dovecot-imapd
$ apt-get install dovecot-mysql

然后配置dovecot的配置文件/etc/dovecot/dovecot.conf,注意如果有旧的的dovecot.conf,那么把旧的文件删掉,并不需要旧的那个了

protocols = imap pop3
auth_mechanisms = plain
passdb {
    driver = sql
    args = /etc/dovecot/dovecot-sql.conf
}
userdb {
    driver = sql
    args = /etc/dovecot/dovecot-sql.conf
}

service auth {
    unix_listener /var/spool/postfix/private/auth {
                    group = postfix
                    mode = 0666
                    user = postfix
    }
    user = root
}
mail_home = /home/vmail/%d/%n
mail_location = maildir:~
ssl_cert = </etc/ssl/private/yourca.crt
ssl_key = </etc/ssl/private/yourca.key

接着配置一下/etc/dovecot/dovecot-sql.conf,让dovecot能够访问数据库

driver = mysql
connect = host=localhost dbname=postfixadmin user=postfixadmin password=password
# It is highly recommended to not use deprecated MD5-CRYPT. Read more at http://wiki2.dovecot.org/Authentication/PasswordSchemes
default_pass_scheme = SHA512-CRYPT
# Get the mailbox
user_query = SELECT '/home/vmail/%d/%n' as home, 'maildir:/home/vmail/%d/%n' as mail, 5000 AS uid, 5000 AS gid, concat('dirsize:storage=',  quota) AS quota FROM mailbox WHERE username = '%u' AND active = '1'
# Get the password
password_query = SELECT username as user, password, '/home/vmail/%d/%n' as userdb_home, 'maildir:/home/vmail/%d/%n' as userdb_mail, 5000 as  userdb_uid, 5000 as userdb_gid FROM mailbox WHERE username = '%u' AND active = '1'
# If using client certificates for authentication, comment the above and uncomment the following
#password_query = SELECT null AS password, %u AS user                                                  

注意,这里我用的是private/auth这一套,有些文档使用的是auth-client那一套,然而我并没有成功,总是提示找不到对应的文件。

  • step5 配置postfix,使得postfix通过dovecot来代理邮件到虚拟用户的分发
    配置/etc/postfix/main.cf,在末尾加上
relay_domains = $mydestination
virtual_alias_maps = proxy:mysql:/etc/postfix/virtual_alias_maps.cf #数据库的连接文件,后面要创建的
virtual_mailbox_domains = proxy:mysql:/etc/postfix/virtual_mailbox_domains.cf #数据库的连接文件,后面要创建的
virtual_mailbox_maps = proxy:mysql:/etc/postfix/virtual_mailbox_maps.cf #数据库的连接文件,后面要创建的
virtual_mailbox_base = /home/vmail
virtual_mailbox_limit = 512000000
virtual_minimum_uid = 5000
virtual_transport = virtual
virtual_uid_maps = static:5000  #这里就是之前创建的vmail的uid 5000
virtual_gid_maps = static:5000
local_transport = virtual
local_recipient_maps = $virtual_mailbox_maps
transport_maps = hash:/etc/postfix/transport
smtpd_sasl_auth_enable = yes
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth  #这里要注意,是和上面dovecot配置的时候紧密相关的,通过这个路径才能进行sasl的认证。
smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination
smtpd_relay_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination
smtpd_sasl_security_options = noanonymous
smtpd_sasl_tls_security_options = $smtpd_sasl_security_options
smtpd_tls_security_level = may
smtpd_tls_auth_only = yes
smtpd_tls_received_header = yes
smtpd_tls_cert_file = /etc/ssl/private/www.st0rm23.com.crt
smtpd_tls_key_file = /etc/ssl/private/www.st0rm23.com.key
smtpd_sasl_local_domain = $mydomain
broken_sasl_auth_clients = yes
smtpd_tls_loglevel = 1

同时完成/etc/postfix/virtual_alias_maps.cf、/etc/postfix/virtual_mailbox_domains.cf、/etc/postfix/virtual_mailbox_maps.cf三个文件的数据库配置。
/etc/postfix/virtual_alias_maps.cf

user = postfixadmin
password =  password #你的密码
hosts = localhost
dbname = postfixadmin
table = alias
select_field = goto
where_field = address

/etc/postfix/virtual_mailbox_domains.cf

user = postfixadmin
password =  password #你的密码
hosts = localhost
dbname = postfixadmin
table = domain
select_field = domain
where_field = domain

/etc/postfix/virtual_mailbox_maps.cf

user = postfixadmin
password =  password #你的密码
hosts = localhost
dbname = postfixadmin
table = mailbox
select_field = maildir
where_field = username

这样用/etc/init.d/postfix restart 重启完postfix后就可正式生效了。我们可以用公共的邮箱向在step3中建立的虚拟邮箱hello@example.com用户发一封邮件。就会发现邮件可以成功发送了。

碰到的问题

一路上还是碰到不少问题的,特别是搭建dovecot的时候,由于很陌生,各个文档的说法都不一致碰到过很多问题。这里有一个很有效的调试方法,发一封邮件,然后看/var/log/mail.log下的日志

$ tail /var/log/mail.log -n 20

很明显能够看到失败的原因,这里分享几个错误和解决的方法。

  • postfix/smtpd[19476]: warning: SASL: Connect to /var/run/dovecot/auth-client failed: No such file or directory
    这个我也不知道为什么postfix和dovecot在auth-client的文件上找不到。后来我就改成了private/auth的接入方式(理论上两种方式都可以的,只是两个程序内部的管道数据流罢了)。就是在/etc/dovecot中unix_listener的地方改成/var/spool/postfix/private/auth,同时在/etc/postfix/main.cf的smtpd_sasl_path改成private/auth。重启两个服务就可以了
  • dovecot: auth: Fatal: Unknown database driver 'mysql'
    这个是由于没有安装dovecot-mysql组件的原因,用aptget-install安装一下就好了
  • Temporary lookup failure
    这个导致的原因多种多样,我的原因是因为我在/etc/postfix/main.cf中同时开了virtual_transport和transport_maps。前者是虚拟转发,转发到虚拟用户,而后者是真实地路由到其他的服务器。所以把后者注释掉了,就可正常接收邮件了。否则由于我没有transport.db文件,就会报错收不到邮件。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容