Linux郵件服務(wù)器搭建攻略(一文吃透Postfix+Dovecot+MySQL)

1.jpg

今天來(lái)聊聊Linux郵件服務(wù)器的搭建旨袒,本以為電子郵件這種高度成熟的技術(shù)應(yīng)該很容易部署厕吉,上手后才發(fā)現(xiàn)原來(lái)坑還真不少打肝。本方案以主流的postfix + dovacot為基礎(chǔ)搞挣,其中postfix用作smtp胀糜,dovecot用作pop3(或imap)宫莱。

  1. 工作模式
    用postfix構(gòu)建的郵件系統(tǒng)至少有兩種工作模式投慈,第一種是利用本地Linux賬號(hào)進(jìn)行郵件收發(fā)荧降,比如本地系統(tǒng)有用戶root或someone专挪,那么就有root@example.comsomeone@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)很多令人頭疼的問題。

  2. 運(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)都是一致的缩挑。


pop3-smtp-imap-difference-00.jpg

基礎(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)備工作部分我們要做三件事:

  1. 建立數(shù)據(jù)庫(kù)
  2. 修改DNS設(shè)置
  3. 獲取域名證書

一步一步來(lái),我們首先來(lái)創(chuàng)建數(shù)據(jù)庫(kù)(默認(rèn)你已經(jīng)裝好了MySQL或MariaDB):


準(zhǔn)備步驟1:創(chuàng)建數(shù)據(jù)庫(kù)

  1. 建庫(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;
  1. 建表
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;
  1. 生成一些初始數(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)單的操作:

  1. 添加一個(gè)A記錄记劝,如圖:


    image.png
  2. 添加一個(gè)MX記錄变姨,如圖:


    image.png

每個(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è)面也是可以的舍咖。

  1. 首先安裝nginx
    dnf -y install nginx
    裝好之后到瀏覽器輸入你的域名矩父,如果出現(xiàn)nginx歡迎頁(yè)面,說明安裝成功排霉。

  2. 然后安裝certbot
    dnf -y install certbot python3-certbot-nginx

  3. 生成證書
    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)作扛点。

  1. 接下來(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為例浩销,如圖:
image.png
image.png

  • 結(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ぬ丁邀泉!
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市钝鸽,隨后出現(xiàn)的幾起案子汇恤,更是在濱河造成了極大的恐慌,老刑警劉巖寞埠,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件屁置,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡仁连,警方通過查閱死者的電腦和手機(jī)蓝角,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)饭冬,“玉大人使鹅,你說我怎么就攤上這事〔伲” “怎么了患朱?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)炊苫。 經(jīng)常有香客問我裁厅,道長(zhǎng),這世上最難降的妖魔是什么侨艾? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任执虹,我火速辦了婚禮,結(jié)果婚禮上唠梨,老公的妹妹穿的比我還像新娘袋励。我一直安慰自己,他們只是感情好当叭,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布茬故。 她就那樣靜靜地躺著,像睡著了一般蚁鳖。 火紅的嫁衣襯著肌膚如雪磺芭。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天醉箕,我揣著相機(jī)與錄音钾腺,去河邊找鬼甘邀。 笑死,一個(gè)胖子當(dāng)著我的面吹牛垮庐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播坞琴,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼哨查,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了剧辐?” 一聲冷哼從身側(cè)響起寒亥,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎荧关,沒想到半個(gè)月后溉奕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡忍啤,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年加勤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片同波。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡鳄梅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出未檩,到底是詐尸還是另有隱情戴尸,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布冤狡,位于F島的核電站孙蒙,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏悲雳。R本人自食惡果不足惜挎峦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望怜奖。 院中可真熱鬧浑测,春花似錦、人聲如沸歪玲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)滥崩。三九已至岖圈,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間钙皮,已是汗流浹背蜂科。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工顽决, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人导匣。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓才菠,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親贡定。 傳聞我的和親對(duì)象是個(gè)殘疾皇子赋访,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容