今天來(lái)聊聊Linux郵件服務(wù)器的搭建旨袒,本以為電子郵件這種高度成熟的技術(shù)應(yīng)該很容易部署厕吉,上手后才發(fā)現(xiàn)原來(lái)坑還真不少打肝。本方案以主流的postfix + dovacot為基礎(chǔ)搞挣,其中postfix用作smtp胀糜,dovecot用作pop3(或imap)宫莱。
工作模式
用postfix構(gòu)建的郵件系統(tǒng)至少有兩種工作模式投慈,第一種是利用本地Linux賬號(hào)進(jìn)行郵件收發(fā)荧降,比如本地系統(tǒng)有用戶root或someone专挪,那么就有root@example.com和someone@example.com兩個(gè)email地址及志。 第二種相對(duì)復(fù)雜一些,為了管理的方便和系統(tǒng)安全寨腔,postfix的用戶管理采用了虛擬用戶方式速侈,即postfix單獨(dú)設(shè)立了許多用戶,他們各自在系統(tǒng)中映射有獨(dú)立的硬盤空間迫卢。但同時(shí)這些用戶又跟本地Linux系統(tǒng)內(nèi)固有的真實(shí)賬號(hào)沒有關(guān)聯(lián)倚搬。本文所有討論就是建立在這種模式下的,值得注意的是乾蛤,這兩種工作模式的部署方法差異極大每界,在參考網(wǎng)上教程的時(shí)候,首先要確認(rèn)它是建立在哪個(gè)模式下的家卖,否則容易張冠李戴眨层,出現(xiàn)很多令人頭疼的問題。運(yùn)行流程
對(duì)于電子郵件上荡,我們有可能存在的一個(gè)誤區(qū)是趴樱,將smtp和pop3按照字面的意思去理解,即smtp只管發(fā)件,pop3則只負(fù)責(zé)收件叁征。其實(shí)并不完全是這樣纳账。下面是一封電子郵件在互聯(lián)網(wǎng)上的投遞流程:
- 發(fā)件人:me@qq.com 收件人:you@gmail.com
me@qq.com 用郵件客戶端(比如outlook)寫了一封郵件給you@gmail.com,點(diǎn)下發(fā)送按鈕后航揉,郵件首先會(huì)發(fā)送到smtp.qq.com - smtp.qq.com 檢索到這封郵件的收件人域名是gmail.com塞祈,于是通過互聯(lián)網(wǎng)(WAN)將郵件發(fā)送到smtp.gmail.com
- smtp.gmail.com確認(rèn)收下郵件后,將它轉(zhuǎn)存到郵件服務(wù)器的硬盤中待收帅涂。
通過觀察以上流程,你會(huì)發(fā)現(xiàn)smtp服務(wù)器其實(shí)身兼了 “收尤蛮、發(fā)” 兩個(gè)功能媳友。 對(duì)于smtp.qq.com而言,是發(fā)送产捞。 而從smtp.gmail.com的角度來(lái)看醇锚,則是接收。那么坯临,咱們平時(shí)經(jīng)常說起的 “收件服務(wù)器pop3” 又是怎么回事呢焊唬,整個(gè)流程似乎看不到它的身影?
pop3(或imap服務(wù)器看靠,與之性質(zhì)相同)更多的是起一個(gè)中轉(zhuǎn)作用赶促,它將存儲(chǔ)在郵件服務(wù)器硬盤中的郵件轉(zhuǎn)移回郵件客戶端(user agent),它只負(fù)責(zé)從郵件服務(wù)器到郵件客戶端這段路徑挟炬,而郵件在廣域網(wǎng)上的收發(fā)則是smtp要做的事鸥滨,與pop3沒有關(guān)系。
pop3與imap的區(qū)別是谤祖,pop3將郵件拉回本地后婿滓,即與服務(wù)器脫鉤了。imap則更先進(jìn)一些粥喜,它能做到實(shí)時(shí)將你在郵件客戶端的操作反饋回郵件服務(wù)器凸主,比如:刪除郵件,標(biāo)記已讀等额湘,服務(wù)器上的郵件也會(huì)做相應(yīng)的動(dòng)作卿吐。所以無(wú)論從瀏覽器登錄郵箱或者客戶端軟件登錄郵箱,看到的郵件以及狀態(tài)都是一致的缩挑。
基礎(chǔ)原理就這么點(diǎn)但两,下面開始進(jìn)入實(shí)戰(zhàn)環(huán)節(jié)。
一供置、 準(zhǔn)備工作
前面說過谨湘,本文以虛擬郵件用戶為基礎(chǔ),創(chuàng)建虛擬用戶有很多方法,其中最容易也最易于擴(kuò)展的方式莫過于采用數(shù)據(jù)庫(kù)來(lái)管理郵件客戶紧阔。比如說以后如果需要擴(kuò)展Web Mail功能坊罢,就比較容易與現(xiàn)有系統(tǒng)無(wú)縫銜接。
本文選用Centos下最常見的MariaDB作為數(shù)據(jù)庫(kù)擅耽,它與MySQL是完全兼容的活孩,關(guān)于MariaDB的部署不在本文討論之內(nèi),網(wǎng)上有很多教程乖仇,也非常簡(jiǎn)單憾儒。
首先將我的運(yùn)行環(huán)境做一個(gè)說明:
OS : Centos 8.2
DB : MariaDB 10.3.17
Postfix 3.3.1
Dovecot 2.3.8
編輯器:nano
注意:
- 文中所有出現(xiàn)example.com的地方,需要換成你自己的域名乃沙。
- 文中凡出現(xiàn)nano開頭的地方表達(dá)的意思就是編輯這個(gè)文件起趾。
準(zhǔn)備工作部分我們要做三件事:
- 建立數(shù)據(jù)庫(kù)
- 修改DNS設(shè)置
- 獲取域名證書
一步一步來(lái),我們首先來(lái)創(chuàng)建數(shù)據(jù)庫(kù)(默認(rèn)你已經(jīng)裝好了MySQL或MariaDB):
準(zhǔn)備步驟1:創(chuàng)建數(shù)據(jù)庫(kù)
- 建庫(kù)
mysql -u root -p 密碼
進(jìn)入mysql警儒,然后執(zhí)行:
create database servermail;
GRANT SELECT ON servermail.* TO 'usermail'@'127.0.0.1' IDENTIFIED BY 'mailpassword';
FLUSH PRIVILEGES;
USE servermail;
- 建表
CREATE TABLE `virtual_domains` (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `virtual_users` (
`id` INT NOT NULL AUTO_INCREMENT,
`domain_id` INT NOT NULL,
`password` VARCHAR(106) NOT NULL,
`email` VARCHAR(120) 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 NOT NULL AUTO_INCREMENT,
`domain_id` INT 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;
- 生成一些初始數(shù)據(jù)
創(chuàng)建域名:
INSERT INTO `servermail`.`virtual_domains`
(`id` ,`name`)
VALUES
('1', 'example.com'),
('2', 'mail.example.com');
生成兩個(gè)初始email賬號(hào):
其中训裆,dmarck-reports@example.com是將來(lái)設(shè)置DKIM需要用到的,這是后話先別管它蜀铲,創(chuàng)建了再說:
INSERT INTO `servermail`.`virtual_users`
(`id`, `domain_id`, `password` , `email`)
VALUES
('1', '1', ENCRYPT('密碼', CONCAT('$6$', SUBSTRING(SHA(RAND()), -16))), 'webmaster@example.com'),
('2', '1', ENCRYPT('密碼', CONCAT('$6$', SUBSTRING(SHA(RAND()), -16))), 'dmarck-reports@example.com');
生成一個(gè)別名:
INSERT INTO `servermail`.`virtual_aliases`
(`id`, `domain_id`, `source`, `destination`)
VALUES
('1', '1', 'boss@example.com', 'webmaster@example.com');
據(jù)庫(kù)的基本操作完畢边琉。
準(zhǔn)備步驟2:修改DNS服務(wù)器
這需要登錄你的域名管理界面,做幾個(gè)簡(jiǎn)單的操作:
-
添加一個(gè)A記錄记劝,如圖:
-
添加一個(gè)MX記錄变姨,如圖:
每個(gè)域名提供商的操作界面有可能不太一樣,但都大同小異的隆夯。
準(zhǔn)備步驟3:申請(qǐng)證書
接下來(lái)我們需要為郵件服務(wù)器獲取域名證書钳恕,拋開安全性不談,純粹從裝X的角度而言蹄衷,這玩意就如同https一樣忧额,這年頭你的網(wǎng)站還穿著http出來(lái)見人就真的有點(diǎn)丟人了,因此證書幾乎是必備的愧口。
域名證書有很多獲取方式睦番,有收費(fèi)的也有免費(fèi)的,國(guó)內(nèi)有一家通過網(wǎng)頁(yè)申請(qǐng)的耍属,可參見我寫的另一篇博文:http://www.reibang.com/p/b4b5ca1d88d6
今天我們采用另一個(gè)方法托嚣,利用Letsencrypt在線生成,這個(gè)方案的好處是不用等待厚骗,證書立等可取示启,而且流程相對(duì)也比較簡(jiǎn)單。因?yàn)樽C書必須要對(duì)應(yīng)一個(gè)真實(shí)存在的網(wǎng)站领舰,所以我們還必須先裝裝樣子夫嗓,安裝一個(gè)nginx迟螺,還好Letsencrypt對(duì)網(wǎng)站的實(shí)際內(nèi)容沒什么要求,nginx默認(rèn)的初始頁(yè)面也是可以的舍咖。
首先安裝nginx
dnf -y install nginx
裝好之后到瀏覽器輸入你的域名矩父,如果出現(xiàn)nginx歡迎頁(yè)面,說明安裝成功排霉。然后安裝certbot
dnf -y install certbot python3-certbot-nginx
生成證書
certbot certonly -a nginx --agree-tos --staple-ocsp --email webmaster@example.com -d mail.example.com
如果沒有問題窍株,系統(tǒng)將回顯如下:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/mail.example.com/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/mail.example.com/privkey.pem
Your cert will expire on 2021-02-27.
這里面包括了公私鑰的存放地址以及有效期之類的信息。
至此攻柠,準(zhǔn)備工作全部完成了球订,下面進(jìn)入我們的核心部署環(huán)節(jié)!
二辙诞、核心內(nèi)容:Postfix篇
首先我們需要安裝postfix辙售,在centos下這很簡(jiǎn)單,只需要一條命令:
dnf -y install postfix postfix-mysql
設(shè)置自啟動(dòng):
systemctl start postfix
systemctl enable postfix
安裝完畢后飞涂,開始對(duì)postfix進(jìn)行設(shè)置,其中關(guān)鍵的配置文件有兩個(gè):main.cf和master.cf祈搜。
1. nano /etc/postfix/main.cf
這是一個(gè)超復(fù)雜的配置文件较店,不過大多數(shù)都是注釋。限于篇幅我就不把整個(gè)文件貼出來(lái)了容燕,你可以將源文件完全清空梁呈,然后將以下內(nèi)容原封不動(dòng)地復(fù)制進(jìn)去,保存即可蘸秘。注意所有出現(xiàn)example.com的地方官卡,需要換成你自己的域名(后面的所有配置文件都是如此,接下來(lái)我就不再?gòu)?qiáng)調(diào)了)
mydomain = example.com
myorigin = mail.example.com
myhostname = mail.example.com
mydestination = \$mydomain
inet_interfaces = all
message_size_limit=52428800
mailbox_size_limit=0
smtpd_tls_cert_file=/etc/letsencrypt/live/mail.example.com/fullchain.pem
smtpd_tls_key_file=/etc/letsencrypt/live/mail.example.com/privkey.pem
smtpd_use_tls=yes
smtpd_tls_auth_only = yes
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination
smtpd_banner = $myhostname ESMTP \$mail_name (Ubuntu)
biff = no
append_dot_mydomain = no
readme_directory = no
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
relayhost =
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_size_limit = 0
recipient_delimiter = +
virtual_transport = lmtp:unix:private/dovecot-lmtp
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
話說整個(gè)main.cf有相當(dāng)多的設(shè)置項(xiàng)目醋虏,真正鉆進(jìn)去研究透徹需要花費(fèi)大量時(shí)間寻咒,對(duì)于上述設(shè)置我只談幾個(gè)我已經(jīng)看明白的:
mydomain = example.com
設(shè)置域名是example.com
myorigin = example.com
myorigin參數(shù)指定默認(rèn)域名,該默認(rèn)域名將附加到?jīng)]有@domain部分的發(fā)件人和收件人地址颈嚼。 需要將其值更改為example.com毛秘,因此郵件服務(wù)器上的發(fā)件人將具有@example.com地址。
myhostname = mail.example.com
與其他SMTP服務(wù)器通信時(shí)阻课,Postfix使用此主機(jī)名來(lái)標(biāo)識(shí)自己叫挟。 但是,操作系統(tǒng)主機(jī)名可能會(huì)更改限煞,因此抹恳,最好直接在配置文件中設(shè)置。
mydestination = \$mydomain
mydestination參數(shù)指定服務(wù)器將其視為自身最終目的地的域列表署驻。這個(gè)聽起來(lái)有點(diǎn)拗口奋献,說白了就是別人給您發(fā)信健霹,哪些信你是接受的。比如12345@qq.com給您發(fā)一封信秽荞,收件人是webmaster@example.com骤公,當(dāng)你的smtp服務(wù)器接收到這封信的時(shí)候表示接受,對(duì)應(yīng)的規(guī)則就是$mydomain扬跋。注意:此處如果設(shè)錯(cuò)了阶捆,有可能出現(xiàn)一個(gè)問題:你可以給別人發(fā)信,但是別人給你發(fā)的信你會(huì)收不到钦听。
smtpd_tls_cert_file=/etc/letsencrypt/live/mail.example.com/fullchain.pem
smtpd_tls_key_file=/etc/letsencrypt/live/mail.example.com/privkey.pem
這兩個(gè)是剛才我們生成的證書洒试。
message_size_limit=52428800
mailbox_size_limit=0
這兩個(gè)設(shè)置比較實(shí)用,是指附件最大允許容量和郵箱的總?cè)萘科由希@里我們把最大附件設(shè)為50MB垒棋,郵箱總?cè)萘縿t不設(shè)限制(0)
virtual_transport = lmtp:unix:private/dovecot-lmtp
這是一條核心設(shè)置,表示通過lmtp (Local Mail Transfer Protocol)協(xié)議痪宰,將本地郵件傳遞到dovecot中叼架,相當(dāng)于告訴Postfix,將從廣域網(wǎng)收到的郵件衣撬,最終傳遞到dovecot能控制的地方乖订,以便我們用pop3或imap下載到郵件客戶端。
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
這三行與數(shù)據(jù)庫(kù)有關(guān)具练,表示郵箱的虛擬域乍构,用戶映射關(guān)系和別名映射關(guān)系,分別由哪三個(gè)SQL腳本做查詢動(dòng)作扛点。
- 接下來(lái)我們就要?jiǎng)?chuàng)建這3個(gè)SQL腳本了哥遮,稍懂一點(diǎn)SQL語(yǔ)句的朋友一定也可以看出其中的關(guān)聯(lián),這里也不再展開討論了:
nano /etc/postfix/mysql-virtual-mailbox-domains.cf
user = usermail
password = mailpassword
hosts = 127.0.0.1
dbname = servermail
query = SELECT 1 FROM virtual_domains WHERE name='%s'
nano /etc/postfix/mysql-virtual-mailbox-maps.cf
user = usermail
password = mailpassword
hosts = 127.0.0.1
dbname = servermail
query = SELECT 1 FROM virtual_users WHERE email='%s'
nano /etc/postfix/mysql-virtual-alias-maps.cf
user = usermail
password = mailpassword
hosts = 127.0.0.1
dbname = servermail
query = SELECT destination FROM virtual_aliases WHERE source='%s'
創(chuàng)建好之后陵究,用systemctl restart postfix
重啟一次postfix眠饮,然后測(cè)試一下剛才建立的三個(gè)腳本。
postmap -q example.com mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
正確的話畔乙,應(yīng)該返回:1
postmap -q webmaster@example.com mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
正確的話君仆,應(yīng)該返回:1
postmap -q boss@example.com mysql:/etc/postfix/mysql-virtual-alias-maps.cf
正確的話,應(yīng)該返回:webmaster@example.com
2. nano /etc/postfix/master.cf
這也是一個(gè)巨復(fù)雜的配置文件牲距,不過你依然可以先把它徹底清空返咱,然后原封不動(dòng)把以下內(nèi)容粘貼進(jìn)去:
smtp inet n - n - - smtpd
submission inet n - - - - smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
smtps inet n - y - - smtpd
-o syslog_name=postfix/smtps
-o smtpd_tls_wrappermode=yes
-o smtpd_sasl_auth_enable=yes
-o smtpd_relay_restrictions=permit_sasl_authenticated,reject
-o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject
-o smtpd_sasl_type=dovecot
-o smtpd_sasl_path=private/auth
pickup unix n - n 60 1 pickup
cleanup unix n - n - 0 cleanup
qmgr unix n - n 300 1 qmgr
tlsmgr unix - - n 1000? 1 tlsmgr
rewrite unix - - n - - trivial-rewrite
bounce unix - - n - 0 bounce
defer unix - - n - 0 bounce
trace unix - - n - 0 bounce
verify unix - - n - 1 verify
flush unix n - n 1000? 0 flush
proxymap unix - - n - - proxymap
proxywrite unix - - n - 1 proxymap
smtp unix - - n - - smtp
relay unix - - n - - smtp
-o syslog_name=postfix/$service_name
showq unix n - n - - showq
error unix - - n - - error
retry unix - - n - - error
discard unix - - n - - discard
local unix - n n - - local
virtual unix - n n - - virtual
lmtp unix - - n - - lmtp
anvil unix - - n - 1 anvil
scache unix - - n - 1 scache
master.cf這個(gè)文件主要掌管著postfix的各種服務(wù),
這個(gè)文件的與一般的配置文件不同牍鞠,它是縮進(jìn)敏感的咖摹。
每一個(gè)頂格的行,代表一種服務(wù)难述,比如:
submission inet n - - - - smtpd
smtps inet n - y - - smtpd
同時(shí)他們下面又有一些
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
以-o開頭的行萤晴,前面多了兩空格吐句,表示該服務(wù)下的具體設(shè)置。這兩個(gè)空格不能刪除店读,否則會(huì)報(bào)錯(cuò)嗦枢,這就是所謂的縮進(jìn)敏感。
可以看到我們開啟了smtp屯断,smtps和submission這三個(gè)服務(wù)文虏,分別對(duì)應(yīng)端口25,465和587殖演,功能分別是:傳統(tǒng)smtp服務(wù)氧秘,加密的smtps服務(wù),還有一個(gè)submission趴久。這是一個(gè)與smtps類似的加密協(xié)議丸相。smtps 和 submission從功能上而言極其雷同,關(guān)于這兩個(gè)端口彼棍,歷史上還有一些彼此爭(zhēng)奪話語(yǔ)權(quán)的野史灭忠,感興趣的可以自行搜索。題外話我們暫且不表座硕,反正兩個(gè)都開通就是了更舞。
至此,Postfix的設(shè)置工作就完成了坎吻,你可以通過以下命令用它發(fā)一封最簡(jiǎn)單的郵件,看看能否收到宇葱?
echo "Hello world!" | sendmail 你的qq@qq.com
三瘦真、核心內(nèi)容:Dovecot篇
1. 安裝dovecot
dnf -y install dovecot dovecot-mysql
設(shè)置自啟動(dòng):
systemctl start dovecot
systemctl enable dovecot
2. nano dovecot.conf
protocols = imap lmtp
listen = *, ::
mail_max_userip_connections = 50
!include conf.d/*.conf
!include_try local.conf
這其實(shí)也是一個(gè)很復(fù)雜的配置文件,但是注釋去掉之后也沒什么內(nèi)容黍瞧。
protocols = imap lmtp
表示支持的協(xié)議诸尽,這里我們只開通了imap和lmtp,如果你需要pop3的話印颤,加上去即可您机。
注意:此處的lmtp必須打開,這是dovecot和postfix交流的通道年局。
listen = *, ::
表示監(jiān)聽所有地址际看,*是ipv4的表達(dá)方法,::則是ipv6的矢否,如果你沒有啟用ipv6仲闽,直接listen = *也行
mail_max_userip_connections = 50
設(shè)置一個(gè)合理的數(shù)值,否則會(huì)報(bào)mail_max_userip_connections 錯(cuò)誤僵朗。
!include conf.d/*.conf
!include_try local.conf
沒有太大的作用赖欣,表示此處將包含conf.d文件夾下的所有配置文件屑彻。
3. nano /etc/dovecot/conf.d/10-mail.conf
mail_location = maildir:/var/mail/vhosts/%d/%n
mail_privileged_group = mail
這個(gè)文件的原始體積也很大,但刪掉注釋之后只有2行顶吮,它設(shè)置的是郵箱對(duì)應(yīng)硬盤的具體位置社牲,%d表示域名,%n表示用戶名悴了,比如在本文中搏恤,webmaster@example.com這個(gè)用戶在硬盤中的物理位置在:
/var/mail/vhost/example.com/webmaster
4. 創(chuàng)建用戶組和用戶:
groupadd -g 5000 vmail
useradd -g vmail -u 5000 vmail -d /var/mail
創(chuàng)建一個(gè)用戶組vmail并添加一個(gè)用戶vmail,id為5000让禀,
用戶vmail隸屬于用戶組vmail挑社。起始目錄為 /var/mail
5. 創(chuàng)建域名目錄:
mkdir -p /var/mail/vhosts/example.com
6. 修改/var/mail和/etc/dovecot的擁有者:
chown -R vmail:vmail /var/mail
chown -R vmail:dovecot /etc/dovecot
chmod -R o-rwx /etc/dovecot
7. 查看權(quán)限
ls -ld /var/mail
如果顯示:
lrwxrwxrwx. 1 vmail vmail 10 May 11 2019 /var/mail -> spool/mail
說明權(quán)限設(shè)置成功,請(qǐng)注意:這一步非常重要巡揍,如果該目錄持有者不是vmail的話痛阻,dovecot在收到郵件后無(wú)法保存,將會(huì)報(bào)錯(cuò)腮敌。
8. nano /etc/dovecot/conf.d/10-auth.conf
disable_plaintext_auth = yes
auth_mechanisms = plain login
!include auth-sql.conf.ext
disable_plaintext_auth = yes
表示登錄密碼必須加密阱当,否則不通過,我們這個(gè)方案是全盤TLS加密的糜工,因此此處把他打開弊添,不允許明文密碼。
auth_mechanisms = plain login
授權(quán)機(jī)制捌木,表示允許明文密碼授權(quán)和login密碼授權(quán)油坝,為啥此處我們選擇明文密碼呢?此明文非彼明文刨裆,此處的明文是指在SSL/TLS加密通道中的明文澈圈,因?yàn)楸旧砭鸵呀?jīng)加密過了,所以我們不需要擔(dān)心密碼泄露問題帆啃,而此處的login方式瞬女,是專門為outlook準(zhǔn)備的。此處可以選擇cram-md5努潘,專門用于加密密碼诽偷,但本身我們已經(jīng)是加密通道了,因此沒有必要畫蛇添足疯坤。
!include auth-sql.conf.ext
此行表示啟用MySQL授權(quán)
9. nano /etc/dovecot/conf.d/auth-sql.conf.ext
passdb {
driver = sql
args = /etc/dovecot/dovecot-sql.conf.ext
}
userdb {
driver = static
args = uid=vmail gid=vmail home=/var/mail/vhosts/%d/%n
}
當(dāng)我們通過郵件客戶端登錄咱們的pop3(或imap)服務(wù)器準(zhǔn)備取回郵件時(shí)报慕,需要進(jìn)行密碼核對(duì)和用戶名核對(duì),那么dovecot是如何實(shí)現(xiàn)的呢贴膘?這個(gè)文件指定dovecot是如何獲取用戶密碼和用戶資料的卖子,密碼部分采用sql腳本方式。用戶數(shù)據(jù)采用static (靜態(tài)) 方式刑峡,通常洋闽,SQL數(shù)據(jù)庫(kù)也可以做這件事玄柠,也可以通過它得到用戶的UID,GID和主目錄诫舅。但此處如果我們僅使用靜態(tài)UID和GID羽利,并且可以使用模板指定主目錄,則可以改用靜態(tài)方式刊懈,它會(huì)比SQL方式略快一些这弧。
10. nano /etc/dovecot/dovecot-sql.conf.ext
driver = mysql
connect = host=127.0.0.1 dbname=servermail user=usermail password=mailpassword
default_pass_scheme = SHA512-CRYPT
password_query = SELECT email as user, password FROM virtual_users WHERE email='%u';
這個(gè)文件就是剛才我們說的SQL方式獲取用戶密碼的腳本,很簡(jiǎn)單只有一句虚汛,相信大家都能看得懂匾浪。
說句題外話,dovecot只能識(shí)別user和password字段卷哩,如果你的初始數(shù)據(jù)庫(kù)用的并不是這兩個(gè)字段的話蛋辈,必須是用as修飾符強(qiáng)制將它們轉(zhuǎn)換成user和password。
11. nano /etc/dovecot/conf.d/10-master.conf
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
mode = 0600
user = postfix
group = postfix
}
}
service auth {
unix_listener /var/spool/postfix/private/auth {
mode = 0666
user = postfix
group = postfix
}
unix_listener auth-userdb {
mode = 0600
user = vmail
}
user = dovecot
}
service auth-worker {
user = vmail
}
這個(gè)文件主要作用是為了打通dovecot和postfix的關(guān)聯(lián)将谊,授權(quán)postfix通過lmtp協(xié)議訪問屬于dovecot的地盤冷溶,訪問權(quán)限是0600,表示有讀寫權(quán)限尊浓,但無(wú)執(zhí)行權(quán)限逞频。這個(gè)文件的源文件也比較龐雜,里面對(duì)多個(gè)協(xié)議都有設(shè)定栋齿,但是如果你全部把它們刪了也沒關(guān)系苗胀,等于采用默認(rèn)設(shè)置,比如你把imap這一段刪了瓦堵,那么dovacot會(huì)將imap設(shè)為默認(rèn)端口993柒巫。
11. nano /etc/dovecot/conf.d/10-ssl.conf
ssl = required
ssl_cert = </etc/letsencrypt/live/mail.example.com/fullchain.pem
ssl_key = </etc/letsencrypt/live/mail.example.com/privkey.pem
ssl_cipher_list = PROFILE=SYSTEM
這個(gè)配置文件主要是設(shè)置SSL,
ssl = required
表示強(qiáng)制使用SSL加密通道谷丸,從密碼到郵件內(nèi)容全部加密,這就是前面咱們?cè)凇笆跈?quán)機(jī)制”那個(gè)步驟允許使用的plain(明文密碼)的原因了应结,因?yàn)檎麄€(gè)通道都已經(jīng)被加密了刨疼,明文密碼走在加密通道里面也可以認(rèn)為是安全的,后面兩行指定了我們?cè)跍?zhǔn)備步驟生成的證書存放位置鹅龄。請(qǐng)注意揩慕,這兩個(gè)文件與Postfix里的設(shè)置是完全一致的,也就是說Postfix和Dovecot采用的是同一個(gè)證書扮休,不僅如此迎卤,實(shí)際上這本證書還可以用于nginx用于加密你的Web網(wǎng)站,開通https等玷坠。
12. nano /etc/dovecot/conf.d/15-mailboxes.conf
namespace inbox {
inbox = yes
mailbox Drafts {
auto = create
special_use = \Drafts
}
mailbox Junk {
auto = create
special_use = \Junk
}
mailbox Trash {
auto = create
special_use = \Trash
}
mailbox Sent {
auto = create
special_use = \Sent
}
mailbox "Sent Messages" {
auto = create
special_use = \Sent
}
}
這個(gè)文件是用來(lái)指定收件箱的命名空間的蜗搔,auto = create
表示當(dāng)這些郵箱都沒有的時(shí)候劲藐,就自動(dòng)創(chuàng)建它,這里指定的都是常規(guī)的樟凄,比如收件箱聘芜,已發(fā)送宰译,垃圾箱伤靠,已刪除等等,如果需要?jiǎng)e的種類君账,請(qǐng)自行研究叔壤。
四瞎饲、驗(yàn)證篇
終于快大功告成了!
現(xiàn)在我們需要驗(yàn)證一下服務(wù)器到底設(shè)置成功沒有炼绘,首先重啟一下postfix和dovecot:
stystemctl restart postfix dovecot
查看日志的方法是:
tail -f /var/log/maillog
請(qǐng)注意:postfix和dovecot的日志是合并在一起的嗅战,兩者的變化都會(huì)記錄在這個(gè)文件里。
1. 初級(jí)判斷:
本文中饭望,我們開通了smtp, smtps, imaps, lmtp, submission 這四個(gè)服務(wù)仗哨,分別對(duì)應(yīng)端口:
25/tcp smtp :負(fù)責(zé)廣域網(wǎng)郵件傳遞,非加密
465/tcp smtps :同上铅辞,加密
143/tcp imap :負(fù)責(zé)將服務(wù)器的郵件傳回郵件服務(wù)端厌漂,非加密
993/tcp imaps :同上,加密
587/tcp submission :同上斟珊,加密
lmtp :為內(nèi)部傳輸服務(wù)苇倡,不對(duì)外,無(wú)端口號(hào)
最簡(jiǎn)單的囤踩,我們可以用:
netstat -tunlp
看看這些端口起來(lái)了沒有旨椒,
如果顯示這樣:
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:25 0.0.0.0:* LISTEN 6717/master
tcp 0 0 0.0.0.0:465 0.0.0.0:* LISTEN 6717/master
tcp 0 0 0.0.0.0:143 0.0.0.0:* LISTEN 6729/dovecot
tcp 0 0 0.0.0.0:993 0.0.0.0:* LISTEN 6729/dovecot
tcp 0 0 0.0.0.0:587 0.0.0.0:* LISTEN 6717/master
說明OK,如果指定的端口號(hào)不存在堵漱,那么說明服務(wù)有問題综慎,需要排查。
另外一個(gè)更高端的端口掃描器叫做nmap勤庐,也可以實(shí)現(xiàn)同樣的功能示惊,首先安裝它:
dng -y install nmap
使用很簡(jiǎn)單:
nmap mail.example.com
2. 測(cè)試連通性:
如果端口都存在,說明大毛病沒有了愉镰,我們可以用telnet測(cè)一下米罚,
命令很簡(jiǎn)單,比如我們想測(cè)一下993端口:
telnet mail.example.com 993
如果返回:
Trying 123.123.123.123...
Connected to mail.example.com.
Escape character is '^]'.
說明沒有大問題丈探,輸入quit或ctrl+c录择,退出。
如果返回:
Trying 123.123.123.123...
telnet: connect to address 123.123.123.123: Connection refused
則說明這個(gè)端口有毛病,需要排查隘竭。
3. 高端測(cè)試
利用openssl命令塘秦,我們可以對(duì)這些服務(wù)進(jìn)行更深層次的檢測(cè)。
例如我們想查一下服務(wù)器的993端口(imap)加密通道到底正不正常:
openssl s_client -connect mail.example.com:993
如果返回一大堆類似密文的東西货裹,說明基本OK嗤形,往上翻,如果出現(xiàn)類似這樣的信息:
depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
verify return:1
depth=0 CN = mail.example.com
說明證書是OK的弧圆,由Let's Encrypt公司頒發(fā)赋兵,域名也跟你的實(shí)際域名對(duì)得上,說明SSL這一塊大問題沒有搔预。
如果輸入了這條命令毫無(wú)反應(yīng)霹期,或報(bào)錯(cuò),或者域名不是你的域名拯田,你就要仔細(xì)排查你的域名證書是不是有問題了历造,因?yàn)閐ovecot裝好之后本身有一本默認(rèn)證書,但那不是你的域名的船庇,盡管看上去好像沒毛病吭产,但實(shí)際那本證書是無(wú)法使用的。
4. 常見錯(cuò)誤
- 問題: Error: namespace configuration error: inbox=yes namespace missing
nano /etc/dovecot/conf.d/15-mailboxes.conf
namespace inbox {
inbox = yes #添加這一行鸭轮,注意位置一定別搞錯(cuò)臣淤,只能加在這里
mailbox Drafts {
auto = create
special_use = \Drafts
}
- 問題:Recipient address rejected: User unknown in local recipient table
nano /etc/postfix/main.cf :
mydestination = \$mydomain
- 問題: Error: Diffie-Hellman key exchange requested, but no DH parameters provided. Set ssh_dh=</path/to/dh.pem
nano /etc/dovecot/dovecot.conf
去掉pop3:
protocols = imap lmtp
pop3需要強(qiáng)制使用迪菲-赫爾曼密鑰(簡(jiǎn)稱DH),因此你需要自己去建一個(gè),相當(dāng)耗時(shí)且麻煩窃爷,所以本文中干脆就不用pop3了邑蒋,imap現(xiàn)在已經(jīng)是主流協(xié)議了,而且功能更強(qiáng)大按厘。
- 其他認(rèn)證類問題:
基本上問題出在SSL医吊,各種亂七八糟的報(bào)錯(cuò)都有,這里就不贅述了逮京,實(shí)在不行就從源頭開始查卿堂,從生成證書那一步就開始認(rèn)真核對(duì),比如輸入域名的時(shí)候有沒有敲錯(cuò)之類懒棉。
- 更詭異的問題:
大家不一定都能碰到御吞,在此我只做一個(gè)記錄:
所有服務(wù)都運(yùn)行正常,openssl測(cè)試也通過了漓藕,但是當(dāng)我用客戶端進(jìn)行設(shè)置的時(shí)候foxmail就是報(bào)ssl錯(cuò)誤,百思不得其解挟裂,更詭異的是享钞,日志絲毫沒有反應(yīng),連報(bào)錯(cuò)都沒有,排查工作根本無(wú)從談起栗竖。折騰了一晚上暑脆,第二天故障居然自行消失了!找不到問題這更讓人窩火狐肢,后來(lái)通過慢慢回憶添吗,我找出了問題所在:我在用foxmail客戶端測(cè)試的時(shí)候忘記關(guān)FQ開關(guān)。因?yàn)椴捎玫氖莟un2socks方式全局FQ份名,我猜測(cè)某些數(shù)據(jù)經(jīng)過多層跳板是不是無(wú)法最終發(fā)送到服務(wù)器導(dǎo)致碟联?
- 目前的問題:
Mozilla Thunderbird客戶端無(wú)法使用,F(xiàn)oxmail卻很完美僵腺,目前我也沒有招鲤孵,搜遍整個(gè)google,貌似不止我一個(gè)辰如,初步判斷是Thunderbird對(duì)加密證書有別的要求普监,反正平時(shí)我也是用Foxmail,這個(gè)問題先擱一邊琉兜,以后有時(shí)間再慢慢研究凯正。
- 關(guān)于防火墻:
firewalld和iptables本人不會(huì)用,只貼一個(gè)nft的簡(jiǎn)單版豌蟋,放行了本文中所有涉及到的端口廊散,關(guān)于端口放行的問題,不麻煩夺饲,請(qǐng)自行百度谷歌奸汇。
我的簡(jiǎn)單防火墻腳本:
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
ct state established,related accept
ct state invalid drop
iif lo accept
ip protocol icmp icmp type { destination-unreachable, router-solicitation, router-advertisement, time-exceeded, parameter-problem } accept
ip protocol igmp accept
tcp dport { ssh, http, https,smtp, smtps, imap, imaps} accept
}
chain forward {
type filter hook forward priority 0; policy drop;
}
chain output {
type filter hook output priority 0; policy accept;
}
}
使用方法,先把上面的粘貼復(fù)制成一個(gè)文件往声,然后nft -f 文件名擂找,即可。
- 關(guān)于客戶端設(shè)置:
以Foxmail為例浩销,如圖:
- 結(jié)束了嗎贯涎?
其實(shí)才剛開始,后面的事情還多著呢慢洋,還需要給我們的郵件服務(wù)器設(shè)置WEB Mail塘雳,設(shè)置SPF、DKIM普筹、DMARC等等等等败明,SPF和DKIM可以參考我的前一篇博文:
http://www.reibang.com/p/736867371d28
如何提高郵件服務(wù)器的“受尊重度”是一門大學(xué)問,而且還不怎么和技術(shù)直接掛鉤太防,非常不省心妻顶,我的郵件服務(wù)器至今也沒進(jìn)得了gmail的法眼,盡管可以通過Postmark等第三方smtp代發(fā)機(jī)構(gòu)解決這個(gè)難題,但如果大家有什么好方法讓我們理直氣壯被gmail認(rèn)可的話讳嘱,歡迎留言告知幔嗦,交流,感謝Aぬ丁邀泉!