Linux 系统管理高级教程(六)

原文:Pro linux system administration

协议:CC BY-NC-SA 4.0

十一、Web 和 SQL 服务

您要做的最常见的事情之一是设置 web 服务。web 服务很可能需要一个结构化的英语查询语言(SEQUEL)数据库。在这一章中,我们将探索安全 web 服务的主要组成部分。

在本章中,您将学习如何安全地设置 Apache web 服务器和 MariaDB 数据库服务器。为了保护与新 web 服务器的通信,我们将使用 Let’s Encrypt 来创建安全套接字层(SSL)/传输层安全性(TLS)证书。这也将为我们提供保护其他服务的证书。然后我们将展示如何安装一个内容管理系统和一个 webmail 应用程序。最后,我们将向您展示如何通过 web 代理保护您的员工,让他们的 web 浏览体验变得更快、更安全。

Apache Web 服务器

Apache 是当今使用最广泛的开源软件之一。虽然它的受欢迎程度在过去几年中有所下降,但它仍然被用于托管超过 30%的现有网站 1 ,并且通常因其成熟度、稳定性和应用程序的性质而被选中。它被设计成模块化的,因此可以通过启用或禁用模块来添加或删除额外的功能。几乎所有的 Linux 发行版都有软件包,所以您可以通过软件包管理系统在您的主机上安装它。

Apache 服务器可以作为单个站点的单个 web 服务器运行,或者更常见的是,可以作为虚拟主机服务于数百个站点。也就是说,许多网站共享底层资源,如单个 web 服务器的中央处理器(CPU)、磁盘资源和互联网协议(IP)地址。

Apache 目前有三个多处理模块(MPM)供您选择使用。它们是预工作、工作人员和事件。

  • prefork 模块是由单独的进程处理连接的地方。它适用于非线程安全的 web 应用程序。在 prefork 模块中,控制进程创建一个监听连接的子进程。
  • worker 模块混合了基于进程和基于线程的处理。它适用于线程安全应用程序。在 worker 模型中,父进程创建一个启动几个线程的子进程;为每个传入连接分配一个线程。一种是监听传入的连接,并将它们传递给等待的服务器线程。
  • 事件模块较新,基于工作模块。它的线程模型类似于 worker,但是针对处理 keepalive 连接进行了优化。它用几个线程来处理 keepalivess,keepalive 将活动连接交给等待的线程。

Apache web 服务器的另一个流行替代品是 Nginx。Nginx 是一种快速的模块化 web 服务器,通常与 Apache 服务器一起用作缓存服务器,或者单独用作 web 服务器。我们将在第十九章讨论 Ansible 时展示如何安装 Nginx 服务器。

安装和配置

CentOS 和 Ubuntu 都安装 Apache 版,但是包的命名不同。在 CentOS 上运行sudo yum install httpd,在 Ubuntu 上运行sudo aptitude install apache2。添加这些包将导致安装一些额外的库。

此外,CentOS 和 Ubuntu 都允许您通过加载您想要使用的特定模块来选择 MPM。我们将很快展示如何做到这一点。除了加载特定的 MPM,您还可以加载模块来加载运行不同 web 服务器应用程序所需的软件,比如 PHP 或 Django。我们很快也会向您展示这一点。

Note

如果您运行一个高容量、高流量的网站,您可能会考虑换一个不同的 Apache 引擎或者完全不同的 web 服务器,比如 Nginx。Nginx 不同于 Apache,因为它是真正的非阻塞、事件驱动的大规模 web 服务器。关于这些 web 服务器的差异和功能,请参见 https://www.digitalocean.com/community/tutorials/apache-vs-nginx-practical-considerations

您还可以在 http://en.wikipedia.org/wiki/Comparison_of_web_servers 找到 web 服务器列表。

我们将从展示如何为 Apache 进行基本配置开始。稍后,我们将展示如何添加一些模块来扩展功能。

CentOS

在这一节中,我们将展示如何配置我们的 Apache web 服务器。Apache web 服务器将其配置文件存储在/etc/httpd中,主配置文件是/etc/httpd/conf/httpd.conf。我们将首先编辑/etc/httpd/conf/httpd.conf文件,然后创建一个虚拟主机文件。

CentOS 的默认 MPM 模块是 prefork。您可以通过编辑/etc/httpd/conf.modules.d/00-mpm.conf来更改模块,并对适当的模块进行注释和取消注释。我们将使用 worker 模块,因为它提供了优于 prefork 模块的性能配置文件。

#LoadModule mpm_prefork_module modules/mod_mpm_prefork.so
LoadModule mpm_worker_module modules/mod_mpm_worker.so

httpd.conf文件超过 350 行,所以我们不会显示每个选项。与许多其他 Linux 配置文件一样,#表示注释,选项以<name> <directive>的形式出现。让我们从基础开始:服务器名(ServerName)和网站管理员的电子邮件地址(ServerAdmin)。

ServerName au-mel-centos-1.example.com
ServerAdmin webmaster@example.com

Apache 在显示默认错误页面时会使用服务器名称和网站管理员电子邮件地址。我们已经为自己的主机输入了值,au-mel-centos-1.example.comwebmaster@example.com。默认情况下,Apache 将在所有可用的网络地址上监听和服务请求。如果你想选择一个特定的地址,你可以使用Listen指令来改变它。您也可以配置想要监听的端口。要更改默认值,您可以指定如下内容:

Listen 192.168.0.1:8080

前一行指定只监听特定的 IPv4 地址和端口 8080。要小心,因为当 Apache 试图启动时,具有相同 IP 和端口的多个Listen指令会给出一个错误((98)Address already in use)。在我们的例子中,我们将设置Listen监听端口 80 上的所有地址。

Listen 80

通过设置UserGroup字段,可以更改 web 服务器运行的用户和组。

User apache
Group apache

如果您更改了UserGroup字段,重要的是不要将它们更改为系统中其他地方使用的用户和组,例如数据库用户。Apache 服务是由 root 用户启动的,因此它可以绑定到端口 80(一个特权端口),并按照这里定义的用户启动子进程。这个用户应该拥有尽可能少的特权,并且应该能够阅读它所提供的内容。

最后,我们将重点介绍这些配置项目:

