1、配置 MySQL

首先启动 MySQL 服务器,并且修改 MySQL 的 root 用户的密码:

1
2
mysql.server start
/home/mysql/bin/mysqladmin -u root password your_password

运行 /home/mysql/bin/mysql -u root -p,并且在提示符后输入 root 用户的密码,进入 MySQL 客户端,执行以下命令:

1
2
3
4
5
6
# 创建 postfix 数据库
CREATE DATABASE `postfix` DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;
# 创建同名用户,并且设置密码
CREATE USER 'postfix'@'localhost' IDENTIFIED BY 'postfix_user_password';
# 将 postfix 数据库的所有权限都赋予 postfix 用户
GRANT ALL PRIVILEGES ON `postfix`.* TO 'postfix'@'localhost';

2、配置 Apache

2.1、httpd.conf

编辑 /home/httpd/conf/httpd.conf 文件,找到如下配置并且按照你自己的实际情况修改:

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
34
35
# 设置默认字符集为 utf-8
AddDefaultCharset utf-8

# 设置以 vmail:vmail 的身份执行所有的 web 程序
<IfModule !mpm_netware_module>
    User vmail
    Group vmail
</IfModule>

# 服务器管理员电子邮件,在出错页面显示
ServerAdmin you@domain.tld

# 监听 80 端口
ServerName localhost:80

# 设置文档主目录为 /home/www
# 我的习惯是对不同的虚拟主机使用 /home/www/domain 的目录命名习惯
# 具体可见 home/httpd/conf/extra/httpd-vhosts.conf
DocumentRoot "/home/www"

# 设置 /home/www 的默认权限
<Directory "/home/www">
    Options Indexes Includes FollowSymLinks MultiViews
    AllowOverride All
    Order allow,deny
    Allow from all
</Directory>

# 设置默认索引页
<IfModule dir_module>
    DirectoryIndex index.html index.php
</IfModule>

# 加载虚拟主机配置文件
Include conf/extra/httpd-vhosts.conf

2.2、httpd-vhosts.conf

编辑 /home/httpd/conf/httpd.conf 文件,找到如下配置并且按照你自己的实际情况修改。我们在后面配置 Extman/Extmail 的时候同时配置该文件。

说明:如果有域名的 DNS 管理权限,推荐使用不同的域名表示不同服务,这样便于访问和管理,那么就需要配置该文件以支持多域名对应的虚拟主机。如果没有 DNS 管理权限,那么就只能把所有的服务都放在一个目录下,那么就不需要本文件的支持,同时上一节中的 /home/httpd/conf/httpd.conf 文件的 Include conf/extra/httpd-vhosts.conf 也可以注释掉。但是这种情况下,ExtMan 和 ExtMail 的 CGI 设置需要对应的修改。

3、配置 Postfix

3.1、main.cf

编辑 /etc/postfix/main.cf 文件,如下:

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# LOCAL PATHNAME INFORMATION
queue_directory = /home/postfix/spool
command_directory = /home/postfix/sbin
daemon_directory = /home/postfix/libexec
data_directory = /home/postfix/var

# QUEUE AND PROCESS OWNERSHIP
mail_owner = postfix

# INTERNET HOST AND DOMAIN NAMES
myhostname = mail.$mydomain
mydomain = domain.ltd

# SENDING MAIL
myorigin = $mydomain

# RECEIVING MAIL
inet_interfaces = all
mydestination =

# REJECTING MAIL FOR UNKNOWN LOCAL USERS
local_recipient_maps = $alias_maps $virtual_mailbox_maps unix:passwd.byname
unknown_local_recipient_reject_code = 550

# TRUST AND RELAY CONTROL
mynetworks_style = subnet
mynetworks = 202.119.43.0/24, 127.0.0.0/8

# ALIAS DATABASE
alias_maps = mysql:/etc/postfix/mysql_virtual_alias_maps.cf

# DELIVERY TO MAILBOX
home_mailbox = Maildir/
mail_spool_directory = /home/mailbox

# DEBUGGING CONTROL
debug_peer_level = 2
debugger_command =
  PATH=/bin:/usr/bin:/usr/local/bin; export PATH; (echo cont;
  echo where) | gdb $daemon_directory/$process_name $process_id 2>&1
  >$config_directory/$process_name.$process_id.log & sleep 5

