備註:這篇是修改自三年前的「Mail server on CentOS 6」,加上些新的內容和補充
本文開始~~
一般來說email是由三個部分組成,Mail (Transfer/Delivery/User) Agent,為什麼wiki上說有五種呢?因為MSA和MRA通常是包含在前面三種裡
在伺服端的重點是MTA跟MDA,負責收發跟儲存信的兩個部分,這邊我們用postfix和dovecot來實作
套件
在開始之前,先安裝必須的軟體
dnf install postfix postfix-mysql dnf install dovecot dovecot-mysql dnf install mariadb-server
SSL憑證
由於這個教學會設定成提供加密連線,憑證是必需品
dovecot在安裝後會自動產生一組self-signed cert,放在/etc/pki/dovecot裡面,不過還是建議向CA申請,避免使用者在連線時會出現錯誤
向CA拿到憑證之後,就直接放在/etc/pki/dovecot/certs/裡面,私鑰則是/etc/pki/dovecot/private/
如果CA有中繼憑證(intermediate certificate)的話,只需把中繼憑證以倒敘的方式append在自己的憑證後面即可
最後,檢查憑證跟私鑰的selinux context和存取權限,權限建議是root:root 600
selinux在enforcing的情況下,context如果不是「unconfined_u:object_r:dovecot_cert_t:s0」,會造成dovecot無法啟動的狀況(permission denied)
如果使用Let's encrypt作為CA的話,可以不用搬到/etc/pki/dovecot/裡面,直接指向/etc/letsencrypt底下的憑證即可
MySQL
首先是產生所需的db和table,使用mysql root來執行以下語句
# 產生DB CREATE DATABASE mailserver; # 產生使用者,設定密碼為mailuserpass,並提供mailserver的select權限 GRANT SELECT ON mailserver.* TO 'mailuser'@'127.0.0.1' IDENTIFIED BY 'mailuserpass'; # 更新權限表 FLUSH PRIVILEGES; # 切換DB USE mailserver; # 產生網域表 CREATE TABLE `virtual_domains` ( `id` int(11) NOT NULL auto_increment, `name` varchar(50) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; # 產生使用者表 CREATE TABLE `virtual_users` ( `id` int(11) NOT NULL auto_increment, `domain_id` int(11) NOT NULL, `password` varchar(106) NOT NULL, `email` varchar(100) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `email` (`email`), FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; # 產生別名表 CREATE TABLE `virtual_aliases` ( `id` int(11) NOT NULL auto_increment, `domain_id` int(11) NOT NULL, `source` varchar(100) NOT NULL, `destination` varchar(100) NOT NULL, PRIMARY KEY (`id`), FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; # 新增網域 INSERT INTO `virtual_domains` (`name`) VALUES ('example.com'); # 新增使用者 # domain_id就是網域表中example.com的id # firstpassword是[email protected]的密碼 # 亂數可以用`base64 --wrap=0 /dev/urandom`來產生 INSERT INTO `virtual_users` (`domain_id`, `password` , `email`) VALUES ('1', ENCRYPT('firstpassword', CONCAT('$6$', '這邊用亂數做salt')), '[email protected]'), ('1', ENCRYPT('secondpassword', CONCAT('$6$', '這邊用亂數做salt')), '[email protected]'); # 新增別名 # domain_id就是網域表中example.com的id INSERT INTO `virtual_aliases` (`domain_id`, `source`, `destination`) VALUES ('1', '[email protected]', '[email protected]'), ('1', '[email protected]', '[email protected]');
到這邊就新增完成了,記得先用select看一下DB的內容是否正確
Postfix
首先到/etc/postfix/main.cf去看看
# /etc/postfix/main.cf ### 基本設定 ### # 這台mail server對外的名字 myhostname = mail.example.com # localhost的網域,預設是把myhostname減掉第一組主機名 mydomain = example.com # 從localhost寄信的時候,要附上的網域 myorigin = $mydomain # localhost收信的網域,不要和mysql裡的一樣,mysql裡面寫的是virtual domain mydestination = $myhostname, localhost.$mydomain, localhost # 監聽所有介面 inet_interfaces = all # 信任的區域網路只有自己,如果有LAN要信任就改成subnet mynetworks_style = host
基本設定主要是和本機(localhost)有關,我們的信箱會使用虛擬網域來收發信
在這之前,先把驗證和加密的功能設定好
# /etc/postfix/main.cf ### TLS ### # 憑證和私鑰 smtpd_tls_cert_file=/etc/pki/dovecot/certs/mailer.crt smtpd_tls_key_file=/etc/pki/dovecot/private/mailer.key # 啟用TLS,但為了相容性只有驗證時強制加密 smtpd_tls_auth_only = yes smtpd_tls_security_level = may smtp_tls_security_level = may # 不要用DH來做key exchange smtpd_tls_exclude_ciphers = kEDH ### SMTP auth ### # 使用dovecot做SASL(Simple Authentication and Security Layer)驗證 smtpd_sasl_type = dovecot # dovecot驗證用的socket,/var/spool/postfix/的相對位置 smtpd_sasl_path = private/auth # 啟用SASL驗證 smtpd_sasl_auth_enable = yes # 允許通過SASL驗證和信任網路的來源,並拒絕其他不是寄到本機的信,然後對client檢查RBL smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_non_fqdn_hostname, reject_non_fqdn_sender, reject_non_fqdn_recipient, reject_unauth_destination, reject_unauth_pipelining, reject_invalid_hostname, reject_rbl_client bl.spamcop.net, reject_rbl_client b.barracudacentral.org, reject_rbl_client cbl.abuseat.org, reject_rbl_client dnsbl.sorbs.net, reject_rbl_client zen.spamhaus.org # 使用者帳號和網域的對應表(檔案稍後加入) smtpd_sender_login_maps = mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf # 拒絕非法網域和與使用者帳號不合的網域 smtpd_sender_restrictions = reject_unknown_sender_domain, reject_sender_login_mismatch
再來是設定虛擬信箱
# /etc/postfix/main.cf ### incoming email handling ### # 將寄來的信以lmtp協定轉給dovecot儲存 virtual_transport = lmtp:unix:private/dovecot-lmtp ### Virtual mailbox ### # 定義要進行virtual_transport的網域和信箱 virtual_mailbox_domains = mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf virtual_mailbox_maps = mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf virtual_alias_maps = mysql:/etc/postfix/mysql-virtual-alias-maps.cf
馬上就來新增剛剛寫的mysql檔案,總共有三個
# /etc/postfix/mysql-virtual-mailbox-domains.cf user = mailuser password = mailuserpass hosts = 127.0.0.1 dbname = mailserver query = SELECT `name` FROM virtual_domains WHERE name='%s'
# /etc/postfix/mysql-virtual-mailbox-maps.cf user = mailuser password = mailuserpass hosts = 127.0.0.1 dbname = mailserver query = SELECT `email` FROM virtual_users WHERE email='%s'
# /etc/postfix/mysql-virtual-alias-maps.cf user = mailuser password = mailuserpass hosts = 127.0.0.1 dbname = mailserver query = SELECT `destination` FROM virtual_aliases WHERE source='%s'
存好之後使用chmod修改存取權限為600以免DB密碼被看到
然後使用以下指令來驗證上述三個檔案是不是正確設定
postmap -q example.com mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf postmap -q [email protected] mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf postmap -q [email protected] mysql:/etc/postfix/mysql-virtual-alias-maps.cf
如果設定正確,應該會看到網域或是信箱,什麼都沒有代表失敗,就要檢查設定或是資料庫是否有問題
最後修改/etc/postfix/master.cf,開放465和587的port
# /etc/postfix/master.cf # 將以下兩行註解拿掉即可 submission inet n - n - - smtpd smtps inet n - n - - smtpd
Postfix到這邊就完成了,記得要替防火牆開port 25, 465, 587,然後重開postfix服務
Dovecot
dovecot的主要設定都在conf.d裡,我們逐步來修改
# /etc/dovecot/conf.d/10-mail.conf # 修改以下兩行 mail_location = maildir:/var/mail/vhosts/%d/%n mail_privileged_group = mail
來弄資料夾的部分
#!/bin/bash # 新增email資料夾 mkdir -p /var/mail/vhosts/example.com # 新增使用者 groupadd -g 5000 vmail useradd -g vmail -u 5000 vmail -d /var/mail -s /sbin/nologin # 調整email資料夾權限 chown -R vmail:vmail /var/mail/vhosts # 調整dovecot資料夾權限 chown -R vmail:dovecot /etc/dovecot chmod -R o-rwx /etc/dovecot
過來是驗證的部分
# /etc/dovecot/conf.d/10-auth.conf # 先修改底下兩個驗證參數 disable_plaintext_auth = yes auth_mechanisms = plain login ### 檔案最底下有這一排,把auth-sql以外的都註解掉 #!include auth-system.conf.ext !include auth-sql.conf.ext #!include auth-ldap.conf.ext #!include auth-passwdfile.conf.ext #!include auth-checkpassword.conf.ext #!include auth-vpopmail.conf.ext #!include auth-static.conf.ext
來到剛剛引入的auth-sql.conf.ext
# /etc/dovecot/conf.d/auth-sql.conf.ext # args那個檔案下一步驟會做 passdb { driver = sql args = /etc/dovecot/dovecot-sql.conf.ext } userdb { driver = static args = uid=vmail gid=vmail home=/var/mail/vhosts/%d/%n }
沿著剛剛的args繼續往下做回到上一層新增dovecot-sql.conf.ext
# /etc/dovecot/dovecot-sql.conf.ext driver = mysql connect = host=127.0.0.1 dbname=mailserver user=mailuser password=mailuserpass default_pass_scheme = SHA512-CRYPT password_query = SELECT email as user, password FROM virtual_users WHERE email='%u';
pass_scheme選SHA512-CRYPT的原因是插入使用者資料時使用$6$作為參數呼叫ENCRYPT(),libc的crypt()在hash時會知道我們要使用SHA512
進入倒數第二個部分,dovecot的socket
# /etc/dovecot/conf.d/10-master.conf # lmtp協定的socket service lmtp { unix_listener /var/spool/postfix/private/dovecot-lmtp { mode = 0600 user = postfix group = postfix } } # 驗證用的socket service auth { unix_listener /var/spool/postfix/private/auth { mode = 0666 user = postfix group = postfix } unix_listener auth-userdb { mode = 0600 user = vmail #group = } user = dovecot } # 驗證使用的帳號 service auth-worker { user = vmail }
最後是SSL的設定
# /etc/dovecot/conf.d/10-ssl.conf # 強迫加密 ssl = required # 憑證跟私鑰 ssl_cert = </etc/pki/dovecot/certs/mailer.crt ssl_key = </etc/pki/dovecot/private/mailer.key # 一樣不要用DH做key exchange ssl_cipher_list = ALL:!LOW:!SSLv2:!EXP:!aNULL:!kEDH
大功告成!
一樣記得開防火牆的port 110,143,993,995,然後重啟dovecot服務
如果要讓寄信更順不會被擋,可以再設定SPF、DKIM、DMARC、IP反解
要先跟ISP搞定Reverse DNS哦
不然信出去八成也是直接被吃掉 {116}
@malsvent
用DKIM和SPF就還好啦 {124}
可以從key跟ip確定發信來源