Include conf.modules.d/*.conf
IncludeOptional conf.d/*.conf

第一个加载模块,比如前面描述的 MPM。模块提供不同的软件功能;有授权模块,像 PHP 这样的 web 语言模块,以及其他种类的特性。IncludeOptional指令可以用来存储配置文件,比如虚拟主机或者其他配置文件,比如php.conf。如果这些文件是有编号的,像00-php.conf,那么它们将按数字顺序加载。

创建虚拟主机

我们现在准备创建我们的第一个虚拟主机。一台运行 Apache 的 Linux 主机可以服务数百或数千个网站,它们都有自己的主机名。我们称之为虚拟主机,因为这些网站都运行在一个单独的网络服务器上。有两种虚拟主机:基于 IP 和基于名称。Apache 可以同时提供这两者。

基于 IP 的虚拟主机使 Apache 根据接收请求的 IP 地址,从特定的目录提供 web 页面。对于每个基于 IP 的虚拟主机,Linux 主机需要有一个分配给网络接口的 IP 地址。正如我们在第七章中所讨论的,这是通过向接口添加额外的地址来实现的。现在服务器名称指示(SNI; www.ietf.org/rfc/rfc4366.txt )可用,这是使用 SSL/TLS 证书时向 web 服务器提供服务器名称的一种方式。因为一些老的浏览器不支持 SNI,你仍然可以看到基于 IP 的虚拟主机,这样做是有意义的。

基于名称的虚拟主机使 Apache 根据远程用户连接的站点名称为特定目录提供网页。任意数量的基于名称的虚拟主机可以共享一个 IP 地址。站点的名称由一个特殊的头决定,这个头在请求中被发送到 web 服务器。

我们将创建一个命名的虚拟主机。为此,我们需要为我们的站点创建一个配置文件。我们在 Apache conf.d目录下/etc/httpd/conf.d/ www.example.com.conf 中创建这个文件。让我们从如何描述虚拟主机开始。

<VirtualHost *:80>
...
</VirtualHost>

Apache 有一个特殊的语法来描述虚拟主机。每个虚拟主机的所有配置都需要包含在<VirtualHost *:80></VirtualHost>指令中。opening 指令声明虚拟主机的开始,在这种情况下,指定您应该监听该主机端口 80 上的所有网络接口(*:80)。然后,我们用关闭指令</VirutalHost>关闭虚拟主机配置。

对于基本虚拟主机,我们可以使用以下配置:

<VirtualHost *:80>

  ServerName www.example.com
  ServerAdmin webmaster@example.com
  DocumentRoot  /var/www/html/www.example.com

</VirtualHost>

ServerName告诉 Apache 服务器应该将对 www.example.com 网站的请求发送到这个虚拟主机。DocumentRoot目录设置是 Apache 为网站提供文件的地方。您可以覆盖此虚拟主机的网站管理员电子邮件地址。

我们可以在文档根目录下创建一个index.html文件,并启动 Apache 服务器。

$ sudo mkdir –p /var/www/html/www.example.com
$ sudo bash –c "echo www.example.com > /var/www/html/www.example.com/index.html"

现在我们只需要重启我们的 Apache 服务器。不过,在此之前,我们应该验证我们的 Apache 配置。我们通过以下方式做到这一点:

$ sudo apachectl configtest
Syntax OK

这里我们使用apachectl命令来管理我们的 Apache 服务。apachectl程序可以用来启动、停止、重启、正常重启和检查配置,就像我们在这里所做的一样。更多信息参见man apachectl页面。要启动 Apache 服务,还可以在 CentOS 上使用systemctl命令。让我们继续做那件事。

$ systemctl start httpd.service

您将在/var/log/httpd目录中看到 Apache 服务的日志。您可以使用以下命令跟踪日志:

$ sudo tail –f /var/log/httpd/access_log /var/log/httpd/error_log

现在我们可以检查我们的主机是否如我们预期的那样响应。为此,我们将使用curl命令。curl命令将允许我们在 shell 中向 web 服务器发出请求。

$ curl –H 'Host: www.example.com' http://localhost
www.example.com

这表明我们的服务器已经正确地响应了我们的虚拟主机。使用curl命令,我们向监听本地主机的 web 服务器发出请求。我们还发送了一个Host头(-H 'Host:),其中包含了我们希望向其发送请求的 web 服务器的名称。Apache 将读取这个头并将这个请求传递给相应的虚拟主机。如果它找不到具有相同ServerName字段的虚拟主机,它会将请求路由到“基本”虚拟主机,或者换句话说,它加载的第一个虚拟主机。因此,最好在配置文件中添加一个数字作为后缀,如00- www.example.com.conf ,它将决定虚拟主机的加载顺序。

在我们向外界公开之前,我们应该确保我们的防火墙允许超文本传输协议(HTTP)流量到达我们的主机。首先,让我们看看当前防火墙允许的服务列表。

$ sudo firewall-cmd --list-services
dhcpv6-client ssh

我们需要添加http服务。我们用firewall-cmd再做一次。

$ sudo firewall-cmd --add-service http --permanent
$ sudo firewall-cmd --reload

默认情况下,这将服务添加到公共区域。现在我们应该能够从远程客户端访问我们的站点了。

在 Ubuntu 上,基本配置被分成多个文件。Ubuntu 上 Apache 加载的主文件是/etc/apache2/apache2.conf。我们已经在清单 11-1 中包含了这个文件中的基本配置指令。虽然该文件包含常见的 Apache 指令,但它引用了其他文件来通过 include 语句配置虚拟主机、模块、端口和 IP 地址,就像我们在 CentOS httpd.conf文件中看到的那样。

ServerRoot "/etc/apache2"
Mutex file:${APACHE_LOCK_DIR} default
PidFile ${APACHE_PID_FILE}

Timeout 300

KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5

User ${APACHE_RUN_USER}
Group ${APACHE_RUN_GROUP}

AccessFileName .htaccess
<FilesMatch "^\.ht">
        Require all denied
</FilesMatch>

HostnameLookups Off
ErrorLog ${APACHE_LOG_DIR}/error.log
LogLevel warn
LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %O" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent

IncludeOptional mods-enabled/*.load
IncludeOptional mods-enabled/*.conf
Include ports.conf

# Include generic snippets of statements
IncludeOptional conf-enabled/*.conf

# Include the virtual host configurations:
IncludeOptional sites-enabled/*.conf

Listing 11-1.Defaults in Ubuntu’s apache2.conf File

Ubuntu 上的默认配置与 CentOS 上的基本相同。然而,Ubuntu 和 Debian 在管理虚拟主机或站点配置的方式上有所不同。最明显的是,您会看到在配置中声明了几个环境变量。这些解析的值可以在/etc/apache2/envvars文件中找到。

同样值得注意的是AccessFileName指令。它指定可能包含服务器配置指令的文件的名称。这个文件被命名为.htaccess,任何 web 目录都可能包含这样一个文件。服务器将检查文件是否存在,并在尝试向连接的客户端提供文件之前处理它包含的任何指令。

因为.htaccess文件可能包含敏感信息,我们应该限制对该文件的访问。以下指令实现了这一点:

<FilesMatch "^\.ht">
        Require all denied
</FilesMatch>

这是一个匹配指令的例子,我们可以匹配任何以.ht ( <FilesMatch "^\.ht">)开头的文件,并拒绝所有访问这些文件的请求(Require all denied)。

Note

不建议使用文件,因为使用它们会对性能产生负面影响。

日志指令描述了我们将如何记录我们的 Apache 信息。您可以通过使用LogFormat指令来决定在 Apache 日志中记录什么。

LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined

Apache 解释字符串中的每个%<value>,并允许您以对自己有用的方式格式化日志输出。在这个LogFormat指令中,我们让 Apache 包含接受请求的虚拟主机的虚拟主机(%v)和端口(%p)。接下来我们有远程主机名(%h)和远程用户名(%l)、认证用户(%u)。记录请求(%r)以及最终状态(%>s)和字节大小(%O)。最后,我们记录 referrer ( %{Referer}i)和 user agent ( %{User-Agent}i),它们利用了 Apache VARNAMEs——可用于记录格式的变量名。这些是从浏览器发送的标头中派生出来的。然后我们将这种日志格式命名为vhost_combined。现在,我们可以在配置中使用这种格式,方法是像这样声明CustomLog:

<VirtualHost *:80>
...
  CustomLog ${APACHE_LOG_DIR}/access.log vhost_combined
...
</VirtualHost>

你可以在 https://httpd.apache.org/docs/2.4/mod/mod_log_config.html#formats 找到更多关于LogFormat选项的信息。在 http://httpd.apache.org/docs/current/expr.html 可以看到 VARNAMEs 中可以使用的变量。

在 CentOS httpd.conf文件中,我们有Listen指令;在 Ubuntu 上,Apache 从ports.conf文件中加载关于应该监听哪些 IP 地址和端口的信息;该文件的默认值如下:

Listen 80

<IfModule ssl_module>
    Listen 443
</IfModule>

<IfModule mod_gnutls.c>
    Listen 443
</IfModule>

在这个文件中,你将看到如何防御性地为模块添加指令。类似超文本标记语言(HTML)的语法<IfModule ssl_module>…</IfModule>表示只有当ssl_module被加载时Listen 443指令才应该被加载。这可以防止 Apache 在模块尚未启用时出错。

Ubuntu 与 CentOS 的不同之处还在于它包含了模块和配置文件,比如虚拟主机。你会看到有IncludeOptional <resource>-enabled/*.conf之类的指令。Ubuntu(当然还有 Debian)利用符号链接来启用模块或配置选项。

管理模块

我们来看看/etc/apache2/mod-available目录。我们已经进入了/etc/apache2目录,并将执行一个mod-available目录的列表。在该目录中,您将找到当前可以在 Apache 启动时加载的模块。事实上,这就是我们选择想要为 Ubuntu 加载的 MPM 的方式。

$ ll mods-available/mpm*
-rw-r--r-- 1 root root 668 Mar 19 09:48 mods-available/mpm_event.conf
-rw-r--r-- 1 root root 106 Mar 19 09:48 mods-available/mpm_event.load
-rw-r--r-- 1 root root 571 Mar 19 09:48 mods-available/mpm_prefork.conf
-rw-r--r-- 1 root root 108 Mar 19 09:48 mods-available/mpm_prefork.load
-rw-r--r-- 1 root root 836 Mar 19 09:48 mods-available/mpm_worker.conf
-rw-r--r-- 1 root root 107 Mar 19 09:48 mods-available/mpm_worker.load

在前面的清单中,您可以看到我们已经讨论过的三种不同的 Apache MPM 引擎。如果我们现在查看/etc/apache2/mod-enabled目录,我们可以看到 Apache 启动时加载了这些模块中的哪一个。

$ ls -l mods-enabled/mpm*
lrwxrwxrwx 1 root root 32 Aug  5 12:18 mods-enabled/mpm_event.conf -> ../mods-available/mpm_event.conf
lrwxrwxrwx 1 root root 32 Aug  5 12:18 mods-enabled/mpm_event.load -> ../mods-available/mpm_event.load

现在你可以看到默认情况下 Ubuntu 将运行 MPM 事件。有一个.conf文件和一个加载文件,一个文件用于配置指令,另一个用于实际加载模块。虽然您可以自己添加符号链接来启用模块,但首选方法是使用 Ubuntu 为此提供的命令。这些命令是用于启用模块(创建符号链接)的a2enmod和用于禁用模块(删除符号链接)的a2dismod

为了展示如何使用这些命令,我们将启用和禁用status模块,该模块允许我们查看 web 服务器的当前状态。首先,为了启用它,我们将发出以下命令:

$ sudo a2enmod status
Enabling module status.
To activate the new configuration, you need to run:
  service apache2 restart

这可以在任何目录下执行,并且需要重启apache2服务。该命令创建了以下符号链接:

$ ls -l mods-enabled/status*
lrwxrwxrwx 1 root root 29 Aug  6 05:08 mods-enabled/status.conf -> ../mods-available/status.conf
lrwxrwxrwx 1 root root 29 Aug  6 05:08 mods-enabled/status.load -> ../mods-available/status.load

现在,让我们使用以下命令禁用该模块:

$ sudo a2dismod status
Module status disabled.
To activate the new configuration, you need to run:
  service apache2 restart

Ubuntu 没有检查目录中的符号链接,而是提供了另一个命令来检查当前的 Apache 设置。a2query命令可用于查找模块的状态,如下所示:

$ a2query -m status
No module matches status (disabled by site administrator)

因为我们刚刚禁用了该模块,所以状态模块被列为禁用。如果模块不存在,您只会看到“没有模块匹配 fakemodule”。a2query也可用于查询其他配置选项,如表 11-1 所述。

表 11-1。

a2query Options

| `-q` | 安静输出,用于脚本 | | `-m ` | 列出已启用的模块,如果没有指定模块,则列出所有模块 | | `-M` | 列出当前的 MPM | | `-s ` | 检查站点是否已启用,如果没有指定站点,则检查全部 | | `-c ` | 列出已启用的配置文件,如果没有指定配置,则列出全部 | | `-d` | 返回`Apache2`模块目录 |
在 Ubuntu 上管理网站

我们将向 Ubuntu web 服务器添加一个虚拟主机,就像我们对 CentOS 主机所做的那样。传统上,Debian(和 Ubuntu)系统管理员倾向于将服务相关的文件放在/srv目录中。在这个例子中,我们不打算遵循这个习惯用法,但是没有理由不能将 web 服务器文件放在/srv/www/var/local目录中或者文件系统上任何其他有意义的地方。为了定义虚拟主机,我们将把清单 11-2 中的指令添加到/etc/apache2/sites-available/ www.example.com 中。

<VirtualHost *>
    ServerName www.example.com
    ServerAlias example.com
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/html/www.example.com
    <Directory /var/www/html/www.example.com>
        Options Indexes FollowSymLinks Includes IncludesNOEXEC SymLinksIfOwnerMatch
        AllowOverride None
    </Directory>
</VirtualHost>
Listing 11-2.Our New Virtual Host Definition

这类似于我们的 CentOS 虚拟主机声明。在这个例子中,我们添加了一些额外的指令。我们首先打开VirtualHost标签,并指定该定义将应用于所有地址。接下来,我们指定希望该虚拟主机回复的名称。只有一个ServerName可以应用于任何给定的虚拟主机,但是其他的可以通过ServerAlias添加。您可以通过使用更多的ServerAlias指令或者通过将额外的主机名添加到由空格分隔的单个ServerAlias来添加额外的别名。

正如我们已经说过的,DocumentRoot指令指定了这个虚拟主机将提供文件的目录。一旦定义了这个,就可以使用Directory指令来指定这个目录及其包含的所有文件和目录的选项。您指定的列表与 CentOS 机器上的列表相同。Options指令列出了在任何特定目录中启用的特性。在表 11-2 中,我们对此处包含的内容进行了解释。通过将AllowOverride设置为None,您拒绝服务器使用来自.htaccess文件的设置来修改这些选项。您可以通过将AllowOverride设置为All来实现这一点,或者使用类似Options=Indexes,MultiViews的东西来更详细地描述什么是允许的。最后,关闭DirectoryVirtualHost指令并保存文件。

表 11-2。

Options

| [计]选项 | 功能 | | --- | --- | | `All` | 除`MultiViews`外的所有选项。 | | `ExecCGI` | 脚本作为应用程序执行,其输出被发送到浏览器。 | | `FollowSymLinks` | 服务器可以跟随符号链接并提供它所指向的文件或目录。 | | `Includes` | 服务器将处理可以嵌入页面的服务器端包含指令。 | | `IncludesNOEXEC` | 服务器端 include 指令可能不会在服务器上执行脚本。 | | `Indexes` | 如果目录中不存在索引页,则在列表中直接显示目录。 | | `SymLinksIfOwnerMatch` | 只有当链接的所有者与链接目标的所有者相同时,服务器才能跟踪符号链接。 | | `MultiViews` | 使用`mod_negotiation`模块,您可以根据客户端的能力指定如何选择内容。 |

我们可以通过使用实用程序a2ensite来启用虚拟主机。像a2enmod一样,这将创建从/etc/apache2/sites-available/etc/apache2/sites-enabled的符号链接。

$ sudo a2ensite www.example.com
Enabling site www.example.com.
To activate the new configuration, you need to run:
  service apache2 reload

您现在可以按照脚本建议的那样做,或者使用sudo apache2ctl graceful手动重新加载服务器配置。您还可以使用a2query来检查站点是否启用,如下所示:

$ sudo a2query -s www.example.com
www.example.com (enabled by site administrator)

我们还可以通过发出以下命令来确保防火墙允许 HTTP 流量通过我们的主机:

$ sudo ufw allow http

这允许 web 流量通过我们的 web 服务。

httpd 性能

有几个旋钮和转盘可以针对 Apache 性能进行调整。一个 Apache web 服务器,在不改变默认设置的情况下,可以处理数百个并发用户。我们将在这里讨论其中的一些。性能是一个相对的主题,您应该使用从您的 web 服务和主机收集的指标来指导您完成这个过程。第十七章将处理指标收集。

大多数文档会告诉你,随机存取存储器(RAM)是首先要考虑的。对于您的 web 应用程序和系统进程,您将需要足够的内存。写密集型应用程序将需要速度适当的磁盘。为此,从系统指标收集的数据将成为您的指南。

以下设置决定了 Apache 如何管理连接超时和保持活动状态:

Timeout 300

KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5

Timeout是连接超时设置,以秒为单位。这可以根据您的要求加长或缩短。KeepAlive设置决定了 Apache 如何处理长时间运行的会话。您可以指定 Apache 服务器应该使用相同的 TCP 连接,而不是为会话创建新的 TCP 连接。您可以使用MaxKeepAliveRequestsKeepAliveTimeout微调这些设置。

不同的 MPM 也有办法调整它们的性能。我们将在这里查看工人和事件 MPM。

对于工作人员和事件绩效,有两个主要的绩效选项可以调整。第一个是ThreadsPerChild,第二个是MaxRequestWorkers. ThreadsPerChild描述每个子进程创建了多少个服务器线程。MaxRequestWorkers确定总共启动的最大线程数。许多 web 浏览器与 web 服务器建立多个连接,因此它们可以同时下载样式表和图像。因此,来自用户的单个 web 连接可以启动多个线程。这意味着每个用户连接都会增加系统资源的数量,例如 RAM 和 CPU 时间。如果您遇到性能不佳的情况,应该调整、监控和优化这些设置。

Apache httpd 文档为一些合理的性能设置提供了一些指导。但是,以下是员工 MPM 的默认设置:

ServerLimit          16
StartServers          3
MaxRequestWorkers   400
MinSpareThreads      75
MaxSpareThreads     250
ThreadsPerChild      25

至于设置,ServerLimit定义了活动线程数量的硬限制。MaxRequestWorkers设置为 400,这是总线程数。该值来自于ServerLimit值乘以ThreadsPerChild值,后者被设置为 25。StartServers是启动的线程的初始数量。MinSpareThreadsMaxSpareThreads定义最小和最大空闲线程。Apache 将根据这些设置来减少或增加可用的空闲线程。

对于事件 MPM,除了对工人 MPM 进行调优之外,还有另外一个性能考虑因素。对于事件 MPM,由于没有线程来处理新请求,这种情况可能会导致线程饥饿。AsyncRequestFactor可以通过限制并发连接数来对空闲线程进行微调。

建议您在测量和调优 Apache 服务器时,将mod_status模块与任何可用的指标收集工具结合使用。

存取限制

在配置部分,我们讨论了使用Require指令来限制对目录的访问。在本节中,我们将向您展示更多关于该指令以及如何使用基本用户名和密码来保护您的站点的信息。

Require指令可以用来限制对目录(和位置)路径的访问。您已经看到它已经被用来保护对.htacess文件的访问。

<FilesMatch "^\.ht">
        Require all denied
</FilesMatch>

这里我们拒绝了对任何以.ht开头的文件的访问。该指令来自mod_authz_core模块。还有其他人扩展了这个模块,比如mod_authz_host,它允许我们基于 IP 授权访问。

举个例子,假设我们有一个名为/var/www/html/ www.example.com/uploads 的目录。我们可以限制只能从内部 IP 地址访问。

<Directory /var/www/html/www.example.com/uploads>
    Options -Indexes -FollowSymLinks
    AllowOverride None
    Require ip 192.168.0
</Directory>

模块mod_authz_host为我们提供了根据 IP 地址限制访问部分站点的功能。在前面几行中,只有远程 IP 地址位于 192.168.0.0/24 子网中的主机才能访问此目录。在表 11-3 中,你可以看到Require指令可用的其他选项。

表 11-3。

Require Options

| `Require all granted` | 无条件允许访问。 | | `Require all denied` | 无条件拒绝访问。 | | `Require env ` | 如果设置了环境变量,则授予访问权限。 | | `Require method ` | 对某些 HTTP 方法授予访问权限。 | | `Require expr ` | 如果表达式为真,则授予访问权限。 | | `Require user ` | 仅向这些用户授予访问权限(`mod_authz_user`)。 | | `Require group ` | 将访问权授予指定组中的用户(`mod_authz_groupfile`)。 | | `Require valid-user` | 将访问权授予授权用户。 | | `Require ip ` | 授予 IP 地址范围内的客户端访问权限。 |

限制访问资源的另一种方法是要求用户输入用户名和密码。许多 web 应用程序在内部进行管理,但是您也可以让 Apache 管理用户名和密码的列表,从而允许您保护特定的目录,而不需要额外的软件。身份验证源可以是文件、数据库或轻量级目录访问协议(LDAP)。我们将向您展示如何执行由文件支持的身份验证。

首先,我们需要创建一个文件,其中包含我们希望通过htpasswd实用程序使用的用户名和密码。我们不想把这个文件放在 Apache 服务器服务的目录中,所以我们创建了一个名为/opt/apache/ www.example.com 的目录,并把我们的密码文件放在那里。通常,我们传递要使用的文件名和要创建的用户作为参数,但是如果文件尚不存在,我们还需要传递-c选项。

$ sudo htpasswd -c /opt/apache/www.example.com/passwords jsmith
New password:
Re-type new password:
Adding password for user jsmith

我们现在可以添加额外的用户,而不需要-c选项。如果我们不想被要求输入密码,我们也可以通过-b选项在命令行上设置。

$ sudo htpasswd -b /opt/apache/www.example.com/passwords ataylor s3kr@t
Adding password for user ataylor

接下来,我们需要告诉 Apache 请求认证。如果您选择在/var/www/ www.example.com 目录中的.htaccess文件中这样做,您将需要添加覆盖AuthConfig选项的能力。我们需要设置AllowOverride AuthConfig,这样才能正常工作。我们不打算添加.htaccess指令;我们将在虚拟主机配置中添加目录级别的身份认证。

    <Directory /var/www/html/www.example.com/uploads>
        Options -Indexes -FollowSymLinks
        AllowOverride None
        AuthType Basic
        AuthName "Restricted Uploads"
        AuthBasicProvider file
        AuthUserFile "/opt/apache/www.example.com/passwords"
        Require valid-user
</Directory>

首先,我们通过AuthType指令指定想要使用的认证类型,在我们的例子中是basic。然后我们需要告诉 Apache 哪个模块将使用AuthBasicProvider,也就是file,提供基本的认证。接下来,我们需要通过AuthUserFile指令告诉 Apache 哪个文件保存了我们的认证信息。

为了帮助用户确定他们试图访问什么,我们可以通过AuthName指令为受保护的资源指定一个名称。当用户被要求提供凭证时,该名称将会显示给用户,如图 11-1 所示,因此让该名称更具描述性会有所帮助。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11-1。

Apache authentication

最后,需要告诉 Apache,只有在用户成功通过身份验证的情况下,才能授予访问权限。我们通过指定Require valid-user来做到这一点。

如果我们现在浏览到 www.example.com/uploads ,浏览器会要求我们输入用户名和密码,如图 11-1 所示。

如果我们不提供有效的用户名和密码,我们将不会被授予访问权限,但是如果我们输入有效的凭证,Apache 将允许我们查看该站点。应该注意的是,我们通过未加密的 HTTP 会话传递凭证,这是一种危险的做法。我们将很快向您展示如何设置一个 HTTP 安全(HTTPS)服务器。

您可以在 Apache 文档站点上阅读更多关于基于主机和基于用户的访问控制的内容。

模块

我们已经讨论了模块,以及它们如何为 Apache 提供额外的功能,并使用LoadModule指令来启用。该指令指定应该加载的模块文件的路径。

在 CentOS 上,额外的模块通常由模块包安装的/etc/httpd/conf.modules.d中的配置片段启用。当服务器重新启动时,它会选取这些新文件并处理它们的指令。您可以通过在文件名前添加一个数字来对这些模块的加载方式进行排序,这是 CentOS 上的默认设置。为了防止包含这样的代码片段,从而禁用该模块,您可以重命名它,使其文件名不再以.conf结尾,或者从目录中移动或删除该文件。您也可以注释(#)文件中的任何指令。

在 Ubuntu 上,模块包将这些代码片段添加到/etc/apache2/mods-available目录中,然后在/etc/apache2/modules-enabled目录中创建指向它们的链接。这些链接也可以使用a2enmoda2dismod命令手动管理,类似于a2ensitea2dissite

http://httpd.apache.org/docs/2.4/mod/ 可以获得关于所有包含的 Apache 模块及其提供的功能的信息。

安装 PHP 支持

许多 web 应用程序都是用 PHP 编写的,PHP 是一种由拉斯马斯·勒德尔夫开发的脚本语言,它为世界各地的许多网站提供支持,包括流行的 WordPress 内容管理系统(CMS)。当您的 web 浏览器从这样的应用程序请求页面时,web 服务器处理页面中的代码,并向您的浏览器显示输出。为了能够托管这些 web 应用程序,web 服务器需要能够理解和执行 PHP 代码。

执行 PHP 有两种方法。您可以通过安装一个模块并使用 prefork Apache MPM 来为 Apache 添加 PHP 支持。然而,我们将使用 worker MPM,由于 PHP 不是线程安全的,我们将使用 FastGGI 进程管理器将 Apache 链接到 PHP。

Note

你可以在 www.php.net/ 阅读所有关于 PHP 的内容。

PHP 本身是模块化的,所以你可以通过安装额外的包来增加 PHP 的功能。我们将很快建立一个 MariaDB 服务器,所以要让 web 应用程序使用它,我们需要在 PHP 中添加 MariaDB 支持。此外,我们将安装对常用的 GD 图形库(用于处理和操作图像文件)、mbstring 字符串转换库(提供对多字节字符串编码的支持)和 IMAP 邮件协议(提供处理 Internet Message Access Protocol[IMAP]和 Post Office Protocol [POP3]功能以处理邮件的能力)的支持。后者将允许我们安装和使用基于 PHP 的 webmail 应用程序。

在 CentOS 上,我们可以通过sudo yum install php-fpm php-mysql php-gd php-imap php-mbstring安装所有这些,在 Ubuntu 上通过sudo aptitude install php-fpm php-mysql php-mbstring php-gd php-imap安装。

在本章的后面,我们将建立一个使用 PHP 的网站。但是在这里,我们将向您展示如何在我们的 CentOS 主机上的虚拟主机中使用 PHP-FPM。

首先,我们需要确保加载了以下模块。如您所知,模块是通过/etc/httpd/conf.modules.d/目录加载的。我们正在寻找两个代理文件。

$ grep -E '(proxy.so|fcgi)' /etc/httpd/conf.modules.d/00-proxy.conf
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so

这些模块分别由 CentOS 和 Ubuntu 的httpd包和apache2包提供。

接下来我们将移走我们的/etc/httpd/conf.d/php.conf文件,因为这是php模块的配置文件。

$ sudo mv /etc/httpd/conf.d/php.conf /etc/httpd/conf.d/php.conf_bak

PHP-FPM 是一个守护进程,它将翻译来自 HTTP 服务器的请求,并用来自 PHP 代码的适当响应进行响应。php-fpm.conf文件配置这个守护进程。PHP-FPM 可以将应用程序分成多个池。您在/etc/php-fpm.d目录中创建池。我们现在要编辑/etc/php-fpm.d/ www.conf 文件并添加下面一行:

; Start a new pool named 'www'.
[www]

; The address on which to accept FastCGI requests.
; Valid syntaxes are:
;   'ip.add.re.ss:port'    - to listen on a TCP socket to a specific address on
;                            a specific port;
;   'port'                 - to listen on a TCP socket to all addresses on a
;                            specific port;
;   '/path/to/unix/socket' - to listen on a unix socket.
; Note: This value is mandatory.
listen = 127.0.0.1:9000
listen = /run/php-fcgi.sock

编辑完该文件后,您需要重启php-fpm。你可以用$ sudo systemctl restart php-fpm在 CentOS 上做到这一点。您现在应该注意到在/run目录(这是一个特殊的内存目录)中创建了一个套接字文件。

$ ll /run/php-fcgi.sock
srw-rw-rw-. 1 root root 0 Aug 16 09:49 /run/php-fcgi.sock

一旦完成,我们就可以运行 PHP 网站了。剩下要做的就是在我们的 HTTP 配置中添加一个ProxyPassMatch指令来匹配任何.php文件,并将它们传递给 PHP-FPM 守护进程。

<VirtualHost *:80>

  ServerName www.example.com
  ServerAdmin webmaster@example.com
  DocumentRoot  /var/www/html/www.example.com
  DirectoryIndex index.php
  ProxyPassMatch ^/(.*\.php(/.*)?)$ unix:/run/php-fcgi.sock|fcgi://127.0.0.1:9000/var/www/html/www.example.com/
  <Directory /var/www/html/www.example.com>
     Require all granted
  </Directory>
</VirtualHost>

虚拟主机现在已经准备好处理我们的 PHP 应用程序,我们将在本章的后面安装它。ProxyPassMatch允许我们使用正则表达式来匹配统一资源定位符(URL ),并将请求传递给代理后端。我们提供代理监听的位置,并给它我们将安装 PHP 代码的目录的位置。

你可以在这里阅读更多关于mod_proxy的指令,包括ProxyPassMatch指令:

文件和目录权限

当您使用网站时,您需要对安装网站的文档根目录具有写权限。同时,Apache 用户需要不能写入相同的目录,因为这可能允许匿名 web 用户在发现网站中的漏洞时向您的系统写入文件。

如果多个用户将管理网站,为此创建一个组是个好主意。只要该组对文档根目录具有写权限,您添加到该组的任何用户都将能够写文件和创建目录。很多时候,web 应用程序是由部署用户自动部署的。

Tip

使用一个特定的系统组来管理网站也意味着你可以允许这个组的成员通过sudo使用apachectlapache2ctl命令,而不需要给他们完全的根访问权限。

为了确保一个用户创建的文件可以被同一组中的另一个用户修改,您需要设置umask选项,以便任何新创建的文件和目录都可以被该组写入。您还需要设置setgid位,以便新的文件和目录将从拥有父目录的组继承所有权,而不是碰巧创建了有问题的文件或目录的用户的主要组。稍后,当我们安装一些 web 应用程序时,我们将向您展示一个这样的示例。

Tip

您可以在 http://httpd.apache.org/ 找到更多信息和 Apache 文档。

SQL 数据库

因为许多基于 web 的应用程序使用 SQL server 来存储数据,所以我们还将向您展示如何安装 SQL server。我们将向您展示如何安装 MySQL 数据库服务器的一个名为 MariaDB 的分支。数据库服务器提供数据存储和检索,而客户端可以是使用数据库服务器的任何应用程序,可以是命令行实用程序、LibreOffice 或网站使用的库。

因为 MariaDB 是 MySQL 的一个分支,所以它是 MySQL 数据库的直接替代。在 MariaDB 中,MySQL 的许多命令都是相同的,配置和环境变量也是相同的,因此很容易在这些数据库之间进行交换。MariaDB 之所以产生,是因为 MySQL 被甲骨文公司收购后,MySQL 的前开发者希望在 GNU 通用公共许可证(GNU GPL)许可下保持免费。

MariaDB 仍然将 MySQL 中的代码或移植代码合并到其代码库中,尽管它们不相同,但 MariaDB 的版本可以映射到 MySQL 的版本。直到 MariaDB 的 5.5 版本,MariaDB 一直保持着与 MySQL 相同的版本号。但是最近它把发布号改成了 10.x,这可能会让事情变得更加混乱。下表 11-4 说明了这些版本。

表 11-4。

MariaDB to MySQL Versions

| MariaDB 5.5 | MariaDB 5.3 和 MySQL 5.5 | | MariaDB 10.0 | MariaDB 5.5 和后端口 MySQL 5.6 | | MariaDB 10.1 | 包含 MySQL 5.6 和 5.7 的端口 | | MariaDB 10.2 | Alpha 版本 |

Note

对于这些版本号变化背后的原因的解释,见 https://mariadb.org/explanation-on-mariadb-10-0/

装置

在 CentOS 和 Ubuntu 上,您可以使用软件包管理器轻松安装 MariaDB。在 CentOS 上,MariaDB 通过mariadb-server包安装。

$ sudo yum install mariadb-server

在 Ubuntu 上,服务器组件由mariadb-server-core-10.0包提供(编写时)。你可以通过虚拟包安装它。

$ sudo aptitude install mariadb-server.

初始配置

您需要进行一些基本的配置更改。默认情况下,在 CentOS 上,MariaDB 服务器监听所有已配置的网络接口和地址上的连接。因为我们将 web 服务器和数据库放在同一台主机上,所以我们将限制数据库只监听环回地址。这更安全,但是在理想情况下,我们应该将数据库服务器和 web 服务器放在不同的主机上。对于 Ubuntu,如果您检查/etc/mysql/mariadb.conf.d/50-server.cnf配置文件,您会看到下面的 bind-address 指令已经存在。

在 CentOS 上,我们在文本编辑器中打开/etc/my.cnf,并在[mysqld]部分下添加以下行:

bind-address = 127.0.0.1

这里我们指示数据库服务器只监听环回地址,这样可以防止其他主机访问我们的数据库。当我们希望其他主机访问我们的数据库时,我们需要更改它,在适当的接口上监听。我们的新配置文件将类似于清单 11-3 。

[mysqld]
bind-address = 127.0.0.1

datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0

[mysqld_safe]
log-error=/var/log/mariadb/mariadb.log
pid-file=/var/run/mariadb/mariadb.pid

!includedir /etc/my.cnf.d

Listing 11-3.Our /etc/my.conf on CentOS

可以为 MariaDB 服务器配置许多不同的设置。您可以在这里找到一些有用的文档:

我们现在可以通过systemctl命令启动 MariaDB 服务器,如清单 11-4 所示。

$ sudo systemctl start mariadb
Listing 11-4.MariaDB First Run on CentOS

服务器现在正在运行,因此我们可以设置一个 root 密码并清理默认表。我们可以在 CentOS 和 Ubuntu 上这样做。有一个名为mysql_secure_installation的实用程序将为我们做这件事。

$ sudo mysql_secure_installation

NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB
      SERVERS IN PRODUCTION USE!  PLEASE READ EACH STEP CAREFULLY!

In order to log into MariaDB to secure it, we'll need the current
password for the root user.  If you've just installed MariaDB, and
you haven't set the root password yet, the password will be blank,
so you should just press enter here.

Enter current password for root (enter for none):
OK, successfully used password, moving on...

Setting the root password ensures that nobody can log into the MariaDB
root user without the proper authorisation.

Set root password? [Y/n] y
New password:
Re-enter new password:
Password updated successfully!
Reloading privilege tables..
 ... Success!

to log into MariaDB without having to have a user account created for
them.  This is intended only for testing, and to make the installation
go a bit smoother.  You should remove them before moving into a
production environment.

Remove anonymous users? [Y/n] y
 ... Success!

Normally, root should only be allowed to connect from 'localhost'.  This
ensures that someone cannot guess at the root password from the network.

Disallow root login remotely? [Y/n] y
 ... Success!

access.  This is also intended only for testing, and should be removed
before moving into a production environment.

Remove test database and access to it? [Y/n] y
 - Dropping test database...
 ... Success!
 - Removing privileges on test database...
 ... Success!

Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.

Reload privilege tables now? [Y/n] y
 ... Success!

Cleaning up...

All done!  If you've completed all of the above steps, your MariaDB
installation should now be secure.

Thanks for using MariaDB!

我们的服务器现在是安全的。它不接受来自远程主机的连接,也不允许没有 MariaDB 帐户的用户进行连接。为了确保它在引导时启动,我们将使用systemctl命令在引导时启用mariadb

$ sudo systemctl enable mariadb

让我们现在测试我们的服务器,以确保我们可以连接到它。

测试服务器

为了检查 MariaDB 服务器是否正在运行,我们可以通过命令行客户端连接到它。我们需要指定-u选项来指定要连接的用户(图 11-2 )。-p选项将提示我们输入相关密码。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11-2。

Signing in to MariaDB

我们能够连接并运行查询;MariaDB 服务器工作正常。请注意,根据安装的 MariaDB 服务器版本,主机上返回的版本字符串可能会有所不同。在 Ubuntu 上,你可以通过sudo命令访问mysql命令行。

$ sudo mysql

MariaDB 存储引擎

MariaDB 有几种不同的存储引擎,旨在更好地满足不同数据集的要求。默认引擎称为 XtraDB,是一个符合原子性、一致性、隔离性、持久性(ACID)属性和多版本并发控制(MVCC)的数据库;对于大多数应用程序类型来说,这通常是一个不错的选择。

还有其他几个可用的。表 11-5 中列出了您可能感兴趣的主要产品。

表 11-5。

MariaDB Storage Engines

| 档案馆 | 数据存档 | | --- | --- | | 咏叹调 | 增强的 MyISAM 数据库 | | 卡桑德拉 | 访问 Cassandra 集群中数据的 NoSQL 存储引擎 | | 连接 | 允许像访问数据库表一样访问文本文件 | | ScaleDB | 商业大规模高可用性(HA)/耐用数据库存储引擎 | | 蜘蛛;状似蜘蛛的物体;星形轮;十字叉;连接柄;十字头 | 允许通过分片无共享架构访问分布式数据库 | | 德 DB(德 db) | 高性能写入密集型数据库 | | XtraDB | MySQL InnoDB 的直接替代 |

通过发出图 11-3 中的命令,可以看到已经安装的引擎列表。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11-3。

Showing database engines

在图 11-3 中,您可以看到默认安装的数据库引擎。你可以看到 XtraDB 仍然被称为 InnoDB 引擎,你可以看到每一个都支持什么。

XtraDB 的基本调谐

所有的性能调优通常涉及这三个方面:硬件、操作系统和数据库配置。硬件相当容易;对于数据库,一般规则是更快的磁盘、更快的 CPU 和更多更快的内存。操作系统有许多性能调整,包括磁盘挂载选项、sysctl设置、内核调度程序等等。通过数据库调优,我们有许多配置选项和数据库优化策略。我们将专注于 MariaDB 的 XtraDB 引擎的基本调校。

要显示 MariaDB 的当前设置,可以从命令行发出以下命令:

MariaDB [(none)]> show variables;

这个命令产生一个当前存储在 MariaDB 中的所有变量的长列表。要查看单个设置,我们可以使用图 11-4 所示的 SQL。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11-4。

Listing environment variables

在图 11-4 中,我们使用了 SQL like子句来搜索show variables列表中的innodb_fast_shutdown变量并显示其设置。

How Innodb Stores Data

InnoDB 和 XtraDB 有两层数据存储设计。存储在磁盘上的数据位于/var/lib/mysql目录中。在这个目录中有ibdata1ib_logfile0ib_logfile1文件。ibdata1文件包含系统和用户数据,ib_logfile0ib_logfile1文件是重做或事务日志。数据库是在/var/lib/mysql/<databasename>目录下的目录中创建的。这些数据库中的表存储在/var/lib/mysql/<databasename>/<tablename.frm>中。

当表中的数据在内存中发生变化时(例如,因为您插入了一条记录),InnoDB 会将其存储在重做日志中。当这些事务日志写满时,MariaDB 服务器将这些更改的数据记录刷新到表文件中。

其中一个原因是性能,就像日志文件系统一样。通过一次执行所有这些操作,磁盘写入效率更高。另一个原因是持久性,因为当系统从意外崩溃中恢复时,这些日志可以用来重放事务。

当 MariaDB 服务器关闭时,它不会处理这些事务日志,因此它们通常包含实时数据。这意味着不能简单地通过删除和重新创建来增加或减少它们的大小。

我们可以做的一个简单的性能调优是更改重做日志的默认大小。如果文件太小,它会很快填满,这意味着 SQL server 会不断清空该文件,从而降低性能。如果文件太大,则恢复时间可能会延长。

在图 11-5 中,我们可以看到 MariaDB 5.5 的日志文件大小,默认为 5MB。MariaDB 10.0 和更高版本的默认值为 48MB。对于较旧的 MariaDB 5.5 版本,在我们更改 InnoDB 事务日志文件大小之前,我们需要确保事务日志文件不再包含任何实时数据。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11-5。

Redo log file size

我们可以通过强制服务器处理事务日志中的所有条目,并在关闭服务器时将它们写入表文件来做到这一点。这个行为是由变量innodb_fast_shutdown控制的,我们可以在一个正在运行的服务器上更改这个变量,方法是以root用户的身份连接到它,然后运行查询SET GLOBAL innodb_fast_shutdown=1,如清单 11-5 所示。

MariaDB [(none)]> SET GLOBAL innodb_fast_shutdown = 1;
Query OK, 0 rows affected (0.00 sec)
Listing 11-5.Forcing an InnoDB Transaction Log Flush at Shutdown

我们现在可以关闭 MariaDB 服务器,它将把所有挂起的更改从事务日志刷新到表文件中。这意味着我们可以安全地将现有文件移走,并更改事务日志文件的大小。在 CentOS 上,我们通过sudo systemtctl stop mariadb来实现。

日志文件被称为ib_logfile0ib_logfile1,它们可以在/var/ lib/mysql目录中找到。我们将把这两个文件都移走,以便 MariaDB 服务器可以在下次启动时创建新的文件。

$ cd /var/lib/mysql
/var/lib/mysql$ sudo mv ib_logfile* /root

Caution

在验证 MariaDB 服务器可以使用其新配置之前,不要删除这些日志文件。

我们现在可以编辑配置文件了。在 CentOS 上,该文件是/etc/my.cnf.d/server.cnf。这个文件在 CentOS 上相对来说是空的,所以您可以简单地添加我们稍后会给您的配置指令。

在 Ubuntu 上,安装的是 MariaDB 10.0.25。默认情况下,日志文件大小为 48MB,因此通常不需要更改。但是,如果您确实需要更改它,您只需要编辑文件/etc/mysql/mysql.conf.d/mysqld.cnf并添加或更改innodb_log_file_size。然后,在 Ubuntu 上,你需要重启mysql服务(是的,Ubuntu 目前用mysql服务运行 MariaDB)。

我们在这里做的所有更改都在[mysqld-5.5]部分(CentOS)或[mysqld]部分(Ubuntu)下。

innodb_log_file_size = 48M
innodb_log_buffer_size = 16M
innodb_log_files_in_group = 2
innodb_buffer_pool_size = 128M
innodb_flush_method = O_DIRECT

我们将 InnoDB 事务日志文件大小设置为 48Mb,内存中的日志缓冲区设置为 16Mb。这些值意味着服务器将使用多一点的 RAM,但它需要访问磁盘的频率将会降低,从而获得更好的性能。我们通过innodb_log_files_in_group告诉服务器它有两个事务日志文件,这是默认的。

接下来,我们需要为服务器分配一些 RAM 来保存表数据和执行查询。这个数量由innodb_buffer_pool_size变量控制,我们将其设置为 128Mb。在运行 MariaDB 和其他服务的现代服务器上,这应该是一个合理的数量。在专用服务器上,它可以设置为 80%的可用内存。

我们可以通过设置innodb_flush_method告诉服务器不要在操作系统磁盘缓存中缓存任何数据。毕竟,数据存储在我们为 InnoDB 缓冲池保留的内存中。通过指定O_DIRECT,我们通过定期将数据刷新到磁盘来防止系统在 RAM 中保存数据的两个副本。默认情况下,它是未设置的,有几个选项可供选择。根据您的情况和版本,您可能会选择ALL_O_DIRECT(对于大型 InnoDB 数据库文件)。

当数据不在 RAM 中,需要从磁盘写入时,MariaDB 默认一次读取一个很小的 128KB 的数据块。这可以节省内存使用,但当需要读取大量数据时,速度会非常慢。我们将通过read_buffer_sizeread_rnd_buffer_size变量增加这个块的大小。

read_buffer_size = 1M
read_rnd_buffer_size = 1M

我们还将允许服务器执行非常大的查询,因此可以存储更多的数据。默认值为 1Mb(在旧版本上);我们将把它改为 16Mb。

max_allowed_packet = 16M

最后,我们将通过设置log_bin变量来启用二进制日志。这将有助于我们在撞车时恢复。

log_bin  = /var/log/mariadb/mariadb-bin.log
expire_logs_days = 14
max_binlog_size = 128M

bin 日志或二进制日志用于数据库上的复制事务。插入、更新和删除都记录在其中,并且可以在辅助服务器上重放以保持同步。管理员也可以使用它们来恢复数据库的备份。在前面的代码中,我们告诉服务器在 14 天后自动清除二进制日志。这意味着我们应该至少每两周备份一次 MariaDB 数据。(我们将在第十四章介绍如何实现备份过程的自动化。)最后,我们告诉服务器,一旦当前的二进制日志文件达到 128Mb,就启动一个新的二进制日志文件。这使得 bin 日志更易于管理,并且可以更快地传输到任何二级或三级数据库。我们还在独立于主数据库文件的位置创建了它们,最好是在它们自己的磁盘或分区上。

我们现在已经完成了基本的 MariaDB 服务器调整,所以我们可以通过 CentOS 上的sudo systemctl start mariadb或 Ubuntu 上的sudo systemctl start mysql重新打开它。要验证 MariaDB 服务器是否运行良好并创建了新的 InnoDB 事务日志文件,您可以检查日志。在 CentOS 上,mariadb写入/var/log/mariadb/mariadb.log文件;在 Ubuntu 上,它使用的是/var/log/syslog文件。

请注意,我们没有针对高端性能调整 MariaDB 服务器;我们刚刚修改了基本配置,以提供更好的数据完整性,并比正常情况下执行得更好。如果您需要极高的性能或高级功能,如跨多个服务器的数据复制,我们建议您阅读 Baron Schwartz 等人的《高性能 MySQL,第三版》(O’Reilly Media,Inc .,2012)。

基本 MariaDB 管理

正如您已经看到的,MariaDB 有一个用户和密码的内部列表。这意味着您需要知道如何管理 MariaDB 用户,因为您不希望所有应用程序都以root的身份连接到 MariaDB 服务器。我们将演示如何通过命令行mysql客户机创建和删除数据库和用户。

数据库

在 MariaDB 中创建数据库很容易。您通过命令行实用程序连接到服务器并发出CREATE DATABASE语句,将数据库名称作为参数给它,如图 11-6 所示。(注意,为了清楚起见,我们在 SQL 语句中使用了大写字母;如果你使用小写,他们仍然会工作得很好。)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11-6。

Creating a new database in MariaDB

在图 11-6 中,你可以看到我们创建了一个名为mydb的数据库,然后我们切换到那个数据库并检查它是否包含任何表。你会注意到,当我们切换到mydb数据库时,我们的提示也从[(none)]变成了[mydb],表示我们正在处理的当前数据库。请注意,我们使用了反引号来引用数据库名称。在这种情况下,没有明确的必要这样做,但是数据库、表和列的名称有时可以包含一个保留字符,如连字符。例如,如果你想创建一个名为my-db的数据库,你需要使用反引号;否则,MariaDB 会将my-db解释为从my列的值中减去db列的值。由于这两列都不存在,将会产生一个错误,如图 11-7 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11-7。

The importance of proper quoting

使用引号,数据库以指定的名称创建。

Tip

命名数据库和表时,通常最好只使用字母数字字符和下划线字符。即使这样,适当的引用也是一个好习惯。

但是我们不需要这个数据库,所以我们将再次删除它。我们通过DROP DATABASE语句做到这一点。

MariaDB [mydb]> DROP DATABASE `my-db`;
Query OK, 0 rows affected (0.00 sec)

Caution

您不能撤销一个DROP DATABASE命令,即使您在一个事务中运行它然后回滚也不行。在这样做之前,请仔细考虑,并确保在删除数据之前创建了备份。

用户和权限

特权是通过GRANT语句管理的。该语句接受一组参数,这些参数定义了允许给定主机上的用户对特定对象执行的一组操作。

实际上,您通常只需创建一个用户,允许他在单个数据库上执行所有操作。

这意味着每个使用自己数据库的应用程序都有自己的 MariaDB 登录。如果某个应用程序包含允许访问数据库服务器的错误,那么只有该应用程序使用的数据会受到威胁。

我们以 root 身份连接到 MariaDB 服务器,然后创建一个名为jsmith的用户,就像我们的主机帐户一样,他可以访问所有数据库和表并创建新用户。这样我们就不需要继续使用 MariaDB root账户了。

图 11-8 中的代码创建了一个名为jsmith的用户,他只能用密码“secret”从本地主机连接ALL关键字指定用户拥有所有权限。我们使用简写*.*来表示所有数据库中的所有表格。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11-8。

Creating a GRANT for users

我们可以通过使用mydb.*来限制对名为mydb的单个数据库中的表的访问。最后,我们指定了GRANT OPTION,它允许这个用户使用GRANT语句。表 11-6 显示了可能的特权。

表 11-6。

GRANT Privileges

| `SELECT` | 提供执行`SELECT`语句的能力 | | `INSERT` | 提供执行`INSERT`语句的能力 | | `UPDATE` | 提供执行`UPDATE`语句的能力 | | `DELETE` | 提供执行`DELETE`语句的能力 | | `INDEX` | 提供在表上创建索引的能力 | | `CREATE` | 提供创建数据库表的能力 | | `ALTER` | 提供改变数据库表的能力 | | `DROP` | 提供删除数据库表的能力 | | `GRANT OPTION` | 能够向其他用户授予相同的权限 | | `ALL` | 授予除`GRANT OPTION`之外的所有权限 |

让我们以刚刚创建的用户身份登录,并创建一个只能访问mydb数据库的用户。我们现在不需要指定一个 MariaDB 用户来连接,因为我们刚刚创建了一个与我们的主机帐户同名的 MariaDB 用户。

要做到这一点,就像我们在图 11-9 中看到的那样,将以下参数传递给mysql客户端。我们使用–h连接到本地主机,-u表示我们想要连接的用户,–p表示我们将提供一个密码。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11-9。

Creating user accounts

我们现在有一个名为mydb的用户,他只能访问mydb数据库中的表。由于我们目前不需要这个用户,我们将向您展示如何通过从系统中删除mydb来删除该用户。

MariaDB [(none)]> DROP USER `mydb`@`localhost`;
Query OK, 0 rows affected (0.00 sec)

由于我们也不需要mydb数据库,我们也将删除它。

MariaDB [(none)]> DROP DATABASE `mydb`;
Query OK, 0 rows affected (0.00 sec)

教授 SQL 和 MariaDB 管理技能超出了本书的范围,但是这些基本技能将允许您通过遵循安装说明来设置大多数基于 MariaDB 的 web 应用程序。许多网站致力于教授 MySQL 和 MariaDB 技能,以下资源也是很好的信息来源:

管理网站内容

有了可用的 web 和 SQL server,您现在可以安装一些 web 应用程序来增强您的在线状态。在本节中,我们将向您展示如何在自己的虚拟主机上安装一些 web 应用程序。我们不会向您展示如何使用这些 web 应用程序,因为大多数都附带了优秀的文档和支持社区。

我们将首先创建一个名为www的组,我们将向其中添加任何需要能够修改网站安装的用户,并且我们将自己添加到该组中。我们可以通过-K参数覆盖这个组的默认umask

$ sudo groupadd -K UMASK=0002 www
$ sudo usermod -G www jsmith

一旦我们注销并重新登录,组成员资格更改将生效。

接下来,我们将更改 /var/www/html/www.example.com 目录及其包含的任何目录的所有权和权限,以便www组可以完全访问它。

$ sudo chgrp -R www /var/www/html/www.example.com
$ sudo chmod u+rwx,g+srwx,o+rx /var/www/html/www.example.com

除了完整的权限字符串,我们还可以指定八进制模式 2775。在 CentOS 上,web 服务器作为apache用户运行,在 Ubuntu 上,它作为www-data用户运行,您需要根据需要chown文件和目录。

$ sudo chown www-data -R /var/www/html/www.example.com

网络状态

当然,你会希望你的企业有一个网站,当然这从来没有这么容易实现。为此,我们将安装一个 CMS 作为我们的网站。

CMS 允许我们将精力集中在创建内容并使其看起来不错,同时为我们提供了一个框架,可以保存页面的多次修订,将 web 内容与图形设计分开,并管理用户和员工的访问权限。

PHP 是世界上最流行的网站框架之一,而用于开发网站的最流行的工具之一叫做 WordPress。我们将在 www.example.com 虚拟主机上安装 WordPress。当然有很多 CMSs 我们选择 WordPress 是因为在其他基于 PHP 的 CMSs 中,它是最简单和最广泛的。你还有其他选择;您可以考虑以下方法之一:

该软件从 https://wordpress.org/download/ 开始以 tarball 的形式提供。在撰写本文时,最新的版本是 WordPress 4.5.3。我们将使用curl命令将其下载到我们的主目录。

$ curl https://wordpress.org/latest.tar.gz -o wordpress.tar.gz

接下来,我们打开 tarball。我们可以在这里将其解包,然后将所需的文件和目录移动到 web 根目录,或者我们可以直接将其解包到 web 根目录。我们将通过告诉tar从归档中去除第一个目录组件并使用-C选项指定一个目标目录来实现后者。

$ sudo tar -xz --strip-components=1 -C /var/www/html/www.example.com/ -f wordpress.tar.gz

Tip

要找出一个 tar 存档包含哪些目录,使用-t-v选项显示一个文件列表,而不提取它们(例如tar -tvzf wordpress.tar.gz)。

我们现在需要创建一个新的数据库和一个新的数据库用户。我们就像之前展示给你的那样做。

MariaDB [(none)]> CREATE DATABASE example;
MariaDB [(none)]> GRANT CREATE, SELECT,  INSERT,  UPDATE,  DELETE  ON example.*
  TO  `wpexample`@`localhost` IDENTIFIED BY 'secret';

我们在那里做了什么?我们只授予了 WordPress 通常需要的数据库的必要权限。这符合最小特权访问原则,我们只提供用户需要的权限,不提供更多。我们还为该用户使用了一个不太好的密码示例。

WordPress 站点有一个需要编辑的配置文件,描述了数据库细节和一些密钥。我们可以复制这个文件,并将其重命名为所需的名称。我们将进入 www.example.com 目录来编辑这些文件。

$ sudo cp wp-config-sample.php wp-config.php

在我们编辑wp-config.php文件之前,请访问这个站点,它创建了配置文件中所需的随机密钥: https://api.wordpress.org/secret-key/1.1/salt/ 。这些密钥用于对会话 cookies 进行签名,您可以随时更改它们(任何已登录的用户都必须重新登录)。我们只是复制了这些钥匙。

define('AUTH_KEY',         'yr-[fb[mc=0ef:L9 Px|6∼al0PwR<KrxOy!|%g??@hD&hPh(=1J-DWO9pSWGiuic');
define('SECURE_AUTH_KEY',  '24|Nn+<)pFE@6Ity9LwMrDT!|JYe*JQFQm+qb(#[2-J?|c!U|$5/$rr;_wln∼p-a');
define('LOGGED_IN_KEY',    'D_OYeZJLx∼,/bB^]l1-?dDIni1StB(z-/-2FQSd^:}2.l|]uJXlMW%,<h6Q!k9x^');
define('NONCE_KEY',        ' 7=5Z7c4%tO!b@HAD= [n0by2Unrp^Et@.h-&3S2SrxdLL6gKV>3<o+dVj;,BI^h');
define('AUTH_SALT',        'ZYV|3qST=QVlH^MsccnF;k,-yKa=oq&x8iA|ohNN,6j.Y:o_,9zp$XBPzO3UcI^i');
define('SECURE_AUTH_SALT', 'vvC.{}1RjuE2I!yRs?]D/iHmZ3rbf->bHzpAlz?tR]$Nt..#=5{WC52#ty#C93+]');
define('LOGGED_IN_SALT',   'JZ>-u/:oUbhdK4qgJ.n_ReUi%Lj∼J(t8{MI?kme#.U[qF:aZw*zpwIoc^:#4/[$O');
define('NONCE_SALT',       'T%|]FT^^!.:[sL}S4-DXz{o)R*TasHB.eh}<hknQjuK|R&yW⁵ff9M-f{KlC-I@4');

现在,当您编辑wp-config.php文件时,您可以在删除带有put your unique phrase here字符串的行之后,将您的密钥粘贴到“认证唯一密钥和 Salts”部分。接下来,您还应该添加我们在上一节中创建的数据库细节。

有了正确位置的站点内容,我们现在可以将 web 浏览器指向 www.example.com/wp-admin/install.php 。这将允许我们开始基于网络的安装过程,如图 11-10 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11-10。

WordPress installation

要继续,我们点击继续安装我们本地语言的 WordPress。下一页如图 11-11 所示,让我们有机会命名我们的网站并提供管理细节。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11-11。

Entering the web site details and admin credentials

记得把你的密码记在安全的地方;你很快就会需要它。完成后,我们会看到成功页面,并提供一个登录按钮(图 11-12 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11-12。

Successfully installed WordPress

下面给大家快速展示一下登录流程。首先,我们通过刚刚创建的用户名和密码获得访问权限(图 11-13 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11-13。

Logging in

登录后,我们就可以访问 WordPress 管理控制台(图 11-14 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11-14。

WordPress admin console

使用 SSL/TLS 证书保护您的 Web 服务

拥有安全的 web 服务几乎被认为是强制性的。保护您的 web 服务有很多原因,而不保护它们的原因很少。适当保护的 web 服务器通信不仅可以防止对您的通信(如用户名和密码或信用卡信息)的任何窃听,还可以阻止对 cookies 或会话信息的窥探,并有助于防止跨站点脚本和恶意代码注入。谷歌现在使用 HTTPS 作为排名信号,这意味着如果你的网站完全加密,那么你的排名将高于相同内容的未加密网站。

我们将讨论 TLS,然后向您展示如何创建自己的证书颁发机构(CA ),最后我们将安装由 Let’s Encrypt 提供的证书。

TLS 和证书

TLS 使用数字证书和一种称为公钥加密的加密技术。公钥加密使用两个密钥:公钥是公开的,私钥存储在服务器上并保密。使用公钥加密的任何内容只能用相应的私钥解密;这与第十章的“DNSSEC”边栏部分描述的概念相同。

Note

数字证书和公钥加密是复杂的话题。这只是给你使用 TLS 的基础知识的一个介绍。如果你真的对这背后的数学感兴趣,我们推荐这本优秀的书:《应用密码学:协议、算法和 C 语言源代码》,20 周年纪念版,作者 Bruce Schneier (John Wiley & Sons,2015)。

使用 TLS 时,数字证书是服务器的公钥,其作用类似于电子驾照。它标识您正在连接的服务器或网站。当你连接到一个 HTTPS 网站时,你的浏览器所做的是接受该网站的数字证书作为该网站是它所声称的那个网站的证据。像驾照一样,证书也有有效期,并且只在固定的时间内有效,通常是 12 个月。

每个数字证书还可以包含对证书颁发机构的引用。CA 是一种颁发证书的机制,它有一个称为根证书的特殊证书,用于验证服务器证书的真实性。用同样的许可证比喻,根证书就像您所在州的机动车部门。人们去那里检查你是否有有效的执照,以及你是否是你所说的那个人。这些根证书通常与用于连接服务器的客户端捆绑在一起;例如,您的 web 浏览器将拥有来自知名 ca 的根证书集合。

因此,基于证书的加密的基本流程(简单来说)如下:

  1. 您的客户端连接到服务器并请求证书。
  2. 服务器出示其证书。
  3. 客户端检查对根证书的引用。
  4. 客户端使用捆绑的根证书来验证您的证书是真实的。
  5. 如果您的客户端信任该证书,则使用服务器的公共证书在客户端和服务器之间启动并加密连接。

Tip

在某些情况下,您的客户端会告诉您不确定是否信任该证书,并提示您决定是否信任该服务器。

您需要了解四种类型的证书,使用每种类型都有利弊。

  • 由商业 CA 颁发的证书
  • 由非商业性 CA 颁发的证书
  • 由自我管理的 CA 颁发的证书
  • 自签名证书
商业证书颁发机构颁发的证书

来自商业 ca 的证书由流行的提供商(如 VeriSign、Thawte 或 Comodo)颁发。这些证书通常要求定期付款,例如一年或两年一次。价格取决于证书的类型和数量。大多数商业 ca 的根证书与客户端捆绑在一起,如浏览器、邮件客户端和其他使用 SSL/TLS 连接的工具。通常会定期对商业 ca 进行安全性审核,并且由它们颁发的证书通常被认为是安全的。

来自非商业证书颁发机构的证书

除了商业证书提供商之外,还有少量非商业证书提供商。这些提供商不对他们的证书收费,但相应地,他们的根证书有时并不与许多浏览器捆绑在一起。这意味着如果您将这些证书用于网站或保护简单邮件传输协议(SMTP)之类的服务,您的客户端很可能会警告您无法确定证书的有效性和安全性。

如果浏览器中没有安装 CA 的根证书,唯一的解决方法是手动将非商业 CA 的根证书添加到浏览器中。如果您有很多客户端浏览器,这会给您的环境增加很多开销和维护。在许多情况下,例如在网站上,您无权访问客户端,这些错误可能会导致某人收到客户端无法验证证书的消息,从而不信任您的网站。例如,这使得在电子商务网站上使用非商业证书成为问题。

然而,最近情况发生了变化。为了使互联网更加安全,人们大力推动对互联网进行加密。不在网站上使用 HTTPS 的原因之一是证书太贵,而且非商业证书没有得到广泛支持,正如我们提到的。互联网安全研究小组(ISRG)决定创建“让我们加密”来解决这个问题。

Let’s Encrypt 是一个非营利组织,致力于通过提供一种简单的自动机制来获取和安装 TLS 证书,从而帮助加密互联网。让我们加密根 CA 也捆绑在许多现代浏览器中,这解决了非商业 CA 面临的许多问题。你可以在 https://letsencrypt.org/ 找到更多关于 Let’s Encrypt 的信息。

获得非商业证书的另一种方法是使用 CAcert。它提供免费的临时证书(如 Let’s Encrypt ),但也允许您拥有更长的证书,如果您传递一个验证域所有者的“信任密钥”。欲了解更多信息,请访问 CAcert 网站和 wiki: www.cacert.org/http://wiki.cacert.org/wiki/

来自自我管理的证书颁发机构的证书

您也可以创建和管理自己的证书。这些证书由您自己创建和管理的证书颁发机构颁发。因此,这些证书不需要花费任何钱,但是它们确实有其他问题。首先,既然是自己的 CA,就不能指望别人信任你的证书。这就引出了第二个问题:可用性。您的 CA 的根证书不与客户端捆绑在一起,将来也不会。所以如果你想安装我们的根证书,你需要通过软件管理来完成(比如 Ansible 或 Puppet,在第十九章中讨论)。

Note

在非商业 ca 的情况下,至少有少量的客户端捆绑了它们的根证书。在您自己的自我管理 CA 的情况下,拥有您的根证书的客户端是您自己安装的。

因此,例如,当您的 web 客户端尝试验证您的 CA 提供的证书时,会生成一条错误消息,指示客户端不信任该 CA。其他服务可能会拒绝使用有效证书进行连接。为了克服这个错误,您需要在客户端上安装 CA 的根证书。这是您可以为您管理的客户端(例如,您的内部桌面)做的事情,但对其他人来说这是不可行的。

Tip

在这种模式下,您必须保护和管理自己的 CA。对于少量的证书来说,这并不太复杂,但是它确实会带来一些问题和风险,我们将会讨论这些问题和风险。

自签名证书

自签名证书不使用 CA。它们是由你签名的,因此也不花任何钱。与自我管理的 CA 生成的证书一样,它们是不可信的,并且会在您的客户端上生成类似的错误消息。与自我管理的 CA 生成的错误不同,您不能通过添加根证书来消除此错误,因为您没有根证书可添加到客户端。自签名证书通常仅用于测试,很少在生产环境中使用。

选择证书类型

如果您想长期购买证书,最好使用由商业 ca 颁发的证书。这里的关键问题是成本。来自商业 CA 的证书一年可能要花费数百美元。仅仅为了保护你的电子邮件或你的商业营销网站,这就是一笔相当大的费用。因此,如果您不想要购买证书的费用,我们推荐一个让我们加密证书。

如果我们选择商业证书,我们将需要创建私钥和证书签名请求(CSR)。我们接下来会展示这一点。

为 TLS 创建证书

正如您已经发现的,为了让 TLS 工作,我们需要两个证书:一个服务器证书和一个 CA(商业 CA、非商业 CA 或您自己的 CA)的根证书。让我们从生成第一个服务器证书开始。第一步是生成服务器密钥和 CSR。无论我们是从商业或自我管理的 CA 生成证书,我们都会采取这些步骤。

该过程创建了我们的私钥和 CSR。该 CSR 然后被提交给 CA,在我们的例子中是我们自己的 CA,但也提交给商业 CA。正是这个签名过程允许客户端确认服务器证书的身份。

在清单 11-6 中,我们使用作为 OpenSSL 应用程序一部分的openssl命令生成一个密钥和请求。OpenSSL 应用程序是一个开源的 SSL 实现,它允许 Linux 和其他操作系统使用 SSL 加密和保护应用程序。

$ openssl genpkey -algorithm RSA -out www.example.com.key -pkeyopt rsa_keygen_bits:2048
.........................................................................+++
.................+++
Listing 11-6.Generating a Server Key and Request

在清单 11-6 中,我们使用了openssl命令来生成一个使用 RSA 密码的私钥。密钥长度为 2048 位,这是互联网的当前标准,但如果您愿意,也可以更长。问题是一些 ca 不支持更大的密钥长度。

Note

更长的密钥长度增加了加密的安全性,但是有一个(轻微的)处理代价,密钥加倍并不会导致加密安全性加倍。因此,网站使用的大多数密钥长度为 2048 位,预计在 2030 年左右仍能保持安全。如果您愿意,可以将密钥长度增加到 4,096。

我们通过-algorithm选项告诉openssl命令使用 RSA 密码,-out选项告诉openssl命令把密钥写到哪里,这里是写到 www.example.com.key 文件。我们通过–pkeyopt rsa_keygen_bits:2048将位大小传递给openssl

Tip

输入man genpkey可以看到关于openssl genpkey选项的更多细节。

接下来,我们想要生成一个 CSR。这就是我们要交给 CA 签字的东西。这是从我们刚刚生成的私钥中生成的。这样,我们就不必为了得到证书而把我们的私钥给任何人。虽然私钥很珍贵,需要保护,但 CSR 是公开的,不需要这样的限制。我们创建一个 CSR,如清单 11-7 所示。

$ openssl req -new -sha256 -key www.example.com.key -out www.example.com.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:AU
State or Province Name (full name) []:Victoria
Locality Name (eg, city) [Default City]:Melbourne
Organization Name (eg, company) [Default Company Ltd]:Example Inc
Organizational Unit Name (eg, section) []:IT
Common Name (eg, your name or your server's hostname) []:www.example.com
Email Address []:admin@example.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

Listing 11-7.Generating the CSR

在请求创建过程中,系统会提示您输入一些有关新证书的信息。如果不想回答特定的查询,可以键入 Enter 跳过该字段。系统将提示您输入两个字母的国家代码,例如,US 代表美国,GB 代表英国,AU 代表澳大利亚。

Note

您可以在 www.nationsonline.org/oneworld/country_code_list.htm 找到国家代码的完整列表。

系统还会提示您输入您所在组织的州/省、直辖市和名称,以及组织中的组织单位(可选)。当客户端或用户查询时,这些数据将显示在您的证书中。这是一个好主意,在这里要具体和准确——特别是如果你提交你的 CSR 由商业 CA 签署。

接下来,也是最重要的,我们需要指定证书的通用名称。这必须是将要使用该证书的服务器的确切主机名。如果您指定了不正确的主机名,您将得到一个关于服务器和证书名称不匹配的错误。在这种情况下,我们指定mail.example.com,这是电子邮件服务器的完全限定主机名。

然后指定证书联系人的电子邮件地址,在本例中为admin@example.com.

最后,系统会提示您输入证书的一些额外属性。你不需要担心这些,你可以输入回车跳过这些字段。

这个过程会给你留下两个文件: www.example.com.keywww.example.com.csr 。我们将保留这两个文件,因为我们在这个过程的后面会用到它们。

该过程的下一步是用 CA 签署 CSR。如果您要创建自己的 CA,请参阅下一节“创建自己的证书颁发机构”

否则,您需要提供您将提供给商业 CA 的 www.example.com.csr 文件的内容,然后它将向您发送证书。您的商业 CA 将提供如何提供 CSR 文件的说明。通常,您会将 CSR 的内容剪切并粘贴到网页中,然后提交。CA 随后会对其进行签名,并在签名证书可供下载时通知您。

在下一章中,我们将向您展示如何创建另一个证书并在您的 Postfix 安装中使用它。

创建自己的证书颁发机构

创建自己的 CA 是一件容易的事情。首先,您创建一个目录来保存您的 CA 和该目录中的一些子目录。CentOS 将所有 OpenSSL 文件存储在/etc/pki目录中。Ubuntu 用/etc/ssl。在本例中,我们将把我们的 CA 放在 CentOS 主机上的/etc/pki目录中。以下目录应该已经存在:

$ sudo mkdir /etc/pki/CA
$ sudo mkdir /etc/pki/CA/{private,newcerts,crl,certs}
$ sudo chown –R root:root /etc/pki/CA
$ sudo chmod 0700 /etc/pki/CA/private

私有目录将保存 CA 的私有密钥,newcerts目录将包含 CA 将签署的每个证书的副本。我们还确保 root 用户拥有所有目录,并且我们保护私有目录,以便只有 root 用户可以访问它。

接下来,您需要创建一个数据库来保存您的签名证书的详细信息。

$ echo '01' | sudo tee /etc/pki/CA/serial
$ sudo touch /etc/pki/CA/index.txt

Note

在第一行中,我们将数字01回显到了/etc/pki/CA/serial文件中。为此,我们使用了一个名为tee的命令,它可以从标准输出中读取数据,然后写入标准输出和文件。您可以在 tee 命令的man页面中找到更多信息。

串行文件跟踪通过此 CA 颁发的证书的最后一个序列号,从数字 01 开始。CA 颁发的每个证书都有一个唯一的序列号。

index.txt文件将包含当前由该 CA 管理的证书列表。每个证书旁边都有一个字母,表示该证书的状态。

  • R:撤销
  • E:过期
  • V:有效

OpenSSL 有一个控制缺省值和 CA 设置的配置文件。大多数发行版上都有一个模板文件。这个名为openssl.cnf的文件位于 CentOS 发行版的/etc/pki/tls/目录和 Ubuntu 的/etc/ssl/目录中。

如果您的 CA 使用非标准目录或者有一些其他设置,您可以复制这个文件并在您的CA目录中编辑它。为此,请在配置文件中找到以下列内容开头的部分:

[ CA_default ]

在下面的例子中,我们更改了名为dir的配置选项。如果我们想更改openssl命令来从当前目录中读取 CA 信息,我们应该执行以下操作:

dir = .

这告诉 OpenSSL 在当前目录中查找配置和签署证书所需的目录和文件。对于 CentOS,这已经设置为/etc/pki/CA。Ubuntu 将此设置为./demoCA。这意味着当您签署证书时,您必须将您的工作目录更改为CA目录,在我们的例子中是/etc/pki/CA

Tip

查看一下您的 CA 在openssl.cnf文件中的默认设置。它应该显示您为 CA 创建的默认目录和文件;在我们的例子中,它们是private目录和serial文件。

现在您需要为您的 CA 创建一个自签名证书和一个私钥。

$ cd /etc/pki/CA
$ sudo openssl req -new -x509 -newkey rsa:4096 -keyout private/cakey.pem \
   -out certs/cacert.pem -days 3650 \
   -subj '/C=AU/ST=Victoria/L=Melbourne/O=Example Inc/OU=IT/CN=ca.example.com/emailAddress=admin@example.com/'
Generating a 4096 bit RSA private key
...................................++
..................................................................................................................................................++
writing new private key to 'private/cakey.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----

首先,正如我们提到的,我们将工作目录改为/etc/pki/CA。接下来,我们创建一个密钥,这个也是 RSA,长度为 4096 位。我们将密钥存储在/etc/pki/CA/private/cakey.pem文件中。我们还将证书创建为自签名的,因为我们没有另一个 CA 来签名它。我们将证书的期限指定为 3,650 天(或 10 年)。我们已经指定了一些其他选项:-x509,这表明证书是自签名的,以及-extensions v3_ca,这表明我们正在创建一个 CA 证书。最后一个选项-subj,允许我们回答我们添加到证书主题的属性。

Tip

值得通读一下openssl.cnf配置文件,以了解您还有哪些其他选择。

系统将提示您输入 CA 私钥的密码短语或密码。选择一个好的密码并记住它。每次创建新证书时,您都需要此密码。

如您所见,CA 由一个私钥和一个公钥证书组成。您现在有了自己的 CA,可以用它来签署证书。

Securing Your Certificate Authority

如果您使用 CA 来保护生产或任何敏感数据的传输,您会希望 CA(私钥、CRL 等)非常安全。如果你只是为了好玩和试验而使用它,你可以对如何保护它不那么严格。

在本例中,我们在用于 web 服务器的同一台主机上创建了一个 CA。这在现实世界中并不理想,最好有一个专门的主机来进行这项活动。理想情况下,该主机在使用时应该受到限制或与网络断开连接,而将它放在 web 服务器上是很危险的。我们强烈建议使用专用主机。

保护 CA 的一个好方法是在有密码保护的加密磁盘上建立一个专用的虚拟映像。当您想要签署证书时,可以装载加密的磁盘,启动虚拟映像,签署证书,关闭虚拟主机,然后卸载磁盘。

我们可以在任何我们喜欢的主机上为 www.example.com 创建一个私钥。您不需要在具有相同主机名的主机上创建私钥。然后,您必须将私钥复制到 www.example.com 主机才能使用它。建议您不要将私钥放在不使用它们的主机上。如果不需要的话,应该安全地删除它们(比如使用shred程序)。

如果您的 CA 遭到破坏,根据谁在使用它,您可以重新创建它并重新签名您的所有证书。如果其他组织正在使用您的 CA,或者颁发的证书数量很大,那么重新创建 CA 的工作可能会很烦人,而且会造成干扰。

当然,与 CA 相关联的密码将被安全地存储在密码管理器中,并且 CA 的私有密钥的副本可以被存储在加密的拇指驱动器上并且存储在安全的保险库中。

向您的证书颁发机构签署您的证书

现在,您已经创建了您的 CA,您可以使用它来签署您的证书请求。在我们的例子中,CA 位于我们创建 CSR 请求的同一个主机上。您通常需要将 CSR 文件复制到 CA 主机。这将获取您的 CSR 并用您的 CA 对其进行签名,并输出一个签名证书。在清单 11-8 中,我们已经签署了我们的 CSR。

$ cd /etc/pki/CA
$ sudo openssl ca -out /root/www.example.com.cert -infiles /root/www.example.com.csr
Using configuration from /etc/pki/tls/openssl.cnf
Enter pass phrase for /etc/pki/CA/private/cakey.pem:
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 1 (0x1)
        Validity
            Not Before: Aug 21 02:05:11 2016 GMT
            Not After : Aug 21 02:05:11 2017 GMT
        Subject:
            countryName               = AU
            stateOrProvinceName       = Victoria
            organizationName          = Example Inc
            organizationalUnitName    = IT
            commonName                = www.example.com
            emailAddress              = admin@example.com
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            Netscape Comment:
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier:
                3E:37:13:CB:D3:84:58:9D:47:73:89:A6:80:12:DD:90:FE:C7:06:4B
            X509v3 Authority Key Identifier:
                keyid:54:57:27:C4:82:CA:C2:97:CE:5E:C7:64:A8:99:D3:A8:D1:1E:EC:77

Certificate is to be certified until Aug 21 02:05:11 2017 GMT (365 days)
Sign the certificate? [y/n]:y

1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated

Listing 11-8.Signing Our Certificate Request

在清单 11-8 中,我们使用了ca选项来签署我们的请求。-out选项指定了我们将要输出的签名证书,而-infiles选项指定了我们想要签名的 CSR(我们假设我们的 CSR 文件在/root目录中)。

Tip

您可以通过输入man ca来查看openssl ca命令的其他可用选项。

系统将提示您输入为 CA 的私钥创建的密码,然后将显示您的证书的详细信息,最后将提示您签署证书并将其详细信息写入 CA 的数据库。对两个问题都回答y是。

在这个过程的最后,您将拥有一个签名的证书、一个私钥和一个证书请求,它们都位于/root目录中。您的证书有效期为一年(您可以使用-days选项指定不同的有效期来覆盖此期限)。

您可以使用openssl命令检查证书的详细信息。

$ openssl x509 -in /root/www.example.com.cert -noout -text -purpose | more

Tip

你可以把握你的企业社会责任。当您想要更新您的证书时,在我们的例子中是一年后,您可以使用清单 11-8 中的命令重新签署这个请求。这意味着你不需要不断重新创造你的企业社会责任。

请记住,为了避免您的客户端指出您的证书不可信,您必须将您的根证书安装在相关的客户端中,例如,用户的浏览器!CAcert 网站有在 http://wiki.cacert.org/FAQ/BrowserClients 将其根证书安装到各种客户端的说明。若要安装您的证书,请在说明中用您的证书替换它的证书。

使用“让我们加密”创建 HTTPS 证书

Let’s Encrypt ( https://letsencrypt.org )有加密互联网的使命!它是一个免费的、自动化的、开放的认证机构,来自非营利的互联网安全研究组织(ISRG)。Let’s Encrypt 是一个免费的 CA,它将自动创建、请求和签署证书,主要用于 web 服务器。我们将在我们的许多服务中使用 Let’s Encrypt,因为这是加密所有流量的一种安全便捷的方式。

它是如何工作的?嗯,就像我们说的,它的核心就像一个普通的 CA。Let’s Encrypt 提供了一个代理,它使用自动证书管理环境(ACME)协议首先验证 web 服务器域,然后创建私钥和 CSR 请求来创建有效的证书。续订和撤销也由 Let’s Encrypt 完成。更详细的解释请参考这里的文档: https://letsencrypt.org/how-it-works/

我们将使用 Let’s Encrypt 提供的 Certbot 代理来管理我们的证书。为此,您的 web 服务器需要一个有效的域名系统(DNS)公共记录,并且能够接受来自 Internet 的 HTTP 和 HTTPS 连接。我们还将使用 Let’s Encrypt staging 环境,以便我们的测试不会影响他们的服务。

要安装 Certbot,我们可以在这里看到说明: https://certbot.eff.org 。我们选择了 Apache 和 CentOS 7 的指令。我们需要发布以下内容:

$ sudo yum install epel-release

然后我们需要安装python-certbot-apache包。

$ sudo yum install python-certbot-apache

对于 CentOS 上的 Apache HTTPS,我们要求安装mod_ssl包。在 Ubuntu 上,SSL 模块是核心 Apache 包的一部分。对于 CentOS,模块通过/etc/httpd/conf.modules.d/00-ssl.conf加载,在安装软件包后应该会出现。

我们现在要做的是使用certbot命令来创建和安装我们的证书。Certbot 将处理证书的创建和安装,它将复制我们的虚拟主机并将http://流量重定向到https://。因为我们使用的是 Let’s Encrypt 临时服务器,所以我们将制作无用的证书,但是在测试生产 Let’s Encrypt 系统时,我们不会受到访问限制的约束。

Note

我们不能使用example.com域来创建加密证书,因为我们显然不拥有该域。相反,我们在这些例子中使用了另一个域。

certbot命令有几个选项可用。您可以通过键入certbot --help来查看它们,或者对于所有可用的选项,您可以发出certbot --help all。让我们使用certbotwww.example.com 创建我们的证书。

$ sudo certbot --test-cert –d www.example.com

这里,我们发出了带有--test-cert参数的certbot,这意味着我们将使用分段应用程序编程接口(API)而不是真正的加密端点。这个 staging API 将完成我们需要的一切,除了创建一个有效的证书(证书是由假的 LE 发布的)。我们还将–d选项传递给 Certbot,以提供我们想要认证的主机名。我们可以通过添加额外的–d <hostname>参数来提供多个主机名,只要您有虚拟主机。

当我们第一次运行certbot时,我们提供了一个电子邮件地址来联系我们的证书(图 11-15 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11-15。

Adding e-mail address to Certbot

这个过程在/etc/letsencrypt/accounts目录中为暂存 API 创建一系列文件。当我们第一次运行certbot时,我们提供了一个电子邮件地址来联系我们的证书(图 11-16 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11-16。

Agreeing to the Let’s Encrypt terms of service

在图 11-17 中,我们有两个选项。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11-17。

Securing our web site

第一种选择很容易;这是我们保留http://https://访问的地方。第二个选择(安全)是我们只允许https://访问我们的网站。在这个场景中,http://流量被重定向到https://。它通过将以下几行添加到我们的虚拟主机配置中来实现这一点:

<VirtualHost *:80>
...
RewriteEngine on
RewriteCond %{SERVER_NAME} =www.example.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,QSA,R=permanent]
</VirtualHost>

certbot命令还创建了一个新文件来包含我们的 SSL 配置。它与我们的http://虚拟主机具有相同的配置,但是添加了 SSL 密钥。RewriteEngine允许我们根据特定条件路由 HTTP 流量。在这里,我们已经将http://的所有流量重定向到网站的https://版本。

/etc/httpd/conf.d/www.example.com-le-ssl.conf
<IfModule mod_ssl.c>
<VirtualHost *:443>

  ServerName www.example.com

  ServerAdmin webmaster@example.com
  DocumentRoot  /var/www/html/www.example.com
  DirectoryIndex index.php
  ProxyPassMatch ^/(.*\.php(/.*)?)$ unix:/run/php-fcgi.sock|fcgi://127.0.0.1:9000/var/www/html/www.example.com/
  <Directory /var/www/html/www.example.com>
     Require all granted
  </Directory>

SSLCertificateFile /etc/letsencrypt/live/www.example.com/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/www.example.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateChainFile /etc/letsencrypt/live/www.example.com/chain.pem
</VirtualHost>

</IfModule>

这里我们有一个之前创建的虚拟主机的副本,但是让我们加密添加了刚刚创建的 SSL 证书细节。这样做,它将重启 Apache 服务器,我们可以访问https://版本(图 11-18 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11-18。

We have our certificates.

前面说过,我们无法用 www.example.com 来测试真实,所以你可以看到假装的网址(图 11-19 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11-19。

Our fake certificate

staging API 会给我们一些我们可以使用的证书,但是这些证书不会被任何人信任。为了使它成为一个真正可信的证书,我们只需从我们的certbot命令中删除–test-cert并再次添加我们的电子邮件地址,我们将拥有一个工作证书(图 11-20 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11-20。

Our true certificate

$ sudo certbot -d cido.cloud.ownenergy.com.au

其他 Web 应用程序

我们已经向您展示了如何在自己的虚拟主机中安装两个 web 应用程序,这应该会让您对这个过程有一个基本的了解。我们不能在这里包含所有 web 应用程序的安装指南,但是我们可以推荐一些您可能会觉得有用的指南。

MediaWiki 是一个运行维基百科(以及其他站点)的协作工具。可以从 www.mediawiki.org/ 下载。

Moodle 是一个课程或学习管理系统。许多学校用它来向学生提供基于网络的学习。可以从 www.moodle.org/ 下载。

SugarCRM 是客户关系管理(CRM)软件,可以帮助您和您组织的销售人员管理客户和客户关系。可以从 www.sugarcrm.com/ 下载。

Web 缓存

Web 缓存用于通过将缓存的响应返回给多个客户端来加速网页的交付。这可以是内部用户或外部公共客户端,可以使您的 web 服务器不必处理进入您站点的每个请求,从而将它们解放出来,以便更好地处理动态内容生成。

有不同类型的缓存软件和服务。有 Akamai、Cloudflare、CloudFront 和 Fastly 等内容交付网络(CDNs)服务,也有 Varnish、Nginx、Apache 和 Squid-Cache 等软件。

Web 缓存通过使用 HTTP 头来工作。浏览器使用Cache-ControlETag头来确定它所请求的资源何时已经改变并且应该被再次获取。对于图像、JavaScript 和 CSS 之类的文件,您可以设置一个类似于max-age=120Cache-Control头,这意味着浏览器会将一个资源对象在其缓存中存储 120 秒,然后才会认为它过时。过了这段时间,它将再次获取资源。

但是,如果资源在这段时间内没有发生任何变化,那么再次下载它将是一种资源浪费。最好更新缓存版本。浏览器可以通过使用ETag值来确定资源是否已经改变。浏览器通过在请求中设置一个报头IF-NONE-MATCH和它所具有的ETag值,询问 web 服务器具有这个特定ETag的资源是否已经改变。如果已经改变,则再次下载该资源;如果没有,那么 web 服务器发回一个304 Not Modified响应,缓存中的对象被更新 120 秒。

一些组织将在其主 web 服务器前使用 web 缓存服务器。例如,您可能在 Apache 服务器前使用 Varnish 或 Nginx 服务器,或者您可能希望您的全球用户能够从 CDN 中受益,该 CDN 提供了离您的客户端更近的 web 呈现。这取决于您的基础设施和您的网站将如何被使用的性质。如果你一个月只有几千个用户,可能没什么好处。如果你正在向世界各地成千上万的人分发内容,你肯定会想看看一个 CDN。

在我们的示例中,我们将安装一个 web 缓存服务器来帮助减少本地带宽并加快浏览速度。

鱿鱼贮藏库

当您办公室的多个用户开始同时浏览网页时,他们可能会占用大量带宽。为了帮助最小化 web 浏览对其他网络用户的影响,您可以安装缓存或代理服务器。

Linux 上常用的 web 缓存服务器之一是 Squid-Cache。当您的浏览器配置为使用缓存时,Squid 会保存您从网站检索的任何文件的本地缓存副本,因此下次访问相同的文件时,可以从本地 Squid 缓存提供。

Squid 的另一种操作模式是作为反向代理,它位于连接的 web 服务器端的一个或多个 web 服务器的前面。当网站提供大量不经常改变的内容时,使用反向代理。通过允许反向代理缓存不变的数据,可以减少底层 web 服务器上的负载。这种代理也被称为 web 加速器。

配置

鱿鱼由squid包提供。通过 CentOS 上的sudo yum install squid或 Ubuntu 上的sudo aptitude install squid安装。两个发行版对 Squid 使用相同的配置文件,即/etc/squid/squid.conf。因为该文件可能包含敏感信息(如密码),如果不使用sudo,您甚至无法查看该文件。

Ubuntu 上的默认配置文件已经被很好地注释了,所以我们不会对大多数选项进行详细说明。CentOS 上的squid.conf文件已被分条为建议的最低设置。我们将向您展示如何配置 Squid 应该监听的地址和端口,以及如何配置它,以便您的用户实际上被允许通过缓存访问 Web。

默认情况下,Squid 监听所有网络接口上的端口 3128,尽管端口 8080 也很常用。配置文件中修改端口的指令是http_port。此指令允许您指定端口号或地址和端口号的组合。

如果希望 Squid 监听多个地址和端口,可以添加更多的http_port指令。

因为我们在网关主机上设置了 Squid,所以我们不希望它监听所有接口上的连接;不在我们本地网络上的用户应该不能访问它。因此,我们需要添加两行http_port:一行用于无线网络地址范围,一行用于有线网络地址范围。

http_port 192.168.0.254:3128
http_port 192.168.1.254:3128

接下来,我们需要告诉 Squid 允许哪些 IP 地址范围连接到它并访问网站。Squid 为此使用访问控制列表(ACL)。对于您想要控制的每个网络范围,您需要定义一个 ACL。然后创建控制每个 ACL 访问的规则。配置文件包含一些基本的 ACL,我们已经将它们包含在清单 11-9 中。

acl all src 0.0.0.0/0.0.0.0
acl localhost src 127.0.0.1/255.255.255.255
acl to_localhost dst 127.0.0.0/8
Listing 11-9.ACL Definitions

acl指令告诉 Squid 该行的其余部分是 ACL 定义。接下来,我们给 ACL 一个标签,以便以后引用。然后,我们指定要创建的 ACL 类型。Squid 支持许多类型,但是我们将只使用srcdstport,它们控制我们是处理源地址、目的地址还是端口号。最后,我们使用字符串定义源、目的地或端口。要获得 ACL 类型的完整列表,您可以阅读 Squid 网站上的 ACL 部分,网址为 www.squid-cache.org/Versions/v2/2.6/cfgman/acl.html

在我们的例子中,我们定义了一个名为all的 ACL,它包含了所有的互联网地址。下一个 ACL 允许我们将源自本地网络接口的所有流量称为 localhost。第三个执行相同的操作,但用于本地网络接口的流量。

让我们为我们的网络地址添加一些 ACL。我们可以将这些直接添加到定义to_localhost的行下面。

acl wired src 192.168.0.0/255.255.255.0
acl wireless src 192.168.1.0/255.255.255.0

我们定义了两个新的 ACL,一个用于有线网络范围,一个用于无线范围。我们可以通过简单地为两个 ACL 指定相同的标签来合并它们。然而,给他们不同的名字意味着我们可以给他们不同级别的访问权限,如果我们想的话。

另一个可能有用的配置选项是设置允许来自任何特定网络或区域的访问的时间。

acl wireless_hours time M T W T F 8:30-17:30

Squid 包含一个名为Safe_ports的 ACL,其中包含 web 和 FTP 流量的常用端口。这样,您可以控制希望本地用户能够连接到远程服务器上的哪些端口。如果您需要访问的站点运行在非标准端口上,您可以将端口号添加到Safe_ports ACL,从而允许浏览器连接到它。

acl Safe_ports port 80  # http
acl Safe_ports port 21     # ftp
acl Safe_ports port 443 # https

既然我们已经定义了我们需要的所有 ACL,我们可以通过为这些 ACL 定义访问规则来完成我们的配置。Squid 使用http_access指令来确定是否允许给定的 ACL 使用缓存。这个指令有两个参数,一个动作和一个 ACL。这些指令按顺序处理,当规则匹配时,处理停止。

第一条规则防止浏览器连接到我们没有在Safe_ports ACL 中明确列出的端口。

http_access deny !Safe_ports

接下来,允许 localhost 连接,拒绝所有其他连接。

http_access allow localhost
http_access deny all

如果没有http_access规则匹配,则应用与最后看到的动作相反的动作。这就是为什么总是把http_access deny all留在原位作为最终规则是很重要的;这意味着 Squid 将拒绝访问,除非它遇到允许访问的规则。

我们应该在它们之间插入新的规则,如清单 11-10 所示。

http_access allow localhost
http_access allow wired
http_access allow wireless wireless_hours
http_access deny all
Listing 11-10.Granting Access for Our Networks

我们将添加一些日志记录来帮助跟踪我们的配置中的任何问题。为此,我们添加了access_log指令。日志将被写入/var/log/squid

access_log daemon:/var/log/squid/access.log squid

这将为我们的访问日志提供一些日志详细信息,如下例所示:

1471953526.429    934 192.168.0.1 TCP_MISS/200 10265 GET http://blahblah.com/ - HIER_DIRECT/64.207.180.61 text/html
1471953526.961    493 192.168.0.1 TCP_MISS/200 19834 GET http://blahblah.com/blah.jpg - HIER_DIRECT/64.207.180.61 image/jpeg
...
1471953633.942    389 192.168.0.1 TCP_REFRESH_UNMODIFIED/304 305 GET http://blahblah.com/ - HIER_DIRECT/64.207.180.61 –

在这个访问日志的例子中,您可以看到我们首先获得了我们所追求的资源,然后我们可以看到一个后续的请求返回一个 304 未修改状态。

最后,我们可以使用cache_dir指令更改磁盘上 Squid 用来存储其缓存对象的目录。这被注释掉了,这意味着它将使用内置的默认值,如下所示:

# cache_dir ufs /var/spool/squid 100 16 256

前面一行告诉 Squid 以ufs格式将缓存对象存储在/var/spool/squid目录下。它将存储最多 100Mb 的对象;之后,旧对象将从缓存中过期,并被新对象替换。最后两个数字控制 Squid 将在主缓存目录中创建多少个子目录。在这种情况下,它将创建 16 个主子目录,每个子目录包含另外 256 个子目录。

这个子目录模式的出现是因为大多数文件系统在访问包含大量文件的目录时非常慢。例如,如果每个 Squid 子目录包含大约 100 个缓存文件,缓存中的文件总数将超过 400,000。如果它们都存储在单个目录中,每次浏览器请求这些文件中的一个时,主机将需要在目录 inode 中搜索多达 400,000 个条目,以找出它需要的数据存储在哪里。通过细分缓存,对于任何给定的文件,需要搜索的索引节点的数量都要少得多,从而减少了缓存增长时的性能下降。

由于磁盘空间通常比带宽便宜,我们将允许我们的缓存变得更大。

cache_dir ufs /var/spool/squid 2000 16 256

我们保存配置文件并启动 Squid。在 CentOS 上,我们应该首先通过systemctl创建启动链接。

$ sudo systemctl enable squid

我们现在可以通过 CentOS 上的sudo systemctl start squid启动 Squid,或者通过sudo service squid restart在 Ubuntu 上重启它。在 CentOS 上,我们指定的缓存目录将在 Squid 首次启动时创建。当我们安装这个包的时候,这已经在 Ubuntu 上发生了。

客户端配置

剩下我们要做的就是配置 web 浏览器来使用代理。在 Chrome 中,我们选择设置➤网络➤更改代理设置。在这台苹果 Mac 主机上,我们可以如图 11-21 所示为仅http://流量配置代理服务。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11-21。

Setting a proxy server in Chrome

如果我们愿意,我们也可以配置https://的流量。然后我们关闭网络和 Chrome 设置,访问我们最喜欢的网站。我们可以通过查看 Squid 访问日志来验证代理正在被使用。

透明度

如果您不想让您的用户为了使用 Squid 缓存而更改他们的代理设置,您可以将 Squid 作为透明代理来运行。透明代理通过防火墙规则将所有出站 web 流量重定向到它。访问 web 的浏览器不知道他们正在使用缓存,并且您不需要显式配置任何 Web 浏览器来使用它。

Note

如果您希望对代理服务使用身份验证,您将无法使用透明代理。客户端认为它是在直接与原始服务器对话。

要将我们当前的配置转换成透明代理,我们必须对配置文件做两个小的修改。对于每个http_port指令,我们需要添加选项transparent

http_port 192.168.0.254:3128 transparent
http_port 192.168.1.254:3128 transparent

重启 Squid 后,我们在网关主机上添加防火墙规则。这些规则应该拦截到远程网站的所有连接,并将它们重定向到我们的代理。我们希望在网关将数据包发送到互联网之前,更改数据包的目的地址和端口号。这是网络地址转换(NAT)的一种形式,由 Netfilter 在 NAT 表中完成。命令firewall-cmd可再次用于此目的。

Note

我们将在第七章中介绍防火墙。

要更改数据包的目的地地址,我们需要创建一个DNAT目标,并破坏 HTTP 出站流量。首先确保我们伪装我们的联系。然后,我们将进入防火墙端口 80 的流量转发到端口 3128,Squid 将在那里等待。

$ sudo firewall-cmd --permanent --zone=public --add-masquerade
$ sudo firewall-cmd --permanent --zone=public --add-forward-port=port=80:proto=tcp:toport=3128:to_addr=192.168.0.254
$ sudo firewall-cmd --reload

然后,我们重新加载防火墙,使这些更改永久生效。

Caution

如果您的透明代理主机不是网关主机,您应该确保它可以直接访问远程网站,而无需重定向到自身。

摘要

在本章中,我们向您展示了如何使用您的 Linux 主机作为具有 SQL 支持的灵活的 web 服务器,以及如何通过安装 web 服务来利用这一点。现在,您应该能够执行以下操作:

  • 创建和管理虚拟网站
  • 通过模块向 Apache 添加功能
  • 基于主机名或用户名和密码控制对站点的访问
  • 创建和管理 MariaDB 数据库和用户
  • 安装和配置第三方 web 应用程序
  • 配置 web 代理以节省带宽成本并提高速度

在下一章,我们将看看如何设置我们的邮件服务器。

Footnotes 1

http://news.netcraft.com/archives/web_server_survey.html

十二、邮件服务

部署 Linux 主机的一个最常见的原因是提供邮件服务,包括通过 Internet 消息访问协议(IMAP)和邮局协议(POP3)等机制接收和发送电子邮件以及检索电子邮件。在本章中,我们将简要解释电子邮件的工作原理,并向您介绍电子邮件解决方案的组成部分,包括

  • 邮件传输代理(MTA):发送和接收电子邮件的服务器
  • 邮件用户代理(mua):用户通过其发送和接收电子邮件的客户端
  • 邮件传递代理(MDA):帮助您将电子邮件传递到邮箱的工具

我们还将向您介绍执行这些功能的应用程序:

  • Postfix:简单邮件传输协议(SMTP)电子邮件服务器
  • Dovecot:一个 IMAP 和一个 POP3 服务器

Postfix 电子邮件服务器将允许您的用户发送和接收来自内部用户和外部(如来自互联网)的电子邮件。Dovecot 服务器提供 IMAP 和 POP3 守护程序。IMAP 和 POP3 是用户从电子邮件服务器上的邮箱中检索电子邮件的两种不同方式(我们将解释这些区别以及为什么您可能会使用其中一种而不是另一种)。

我们还将向您展示如何保护您的用户免受不请自来的电子邮件或垃圾邮件以及病毒的侵害。

在本章中,我们将解释基本的邮件服务——发送、接收和管理电子邮件。许多用户现在对电子邮件服务器有了更多的期望,如日历、消息传递,甚至文档管理。他们希望这些功能能够在不同的设备上无缝运行。这些协作服务可以在经过不同程度的改进后的 Linux 下获得。有些是专有许可的,有些是 GPL 或其变体。有些将提供一个基本的服务,有些将对每个用户收取少量费用,有些将是免费的,除了某些专有模块。我们将在本章末尾讨论其中的一些。

电子邮件是如何工作的?

电子邮件在个人和商业交流中仍然无处不在。虽然社交媒体现在也用于交流,但电子邮件仍然是大多数公司的核心。大多数人不需要担心撰写电子邮件和点击发送按钮之外的事情。然而,要运行你自己的邮件服务器,你需要对电子邮件的内部工作原理有更多的了解。在图 12-1 中,您可以看到典型的电子邮件生命周期。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12-1。

E-mail life cycle

当你发送电子邮件时会发生什么?

电子邮件基于一种叫做 SMTP 的协议(定义于 RFC 5321 www.ietf.org/rfc/rfc5321.txt )。每封电子邮件都有一系列的标题,告诉您的邮件服务器如何处理它以及将它发送到哪里。因此,当用户创建一个新的电子邮件时,他们会注明该电子邮件的地址。他们添加一个收件人(或收件人字段),并且可能将电子邮件“抄送”或“密件抄送”给其他人。然后他们发送电子邮件。

用户的电子邮件客户端配置了一个服务器,您的客户端现在联系这个服务器(在 TCP 端口 25 上)并说“Hello!我有这个人给这些人的邮件—请把它发给他们!”实际上,我们的客户端并没有准确地说“你好”,它说了一些非常接近的东西——一个名为EHLO(或者更罕见的是HELO)的命令。

Note

电子邮件服务器有很多名字。它们可以被称为 SMTP 服务器或 SMTP 守护程序,但它们的正确名称是邮件传输代理。发送电子邮件的客户端在此术语中称为邮件用户代理。在本章的后面,我们还将了解另一个组件,称为邮件传递代理,它可以用来将电子邮件传递到用户的邮箱。

EHLO是 SMTP 命令,是 SMTP“语言”的一部分命令是 SMTP 客户端和服务器(或 mua 和 MTA)相互通信的方式。最初,SMTP 语言中只有大约十个单词或命令。最近,一个名为扩展 SMTP (ESMTP)的 SMTP 增强版本被开发出来,它向该语言添加了许多更有用的命令,以提供诸如身份验证和加密等功能。

Note

我们之前提到的HELO命令是EHLO命令的旧形式。现在已经很少使用它了,但是所有性能良好的邮件服务器都应该支持它,作为万一你的客户端老了,认不出EHLO时的后备。

我们现在将使用 netcat ( nc)命令连接到一个邮件服务器。我们将使用nc向您展示邮件服务器在发送电子邮件时相互发送的实际命令。为此,我们将发布$ nc mail.example.com 25。在这种情况下,客户机告诉服务器它是谁,在清单 12-1 中,您可以看到用 SMTP 的“语言”进行的简单对话

220 mail.example.com ESMTP Server
EHLO client.example.com
250-mail.example.com
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
Listing 12-1.A Simple SMTP Conversation

当您启动到邮件服务器的连接时,它应该用状态代码 220 及其名称和功能来响应。清单 12-1 中的第一行是服务器告诉客户机它是谁,mail.example.com,它是一个支持 ESMTP 的 SMTP 服务器。

Note

您可以看到该行以格式为2xx的数字开始。这是一个响应代码,客户端和服务器交换该代码以指示成功或失败。如果该行以数字5xx开头,您的客户机和服务器就会知道这是某种错误代码。稍后您会看到更多这些数字。

在下一行,我们输入了命令EHLO client.example.com。当客户端打招呼告诉服务器是谁的时候,应该提供一个像client.example.com这样的全限定域名。根本没有验证这是否是合法的主机名,所以它可以是任何东西(不幸的是,这就是大量垃圾邮件的传送方式——稍后将详细介绍)。最后,服务器做出响应,确认连接(状态代码 250),并返回一个功能列表。

接下来,我们将通过该服务器向example.com域中的用户发送一封电子邮件。这从发送发件人和收件人的详细信息开始,也就是通常所说的信封。

MAIL FROM: <ataylor@example.com>
250 2.1.0 Ok

这里,发送者ataylor@example.com使用了MAIL FROM命令。服务器进行检查,返回 250 响应代码,并指示允许该发件人提交电子邮件。这种接受可以基于许多标准,包括一个正确构造的电子邮件地址,我们将在本章的后面讨论像身份验证这样的机制,但是仍然很少验证这个发送地址是否合法。

接下来,服务器期待RCPT TO命令,或者电子邮件发送给谁。

RCPT TO: <jsmith@example.com>
250 2.1.5 Ok

在这里,地址的接受取决于一些标准,例如具有格式正确的电子邮件地址,以及该服务器被配置为代表example.com域接受邮件。如果此邮件服务器配置不当,并且接受不受其控制的域的邮件,则称为开放中继。

接下来,在我们的简单示例中,我们需要实际电子邮件的内容。客户端向服务器发送一个名为DATA的命令。

DATA

354 End data with <CR><LF>.<CR><LF>

Message-ID:

Date: Mon, 17 Aug 2016 12:29:26 +1100

From: Anne Taylor ataylor@example.com

To: John Smith jsmith@example.com

Subject: Email is cool

This is an email message.

.

250 2.0.0 Ok: queued as DF44644A9

服务器的响应是请求电子邮件的内容,然后在一行中单独添加一个句点或句号标记,表示电子邮件的结束。

您可以看到我们传递了一些相当默认的标题,如日期、收件人和发件人标题、主题和电子邮件的内容。我们已经指定了.标记,服务器已经响应说它已经接受了这封电子邮件。然后,每封电子邮件都被提交到邮件队列,由服务器进行处理和发送。

您现在可以通过重复MAIL FROM命令继续发送电子邮件,或者使用QUIT命令断开与服务器的连接。

QUIT
221 2.0.0 Bye

这是一个发送电子邮件的简单场景。这是最基本的命令交换。当您考虑加密和身份验证等因素时,大多数正常的电子邮件发送会稍微复杂一些。

E-mail Addresses

那么什么是可以接受的电子邮件地址呢?什么是格式正确的电子邮件地址?电子邮件地址最基本的形式是用户名和主机名、域名或完全限定的域名,由一个@符号分隔,例如jsmith@example.com。关于允许使用哪些字符以及电子邮件地址的适当结构的规则常常令人困惑。电子邮件地址可以采用多种形式,不同的电子邮件服务器或 MTA 接受不同的有效格式。我们将向您展示的 MTA Postfix 接受各种格式的电子邮件地址。Postfix 的电子邮件地址重写指南展示了一些被接受的电子邮件地址格式: www.postfix.org/ADDRESS_REWRITING_README.html

发送电子邮件后会发生什么?

在服务器(或 MTA)收到来自客户机的电子邮件并将其放入邮件队列后,一组全新的命令和步骤将被执行。首先,服务器需要找到发送电子邮件的目的地。为此,服务器将电子邮件地址的一部分放在@符号的右边。这通常是完全限定的域名,例如example.com。然后,电子邮件服务器使用域名系统(DNS)查询来联系远程域,并询问它将电子邮件发送到哪里。

Note

我们在第十章讨论了 DNS。

电子邮件服务器通过查询一种称为 MX 记录的特殊 DNS 记录来实现这一点。查询 MX 记录会返回一个或多个条目,告诉您的电子邮件服务器将电子邮件发送到哪里,通常是一个特定的主机或 IP 地址。如果返回了多个电子邮件服务器,还会返回一个优先级,告诉您的电子邮件服务器首先使用哪个条目,然后再使用哪个条目,依此类推。在本章的后面,我们将展示如何配置我们的 DNS MX 记录。

Note

如果 DNS 查询表明没有 MX 记录,您的电子邮件服务器将无法传递该电子邮件,并将向您发送一封表明这一点的邮件。如果用户键入错误或指定了不正确的电子邮件地址,这种情况经常会发生。

然后,电子邮件服务器将您的待发电子邮件提交到另一个队列,并从那里发送到目标电子邮件服务器。为此,您的电子邮件服务器会尝试通过 TCP 端口 25 或 TCP 465 的安全传输端口,按照记录指定的优先级顺序连接到 MX 查询返回的每个电子邮件服务器。然后,电子邮件服务器会按照提交顺序查看是否可以发送您的电子邮件。

  1. 如果电子邮件服务器响应,它将尝试提交电子邮件。
  2. 如果电子邮件服务器没有响应,您的电子邮件服务器将按顺序尝试从 MX 记录返回的下一个服务器。
  3. 如果没有电子邮件服务器响应,您的电子邮件服务器通常会将您的电子邮件排队,稍后再试。
  4. 如果在连续失败后,电子邮件仍然无法发送,电子邮件服务器将通过电子邮件向用户报告失败。

您的电子邮件服务器试图发送的目的地服务器可能是您的电子邮件的最终目的地,或者它可能只是一个网关,您的电子邮件通过它到达一个或多个更远的电子邮件服务器,直到它最终到达它的目的地。这取决于目的地如何配置其电子邮件环境。许多环境都有接收邮件的面向 Internet 的电子邮件网关,然后有处理内部邮件的内部电子邮件服务器。此配置允许在您的电子邮件网关上使用与内部服务器不同的功能,如垃圾邮件和病毒过滤。然而,正如我们所说的,一个正确配置的电子邮件服务器应该被设置为只接受其控制下的域的邮件。

Note

需要注意的是,电子邮件被归类为“尽力而为”,没有保证。也就是说,邮件服务器通常会尝试发送 4 个小时的邮件,然后才会放弃。虽然通常邮件会在不到一分钟的时间内送达世界各地,但这是无法保证的。

配置电子邮件

我们将向您展示如何创建一个基本的电子邮件服务器配置,允许您发送和接收电子邮件,并帮助保护您的用户免受垃圾邮件、病毒和恶意软件的侵害。我们还将利用传输层安全性(TLS),这是一种加密形式,可用于加密您的电子邮件,并讨论 SMTP AUTH,这是一种在用户发送电子邮件时对其进行身份验证的方法。

我们将使用headoffice.example.com主机作为我们的电子邮件服务器,我们的gateway.example.com将电子邮件流量传递到该主机,正如我们在第七章的示例网络配置中所描述的。

我们的邮件服务器将被称为mail.example.com(这是我们在第十章中创建的一个 DNS CNAME)并且有一个内部 IP 地址 192.168.0.1。你可以在图 12-2 中看到我们的示例网络。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12-2。

Example network

装置

我们将从安装我们需要的包开始 Postfix 和 Dovecot 应用程序。

CentOS 装置

在 CentOS 的更高版本中,默认 MTA 是 Postfix,并作为最小安装的一部分安装。另一种常见的 MTA 叫做 Sendmail。我们将使用后缀 MTA,它更易于理解、配置和故障排除。

Note

总是有很多关于哪个 MTA 最好的争论,有很多可用的,包括 Sendmail、Postfix、Exim 等等。我们的建议是从 Postfix 开始,看看效果如何。我们认为你会发现 Postfix 功能强大且易于使用,它能满足你的所有需求。

首先,我们来看看 Postfix 和 Dovecot 是否已经安装。

$ sudo rpm -q postfix dovecot
postfix-2.10.1-6.el7.x86_64
package dovecot is not installed

如果一个或多个软件包没有安装,我们需要安装它们。我们在这里使用了yum命令:

$ sudo yum install -y postfix dovecot

Note

一些附加的必备软件包也可以通过这两个命令安装。我们还将在本章的后面安装一些额外的包来提供对其他功能的支持。

Ubuntu 安装

后缀 MTA 也是 Ubuntu 发行版的默认 MTA,所以它通常已经安装了。事实上,你在第二章中看到,我们的 Ubuntu 安装提示我们执行一些基本的 MTA 配置。我们将很快再次访问配置对话框(参见“编辑后缀配置”侧栏)。

如果没有安装 Postfix MTA,我们希望安装 Postfix 和 Dovecot 软件包。让我们先检查一下它们是否已安装。

$ sudo aptitude show postfix
Package: postfix
State: installed
...
$ sudo aptitude show dovecot-core
Package: dovecot-core
State: installed
...

这里我们已经检查了是否安装了postfix包和dovecot-core包。如果两者都安装了,您就已经拥有了所需的东西。

如果没有安装,可以使用aptitude命令安装。

$ sudo aptitude install postfix dovecot-core dovecot-imapd dovecot-pop3d

开始后缀

安装后,使用我们在第六章中介绍的服务管理工具启动 Postfix 很容易。对于 CentOS 和 Ubuntu,使用systemctl命令启动 Postfix。

$ sudo systemctl start postfix.service

Tip

在进行配置更改后重新加载或重启 Postfix 也很重要,你会看到我们在整章中都提到了这一点。如果您无法找出某些东西不工作的原因,重启通常是故障诊断的良好开端。

您可以通过检查日志文件来确认 Postfix 已启动。Postfix 将其输出记录到系统日志或 syslog 中,后者依次记录到位于您主机上的文件中。您可以在/var/log目录中找到它的日志文件。在 CentOS 上,我们需要查看/var/log/maillog file。在 Ubuntu 上,Postfix 将所有日志消息发送给/var/log/mail.log。在 Ubuntu 上,错误和警告信息也会被分别记录到/var/log/mail.err/var/log/mail.warn文件中。监控这些文件中的错误消息是一个好主意。一个很好的方法是使用-f选项的tail命令,它实时监控文件,并在新的日志消息添加到文件中时向下滚动屏幕。

$ sudo tail –f /var/log/maillog

当 Postfix 成功启动时,您应该会看到以下日志消息:

Jul 10 03:21:34 au-mel-centos-1 postfix/postfix-script[4500]: starting the Postfix mail system
Jul 10 03:21:34 au-mel-centos-1 postfix/master[4502]: daemon started -- version 2.10.1, configuration /etc/postfix

了解后缀配置

大部分后缀配置由位于/etc/postfix目录中的两个文件处理。这些文件被称为main.cfmaster.cfmain.cf文件包含您可以用来定制 Postfix 的主要配置选项的子集。您可以向该文件添加配置 Postfix 所需的任何附加选项。master.cf文件控制客户端如何连接到您的服务器,以及组成服务器的服务如何配置。大多数时候你在master.cf档不会有太大的改变。

让我们先快速看一下每个文件的结构。

Note

大多数发行版安装预配置的main.cfmaster.cf文件。这些通常包括描述每个选项的大量内嵌文档。

main.cf中,每个选项的结构如下:

option = value

选项不必按任何顺序排列,空行会被忽略。

Note

后缀配置文件是 INI 格式,带有option = value。像大多数 Linux 配置文件一样,任何以#开头的行都是注释。

在清单 12-2 中,您可以看到一个典型的main.cf文件的样本。

...
# LOCAL PATHNAME INFORMATION
#
# The queue_directory specifies the location of the Postfix queue.
# This is also the root directory of Postfix daemons that run chrooted.
# See the files in examples/chroot-setup for setting up Postfix chroot
# environments on different UNIX systems.
#
queue_directory = /var/spool/postfix
...
Listing 12-2.The main.cf File

我们将在本章中讨论main.cf文件中的一些配置选项;您可以通过$ man 5 postconfwww.postfix.org/postconf.5.html 查看完整列表。

master.cf文件中,您可以看到可以在 Postfix 中启用和配置的守护进程、服务和进程的结构化列表。在清单 12-3 中,您可以看到这个文件中的一些示例行。

...
# ==========================================================================
# service        type         private         unpriv           chroot        wakeup       maxproc        command + args
#                    (yes)          (yes)           (yes)             (never)        (100)
# ==========================================================================
smtp              inet                 n             -                  n                 -                  -                 smtpd
...
submission        inet                 n                 -                    n            -                  -                smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_reject_unlisted_recipient=n
...
Listing 12-3.The master.cf File

这里定义了两个服务,smtpsubmission。每个服务通常都是后台运行的守护进程,执行特定的功能。

Note

与许多其他服务不同,Postfix 不是一个单一的守护进程,而是一些小进程的集合,它们执行各自的功能并相互通信。因此,当您启动 Postfix 时,您可能会看到多个进程启动,而不是单个进程。

在这种情况下,smtp服务是在 TCP 端口 25 上为您的主机接收邮件的基本 SMTP 服务,而submission服务是在 TCP 端口 567 上侦听的替代服务,有时用于接收来自内部邮件客户端(mua)的电子邮件。

接下来,我们定义服务的类型;这里inet将这些定义为基于网络的服务(即,在您的网络接口上运行的服务)。其他可用的服务类型包括本地 Unix 套接字和命名管道。Unix 域套接字和命名管道用于在服务之间发送消息;参见 http://en.wikipedia.org/wiki/Unix_domain_sockethttp://en.wikipedia.org/wiki/Named_pipe

接下来,我们对每个服务进行一系列设置。每个设置都在一行中按顺序指定,并用空格分隔。对于您的基本配置,您不需要担心这些设置,但您可以在$ man 4 masterwww.postfix.org/master.5.html 找到更多详细信息。

最后,每个服务都需要指定启动服务的命令,以及传递给该命令的任何参数。在清单 12-3 中,两个服务都是用命令smtpd启动的,但是submission服务有几个传递给命令的选项。这些选项与main.cf配置文件中的选项相同,它允许我们以不同于主配置的方式配置特定的服务。我们将在本章后面的“抗击病毒和垃圾邮件”一节中讨论如何将这些选项传递给单个服务。

Editing Postfix Configuration

有三种方法可以编辑您的 Postfix 配置文件,尤其是main.cf文件。

  • 您可以使用postconf命令。
  • 在 Ubuntu 上,dpkg-reconfigure命令可以进行基本的后缀配置。
  • 您可以使用文本编辑器,如vimgedit

我们通常推荐最后一个选项,使用文本编辑器来编辑您的配置文件,但是首先让我们快速地看一下另外两个选项。该文件可能很长,您可能会误以为同一个选项有两个值。在这种情况下,最后一个值将获胜,您可能会花几个小时挠头,想知道为什么它不像您预期的那样工作。

postconf命令是一个特殊的命令,允许您操作main.cf文件并显示您现有的配置。该命令还有一些用于调试和显示配置的有用的命令行选项。例如,要显示任何与默认配置不同的配置选项(即针对您的主机进行了修改),您可以使用–n配置标志。

$ sudo postconf -n

如果您正在寻找故障排除,通常会要求您提供postconf -n命令的输出。您还可以使用–d标志显示每个配置选项及其默认设置。最后,您可以使用命令通过-e选项编辑您的配置文件,如下所示:

$ sudo postconf -e 'inet_interfaces = all'

这里的inet_interfaces选项(控制 Postfix 绑定到哪些网络接口)已经被设置为值all

在 Ubuntu 上,可以使用dpkg-reconfigure命令来配置 Postfix 的基本状态。

$ sudo dpkg-reconfigure postfix

此命令为您提供了一系列基本配置模型,例如,发送和接收电子邮件的基本 Internet 主机。另一种型号使用智能主机;在这种情况下,电子邮件被发送到中间中继服务器。这种模式通常用于 Internet 服务提供商(ISP)环境,在这种环境中,您有时会受到限制,无法直接通过端口 25 发送和接收电子邮件。这旨在通过防止从 xDSL 或有线网络中受损的桌面主机发送和转发电子邮件来减少垃圾邮件数量。我们将在本章后面的“智能主机”边栏中讨论智能主机。

该实用程序还设置了许多其他配置选项。但是,我们不建议您使用该实用程序;相反,您应该使用文本编辑器手动编辑您的配置文件,这样您会更加熟悉所有选项。

永远记住,在任何 Postfix 配置更改之后,您必须重新加载或重启postfix服务。

初始配置

尽管有看起来相当复杂的配置过程和选项,Postfix 实际上很容易配置。一个简单的电子邮件服务器,设计用于发送和接收域的电子邮件,可以在几分钟内建立起来。

第一步是告诉 Postfix 应该处理哪些域的邮件。为此,我们通过添加我们的域来更新main.cf配置文件中的mydestination配置选项,在本例中是example.com。我们可以通过直接编辑main.cf文件并更改选项来进行更改,如下所示:

mydestination = mail.example.com, localhost.localdomain, localhost, example.com

我们也可以使用postconf命令来改变它。

$ sudo postconf -e "mydestination = mail.example.com, localhost.localdomain,
localhost, example.com"

在前一行,我们已经添加了两个项目:我们的邮件服务器和我们的本地域。Postfix 现在知道,如果它收到发往这些地址之一的邮件,例如,ataylor@mail.example.comataylor@example.com,它应该接受并处理这封电子邮件。

Note

Postfix 将只接收它知道的用户的邮件。通常,这将是在主机上创建的用户,但是我们将在本章后面的“虚拟域和用户”一节中简要地看一下“虚拟”用户。在某些情况下,Postfix 知道其他电子邮件服务器上的用户,并可以配置为将邮件转发到另一台主机。但是一般来说,如果 Postfix 找不到电子邮件的收件人(例如,如果一封电子邮件被发送到bjones@example.com并且 Postfix 不知道这个用户),该电子邮件将被拒绝。

当我们希望 Postfix 接收其他域的电子邮件时(例如,我们也希望接收来自example.net域的电子邮件),我们可以将该域添加到mydestination选项中。

mydestination = mail.example.com, localhost.localdomain, localhost,
example.com, example.net

其他条目通常已经存在,包括localhost,它告诉 Postfix 处理主机本地的电子邮件,例如本地进程发送的电子邮件。也正是这种设置阻止了你的邮件像我们之前谈到的那样成为一个开放的中继。邮件服务器将只接受为此处列出的域配置的邮件。如果您的域名未在mydestination中列出,当您向用户发送邮件时,您将会收到如下内容:

RCPT TO: <bobby@unlisted.org>
554 5.7.1 <bobby@unlisted.org>: Relay access denied

接下来,我们需要将本地网络添加到mynetworks配置选项中。这告诉 Postfix SMTP 客户端处理电子邮件需要哪些可信的 IP 地址范围。允许受信任的 SMTP 客户端通过我们的电子邮件服务器中继(向其他电子邮件服务器发送电子邮件)。在我们的例子中,我们只关心 192.168.0.0/24 和 192.168.1.0/24 范围,这是我们的本地有线和无线网络范围。127.0.0.1 或 localhost 地址应该已经存在于选项中。

mynetworks = 127.0.0.0/8, 192.168.0.0/24, 192.168.1.0/24

如果我们有外部用户需要从其他网络访问我们的电子邮件服务器,他们需要在被允许中继之前进行身份验证。我们可以再次使用postconf命令来编辑选项。

$ sudo postconf -e "mynetworks = 127.0.0.0/8, 192.168.0.0/24, 192.168.1.0/24"

现在我们需要将 Postfix 绑定到我们希望它监听的网络接口。在这种情况下,我们将绑定到所有网络接口,这是默认设置。

inet_interfaces = all

或者我们可以使用postconf命令。

$ sudo postconf –e "inet_interfaces = all"

但是,您可以更有选择性,如果您想将 Postfix 绑定为只在单个接口上侦听,您可以按如下方式进行:

inet_interfaces = enp0s3

Tip

有一个名为inet_protocols的设置,它控制 Postfix 在建立或接受连接时将尝试使用哪个 IP 版本。默认设置为all,但您可以根据需要指定ipv6ipv4。在 CentOS 上,将all设置为inet_protocol也将成为我们在 IPv6 上监听的默认接口,这意味着我们的电子邮件服务器需要支持 IPv6 以避免错误。

最后,在做了所有相关的修改后,我们需要重启 Postfix。我们可以发布以下内容:

$ sudo systemctl reload postfix.service

Note

每次更改 Postfix 配置选项时,都应该重新加载或重启 Postfix。

除了重新启动 Postfix,您还需要确保主机上的 TCP 端口 25 是打开的,以允许传入的连接。如果您运行了iptables防火墙,您将需要创建适当的规则来允许访问。这里有一个例子:

$ sudo iptables -A INPUT -p tcp -m conntrack --ctstate NEW -m tcp --dport 25 -j ACCEPT

Tip

我们在第七章中讨论了iptables防火墙、编写规则和开放端口。
我们现在应该在第十章中设置的 DNS 服务器中配置我们的 MX 记录。请记住,MX 记录是邮件交换的缩写,当您的 MTA 服务器向另一个域发送邮件时,它会查找该记录。

首先,我们需要冻结从主 DNS 服务器上的 DHCP 等服务到我们的example.com区域的任何nsupdate(名称服务器更新)。

$ sudo rndc freeze example.com

现在打开区域文件,将序列号增加到适当的日期。要添加 MX 记录,我们将在我们的example.com.db文件中的 NS 记录后添加一个,如下所示:

       IN    NS         ns.example.com.
       IN    MX  10  mail.example.com.

我们有记录的名称、互联网类型(IN)、记录类型(MX)、邮件服务器优先级(10,以及它映射到的主机(mail.example.com)。保存区域文件并退出。

接下来,我们需要再次解冻该区域。

$ sudo rndc thaw example.com

最后,让我们验证一下使用dig命令所做的更改。

$ dig -t MX example.com @192.168.0.1
;; ANSWER SECTION:
example.com. 86400 IN MX 10 mail.example.com.

看起来像我们期望的那样。我们准备开始测试。

测试后缀

我们现在可以通过给自己发送一封电子邮件来测试 Postfix 是否正常工作。就像我们在本章开始时所做的那样,我们将通过名为 netcat ( nc)的有用工具来完成这项工作。正如我们所见,nc命令是网络工具的瑞士军刀,可用于创建和操作传输控制协议(TCP)和用户数据报协议(UDP)连接。

Note

还有其他发送测试电子邮件的方法(例如,从命令行使用mail命令),但是nc命令允许您查看 SMTP 命令,并在命令行上显示任何可以看到的错误消息。

让我们再次使用nc命令编写与 Postfix 电子邮件服务器的会话,如清单 12-4 所示。

$ nc mail.example.com 25
220 mail.example.org ESMTP Postfix
ehlo example.com
250-mail.example.com
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
mail from: jsmith@example.com
250 2.1.0 Ok
rcpt to: ataylor@example.com
250 2.1.5 Ok
data
354 End data with <CR><LF>.<CR><LF>
Subject: My first mail for my domain
This is a test.
Thanks
Mr Testing
.
250 2.0.0 Ok: queued as 61A703FA5E
quit
221 2.0.0 Bye
Listing 12-4.A Scripted E-mail Session with nc

在清单 12-4 中,我们首先指定了nc命令、我们想要连接的电子邮件服务器以及我们想要连接的端口 25。接下来,我们逐步完成了 SMTP 命令(这次是小写的;这些命令是不区分大小写的)。在清单 12-4 中,所有粗体文本代表我们输入的命令,您需要输入这些命令来发送您的电子邮件。调整文本以适应您的环境,例如,用您的域名替换example.com。非折叠文本是我们的电子邮件服务器的预期响应。

Note

您可以看到每一行都以 SMTP 响应代码为前缀,例如 250。您可以在 https://www.iana.org/assignments/smtp-enhanced-status-codes/smtp-enhanced-status-codes.xml#smtp-enhanced-status-codes-3 查看这些代码的完整列表。

我们用EHLO命令告诉服务器我们是谁,它用自己的身份和可用特性列表来响应。然后,我们指出我们要向谁发送电子邮件,以及邮件来自谁。在我们的例子中,我们向ataylor@example.com和从jsmith@example.com发送电子邮件。

Note

我们在第五章中创建了这些用户。如果您继续进行,您应该替换本地主机上的用户名,或者创建一些新用户来测试您的电子邮件。

然后,我们告诉我们的服务器,我们正在发送带有DATA命令的电子邮件。我们输入我们的电子邮件,用句号(.)标记它的结尾,然后退出。

Tip

如前所述,从命令行发送本地电子邮件的另一种方式是使用mail命令,可以从mailutils包(Ubuntu)或mailx包(CentOS)中获得。这并没有给我们一个服务器的诊断视图,但是它更容易用来发送邮件。要启动该命令,请在命令行中键入 mail 以及您要发送电子邮件的电子邮件地址,例如 mail root@example.com。单独输入 mail 命令将打开一个简单的命令行邮件客户端。

我们现在可以检查我们的电子邮件是否已经到达。在我们的例子中,我们希望检查用户ataylor是否收到了电子邮件。默认情况下,CentOS 和 Ubuntu 都使用一种叫做 mbox 的邮箱格式来存储收到的电子邮件。mbox 格式将所有的电子邮件保存在一个文件中。Ubuntu 和 CentOS 都将这些文件存储在不同的位置,但都使用符号链接来确保文件出现在相似的位置。

Note

有关 mbox 格式的更多详细信息,请参见 http://en.wikipedia.org/wiki/Mbox

在 Ubuntu 上,会在/var/mail目录下创建一个以用户命名的邮箱文件,例如/var/mail/ataylor。但是对于/var/spool/mail目录,有一个到/var/mail目录的符号链接。

在 CentOS 上,每个用户在/var/spool/mail目录中都有一个 mbox 格式的邮箱文件。文件以用户命名,例如/var/spool/mail/ataylor。同样,/var/mail目录有一个到/var/spool/mail目录的符号链接。

让我们看看清单 12-5 中的一个 mbox 文件。

$ more /var/mail/ataylor
From jsmith@example.com  Sun Jul 10 12:12:46 2016
Return-Path: <jsmith@example.com>
X-Original-To: ataylor@example.com
Delivered-To: ataylor@example.com
Received: from example.com (ns.example.com [192.168.0.254])
    by mail.example.com (Postfix) with ESMTP id 2625C3FA5A
    for <ataylor@example.com>; Sun, 10 Jul 2016 12:12:18 +0000 (UTC)
Subject: My first mail for my domain

This is a test.
Thanks
Mr Testing

Listing 12-5.An mbox File

在清单 12-5 中,您可以看到 mbox 文件包含了我们的电子邮件,包括电子邮件的所有标题和内容。额外的电子邮件将被附加到这个文件。因此,如果您有大量的电子邮件,这些文件会变得难以管理、搜索和备份。

Aliases

当电子邮件到达您的主机时,Postfix 会查看收件人以确定将邮件发送给谁。一些应用程序使用收件人,例如邮局主管地址(例如,来自 MTA 的错误通常被发送到您的域中的用户邮局主管)和root用户。因为人们通常不会以这两个用户中的任何一个登录,所以这封电子邮件可能永远不会被看到。Postfix 使用一种称为别名的功能,允许您将发送给这些收件人的邮件重定向到其他用户。Postfix 在main.cf配置文件中使用一个名为alias_maps的配置选项来指定一个文件,该文件将收件人与实际接收电子邮件的用户进行匹配。默认的别名文件通常是/etc/aliases。在这个文件中,您会发现一个用户列表,如下所示:

user1:user2

在这里,user1的所有邮件将被重定向到user2,每个用户名用冒号隔开。您应该检查这个文件,并确保邮局主管和root用户的电子邮件都指向一个合适的用户。您还可以通过指定外部电子邮件地址向另一台主机上的用户发送电子邮件,如username@example.com。一种常见的模式是将系统用户的所有电子邮件发送给root用户,然后将root用户重定向到需要查看该电子邮件的人,例如:

postmaster: root
operator: root
lp: root
root: ataylor

这里,postmasteroperatorlp用户的邮件都被重定向到root用户,而root用户的邮件又被重定向到用户ataylor

您也可以将一个用户的邮件发送给多个后续用户。如果我们想将根用户的邮件重定向到ataylorjsmith,我们应该做以下事情:

root: ataylor,jsmith

现在,当 root 收到一封电子邮件时,ataylorjsmith都会收到同一封电子邮件。

在对/etc/aliases文件进行任何更改之后,您需要运行一个名为newaliases的命令来更新 Postfix。

$ sudo newaliases

在接下来的“后缀查找表和虚拟域”一节中,我们将深入探讨这是如何工作的。

选择邮箱格式

除了有可能变成一个大而难以处理的文件之外,默认的 mbox 格式还有另一个问题:文件损坏的可能性。例如,如果您的 MTA 正在向您的 mbox 文件发送邮件,同时您的 MUA 或邮件客户端正在删除邮件,则您的 mbox 文件可能会损坏或返回不可预知的结果。

mbox 的替代方法是 Maildir 邮箱格式。Maildir 将你的电子邮件存储在一个目录下的不同文件中,而不是一个单独的文件。这允许多个进程与您的邮箱交互,而没有任何冲突或损坏的风险。备份和恢复也更容易。

Maildir 格式是一个目录,恰当地称为Maildir,包含三个子目录:curnewtmp。您可以在此处看到 Maildir 格式目录的列表:

$ ls -l Maildir
total 168
drwxr-xr-x 2 ataylor ataylor 28672 2009-01-01 13:53 cur
drwxr-xr-x 2 ataylor ataylor  4096 2009-01-01 13:53 new
drwxr-xr-x 2 ataylor ataylor  4096 2009-01-01 13:53 tmp

电子邮件消息首先被传递到tmp目录,并被赋予一个惟一的名称(通常由当前时间、主机名和其他伪随机特征构成)。然后,电子邮件被转移到new目录中,处于“未读”状态。当您的 MUA 或邮件客户端连接到邮箱时,它会检测到new目录中的电子邮件,然后将它们移动到cur目录。

Note

这听起来有点复杂,但它可以确保在从您的邮箱中传递、阅读、发送和删除电子邮件时,电子邮件不会损坏或放错位置。

要使用 Maildir 而不是 mbox,我们需要告诉 Postfix 我们正在使用不同的邮箱格式。我们还将把默认邮箱位置从现有位置/var/mail/var/spool/mail更改为用户的主目录。为了做到这两点,我们将像这样更新一个名为home_mailbox的后缀选项:

home_mailbox = Maildir/

或者使用postconf命令,就像这样:

$ sudo postconf -e "home_mailbox = Maildir/"

home_mailbox选项告诉 Postfix 用户邮箱的位置,相对于用户的主目录,这样Maildir/就转化为/home/ataylor/Maildir

Note

结尾的/很重要。它需要在那里,它告诉 Postfix 这个目录是一个Maildir目录。

我们还需要确认另一个选项mailbox_command为空。mailbox_command选项可以指定外部命令,例如procmailmaildrop等邮件处理工具。这些工具称为 MDA 或邮件过滤器,可以在收到的邮件发送到您的邮箱时对其执行操作。我们将在本章后面的“邮件传递代理和邮件过滤”边栏中详细讨论这些应用程序。所以我们现在将这个选项设置为空值。

mailbox_command =

或者再次使用postconf命令。

$ sudo postconf -e "mailbox_command = "

最后,我们需要重新加载 Postfix 以使所有这些生效,例如:

$ sudo systemctl reload postfix

现在,如果您发送另一封电子邮件,您会发现在收件人的主目录中创建了一个名为Maildir的新目录。在这个目录中有tmpnewcur子目录,在new目录中有你的电子邮件。您可以使用less命令显示该文件的内容,例如:

$ less /home/jsmith/Maildir/new/1468154018.V801I3fa69M48418.mail.example.com
Return-Path: <ataylor@au-mel-centos-1.example.com>
X-Original-To: jsmith@example.com
Delivered-To: jsmith@example.com
Received: from au-mel-centos-1.example.com (ns.example.com [192.168.0.254])
        by mail.example.com (Postfix) with ESMTP id 09F9E3FA66
        for <jsmith@example.com>; Sun, 10 Jul 2016 12:33:38 +0000 (UTC)
Received: by au-mel-centos-1.example.com (Postfix, from userid 1000)
        id 1F5EF61A55; Sun, 10 Jul 2016 08:33:38 -0400 (EDT)
Date: Sun, 10 Jul 2016 08:33:38 -0400
To: jsmith@example.com
Subject: My first email to my new Maildir mailbox
User-Agent: Heirloom mailx 12.5 7/5/10
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Message-Id: <20160710123338.1F5EF61A55@au-mel-centos-1.example.com>
From: ataylor@au-mel-centos-1.example.com (ataylor)

This is also a test.
Thanks
Mr Testing

在这里,您可以看到单个的Maildir文件将包含一封带有所有标题的电子邮件。

Note

每个Maildir必须由它所属的用户拥有。例如,属于用户ataylorMaildir目录必须只有该用户拥有和可写(权限为 0700)。如果需要,您可以使用chownchmod命令分别更改所有权和权限。

虽然在这种情况下,Postfix 自动创建了Maildir目录,但是用一个空的Maildir目录预先填充用户的主目录通常是一个好主意。您可以通过在/etc/skel目录中添加一个空的Maildir目录来实现这一点。您在第五章中看到了/etc/skel目录,并发现其内容被复制到任何新创建用户的主目录中。

在 Ubuntu 上创建一个新的Maildir目录,有一个很有用的命令叫做maildirmake.dovecot,可以自动创建Maildir结构。

$ sudo maildirmake.dovecot /etc/skel/Maildir

该命令还将创建tmpnewcur子目录。

Tip

您还可以在您的Maildir结构中创建文件夹,例如一个Sent文件夹。文件夹可以用来分类和存储电子邮件,以便更容易找到电子邮件。文件夹是以句号(.)为前缀的子目录;一个Sent文件夹将具有通过使用命令maildirmake.dovecot /etc/skel/Maildir/.Sent创建的结构/home/ataylor/Maildir/.Sent。注意避免文件夹名称包含空格,如“我的个人邮件”,因为有时你的邮件客户端可能会混淆。你应该用下划线或破折号将单词连接起来,就像这样:“我的个人邮件。”

在 Ubuntu 上,有另一种可能更简单的方法来创建你的Maildir目录和文件夹。为此,您可以安装一个名为maildrop的包,其中包含maildirmake命令,这是maildirmake.dovecot命令的一个更复杂的版本。

然后您可以使用maildirmake命令创建框架目录和任何需要的文件夹。

$ sudo maildirmake /etc/skel/Maildir
$ sudo maildirmake -f Sent /etc/skel/Maildir
$ sudo maildirmake -f Trash /etc/skel/Maildir
$ sudo maildirmake -f Drafts /etc/skel/Maildir
$ sudo maildirmake -f Spam /etc/skel/Maildir

这里我们使用了malldirmake命令的-f选项来创建文件夹。我们指定想要创建的文件夹的名称和在其中创建文件夹的Maildir

如果不想安装maildrop包,可以使用mkdir命令创建目录,如清单 12-6 所示。

$ sudo mkdir -p /etc/skel/Maildir/{cur,new,tmp}; chmod -R 0700 /etc/skel/Maildir
Listing 12-6.Manually Creating Maildir

Note

在清单 12-6 中,我们使用了一个聪明的 Bash 快捷方式,列出了所有三个用括号({ })括起来并用逗号分隔的目录。这个技术,大括号扩展,告诉mkdir创建所有三个子目录。您可以将它与各种其他命令一起使用,而不需要键入命令三次。–p选项创建所有的父目录和目标目录。

清单 12-6 创建Maildir和所需的子目录,并将结果目录的权限更改为 0700,因此只允许拥有Maildir的用户访问它。

Mail Delivery Agents and Mail Filtering

在本章的前面,我们讨论了 MDA。这些工具位于您的 MTA 和用户邮箱之间,您可以告诉 Postfix 什么 MDA(如果有的话)要与您之前看到的mailbox_command配置选项一起使用。当在此选项中指定了 MDA 时,Postfix 会将电子邮件传递到此 MDA,而 MDA 会将电子邮件传递到用户的邮箱。

在交付过程中,MDA 可以执行各种操作;例如,它可以查找电子邮件的特征,如来自谁,并将其重定向到特定的邮箱文件夹。许多人使用 MDA 将邮件列表中的电子邮件分类到单独的文件夹中。MDA 还用于根据其他应用程序添加的邮件头对电子邮件进行排序;例如,许多垃圾邮件过滤器会添加指示电子邮件是否为垃圾邮件的标题。MDA 可以读取这些邮件头,并将电子邮件放入适当的文件夹中,例如,放入垃圾邮件文件夹中。您还可以使用 MDA 来生成外出通知,将特定的电子邮件转发给其他人,以及执行各种其他任务。

您还可以从一些 MDA 调用其他应用程序。例如,有些人不在他们的 MTA 中运行垃圾邮件过滤器,而是在他们的 MDA 中运行垃圾邮件过滤器。

在本章中,我们将使用 Dovecot 将邮件从 MTA 发送到用户的邮箱。使用 Dovecot LDA(本地递送代理- MDA 和 LDA 是同义词),我们可以使用 Sieve 插件进行邮件过滤、转发和自动回复电子邮件。

扩展后缀配置

到目前为止,我们只是触及了允许本地用户发送和接收电子邮件的 Postfix 配置的基础。然而,Postfix 还有许多其他方面可以让您的环境更安全,让您的用户体验更好,包括以下方面:

  • 加密:保护电子邮件和用户凭证的传输
  • 认证:确保只有适当的和经过认证的用户才能发送电子邮件

使用加密

后缀 MTA 能够通过称为 TLS 的加密协议对电子邮件传输进行加密。TLS 是安全套接字层(SSL)的后续协议,通常用于加密传输控制协议/互联网协议(TCP/IP)流量。邮件流量的 TLS 与使用超文本传输协议安全(HTTPS)协议连接到网站时相同,例如, https://www.gmail.com

TLS 为我们的电子邮件通信提供了两个关键功能。

  • 防止窃听我们的电子邮件内容
  • 加密客户端和服务器之间的通信,从而保护身份验证

不幸的是,您应该意识到电子邮件传输中的 TLS 并不像每个人希望的那样安全。邮件服务器可以配置为通过STARTTLS加密电子邮件的发送和接收。因为不要求邮件服务器使用STARTTLS,所以很多会降级为明文,或者容易受到恶意降级攻击。因此,虽然我们建议使用像 TLS 这样的安全传输,但它并不能保证防止窃听。电子邮件客户端是不同的,您可以确保客户端仅使用正确配置的安全传输。

为 Postfix 创建 SSL 证书

我们将使用 Let’s Encrypt 来获取 SSL 证书。我们用上一章看到的certbot命令来完成。Certbot过程需要一个 web 服务器来管理验证过程以获得您的证书。好消息是,在我们运行获取证书的过程时,certbot命令可以选择运行一个独立的 web 服务器。

独立的 web 服务需要通过端口 80 (HTTP)或端口 443 (HTTPS)访问您的主机。我们可以用ufwfirewall-cmd命令来完成。对于 Ubuntu,我们将发出以下命令:

$ for h in http https ;do sudo ufw allow $h ;done

或者在 CentOS 上,我们将发布以下内容:

$ for h in http https; do sudo firewall-cmd --zone public --add-service=$h ;done

一旦完成,我们可以使用Certbot为我们的邮件主机创建证书。同样,如果我们正在测试我们的证书的创建,我们应该使用--test-cert选项在 Let’s Encrypt 中使用 staging API。

$ sudo certbot certonly --test-cert --standalone --uir --hsts --agree-tos -n -m admin@example.com -d mail.example.com
IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/mail.example.com/fullchain.pem.
   Your cert will expire on 2016-11-22\. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot
   again. To non-interactively renew *all* of your certificates, run
   "certbot renew"

当我们高兴地准备好真正生成我们的证书时,我们将删除--test-cert。我们使用的其他选项是certonly,它表示我们只需要证书,而不需要将它安装到我们的 web 配置中。--standalone选项告诉certbot启动自己的 web 服务来生成证书。接下来的两个选项,--uir--hsts,是为了确保每个到 Certbot API 的通信都在https://之下。使用--agree-tos选项,我们同意服务条款。–n选项是用于非交互式的,这有利于脚本编写。然后我们提供注册联系人(-m)和我们想要注册的主机名(-d)。然后,证书被存储在/etc/letsencrypt/live/mail.example.com/目录中。

为 TLS 配置后缀

现在,您已经从 Let’s Encrypt 获得了一个证书和一个密钥,或者您已经获得了一个商业证书或一个由您的自我管理的证书颁发机构(CA)签名的证书。您还需要来自商业 CA 或自我管理 CA 的根证书。如果您使用的是商业证书,您的 CA 通常会提供一个可下载根证书的链接,或者如果您使用的是自己的 CA,该证书会在/etc/pki/CA/cacert.pem中。

现在您已经有了证书和密钥,您需要配置 Postfix 的main.cf配置文件。在清单 12-7 中,您可以看到您需要添加到您的main.cf配置文件中的选项,我们将带您浏览这些设置。

smtp_tls_security_level = may
smtp_tls_CAfile = /etc/letsencrypt/live/mail.example.com/chain.pem
smtp_tls_cert_file = /etc/letsencrypt/live/mail.example.com/cert.pem
smtp_tls_key_file = /etc/letsencrypt/live/mail.example.com/privkey.pem

smtpd_tls_security_level = may
smtpd_tls_CAfile = /etc/letsencrypt/live/mail.example.com/chain.pem
smtpd_tls_cert_file = /etc/letsencrypt/live/mail.example.com/cert.pem
smtpd_tls_key_file = /etc/letsencrypt/live/mail.example.com/privkey.pem
smtpd_tls_loglevel = 1
smtpd_tls_mandatory_exclude_ciphers = aNULL, MD5
smtpd_tls_mandatory_protocols = TLSv1

Listing 12-7.Postfix TLS Configuration

如果你查看清单 12-7 中的选项,你会发现它们看起来很相似,除了初始前缀的不同。一个以smtp开头,一个以smtpd开头。当 Postfix 向另一个邮件服务器发送邮件时,使用以smtp开头的配置选项。以smtpd开头的选项在 Postfix 接收电子邮件时使用,例如从客户端接收邮件。通过指定smtp_tls_security_levelsmtpd_tls_security_level,我们告诉 Postfix 我们希望加密传入和传出的连接。

两个选项的may值启用了一种称为机会 TLS 的模式。这基本上意味着,如果远程客户机或服务器支持 TLS,就应该使用它。否则,纯文本连接是可以接受的。不幸的是,并非所有的电子邮件服务器都支持 TLS。因此,考虑到并非所有的客户端和服务器都支持 TLS,目前may是一个明智的选择,将服务器限制为加密连接将意味着一些电子邮件服务器无法向您发送电子邮件。

接下来的三个选项,smtpd_tls_key_filesmtpd_tls_cert_filesmtpd_tls_CAfile,指定我们的证书、密钥文件和 CA 证书的位置。

下一个选项smtpd_tls_loglevel控制 Postfix 将生成多少 TLS 连接日志。此处指定 0 会禁用日志记录,指定 1 会提供基本日志记录,而指定 3 和 4 会产生最高级别的日志记录(除非您正在进行故障排除,否则不建议使用)。对于日常操作,我们建议将其设置为 1,这将产生一些关于连接和所用证书的简要信息。

我们还设置了一些选项来决定我们将接受什么样的密码以及我们想要使用什么样的协议。smtpd_tls_mandatory_exclude_ciphers选项决定了我们不接受哪些密码;由于aNULLMD5是弱密码,我们不会在 TLS 传输中使用它们。对于smtpd_tls_mandatory_protocols,我们声明我们将只支持TLSv1和更高版本,因为任何更低的版本都被认为是易受攻击的。

进行更改后,您需要重新启动 Postfix 服务。

$ sudo service postfix restart

一旦 Postfix 服务重新启动,您就可以使用我们之前介绍的相同的nc命令来测试 TLS 是否被启用,如清单 12-8 所示。

$ $ openssl s_client -connect localhost:25 -starttls smtp
CONNECTED(00000003)
depth=1 CN = Fake LE Intermediate X1
verify error:num=20:unable to get local issuer certificate
verify return:0
---
Certificate chain
 0 s:/CN=mail.example.com
   i:/CN=Fake LE Intermediate X1
 1 s:/CN=Fake LE Intermediate X1
   i:/CN=Fake LE Root X1
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIE+zCCA+OgAwIBAgITAPpVz+iRXsKC430YQrhOPwEhdjANBgkqhkiG9w0BAQsF
ADAiMSAwHgYDVQQDDBdGYWtlIExFIEludGVybWVkaWF0ZSBYMTAeFw0xNjA4MjQx
...<snip>...
iIVJyRvMWqW2x9i0o/t9bheRaoSX/Vt7X4ZF8vClEQQ0iSNTC956WxAiyFOXLU7A
86RIlXw3Zm01CtiP4rHi2ZzoIChvcSBfdNG5kOCy5w==
-----END CERTIFICATE-----
subject=/CN=mail.example.com
issuer=/CN=Fake LE Intermediate X1
---
Acceptable client

certificate CA names
/CN=Fake LE Intermediate X1
Server Temp Key: ECDH, prime256v1, 256 bits
---
SSL handshake has read 3421 bytes and written 428 bytes
---
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-SHA
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1
    Cipher    : ECDHE-RSA-AES256-SHA
    Session-ID: 419EB576C7D51B5818CD1F64564275F8104AEB4ABAE8FAA0C9EA300A0F44B8F3
    Session-ID-ctx:
    Master-Key: 6FD71DE08D3888747E57D506FCDB710BCCEBE7557810DC92F1E4FBCC77CCAD0CCA2DE0616E882E0B9BC1775E8054298D
    Key-Arg   : None
    Krb5 Principal: None
    PSK identity: None
    PSK identity hint: None
    TLS session ticket lifetime hint: 3600 (seconds)
    TLS session ticket:
    0000 - 5d e2 39 53 22 6b 33 9e-d9 4e 14 de 63 6d de 73   ].9S"k3..N..cm.s
    0010 - d0 1c e9 55 7a 1e 70 32-b3 02 30 93 e5 f5 d3 d4   ...Uz.p2..0.....
    0020 - 8e a6 e5 bf c8 d5 20 a2-88 0e 20 88 15 29 4c f4   ...... ... ..)L.
    0030 - f1 88 eb b8 a1 47 1a 2c-3e 74 2e f0 b5 c1 f5 d2   .....G.,>t......
    0040 - 97 ec 26 a9 65 c8 e9 b6-92 3a 07 a0 30 56 5f e5   ..&.e....:..0V_.
    0050 - ad 73 a7 46 42 47 7f a2-82 b8 ed 08 6a da 25 6b   .s.FBG......j.%k
    0060 - ae 44 a6 c7 b3 b8 e4 f9-8f 73 64 b6 47 01 79 36   .D.......sd.G.y6
    0070 - 7d 91 3a 26 e7 03 74 5d-4f db 1a d4 28 65 e1 f7   }.:&..t]O...(e..
    0080 - b8 d0 a5 91 81 96 0a 3a-cd fa a1 f0 97 c7 b5 37   .......:.......7
    0090 - 0e bd 29 7b 1d 56 ad 91-81 a9 50 6e c4 ee 0f 94   ..){.V....Pn....

    Start Time: 1472046666
    Timeout   : 300 (sec)
    Verify return code: 20 (unable to get local issuer certificate)
---
250 DSN
EHLO o.yeah.com
250-mail.example.com
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN

Listing 12-8.Testing Postfix with TLS

在清单 12-8 中,我们已经连接到我们的电子邮件服务器并发出了EHLO命令。我们使用openssl s_client命令连接到我们的电子邮件服务器,并传递START命令。您可以看到电子邮件服务器做出了响应,我们建立了一个加密会话。在我们发出EHLO命令后,电子邮件服务器用可用的支持命令进行了响应。

如果您只连接 netcat,您会看到这里列出了一个新命令,STARTTLS。这告诉我们 Postfix 现在向客户端和其他服务器提供 TLS。

$ nc localhost 25
220 mail.example.com ESMTP Postfix
EHLO ah.ah.com
250-mail.example.com
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
STARTTLS
220 2.0.0 Ready to start TLS

然后,我们输入STARTTLS命令,告诉 Postfix 我们想要启动一个加密连接。Postfix 回应说它已经准备好开始加密连接。这表示 TLS 已成功设置,正在等待连接。

另一种测试你的服务器是否被正确设置来发送安全邮件的方法是对照 www.checktls.com/testreceiver.html 来检查它。这将尝试与您的电子邮件服务器建立连接,并向您报告连接是否安全。

如果您在配置 Postfix TLS/SSL 加密时遇到问题,请参阅即将到来的“获取 Postfix 帮助”一节中的指针和链接。

Caution

请务必注意一些关于使用 Postfix TLS 加密的问题,以确保您的电子邮件内容的机密性。Postfix 向其他服务器发送电子邮件,但只有当其他服务器支持 TLS 时才加密邮件。由于并非所有服务器都支持加密,有些电子邮件可能没有加密。确保所有电子邮件加密的唯一方法是使用基于内容的加密解决方案,如 S/MIME ( http://en.wikipedia.org/wiki/S/MIME )、PGP ( www.pgp.com/ )和 GnuPG ( http://www.gnupg.org/ )。

证明

现在我们已经配置了 TLS,我们可以加密客户端和服务器之间的会话,以及我们的服务器和其他支持 TLS 的服务器之间的会话。这就把我们带到了后缀配置的下一个阶段:认证。

在其默认配置中,您的 Postfix 服务器将只接受来自其受信任网络中客户端的电子邮件,如在mynetworks配置选项中所定义的,在我们的示例中,是 192.168.0.0/24 和 192.168.1.0/24 网络。这可以防止不适当的用户使用我们的电子邮件服务器。没有这些限制的电子邮件服务器被称为开放中继。开放中继允许任何人向它发送电子邮件,服务器将继续发送。垃圾邮件制造者大量利用开放中继,用不需要的电子邮件污染互联网。

Caution

开放中继是很成问题的,不正确的配置会导致服务器成为开放中继,这对您的组织来说是非常麻烦的。当检测到开路继电器时,它们通常会被列入黑名单。这个黑名单过程意味着开放中继的 IP 地址被添加到不接受来自其的电子邮件的服务器列表中。如果您的服务器是一个开放的中继,即使在关闭中继并修复您的服务器后,也很难将您自己从这些黑名单中删除并允许您的用户发送电子邮件。你应该定期测试你的服务器是否像一个使用 www.mailradar.com/openrelay/ 服务的开放中继。

默认情况下,Postfix 的配置会阻止您的服务器像开放中继一样运行。但是,尽管这种配置停止了开放中继,但它留下了一个安全漏洞,并产生了一个功能缺口。

关于这个漏洞,任何能在你的网络上获得 IP 地址的人都可以向你的邮件服务器发送电子邮件。例如,如果攻击者破坏了您的无线网络,她可以利用您的电子邮件服务器发送垃圾邮件。

这种配置也给移动用户留下了功能空白。几乎可以肯定的是,有些用户会外出旅行、在家工作,或者使用手机或平板电脑等移动设备。这些用户无法使用您的电子邮件服务器,因为他们是移动用户,在您的网络上没有 IP 地址。这些用户必须依赖服务提供商的电子邮件服务器,该服务器允许中继、开放中继或虚拟专用网络(VPN)进入您的组织。通常这不是一个理想的情况。

有了身份验证,只要经过身份验证,您的用户就可以从任何地方发送电子邮件。这还意味着您信任的网络上的内部用户需要提供身份验证凭据,才能被允许发送电子邮件。这降低了有人可能直接进入您的网络并使用您的电子邮件服务器的风险。

您的身份验证又受到您刚刚配置的 TLS 加密的保护,允许您的用户进行身份验证,而不会在网络上暴露他们的凭据。

Note

这是一件好事,因为人们通常使用像tcpdump或 Wireshark(两者都在第七章中提到)这样的工具来“嗅”网络。这些人“嗅探”加密或暴露的密码等东西来窃取。对于无线网络,这尤其容易,因为攻击者甚至不需要实际接入您的网络。

SMTP 授权和 SASL

电子邮件服务器的认证是由一种叫做 SMTP AUTH的机制提供的。这是另一个 SMTP 命令,它在允许用户发送电子邮件之前提示用户输入用户名和密码。该用户名和密码可以通过各种机制提供,包括明文和加密形式。还可以使用支持一次性密码的机制,如智能卡或令牌。使用什么机制在很大程度上取决于您的客户端支持什么机制。例如,微软的 Outlook 客户端只支持少量的机制,而 Mozilla Thunderbird 支持更多的机制。

Note

您可以在 http://en.wikipedia.org/wiki/One-time_password 了解一次性密码。

为了确认用户的凭证是有效的,AUTH命令使用了一个名为简单认证和安全层(SASL)的认证框架。SASL 很像可插拔认证模块(PAM),我们在第五章中讨论过,它抽象了认证。它允许在简单身份验证和安全层(SASL)协议背后隐藏多种类型的身份验证。这意味着您的电子邮件服务器可以检查各种后端服务,以验证用户是否被允许发送电子邮件,而无需了解如何通过这些服务的身份验证。

这些后端服务可以包括 PAM(可用于允许用户使用其 Linux 登录名和密码进行身份验证)、用户和密码数据库,甚至包括 LDAP 或 Active Directory 等用户存储库。Postfix 没有内置 SASL。它依赖于与其他应用程序的集成来提供 SASL 功能。我们将使用 Dovecot 服务器向 Postfix 提供这些 SASL 功能。

如果到目前为止您一直遵循这个示例,那么当我们在本章前面向您展示如何安装 Postfix 时,您应该已经安装了 Dovecot。如果没有,如果您想按照接下来的说明进行操作,请使用这些说明立即安装。然后,您需要确保 Postfix 支持使用 Dovecot 的 SASL 认证。这可以通过使用-a选项的postconf命令来完成。

$ sudo postconf -a
cyrus
dovecot

这里的postconf命令返回了 Postfix 支持的所有 SASL 认证插件。我们正在寻找dovecot条目。所有最新版本的 CentOS 和 Ubuntu 都应该提供这种支持。

为 SASL 配置鸽笼

现在,我们需要配置 Dovecot 的 SASL 支持并启动 Dovecot 守护进程。鸽笼配置文件位于/etc/dovecot/dovecot.conf/etc/dovecot/conf.dconf.d目录中的文件用于为 Dovecot 配置不同的服务和机制。

我们将编辑/etc/dovecot/dovecot.conf并设置 Dovecot 的 SASL 认证服务。我们打开配置文件,寻找我们想要编辑的第一个选项:protocols。我们首先要关闭除身份验证之外的所有服务。我们通过将它设置为none来做到这一点。

protocols = none

Note

当我们在本章后面的“配置 IMAP 和 POP3”一节中讨论 IMAP 和 POP3 以及如何启用它们时,我们将回到这个选项。

接下来,我们需要配置身份验证服务。为此,我们将编辑/etc/dovecot/conf.d/10-master.conf,找到service auth配置选项。你可以在清单 12-9 中看到我们将要设置的service auth配置选项。

service auth {
...
  # Postfix smtp-auth
  unix_listener /var/spool/postfix/private/auth {
    mode = 0660
    user   = postfix
    group = postfix
  }
....
}
Listing 12-9.Configuring Dovecot auth

service auth由一系列括在括号内的指令组成({ })。该服务可能已经在您现有的10-master.conf配置文件中进行了部分配置。您需要确保现有配置文件中的配置与清单 12-9 中的配置相匹配。

清单 12-9 中的unix_listener指令是提供 Postfix 和 Dovecot 之间连接的套接字。套接字监听来自 Postfix 的身份验证请求,然后返回结果。它通过使用一种叫做套接字的特殊类型的文件来做到这一点,我们在第四章中简要讨论过,它允许应用程序之间的交互。这个套接字位于一个 Postfix 目录中,该目录存储了守护进程/var/spool/postfix/private/使用的文件和套接字,文件名为authmodeusergroup选项控制套接字的权限和所有权,我们只将这些权限和所有权限制给postfix用户。

当 Dovecot 守护进程运行时,您可以在目录中看到这个文件。

$ sudo ls -l /var/spool/postfix/private/auth
srw-rw----. 1 postfix postfix 0 Aug 25 09:33 /var/spool/postfix/private/auth

接下来,我们必须更改/etc/dovecot/conf.d/10-auth.conf中的设置。该文件控制身份验证机制。我们要更改的这个文件中的指令是mechanisms,它指定了这个 Dovecot 实例支持哪些认证机制。默认情况下,接受纯文本格式的用户和密码的PLAIN机制通常是启用的。

Caution

只有在启用了 TLS 的情况下,才应该使用PLAIN机制;否则,攻击者可能会从网络上窃取您的用户凭证。

您可以在表 12-1 中看到 Dovecot 可用的其他类型。

表 12-1。

Dovecot Authentication Mechanisms

| 机制 | 描述 | | --- | --- | | `PLAIN` | 纯文本身份验证。 | | `LOGIN` | Microsoft Outlook 客户端中使用的一种 Microsoft 身份验证机制。 | | `CRAM-MD5` | 加密密码机制。这在邮件客户端中有一些支持。 | | `DIGEST-MD5` | 像`CRAM-MD5`一样,但是有更强的密码。这限制了客户的支持。 | | `NTLM` | 基于 Microsoft Windows 的身份验证,通常仅在 Microsoft 客户端受支持。 | | `GSSAPI` | Kerberos v5 支持。这限制了客户的支持。 | | `ANONYMOUS` | 支持匿名登录。这是不推荐的,也不安全。 | | `OTP` | 一次性密码机制。 | | `SKEY` | 一次性密码机制。 |

Note

您不能指定 Dovecot 不支持的认证机制。例如,没有正确的支持配置,您就不能指定 NTLM 机制。

在清单 12-9 中,我们还启用了LOGIN认证机制,以防我们的任何用户拥有微软客户端,但是我们不打算启用任何其他类型。绝大多数客户端将支持PLAIN,许多其他客户端也将支持LOGIN认证类型。您可以在 http://en.wikipedia.org/wiki/Comparison_of_e-mail_clients#Authentication_support 找到邮件客户端及其支持的认证机制的完整列表。

此外,在10-auth.conf文件中,我们确定将使用哪个认证服务。在文件的底部,你会看到我们包含了!include auth-system.conf.ext!include声明说我们想要包含这个文件中的配置设置。那个文件位于这里:/etc/dovecot/conf.d/auth-system.conf.ext

如果我们查看该文件,我们需要确保它与清单 12-10 匹配。

passdb {
  driver = pam
  # [session=yes] [setcred=yes] [failure_show_msg=yes] [max_requests=<n>]
  # [cache_key=<key>] [<service name>]
  #args = dovecot
}
userdb {
  # <doc/wiki/AuthDatabase.Passwd.txt>
  driver = passwd
  # [blocking=no]
  #args =

  # Override fields from passwd
  #override_fields = home=/home/virtual/%u
}

Listing 12-10.Specifying the Authentication Service

清单 12-10 中的指令控制 Dovecot 检查以执行认证的认证存储。认证存储的默认驱动程序是pampam存储是一个密码数据库,它利用 PAM 应用程序根据本地主机的用户来验证用户。因此,对于要向主机发送电子邮件进行身份验证的用户,他需要在主机上创建一个具有有效密码的用户。

认证用户时,Dovecot 会在/etc/pam.d目录中查找名为dovecot的 PAM 服务定义。当您在发行版上安装 Dovecot 包时,会安装这个文件。在清单 12-11 中,我们展示了 Ubuntu 的/etc/pam.d/dovecot文件。

#%PAM-1.0
auth       required     pam_nologin.so
auth       include      password-auth
account    include      password-auth
session    include      password-auth
Listing 12-11.Dovecot PAM Service

您可以在清单 12-11 中看到,对 Dovecot 的认证查询使用的 PAM 认证检查与登录到主机的用户所经历的相同(正如您在第五章中看到的)。

Note

您可以在 http://wiki.dovecot.org/PasswordDatabase 找到关于 Dovecot 密码数据库的更多信息,以及在 http://wiki.dovecot.org/PasswordDatabase/PAM 找到关于 Dovecot PAM 认证的更多信息。

清单 12-10 、userdb中的另一条指令设置为driver = passwd。这执行用户查找以返回关于用户的一些信息。它返回用户的 UID、GID 和主目录等信息,并从/etc/passwd file中检索这些信息。如您所见,您可以选择覆盖您在passwd文件中的值,比如用户的主目录,将他们的邮件放在不同于他们正常主目录的目录中。

Note

您可以在 http://wiki.dovecot.org/UserDatabase 了解更多关于用户数据库查找的信息。

配置完 Dovecot 后,您需要启动(或重启)它。我们使用 systemctl 命令启动 Dovecot。

$ sudo systemctl start dovecot

或者,您可以检查 Dovecot 进程是否像这样运行:

$ systemctl status dovecot
● dovecot.service - Dovecot IMAP/POP3 email server
   Loaded: loaded (/usr/lib/systemd/system/dovecot.service; disabled; vendor preset: disabled)
   Active: active (running) since Thu 2016-08-25 09:33:09 EDT; 37min ago
  Process: 7172 ExecStartPre=/usr/libexec/dovecot/prestartscript (code=exited, status=0/SUCCESS)
 Main PID: 7177 (dovecot)
   CGroup: /system.slice/dovecot.service
           ├─7177 /usr/sbin/dovecot -F
           ├─7180 dovecot/anvil
           ├─7181 dovecot/log
           ├─7183 dovecot/config

Aug 25 09:33:09 ip-10-0-10-154.ap-southeast-2.compute.internal systemd[1]: Starting Dovecot IMAP/POP3 email server...
Aug 25 09:33:09 ip-10-0-10-154.ap-southeast-2.compute.internal systemd[1]: Started Dovecot IMAP/POP3 email server.
Aug 25 09:33:09 ip-10-0-10-154.ap-southeast-2.compute.internal dovecot[7177]: master: Dovecot v2.2.10 starting up without any protocols (core dumps disabled)

在这里您可以看到dovecotdovecot-auth进程正在运行,表明 Dovecot 已经成功启动。

在 CentOS 上,Dovecot 记录到/var/log/maillog文件,在 Ubuntu 上记录到/var/log/mail.log file,如果您看到如下所示的日志条目,您可以确认它正在运行:

Jan  7 18:37:03 au-mel-rhel-1  dovecot: Dovecot v1.0.7 starting up

为 SASL 配置后缀

接下来,我们需要配置 Postfix 来使用我们刚刚配置的 Dovecot SASL 服务。将清单 12-12 中的条目添加到main.cf配置文件中。

smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_recipient_restrictions = permit_sasl_authenticated,permit_mynetworks,reject_unauth_destination
smtpd_sasl_auth_enable = yes
smtpd_tls_auth_only = yes
Listing 12-12.Configuring Postfix for Dovecot SASL

在清单 12-12 中,我们使用了smtpd_sasl_type选项来指定我们使用 Dovecot 来执行我们的 SASL 认证。smtpd_sasl_path选项指定了认证套接字相对于 Postfix 的 spool 目录的位置,通常是/var/spool/postfix目录。这与我们之前在清单 12-9 中定义的 Dovecot 客户端套接字相匹配。smtpd_sasl_auth_enable选项告诉 Postfix 启用 SASL 认证。

下一个选项smtpd_tls_auth_only告诉 Postfix 只有在 TLS 启用并运行时才宣布并使用认证。这意味着STARTTLS命令需要在客户机和服务器之间创建加密连接的情况下发出。

最后一个选项smtpd_recipient_restrictions,是 Postfix 的限制列表之一。当发出RCPT TO命令时,它告诉 Postfix 允许或拒绝什么,例如,当从客户端收到电子邮件时。默认情况下,正如我们前面提到的,Postfix 将接受电子邮件

  • 来自 IP 地址与mynetworks选项中的值相匹配的客户端
  • 发送到与relay_domains选项值匹配的远程目的地,默认为mydestination选项值
  • 往返于本地主机

我们将调整这个默认行为,告诉 Postfix 也接受来自 SASL 认证的用户的电子邮件。

首先,我们有permit_mynetworks选项,它在mynetworks选项中维护对网络的访问。然后我们添加permit_sasl_authenticated选项,告诉 Postfix 接受来自 SASL 认证用户的邮件。最后,为了让 Postfix 接收电子邮件并拥有有效的配置,我们必须以拒绝限制结束,在本例中是reject_unauth_destination选项。此选项拒绝任何不符合我们刚刚建立的最后两个标准的电子邮件:发往指定的远程目的地或发往和来自本地主机的电子邮件。

Note

你可以在 www.postfix.org/postconf.5.html#smtpd_recipient_restrictions 看到更多关于收件人限制的信息。

测试后缀身份验证

现在,一旦我们重新启动 Postfix,我们的 SASL 配置应该是活动的,我们可以测试这一点。我们现在有很多方法可以测试这个。第一步是配置一个客户机,向我们的服务器发送经过身份验证的电子邮件。但是由于我们还没有为客户端提供浏览邮箱的方式,比如 IMAP 或 POP3 协议,所以这并不是非常有用。我们可以再次使用openssl s_client命令进行测试。

为了测试连接,我们需要创建一个 base64 编码的用户名和密码。为此,我们将使用 Python。

$ python  -c 'import base64; print base64.b64encode("jsmith")'
anNtaXRo
$ python  -c 'import base64; print base64.b64encode("secret")'
c2VjcmV0

在前面的代码片段中,我们使用了python命令来执行(-c)代码,该代码将创建我们需要的用户名和密码的 base64 编码。我们现在将使用这些值来测试我们是否能够通过 SMTP 服务器的身份验证并发送电子邮件。

在清单 12-13 中,您可以看到一个测试 SASL 认证的openssl s_client会话。

$ openssl s_client -connect mail.example.com:25 -starttls smtp
CONNECTED(00000003)
depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
verify return:1
depth=0 CN = mail.example.com
verify return:1
---
Certificate chain
 0 s:/CN=mail.example.com
   i:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
 1 s:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
   i:/O=Digital Signature Trust Co./CN=DST Root CA X3
---
Server certificate

-----BEGIN CERTIFICATE-----
MIIFGjCCBAKgAwIBAgISA0fRIzPUESQUdGrLEPG8niSXMA0GCSqGSIb3DQEBCwUA
...
<snip>
...
PLCtj2aR+DrP2jz7IKO3CmzrvSbPxs+wtmIpgmV96HLE6zc94xAV6bQEoZWvav5F
I2Ra8G/fFEYE1/nNvinV1ik0Qa68vHqYhL0hemU/2Z8/pBCFWg1txqfSSUq4G4mH
NsOPhphTx/QyYjeU7K0=
-----END CERTIFICATE-----
subject=/CN=mail.example.com
issuer=/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
...
< snip>
...
Verify return code: 0 (ok)
---
250 DSN
ehlo me.com
250-mail.example.com
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-AUTH PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
AUTH LOGIN
334 VXNlcm5hbWU6
anNtaXRo
334 UGFzc3dvcmQ6
c2VjcmV0
235 2.7.0 Authentication successful
MAIL FROM: me@here.com
250 2.1.0 Ok
rcpt to: jsmith@example.com
250 2.1.5 Ok
DATA
354 End data with <CR><LF>.<CR><LF>
Subject: hello you
You're ace
.
250 2.0.0 Ok: queued as 5F2051866087
DONE
Listing 12-13.Using swaks to Test SASL

在清单 12-13 中,我们用–starttls smtp选项启动了openssl s_client命令,它告诉openssl在连接到我们的电子邮件服务器时传递STARTTLS命令。我们已经指定了–connect选项,并传递了我们要连接的主机和端口。

当执行该命令时,您可以看到一个连接被启动,启动了STARTTLS命令,并且显示了服务器的公钥细节。我们得到返回代码250 DSN(表示“交付状态通知”)。然后我们发出ehlo me.com命令,SMTP 服务器用它的服务器名和它拥有的列表功能来响应,其中一个是AUTH PLAIN LOGIN,显示了提供的两种可用的认证机制:PLAINLOGIN

然后我们发出AUTH LOGIN命令,我们看到的是334 VXNlcm5hbWU6,这是 base64 编码的 word 用户名。我们提交用户名,然后我们被要求输入密码(334 UGFzc3dvcmQ6)。我们提交密码,全部采用 base64 编码。身份验证成功,测试电子邮件已提交。如果认证机制失败了,Postfix 会继续尝试认证机制,在我们的例子中是LOGIN然后是PLAIN,直到一个机制成功或者所有机制都失败。如果全部失败,客户端将收到一条错误消息。

Note

我们在前面的例子中使用了小写的 RCPT 来:(rcpt to: jsmith@example.com ))。这是因为openssl将重新协商 TLS 会话,如果线路以大写字母 R 开头,您将无法登录。

您还可以通过检查 Postfix 的 syslog 日志文件来确认会话是否成功。

$ sudo less /var/log/maillog
Aug 26 20:38:31 ip-10-0-10-154 postfix/smtpd[10683]: initializing the server-side TLS engine
Aug 26 20:38:31 ip-10-0-10-154 postfix/smtpd[10683]: connect from
  ppp12-29-41-55.bras1.mel11.internode.on.net[12.29.41.15]
Aug 26 20:38:31 ip-10-0-10-154 postfix/smtpd[10683]: setting up TLS connection from
  ppp12-29-41-55.bras1.mel11.internode.on.net[12.29.41.15]
Aug 26 20:38:31 ip-10-0-10-154 postfix/smtpd[10683]: ppp12-29-41-15.bras1.mel11.internode.on.net[12.29.41.15]:
  TLS cipher list "aNULL:-aNULL:ALL:!EXPORT:!LOW:!MEDIUM:+RC4:@STRENGTH:!aNULL:!MD5"

Aug 26 07:52:14 mail postfix/smtpd[9215]: 5F2051866087:  
  client=ppp12-29-41-55.bras1.mel11.internode.on.net[12.29.41.15], sasl_method=LOGIN, sasl_username=jsmith
Aug 26 07:52:29 mail postfix/anvil[9162]: statistics: max connection rate 1/60s for (smtp: 12.29.41.15) at Aug 26 07:42:29
Aug 26 07:52:29 mail postfix/anvil[9162]: statistics: max connection count 1 for (smtp: 12.29.41.15) at Aug 26 07:42:29
Aug 26 07:52:29 mail postfix/anvil[9162]: statistics: max cache size 1 at Aug 26 07:42:29

Aug 26 07:52:37 mail postfix/cleanup[9227]: 5F2051866087: message-id=<>
Aug 26 07:52:37 mail postfix/qmgr[1186]: 5F2051866087: from=<me@here.com>, size=270, nrcpt=1 (queue active)
Aug 26 07:52:37 mail postfix/local[9228]: 5F2051866087: to=<jsmith@example.com>, relay=local, delay=235, delays=235/0.01/0/0, dsn=2.0.0, status=sent (delivered to mailbox)
Aug 26 07:52:37 mail postfix/qmgr[1186]: 5F2051866087: removed

Aug 26 07:52:44 mail postfix/smtpd[9215]: disconnect from ppp12-29-41-15.bras1.mel11.internode.on.net[12.29.41.15]

请注意,在第一部分中建立了 TLS 连接,然后启动身份验证,发送电子邮件,最后断开连接。

如果您的身份验证成功,您现在已经运行了 Postfix 身份验证,您的服务器现在可以被远程用户使用,并且您的内部用户可以安全地提交电子邮件。

如果您在配置 Postfix 身份验证时遇到问题,请参阅即将到来的“获取 Postfix 帮助”一节中的指针和链接。

Smarthosting

正如我们在本章前面所提到的,一些 ISP 会阻止传出的 SMTP 流量。这是为了帮助减少垃圾邮件。此外,一些 SMTP 服务器被配置为不接收来自特定类型网络的电子邮件,如 ADSL 和使用动态 IP 地址的网络。如果您无法发送出站电子邮件,或者某些服务器拒绝来自您的服务器的连接,这可能就是问题所在。检查这一点的一个简单方法是,看看您是否可以使用类似swaks的工具连接到外部 MTA,或者您是否可以联系您的 ISP 以了解它是否限制传出的 SMTP 流量。

如果你被屏蔽了,你可以用智能主机来解决这个问题。智能主机是接收和转发电子邮件的中继服务器。许多 ISP 为他们的用户提供智能主机。

有两种类型的智能主机—未经身份验证的和经过身份验证的。这两种类型都是用main.cf配置文件中的relayhost配置选项指定的(参见 www.postfix.org/postconf.5.html#relayhost ),如下所示,其中mail.isp.net是您的智能主机的主机名:

relayhost = mail.isp.net

这将告诉您的 Postfix 电子邮件服务器将所有发出的电子邮件发送到mail.isp.net。这假定智能主机将接受来自您的电子邮件;例如,一些 ISP 智能主机很乐意接受来自 ISP 管理的任何 IP 地址的电子邮件。

然而,有时如果没有 SASL 认证,你的智能主机不会接受你发来的电子邮件。如果是这样,您需要配置智能主机身份验证。为此,您需要配置 SASL 身份验证,其中 Postfix 是客户端而不是服务器。请记住,当您将它配置为服务器时,所有的配置选项都以smtpd_开头,表示它是用于连接到服务器的。现在您需要将 Postfix 配置为客户端,并且您使用以smtp开始的配置选项。为此,在main.cf文件中设置以下选项:

smtp_sasl_password_maps = hash:/etc/postfix/smtp_sasl_passwd
smtp_sasl_auth_enable = yes
smtp_sasl_mechanism_filter = plain, login
smtp_sasl_security_options = noanonymous

当服务器是客户端时,这将为您的服务器配置 SASL 身份验证。smtp_sasl_password_maps选项(参见 www.postfix.org/postconf.5.html#smtp_sasl_password_maps )指定一个数据库文件,该文件包含一系列智能主机及其所需的凭证。这是通过编辑一个文件并使用postmap命令从该文件创建一个数据库来创建的。/etc/postfix/smtp_sasl_passwd文件需要包含智能主机的名称以及进行身份验证所需的用户名和密码(用冒号分隔),如下所示:

mail.isp.net        username:password

您需要确保这些文件只对根用户可读,并且有适当的权限阻止任何人查看您的密码。

$ sudo chown root:root /etc/postfix/smtp_sasl_passwd
$ sudo chmod 0600 /etc/postfix/smtp_sasl_passwd

然后我们使用postmap命令创建一个数据库。

$ sudo postmap hash:/etc/postfix/smtp_sasl_passwd

然后创建一个名为smtp_sasl_passwd.db的文件。

剩下的选项非常简单。smtp_sasl_auth_enable选项打开 Postfix 作为客户端的 SASL 认证。smtp_sasl_mechanism_filter选项指定智能主机支持什么类型的认证机制,而smtp_sasl_security_options选项禁用匿名机制。

更新配置后,您需要重新加载或重新启动 Postfix,然后可以测试您的服务器是否可以向智能主机发送经过 SASL 验证的电子邮件。您还可以使用传输选项指定更细粒度的智能托管(参见 www.postfix.org/transport.5.html )。

后缀查找表和虚拟域

我们已经在本章讨论了查找和映射,或者是别名,或者是密码。这些通常被称为查找表。后缀查找表用于存储有关访问、路由、重写和过滤内容的信息。查找表可以是基于文本文件的数据库、LDAP 数据库或 SEQUEL 数据库。我们将看两个查找表的例子:别名和虚拟别名域。

前面我们谈到了newaliases命令。该命令使用postalias命令获取在/etc/aliases文件中列出的名称和别名,并创建一个由local交付守护程序使用的索引文件。我们可以使用postalias命令来创建和管理索引目录;然而,newaliases命令为我们管理了这一点,因为我们也需要在每次更改后将配置重新加载到守护进程中,因此更容易使用(并且也与 Sendmail 程序兼容)。

我们可以使用postalias命令来查询别名散列。

$ sudo postalias -c /etc/postfix/ -q root hash:/etc/aliases
ataylor

我们通过main.cf文件中的alias_database配置告诉 Postfix 使用哪个表。我们可以通过以下内容轻松查看:

$ postconf –n |grep alias_database
alias_database = hash:/etc/aliases

我们可以转向更复杂的用途。我们的主机可能是发往example.com域的邮件的最终目的地。但是它也可以用来“托管”其他域。在这种情况下,我们的服务器可能是example.comexample.netexample.id或任何其他类型的注册域名的最终目的地,这些域名的 MX 记录指向我们的邮件服务器。

我们可以通过main.cf文件中的mydestination设置来实现。

mydestination = mail.example.com example.net example.id example.com

这意味着ataylor@example.com的邮件将需要一个本地的ataylor Linux 用户帐户,该地址将被发送到ataylor@example.comataylor@example.netataylor@example.id的同一个邮箱。你可能希望admin@example.comataylor,而admin@example.netbsingh。您可能根本不希望发生这种情况,也可能不希望在您的邮件服务器上为每个邮件用户提供一个 Linux 用户帐户。如果你为多个不同的域托管,这也变得笨拙。

Postfix 可以用两种不同的方式解决这个问题。

  • 虚拟别名域
  • 虚拟邮箱域

您可以采取的第一步是创建虚拟域。这允许您将虚拟域映射到每个域的用户帐户。因此,在前面的例子中,admin@example.com可以转到不同于admin@example.net的用户。为此,我们在 Postfix 中使用一个查找表来管理每个域的用户。

我们需要在我们的main.cf文件中设置以下内容。

virtual_alias_domains = example.net example.id example.com
virtual_alias_maps = hash:/etc/postfix/virtual

我们已经告诉 Postfix,如果它收到给example.com.net.id的邮件,就使用索引文件alias_map /etc/postfix/virtual,这个文件将包含我们的列表。

/etc/postfix/virtual
admin@example.com ataylor
sales@example.com  jsmith
....
admin@example.net bsingh
sales@example.net jsmith ataylor@example.com

这里我们有两个域,example.comexample.netadmin@example.com地址别名为atayloradmin@example.net将被发送到bsingh。该地址可以是本地 Linux 地址或远程地址,就像您在sales@example.net地址中看到的那样。在我们创建了这个文件之后,以及每次我们更改它之后,我们需要使用postmap命令来重新创建索引,并重启 Postfix 来获取更改。

$ sudo postmap /etc/postfix/virtual
$ sudo systemctl reload postfix

假设我们不想在邮件服务器上创建 Linux 用户帐户。我们仍然可以通过虚拟邮箱为邮件用户发送邮件。我们不能为同一个域设置虚拟别名域和虚拟邮箱域,所以只能选其一。

要设置虚拟邮箱域,我们需要设置以下内容:

/etc/postfix/main.cf:
mydestination = localhost
virtual_mailbox_domains = hash:/etc/postfix/virt_domains
virtual_mailbox_maps = hash:/etc/postfix/virt_mailbox
virtual_alias_maps = hash:/etc/postfix/virtual
virtual_transport = lmtp:unix:private/dovecot-lmtp

在前面的例子中,我们已经将mydestination选项重置为localhost,并从virtual_mailbox_domains设置中获取目的地列表。virtual_mailbox_maps设置将列出我们接受的邮件地址。virtual_alias_maps设置将包含邮件用户的别名,就像别名文件一样。

这里是我们接受邮件的虚拟域。它们的格式是<domain> <action>

/etc/postfix/virt_domain
example.com         OK
example.net         OK
example.id          OK

在这里,我们为所有的域设置了OK动作。其他可以设置的动作包括DISCARDFILTERREJECT等。virtual_mailbox文件有类似的语法。

/etc/postfix/virt_mailbox:
ataylor@example.com    OK
ataylor@example.net    OK
bsingh@example.com     OK
jsmith@example.net     OK

这里列出了我们接受的电子邮件地址。同样,我们可以设置其他动作来代替OK,比如REJECTFILTERBCC

最后,我们也可以像对待/etc/aliases文件一样使用虚拟别名。在这里,我们在左侧列出我们接受的电子邮件地址,在右侧列出目的地:

/etc/postfix/virtual:
admin@example.com ataylor@example.com

一旦我们配置或更改了这些,我们需要再次运行postmap命令。

$ sudo postmap /etc/postfix/virt_domains
$ sudo postmap /etc/postfix/virt_mailbox
$ sudo postmap /etc/postfix/virtual
$ sudo systemct reload postfix

现在我们已经为我们的域做好了准备,我们可以将查找表改为 SQL 或 LDAP 支持的。查找表还有许多其他选项;如需完整列表,请访问:

获取后缀的帮助

Postfix 不仅是最容易配置的应用程序之一,具有简单的配置模型和大量的文档,而且也是最容易诊断的应用程序之一,大多数错误消息都是描述性的和有帮助的。

Note

不是所有的 MTA 都很容易配置,其他的有复杂的语法和令人困惑的错误信息。您会发现 Postfix 很容易配置,但其他如 Exim 和 Qmail 也很容易。

你可以在 Postfix 主页( www.postfix.org/ )找到有用的文档。这包括文档( www.postfix.org/documentation.html )以及操作方法和常见问题( www.postfix.org/docs.html )。

有一些有用的资源专门用于 SSL/TLS 加密和 SASL 的配置和故障排除。加密可以在 www.postfix.org/TLS_README.html 找资源。对于 SASL,你可以在 www.postfix.org/SASL_README.html 找到一个有用的 how-to,在 http://adomas.org/2006/08/postfix-dovecot/ 找到另一个 Ubuntu,在 www.lxtreme.nl/index.pl/docs/linux/dovecot_postfix_pam 找到一个更高级的版本。

以下文档也能有所帮助: www.postfix.org/DEBUG_README.html 。它展示了如何调试后缀问题,从增加日志的冗长度到跟踪后缀进程。最有用的调试工具之一是debug_peer_list选项。

通过设置debug_peer_list,可以增加邮件日志中关于一个对等体的信息。您可以这样设置它:

debug_peer_list = troubled.domain.com

在从troubled.domain.com开始的下一次连接中,您将看到日志记录的增加,您会发现这非常有用。

您还可以在 www.postfix.org/SOHO_README.html 找到一些在小型办公室/家庭办公环境中运行 Postfix 的技巧,您可能想考虑在 www.postfix.org/lists.html 加入 Postfix 邮件列表。

请记住,如果您提交问题或错误,您应该包括以下信息:

  • 您的后缀配置(运行postconf -n)
  • 你的平台(运行uname -a
  • 生成的任何日志消息(在 Ubuntu 上的/var/log/mail.log文件中或在 CentOS 上的/var/log/maillog文件中)

在 Freenode IRC 服务器( http://freenode.net/ )上还有一个名为#postfix的 IRC 频道,你可以在那里寻求帮助。

抗击病毒和垃圾邮件

现在您已经运行了带加密和认证的 Postfix,我们将向您展示如何保护您的用户和组织免受垃圾邮件和病毒的侵害。我们将会看到两种工具。

  • SpamAssassin:一个开源反垃圾邮件工具
  • ClamAV:一个开源的反病毒扫描器和引擎

我们将把这两个工具与 Postfix 集成在一起,并教你如何使用它们。

打击垃圾邮件

垃圾邮件是不请自来的电子邮件,范围从请求帮助处理各种非法金融交易到提供将扩大人体解剖部分的药物。垃圾邮件是对用户幸福的最大威胁之一。没有什么比上班时发现一大堆垃圾邮件和你的真实邮件被埋在地下更让人恼火的了。这对您的组织和用户也是一种威胁,因为垃圾邮件通常隐藏着网络钓鱼攻击( http://en.wikipedia.org/wiki/Phishing )、病毒分发和其他类型的恶意软件攻击。

我们将配置我们的 Postfix 服务器来自行拒绝一些垃圾邮件,然后向您介绍一个流行的反垃圾邮件工具 SpamAssassin。SpamAssassin 是一个贝叶斯垃圾邮件过滤器( http://en.wikipedia.org/wiki/Bayesian_spam_filtering )。简单地说,贝叶斯垃圾邮件过滤是一种预测电子邮件中出现单词、短语或其他特征意味着该电子邮件是垃圾邮件的可能性的方法。

根据通过一系列可定制的测试或规则计算的数字分数,每封电子邮件被标记为垃圾邮件或不被标记为垃圾邮件;默认情况下,高于 5.0 的分数被标记为垃圾邮件。根据规则的权重,每个规则会增加或减少该分数。例如,一个规则可能会检查电子邮件的某个特定特征,如果匹配,SpamAssassin 可能会给分配给该电子邮件的分数加 0.5。

贝叶斯垃圾邮件过滤器还可以从用户收到的邮件中学习模式,并可以通过告诉他们哪些邮件是垃圾邮件,哪些不是垃圾邮件来进行训练,这被 SpamAssassin 称为 ham(http://en.wikipedia.org/wiki/Spam_(food`)。从它的学习中得到的数据被添加到一个数据库中,并用于使未来对收到的电子邮件的分析更加准确。

SpamAssassin 在您的主机上作为一个守护进程运行,电子邮件被提交给守护进程,经过分析,然后通过添加一个新的标头被标记为垃圾邮件或非垃圾邮件。

为反垃圾邮件配置 Postfix

在我们配置 SpamAssassin 之前,我们将收紧我们的后缀配置。为此,我们将一些配置选项添加到我们的main.cf配置文件中。这些选项中的大多数会拒绝不符合 SMTP RFC 的电子邮件,例如,拒绝源地址不是有效电子邮件的电子邮件。

我们主要是要更新我们在研究后缀认证时引入的限制列表。表 12-2 列出了这些限制列表。

表 12-2。

Postfix Restriction Lists

| 限制列表 | 描述 | | --- | --- | | `smtpd_client_restrictions` | 客户端连接时的限制 | | `smtpd_helo_restrictions` | 发出`HELO` / `EHLO`命令时的限制 | | `smtpd_sender_restrictions` | 发出`MAIL FROM`命令时的限制 | | `smtpd_relay_restrictions` | 在`smtpd_recipient_restrictions`之前应用于`RCPT TO`的限制 | | `smtpd_recipient_restrictions` | 发出`RCPT TO`命令阻止垃圾邮件时的限制 | | `smtpd_data_restrictions` | 发出`DATA`命令时的限制 |

当特定事件发生时,限制列表被触发;比如客户端连接时检查smtpd_client_ restrictions,客户端发出EHLO命令时检查smtpd_helo_restrictions。如果客户端不发送EHLO命令,这些限制无效。使用postconf命令,我们可以用postconf –emain.cf文件添加指令。我们将添加以下内容:

$ sudo postconf –e 'smtpd_helo_restrictions = reject_unknown_helo_hostname'
$ sudo postconf –e 'smtpd_helo_required = yes'

对于第一个选项smtpd_helo_restrictions,如果它在 DNS 中没有 A 或 MX 记录,我们将拒绝连接的电子邮件服务器。为此,smtpd_helo_required告诉 Postfix 拒绝来自不发送正确的EHLO的客户端的连接,并宣布它们的名称。smtpd_helo_required使连接的 MTA 发送EHLO命令。

在这种情况下,我们将向发件人、收件人和数据限制列表添加一些选项。首先,向main.cf添加smtpd_sender_restrictions选项,如下所示:

$ sudo postconf –e 'smtpd_sender_restrictions = reject_non_fqdn_sender, reject_unknown_sender_domain'

reject_non_fqdn_sender选项拒绝发件人邮件地址格式不正确的电子邮件。这意味着由MAIL FROM命令传递的值必须是有效电子邮件地址的形式,例如ataylor@example.com。诸如Anne TaylorataylorAnne之类的地址或任何您无法回复的地址将不会被接受,该电子邮件也因此被拒绝。

reject_unknown_sender_domain选项拒绝发件人的域名没有 DNS A 或 MX 记录的电子邮件。这通常是因为电子邮件是从一个伪造的域发送的,垃圾邮件也是如此。

我们可以通过添加以下内容来防止我们的电子邮件服务器成为中继服务器:

$ sudo postconf –e 'smtpd_relay_restrictions = permit_mynetworks, permit_sasl_authenticated,
reject_unauth_destination'

这里我们说,我们将允许任何指定的网络(permit_mynetworks)向其他目的地邮件服务器发送邮件。接下来,我们将允许任何经过身份验证的(通过 SASL)客户端(permit_sasl_authenticated)向其他目标服务器发送电子邮件。最后,我们将拒绝任何邮件到未经授权的目的地(reject_unauth_destination)。

接下来,我们想为我们的smtpd_recipient_restrictions选项添加另一个拒绝标准。

$ sudo postconf –e 'smtpd_recipient_restrictions = reject_rbl_client zen.spamhaus.org,
  reject_rhsbl_reverse_client dbl.spamhaus.org,
   reject_rhsbl_helo dbl.spamhaus.org, reject_rhsbl_sender dbl.spamhaus.org, reject_unauth_pipelining '

在本节中,我们试图通过拒绝已知的黑名单服务器和域来减少垃圾邮件的数量。Spamhaus 项目是一个跟踪垃圾邮件和其他网络威胁的非营利组织。它提供了一项服务,您可以通过查询来帮助减少您收到的垃圾邮件数量。这些实时黑洞列表(rbl)将允许您查询他们的数据库中已知的开放中继和坏的往来地址。

reject_rbl_clientzen.spamhaus.org查询 DNS 阻止列表(DNSBL)并拒绝那里的任何肯定条目。reject_rhsbl_reverse_client基于客户端查询dbl.spamhaus.org,客户端是一个域黑名单(DBLs)。它可以根据几个要素(??、IP/DNS、收件人和发件人等)来帮助拒绝垃圾邮件。另外两个 dbl 分别工作在HELO ( reject_rhsbl_helo)和reject_rhsbl_sender

我们包含了reject_unauth_pipelining限制,拒绝使用一种称为管道的特殊技术提交的电子邮件,而不检查是否支持管道。这是垃圾邮件发送者提交电子邮件的常用技巧。

我们还将把这个相同的选项添加到smtpd_data_restrictions中,以捕捉在发出DATA命令时使用相同技术的垃圾邮件发送者。

smtpd_data_restrictions = reject_unauth_pipelining

最后,我们将配置一个与限制列表无关的选项,以阻止一些垃圾邮件。

$ sudo postconf –e 'disable_vrfy_command = yes'

disable_vrfy_command选项禁用 SMTP VRFY命令。VRFY命令允许发送者查询后缀服务器并验证地址是否存在。垃圾邮件发送者使用它来验证地址,黑客偶尔也会在攻击前获取您主机上用户的名称。

Note

您还可以启用其他限制,但这些是最简单、最容易且最不可能将合法电子邮件限制到您的 Postfix 服务器的限制。详见 www.postfix.org/uce.html

完成更改后,重新启动 Postfix 守护进程。

Note

在进行更改后,最好确认您仍然可以发送和接收电子邮件。

安装和配置 SpamAssassin

为了补充我们的后缀更改,我们将安装和配置 SpamAssassin。我们将从安装所需的包开始。在 CentOS 上,我们需要安装spamassassin包,并告诉它自动启动 SpamAssassin 守护进程。

$ sudo yum install spamassassin

在 Ubuntu 上,我们需要安装spamassassinspamc包。

$ sudo aptitude install spamassassin

当 SpamAssassin 打开时,它会启动一个名为spamd的守护进程。我们将创建一个运行这个名为spamd的守护进程的系统用户。

$ sudo useradd –r –m –s /sbin/nologin spamd

–r表示我们需要一个系统用户(UID 低于 1000),–m表示我们需要创建主目录,-s是 shell。前一个是给 CentOS 的;对于 Ubuntu,你可以将 shell 改为/usr/sbin/nologin

然后,我们通过在两个发行版上发出以下命令来启用 SpamAssassin 守护进程:

$ sudo systemctl enable spamassassin

Note

SpamAssassin 软件包有一些额外的必备软件包,当您安装它们时,它们也将安装在 CentOS 和 Ubuntu 上。

对于 SpamAssassin,您可以通过编辑两个发行版上的/etc/mail/spamassassin中的文件来修改配置。您可能想要编辑具有邮件被分类为垃圾邮件的阈值的local.cf文件(required_score)。

我们需要更改的另一个文件是 CentOS 上的/etc/sysconfig/spamassassin或 Ubuntu 上的/etc/default/spamassassin。这个文件控制我们提供给spamd的选项(CentOS 上的SPAMDOPTION,Ubuntu 上的OPTION)。我们将添加运行spamd守护进程的用户和组。

SPAMDOPTIONS="-d -c -m5 -H -u spamd -g spamd"

这里我们将–u–g选项添加到默认设置中。这些缺省值是–d代表后台化,-c代表创建用户偏好文件,-m代表子进程的数量,-H代表指定不同的帮助目录(针对第三方服务)。

然后我们需要启动 SpamAssassin spamd守护进程。我们使用systemctl命令。

$ sudo systemctl start spamassassin

Tip

与 Postfix 一样,在对配置进行更改后,重新启动 SpamAssassin 是一个好主意。

为 SpamAssassin 配置后缀

有许多不同的方法可以将 SpamAssassin 这样的垃圾邮件过滤器集成到您的电子邮件环境中。一种是在将用户收到的电子邮件发送给用户之前,使用 MDA 对其进行扫描。然后,垃圾邮件过滤器通常会在电子邮件中添加邮件头,MDA 会检测到邮件头,并将垃圾邮件定向到特定的文件夹。

另一种方法是在电子邮件仍在 MTA 中时对其进行分析。这允许我们将邮件从 Postfix 的邮件队列传递到 SpamAssassin。然后,电子邮件被扫描并发送回 Postfix 进行发送。然后,客户端或 MDA 可以利用该扫描的结果(同样是添加到电子邮件的标题)来确定如何处理该电子邮件。在图 12-3 中,你可以看到通过 Postfix 的电子邮件的建议流程。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12-3。

SpamAssassin and Postfix filtering

我们将选择后一种方法,因为对于大多数环境来说,这种方法效率更高,可伸缩性更强。

首先,我们更新master.cf文件以向 SpamAssassin 发送电子邮件。为此,我们调整master.cf文件中的smtp服务,如下所示:

smtp     inet     n     -     n     -     -     smtpd
    -o content_filter=spamassassin

这将添加行-o content_filter=spamassassin(-o应该用空格缩进,以显示它是前一行的后续)。content_filter选项告诉 Postfix,我们希望所有发送到smtp服务的电子邮件都被发送到一个名为spamassassin的过滤器。

我们现在需要定义这个过滤器。为此,我们将过滤器添加到master.cf文件的底部。如下定义过滤器:

spamassassin     unix     -     n     n     -     -     pipe
 user=spamd argv=/usr/bin/spamc -e /usr/sbin/sendmail -oi -f ${sender} ${recipient}

这在master.cf file中创建了一个类型为unix的新服务,这是一个 Unix 套接字,它调用另一个名为pipe的 Postfix 守护进程,这个守护进程向外部命令发送电子邮件。在接下来的几行中(再次缩进),我们指定外部命令。

我们指定将要运行的外部命令、运行该命令的用户,然后指定要传递给该命令的命令和参数。我们调用spamc命令,这个二进制文件连接到spamassassin守护进程,提交我们的电子邮件,然后接收扫描结果。

对于spamc命令,我们传递了-e参数。这个参数(必须在命令行的最后指定)告诉spamc命令在电子邮件被扫描后如何处理它。在这种情况下,我们将它提交给/usr/sbin/sendmail命令,这是 Postfix 命令,它将我们的电子邮件传递回 Postfix 以传递给用户(这里的sendmail程序是指向/usr/sbin/sendmail.postfix的符号链接)。

我们还为sendmail命令指定了一些选项。–oi选项告诉sendmail命令,当它发现一行只有一个句点(.)时,不要停止处理电子邮件(还记得我们之前的测试电子邮件在发送一行有句点的行时就结束了)。这是因为电子邮件中可能有一行带有句点,可能并不表示电子邮件的结束。-f ${sender}选项确保电子邮件的发件人被发送到 Postfix。最后,${recipient}选项包含电子邮件的收件人,因此 Postfix 知道该将电子邮件发送给谁。

测试 SpamAssassin

为了测试 SpamAssassin,让我们使用swaks工具发送一封电子邮件,这是一个可以通过包管理器安装的电子邮件测试工具,并检查结果。

$ swaks -tls -a -au ataylor -ap password -t jsmith@example.com -f
ataylor@example.com --body /usr/share/doc/spamassassin-3.4.0/sample-spam.txt

这个命令连接到您的邮件服务器,并从经过 SASL 认证的用户ataylor向用户jsmith@example.com发送一封电子邮件。我们还添加了--body选项来指定我们电子邮件的内容。在本例中,我们使用 SpamAssassin 包中提供的垃圾邮件示例。该电子邮件位于/usr/share/doc/spamassassin-<version>/目录中(用您的 SpamAssassin 版本替换版本,例如 3.4.0)。这个垃圾邮件样本肯定会触发 SpamAssassin 的垃圾邮件过滤器,从而测试我们的垃圾邮件检测。

如果我们检查我们的 Postfix 日志,我们可以看到这封电子邮件被接收和处理,如清单 12-14 所示。

$ sudo less /var/log/mail.log
Aug 27 08:11:35 ip-10-0-10-154 postfix/qmgr[12743]: 564B21866089: from=<ataylor@example.com>, size=1316,
  nrcpt=1 (queue active)
Aug 27 08:11:35 ip-10-0-10-154 spamd[12345]: spamd: connection from localhost [::1]:46002 to port 783, fd 6
Aug 27 08:11:35 ip-10-0-10-154 spamd[12345]: spamd: setuid to mail succeeded
Aug 27 08:11:35 ip-10-0-10-154 spamd[12345]: spamd: creating default_prefs: /home/spamd/.spamassassin/user_prefs
Aug 27 08:11:35 ip-10-0-10-154 spamd[12345]: spamd: failed to create readable default_prefs:
  /var/spool/mail/.spamassassin/user_prefs
Aug 27 08:11:35 ip-10-0-10-154 spamd[12345]: spamd: processing message (unknown) for mail

:8
Aug 27 08:11:36 ip-10-0-10-154 spamd[12345]: spamd: identified spam (999.1/5.0) for mail:8 in 0.3 seconds, 1280 bytes.
Aug 27 08:11:36 ip-10-0-10-154 spamd[12345]: spamd: result: Y 999 - ALL_TRUSTED,GTUBE,MISSING_MID
  scantime=0.3,size=1280,user=mail,uid=8,required_score=5.0,rhost=localhost,raddr=::1,rport=46002,
  mid=(unknown),autolearn=no autolearn_force=no
Aug 27 08:11:36 ip-10-0-10-154 spamd[12344]: prefork: child states: II
Aug 27 08:11:36 ip-10-0-10-154 postfix/pipe[12758]: 564B21866089: to=<jsmith@example.com>, relay=spamassassin,
  delay=0.89, delays=0.57/0.01/0/0.3, dsn=2.0.0, status=sent (delivered via spamassassin service)
Aug 27 08:11:36 ip-10-0-10-154 postfix/qmgr[12743]: 564B21866089: removed
Aug 27 08:11:36 ip-10-0-10-154 postfix/pickup[12742]: 0AF49181186C: uid=8 from=<ataylor@example.com>
Aug 27 08:11:36 ip-10-0-10-154 postfix/cleanup[12757]: 0AF49181186C: message
  id=<20160827121136.0AF49181186C@mail.example.com>
Aug 27 08:11:36 ip-10-0-10-154 postfix/qmgr[12743]: 0AF49181186C: from=<ataylor@example.com>, size=2091,
   nrcpt=1 (queue active)
Aug 27 08:11:36 ip-10-0-10-154 postfix/local[12762]: 0AF49181186C: to=<jsmith@example.com>, relay=local,
  delay=0.04, delays=0.03/0.01/0/0, dsn=2.0.0, status=sent (delivered to mailbox)
Aug 27 08:11:36 ip-10-0-10-154 postfix/qmgr[12743]: 0AF49181186C: removed
Listing 12-14.Postfix Logs with SpamAssassin

在清单 12-14 中,我们已经连接到我们的 Postfix 服务器,通过了身份验证,并提交了我们的电子邮件。在交易过程中,电子邮件被提交给 SpamAssassin(参见带有spamd的行,这是 SpamAssassin 守护进程)。

Aug 27 08:11:35 ip-10-0-10-154 spamd[12345]: spamd: connection from localhost [::1]:46002 to port 783, fd 6
Aug 27 08:11:35 ip-10-0-10-154 spamd[12345]: spamd: setuid to mail succeeded
Aug 27 08:11:35 ip-10-0-10-154 spamd[12345]: spamd: creating default_prefs: /home/spamd/.spamassassin/user_prefs
Aug 27 08:11:35 ip-10-0-10-154 spamd[12345]: spamd: processing message (unknown) for mail:8
Aug 27 08:11:36 ip-10-0-10-154 spamd[12345]: spamd: identified spam (999.1/5.0) for mail:8 in 0.3 seconds, 1280 bytes.
Aug 27 08:11:36 ip-10-0-10-154 spamd[12345]: spamd: result: Y 999 - ALL_TRUSTED,GTUBE,MISSING_MID
 scantime=0.3,size=1280,user=mail,uid=8,required_score=5.0,rhost=localhost,raddr=::1,rport=46002,
  mid=(unknown),autolearn=no autolearn_force=no

我们可以看到 SpamAssassin 守护进程从服务器获得一个连接,将我们的用户更改为mail用户,并处理我们的电子邮件。它返回了一行指示该邮件是垃圾邮件的信息,得分为999.1/5.0(明显大于 5.0,因此是垃圾邮件)。

SpamAsssassin 的工作原理是对已知的垃圾邮件模式进行多次检查。

  • 标题测试
  • 身体短语
  • 贝叶斯过滤器
  • 白名单/黑名单
  • 声誉检查
  • 协作检查
  • rbl 和 DNSRBLs

每一个都会增加总分数,如果超过 5 分,就被认为是垃圾邮件。对之前的测试垃圾邮件触发的检查列表为ALL_TRUSTED,GTUBE,MISSING_MID。看到类似ADVANCE_FEE_5_NEW_FRM_MNY, FILL_THIS_FORM,FILL_THIS_FORM_LOAN这样的垃圾邮件,你会看到其他被触发的。

您还可以训练您的贝叶斯过滤器,以更好地检测来自火腿的垃圾邮件。如果您有一个已知充满垃圾邮件的邮箱,您可以通过发出以下命令来训练您的过滤器:

$ sudo sa-learn --showdots --mbox --spam file-of-spam

您还应该向您的过滤器传授有关 ham 的知识,为此,您应该发出以下命令:

$ sudo sa-learn --showdots --mbox --ham file-of-ham

我们还可以查看我们的实际电子邮件,了解 SpamAssassin 添加的邮件头的详细信息。

$ sudo cat /home/jsmith/Maildir/new/1472350940.Vca02I203b0aaM132480.mail.example.com
Return-Path: <ataylor@example.com>
X-Original-To: jsmith@example.com
Delivered-To: jsmith@example.com
Received: by mail.example.com (Postfix, from userid 993)
id 1F0C4181186F; Sat, 27 Aug 2016 22:22:20 -0400 (EDT)
X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on
mail.example.com
X-Spam-Flag: YES
X-Spam-Level: **************************************************
X-Spam-Status: Yes, score=999.1 required=5.0 tests=ALL_TRUSTED,GTUBE,
MISSING_MID autolearn=no autolearn_force=no version=3.4.0
X-Spam-Report:
* -1.0 ALL_TRUSTED Passed through trusted hosts only via SMTP
* 1000 GTUBE BODY: Generic Test for Unsolicited Bulk Email
*  0.1 MISSING_MID Missing Message-Id: header
Received: from me.here (me.here [63.38.238.98])
for <jsmith@example.com>; Sat, 27 Aug 2016 22:22:19 -0400 (EDT)
Date: Sat, 27 Aug 2016 22:22:17 -0400
To: jsmith@example.com
From: ataylor@example.com
Subject: [SPAM] test Sat, 27 Aug 2016 22:22:17 -0400
X-Mailer: swaks v20130209.0 jetmore.org/john/code/swaks/
X-Spam-Prev-Subject: test Sat, 27 Aug 2016 22:22:17 -0400
Message-Id: <20160828022220.1F0C4181186F@mail.example.com>

Subject: Test spam mail (GTUBE)
Message-ID: <GTUBE1.1010101@example.net>
Date: Wed, 23 Jul 2003 23:30:00 +0200
From: Sender <sender@example.net>
To: Recipient <recipient@example.net>
Precedence: junk
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

我们可以看到 SpamAssassin 增加了 6 个头球。

  • SpamAssassin 版本
  • X-Spam-Level:星号表示总分
  • X-Spam-Flag:仅当电子邮件被识别为垃圾邮件时出现
  • X-Spam-Status:垃圾邮件状态(NoYes),电子邮件的总得分,以及检查的垃圾邮件测试列表
  • X-Spam-Report:垃圾邮件分数是如何得出的
  • X-Spam-Prev-Subject:上一个垃圾邮件主题标题

列表中的前三个被添加到所有电子邮件中;只有当电子邮件被认为是垃圾邮件时,才会添加最后三个。

获得 SpamAssassin 的帮助

与 Postfix 一样,获得 SpamAssassin 的帮助也很容易。网上有丰富的文档以及有用的、广泛的社区。寻求帮助的最佳起点是位于 http://spamassassin.apache.org/ 的 SpamAssassin 主页。该页面包括维基、常见问题和文档。还可以在 http://wiki.apache.org/spamassassin/MailingLists 加入活动邮件列表,在 https://issues.apache.org/SpamAssassin/index.cgi 提交 bug。

您可以通过在我们之前描述的spamd守护进程选项中添加一个-D来提高spamd的调试级别。这将增加您的日志记录级别,并让您深入了解spamd正在做什么。

请记住,如果您提交问题或错误,您应该包括以下信息:

  • 您的 SpamAssassin 和 Perl 版本(运行带有--version选项的spamassassin命令)
  • 你的平台(运行uname -a
  • 生成的任何日志消息(在 Ubuntu 上的/var/log/mail.log文件中或在 CentOS 上的/var/log/maillog文件中)

在 Freenode IRC 服务器( http://freenode.net/ )上还有一个名为#spamassassin的 IRC 频道,你可以在那里寻求帮助。

如何处理垃圾邮件?

如果我们的电子邮件被 SpamAssassin 识别为垃圾邮件,我们可以通过添加“[SPAM]”来修改主题行,但仅此而已。它仍然作为新邮件发送到用户的收件箱中。在大多数情况下,人们把他们的垃圾邮件放在一个单独的文件夹中进行审查,通常会删除。有些人拒绝或删除任何标记为垃圾邮件的电子邮件,导致可能重要的电子邮件丢失。包括 SpamAssassin 在内的垃圾邮件检测工具并不可靠,有时会产生误报。这意味着合法的电子邮件可以被标记为垃圾邮件。如果您删除了您的垃圾邮件,您就失去了这封电子邮件。将它存储在文件夹中一段时间可以让您潜在地找到并检索这些误报。

我们将使用第一种方法,将我们的垃圾邮件移动到我们的Maildir目录中的一个特殊文件夹中,供以后查看。为此,我们可以使用两种主要方法来利用新获得的邮件头,将电子邮件移动到我们希望的位置。这些方法是

  • 使用本地邮件传输协议(LTMP)代理,如 Dovecot
  • 使用 MDA,如procmailmaildrop
  • 使用邮件客户端规则或过滤
使用鸽笼

我们以前见过 Dovecot 来配置我们的 SMTP 认证。我们现在将对其进行配置,以将邮件从 MTA 传输到用户的主目录中。Dovecot 允许我们使用 Sieve ( http://sieve.info/ )来为我们的用户过滤哪些电子邮件被发送到哪里。

为了使用 Dovecot,我们将设置一个 LMTP(本地邮件传输协议),这是一个由 Dovecot 主进程启动的长期运行的进程。这描述了这个 Dovecot 解决方案与procmailmaildrop解决方案之间的区别,这两个解决方案是在每封邮件发送时触发的二进制文件。此外,LMTP 可以运行在单独的服务器上,因为它可以从 TCP 和 unix 套接字读取数据。

第一步是下载 Dovecot Sieve 支持包。对于 CentOS,我们将安装:

$ sudo yum install dovecot-pigeonhole

对于 Ubuntu,我们将安装以下软件:

$ sudo aptitude install dovecot-sieve dovecot-lmtp

我们配置 Dovecot 开始接受与 LMTP 的连接。我们通过向/etc/dovecot/dovecot.conf添加以下内容来实现。

protocols = lmtp

现在我们需要配置下面的文件,/etc/dovecot/conf.d/20-lmtp.conf:

protocol lmtp {
  postmaster_address = postmaster@example.com
  mail_plugins = quota sieve
}

我们需要将 LMTP 进程或 Unix 套接字添加到 Dovecot 主进程中,以便 Postfix 可以通过它传递消息。我们像这样编辑/etc/dovecot/conf.d/10-master.conf文件:

service lmtp {
 unix_listener /var/spool/postfix/private/dovecot-lmtp {
   group = postfix
   mode = 0600
   user = postfix
  }
}

最后,我们需要告诉 Dovecot 在发送邮件时将域名从用户名中删除。LMTP 进程从RCPT TO:获取用户名,我们需要剥离域名。否则,它会尝试将邮件发送给jsmith@example.com,而不仅仅是jsmith(这将与550 5.1.1 User doesn't exist发生错误)。我们在/etc/dovecot/conf.d/10-auth.conf文件中这样做。

auth_username_format = %Ln

现在我们需要编辑后缀配置,告诉它使用 LMTP 套接字。我们通过以下方式做到这一点:

$ postconf –e 'mailbox_transport = lmtp:unix:private/dovecot-lmtp'

我们现在需要重新启动 Postfix 和 Dovecot,以通过以下方式推动更改:

$ sudo systemctl restart dovecot
$ sudo systemctl restart postfix

用筛子过滤

用 Sieve 过滤邮件的语法相当简单。您可以在用户的主目录中设置全局过滤器或单个过滤器。在本例中,我们将向您展示如何将被标记为垃圾邮件的邮件移动到您的垃圾邮件文件夹中,以便以后检查。

Sieve 有几个易于理解的命令和条件。你需要那些你需要的在你的筛子文件的顶部,你通常在∼/.dovecot.sieve中找到。这里有一个例子:

require ["fileinto" ];

还有许多其他命令可以使用,您可以通过运行以下命令找到可用的列表:

$ doveconf -n managesieve_sieve_capability
fileinto reject envelope encoded-character vacation subaddress comparator-i;ascii-numeric relational regex imap4flags copy include variables body enotify environment mailbox date ihave

我们将使用条件语句if将垃圾邮件存储到垃圾邮件文件夹中。我们将测试 SpamAssassin 提供给我们的标题。

require ["fileinto"];
if header :contains "X-Spam-Flag" "YES" {
        fileinto "Spam";
}

这表示如果标题X-Spam-Flag包含单词YES,则将邮件归档到Spam文件夹中。你可以看到它是多么简单。

在测试之前,我们需要确保Spam文件夹存在。我们可以通过使用doveadm命令来做到这一点。首先我们列出来看看文件夹是否存在。

$ doveadm mailbox list -u jsmith
INBOX

在本例中没有,因此我们将创建它。

$ doveadm mailbox create -u jsmith Spam
$ doveadm mailbox list -u jsmith
Spam
INBOX

接下来,当我们像以前一样发送测试垃圾邮件时,我们将看到以下内容:

Aug 28 05:17:10 ip-10-0-10-154 dovecot: lmtp(18407): Connect from local
Aug 28 05:17:10 ip-10-0-10-154 dovecot: lmtp(18407, jsmith): Kl1sKRaswlfnRwAArNTl4g: sieve: msgid=<20160828091710.A40A21811885@mail.example.com>: stored mail into mailbox 'Spam'
Aug 28 05:17:10 ip-10-0-10-154 dovecot: lmtp(18407): Disconnect from local: Successful quit

太好了。我们将邮件发送到我们的邮箱,并让它过滤掉垃圾邮件。

抗病毒素

我们都应该知道,病毒是恶意代码,旨在攻击您的主机、窃取您的数据或危害您组织的其他方面。虽然在 Linux 发行版上极其罕见,但一些病毒已经瞄准了 Linux 发行版。但是我们并不特别担心病毒通过电子邮件攻击我们的 Linux 主机;相反,我们担心的是病毒可能通过电子邮件传播到其他更易受感染的主机上,如 Microsoft Windows 桌面,或者从您的组织传播到其他组织。

我们将介绍一个名为 ClamAV 的应用程序,并向您展示如何将它与 Postfix 集成为一个邮件过滤器。ClamAV 是一个开源防病毒引擎,很像赛门铁克和迈克菲等公司的类似工具。与这些商业产品不同,ClamAV 软件及其更新签名是免费的。

Note

ClamAV 使用称为签名的特殊规则来扫描您收到的电子邮件中看起来像病毒的数据。每个特征包含关于特定病毒的信息,例如,病毒文件包含的一串数据,当发现时,告诉 ClamAV 已经检测到病毒。

我们将向您展示如何将 ClamAV 作为一个 milter 集成到 Postfix 中。Postfix 允许将邮件发送到过滤器,然后重新排队。有两种类型的后缀分隔符,仅 smtpd 和非 smtpd。我们将向您展示如何设置 smtpd 过滤器。

network -> smtpd -> filter -> smtpd -> delivery

前面是我们将向您展示的流程的简化版本。

安装 ClamAV

首先,您需要安装和配置 ClamAV 扫描器及其守护进程,名为clamd。您还需要安装一个名为 FreshClam 的更新工具,该工具可以自动下载和更新 ClamAV 用于检测病毒的病毒签名。

在 CentOS 上,安装 ClamAV 的过程是通过以下软件包完成的:

$ sudo yum install -y clamav-scanner clamav-update clamav-server-systemd clamav-milter-systemd sendmail-milter

在 Ubuntu 上,你安装clamavclamav-daemon包。一些附加的软件包也可以作为这些软件包的先决条件进行安装。

$ sudo aptitude install clamav clamav-daemon clamav-milter

同样,发行版将配置文件放在不同的位置。对于 CentOS,我们在/etc/mail/clamav-milter.conf中找到clamav-milter,对于clamav守护进程,我们在/etc/clam.d/scan.conf中找到它们。对于 Ubuntu,你可以在/etc/clamav找到文件。

对于 CentOS,我们希望从/etc/mail/clamav-milter.conf中删除单词 Example,并设置以下内容:

MilterSocket /var/run/clamav-milter/clamav-milter.socket
MilterSocketGroup mail
MilterSocketMode 660
AllowSupplementaryGroups yes
ClamdSocket unix:/var/run/clamd.scan/clamd.sock
OnInfected Accept
AddHeader Add
ReportHostname mail.example.com

在前面几行中,我们已经设置了一些配置选项,比如用于clamav-milter的套接字文件和我们与扫描仪(clamd)对话的套接字。值得注意的是OnInfected Accept。通常我们会将此设置为Quarantine,但是在接下来的例子中,我们希望我们的受感染邮件被发送,这样我们就可以看到我们添加的邮件头。

对于 CentOS 上的扫描仪,我们必须编辑/etc/clamd.d/scan.conf并确保设置以下内容,如果移除了Example:

LocalSocket /var/run/clamd.scan/clamd.sock

Ubuntu 不需要太多配置。文件/etc/clamav/clamav-milter.conf需要以下内容:

MilterSocket inet:7357@localhost
OnInfected Accept
AddHeader Add

同样,为了测试,我们接受受感染的文件并添加文件头。此外,对于 Ubuntu,我们将设置 milter 监听环回地址,而不是像在 CentOS 设置中那样使用命名套接字。两种发行版都可以使用这种方法。我们不需要更改/etc/clamav/clamd.conf,尽管该文件包含您可能想要查看的不同扫描设置(CentOS 中的/etc/clamd/scan.conf)。

现在,我们需要将postfixclamilt用户添加到 CentOS 上的mail组。

$ sudo usermod –aG mail postfix && sudo usermod –aG mail clamilt

而对于 Ubuntu,除非我们使用的是命名套接字,否则不需要做任何改动。但是我们需要对后缀main.cf文件做一些修改来反映我们的smtpd_milter。为此,我们向 CentOS 主机添加了以下内容:

milter_default_action = accept
smtpd_milters = unix:/var/run/clamav-milter/clamav-milter.socket

因为使用 Ubuntu,我们通过回送地址与 milter 对话,所以我们需要:

milter_default_action = accept
smtpd_milters = inet:7357

最后,在 CentOS 上,我们需要对 SELinux 策略进行一些调整。以下要求安装policycoreutils-python包。通常你可以启动你的服务,等待它失败,检查/var/log/audit/audit.log,并运行audit2allow命令来修复任何 SELinux 权限问题。在本例中,我们将使用目标条目文件来生成我们的策略包文件,然后将它加载到 SELinux 中(有关 SELinux 的更多信息,请参见即将到来的“SELinux 和 Apparmor”侧栏)。我们的clamav-write.te目标条目文件的内容如下所示:

module clam-write 1.0;

require {
       type unconfined_t;
       type var_run_t;
       type postfix_smtpd_t;
       type init_t;
       class sock_file write;
       class unix_stream_socket connectto;
}

#============= postfix_smtpd_t ==============
allow postfix_smtpd_t init_t:unix_stream_socket connectto;
allow postfix_smtpd_t unconfined_t:unix_stream_socket connectto;
allow postfix_smtpd_t var_run_t:sock_file write;

第一行由模块名和版本组成。部分包含了我们需要的不同类型和类别。最后,我们有允许smtpd守护进程连接和写入 Unix 套接字(如/run/clamav-milter/clamav-milter.socket)的代码行。我们现在必须编译策略包,将其加载到 SELinux 策略配置中。为此,我们首先使用以下命令编译一个策略模块文件:

$ sudo checkmodule -M -m -o clamav-write.mod clamav-write.te

checkmodule命令接受以下参数,-M启用 LSM 支持,-m生成模块二进制文件,–o是输出文件名。现在,我们使用以下命令创建策略包:

semodule_package –o clamav-write.pp -m clamav-write.mod

我们通过将模块(-m)文件传递给semodule_package命令来创建策略包,并将其(-o)写入clamav-write.pp文件。现在我们准备将这个策略包加载到 SELinux 中。这通过简单地发出以下命令来实现:

$ sudo semodule –i clamav-write.pp

我们已经告诉semoduleclamav-write.pp策略安装到 SELinux 中(-i)。我们现在准备启动 ClamAV 服务。

一旦安装了所有相关的包,您需要确保 ClamAV 守护进程已经启用并启动。让我们启动clamd服务。

$ sudo systemctl enable clamd@scan && sudo systemctl start clamd@scan (CentOS)
$ sudo systemctl enable clamav-daemon && sudo systemctl start clamav-daemon (Ubuntu)

接下来,我们将启动clamav-milter服务和freshclamd服务,它们轮询最新的病毒签名更新。

$ sudo systemctl enable clamav-milter && sudo systemctl start clamav-milter (Both)
$ sudo systemctl enable clamav-freshclam && sudo systemctl start clamav-freshclam (Ubuntu)

我们现在应该能够更多地了解 ClamAV 的配置。

SELinux and Apparmor

在 Linux 中,通过 Linux 安全模块(LSM)提供了不同类型的访问控制,它是 Linux 内核的一部分。其中一个叫做强制访问控制(MAC ),由 SELinux 在基于 RHEL 和 Debian 的发行版上提供,由 Apparmor 在 Ubuntu 和 Debian 上提供。每一种都提供了允许或限制访问文件、进程和网络资源的能力,当然,每一种都有不同的做法。

MAC 不同于自主访问控制(DAC),自主访问控制是 Linux 操作系统的核心,也是我们比较熟悉的一个。DAC 允许资源(例如文件)的所有者设置该文件的权限。另一方面,MAC 规定了内核中资源的权限,只有通过将访问策略从用户空间加载到内核中,才能更改权限。

SELinux 由美国国家安全局(NSA)开发,其工作原理是标记系统上的每个对象,然后使用 SELinux 安全模块来验证对资源的访问。它会将访问违规记录到审计日志中,通常是/var/log/audit/audit.log。从那里,您可以使用audit2allow命令来创建新的目标条目文件和策略包。目标入口文件(通常以.te结尾)用纯文本解释策略。由此我们可以创建策略包(以.pp结尾),并将其加载到内核中。

type=AVC msg=audit(1472477657.569:13159): avc:  denied  { write } for  pid=24859 comm="smtpd" name="clamav-milter.socket" dev="tmpfs" ino=281983 scontext=system_u:system_r:postfix_smtpd_t:s0 tcontext=unconfined_u:object_r:var_run_t:s0 tclass=sock_file

这里我们可以看到日志 SELinux 在audit.log中的输出。我们可以将其分为三个部分,所需的访问、源上下文和目标上下文。

type=AVC是访问向量缓存,然后是审计时间戳。然后是被拒绝的avc动作,write ( denied { write }),由命令smtpd尝试写入clamav-milter.socket。源上下文(scontext)是system_u:system_r:postfix_smtpd_t:s0,目标上下文(tcontext)是tcontext=unconfined_u:object_r:var_run_t:s0。这意味着类型为postfix_smtpd_t的进程试图访问类型为var_run_t的套接字文件,但是失败了。解决方案是允许后缀smtpd进程对套接字文件进行写操作。如果我们收集这些消息并将它们传递给audit2allow程序,我们将能够创建允许正确访问所需的策略包。

sudo grep "denied" /var/log/audit/audit.log |grep clamav | audit2allow -M clamav-write

该命令将创建clamav-write.teclamav-write.pp,然后您可以通过以下方式加载它们:

sudo semodule -i clamav-write.pp

对于 Apparmor 来说,这是一个不同的概念。SELinux 在对象上使用标签,而 Apparmor 对路径名应用安全策略。您可以通过定义应用程序需要什么样的权限来创建应用程序的概要文件,并且您可以使用 Apparmor 附带的工具很容易地管理它。

要查看 Apparmor 的状态,可以发出以下命令:

$ sudo apparmor_status
apparmor module is loaded.
15 profiles are loaded.
15 profiles are in enforce mode.
   /sbin/dhclient
   /usr/bin/freshclam
   /usr/bin/lxc-start
...
4 processes have profiles defined.
4 processes are in enforce mode.
   /usr/bin/freshclam (2153)
   /usr/sbin/clamd (11998)
   /usr/sbin/mysqld (2997)
0 processes are in complain mode.
0 processes are unconfined but have a profile defined.

您可以看到已经有一个针对clamd服务的策略。这些概要文件与它们相关的包一起安装,包clamav-daemon提供了clamd概要文件。

要创建您自己的概要文件,您需要创建一个测试计划,这是一个运行和执行您正在概要分析的流程的计划。然后用aa-genprof命令运行程序。在回答了关于应用程序访问的问题之后,就构建了概要文件。然后可以将生成的概要文件复制到/etc/apparmor.d/目录中,并通过发出以下命令来启用它:

$ sudo aa-enforce /etc/apparmor.d/<your profile>

Apparmor 发布在 Ubuntu 和 OpenSUSE 上,但是可以安装在 Debian 和 CentOS 上。

我们只是触及了这些主题。阅读以下文件对你有好处:

在任何面向互联网的系统中使用这两者中的任何一个都是明智的想法。

配置 ClamAV

你通常不需要改变 ClamAV 的任何配置选项,但是你应该知道一点它是如何配置的。在 CentOS 上,ClamAV 守护程序通过/etc/clamd.d/scan.conf文件进行配置。scan.conf文件配置 ClamAV 守护进程。软件包安装过程还为 FreshClam 更新工具创建一个 cron 条目(在/etc/cron.daily目录中),该工具每天更新 ClamAV 的签名一次。

在 Ubuntu 上,ClamAV 守护进程通过/etc/clamav/clamd.conf配置文件配置,而freshclam更新守护进程通过/etc/clamav/freshclam.conf配置文件配置。与 Ubuntu 上的cron作业不同,FreshClam 服务是作为一个守护进程运行的,每天会多次尝试下载任何可用的签名。

在 CentOS 和 Ubuntu 上,运行 ClamAV 守护程序将创建一个 Unix 套接字文件。ClamAV milter 使用这种特殊类型的文件与防病毒扫描程序进行通信。电子邮件被提交到套接字,进行扫描,然后返回到 ClamAV milter,并评估它是否是病毒。然后,该评估以X-Spam-Virus标题的形式添加到扫描的电子邮件中。

在 CentOS 上,这个插座默认位于/var/run/clamd.scan/clamd.sock中,您可以在这里看到它的列表:

$ sudo ls -l /var/run/clamd.scan/clamd.sock
srw-rw-rw-. 1 clamscan clamscan 0 Sep  3 04:07 /var/run/clamd.scan/clamd.sock

在 Ubuntu 上,socket 位于/var/run/clamav目录下,名为clamd.ctl

$ sudo ls -lart /var/run/clamav/clamd.ctl
srw-rw-rw- 1 clamav clamav 0 Sep  3 11:20 /var/run/clamav/clamd.ctl

用 ClamAV 测试后缀

现在您已经启用了 ClamAV milter,您需要测试您的接收电子邮件是否正在进行病毒扫描。为此,使用swaks命令和一个特殊文件,该文件包含一个名为eicar.txt的测试病毒签名,如下所示:

$ swaks -tls -a -au ataylor -ap password -t jsmith@example.com -f ataylor@example.com --body eicar.txt

我们再次使用了swaks命令向jsmith@example.com发送电子邮件。文件eicar.txt包含这个字符串,它将触发病毒扫描程序。

X5O!P%@AP4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*

Note

您可以在您的环境中用适当的值替换一个用户来测试这一点。

该电子邮件将由您的 MTA 接收和处理,然后传递给 ClamAV milter,ClamAV milter 将与 ClamAV 扫描器对话,然后根据您的配置传递给 SpamAssassin 进行分析。电子邮件将被提交到用户jsmith的邮箱,然后您可以检查电子邮件标题的内容。在清单 [12-15 中,您可以看到我们刚刚发送的电子邮件的标题。

X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on
X-Spam-Level: *
X-Spam-Status: No, score=-0.9 required=5.0 tests=ALL_TRUSTED,MISSING_MID
X-Mailer: swaks v20130209.0 jetmore.org/john/code/swaks/
X-Virus-Scanned: clamav-milter 0.99.2 at mail.example.com
X-Virus-Status: Infected (Eicar-Test-Signature)
Listing 12-15.E-mail Headers After SpamAssassin with ClamAV Scan

在清单 12-15 中,您可以看到一个名为X-Spam-Virus的标题被添加到了电子邮件中。清单 12-15 中的头有一个值Infected和它匹配的签名。如果检测到病毒,标题会被标记为Clean

如何处理受感染的电子邮件?

与使用X-Spam-Status标题一样,您可以使用此标题以不同方式处理被识别为包含病毒的电子邮件,例如,如果您想要将所有此类电子邮件移动到一个名为Viruses的单独文件夹中。您可以使用之前用于将垃圾邮件分类到单独文件夹中的筛选配置来完成此操作。要使用 Sieve 做到这一点,您可以向用户的∼/.dovecot.sieve文件中添加一个如下所示的配方:

require ["fileinto"];
if header :contains "X-Virus-Status" "" {
        fileinto "Spam";
}
if not header :contains "X-Virus-Status" "Clean" {
        fileinto "Virus";
}

但是,最好不要将受感染的文件传递给用户。您可以通过设置clamav-milter.conf文件中的OnInfected Quarantine值来隔离邮件服务器上的受感染文件。我们将它提前设置为 accept,这样我们就可以看到邮件到达我们的收件箱。然而,现在明智的做法是阻止那些邮件被别人误打开。

获得 ClamAV 的帮助

您可以找到各种资源来对 ClamAV 进行故障诊断。你应该从 ClamAV 主页开始( www.clamav.net/ )。在同一个网站上,你会找到各种可用的支持资源( www.clamav.net/support/ ),你也可以加入 ClamAV 邮件列表( www.clamav.net/support/ml/ )。你可以在 www.clamav.net/bugs/ 找到当前 bug 列表。

请记住,如果您提交问题或错误,您应该包括以下信息:

  • 您的 ClamAV 版本(运行带有--version选项的clamscan命令)
  • 你的平台(运行uname -a
  • 生成的任何日志消息(在 Ubuntu 上的/var/log/clamav/clamav.log或/var/ log/clamav/freshclam.log文件中,或者在 CentOS 上的/var/log/clamav/clamd.log/var/log/clamav/freshclam.log文件中)

在 Freenode IRC 服务器( http://freenode.net/ )上还有一个名为#clamav的 IRC 频道,你可以在那里寻求帮助。

SPF 和 DKIM,控制你的电子邮件

我们可以采取进一步的行动来帮助击败垃圾邮件。这两种方法本身都不能阻止垃圾邮件,但每一种都是帮助垃圾邮件难以通过的工具的一部分。它们确实有助于阻止垃圾邮件发送者在发送邮件时伪造您的域名。

发件人策略框架(SPF)用于标识可以代表您的域发送电子邮件的电子邮件服务器。域密钥识别邮件(DKIM)是一种通过根据您的公开密钥验证邮件头来识别来自您的服务器的邮件的方法。

防晒系数

SPF 为您的域使用添加到 DNS 中的文本记录。您的 SPF 记录告诉接收您的电子邮件的电子邮件服务器,它们应该根据发送邮件的服务器来接受还是拒绝该邮件。让我们举一个例子,你通过 MailChimp 或 Sendgrid 或其他大量电子邮件服务向你的客户发送公司的营销通讯。当电子邮件进入客户的电子邮件服务器时,它将来自批量电子邮件提供商的电子邮件服务器之一。客户的电子邮件服务器如何确定它真的来自您的营销团队?

使用 SPF,我们可以告诉客户的电子邮件服务器,它应该代表我们接受来自这个批量电子邮件服务的电子邮件。这样,我们可以说电子邮件服务器1.bulk.mailer.net可以为example.com域发送邮件。

让我们来看看我们的example.com域名的 DNS 记录示例。我们将为example.com域添加一个 TXT 记录。

example.com.    IN  TXT “v=spf1 mx -all"

这里我们正在编辑example.com的区域文件并添加 TXT 记录。您也可能通常将此视为已经贬值的 SPF 记录。TXT 记录本身包含 SPF 的版本(spf1)、哪些电子邮件服务器可以为我们的域发送(所有列出的 MX 服务器),以及我们是否应该接受或拒绝来自不在该列表中的服务器的电子邮件(-all)。

在这个例子中,我们说任何被列为 MX 记录的服务器都能够代表我们发送邮件。那么,我们如何允许1.bulk.mailer.net代表我们发送电子邮件呢?我们可以指定主机名、IPv4 或 IPv6、CIDRs 以及它们的组合,而不是指定mx。批量电子邮件服务通常具有用于发送邮件的 IP 地址的地址范围。你应该把这些加到你的防晒指数记录里。这个 RFC 有更多关于什么被接受的细节: https://tools.ietf.org/html/rfc7208#section-3

–all选项表示我们希望接收邮件的服务器拒绝任何不是来自我们确定的邮件服务器的邮件。您可以将此设置为∼all,它告诉接收邮件的服务器不要拒绝它,而是将其标记为伪造的。如果您完全控制您域名的电子邮件,您应该能够将其设置为–all

要获得创建 SPF 记录的帮助,您可以访问以下网站。它会根据您输入的信息生成 SPF 记录: http://spfwizard.com/

一旦我们的电子邮件服务完成了这一步,我们就需要对它进行设置,以便我们接收电子邮件的电子邮件服务器也使用 SPF 来验证发送给它的电子邮件。为此,我们需要添加另一个包来处理这个验证。

对于 Ubuntu,我们必须添加以下软件包:

$ sudo aptitdue install –y postfix-policyd-spf-python

对于 CentOS,我们将添加此包:

$ sudo yum install –y pypolicyd-spf.noarch

那么 Postfix 的配置只需将以下内容添加到/etc/postfix/main.cf:

smtpd_recipient_restrictions =
....
   reject_unauth_destination
   check_policy_service unix:private/policyd-spf
   reject_rbl_client zen.spamhaus.org
...
policyd-spf_time_limit = 3600

然后到/etc/postfix/master.cf,我们需要以下内容:

policyd-spf  unix  -       n       n       -       0       spawn
 user=nobody argv=/usr/libexec/postfix/policyd-spf

我们可以通过编辑/etc/postfix-policyd-spf-python/policyd-spf.conf (Ubuntu)或/etc/python-policyd-spf/policyd-spf.conf (CentOS)来更改 Postfix SPF 的配置。policyd-spf.confman页面描述了配置选项。默认值应该没问题,但是您可能想要调整skip_addresses并设置debug_level (1 到 5,5 是最详细的)。

现在,当您发送一封测试电子邮件时,您将看到以下邮件头被添加到电子邮件中(SpamAssasin 将使用它来计算垃圾邮件分数):

X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on
        ip-10-0-10-154.ap-southeast-2.compute.internal
X-Spam-Level: *
X-Spam-Status: No, score=1.8 required=5.0 tests=MISSING_SUBJECT autolearn=no
        autolearn_force=no version=3.4.0
Received-SPF: Pass (sender SPF authorized)  identity=mailfrom; client-ip=31.28.208.98; helo=mail.example.net; envelope-from=ataylor@example.net; receiver=jsmith@example.com
X-Virus-Scanned: clamav-milter 0.99.2 at mail.example.com
X-Virus-Status: Clean

你可以看到现在我们有了Received-SPF: Pass (sender SPF authorized),这意味着我们已经查找了example.net的 TXT 记录,发现mail.example.net能够为example.net域发送邮件。

现在让我们看看如何设置域密钥标识的邮件。

dkim!dkim

域密钥识别邮件是指我们将在发送的邮件中添加一个签名头,以便其他邮件服务器可以通过我们发布的公钥来验证它是否来自我们。您已经看到了用于验证 web 服务器和域记录的公钥基础设施(PKI)。现在,我们可以使用该框架来验证我们正在发送的电子邮件。

我们将通过 DNS 再次发布我们的公钥,以便其他邮件服务器可以验证我们的签名。此外,我们将需要 OpenDKIM 包来管理我们的 DKIM 服务。

$ sudo yum install –y opendkim (CentOS)
$ sudo aptitude install –y opendkim (Ubuntu)

这将安装 OpenDKIM 包并创建opendkim用户。在 Ubuntu 和 CentOS 上,您都可以通过配置文件/etc/opendkim.conf配置 OpenDKIM,我们将进行以下配置设置:

Mode               sv
SubDomains         no
SignHeaders        From,Subject,Date
OversignHeaders    From,Subject,Date
Syslog             yes
UMask              002
UserID             opendkim
KeyTable           /etc/opendkim/KeyTable
SigningTable       refile:/etc/opendkim/SigningTable
ExternalIgnoreList /etc/opendkim/TrustedHosts
InternalHosts      /etc/opendkim/TrustedHosts

Canonicalization   relaxed
AutoRestart        yes
AutoRestartRate    10/1M
Background         yes
DNSTimeout         5
SignatureAlgorithm rsa-sha256
Socket             /var/spool/opendkim/opendkim.socket

我们不会遍历每一行,但是我们会把您带到声明ModeSubDomains. Mode可以是svsv的前两行。s表示签名,v表示验证,sv表示两者。SubDomains no表示我们不会签署我们在表格文件中列出的域名的子域。我们还设置了一个套接字文件,稍后我们将连接到 Postfix。

最后,我们来谈谈SignHeadersOversignHeaders From。我们在签名中包含头,并告诉 OpenDKIM 包含From,Subject,Date头。如果需要,您可以包含其他内容,但 From 标头必须经过签名。OverSignHeaders告诉 OpenDKIM 包括这些头,即使它们不存在,并将它们记录为 null,这可以防止以后添加它们。

在 Ubuntu 上,我们将使用以下内容创建所需的 OpenDKIM 目录:

$ sudo mkdir –p /etc/opendkim/keys && sudo touch /etc/opendkim/{KeyTable,SigningTable,TrustedHosts}
$ sudo mkdir –p /var/spool/opendkim
$ sudo chown opendkim:opendkim –R /etc/opendkim/* /var/spool/opendkim && sudo chmod 0640 /etc/opendkim/*
$ sudo chmod 0750 /etc/opendkim/keys

接下来,我们将讨论加密配置。我们需要将我们的域添加到表文件中。首先我们将编辑/etc/opendkim/SigningTable。我们将添加以下内容:

*@example.com   example

这告诉 OpenDKIM 对example.com域(*@example.com)中的所有地址进行签名,它有一个简称example。接下来,我们用以下代码编辑/etc/opendkim/KeyTable文件:

example     example.com:201609:/etc/opendkim/keys/example.com.private

这里我们使用的是KeyTable中 like 的简称来匹配SigningTable中的 like。然后我们看到域和选择器,这是一个唯一的任意值(在 DNS 查找期间使用,格式为 YYYYMM),后面是我们将用于签名的私钥。

我们现在将编辑TrustedHosts文件,添加我们将发送邮件的可信主机。

127.0.0.1
::1
localhost
mail
mail.example.com
example.com

这涵盖了我们的主机可以引用的不同名称。我们现在要生成我们的密钥。我们使用以下命令来实现:

$ opendkim-genkey –D /etc/opendkim/keys -a -d example.com -b 2048 -r -s 201609
$ sudo ls –l /etc/opendkim/keys
total 8
-rw-------. 1 root root 1679 Sep  5 09:21 201609.private
-rw-------. 1 root root  504 Sep  5 09:21 201609.txt

这里我们在/etc/opendkim/keys目录(-D)中创建了一个 2048 位的私钥(-b 2048)和一个公钥。我们附加域(-a),这将我们的域附加到区域文件存根。–d表示我们正在为特定的域生成密钥。如果您想对多个域使用同一个密钥,可以删除它。我们还将此密钥(-r)限制为仅用于电子邮件。–s是选择器,我们已经说过,它用于 DNS 名称查找。

我们将把这两个生成的文件移动到我们在KeyTable文件中指定的名称。

$ sudo mv /etc/opendkim/keys/201609.private /etc/opendkim/keys/example.com.private
$ sudo mv /etc/opendkim/keys/201609.txt /etc/opendkim/keys/example.com.txt
$ sudo chown opendkim /etc/opendkim/keys/ownenergy.com.au.private

我们现在需要用example.com.txt文件中的文本再次更新我们的 DNS。如果我们深入观察,我们会看到以下内容:

201609._domainkey.example.com. IN TXT ( "v=DKIM1; k=rsa; s=email; " "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz5DbbqRCsZ564tDCDeonTkr4ggYrVr5H19qBCYPwnksFyqzmQtpntQq78hpt7lcYghwmhDT9V3o72lUKYn151p6e3rsvtSXmNHuhgxHRwozDf7NdQeDEzpEa7+/UdWvDDtmg9Bbsx6kLhOfTZU8TvnOW3UCJPFkzKNhCg5rrZGLXUqs0S762T4gLDJYCrgkIxUW1KEazkRn1mr" "XvcvE+wt6QL4GPcz6ddPYw4DS9sdZ17DZMa7ngv2C0EjrQwfTcIfoTkfc2G6GgjayVM+RgAs234Eo6+7tX+W7ZmXpzgk2YtHah1cNjHV2dAgGRo/B6H2W0KK89LkZsfTzMYjasfQIDAQAB" )  ; ----- DKIM key 201609 for example.com

DNS TXT 记录的字符串长度不能超过 255 个字符;我们需要把它分成多行。我们需要复制()之间的数据。对于我们的绑定 DNS,我们可以将其添加为多行 DNS 记录:

201609._domainkey IN TXT ("v=DKIM1 ; k=rsa, s=email; "
    "p= MIIBIjANBgkqhkiG ... "
    "XvcvE+wt6Q ... jasfQIDAQAB")

如果您使用外部 DNS 提供商,您可能也需要使用 multiline(例如 AWS Route53)。最好查阅任何关于 DKIM 的文档。我们现在可以使用以下命令来验证我们的 DNS 记录:

opendkim-testkey -d example.com -s 201609

没有产出意味着我们成功了。我们现在将启用并启动opendkim

$ sudo systemctl enable opendkim
$ sudo systemctl start opendkim

要配置 Postfix,我们需要添加另一个 milter。我们通过再次编辑main.cf文件来实现。

smtpd_milters = unix:/var/run/clamav-milter/clamav-milter.socket unix:/var/spool/opendkim/opendkim.socket

我们将把opendkim组添加到postfix用户中。

$ sudo usermod –aG opendkim postfix

然后我们需要修改 SELinux 策略。

我们现在也可以重启 Postfix 了。

$ sudo systemctl restart postfix

我们现在可以给自己发送一封电子邮件到我们的一个外部地址。我们选择了一个 Gmail 地址,如果我们查看该电子邮件的标题,我们会看到:

Authentication-Results: mx.google.com;
       dkim=pass header.i=@example.com;
       spf=pass (google.com: domain of jsmith@example.com designates 52.82.67.42 as permitted sender) smtp.mailfrom=jsmith@example.com
Received: by mail.example.com (Postfix, from userid 1000)
id 99CFA187135A; Tue,  6 Sep 2016 07:59:43 -0400 (EDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple;
d=example.com; s=201609; t=1473163183;
bh=ShAzA6t1zCobzHEAhrmK5udJcy/7FvQ3DqD9cIsQ/Lk=;
h=Date:Subject:From:From:Subject:Date;
b=ecfUXsieztVsVnngyFtsY1RrAeApoCCt+MoAclGdrS4XmSEOQIMrq3olstlsLm8WO
 /qmV5MSxvFzpQ0EXZ5RnRMyo0VPAgaHx4gSP5mjEpWozawD4KYC6WA09jxVNSX8fzU
 Mc0Jn7wQdDIWAjXjv0ubEkFFn9AyLs77aUhwRj0T2CwpJhSzzPYvWOR+LZrO6PymTf
 FQ6C9t4jMSRfGDHnWMTp/QkleeSjCzLlebaQFaDgo38phdNYx2LOKLxdyqzJq/nkeK
 2XXM7rGRM9fllTMy4OHDiabvjSg2GfubOMkwKiJaEv7S0Fc5MrW6nGFR+3s5u4jdq8
 kKDmm2pyeR+oQ==

现在,Authentication-Results头被添加到我们发送的电子邮件中,您可以看到我们的公钥也被添加了。您也可以像这样使用外部验证器服务:

echo 'hello' | mail check-auth@verifier.port25.com

这将向check-auth@verfier.port25.com发送一封电子邮件,它将运行一份关于您的 DKIM 和 SPF 设置的报告,并通过电子邮件向您发送一份详细的报告。

配置 IMAP 和 POP3

与你在本章前面大部分章节中看到的不同,你的用户不会通过命令行直接访问他们的电子邮件。他们希望从本地桌面上的电子邮件客户端访问它。这就是 IMAP 或 POP3 服务器发挥作用的地方。这些协议代表了从邮件客户端或 MUA 访问邮箱的两种不同方法。我们将研究这两种方法,解释每种方法的优缺点,并演示如何在您的环境中配置和实现它们。

因特网邮件访问协议

IMAP 用于从远程客户端(如台式机或笔记本电脑)访问电子邮件邮箱。您的客户端连接到 IMAP 服务器,您可以阅读、管理和删除邮箱中的任何电子邮件。您还可以搜索邮件、创建和删除文件夹,以及执行各种其他管理任务。

POP3

POP3 还用于从远程客户端访问电子邮件邮箱。电子邮件被接收并保存在用户的邮箱中,直到他们检查他们的电子邮件。当用户的电子邮件客户端连接时,所有等待的电子邮件都被下载到客户端并从服务器上删除。

有什么区别?

IMAP 协议的作用很像文件服务器。您的电子邮件保留在服务器上,可以被阅读、删除和操作。POP3 是一种存储转发机制。每种基本协议都有优点和缺点。

IMAP 的优势:

  • 允许用户从多个位置访问电子邮件,而不仅仅是他们的客户端
  • 允许网络邮件访问
  • 保护您的邮件不被意外删除
  • 集中化电子邮件,使备份和恢复更容易

POP3 的优势:

  • 你不需要连接到服务器(或者网络)来访问你的电子邮件。
  • 它不使用服务器上的任何存储,所有邮件在检索后都存储在您的客户端上。

IMAP 的缺点:

  • 您需要能够连接到服务器(从而连接到网络和/或互联网)来访问您的电子邮件。
  • 它要求服务器上有足够的存储空间。

POP3 的缺点:

  • 邮件只存在于客户端,不能从其他地方访问。
  • 如果用户丢失、损坏或重建他们的客户端台式机、笔记本电脑等,而没有足够的备份,他们可能会丢失电子邮件。
  • 如果用户要求备份电子邮件,则基于客户端的备份和恢复策略可能会很复杂,而且难以实施。

在 IMAP 和 POP3 之间选择

在绝大多数情况下,我们建议您使用 IMAP。这样做的原因是简单和易于使用。IMAP 允许您的用户带着或不带他们的客户端漫游;例如,IMAP 服务器允许用户通过她的笔记本电脑和智能手机或其他移动设备访问她的电子邮件。

您的用户的电子邮件也在一个中心位置,这使得您可以轻松地备份它(并且当您的用户不可避免地删除了一封重要的电子邮件时,可以恢复它)。另外,由于存储成本低廉,在大多数公司中,将电子邮件集中存储在服务器或磁盘阵列上不再是一个问题。

主要的警告是,如果您的用户无法连接到 IMAP 服务器,他们将无法检索他们的电子邮件。在这种情况下,我们认为 IMAP 的其他优势大于风险。

在这一节中,我们将在示例中演示如何配置 IMAP。如果你对配置 POP3 感兴趣,你可以在 http://wiki.dovecot.org/POP3Serverhttp://wiki.dovecot.org/QuickConfiguration 看到一些说明、提示和警告。

Dovecot IMAP 简介

已经向您介绍了 Dovecot 服务器,因为在我们的示例中,我们将它用作 Postfix 的认证服务。结果是有一些好消息。如果您一直关注这一点,那么您已经安装、启动并部分配置了 Dovecot。这意味着你现在需要采取的步骤有限。

在本节中,我们将向您展示如何打开 IMAP,特别是 IMAP 协议的安全版本 IMAPS(S 表示安全)。当用户的电子邮件在客户端和服务器之间流动时,它使用 SSL 加密来保护用户身份验证和内容。IMAP 和 IMAPS 的另一个主要区别是它们运行的 TCP 端口。IMAP 协议在端口 143 上运行,而 IMAPS 协议在端口 993 上运行。您需要在您的邮件客户端中指定这个端口号(并可能告诉您的客户端使用 SSL)。

Tip

POP3 协议在 TCP 端口 110 上运行,它的安全对等协议 SSL-POP3 在 TCP 端口 995 上运行。

我们还将配置 Dovecot 来查找我们的本地 Maildir 邮箱。我们不需要配置身份验证,因为我们已经完成了。我们为 Postfix 启用的相同的身份验证机制,使用 PAM 身份验证来检查本地用户的用户名和密码,将很好地用于 IMAP 连接。

配置鸽笼

Dovecot 服务器是使用dovecot.conf配置文件配置的,正如您在本章前面所发现的。在两个发行版中,这个文件都位于/etc/dovecot/dovecot.conf。让我们通过启用 IMAPS 协议并指定将要使用的 SSL 证书的位置来开始我们的配置过程。为了简单起见,我们将重用为后缀加密创建的相同证书。

首先,我们通过编辑protocols配置选项并将其从lmtp更改为lmtp imap来启用 IMAP,如下所示:

protocols = lmtp imap

我们在/etc/dovecot/conf.d/10-master.conf文件中指定 IMAP 如何监听。我们需要将service imap-login改为如下:

service imap-login {
  inet_listener imap {
    port = 0
  }
  inet_listener imaps {
    port = 993
    ssl = yes
  }

这将关闭非 SSL 纯文本端口,只监听 SSL 端口 993。

接下来,我们指定 SSL 证书和密钥文件。为此,我们需要取消注释并更新ssl_cert_filessl_key_file选项,并添加我们的证书和密钥的位置。该文件位于/etc/dovecot/conf.d/10-ssl.conf

ssl = required

ssl_cert = </etc/letsencrypt/live/mail.exmaple.com/cert.pem
ssl_key = </etc/letsencrypt/live/mail.example.com/privkey.pem
ssl_ca = </etc/letsencrypt/live/mail.example.com/chain.pem
# SSL protocols to use
ssl_protocols = !SSLv2 !SSLv3
ssl_cipher_list = ALL:!LOW:!SSLv2:!SSLv3:!EXP:!aNULL
# Prefer the server's order of ciphers over client's.
ssl_prefer_server_ciphers = yes

我们将要使用的证书和密钥文件与我们用来提供 Postfix 加密的文件相同。您可以按照我们在那一节中遵循的相同步骤来创建特定于 Dovecot 的证书,或者如果您愿意,您甚至可以专门为 Dovecot 购买额外的证书,但是我们认为这没有必要。

Note

记住,您的证书与一个主机名相关联,在我们的例子中是mail.example.com。如果您在另一台主机上运行 Dovecot 服务器,您应该使用运行 Dovecot 的服务器的主机名创建一个新的密钥和证书。此外,由于证书与主机名相关联,因此您必须在邮件客户端中指定该主机名(在本例中为mail.example.com),而不是该主机已知的任何其他 DNS 名称。

接下来,我们取消注释并将/etc/dovecot/conf.d/10-auth.conf文件中的disable_plaintext_auth选项改为yes

disable_plaintext_auth = yes

此选项禁用任何纯文本身份验证,除非启用了 SSL 并且加密连接正在运行。这可以保护我们用户的身份验证凭证免受攻击,这些攻击可能会从网络或互联网上嗅探或获取这些凭证。

最后,使用mail_location选项(我们之前设置的)确保我们的邮箱位置正确。您将需要编辑/etc/dovecot/conf.d/10-mail.conf

mail_location = maildir:∼/Maildir

这告诉 Dovecot 我们正在使用位于用户主目录或∾中的Maildirs和目录Maildir

现在我们需要重新启动 Dovecot 服务器,然后我们可以测试是否可以建立连接并在我们的服务器上检索我们的电子邮件,例如:

$ sudo systemctl restart dovecot

测试鸽笼

现在我们已经配置了 Dovecot,我们可以启用一个客户端并测试它的访问。我们将配置一个 Mozilla Thunderbird 客户端来测试 Dovecot 当然,您可以使用任何 IMAP 客户端。

Note

Mozilla Thunderbird 是 Mozilla 基金会发布的一款流行的开源邮件客户端,该基金会还开发了 Firefox 浏览器。

要配置客户端,我们首先需要安装它。在 CentOS 和 Ubuntu 上,所需的包称为thunderbird,您应该使用您的应用程序安装工具(或包管理器)来安装它。

现在,让我们回顾一下为了配置我们的客户端,我们需要知道些什么:

  • 我们服务器的名称
  • 我们的用户名和密码

我们将通过选择菜单选项应用程序➤互联网➤雷鸟来启动 Mozilla 雷鸟邮件客户端,如图 12-4 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12-4。

Launching Mozilla Thunderbird

如果这是你第一次启动雷鸟,帐户向导将会启动。此向导允许您在服务提供商处创建一个帐户。您可以通过选择首选项➤帐户设置并单击添加帐户来创建新帐户。

到目前为止,大多数人已经熟悉了电子邮件客户端的设置。你将需要类似于图 12-5 的细节。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12-5。

Specifying server details

您可以测试连接,雷鸟将尝试连接到邮件服务器,并验证它实际上是一个电子邮件服务器(图 12-6 )。完成后,点按“完成”。现在我们要做的就是给自己发一封电子邮件,我们已经成功地设置了电子邮件服务器。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12-6。

Testing our ability to send and receive e-mail

您还应该能够在适用于您的发行版的日志文件中看到您的连接和认证记录:CentOS 上的/var/log/maillog和 Ubuntu 上的/var/log/mail.log,如清单 12-16 所示。

Sep  6 10:19:49 ip-10-0-10-154 dovecot: imap-login: Login: user=<jsmith>, method=PLAIN, rip=203.217.94.151, lip=10.0.10.154, mpid=2762, TLS, session=<aqdGfdc72ADL2V6X>
Sep  6 10:25:18 ip-10-0-10-154 dovecot: imap(jsmith): Disconnected: Disconnected in IDLE in=1186 out=120979
Listing 12-16.Dovecot Authentication Log Entries

鸽笼故障排除

如果有些东西不工作,或者您无法连接到 Dovecot 服务器,那么我们建议您首先查看日志文件。您可以简化这个过程,因为 Dovecot 有一些有用的调试设置,如果遇到问题,您可以启用这些设置来获得更详细的输出。表 12-3 提供了这些选项的列表。

表 12-3。

Dovecot Debugging Options

| [计]选项 | 描述 | | --- | --- | | `mail_debug` | 当设置为`yes`时,显示邮件过程的更多信息。 | | `auth_verbose` | 设置为`yes`时,显示认证过程的更多信息。 | | `auth_debug` | 设置为`yes`时,显示认证过程的调试信息。 | | `auth_debug_password` | 如果`auth_debug`和该选项都设置为`yes`,则显示认证机制和密码。 |

打开这些选项中的一个或多个以查看详细的调试信息。这些信息被发送到 syslog 守护进程,并因此保存到您的/var/log/maillog/var/log/mail.log日志文件中。这些额外的信息将使您更容易确定 Dovecot 安装是否有问题。

Note

在更改这些选项后,您必须重新启动 Dovecot 服务器,我们建议您在修复任何问题后将选项设置回no。打开调试会影响 Dovecot 服务器的性能。

获得 Dovecot 的帮助

大量有用的信息可帮助您解决 Dovecot 的任何潜在问题。寻求帮助的最佳起点是位于 www.dovecot.org/ 的鸽派主页。该网站包括一个全面的 wiki ( http://wiki.dovecot.org/ ),其中包括许多如何在各种实现中配置 Dovecot 的方法和示例。同样可用的还有 Dovecot 邮件列表( www.dovecot.org/mailinglists.html )和 bug 提交说明( www.dovecot.org/bugreport.html )。

请记住,如果您提交问题或错误,您应该包括以下信息:

  • 您的 Dovecot 版本(运行带有--version选项的dovecot命令)
  • 包括您的配置,您可以通过doveconf -n获得
  • 你的平台(运行uname -a
  • 生成的任何日志消息(在 Ubuntu 上的/var/log/mail.log文件中或在 CentOS 上的/var/log/maillog文件中)

在 Freenode IRC 服务器上还有一个名为#dovecot的 IRC 频道( http://freenode.net/ ),你可以在那里寻求帮助。

虚拟域和用户

在本章中,我们已经介绍了向用户提供电子邮件的基础知识。在这里,我们将讨论扩展本章中介绍的邮件服务的方法。

扩展 Postfix 和 Dovecot 的主要方式是扩展到虚拟域和虚拟用户。到目前为止,我们一直假设我们发送邮件的域和接收邮件的用户都是物理实例。我们接受电子邮件的域是邮件服务器所属的域,我们的用户实际上存在于我们的邮件服务器上。通过虚拟域和用户,您可以配置非物理的电子邮件目的地和收件人。我们不会演示这些概念,但我们会解释它们,并让您参考文档,这些文档将允许您扩展我们在本章中构建的内容来完成所有这些工作。

托管虚拟域允许您接收其他域的电子邮件。例如,假设您当前收到了域example.com的邮件。你的公司可能也有域名product.comanotherproduct.com。您可以配置 Postfix 来接收这些附加域的电子邮件。

虚拟用户是一个类似的概念。到目前为止,我们所有的用户都是真正的 Linux 用户,例如,jsmithataylor。他们的邮箱已经存储在/home目录树中。使用虚拟用户,您的邮件用户不需要被创建为操作系统用户。每个电子邮件地址都映射到一个虚拟用户或包含在 MySQL 或 LDAP 等数据库中的用户。这减少了创建和管理大量操作系统用户的需要。

您可以在 www.postfix.org/VIRTUAL_README.html 找到使用 Postfix 配置虚拟域和用户的完整操作方法。你可以在 https://help.ubuntu.com/community/PostfixCompleteVirtualMailSystemHowto 找到更具体的 Ubuntu 指南。你也可以在 http://wiki.dovecot.org/ VirtualUsershttp://wiki.dovecot.org/HowTo 的 Dovecot 操作指南页面上找到以类似方式扩展 Dovecot 的说明。

适用于 Linux 的备选邮件服务器

有几个免费的和商业的电子邮件解决方案提供了比本章所描述的更多的功能。许多人希望日历、企业认证、文件共享和协作功能成为他们日常工作体验和需求的一部分。

表 12-4 列出了一些已经存在多年的解决方案。他们在不同的许可下提供他们的软件,但是每个都有一个开源版本。许多公司以商业价格提供附加功能并签署支持协议。

表 12-4。

List of Alternative E-mail Solutions

| 科拉布社区 | 自由软件(`https://www.gnu.org/philosophy/free-sw.en.html`)。 | | 打开-exchange | 免费用于非商业用途。商业许可证付款( [`https://www.open-xchange.com/terms-and-conditions`](https://www.open-xchange.com/terms-and-conditions) )。 | | 津巴 | 开源版免费。商业许可可用于获得某些功能( [`https://www.zimbra.com/legal/licensing/`](https://www.zimbra.com/legal/licensing/) )。 | | iRedMail | 带商业附加组件的开源( [`https://creativecommons.org/licenses/by-nd/3.0/us/`](https://creativecommons.org/licenses/by-nd/3.0/us/) )。 |

摘要

在本章中,我们向您介绍了 Linux 主机上的邮件服务,它允许您的用户从您的组织发送和接收电子邮件。我们讨论了 IMAP 和 POP3,这些协议允许用户连接到您的主机,并检索和管理他们邮箱中的电子邮件。

在这个过程中,我们讨论了一些重要的概念:

  • 通过加密保护用户的电子邮件及其身份验证凭据
  • 启用 SASL 身份验证以允许您的用户安全可靠地通过邮件服务器的身份验证来发送和接收电子邮件
  • 利用 SpamAssassin 过滤您的电子邮件,阻止垃圾邮件到达您的用户
  • 使用开源 ClamAV 防病毒引擎检查用户的电子邮件中是否有病毒和恶意软件
  • 使用 Dovecot 和 Sieve 等 LMTPs 来过滤你的电子邮件
  • 通过使用 SPF 和 DKIM 进一步保护您的服务器及其信誉
  • 实现 Dovecot 服务器以允许用户连接到他们的邮箱并检索电子邮件

在下一章,我们将向您介绍文件和打印服务,并教您如何运行自己的 NFS 服务器和查看集群网络文件系统。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值