# INSTALL-TIME CONFIGURATION INFORMATION
sendmail_path = /home/postfix/sbin/sendmail
newaliases_path = /home/postfix/bin/newaliases
mailq_path = /home/postfix/bin/mailq
setgid_group = postdrop
html_directory = /home/postfix/html
manpage_directory = /home/postfix/man
sample_directory = /etc/postfix
readme_directory = /home/postfix/doc

# VIRTUAL DOMAIN STORAGE
virtual_mailbox_base = /home/mailbox
virtual_mailbox_maps = mysql:/etc/postfix/mysql_virtual_mailbox_maps.cf,
  mysql:/etc/postfix/mysql_virtual_alias_domain_mailbox_maps.cf
virtual_mailbox_domains = mysql:/etc/postfix/mysql_virtual_domains_maps.cf
virtual_alias_domains =
virtual_alias_maps = mysql:/etc/postfix/mysql_virtual_alias_maps.cf,
  mysql:/etc/postfix/mysql_virtual_alias_domain_maps.cf,
virtual_uid_maps = static:2002
virtual_gid_maps = static:202
virtual_transport = maildrop
virtual_minimum_uid = 200
relay_domains = $mydestination
maildrop_destination_recipient_limit = 1
maildrop_destination_concurrency_limit = 1

# QUOTA
message_size_limit = 14336000
virtual_mailbox_limit = 20971520
virtual_create_maildirsize = yes
virtual_mailbox_extended = yes
virtual_mailbox_limit_maps = mysql:/etc/postfix/mysql_virtual_mailbox_limit_maps.cf
virtual_mailbox_limit_override = yes
virtual_maildir_limit_message = Sorry, the user's maildir has overdrawn his diskspace quota, please try again later.
virtual_overquota_bounce = yes

# SASL
smtpd_sasl_path = smtpd
broken_sasl_auth_clients = yes
smtpd_recipient_restrictions =
  permit_sasl_authenticated,
  permit_mynetworks,
  reject_unauth_destination
smtpd_sasl_auth_enable = yes
smtpd_sasl2_auth_enable = yes
smtpd_sasl_local_domain = $myhostname
smtpd_sasl_security_options = noanonymous
smtpd_sasl_application_name = smtpd
smtpd_banner=$myhostname ESMTP "Version not Available"
smtpd_sasl_authenticated_header = yes

# TLS
smtpd_use_tls = yes
smtpd_tls_cert_file = /etc/postfix/postfix.pem
smtpd_tls_key_file = $smtpd_tls_cert_file

# OPTIONAL PART
smtpd_helo_required = yes
disable_vrfy_command = yes
smtpd_data_restrictions = reject_unauth_pipelining
smtpd_etrn_restrictions = reject
show_user_unknown_table_name = no

# AMAVIS
content_filter=smtp-amavis:[127.0.0.1]:10024

3.2、master.cf

编辑 /etc/postfix/master.cf 文件。

找到如下的代码:

1
2
maildrop  unix  -       n       n       -       -       pipe
  flags=DRhu user=vmail argv=/usr/local/bin/maildrop -d ${recipient}

修改为:

1
2
maildrop  unix  -       n       n       -       -       pipe
  flags=DRhu user=vmail argv=/home/courier/maildrop/bin/maildrop -d ${recipient}

在该文件的最后增加如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
smtp-amavis unix -      -       n       -       2  lmtp
    -o lmtp_data_done_timeout=1200
    -o lmtp_send_xforward_command=yes

127.0.0.1:10025 inet n  -       n       -       -  smtpd
    -o content_filter=
    -o local_recipient_maps=
    -o relay_recipient_maps=
    -o smtpd_restriction_classes=
    -o smtpd_client_restrictions=
    -o smtpd_helo_restrictions=
    -o smtpd_sender_restrictions=
    -o smtpd_recipient_restrictions=permit_mynetworks,reject
    -o mynetworks=127.0.0.0/8
    -o strict_rfc821_envelopes=yes
    -o smtpd_error_sleep_time=0
    -o smtpd_soft_error_limit=1001
    -o smtpd_hard_error_limit=1000

3.3、mysql_*.cf

新建如下文件:

/etc/postfix/mysql_virtual_alias_domain_mailbox_maps.cf

1
2
3
4
5
user = postfix
password = password_for_postfix
hosts = localhost
dbname = postfix
query = SELECT maildir FROM mailbox,alias_domain WHERE alias_domain.alias_domain = '%d' and mailbox.username = CONCAT('%u', '@', alias_domain.target_domain) AND mailbox.active = 1 AND alias_domain.active='1'

/etc/postfix/mysql_virtual_alias_domain_maps.cf

1
2
3
4
5
user = postfix
password = password_for_postfix
hosts = localhost
dbname = postfix
query = SELECT goto FROM alias,alias_domain WHERE alias_domain.alias_domain = '%d' and alias.address = CONCAT('%u', '@', alias_domain.target_domain) AND alias.active = 1 AND alias_domain.active='1'

/etc/postfix/mysql_virtual_alias_maps.cf

1
2
3
4
5
6
user = postfix
password = password_for_postfix
hosts = localhost
dbname = postfix
query = SELECT goto FROM alias WHERE address='%s' AND active = '1'
#expansion_limit = 100

/etc/postfix/mysql_virtual_domains_maps.cf

1
2
3
4
5
6
7
8
9
user = postfix
password = password_for_postfix
hosts = localhost
dbname = postfix
query  = SELECT domain FROM domain WHERE domain='%s' AND active = '1'
#query = SELECT domain FROM domain WHERE domain='%s'
#optional query to use when relaying for backup MX
#query = SELECT domain FROM domain WHERE domain='%s' AND backupmx = '0' AND active = '1'
#expansion_limit = 100

/etc/postfix/mysql_virtual_mailbox_maps.cf

1
2
3
4
5
6
user = postfix
password = password_for_postfix
hosts = localhost
dbname = postfix
query = SELECT maildir FROM mailbox WHERE username='%s' AND active = '1'
#expansion_limit = 100

3.4、创建 SSL 证书

1
2
cd /etc/postfix
/usr/local/ssl/bin/openssl req -x509 -newkey rsa:1024 -keyout postfix.pem -out postfix.pem -nodes -days 365

按照提示输入你的组织等信息。

3.5、修改权限

1
2
chmod 640  /etc/postfix/mysql_*
chgrp postfix /etc/postfix/mysql_*

4、配置 CYRUS-SASL

创建并且修改 /home/cyrus-sasl/lib/sasl2/smtpd.conf 文件,内容如下:

1
2
3
4
5
6
pwcheck_method:authdaemond
log_level:3
srp_mda:md5
password_format:crypt
mech_list:PLAIN LOGIN
authdaemond_path: /home/courier/authlib/var/spool/authdaemon/socket

设置属性:

1
2
chown postfix:postfix /home/cyrus-sasl/lib/sasl2/smtpd.conf
chmod 400 /home/cyrus-sasl/lib/sasl2/smtpd.conf

5、配置 Courier Authlib

打开 /home/courier/authlib/etc/authlib/authdaemonrc 文件,修改 27 行:

1
authmodulelist="authuserdb authldap authmysql authcustom authpipe"

为:

1
authmodulelist="authmysql"

修改 /home/courier/authlib/etc/authlib/authmysqlrc

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
34
35
36
37
38
39
# MySQL 服务器地址
MYSQL_SERVER            localhost
# MySQL 用户名
MYSQL_USERNAME          postfix
# MySQL 密码
MYSQL_PASSWORD          password_for_postfix
# 链接 MySQL 用的 sock
MYSQL_SOCKET            /tmp/mysql.sock
# 上面指定了使用 sock 方式,所以端口号不需要指定
# MYSQL_PORT            0
MYSQL_OPT               0
# 数据库名
MYSQL_DATABASE          postfix
# 需要访问的表名
MYSQL_USER_TABLE        mailbox
# 存放加密密码的列名
MYSQL_CRYPT_PWFIELD     password
# 存放密码明文的列名,在这里不需要
# MYSQL_CLEAR_PWFIELD   clear
# 默认域名
DEFAULT_DOMAIN          domain.ltd
# 用户 ID 和用户组 ID
MYSQL_UID_FIELD         2002
MYSQL_GID_FIELD         202
# 存放用户名 (email) 的列名
MYSQL_LOGIN_FIELD       username
# 存放邮箱跟目录的列名,直接指定
MYSQL_HOME_FIELD        '/home/mailbox/'
# 用户姓名列
MYSQL_NAME_FIELD        name
# 存放用户邮箱路径的列名
MYSQL_MAILDIR_FIELD     maildir
# MYSQL_DEFAULTDELIVERY defaultdelivery
# 存放配额的列名
MYSQL_QUOTA_FIELD       quota
# 附加选项列
# MYSQL_AUXOPTIONS_FIELD        CONCAT("disableimap=",  disableimap, ",disablepop3=", disablepop3, ",disablewebmail=", disablewebmail, ",sharedgroup=" ,sharedgroup)
# 附加 WHERE 语句
MYSQL_WHERE_CLAUSE      active='1'

注意:

  1. 确认在这个文件中不能用空格键(包括行尾),只能用 Tab 键。
  2. 确认只使用单引号,比如:’/var/mailbox/’
  3. localhost 不能用单引号。
  4. 确认你的 /etc/hosts 文件中有 localhost 解析。
  5. 编译时如果支持 Ipv6 可能导致错误。
  6. MYSQL_GID_FIELD 和 MYSQL_UID_FIELD 是 maildrop 所用到的用户(在这里是 vmail:vmail)的 UID 和 GID,而不是 MySQL 的。

6、配置 Courier IMAP

修改 /home/courier/imap/etc 目录下的 imapdimapd-sslpop3dpop3d-ssl 四个文件。找到 IMAPDSTARTIMAPDSSLSTARTPOP3DSTARTPOP3DSSLSTART 四行,把 NO 修改为 YES。如下:

1
IMAPDSTART=YES

如果你不需要 SSL 认证,则不需要修改 imapd-sslpop3d-ssl 文件。下面一步可以直接跳过。

创建 IMAP 和 POP3 需要的 SSL 证书:

1
2
3
cd /home/courier/imap/share
/usr/local/ssl/bin/openssl req -x509 -newkey rsa:1024 -keyout pop3d.pem -out pop3d.pem -nodes -days 365
/usr/local/ssl/bin/openssl req -x509 -newkey rsa:1024 -keyout imapd.pem -out imapd.pem -nodes -days 365

按照提示输入你的组织等信息。

7、配置 Courier MailDrop

创建并修改 /etc/maildroprc 文件,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
logfile "/var/log/maildrop.log"

if ( $SIZE < 26144 )
{
    exception {
       xfilter "/usr/bin/spamassassin --prefspath=$HOME/$DEFAULT/.spamassassin/user_prefs "
    }
}

if (/^X-Spam-Flag: *YES/)
{
    exception {
        to "$HOME/$DEFAULT/.Junk/"
    }
}
else
{
    exception {
        to "$HOME/$DEFAULT"
    }
}

创建日志文件并且设置正确的权限:

1
2
3
touch /var/log/maildrop.log
chown vmail:vmail /var/log/maildrop.log
chmod a+r /etc/maildroprc

8、配置 Spamassassin

修改 /etc/mail/spamassassin/local.cf,找到如下行:

1
2
3
4
5
# rewrite_header Subject *****SPAM*****
# report_safe 1
# required_score 5.0
# use_bayes 1
# bayes_auto_learn 1

对应修改成如下:

1
2
3
4
5
rewrite_header Subject *****SPAM*****
report_safe 0
required_score 10.0
use_bayes 1
bayes_auto_learn 1

并且最最后增加如下规则,以适应中国的邮件,减少误报的机会:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
##################################################
##Follow is diables some bad rules for chinese mail
##################################################
score SUBJ_FULL_OF_8BITS 0.0
score BASE64_ENC_TEXT 0.0
score BAYES_99 0.1
score BAYES_90 0.1
score BAYES_80 0.1
score BAYES_70 0.1
score BAYES_60 0.1
score FROM_ILLEGAL_CHARS 0.1
score HEAD_ILLEGAL_CHARS 0.1
score SUBJ_ILLEGAL_CHARS 0.1
score MIME_BASE64_TEXT 0.1
score FAKE_HELO_AOL 0.1
score NO_RDNS_DOTCOM_HELO 0.1
score CHINA_HEADER 0.1

9、配置 Amavisd-new

编辑 /etc/amavisd.conf 文件。找到如下行:

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
$daemon_user  = 'vscan';     # (no default;  customary: vscan or amavis), -u
$daemon_group = 'vscan';     # (no default;  customary: vscan or amavis), -g

$mydomain = 'example.com';   # a convenient default for other settings

# $MYHOME = '/var/amavis';   # a convenient default for other settings, -H

$QUARANTINEDIR = '/var/virusmails';  # -Q

# $db_home   = "$MYHOME/db";      # dir for bdb nanny/cache/snmp databases, -D
# $helpers_home = "$MYHOME/var";  # working directory for SpamAssassin, -S
# $lock_file = "$MYHOME/var/amavisd.lock";  # -L
# $pid_file  = "$MYHOME/var/amavisd.pid";   # -P

# $myhostname = 'host.example.com';  # must be a fully-qualified domain name!

# $final_virus_destiny      = D_DISCARD;
# $final_banned_destiny     = D_BOUNCE;
# $final_spam_destiny       = D_BOUNCE;
# $final_bad_header_destiny = D_PASS;

# ['ClamAV-clamd',
#   \&ask_daemon, ["CONTSCAN {}\n", "/var/run/clamav/clamd"],
#   qr/\bOK$/m, qr/\bFOUND$/m,
#   qr/^.*?: (?!Infected Archive)(.*) FOUND$/m ],

对应修改成如下:

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
$daemon_user  = 'amavis';     # (no default;  customary: vscan or amavis), -u
$daemon_group = 'amavis';     # (no default;  customary: vscan or amavis), -g

$mydomain = 'domain.ltd';   # a convenient default for other settings

$MYHOME = '/home/amavis';   # a convenient default for other settings, -H

$QUARANTINEDIR = '/home/mailbox/virusmails';  # -Q

$db_home   = "$MYHOME/db";      # dir for bdb nanny/cache/snmp databases, -D
$helpers_home = "$MYHOME/var";  # working directory for SpamAssassin, -S
$lock_file = "$MYHOME/var/amavisd.lock";  # -L
$pid_file  = "$MYHOME/var/amavisd.pid";   # -P

$myhostname = 'domain.ltd';  # must be a fully-qualified domain name!

$final_virus_destiny      = D_PASS;
$final_banned_destiny     = D_PASS;
$final_spam_destiny       = D_PASS;
$final_bad_header_destiny = D_PASS;

['ClamAV-clamd',
  \&ask_daemon, ["CONTSCAN {}\n", "/tmp/clamd.socket"],
  qr/\bOK$/m, qr/\bFOUND$/m,
  qr/^.*?: (?!Infected Archive)(.*) FOUND$/m ],

10、配置 Clam AntiVirus

10.1、clamd.conf

修改 /home/clamav/etc/clamd.conf,找到如下行:

1
2
3
4
Example
#LogFile /tmp/clamd.log
#TemporaryDirectory /var/tmp
#DatabaseDirectory /var/lib/clamav

对应修改成如下:

1
2
3
4
#Example
LogFile /tmp/clamd.log
TemporaryDirectory /tmp
DatabaseDirectory /home/clamav/var

10.2、freshclam.conf

修改 /home/clamav/etc/freshclam.conf,找到如下行:

1
2
3
Example
#DatabaseDirectory /var/lib/clamav
#UpdateLogFile /var/log/freshclam.log

对应修改成如下:

1
2
3
# Example
DatabaseDirectory /home/clamav/var
UpdateLogFile /var/log/freshclam.log

10.4、病毒库升级

首先创建日志文件并且升级病毒库:

1
2
3
4
touch /var/log/freshclam.log
chmod 666 /var/log/freshclam.log
chown amavis /var/log/freshclam.log
/home/clamav/bin/freshclam

设置定时更新,执行 crontab -e,增加如下指令:

1
00 08 * * * /home/clamav/bin/freshclam --quiet

表示每天的 08:00 自动升级病毒库。