原文:
zh.annas-archive.org/md5/BC997E7C6B3B022A741EFE162560B1CA
译者:飞龙
第五章:监控系统资源
随着您的组织需求的扩大,您的网络将随着增长和变化而增长和变化。跟踪每个节点上的资源对于稳定性非常重要。虽然 Linux 处理资源异常出色,但它只能做到这么多。CPU 可能被过度利用,磁盘变满,过多的输入/输出甚至可以使最强大的服务器停止。密切关注这些事情非常重要,特别是当系统用于生产并且被其他人依赖时。
在本章中,我们将探讨检查 Linux 系统上正在运行的内容以及管理其资源的方法,以确保您的节点在网络上表现良好。
在本章中,我们将涵盖:
-
检查和管理进程
-
了解负载平均值
-
检查可用内存
-
使用基于 shell 的资源监视器
-
检查磁盘空间
-
扫描已使用的存储空间
-
日志简介
-
使用 logrotate 维护日志大小
-
了解 systemd 初始化系统
-
了解 systemd 日志
检查和管理进程
在典型的故障排除场景中,您可能会遇到一个行为不端或需要对其执行操作的进程。如果您在工作站上使用图形桌面环境,您可能会使用诸如 GNOME 系统监视器之类的工具来调查系统上运行的进程,然后终止问题进程。但在大多数情况下,您可能不会有图形桌面环境(至少不会在服务器上),因此您将使用诸如kill
之类的命令来摆脱行为不端的进程。但在终止进程之前,您需要知道其进程标识符(PID)。在所有 Linux 系统上找到进程的 PID 的一种方法是打开终端并使用ps
命令。以下是其用法示例:
ps aux
除了ps
,如果您已经知道进程的名称,通常会使用grep
。在这种情况下,您可以将ps aux
的输出导入grep
,然后搜索进程。
ps aux |grep httpd
ps
命令将为您提供正在运行的进程列表。如果使用了grep
,输出将被缩小为与搜索项匹配的进程列表。您将在结果中看到每个进程的PID
位于第二列中。在第三列中,您将看到进程正在消耗多少 CPU,然后是内存使用列。
!检查和管理进程
在 Debian 系统上的 ps aux 输出
USER
,STAT
,START
,TIME
和COMMAND
是我们可以从此输出中看到的其他列。虽然USER
是不言自明的,但这里是其他列标题的简短描述:
-
STAT
:此字段标识程序的状态,其中一个或两个字符代码表示程序当前所处的状态。例如,S
表示进程正在等待某些事件完成,而D
是不可中断的睡眠状态,通常与 IO 相关。要查看完整列表,请查看ps
的手册页。 -
START
:此字段指的是进程开始运行的时间。 -
TIME
:这表示进程已经利用 CPU 的总时间。每当进程命中 CPU 并需要执行工作时,时间都会记录在 CPU 上。 -
COMMAND
:显示当前进程正在运行的命令。
现在您知道如何找到进程的 PID,我们可以看一下kill
命令,这是一个在需要关闭正常情况下无法关闭的程序时非常有用的命令。例如,如果您正在运行一个进程 ID 为 25787 的脚本,您可以通过执行以下命令来终止它:
# kill 25787
kill
命令通过向 PID 发送特定信号来工作。例如,信号 15 被称为SIGTERM。如果您对一个进程执行kill
而没有任何参数(就像我们在上一个示例中所做的那样),则默认发送信号 15,这基本上是礼貌地要求进程关闭。您可以向进程发送 18 种不同的信号,您可以在手册页中阅读有关这些信号的信息。就我们在这里讨论的而言,SIGINT
,SIGTERM
和SIGKILL
是您最有可能使用的。您可以通过执行以下命令查看这些信号以及它们的含义的列表:
man 7 signal
要发送特定信号,请在kill
命令后输入连字符,然后输入您希望发送的信号。由于kill
本身发送信号 15,您可以通过执行以下命令来执行相同的操作:
# kill -15 25787
要发送不同的信号,比如 2(SIGINT),请输入以下命令:
# kill -2 25787
如果您非常绝望,可以向进程发送信号 9(SIGKILL):
# kill -9 25787
但是,只有在您已经尽了最大努力但无法使进程关闭时,才应该使用SIGKILL
。SIGKILL
立即关闭进程,但不幸的是它不会给进程清理的机会。这可能导致不干净的临时文件和打开的套接字连接留在系统上。更糟糕的是,它实际上可能会损坏数据库和配置。因此,我再次强调,如果无法使进程正常关闭,kill -9
绝对应该是您尝试的最后一件事。首先尝试您知道的每种方法来正常关闭进程,然后再尝试几次,然后考虑使用它。
另一个可以用来终止进程的命令是killall
命令。killall
命令允许您终止系统上与特定名称匹配的所有进程。例如,假设您有多个打开的 Firefox 窗口并且程序停止响应。要立即终止系统上运行的所有 Firefox 实例,只需执行以下命令:
killall firefox
就这样,您系统上的每个 Firefox 窗口都会立即消失。killall
命令可用于关闭共享相同名称的多个进程,并且在运行多个单个无响应程序或脚本的服务器上非常有用。
这基本上就是使用kill
和killall
命令的全部内容。当然,还有更多选项,手册页会给您更多信息。但简而言之,这些是您实际使用的变体。在理想的世界中,您应该永远不需要使用kill
,并且在服务器上运行的所有进程都会毫无疑问地服从您。不幸的是,我们不生活在一个完美的世界,您可能会比您想象的更经常使用这些命令。
理解负载平均值
对于 Linux 管理员来说,负载平均值是您将学到的最重要的概念之一。虽然您可能已经知道这个数字代表系统承受多大负载,但它也代表着趋势性能。使用这个数字,您将能够确定您的系统是被压倒还是正在恢复和平静下来。基本上,负载平均值由三个数字组成,每个数字代表系统在特定时间范围内的平均负载。第一个数字代表一分钟,第二个代表五分钟,第三个代表 15 分钟。有许多方法可以查看您的负载平均值,并且它也会显示在大多数 Linux 可用的系统监视器中。查看您的负载平均值的一种简单方法是执行以下命令:
cat /proc/loadavg
查看负载平均值
一个更简单的技术是使用uptime
命令。虽然uptime
命令的主要目的是查看系统已经运行了多长时间,但它也显示了系统的负载平均值。
uptime 命令的输出
那么,如何正确解释这些信息呢?通过本节中显示的 uptime 命令的截图,我们看到以下数字:
0.63 0.72 0.71
如前所述,前三个数字分别代表了 1、5 和 15 分钟内系统的负载。所谓的负载表示在每个时间段内等待或当前使用 CPU 的进程数量。在本例中使用的系统上,我们可以看到它的负载相对较低。我们还可以看到负载平均值的趋势。在这个例子系统上,负载正在上升,但只是稍微上升。
一般来说,负载平均值越低越好。但并非总是如此;较低的数字也可能令人不安。例如,如果您有一个本应该忙碌的服务器,其负载平均值下降到小于 1,这可能是一个警告信号。如果负载如此之低,服务器显然并不忙碌。这可能表示应该运行的某个进程已经失败。例如,如果您有一个通常会同时处理数百个查询的 MySQL 服务器,突然发现服务器变得无所事事,肯定会感到奇怪。另一方面,负载平均值达到数百的服务器将如此忙碌,以至于甚至无法处理您的登录请求,也无法访问系统!
让我们再看一个负载平均值。这是我帮助管理的网络上一个更繁忙系统的负载平均值:
9.75 8.96 5.94
在这里,我们可以看到这个系统的负载比前一个例子高得多。这可能是我想要调查的事情。但关于系统的负载平均值令人困惑的一点是,数字本身并不足以证明有警告的理由。如果该系统有十个核心,我就不会那么担心。尽管负载平均值超过了 9,但在这种情况下,将有足够的 CPU 来处理工作负载。然而,我从中获取输出的系统只有四个核心,所以这是一个警告信号。这意味着在每个三个时间窗口内,等待 CPU 时间的进程比系统实际拥有的核心还要多。这不是好事。但幸运的是,我可以看到系统正在恢复,因为负载正在下降。在这种情况下,我不会惊慌,但肯定会继续关注,以确保它继续恢复。我可能还会调查系统,找出到底是什么导致了负载如此高。也许服务器刚刚完成了一个非常大的任务,但值得调查一下。
作为一个经验法则,记录系统在正常预期负载下的基线是一个好主意。您网络上的每个系统都将有一个指定的目的,每个系统在任何时候都会有一个您可以合理预期系统面临的特定负载。如果系统的负载平均值低于基线或高于基线,那么您就需要查看并找出问题所在。如果负载达到一个水平,其中有更多的进程比您的核心处理器处理的,那就是一个警告信号。
检查可用内存
Linux 系统非常出色地处理内存,尽管如果一个进程行为不端或分配的内存不足,事情可能会失控。在系统开始表现迟缓的情况下,检查可用内存可能是您首先要查看的事情之一。为此,我们使用free
命令。为了使输出更易读,您可以添加-m
选项,以以兆字节为单位显示内存使用情况,这样可以使其更容易阅读。起初阅读这个输出可能会令人困惑,但我相信在我们阅读输出后,您会发现它很简单。
free 命令的输出
运行free
命令时,我们得到了三行六列的信息。第一行显示了我们实际的 RAM 使用情况,而第二行声明了缓冲区,第三行声明了交换使用情况。在total
下,我们看到这个系统安装了 7923 MB 的 RAM。从技术上讲,这个系统有 8 GB 的 RAM,尽管其中一部分被保留给内核或某种硬件,可能不会显示在这里。在下一列(used
)中,我们看到了我们系统的 RAM 有多少被使用,然后是free
,它显示了系统 RAM 中有多少是未使用的。在我们之前的例子中,似乎我们只有 927 MB 的 8 GB 是空闲的,但这并不完全正确。那么,到底有多少内存是真正空闲的呢?
首先,第一行中的used
表示实际使用了多少内存,包括缓存的部分。基本上,Linux 中的内存管理声明了所谓的磁盘缓存,这是一块为尚未写入磁盘的数据保留的内存块。您可以在free -m
命令的输出中看到这一点;它是cached
下面最右边的数字。这部分内存不一定被进程使用;它被声明为使系统运行更快。如果启动一个进程并且它需要的 RAM 超过了第一行free
下显示的 RAM,Linux 内核将乐意从磁盘缓存中分配内存给其他进程。
磁盘缓存有助于提高性能。当你从磁盘读取东西时,它会存储在磁盘缓存中,然后每次都从那里读取,而不是每次都从磁盘读取。例如,假设你每天都要查看保存在/home
目录中的文本文件。第一次读取时,你是从磁盘读取的。从那时起,它就存储在磁盘缓存中,每次你想要从那时起读取文件时都是从那里读取。由于 RAM 比硬盘快,这个文件每次只需要从磁盘读取一次,然后以后都是从磁盘缓存中读取。
磁盘缓存中存储的信息会随着时间而过期。随着磁盘缓存的填满,存储在其中的最旧信息会被删除以腾出空间。此外,当进程需要内存时,可以随时从缓存中取回内存。这就是为什么即使有时候看起来大量的 RAM 被缓存使用,也不是一个大问题——应用程序在需要时永远不会被阻止访问这些内存。
回到我们的例子,确定我们有多少空闲内存时要看第二列的数字,第二行的数字。在这个例子中,3736 MB 被认为是空闲的。对于这个特定的系统来说,这是足够的空闲内存。当这个数字减少并且交换开始增加以补偿时,你应该担心。只要你的系统有足够的 RAM 来完成指定的任务,交换应该几乎不会被使用。几乎总会使用一小部分,但当使用大量时就是问题。当你的系统实际上开始耗尽内存时,它将开始使用你的交换分区。由于硬盘比 RAM 慢得多,你不希望这样。如果你看到你的交换空间被滥用,你应该运行某种资源监视器(我们在本章中讨论了其中的一些)来确定是什么在使用它。
为了确保我们对free
命令的输出有一个全面的理解,让我们逐个讨论它包含的所有部分,从第一行开始。我们已经介绍了total
,这是你的系统物理上安装的内存量(减去你的内核或硬件保留的部分)。在第一行的下一个是used
,它指的是任何时候被使用的内存量,包括缓存。而free
列则完全相反,指的是没有被任何东西使用的内存。
第一行的最后两项是buffers
和cache
。虽然这两个部分没有被任何进程使用,但内核会用它们来缓存数据以进行性能优化。但如果一个进程需要更多的内存,它可以从这两个数字中获取。我们已经介绍了磁盘缓存,这是最后一个数字。buffers
指的是尚未写入磁盘的数据。Linux 会在各种时间间隔内运行sync
命令将这些信息写入磁盘。如果你愿意,你甚至可以自己运行sync
命令,尽管这很少是必要的。缓冲区的概念也是为什么你不希望在没有先卸载的情况下突然从计算机中移除外部媒体的一个关键指标。如果你的系统尚未将数据同步到磁盘,如果你过早地弹出媒体,你可能会丢失数据。
在第二行,我们有-/+ buffers cache
(在我们的示例中分别为 4186 MB 和 3736 MB)。这一行的第一个数字(4186 MB)是通过从第一行的已使用列(6995 MB)减去缓存和缓冲区的总和(2808 MB)计算出来的。这给了我们 4187 MB 的总数,由于四舍五入的原因(我们使用了-m
标志,所以我们的输出以 MB 为单位,所以有一点偏差),但足够接近。如果我们按照同样的数学计算,但在我们的 free 命令中没有使用-m
标志,结果将是精确的。第二行的下一个数字是 3736 MB。正如前面提到的,这是系统实际可用的内存量。为了得到这个数字,我们从已使用的内存(4186 MB)中减去我们的总内存(7923 MB)。
再次强调,在第二行的free
下面的内存量是你关心的数字,当你想知道你还剩下多少内存时。然而,了解我们是如何得出这个数字以及 Linux 是如何为我们管理内存的也是很重要的。
使用基于 shell 的资源监视器
安装任何带有桌面环境的 Linux 发行版时,很可能会捆绑一个图形系统监视器。其中流行的有 KSysGuard 和 GNOME 系统监视器,但还有许多其他的。大多数情况下,这些都很好用。GNOME 系统监视器能够显示负载平均值,当前运行的进程(以及它们的 PID,CPU 百分比,内存等),以及磁盘使用情况。许多图形系统监视器也显示这些信息以及更多。虽然这些工具很棒,但典型的基于 Linux 的网络中的节点并不总是有图形用户界面可用。幸运的是,通过 shell 有许多不需要运行桌面环境的资源监视工具。这些工具中一些非常出色,以至于你会在某个时候放弃图形工具而使用 shell 工具。这个类别中流行的工具包括 top,htop,iotop 和 ncdu。
首先,我们需要确保上述工具已经安装在我们的系统上。在大多数情况下,top 已经为我们安装好了,但其他的需要手动安装。你可以通过运行以下命令来验证 top 是否已安装:
which top
你应该看到以下输出:
/usr/bin/top
你可以使用你的发行版的软件包管理器来安装其他工具。对于 Debian,你可以一次性安装它们所有:
# apt-get install htop iotop ncdu
不幸的是,在 CentOS 上,并非所有这些软件包都在默认存储库中可用。要在 CentOS 上安装这些工具,您首先需要添加epel
存储库,然后才能安装所有软件包。以下概述了要使用的命令:
# yum install epel-release
# yum install htop iotop ncdu
随意尝试这些工具。top
和htop
命令都可以在没有 root 访问权限的情况下运行。但是,您需要至少使用sudo
来运行iotop
才能使其正常工作。ncdu
命令将作为普通用户运行,但将被限制为仅查看该用户可以访问的资源。让我们更仔细地看看这些工具。
这些工具对我们有什么作用呢?首先,top
是经过验证的;如果您不是 Linux 的新手,那么您可能以前已经使用过。在查看系统上正在运行的内容时,top
是相当常见的。使用top
,您将看到各种信息,例如正常运行时间,平均负载,已使用内存,已使用交换空间,缓存等。在屏幕的底部部分,您将看到进程列表。完成后,只需按Q退出。
在 CentOS 系统上运行的 top 命令
有几种方式可以运行top
。通过不带参数运行top
,您将看到一个类似于本节前面显示的屏幕。您将在上部看到系统性能摘要,底部显示各种进程。但是,如果您已经知道要监视哪个进程,可以使用-p
标志加上 PID 来仅监视该进程。例如,我们可以使用以下命令来监视 PID 为12844
的进程:
top -p 12844
默认情况下,top
命令中的输出每三秒更新一次。要更改此设置,您可以使用-d
标志选择不同的频率(以秒为单位):
top -d 2
如果您愿意,频率可以小于一秒:
top -d 0.5
如果top
已经在运行,并且您想要更改更新频率,您不必关闭它然后再次启动。您可以在其运行时键入s
,然后会提示您指定一个新的频率。
在top
中,您可以通过按键盘上的键来更改进程列表的排序方式。如果您键入P
,则按 CPU 使用率排序;使用M
,您可以按内存使用率排序(这里大小写要注意)。您甚至可以通过按k
来从这里终止一个进程,然后会提示您输入要终止的 PID。不过要小心;这默认为您按下时进程列表顶部的内容,所以确保在实际输入 PID 之前不要按Enter
,否则可能会终止您不想终止的进程。
那么,为什么要使用top
呢?管理员使用top
的主要目的是帮助确定是什么导致系统变得 CPU 或内存密集。大多数情况下,top
从来不是解决方案,而是根本原因分析的开始。您可以立即看到哪个进程正在消耗您的 CPU 或 RAM,但根据上下文,您可能还不知道如何解决问题。使用top
,您只能发现罪魁祸首。不幸的是,top
可能并不总是显示出根本原因的进程,但当您的系统运行缓慢时,这绝对是一个非常容易的第一处查找地方。
要开始故障排除,顶部的信息将为您提供一个起点,以查看哪个资源正在被使用。在%Cpu(s)
行上,我们可以立即看出系统是否遭受过多的 I/O 等待(%wa
字段),这基本上意味着 CPU 承受的负担超过了它的处理能力。在这种情况下,任务将积压,平均负载将增加。空闲时间(或%id
)是一个数字,它越高越好,这意味着您的系统将有 CPU 时间可用。
在某些情况下,您可能会发现 CPU 使用过高,但在进程列表中并没有显示太多。在这种情况下,您可以打开iotop
来确定您的系统是否受到 I/O 限制。使用iotop
(需要 root 权限),您可以看到写入或从磁盘读取的数据量。使用左右箭头,您可以将焦点从一列转移到另一列,这样可以按该列对进程列表进行排序。
在 Debian 系统上运行 iotop
默认情况下,iotop
中的进程列表相当拥挤。您可以通过执行以下操作来精简它:
# iotop --only
通过附加-only
,您只会看到实际发生读写操作的进程。在本节中iotop
的截图中,您可以看到有相当多的进程根本没有活动。但是使用-only
可能更容易阅读,因为它清理了输出。您实际上可以在iotop
运行时激活-only
,只需在键盘上简单地按下O。此外,另一个有用的键盘快捷键是使用r
更改任何列的排序顺序。
在本节中,我们有htop
。虽然top
是在 Linux 系统上查看系统资源的标准方法,但htop
的受欢迎程度正在迅速增加。
htop 命令的操作
htop
的基本思想与top
相同——top
区域显示当前的 CPU 和内存使用情况,底部部分提供了一个进程列表。但htop
的不同之处在于它如何呈现这些信息,更容易阅读,并提供了 CPU 使用情况的图表区域。除此之外,它还允许您轻松地向进程发送特定信号。在前面,我们介绍了各种信号,您可以使用它们来结束一个进程。在这里,我们可以看到相同的概念以图形方式呈现。要向进程发送信号,请使用键盘上的上下箭头突出显示一个进程,然后按F9选择特定的信号。SIGTERM
是默认选择的,但您也可以向进程发送任何其他信号。
准备在 htop 中向进程发送信号
htop
中的进程列表可以类似于iotop
进行排序。一开始可能不明显的一件事是,htop
支持鼠标输入。虽然您可以使用箭头键选择列,但也可以单击它们。
htop
的另一个好处是它的可定制性。虽然默认布局对大多数用例来说都不错,但您可以添加额外的仪表。要这样做,请按F2或单击设置,您将进入一个菜单,可以从当前视图中添加或删除仪表。在可用仪表
下,突出显示您想要添加的仪表之一,然后按F5将其添加到左列,或按F6将其添加到右列。您可能会发现有用的一个仪表是CPU 平均值
。添加新仪表后,您可以通过突出显示它并按F7将其上移或按F8将其下移来重新定位它。完成后,按Esc返回到主屏幕。这些更改会自动保存,因此下次打开htop
时,您的自定义布局将保持不变。
扫描已使用的存储
几乎每个人都会遇到磁盘空间似乎消失的情况,却没有明确的指示是什么占用了所有的空间。有多种方法可以排除是什么特别占用了你的硬盘空间。为了查看已挂载文件系统的概况以及它们的已用和空闲空间,执行df
命令。对于大多数人来说,使用-h
和df
更容易阅读,因为它会显示以 MB 和 GB 为单位的已用空间:
df -h
掌握了这些信息,您将准确知道哪个设备被使用了,以及要关注的卷。但df
命令实际上并没有告诉您是什么占用了所有的空间;它只是给了您当前情况的概述。
接下来是du
。du
命令也可以与-h
配对,原因相同,它显示目录中使用了多少空间。您只需要cd
进入要检查的目录,然后运行du -h
。为了更易于阅读的输出,可以在目录中运行以下命令:
du -hsc *
分解该命令,我们有-h
参数,我们已经知道它使输出更易于阅读。-s
参数仅显示总计,-c
将在最后呈现总计。由于我们在命令中使用了星号,它将对当前目录中包含的每个子目录运行du -hsc
。使用此命令,您可以确定当前工作目录中哪些目录占用了最多的空间。
但它甚至比这更好。尽管du -hsc *
非常有用,但您仍然需要为每个子目录手动运行它。有方法可以使用它进行更深入的扫描,但du
仅适用于概览摘要。更好的方法是安装ncdu
。ncdu
命令不是图形实用程序,因为它不需要图形桌面环境。但它非常易于使用;您可能会认为它实际上是一个图形实用程序。一旦针对特定目录启动,它会进行深入分析,并允许您实际遍历文件系统树并跟踪占用所有空间的元凶。
您不需要成为 root 用户或具有sudo
权限来使用ncdu
,但请记住,ncdu
只能扫描其调用用户有权限访问的目录。在某些情况下,您可能需要以 root 身份运行它以绕过这一限制。ncdu
的基本用法很简单;只需调用ncdu
并提供要扫描的路径。例如,您可以扫描整个文件系统或其中的一部分:
ncdu /
使用 ncdu 扫描 CentOS 系统的根文件系统
需要注意的是,默认情况下,ncdu
将扫描您提供的目录中的所有内容,包括可能已挂载的任何内容。这可能包括已挂载的 NFS 共享或外部磁盘,但您可能不希望外部挂载影响结果。幸运的是,只需向ncdu
提供-x
选项即可,告诉它在运行扫描时忽略您已挂载的任何内容:
ncdu -x /
扫描完成后,您可以通过键盘上的上下键遍历结果,并按Enter进入目录。在ncdu
内部,您甚至可以通过简单按下D键而无需运行任何额外命令来删除文件。这样,您可以在同一工具中进行审计和清理。
随意在自己的系统上运行ncdu
,并查看您的可用空间去向。除非您真的开始删除东西,否则它是无害的,并且可以显示一些您可能想要清理的潜在项目。在实际服务器上,ncdu
在解决磁盘空间去向方面非常有用。
日志简介
默认情况下,Linux 几乎记录所有内容。这对于在出现问题时进行根本原因分析非常重要。当您在生产服务器上面临问题时,您只需要确定问题开始的时间,然后阅读在该时间内系统上发生的事情的日志文件。Linux 日志非常详尽。
但是,如今,Linux 处理日志的方式正在发生变化。随着 systemd 的崛起,它现在是大多数 Linux 发行版上的默认 init 系统,它几乎接管了一切,包括日志记录。过去,每当您想要阅读日志时,您会进入/var/log
,这是一个包含各种以纯文本格式存储的日志文件的目录。在 Debian 和 CentOS 上,您仍然可以在/var/log
中找到日志,因此您仍然可以像以往一样利用它们进行故障排除。但目前尚不确定这种方式还能维持多久。
许多人可能认为 systemd 接管日志记录是件坏事。毕竟,让 init 系统负责系统的许多维护工作会增加其负担,可能会使其负担过重。但 syslog(之前的方法)的一个问题是,不同发行版在日志创建或命名方面没有一致性。例如,Debian 系统包括auth.log
,而 CentOS 没有。两者都有dmesg
,只有 CentOS 有boot.log
文件。这使得在混合环境中进行故障排除变得非常困难。
systemd 方法(稍后我们将讨论)在不同发行版之间提供了更一致的方法。因此,尽管 systemd 在系统上承担了许多责任,但一致性肯定是受欢迎的。
Debian 和 CentOS 都有一个日志文件,用于用户登录系统,即使是通过 SSH 登录。在 CentOS 上,此日志位于/var/log/secure
。Debian 使用/var/log/auth.log
来实现此目的。如果您需要知道谁何时登录到您的系统,您需要查看这些日志。在两者中,您可以找到/var/log/messages
,其中包括各种有用信息,例如进程输出,网络激活,服务启动等。在硬件故障排除方面,/var/log/dmesg
是一个很好的查看地点。实际上,/var/log/dmesg
有自己的命令。在系统的任何位置(即使您当前的工作目录不是/var/log
),键入dmesg
将呈现相同的日志。
使用tail -f
可以非常容易地实时跟踪/var/log
中的日志文件。tail
的-f
标志不仅限于日志文件。它允许您显示日志文件的输出,就像它正在被写入一样。在故障排除系统时,tail -f
是不可或缺的。例如,如果您有一个无法登录系统的用户,您可以在 Debian 系统上运行以下命令来观察auth.log
文件,以查看他们的尝试。这样,您可以看到系统为其登录失败尝试注册的错误消息:
# tail -f /var/log/auth.log
从那里,随着auth.log
的更新,结果将立即显示在您的终端上。要结束,只需按下Ctrl + C停止跟踪输出。您可以对系统上的任何日志或文本文件执行此操作。这对于多种故障排除策略非常有用,因为您可能想要调查的大多数进程都会将其活动记录到至少一个日志中。
使用 logrotate 来维护日志大小
如您所知,日志在故障排除时至关重要。Linux 通常会很好地记录几乎您想要了解的一切,但随着时间的推移,这些日志可能会不断增加。在生产服务器上,如果不加以控制,日志文件不断增长并占用服务器的所有可用空间是一个非常现实的问题。除了占用磁盘空间外,巨大的日志文件很难在文本编辑器中打开以查看内容,这使得故障排除变得更加困难。超过 500GB 的日志文件不仅会占用大量空间;如果尝试打开它,它可能会导致系统挂起,并且一旦达到非常大的大小,将日志文件传输到另一台服务器进行分析也是不切实际的。
在较新的 Linux 发行版上,过多的日志文件通常不是问题。使用 syslog 时,没有自动维护。如果您没有自己清理日志,或者设置了一些东西来为您轮换日志,那么您肯定需要留意它们。如今,journald为我们处理这个问题。但是对于 Debian 和 CentOS 来说,这可能有点复杂。这是因为尽管 systemd journald 在大多数流行的 Linux 发行版的新版本中为我们处理日志记录,但 syslog 仍然用于兼容性。因此,即使所有部件都已经就位,我们仍然需要处理日志轮换。journald 是未来,尽管 syslog 仍然在企业 Linux 发行版上用于兼容性。
日志轮换是指获取现有日志文件,重命名它,并让进程写入一个全新的空日志文件的过程。以前的日志文件可以全部保留,或者您也可以只保留其中几个。企业系统通常有特定的保留策略。压缩以前的日志是很常见的做法,这样可以节省大量的磁盘空间。这就是 logrotate 的用武之地。这是一个我们可以在服务器上运行的过程,用来自动交换我们的日志文件,并(作为一个选项)压缩备份副本。
在设计 Linux 网络时,了解每台服务器需要运行哪些进程,并从一开始考虑这些进程的日志记录要求是很重要的。在服务器进入生产之前安装和配置 logrotate 是一个好的做法。在生产过程中服务器的空间用完是一个不好的经历,首先了解运行进程创建的日志文件,做好处理准备是一个好主意。在配置日志记录时,重要的是要考虑公司的保留要求,如果有的话。
在我实验室使用的 CentOS 系统上,默认情况下安装了logrotate
。Debian 也默认情况下安装了它。要在您的系统上验证这一点,只需运行以下命令:
which logrotate
在 CentOS 上,logrotate
二进制文件位于/usr/sbin
,而 Debian 将它们存储在/usr/sbin
中。如果which
命令没有输出,您可能需要使用您的发行版软件包管理器来安装logrotate
软件包。
在 Debian 和 CentOS 的默认安装中,logrotate
已经配置为每天运行。当它运行时,它会检查/etc/logrotate.d
目录中的指令,然后执行它们。设置logrotate
规则的配置非常简单。如果您需要示例语法,请参考您自己的系统。默认情况下,为您创建了几个logrotate
脚本。其中一个例子是 Debian 的软件包管理器apt
。在 Debian 系统上安装软件包时,它会被记录在以下位置:
/var/log/apt/history.log
如果您查看此文件,您应该看到您或其他用户执行的最近软件包安装的结果。在 Debian 系统上,默认情况下存在以下文件来处理此日志的轮换:
/etc/logrotate.d/apt
在 Debian 8 上,此文件包含以下内容:
/var/log/apt/term.log {
rotate 12
monthly
compress
missingok
notifempty
}
/var/log/apt/history.log {
rotate 12
monthly
compress
missingok
notifempty
}
正如您所看到的,logrotate
的这个配置文件不仅处理我们之前提到的history.log
,还处理term.log
。此配置的每个部分都以logrotate
要检查的路径开头,然后是方括号内的各个选项。
注意
term.log
文件显示了在运行 apt 实例时将会看到的实际终端输出。
在选项中,我们可以看到rotate 12
,这意味着最多会保留 12 个备份日志文件。接下来,我们看到monthly
,它详细说明了日志实际上会被多久轮换一次。尽管logrotate
默认配置为每天运行,但它将遵循各个配置中包含的指令,只有在符合条件时才会轮换。compress
选项告诉logrotate
压缩备份文件,这在大多数情况下可能是你想要的。压缩的日志文件与未压缩的实时日志相比占用的空间非常少,因此这绝对值得考虑。missingok
告诉logrotate
即使遇到缺失的日志文件也要继续运行。否则,它会显示错误。最后,我们有notifempty
,它简单地告诉logrotate
如果日志文件为空就不要理会它。
注意
你可以通过查阅logrotate
的 man 页面来看到完整的logrotate
配置选项列表。
man logrotate
虽然logrotate
为一些随 CentOS 和 Debian 一起提供的服务有相当不错的默认配置,但你可能需要考虑为你设置的任何新服务创建配置。要这样做,最简单的方法是按照你已经存储在/etc/logrotate.d
中的示例文件中显示的格式。只需从文件路径开始你的配置块,然后在花括号内添加选项。没有需要重新启动的服务或特殊命令来使你的新配置生效。下次logrotate
运行时,它将检查/etc/logrotate.d
目录中是否有新的配置,并在没有错误的情况下运行它们。
理解 systemd init 系统
在当今的许多 Linux 发行版中,init 系统已经切换到 systemd。这适用于分别从版本 8 和 7 开始的 Debian 和 CentOS,但其他发行版如 Fedora、Ubuntu、Arch Linux 等也已经切换。尽管一些管理员更喜欢之前主导的 init 系统 sysvinit,但 systemd 相对于旧系统提供了许多进步。
使用 systemd,你现在使用来启动进程的命令是不同的,尽管大多数旧命令仍然有效(目前)。在 Debian 7 系统上使用 sysvinit,你会使用以下命令来重新启动 Samba:
/etc/init.d/samba restart
然而,现在我们使用systemctl
来start
,stop
或restart
一个进程:
# systemctl restart samba
在 CentOS 和 Debian 中管理进程的 sysvinit 风格以前是一样的,现在仍然是一样的。在撰写本文时,两者都已经切换到 systemd。但在当前版本中,旧的/etc/init.d/<process-name> restart|stop|start
命令在 Debian 和 CentOS 中仍然有效,但不再使用 sysvinit(已经消失),而是转换为 systemd 命令。如果你运行旧的 sysvinit 风格命令,你可能会在输出中看到一些文本,告诉你系统正在使用systemctl
。尽管这对于兼容性来说很好(依赖 sysvinit 风格命令的脚本可能仍然有效),但这种情况不会持续太久。学习 systemd 很重要,因为一旦 sysvinit 兼容层被移除,你将不再能依赖旧的方法。幸运的是,systemd 的基础知识很快就能学会。
要使用 systemd 启动一个进程,执行systemctl
,然后是你想执行的操作,再加上你想对其执行操作的进程。就像我们之前对 Samba 所做的那样,我们执行了systemctl restart samba
。但我们也可以使用systemctl stop samba
来停止 samba,或者以 root 身份执行systemctl start samba
来启动它。
systemd init 系统还允许您启用或禁用进程。启用的进程将在系统启动时启动。只有在您手动启动时,禁用的进程才会启动。根据发行版,进程(或 systemd 称之为单元)可能不会默认启用。例如,在 CentOS 上,您可以安装 Samba,但除非告诉它这样做,否则它不会自动启动。在 Debian 系统上,通常假定您安装了某些东西,因此它将默认启用新安装的进程。无论哪种方式,都不应该假设进程会自动启动 systemd。要找出,请使用以下命令:
systemctl status <process>
使用 systemctl 检查单元的状态
使用systemctl
检查状态会给您提供大量有用的信息,通常比使用 sysvinit 检查进程状态时更多。首先,您可以看到单元是否正在运行。在上一张截图中,我们可以看到nfs-kernel-server
正在运行。此外,状态还给我们提供了几行日志输出,因此如果启动单元时出现任何问题,我们可能会在那里找到错误。
您可能想知道如何找出一个单元是否配置为在系统启动时自动启动。systemd 也使得这变得容易。我们可以使用is-enabled
与systemctl
来查找单元是否已启用。例如,要确保ssh
守护程序已配置为自动启动,我们将在 Debian 系统上发出以下命令:
systemctl is-enabled ssh
要显示系统上的所有单元及其配置方式,请运行以下命令:
systemctl list-unit-files
要启用一个单元,将enable
作为参数传递给systemctl
。同样,您也可以使用disable
来确保单元不会在启动时启动。因此,在 Debian 系统上,systemctl enable ssh
将配置ssh
守护程序在启动时启动,而systemctl disable ssh
将确保它不会启动。CentOS 也是一样,但用sshd
替换ssh
。尽管 Linux 系统之间的单元名称可能会让人感到恼火,但始终记住,您可以像前面提到的那样使用systemctl list-unit-files
来查看注册到您的系统的单元列表及其名称。
简而言之,这就是使用systemctl
管理 Linux 系统上的进程(单元)所需的所有知识。在大多数情况下,启动、停止、启用和禁用单元可以涵盖大多数用例。对于更高级的用法,请参阅systemctl
的 man 页面。
注意
Systemd 还处理电源管理。您可以使用systemctl
的选项,如reboot
、poweroff
和suspend
来启动、关闭或暂停整个系统。
理解 systemd 日志
systemd 的另一个组件是 journald,它处理日志记录。systemd 的 journald 方法启用了二进制日志,这与以前使用的简单文本文件的方法完全不同。由于许多采用 systemd 的发行版仍处于过渡阶段,您可能仍会在/var/log
中看到文本文件日志,就像您可能仍会在/etc/init.d
中看到 init 脚本一样。始终建议尽可能使用 systemd 方法,因为这是发行版正在向其移动的当前解决方案。
您可以使用journalctl
命令查看 journald 日志。此外,可以使用journalctl
命令的各种选项来缩小输出范围或执行某些操作。例如,您可以使用journalctl -f
来跟踪系统上的新日志输出,类似于您可以使用tail -f
来跟踪存储在/var/log
中的日志文件。此外,您可以使用journalctl
来显示特定 PID 的输出。要这样做,只需使用PID=
和 PID 一起使用journalctl
。例如,要查看 PID11753
的输出,您将执行以下命令:
journalctl PID=11753
此外,您可以使用单位的名称来显示其输出:
journalctl -u sshd
虽然journalctl
相对简单易用,但习惯于以前的 syslog 日志记录方式的人会高兴地知道,您仍然可以(至少目前还可以)转到/var/log
并查看日志。例如,dmesg
命令和日志仍然存在且运行良好。但是,虽然需要一段时间来适应journalctl
和二进制日志的概念,但我相信您会发现通过实践,它实际上非常方便。
总结
在本章中,我们介绍了各种管理系统资源和查看日志的方法。我们从管理进程的概述开始,讨论了负载平均值。然后,我们介绍了监视系统内存的方法。此外,我们还研究了基于 shell 的系统监视器,如top
和htop
。我们还介绍了磁盘使用情况和ncdu
,这是一个方便的工具,可以扫描文件系统并以易于使用的方式查看其使用情况。我们还介绍了logrotate
和systemd
。
在下一章中,我们将介绍如何管理基于 Linux 的网络。这将包括配置 DHCP、DNS、NTP,以及使用exim
发送电子邮件和在网络上广告共享服务等内容。
第六章:配置网络服务
到目前为止,我们已经配置了我们的节点,并允许它们实际上相互通信。我们可以访问我们的节点以远程管理它们,在它们之间传输文件,监视它们的资源,并执行基本的网络操作。在本章中,我们将设计我们将用于网络的 IP 地址方案,并设置实施计划所需的服务。这将包括讨论设置和配置动态主机控制协议(DHCP)、域名服务以及网络时间协议(NTP)。
在本章中,我们将涵盖:
-
规划您的 IP 地址布局
-
安装和配置 DHCP 服务器
-
安装和配置 DNS 服务器
-
设置内部 NTP 服务器
规划您的 IP 地址布局
在网络上实施任何计划之前花时间制定一个很好的计划是一个好主意,但是您的 IP 地址方案尤其重要。很容易接受默认设置并迅速让所有人上线。对于一些小公司来说,路由器(或默认情况下处理 DHCP 的任何设备)提供的默认 IP 地址布局可能足够。但是随着公司的发展,这种情况需要改变。为潜在的增长做好准备至关重要。实施 IP 地址方案很容易,但是在已经推出的网络上更改此方案是一个巨大的挑战。一定要花时间进行适当的规划。
确定 IP 地址方案的首要考虑因素是您需要为哪些类型的设备提供地址。通常,您需要处理服务器、工作站和打印机。但是现在,我们的网络上还有其他设备,如 IP 电话、公司发放的电话、会议系统、平板电脑等。当您开始将所有这些设备放在一起时,一个典型的具有 254 个可用地址的 24 位网络似乎并不那么大,即使对于一个小公司来说也是如此。更糟糕的是,一些设备(如笔记本电脑)有多个网络接口卡。如果将所有这些放在一起,您会发现这 254 个地址很快就会被用完。
拥有多个子网肯定会有所帮助。通过子网划分,您可以为每种类型的服务创建单独的网络,每个网络都有自己的一组 IP 地址。例如,您可以将服务器放在一个子网上,打印机放在另一个子网上,最终用户工作站放在它们自己的子网上。您可以将一个 24 位子网分成几个网络,而不是将其在这三种设备类型之间进行划分。我们将在第八章中更详细地介绍子网划分,但是现在,隔离您的网络几乎总是一个好主意,原因甚至超出了 IP 地址的范围。
另一个需要考虑的因素是限制您的广播域。一个 24 位网络(通常是网络设备默认的)是一个广播域。简而言之,一个设备可以在您的网络上直接与另一个设备通信,而无需先进行路由,并共享相同的广播域。如果您只有几台设备,这并不重要(除非一个设备处理了大量的流量)。但是在大多数网络中,分割广播域可以提高性能。如果您有一个路由器分隔您的子网,那么实际上就是在分割您的广播域。因此,如果一个节点位于自己的子网上,它更难以使您的网络饱和。然而,没有完美的解决方案,单独的广播域也可能会变得饱和。
在规划 IP 方案时,一个有用的工具是ipcalc
实用程序。ipcalc
实用程序可以帮助您了解每个方案可用的 IP 地址数量。这个实用程序在 Debian 中通过apt-get
可用,不需要任何额外的存储库。虽然 CentOS 中内置了ipcalc
命令,但它不是同一回事,也没有用。如果可能的话,我建议使用 Debian 版本。要使用它,只需执行ipcalc
以及您考虑使用的网络。例如,您可以运行以下内容进行测试:
ipcalc 10.10.96.0/22
规划您的 IP 地址布局
ipcalc 显示 10.10.9.60/22 内部网络的子网信息
在前面的例子中,我们可以看到,如果我们选择了10.10.96.0/22
方案,我们将有1022
个可允许的 IP 地址,子网掩码为255.255.252.0
,这将是一个 A 类私有网络。虽然您将在本书的后面学到更多关于子网划分的知识,但ipcalc
实用程序对您来说将是一个方便的工具,可以让您玩弄并确定特定 IP 布局的外观。
另一个值得讨论的 IP 地址问题是 IPv4 与 IPv6。很长一段时间以来,IPv4 已经足够满足每个人的需求。不幸的是,现在公共互联网上的 IPv4 地址开始耗尽(在许多情况下已经耗尽)。IPv6 的好处在于有如此多的 IP 地址可用;我们再也不会用尽 IP 地址是完全不可想象的。IPv6 还具有安全性的好处,因为地址空间如此之大,目标被抽象化(本质上是通过混淆来保障安全)。
考虑到这一点,您可能会想在网络内部使用 IPv6 地址而不是 IPv4。然而,我的建议是,除非您有非常充分的理由这样做,否则不要费心。IPv4 地址的枯竭只影响公共互联网,而不影响您的内部网络。虽然您当然可以在内部部署 IPv6,但这样做没有任何好处。鉴于 IPv4 有超过 40 亿个可用地址,您需要相当多的设备才能证明 IPv6 的必要性。另一方面,IPv6 对电信业务确实有用(并且最终将是必需的)。对于那些正在学习思科考试的人来说,理解这个主题是必需的。但是对于本书的目的和设置 Linux 网络来说,IPv6 并不能证明管理开销。
总之,提前规划是很重要的。IPv4 对我们的需求已经足够了,将我们的网络划分为子网是一个好主意(即使您认为您的网络永远不会超过 254 个地址)。规划得越大越好;即使在最坏的情况下,您可能永远不会使用所有配置的 IP 地址。但即使您不打算使用大量 IP 地址,将它们保留以备将来扩展网络是一个好主意,而且以后实施起来更容易。根据我的经验,我曾经有过重新配置公司网络的任务,而该网络并不是为了增长而设计的。虽然这绝对是一次学习经历,但并不是一次愉快的经历。
安装和配置 DHCP 服务器
到目前为止,在本章中,我们讨论了为您的网络创建布局。在本节中,我们将付诸行动。在这里,我们将在 Debian 或 CentOS 机器上设置 DHCP 服务器,并将其配置为为我们的网络提供 IPv4 地址。所以,让我们开始吧!
首先,决定哪个发行版将运行您的 DHCP 服务器。选择 Debian、CentOS 或其衍生版本都无所谓。在每个版本上,配置都是相同的,主要区别在于您需要安装的软件包的名称和要启动的守护程序。在 Debian 上,您将安装isc-dhcp-server
软件包,而在 CentOS 上,您将安装dhcp
。Debian 将为您启用 DHCP 守护程序(isc-dhcp-server
),但它不会启动,因为我们还没有配置它。CentOS 不会尝试启动或启用其 DHCP 守护程序(dhcpd
)。
对于 Debian 和 CentOS,我们需要编辑的配置文件位于/etc/dhcp/dhcpd.conf
。为了设置我们的 DHCP 服务器,我们需要编辑这个文件,然后启动或重新启动守护程序。请使用您喜欢的文本编辑器打开这个文件。如果您在 Debian 上安装了 DHCP 服务器,您会注意到提供了一个包含相当多示例配置的默认/etc/dhcp/dhcpd.conf
文件。另一方面,CentOS 基本上给了您一个空白的文件来使用。为了我们的目的,我们将从头开始创建一些配置。在 Debian 的情况下,您可以删除或备份默认配置文件。
接下来是一个 DHCP 的示例配置文件/etc/dhcp/dhcpd.conf
。在这个示例中,我们使用了之前确定的相同网络,并演示了ipcalc
实用程序(10.10.96.0/22
)。这个网络给了我们几个子网可用,但您不必按照这个方案进行,可以根据需要进行调整以适应您的环境。
default-lease-time 86400;
max-lease-time 86400;
option subnet-mask 255.255.252.0;
option broadcast-address 10.10.99.255;
option domain-name "local.lan";
authoritative;
subnet 10.10.96.0 netmask 255.255.252.0 {
range 10.10.99.100 10.10.99.254;
option routers 10.10.96.1;
option domain-name-servers 10.10.96.1;
}
因此,让我们逐行通过这个配置。
首先,我们有以下两行:
default-lease-time 86400;
max-lease-time 86400;
在这里,我们确定了 DHCP 租约的持续时间。在实践中,当一个节点请求一个 IP 地址时,它的客户端将获得一个租约以及 IP 地址。这意味着 IP 地址只在特定的时间段内有效。在这里,我们设置了一个持续时间为86400
,这意味着我们的租约时间是一天,因为这是以秒为单位的。我们两次列出了这个数字,分别是默认和最大租约时间。如果客户端没有指定请求保留 IP 地址的时间,default-lease-time
将提供给任何客户端。max-lease-time
意味着如果客户端请求保留 IP 地址的时间超过这段时间,将不被允许这样做。我们基本上将默认和最大租约时间设置为相同的数字。如果需要,我们还可以包括min-lease-time
来强制客户端请求更短的最小租约时间。
考虑以下两行:
option subnet-mask 255.255.252.0;
option broadcast-address 10.10.99.255;
通过这一部分,我们正在设置子网掩码,该子网掩码将被分配给客户端,以及广播地址。正如您可能已经知道的那样,子网掩码标识每个连接节点将成为其中一部分的网络。当客户端在被提供地址后检查其 IP 信息时,我们标识的子网掩码将显示出来。广播地址是一个所有节点都能够接收数据包的地址。
考虑以下两行:
option domain-name "local.lan";
authoritative;
在这里,我们将local.lan
的域名附加到连接到我们的 DHCP 服务器的每个节点的主机名上。这一步并不是必需的,但在规范化网络中的域名时可能会有用。我们还在我们的配置中包括authoritative
,以确立我们的 DHCP 服务器是这个子网的主要服务器。
考虑以下行:
subnet 10.10.96.0 netmask 255.255.252.0 {
range 10.10.99.1 10.10.99.254;
option routers 10.10.96.1;
option domain-name-servers 10.10.96.1;
}
最后,我们在结尾有一个非常重要的代码块。在这里,我们确定了我们子网的网络地址、子网掩码、我们正在分配的 IP 地址范围、默认网关和我们的 DNS 服务器。在这个示例中,我们从10.10.99.100
开始分配我们的第一个 DHCP 地址,并在10.10.99.254
结束我们的地址池。如果您回忆一下之前的ipcalc
输出,您会注意到这个子网中的第一个地址从10.10.96.1
开始。但我们并没有从那里开始我们的地址池,而是晚了很多。为了参考,我们使用了10.10.96.0/22
网络,这给了我们以下子网:
10.10.96.0
10.10.97.0
10.10.98.0
10.10.99.0
如果我们愿意,我们可以将 DHCP 范围设置为从10.10.96.1
开始,到10.10.99.254
结束。在这种情况下,我们将有 1,022 个 DHCP 地址。但是,我在我的配置中没有这样做的原因是,前三个网络已被保留用于几个目的。我使用第一个(10.10.96.0/22
)用于服务器,下一个用于 DHCP 预留,第三个用于网络设备。由于前三个子网位于 DHCP 范围之外,DHCP 服务器永远不会向客户端提供这些地址,因此我不必担心 DHCP 租约会处理我可能设置的静态地址。确保静态 IP 地址位于 DHCP 范围之外是一种非常常见的做法。
公平地说,这个配置相当复杂,因为我向您展示了如何在 DHCP 中使用多个子网,而不是专注于一个网络。为了简化一点,如果我们设置一个默认的 24 位网络,我们的配置将如下所示(如果我们使用10.10.10.0/24
网络):
default-lease-time 86400;
max-lease-time 86400;
option subnet-mask 255.255.255.0;
option broadcast-address 10.10.10.255;
option domain-name "local.lan";
authoritative;
subnet 10.10.10.0 netmask 255.255.255.0 {
range 10.10.10.10 10.10.10.254;
option routers 10.10.96.1;
option domain-name-servers 10.10.96.1;
}
通过这个配置,我将 DHCP 范围设置为从10.10.10.10
开始,到10.10.10.254
结束。这给了我九个 IP 地址(10.10.10.1
—10.10.10.9
),永远不会被分配,所以我有空间设置一些静态 IP 地址。
所以,我在这里几次提到了静态 IP 地址。你可能已经知道这是什么意思,但重要的是要详细说明静态 IP 地址对服务器来说是一个很好的主意。这些地址是为某些服务器或节点保留的,您希望它们每次都有相同的 IP 地址。如果您以前配置过网络,这可能是显而易见的。还有一个重要的静态租约的概念。静态租约也称为预留。使用静态租约,IP 地址仍由 DHCP 服务器提供,客户端仍然使用 DHCP 请求地址。不同之处在于,客户端每次连接时都会收到相同的地址。
设置静态租约非常容易。预留可以放在您的/etc/dhcp/dhcpd.conf
文件的末尾。以下是一个示例,展示了语法的样子:
host bahamut {
hardware ethernet 28:B2:BD:05:1E:00;
fixed-address 10.10.97.4;
}
在这里,我们有一个名为bahamut
的主机,MAC 地址为28:B2:BD:05:1E:00
。这个名字是任意的;它除了让我们记住预留是为了哪个主机之外没有实际意义。它不必与请求 IP 的设备的主机名匹配。代码块中的两行只是表示每当网络卡连接到具有 MAC 地址28:B2:BD:05:1E:00
的 DHCP 服务器时,它需要提供 IP 地址10.10.97.4
。我们可以添加尽可能多的类似代码块,以便为我们希望分配的静态租约添加尽可能多的代码块。
也许你会想知道,何时应该使用静态 IP,何时应该使用静态租约?在我看来,只要有意义并符合您的网络设计,就可以使用静态租约。使用静态租约,您只需要在想要查看所有预留的概述时检查/etc/dhcp/dhcpd.conf
文件。此外,即使您重新安装操作系统或从活动安装映像引导主机,主机也将始终收到相同的 IP 地址。对于静态租约,您无需在主机上进行任何配置。通常,静态租约更容易管理。当然,您自己的偏好将超越这一点。
最后,为了使我们的 DHCP 服务器正常运行,必须启动并配置为在启动时运行。Debian 已经负责启用守护程序,因此您只需要重新启动它,以便我们的配置生效:
# systemctl restart isc-dhcp-server
对于 CentOS,我们需要手动启用和启动服务:
# systemctl enable dhcpd
# systemctl start dhcpd
正如你所看到的,配置 Linux 上的 DHCP 服务器非常容易和直接。当然,还有高级用法场景和大量的附加选项。但是对于大多数情况来说,像这里概述的这样的配置应该足够了。
安装和配置 DNS 服务器
域名系统(DNS)使得浏览网络资源变得更加容易。除非你有一个非常小的网络,否则你不太可能记得哪些 IP 地址属于哪些机器。DNS 通过将名称映射到 IP 地址来帮助你,这样你就可以通过主机名引用计算机,DNS 将负责将其翻译回 IP 地址。
DNS 是几乎每个连接到网络的设备都在使用的东西,无论用户是否意识到。计算机、服务器、智能手机、平板电脑、智能家电等都在使用 DNS。每当你在互联网上查找一个服务,比如一个网站或一个远程资源,DNS 会将资源的名称翻译成 IP 地址。
尽管 DNS 的概念和它为我们做的事情可能是常识,但它是那些容易被认为理所当然的东西之一。DNS 是那些在背后工作并让我们的生活变得更加容易的神秘事物之一。我们大多数人都在使用它,但很少有人真正理解它是如何工作的。每当你连接到一个互联网服务提供商(ISP)时,通常会分配给你一个或两个 DNS 服务器供你使用。一些聪明的用户通常会绕过 ISP 分配的 DNS 服务器,使用谷歌或 OpenDNS 等第三方服务器,以期望获得额外的性能。
DNS 在内部网络中也可以证明是有用的。大多数有超过一把工作站的公司都会设置 DNS,这是理所当然的。它使得浏览你的网络变得轻而易举。例如,更容易将你的本地彩色打印机称为hp-color-01
,而不是记住 IP 地址,比如10.19.89.40
。在这种情况下,添加打印机将会很容易。只需让你的操作系统按名称浏览它。你网络上的任何资源都可以被命名,为所有网络资源创建一个一致和可预测的命名方案是一个好主意。所以,让我们做到这一点。
与 CentOS 相比,基于 Debian 的发行版所需软件包的命名通常有所不同。在 Debian 中,你需要安装的软件包是bind9
。CentOS 简单地称其为bind
。如果你想知道的话,BIND代表伯克利互联网名称域(以它被开发的地方命名,即加州大学伯克利分校)。这是互联网上最流行的名称服务器,所以你肯定会想熟悉它。顺便说一句,如果你在 CentOS 系统上进行这个活动,我建议你安装bind-utils
。这给了我们dig
命令,对我们来说会很有用。
第一步是在服务器上安装所需的软件包,然后你只需要启动它并确保它被启用以在启动时运行。Debian 已经为我们启动了守护程序并启用了它。你可以用以下命令来确认:
# systemctl status bind9
CentOS 不会自动启动bind
守护程序,也不会为你启动它。如果你选择的是 CentOS 发行版,你需要执行以下命令来启用bind
并启动它:
# systemctl enable named
# systemctl start named
完成这一步后,你实际上拥有了一个工作的 DNS 服务器。当然,我们没有配置任何东西,所以我们的 DNS 服务器实际上并没有为我们做太多事情。但现在我们已经安装了它,我们可以向其中添加记录并构建我们的配置。
首先,让我们来看一下默认配置文件。Debian 将 bind 的默认配置文件存储在/etc/bind/named.conf
中。CentOS 将它们存储在/etc/named.conf
中(它没有自己的目录)。去看看这个文件,了解一下配置是如何工作的。我们将使用我们自己的配置文件,所以我建议你备份默认文件,然后我们将安装我们自己的文件。
首先,在我们发行版的默认目录中创建一个新的named.conf
文件(在 Debian 中是/etc/bind/named.conf
,在 CentOS 中是/etc/named.conf
)。无论你使用哪个发行版,我们都会使文件相同。如果这个文件已经有文本了,把它复制到一个备份中或清空它,因为接下来的两行是我们在这个文件中需要的唯一文本:
include "/etc/bind/named.conf.options";
include "/etc/bind/named.conf.local";
在这里,我们将包括两个额外的文件(我们很快将创建)。正如你所看到的,我们的named.conf
文件只是调用这些文件,不包含其他配置。这样,我们可以创建我们自己的标准位置来找到这些文件。/etc/bind
已经是 Debian 中的默认位置,但通过在 CentOS 中调用这个目录,我们可以强制它在同一个地方查找配置。但是在 CentOS 中,你需要创建/etc/bind
目录。命令如下:
# mkdir /etc/bind
接下来,让我们创建我们的/etc/bind/named.conf.options
文件并自定义它:
options {
forwarders {
8.8.8.8; 8.8.4.4;
};
};
在这里,我们正在创建一个选项块,其中夹在花括号之间的一些代码,然后包括另一组花括号,我们在其中标识了我们的转发地址。由于这个 DNS 服务器是用于在我们的内部网络中定位资源,转发器块告诉我们的 DNS 服务器在本地找不到它要找的东西时应该将请求发送到哪里。你的 DNS 服务器很可能在没有这个的情况下仍然可以正常工作,因为在大多数情况下它仍然会尝试链条下游的另一个 DNS 服务器。但是在这里设置转发器允许我们强制指定 DNS 查找应该去哪里,以防我们要查找的是外部的东西。在这个示例中,我使用了谷歌的公共 DNS 服务器。但你可以选择你自己的。一些额外的 DNS 服务器(通常更好)可以在www.opennicproject.org找到,这也是一个很好的选择,如果你担心隐私或跟踪的话。
我们的下一个文件是/etc/bind/named.conf.local
,其中包含以下代码:
zone "local.lan" IN {
type master; file "/etc/bind/net.local.lan";
};
zone "96.10.10.in-appr.arpa" {
type master; notify no; file "/etc/bind/revp.10.10.96";
};
zone "97.10.10.in-appr.arpa" {
type master; notify no; file "/etc/bind/revp.10.10.97";
};
zone "98.10.10.in-appr.arpa" {
type master; notify no; file "/etc/bind/revp.10.10.98";
};
zone "99.10.10.in-appr.arpa" {
type master; notify no; file "/etc/bind/revp.10.10.99";
};
在这个文件中,我们首先要确定我们的域名。在这里,我选择了local.lan
。由于这台服务器不是互联网上任何东西的权威,这个名字很合适。在这个块中,我们调用另一个文件/etc/bind/net.local.lan
。事实上,正如你所看到的,这里调用了几个文件(总共五个)。第一个是我们的主 DNS 区域,它是其中最重要的。其后的是我们配置反向 DNS 查找的地方。基本上,DNS 不仅允许我们将主机名映射到 IP 地址,还可以进行反向映射(将 IP 地址映射回主机名)。你可能不需要我在示例中创建的所有文件。对我来说,我为我的四个子网中的每一个创建了一个反向查找文件。如果你不创建多个子网,你只需要创建一个。这些文件的命名约定是revp
,后面跟着 IP 地址的网络部分。所以,例如,我的10.10.99.0
网络的反向查找文件是revp.10.10.99
。这些文件也将存储在/etc/bind
中。
现在,让我们来看看我们的主记录,/etc/bind/net.local.lan
文件:
;
; dns zone for for local.lan
;
$TTL 1D
@ IN SOA local.lan. hostmaster.local.lan. (
201507261 ; serial
8H ; refresh
4H ; retry
4W ; expire
1D ) ; minimum
IN A 10.10.96.1
;
@ IN NS hermes.local.lan.
ceres IN A 10.10.98.1
euphoria IN A 10.10.97.4
galaxy IN A 10.10.96.4
hermes IN A 10.10.96.1
puppet CNAME galaxy
;
; dns zone for for local.lan
;
首先,我放了一些通用的注释,以分号开头的行。如果一行以分号开头,它将被bind
忽略。注释可以是留下关于配置的注释或事实的好方法。然而,在bind
中注释并不经常使用。接下来,我们将我们的生存时间(TTL)设置为一天:
$TTL 1D
这个值决定其他 DNS 服务器能够缓存每个记录的时间有多长。在此期间,任何缓存了这些记录的服务器必须丢弃它们。为了设置内部 DNS 服务器,这个值对我们影响不大。但是,如果您设置了多个 DNS 服务器,这可能是一个重要的配置值。TTL 值可能会被证明有用的一个例子是将地址记录更改为不同的 IP 地址。假设您要将您的电子邮件主机切换到另一个提供商。在这种情况下,您将相应地更改地址记录。但在执行此更改之前,您可能会将 TTL 降低到更短的时间,比如一小时,然后再进行更改。然后,服务器被迫丢弃这个区域并刷新它,导致它更快地看到您更改的电子邮件提供商。完成后,您将把这个值改回来。在下一行,我们确定了一个权威起始(SOA):
@ IN SOA local.lan. hostmaster.local.lan. (
在这种情况下,我们确定了这个 DNS 服务器对local.lan
域有权限。我们还澄清了hostmaster.local.lan
对此负有责任。虽然看起来可能不像,但hostmaster.local.lan
实际上是一个按照 bind 的偏好格式的电子邮件地址。然而,这显然是一个假地址,对于我们的内部 DNS 服务器并不重要。在这一行的末尾,我们正在打开一个配置块,这里是一个开放括号。下一行代表我们的序列号,这是一个非常重要的概念,为了使我们的 DNS 服务器正常工作,必须理解。
201507261 ; serial
每次我们重新启动bind
守护程序时,它都会重新加载这个文件。但是当它这样做时,序列号是它首先查看的东西。如果它是相同的,它可能不会加载任何更改。因此,每次您在bind
中更改区域文件时,您也必须更改这个序列号。在这个例子中,当前日期被使用,没有连字符或空格。最后一位数字只是当天的修订号,如果文件在一天内被多次更改。您可以使用任何您喜欢的方案。但使用日期是一个非常流行的方法。无论您使用的格式是什么,都要确保您在每次更改时将序列号递增 1。这样您就不会因为新创建的记录没有生效而感到沮丧。
8H ; refresh
4H ; retry
4W ; expire
1D ) ; minimum
这些值决定了从属 DNS 服务器被告知多久检查更新。第一个值将配置从属服务器每八小时从主服务器(本服务器)刷新区域记录。关于重试,我们让从属服务器知道如果连接出现问题,要在这段时间内再次检查。最后,我们将区域记录的最小年龄设置为一天,最大年龄设置为四周。配置从属 DNS 服务器超出了本书的范围,但是在以后决定配置从属 DNS 服务器时,有这个配置也不会有任何坏处。
@ IN NS hermes.local.lan.
在这里,我们确定了这个名称服务器。在我的情况下,我称之为hermes
,它的完整域名是hermes.local.lan
。
galaxy IN A 10.10.96.4
hermes IN A 10.10.96.1
最后,在这个示例配置中,调用了四个地址记录。这基本上意味着每当有人寻找这些主机中的一个时,请求就会映射到列出的域名上。这些可以是多个子网中的一部分,也可以是单个子网中的一部分。在我的情况下,这些主机位于不同的子网上。
puppet CNAME galaxy
这个配置的最后一行包含一个规范名称(CNAME)记录。基本上,这允许我们用另一个名称引用一个服务器。在这个例子中,galaxy
也用于名为puppet
的软件,因此为它设置了一个 CNAME 记录。这样,如果有人试图访问galaxy.local.lan
或puppet.local.lan
,他们的请求将解析到相同的 IP 地址(10.10.96.4
)。如果单个服务器为网络提供多个服务,CNAME 记录可能非常有用。
之前,我提到了四个反向查找记录,/etc/bind/revp.10.10.96
,/etc/bind/revp.10.10.97
,/etc/bind/revp.10.10.98
和revp.10.10.99
。接下来,我将演示其中一个文件(在这种情况下,是为10.10.96.0
网络):
$TTL 1D
@ IN SOA hermes.local.lan. hostmaster.local.lan. (
201507261 ; serial
28800 ; refresh (8 hours)
14400 ; retry (4 hours)
2419200 ; expire (4 weeks)
86400 ; minimum (1 day)
)
;
@ NS hermes.local.lan.
1 PTR hermes.local.lan.
3 PTR nagios.local.lan.
4 PTR galaxy.local.lan.
通过这个配置,您会注意到我们有一个权威起始记录,就像我们的主区域一样,还有一个序列号。这里也适用相同的想法。每当您更新任何记录(包括反向查找记录)时,都应该更新文件的序列号。权威起始条目的工作方式与之前相同,没有什么意外。文件的不同之处在于如何调用主机。我们只需要识别最后一个八位字节,因为整个文件专门用于从10.10.96.0
网络进行反向 IP 地址查找。对于您的子网中的每个子网,您都需要创建一个类似的文件。在我们的示例配置中有四个子网,但您不需要那么多。这样提供示例是为了演示如何处理单独的子网,如果您需要的话。
配置完成后,可以随时重新启动 DNS 服务器上的 bind 服务并进行测试。我们可以使用systemctl
命令重新启动bind
,就像以前一样。
对于 Debian,请使用以下命令:
# systemctl restart bind9
对于 CentOS,请使用以下命令:
# systemctl restart named
我们可以通过dig
命令测试我们的 DNS 服务器。在 Debian 中,您应该已经安装了这个软件包。CentOS 需要安装bind-utils
软件包。dig
(域信息检索器)是一个实用程序,允许我们从 DNS 服务器请求信息。要尝试一下,请尝试使用内部主机名:
dig myhostname.local.lan
如果您的 DNS 服务器在输出中显示为SERVER
,则您的 DNS 服务器正常运行。如果由于某种原因没有显示,请验证您输入的内容、序列号以及您上次配置更改后是否重新启动了bind
。
随时练习在 DNS 服务器中设置额外的节点和记录。一开始设置bind
可能会让人沮丧,但坚持下去,您很快就会成为专家。使用本节中的示例,您应该有一个可以在您的环境中设置 DNS 服务器的工作框架。确保您将配置文件中包含的主机名和 IP 地址更改为与您的网络匹配的主机名和 IP 地址。此外,确保您设置bind
以匹配您的子网,或者如果没有其他子网,则删除其他子网的提及。为了安全起见,通常最好手动输入所有内容,而不是直接从本书复制配置。
设置内部 NTP 服务器
大多数 Linux 发行版都提供了一个网络时间协议(NTP)客户端,可用于保持本地时间的最新状态。其想法是,通过配置 NTP 客户端,您的计算机或服务器将定期与互联网上的 NTP 服务器进行同步,以确保其尽可能精确。这非常重要;如果时钟不准确,Linux 机器可能会发生非常奇怪的事情。这些奇怪的事情可能包括节点无法与 DHCP 服务器关联以获取 IP 地址,文件在文件服务器之间变得不同步等。故事的教训是:您需要在您的环境中设置并使 NTP 正常工作。
许多面向最终用户工作站的 Linux 发行版(如 Ubuntu、Linux Mint 等)通常会为您设置 NTP 客户端。这意味着开箱即用,您的时钟很可能已经同步,当然前提是您的安装可以访问互联网。默认情况下,这些客户端将连接到特定于发行版的 NTP 服务器。这可能完全没问题,但是设置自己的 NTP 服务器也是有价值的。其中一个很好的理由是,通过设置自己的 NTP 服务器,您正在成为一个良好的网络公民。想想看。如果您有一家拥有一百台 Linux 机器的公司,如果保持默认配置,每台机器都会定期与公共 NTP 服务器进行通信。这会给服务器造成不必要的压力。如果您设置自己的 NTP 服务器,只有一个服务器会与公共服务器进行通信,这意味着您会消耗更少的资源。此外,出于安全原因,一些公司不允许公共访问端口 123(NTP 使用的端口)。然而,也许允许一个单独的 NTP 服务器访问端口 123,然后您可以配置您的客户端连接并使用 NTP。
在设置 NTP 服务器之前,重要的是要注意,Debian 和 CentOS 通常可以成为默认安装 NTP 客户端的例外情况。根据您在安装过程中选择的选项和软件包,NTP 客户端可能已经可用,也可能尚未可用。在我的测试环境中,当我分别通过最小安装和网络安装安装时,CentOS 和 Debian 默认情况下都没有一个可用的 NTP 客户端。然而,设置 NTP 客户端非常容易。您只需安装 NTP 并启用它。这实际上是 Debian 和 CentOS 具有相同软件包相同名称的罕见情况之一。该软件包简单地称为ntp
,因此如果您尚未安装,请安装它。安装后,Debian 将启动ntp
守护程序并为您启用它。对于 CentOS,请执行以下命令以启动它:
# systemctl enable ntpd
# systemctl start ntpd
使用这两个发行版,一旦安装了软件包,文件/etc/ntp.conf
将被创建,并且该文件将具有一个默认配置,该配置将指向您的发行版的 NTP 服务器。如果您对它的外观感到好奇,可以随意快速查看一下这个文件。要查看您的机器正在与哪个服务器同步,以及关于其同步的一些统计信息,请执行ntpq -p
命令。
查看连接的 NTP 服务器
首先,让我们快速看一下这些数字的含义。第一列remote
包括我们连接的 NTP 服务器的列表,没有什么意外。接下来是refid
,表示这些服务器连接到的地方。st
列是指该服务器的层,这是一个指示该时间服务器所在层的数字。通常,数字越低,它就越好;因为这意味着该服务器与提供时间的源相当接近。链条下的每个服务器都有一个增加的层;最低并不总是意味着服务器更好,但一般来说,较低的数字是好的。t
列是指类型。这可以是单播、广播、组播或多播。在这种情况下,我们使用u
表示单播。
when
列指的是服务器上次轮询的时间。在示例截图中,每个服务器分别在 28、24、21 和 61 秒前轮询。这也可以列出小时或天。poll
列指的是轮询频率,这里设置为每 64 秒轮询一次。reach
列是一个八进制数,其中包含最近八次 NTP 更新的结果。如果所有八次都成功,这个值将读取 377,这是它能达到的最高值。这意味着所有八次尝试都收到了 1(成功),在八进制中,总共是 377。
最后,delay
字段指的是到 NTP 服务器的延迟(以毫秒为单位)。offset
字段对应于本地时钟和服务器时钟之间的差异。最后,jitter
指的是您和服务器之间的网络延迟。
要设置 NTP 服务器,您必须首先安装客户端,就像本章前面提到的那样。安装它,配置守护程序自动启动,然后启动它。执行这些任务后,您已经完成了大部分工作(服务器和客户端使用相同的客户端)。基本上,如果您将其他计算机指向安装和配置了 NTP 的服务器,您基本上已经拥有了所需的一切。
然而,有一些东西应该首先配置。主要是/etc/ntp.conf
配置文件。该文件在 Debian 和 CentOS 上的位置相同。如果您查看文件,您会看到一些类似以下的行:
server 0.centos.pool.ntp.org iburst
server 1.centos.pool.ntp.org iburst
server 2.centos.pool.ntp.org iburst
server 3.centos.pool.ntp.org iburst
在这里,您可以看到,默认情况下,CentOS 标识了四个 NTP 服务器进行同步。对于大多数用例来说,这些服务器通常都很好,但您可能希望考虑官方的 NTP 服务器。要这样做,请查看以下网站:
该网站将允许您查看 NTP Pool Project 的官方 NTP 服务器。要导航,请在右侧选择您的大陆,然后选择您的国家。然后,您应该看到一个可以使用的 NTP 服务器列表。在我的情况下,我得到以下细节:
server 0.north-america.pool.ntp.org
server 1.north-america.pool.ntp.org
server 2.north-america.pool.ntp.org
server 3.north-america.pool.ntp.org
您可以选择使用发行版提供的 NTP 服务器,也可以选择使用 NTP 池项目提供的 NTP 服务器。就我个人而言,我更喜欢后者。一旦您配置了服务器,我们应该进行一次更改。您应该在 CentOS 的配置中看到类似以下的行:
#restrict 192.168.1.0 mask 255.255.255.0 nomodify notrap
在 Debian 中类似于以下内容:
#restrict 192.168.123.0 mask 255.255.255.0 notrust
在您的 NTP 服务器上,取消注释该行,并将网络地址更改为您的地址,以及子网。如果有notrust
,请删除它。作为参考,我的配置中的该行如下:
restrict 10.10.96.0 mask 255.255.252.0 nomodify notrap
有了这个配置,我们限制了 NTP 访问本地客户端,并确保它们无法访问 NTP 服务器的配置(只能从中读取)。我在 NTP 中喜欢做的另一个更改是指定一个日志文件。systemd 通过journalctl
负责记录,但有时在出现问题时查看文本文件也很有用。如果您需要,可以在顶部附近添加以下行:
logfile /var/log/ntp.log
如果您遇到任何问题,请检查该文件。接下来,如果您将 CentOS 用作 NTP 服务器,则应通过其防火墙启用 NTP 流量。要做到这一点,请运行以下代码:
firewall-cmd --add-service=ntp –permanent
firewall-cmd --reload
现在我们已经完成了,重新启动您的 NTP 服务器。我们可以通过以下命令之一来执行(作为 root)。
在 CentOS 上使用systemctl restart ntpd
命令,或在 Debian 上使用systemctl restart ntp
。
在这一点上,您已经有了一个 NTP 服务器。在您的客户端上,将它们配置为与您指定为 NTP 服务器的机器的 IP 同步。在我的情况下,命令如下:
server 10.10.99.133
重新启动 NTP 后,让您的系统一些时间进行同步。在某些情况下,可能需要半个小时以上才能开始同步。给它一些时间,然后检查您的配置,确保它正在使用ntpq -p
命令进行同步。
与自定义 NTP 服务器同步的机器输出
在我的测试环境输出中,您可以看到,我在10.10.99.123
上启动了一个 NTP 服务器,这台 Debian 机器正在与之同步,目前服务器的可达性为7
,但这个数字正在慢慢上升。这很正常,因为服务器只运行了几分钟。
如果您遇到任何问题,请确保在您的网络中打开端口 123(如果服务器是 CentOS,请确保您已运行之前提到的防火墙命令)。但在您感到沮丧之前,请给它一些时间——当第一次设置时,NTP 服务器需要一些时间才能启动是很常见的。通常,一切应该在 20 分钟内开始运行,但我曾经见过更长时间。
总结
在本章中,我们配置了网络的布局。我们首先讨论了规划网络 IP 地址布局,然后通过创建自己的 DHCP 服务器来付诸实施。这次讨论包括如何将此配置分成多个子网,而不是多个子网。我们继续设置 DNS 服务器,以便通过名称解析我们的网络节点。最后,我们通过设置 NTP 服务器来结束本章,以确保我们的所有节点都具有正确的时间。
在下一章中,我们将探讨使用 Apache 托管网页内容。
第七章:通过 Apache 托管 HTTP 内容
Apache是互联网上最常用的 Web 服务器。虽然还有其他可用的 Web 服务器,比如微软的Internet Information Services(IIS),但在提供 Web 内容方面,Apache 占据着统治地位。Apache 在 Linux 和 UNIX 平台上都可用,使您能够托管内容并在本地局域网以及互联网上共享。Apache 服务器有许多用途,包括(但不限于)托管博客或公司网站,或为您的公司设置员工门户网站。
在本章中,您将学习有关安装和配置 Apache 的所有内容。我们将涵盖以下主题:
-
安装 Apache
-
配置 Apache
-
添加模块
-
设置虚拟主机
安装 Apache
像往常一样,在系统上安装 Apache 只是从软件包管理器中安装适当的软件包。在 CentOS 系统上,您可以通过安装httpd
软件包获取 Apache,在 Debian 系统上则是apache2
软件包(分别作为 root 执行yum install httpd
或apt-get install apache2
)。安装软件包后,Apache 的守护程序现在已经存在,并带有一组默认的配置文件。您可以使用systemctl
确认守护程序在您的系统上的存在,尽管守护程序的名称根据您的发行版而有所不同。
在 Debian 上使用以下命令:
# systemctl status apache2
在 CentOS 上使用以下命令:
# systemctl status httpd
默认情况下,Debian 会为您启动和启用守护程序。与此相反,CentOS 不会做任何假设。您可以使用systemctl
命令轻松启动和启用守护程序:
# systemctl enable httpd
# systemctl start httpd
安装和启用 Apache 后,您在网络上已经有了一个工作的 Web 服务器。它可能并不特别有用(因为我们还没有配置它),但在这一点上它是存在的,而且在技术上是工作的。CentOS 和 Debian 版本的 Apache 都在同一个目录/var/www/html
中寻找 Web 内容。在那里,Debian 创建了一个样本网页,以index.html
文件的形式存在,您可以通过另一台计算机上的 Web 浏览器查看(只需将其指向您的 Web 服务器的 IP 地址)。另一方面,CentOS 并没有为您创建一个样本 HTML 页面。这很容易纠正;您只需要手动创建/var/www/html/index.html
文件,并放入一些样本代码。它不需要很豪华;我们只是想确保我们有一些东西可以测试。例如,您可以在该文件中放入以下代码:
<html>
<title>Apache test</title>
<body>
<p>Apache is awesome!</p>
</body>
</html>
此时,您应该已经安装了 Apache 并启动了其服务。您的系统上应该有一个示例的/var/www/html/index.html
文件,无论您是使用 Debian 的默认设置还是在 CentOS 系统上手动创建的。现在,您应该能够通过 Web 浏览器浏览到您的 Web 服务器并查看此页面。如果您知道您的 Web 服务器的 IP 地址,只需在 Web 浏览器的地址栏中输入即可。您应该立即看到示例页面。如果您在 Web 服务器上使用 Web 浏览器,您应该能够浏览到本地主机(http://127.0.0.1
或http://localhost
)并查看相同的页面。
注意
如果您选择了 CentOS 作为您的 Web 服务器,那么默认防火墙可能会妨碍您从另一台机器上浏览到它。根据您的配置,您可能需要通过防火墙允许流量到您的 Web 服务器。要做到这一点,执行以下命令:
# firewall-cmd --zone=public --add-port=80/tcp --permanent
# firewall-cmd --reload
一定要添加端口 443,如果您计划托管一个安全的网站。只需使用与之前相同的firewall-cmd
,但用 443 替换 80。
如果出于某种原因您看不到默认页面,请确保 Apache 正在运行(记住我之前提到的systemctl status
命令)。如果守护程序没有运行,您可能会收到连接被拒绝的错误。另外,请记住,基于硬件的防火墙也可能阻止访问。
从 Debian 上运行的未配置 Apache 提供的默认网页
另一种测试服务器是否提供网页的方法是通过lynx
,这是一个文本化的网页浏览器,您可以在 shell 中使用。在某些情况下,这可能是首选,因为它没有图形网页浏览器的开销,并且启动非常快。一旦在您的机器上安装了 lynx 软件包,您可以通过执行lynx http://localhost
或http://<ip 地址>
从不同的机器访问来自服务器的网站。
使用 lynx 测试 web 服务器功能
注意
要退出lynx
,按Q退出,然后按Y确认退出。
正如我所提到的,Debian 和 CentOS 都在同一个目录中查找要通过 Apache 共享的文件。这个目录是/var/www/html
。为了创建一个网站,您需要将网站的文件放入这个目录。设置 Apache 服务器的典型过程是先安装 Apache,然后测试它是否可以被网络上的其他计算机访问,最后开发您的网站并将其文件放入这个文件夹。
配置 Apache
配置 Apache 是通过编辑其配置文件来完成的,这将位于两个位置中的一个,具体取决于您的发行版。
在 CentOS 上使用以下命令:
/etc/httpd/conf/httpd.conf
在 Debian 上使用以下命令:
/etc/apache/apache2.conf
默认的网页文档目录/var/www/html
可以更改。虽然/var/www/html
是相当标准的,但如果您决定将网页文件存储在其他地方,也没有什么阻止您更改它。如果您查看 CentOS 中的配置文件,您将看到这个目录在从第 131 行开始的一个配置块中被调用。如果您查看 Debian 中的配置文件,您根本看不到这个调用。相反,您将在/etc/apache2
中看到一个名为sites-available
的目录。在该目录中,将有两个默认文件,000-default.conf
和default-ssl.conf
。这两个文件都将/var/www/html
指定为默认路径,但它们的区别在于000-default.conf
文件指定了端口 80 的配置,而default-ssl.conf
负责端口 443 的配置。您可能知道,端口 80 是标准的 HTTP 流量,而端口 443 对应于安全流量。因此,每种类型的流量在 Debian 系统上都有自己的配置文件。
在所有这些情况下,文档根目录都被设置为/var/www/html
。如果您想将其更改为其他目录,您需要更改代码以指向新目录。例如,如果您想将路径更改为/srv/html
之类的内容,您需要对文件进行一些更改。
首先,查找以下行:
DocumentRoot /var/www/html
将其更改为指向新目录:
DocumentRoot /srv/html
在我的测试系统上,我在 Debian 的以下配置文件中找到了DocumentRoot
的调用:
/etc/apache2/sites-available/000-default
在 CentOS 上,我发现在默认配置文件的第 119 行:
/etc/httpd/conf/httpd.conf
更改后,我们必须为新目录设置选项。在 Debian 上,我们需要在以下文件中进行这些更改:
/etc/apache2/apache2.conf
在 CentOS 上,我们需要在以下文件中进行这些更改:
/etc/httpd/conf/httpd.conf
打开其中一个文件,具体取决于您使用的发行版。我们需要更改的代码看起来像这样:
<Directory "/var/www/html">
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
相应地更改以下内容:
<Directory "/srv/html">
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
注意
在前面的示例中,代码中可能夹杂着一些注释,但基本思想是一样的。找到以<Directory "/var/www/html">
开头的行,并确保该块中的未注释代码与示例匹配。只要你这样做,你就应该没问题。
最后,可能不用说,但为了避免麻烦,您应该确保已将权限设置为/srv/html
,使得该目录和内容对所有人可读。还要确保您已经创建或复制了一个示例 HTML 文件(例如index.html
)到该目录中。一旦重新启动 Apache,您应该能够从这个新目录提供网络内容。
除了设置文档根目录外,Apache 配置文件还允许您配置一些非常重要的安全设置。例如,默认情况下禁用对服务器文件系统的访问。这是一件好事。以下代码是从 CentOS 系统中提取的示例,它负责防止整个文件系统的访问。代码如下:
<Directory />
AllowOverride none
Require all denied
</Directory>
默认情况下,通过以下配置块禁用了远程查看.htaccess
文件:
<Files ".ht*">
Require all denied
</Files>
还可以设置其他选项,例如 Apache 日志文件的默认位置。默认情况下,以下默认配置行将日志文件指向/etc/httpd/logs
:
ErrorLog "logs/error_log"
然而,这可能会误导,因为在 CentOS 系统上,/etc/httpd/logs
目录实际上是一个符号链接到/var/log/httpd
,这才是您实际上可以找到日志文件的地方。默认情况下,日志记录设置为warn
,这也可以在 Apache 配置文件中更改,并设置为debug
、info
、notice
、warn
、error
和crit
中的任何一个。
需要注意的是,对于您对 Apache 所做的任何更改,您都需要重新加载或重新启动守护程序。如果重新启动守护程序,它将关闭 Apache 并重新启动。重新加载只是导致 Apache 重新读取其配置文件。在大多数情况下,重新加载是更好的选择。通过这样做,您可以应用新的配置而不会中断对您网站的访问。与大多数 systemd 单元一样,Apache 使用以下命令来管理守护程序的运行状态:
- 使用以下命令启动 Apache 守护程序:
# systemctl start apache2
- 使用以下命令停止 Apache 守护程序:
# systemctl stop apache2
- 使用以下命令在启动时启用 Apache 守护程序:
# systemctl enable apache2
- 在尝试保持其运行状态的同时重新加载 Apache 守护程序:
# systemctl reload apache2
- 使用以下命令重新启动 Apache 守护程序:
# systemctl restart apache2
如果您使用的是 CentOS,请在每种情况下将apache2
替换为httpd
。现在您已经了解了 Apache 的安装和配置方式,我们可以继续使用模块。
添加模块
尽管 Apache 开箱即用非常有用,但您可能需要的一些功能并不是内置的。Apache 使用模块来扩展其功能集。例如,安装php5
模块以使您的站点能够使用 PHP,或者如果您使用 Python 开发,则可能需要 Python 模块。一旦安装并激活了模块,该模块的功能将对您可用。
CentOS 和 Debian 之间的 Apache 实现是不同的,它们之间添加模块的方式也是不同的。事实上,Debian 甚至包括了其专门用于启用和禁用模块的命令,这完全是 Debian 系统的专属。这些命令是a2enmod
和a2dismod
。
要通过 Debian 启用模块的典型过程,我们可以在服务器上启用 PHP 模块。我还将详细介绍 CentOS 中的这个过程,但是正如我提到的,这个过程在这两者之间完全不同。
首先,找到包含您想要的模块的软件包。如果您不知道要安装的软件包的确切名称,可以使用以下命令将可用的 Apache 模块列表打印到终端:
aptitude search libapache2-mod
默认情况下,大多数 Debian 系统上都没有安装aptitude
。如果上一个命令导致command not found error
,您只需要通过apt-get install
安装aptitude
软件包。输出可能会太长,取决于您的终端窗口的大小,因此您可能需要将输出导入less
:
aptitude search libapache2-mod |less
以下屏幕截图显示了在 Debian 系统上使用 aptitude 搜索libapache2-mod
时的搜索结果:
在 Debian 系统中,有相当多的 Apache 模块可用。
通过这种方式搜索,您可以按Enter
或上下箭头键滚动输出,然后在完成时按Q。通过查看输出,您会发现 PHP 包的名称是libapache2-mod-php5
。因此,让我们使用以下命令安装它:
# apt-get install libapache2-mod-php5
安装完包后,检查输出。很可能 Debian 已经为您安装了模块,逻辑是如果您明确要求安装一个包,您可能希望立即使用它。如果您看到类似以下的输出,则此示例中的 PHP 模块已经安装:
apache2_invoke: Enable module php5
您可以尝试启用它来验证这一点,通过在 shell 中执行a2enmod php5
。如果启用了,您将看到类似以下的输出:
Module php5 already enabled
实质上,a2enmod
和a2dismod
命令的工作方式基本相同。您可能已经了解,一个是启用模块,另一个是禁用模块。要使用 Apache 模块,必须启用它。但是,如果您不再需要某个模块,可以禁用它(或者更好的做法是删除它)。查看所有模块及其提供的功能超出了本书的范围。但在实践中,您只会启用站点所需的模块,这在不同的环境中会有所不同。在我们继续在 CentOS 系统上执行相同的过程之前,我给您留下这个提示。要查看在 Debian 系统上安装的所有模块的列表,请发出以下命令:
# apache2ctl -M
现在,让我们转到 CentOS。大多数模块可以通过使用包管理器列出可用的模块包,类似于我们在 Debian 部分之前所做的方式。在 CentOS 中,我们可以通过以下命令来实现:
yum search mod_
很遗憾,PHP 模块在这个输出中没有列出。这是因为我们在 CentOS 中通过简单安装php
包来启用 PHP。这就是事情开始变得混乱的地方;相当多的 CentOS Apache 模块包都遵循以mod_
开头的命名约定,但并非所有模块都是这样。有时需要进行一些研究来确定需要安装哪些包以授予系统对模块的访问权限。如果您在开发网站时需要其他模块,比如用于 LDAP 认证的mod_ldap
,也可以随意安装。
与 Debian 不同,yum
包管理器应该已经为您启用了安装的模块。现在我们在 CentOS 系统中安装了 PHP,一旦重新启动httpd
守护程序,我们应该可以使用 PHP。要验证这一点,我们应该能够创建一个info.php
文件并将其存储在/var/www/html/info.php
中。文件的内容如下:
<?php phpinfo();
?>
如果您导航到 URL http://<your_server_IP>/info.php
,您应该看到包含有关服务器 PHP 实现的信息的页面。
在 Apache 服务器上查看 PHP 服务器信息
注意
虽然使用info.php
文件来测试 PHP 是完全可以的,但不要将其留在服务器上——这是一个安全风险。您不希望使攻击者轻而易举地确定有关服务器正在运行的具体信息。这个过程只是为了测试 PHP 是否正常运行。
现在我们已经介绍了安装 Apache 模块,您应该可以轻松地根据需要定制您的 Web 服务器,以支持您计划运行的任何网站或应用程序。
设置虚拟主机
一个组织托管多个站点是非常常见的。这些站点可以存在于自己的服务器或虚拟机上,但这并不是非常实际的。每台服务器只运行一个站点非常昂贵且效率不高。虚拟主机的概念是多个站点可以存在于一个 Web 服务器上,这样可以节省基础设施。当然,可能会有一个网站产生了大量流量,与其他高流量站点共享可能不是一个好主意,但在这种情况下,推荐使用虚拟主机。
如前所述,/var/www
是 Apache 查找要提供的文件的默认位置。如果您在一台服务器上托管多个站点,您会希望为每个站点创建一个单独的目录。例如,如果您为名为tryadtech.com
和linuxpros.com
的公司托管网站,您可以创建以下目录结构:
/var/www/tryadtech.com/html
/var/www/linuxpros.com/html
在这个例子中,我创建了几层深的目录,所以您可以使用mkdir
命令的-p
标志来创建这些目录及其父目录。
这样,每个站点都有自己的目录,这样可以保持它们的内容分开。每个人都需要读取这些文件,因此我们需要调整权限:
# chmod 755 -R /var/www/<nameofsite>
要创建虚拟主机,我们需要从中创建一个配置文件。在 Debian 上,有一个默认配置文件可以作为起点使用(我将在下一节详细介绍我使用的配置,因此不需要使用此文件)。如果您愿意,可以从以下文件开始:
/etc/apache2/sites-available/000-default.conf
这个文件可以作为创建虚拟主机配置的良好参考点。如果您选择使用它,请将其复制到为虚拟主机创建的目录中:
# cp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/tryadtech.com.conf
在 CentOS 上,/etc/apache2/sites-available
目录甚至不存在,所以请创建它。为了告诉 Apache 从这个目录加载站点,我们需要在/etc/httpd/conf/httpd.conf
文件的底部添加以下行:
IncludeOptional sites-available/*.conf
现在,这是一个虚拟主机配置文件的示例。我在我的 Debian 测试系统上将其保存为/etc/apache2/sites-available/tryadtech.com.conf
,但在 CentOS 上,只需将apache2
替换为httpd
。我从之前提到的000-default.conf
文件中取了这个示例文件,为了简洁起见删除了注释行。第一行是原始文件中没有的,第二行被修改了:
<VirtualHost *:80>
ServerAdmin webmaster@localhost
ServerName tryadtech.com
DocumentRoot /var/www/tryadtech.com/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
正如您在这里看到的,我们在tryadtech.com
目录下调用了一个html
目录。为了开发您的站点,您可以将站点文件放入html
目录中,在重新启动 Apache 之后,您应该能够从 Web 浏览器访问该目录。
那么,Apache 服务器如何知道将访问者发送到哪个目录呢?注意我添加到配置文件的ServerName
行。在这一行中,我指定了这个虚拟主机中的文件所属的特定域名。这要求您已经设置并指向了这个 IP 的 DNS。例如,您在域名注册商处的 DNS 条目将把这两个虚拟主机中的每一个指向同一个 IP 地址。当通过tryadtech.com
域名发出请求时,Apache 应该从/var/www/tryadtech.com/html
目录中为用户提供文件。如果您配置了另一个虚拟主机和域名,对该域名也将适用相同的规则。
总结
在本章中,我们设置了一个 Apache 服务器,可以用来在本地内部网络上共享信息,甚至在我们的机器可以外部路由时也可以用于互联网。我们介绍了安装 Apache,自定义它,设置模块,以及设置虚拟主机。
在下一章中,我们将介绍高级网络技术,如子网划分,向 DHCP 和 DNS 添加冗余性以及路由。到时见!
第八章:理解高级网络概念
到目前为止,我们在 Linux 网络管理方面已经覆盖了从规划、设置文件服务器、网络服务等方面的所有内容。现在,当我们接近本书的结尾时,最后几章将通过关于高级网络、安全性甚至故障排除的信息来完善这些知识。在本章中,我们将介绍一些更高级的概念,例如子网划分、路由等!
在本章中,我们将涵盖:
-
将您的网络划分为子网
-
理解 CIDR 表示法
-
实施服务质量(QoS)
-
理解网络地址转换(NAT)
-
路由 TCP/IP 流量
-
创建冗余的 DHCP 和 DNS 服务器
-
配置网络网关
将您的网络划分为子网
除非您运行的是非常小的家庭或办公网络,否则进行子网划分通常是一个好主意。子网划分允许您将网络分割成更小的部分,每个部分都有自己的 IP 地址和资源。例如,可以将无线流量、服务器、工作站和公司发放的移动设备放在各自的子网上。此外,如果您的网络上有任何特定服务接收最多的流量,您也可以将该服务放在自己的子网上。有无限的可能性,每个管理员都会有自己关于最佳网络划分方式的想法。
在第六章中,配置网络服务,我们设置了一个 DHCP 服务器。在其中,我包括了一个使用特定子网动态租用 IP 地址的示例。在该方案中,我们使用的网络是10.10.96.0/22
。这意味着我们可以使用几个网络,包括10.10.96.0
,10.10.97.0
,10.10.98.0
和10.10.99.0
。有了这个网络,我们基本上可以将每个服务划分到自己的网络中。在我们的配置中,10.10.99.0
用于 DHCP。但是,如果您决定这样做,当然可以使用 IP 地址10.10.96.1
到10.10.99.254
。您如何配置您的网络完全取决于您。在该章节中,我们设置了一些将在本章中使用的基础工作。但我们没有讨论如何得出这些数字,或者如何手动分割网络。
子网划分的魔力完全在于子网掩码,尽管大多数人只是匆匆一瞥。对于相当多的网络,子网掩码保持默认值(255.255.255.0
),没有人真正质疑它。如果您从商店购买路由器并在未配置的情况下投入生产(这是个坏主意),您将得到一个 24 位网络和255.255.255.0
子网掩码。但这实际上意味着什么呢?
有两种不同的子网风格,有类和无类。在生产网络中,几乎没有人再提到实际的类,因为现在的子网划分是以无类进行的(稍后详细介绍)。但在我们深入讨论无类网络之前,了解之前的内容是很重要的。在我们讨论子网划分时,我们多次使用了子网掩码255.255.255.0
的示例,这属于被认为是 C 类网络的子网掩码。总共有五个类,A 类到 E 类。D 类和 E 类用途不大,所以我们将坚持使用 A 类到 C 类来讨论有类 IP 地址。
A 到 C 类的子网掩码如下:
类 | 子网掩码 |
---|---|
A | 255.0.0.0 |
B | 255.255.0.0 |
C | 255.255.255.0 |
这些子网掩码对应于 IP 地址的哪一部分被指定为网络,哪一部分被指定为每个单独的节点。例如,假设我们配置了一个网络地址为192.168.50.0
的 C 类网络。这意味着我们的网络有一个子网掩码为255.255.255.0
。与所有 IPv4 IP 地址一样,我们的网络地址有四个八位组:192
,168
,50
和0
。为了说明子网掩码如何影响 IP 地址,我将每个八位组排成一张表:
192 | 168 | 50 | 0 |
---|---|---|---|
255 | 255 | 255 | 0 |
子网掩码的目的是掩盖IPv4 地址的哪些八位组对应于整个网络,哪些对应于单个节点。每个八位组中可能的最大数字是255
。如果子网掩码中的一个八位组设置为255
,那么它将占据整个八位组,因此将其取消。在这种情况下,每个节点的 IP 地址将以192.168.50
开头,因为前三个八位组被取消了。请注意,网络地址和子网掩码的最后一个八位组都是零。在 IPv4 网络中,0
表示任何内容。因此,子网掩码的最后一个八位组为0
告诉我们它不关心该八位组,而网络地址为0
表示它也不关心。因此,最后一位的任何数字都是可以的。
在我们的情况下,从192.168.50.0
到192.168.50.255
的 IP 地址属于这个网络(子网)。嗯,几乎是。如果我们的子网掩码是255.255.255.0
,我们就不能以分配192.168.50.0
IP 地址开始我们的 DHCP IP 范围。这是因为子网的第一个 IP 地址不能分配给节点。第一个 IP 地址被指定为网络标识符并被保留。在一个 C 类网络中,IP 地址192.168.50.0
是无效的,因为它确实是该子网中的第一个地址。
另一个不能分配给任何节点的 IP 地址是子网的最后一个 IP。在我们的 C 类示例中,那将是192.168.255.255
。这个 IP 地址被称为广播地址,也是保留的。如果需要向整个网络发送广播消息,就会使用广播地址。考虑到这一点,在我们的示例中使用的 C 类网络中,我们的 DHCP 范围的最大值是192.168.50.1
到192.168.50.254
。
你可能想知道广播地址的目的。如前所述,它允许将数据包发送到整个网络。在实践中,网络服务,如 DHCP,利用广播。当你第一次将计算机插入以太网电缆(一个没有静态 IP 的计算机),它会发送一个广播消息请求 IP 地址。在连接之前,它不知道你的 DHCP 服务器的 IP 地址是什么。它可能是192.168.1.1
,甚至是192.168.1.100
。它完全不知道。通过发送广播消息,负责 DHCP 的任何服务器都应该能够听到请求并做出响应。
那么,为什么在上面的例子中选择了 IP 地址192.168.50.0
?那个数字只是随机选择的,以便说明子网掩码如何影响可用的 IP 地址。我们可以使用172.16.254.0
作为我们的网络地址,并且使用 C 类子网掩码255.255.255.0
,这仍然会给我们相同数量的可用 IP 地址(254)。在第二个例子中,我们仍然声明了一个 C 类网络,但只是使用了不同的 IP 方案。由于你正在管理一个内部网络,你可以选择任何你想要的编号系统。只要你的 IP 地址不是公共可路由的,只要你不在任何八位组中使用大于 255 的数字,或者在网络中使用第一个或最后一个 IP 地址,那么你可以使用任何数字。还有一些其他 IP 地址我们不能使用,但我们稍后会讨论。
为了更好地理解这是如何工作的,我们需要重新讨论子网掩码。如前所述,子网掩码有助于确定 IP 地址方案的哪一部分属于各个节点,哪一部分属于网络本身。可以这样理解。子网掩码中的 255 是子网掩码或 IP 地址中任何八位中可能的最大数字。子网掩码中的每个 255 代表一个不会改变的数字。因此,如果您有一个 IP 地址10.19.100.24
和一个子网掩码255.255.255.0
,您可以立即知道这个网络的前三个八位永远不会改变。这意味着该子网的每个主机都将具有以10.19.100
开头的 IP 地址。如果子网掩码是255.255.0.0
,将有更多的 IP 地址可用,因为最后两个八位是可用的。这实际上将给我们提供 65,534 个 IP 地址。前者只允许我们使用 254 个 IP 地址,因为最后一个八位是唯一可以改变的,其最大数字是 255(减去一个广播地址)。
但您可能已经注意到,我使用了一个 Class A IP 地址的例子(10.19.100.24
),但我使用了一个 Class C 子网掩码(255.255.255.0
)。这是有效的吗?当然!尽管通常约定的类结构,子网掩码的唯一目的是帮助您理解哪一部分是主机,哪一部分是节点。因此,255.255.0.0
和255.255.255.0
的子网掩码对于这个网络都是有效的。
然而,一些 IP 地址并不被认为是适用于各个类别的有效地址。虽然具有子网掩码为255.255.255.0
的内部 IP 网络253.221.96.0
符合所有这些规则,但它并不被认为是 Class C 网络的有效地址。如果您只在网络内管理 IP 地址,它可能有效,也可能无效。因此,对于经典风格中的每个类别,都有一个推荐的方案可供选择。我将在下表中说明:
类别 | 起始 IP | 结束 IP |
---|---|---|
A | 0.0.0.0 | 127.255.255.255 |
B | 128.0.0.0 | 191.255.255.255 |
C | 192.0.0.0 | 223.255.255.255 |
注意
与所有网络相关的事物一样,这里也有一个需要牢记的例外,您不能将127.0.0.0
或127.0.0.1
分配给任何东西,因为这是指您的本地环回适配器。
事实上,使用以10
开头的 IP 地址范围在 Class A 方案中是非常常见的,这就是我们在本书早期设置 DHCP 服务器时所做的。在那个例子中,我们使用了10.10.96.0
网络。但是如果您回忆起来,我们没有使用 Class C 子网掩码255.255.255.0
,而是使用了255.255.252.0
。这个区别将直接引导我们进入下一个主题 CIDR。
理解 CIDR 表示法
正如我之前提到的,经典子网划分的概念现在并不经常使用。经典子网划分的主要用途是网络设备(如路由器)的默认配置,以及大多数 DHCP 服务器的默认设置。在家用路由器的情况下,DHCP 服务器通常是内置的,默认方案通常是 Class C 网络(通常为192.168.1.0
,中间有几个变化)。但对于大多数设备,家庭或企业,如果您不将其更改为其他内容,您可能会得到一个 Class C IP 方案。在小型网络中,这些默认设置并没有什么问题,但是几乎没有人在配置网络时使用经典风格。原因是经典网络太过限制;在复杂的网络部署中,强迫您的网络计划适应这些预定方案可能会很麻烦。
在有类别的方案中缺乏灵活性的答案是无类别域间路由(CIDR)。使用 CIDR,我们基本上抛弃了类 A、B 和 C 子网掩码的限制。相反,我们使用二进制系统来确定如何划分我们的网络。因此,我们不再仅使用三种不同的子网掩码,我们可以借用位并更灵活地改变子网掩码以划分网络。
要理解这个概念,首先要理解位的概念。子网掩码中的每个八位组包含八位。每一位都是1
或0
(二进制)。此外,这八位中的每一位都有一个值。为了说明这一点,拿数字255
来说。这是任何八位组的最大值。用二进制写,255
是11111111
。因此,一个类 C 子网掩码255.255.255.0
用二进制写就是11111111.11111111.11111111.00000000
。
为了更容易理解,看看下表,我在其中概述了四个插座(255
)之一,并以二进制形式显示出来。在这个表中,顶部行给出了每个位的点值。你可以看到最右边的位只值1
,而最左边的位值为128
。底部的任何位是1
都会被加起来。在这种情况下,每个位都是1
(因为255
是最大值),所以我们把顶部行的每个数字加起来,得到255
。
128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
---|---|---|---|---|---|---|---|
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
另一个例子,参见以下表:
128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
---|---|---|---|---|---|---|---|
1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
要将这个数字转换成十进制,从右边开始,向左移动。第一位是 0。它是否符合 1 的点值?不符合。跳过。接下来,它也不符合 2、4 或 8。所以跳过这些。但它确实符合最后四位,16、32、64 和 128。把它们加在一起。答案是 224。你刚刚把二进制数1111000
转换成了十进制。
我们可以在子网掩码中使用1101000
吗?不行。原因是因为子网掩码中的 1 必须是连续的。以下是子网掩码中所有有效的二进制数:
00000000
10000000
11000000
11100000
11110000
11111000
11111100
11111110
11111111
实际上,就是这样。由于任何 1 必须是连续的(从左到右开始),这些是子网掩码中任何八位组的唯一有效数字。因此,子网掩码的任何八位组的唯一有效十进制值是 0、128、192、224、240、248、252、254 和 255。
注意
如果将 IP 地址转换为二进制,你会按照之前的表中的点值进行转换,尽管连续 1 的规则不适用。IP 地址中的任何数字从 0 到 255 在任何八位组中都是有效的,每个八位组中的 1 和 0 的任何组合也是有效的。
要对网络进行子网化,我们只需改变连续 1 的数量。例如,255.255.255.0
的二进制表示是11111111.11111111.11111111.00000000
。我们可以在这个掩码中添加一个额外的 1,得到11111111.11111111.11111111.10000000
,这给我们一个子网掩码为255.255.255.128
。使用这个子网掩码,我们能够将我们的网络分成两部分。让我们来分解一下。
正如我多次提到的,子网掩码的目的是掩盖IP 地址的哪一部分是网络的,哪一部分是个体节点的。正如我们已经知道的,子网掩码为255.255.255.0
意味着前三个八位组不能使用,但我们可以使用最后一个为 0。如果我们将这个子网掩码应用到10.10.10.0
网络,我们可以知道每个主机的 IP 地址都是10.10.10.x
。最后一个八位组是 0,它告诉我们 IP 地址10.10.10.1
到10.10.10.254
是可用的。同样,我们不能使用子网的第一个 IP(在这种情况下是10.10.10.0
)或最后一个(10.10.10.255
),因为它们分别对应网络标识符和广播地址。
但是,对于一个子网掩码并不以 0 结尾的情况,我们该怎么办呢?对于子网掩码为255.255.255.128
,最后一个八位组被使用但没有耗尽,因为它不是 255 的最大值。我们还有一些剩余。这是因为当一个八位组在子网掩码中不是 255 时,它并没有完全屏蔽掉该八位组。相反,它创建了一个分割线。如果我们将该子网掩码应用到我们的10.10.10.0
网络上,IP 地址10.10.10.128
就不能使用。我们已经将最后一个八位组分成了两半。记住,八位组中的值从 0 到 255 都是有效的;因此,256 个可用数字的一半是 128。考虑到这一点,我们创建了一个方案,其中我们有两个网络。一个网络包含 IP 地址10.10.10.1
到10.10.10.126
。另一个允许我们使用 IP 地址10.10.10.129
到10.10.10.254
。之所以这样做是因为10.10.10.128
是我们子网的分割线,不能使用。我还提到了块内的第一个和最后一个 IP 地址也不能使用,因为10.10.10.0
和10.10.10.128
是每个网络的标识符。每个块中的最后一个 IP 地址分别是10.10.10.127
和10.10.10.255
,因为这些现在是这两个网络的广播地址。如果我们以 CIDR 格式写出这些网络,我们会得到以下结果:
10.10.10.0/25
10.10.10.128/25
记住,我们计算子网掩码中连续的 1 的数量,以达到最后的斜杠数字。我们可以将其写成以下形式,但我相信你会同意 CIDR 更容易输入:
10.10.10.0/255.255.255.128
10.10.10.128/255.255.255.128
在二进制中,该子网掩码是11111111.11111111.11111100.00000000
。因为有 25 个 1,这个子网掩码的 CIDR 表示法是 25。希望现在这个概念已经讲清楚了。
至于我们的无类别样式,没有什么能阻止你使用诸如255.255.255.0
这样的子网掩码。并不是每个人都需要大量的主机。但是,我们不再称之为类 C 子网掩码,而是在 CIDR 样式中我们会称之为/24
网络。在表中,我列出了在讨论有类别网络时使用的子网掩码,以及它们的 CIDR 等效。
类别 | 子网掩码 | CIDR 表示法 |
---|---|---|
A | 255.0.0.0 | /8 |
B | 255.255.0.0 | /16 |
C | 255.255.255.0 | /24 |
既然我们了解了子网划分的工作原理,那么我们如何在我们的网络中实施呢?幸运的是,这部分很容易。实施子网的魔力都在于你的 DHCP 服务器。如果你还记得,在第六章中,配置网络服务,我们在 DHCP 服务器的/etc/dhcp/dhcpd.conf
文件中使用了以下配置:
default-lease-time 86400;
max-lease-time 86400;
option subnet-mask 255.255.252.0;
option broadcast-address 10.10.99.255;
option domain-name "local.lan";
authoritative;
subnet 10.10.96.0 netmask 255.255.252.0 {
range 10.10.99.100 10.10.99.254;
option routers 10.10.96.1;
option domain-name-servers 10.10.96.1;
}
在第一行粗体字中,我为从该服务器接收 IP 地址的每个节点提供了一个子网掩码为255.255.252.0
。在代码块的末尾,我决定从10.10.99.100
到10.10.99.254
发放 IP 地址。因此,每个节点将收到一个10.10.99.x
的 IP 地址和一个255.255.252.0
的子网掩码。
实施子网方案时唯一剩下的事情就是确保每个具有静态 IP 地址的服务器或设备也被更改。除非你使用了静态租约(也称为保留),否则你将不得不手动找到这些主机并进行更改。因此,我总是更喜欢静态租约而不是静态 IP。使用静态租约,你只需要编辑 DHCP 配置并更改分配给你的主机的 IP。参考第六章中我们是如何设置我们的保留的。
实施服务质量
并非所有的网络流量都是平等的,也并非所有的服务都同等重要。有时,网络需要对某些服务给予比其他服务更紧急的处理。也许在服务器环境中,您的 Web 服务器从访问者那里接收到大量流量,并且必须优先考虑 MySQL,或者您的办公室使用VoIP(即IP 电话)并需要优先考虑电话系统。您的网络可能有许多原因需要对某项服务给予比其他服务更紧急的处理。服务质量(QoS)帮助我们实现这一点。
虽然有多种调整网络适配器以实现 QoS 的方法,但最典型的是所谓的排队规则(或更简单地说,qdisc)。排队规则是管理员可以应用于网络适配器的一种方法,以使用多种调度程序中的一种,每种调度程序对流量处理方式有不同的影响。要查看您的网络适配器当前使用的调度程序,请运行以下命令:
ip link list
查找您的默认网络卡,很可能是eth0
(在 Debian 中)或eno1
(在 CentOS 中)或类似的。
在 Debian 中查看 IP 链接列表的输出
最有可能,您会在输出中看到qdisc pfifo_fast
,这告诉我们当前使用的排队规则是pfifo_fast
。这基本上是一个先到先服务的调度程序(先进先出)。但pfifo_fast
不是包含一个带宽,而是包含三个——每个都将流量分为三个优先级。第一个带宽(带宽 0)包含最高优先级的流量。除非您的发行版更改了默认调度程序,否则pfifo_fast
很可能是您系统中默认使用的。
pfifo_fast
调度程序被称为无类调度程序。换句话说,你看到的就是你得到的——在处理无类调度程序过滤流量时不需要进行任何配置。其他无类规则包括随机公平 排队(SFQ)、扩展随机公平排队(ESFQ)和令牌桶过滤器(TBF)。
SFQ qdisc 使用了我们之前提到的 FIFO 的概念,但将网络流量分成多个 FIFO,并以循环方式处理。这种 qdisc 试图尽可能公平地使用流来调度数据包传输。这使得每个流都有机会传输,防止任何一个流变得过度饱和。ESFQ 非常相似,但它为管理员提供了更多配置选项。与 SFQ 不同,TBF 实际上不会操纵数据包,也不会进行任何调度。TBF 的主要目的是设置传输速率,允许您设置参数,如速率、突发、峰值速率等。有关这些 qdisc 的更深入信息,请参阅sfq
和tbf
的主页。通过tc
命令可以在网络适配器上设置首选的 qdisc。请参阅以下示例,设置以太网适配器eno1
上的sfq
:
# tc qdisc add dev eno1 root sfq perturb 60
在这里,我们使用tc
命令与qdisc
,并澄清我们想要add
(我们也可以del
)一个 qdisc。我们将对接口eno1
执行此操作,并请求将此更改应用于出口(root
),同时针对我们的接口使用sfq
qdisc。最后,我们设置我们的 qdisc 特定参数(在本例中为pertub
)。perturb 参数允许我们设置此 qdisc 的哈希算法将被重置的秒数。我们可以更改其他特定于 sfq 的值,如使用的流数、量子、redflowlimit 等。请参阅man sfq
,了解可以与 sfq 或 tbf 一起使用的参数的完整描述。
无类 qdisc 的概念存在不足之处,即它们不允许你像人们希望的那样对流量进行细致的分类。虽然改变数据包的调度方式肯定是有用的,但这个概念不允许你在任何给定时间选择哪种类型的流量优先级。有类 qdisc 解决了这个问题,并给管理员更多的灵活性。通过这些,你可以设置父类和子类,每个都有不同的规则。事实上,这是有类和无类 qdisc 之间的主要区别。无类 qdisc 并不是完全不可配置;它们只是没有支持高级用例灵活性的选项。接下来,我们将探讨有类 qdisc 以及它们如何为我们提供这种额外的灵活性。
通过利用有类 qdisc 的强大功能,你几乎完全控制了网络上数据包的处理方式。我说几乎是因为重要的是要记住,排队规则的概念只影响出站流量(出口),而对于管理入站流量几乎无能为力。然而,在生产网络中,保证特定服务一定数量的带宽是非常有益的。正如我们在前一节中讨论的,无类 qdisc 允许我们管理数据包处理的一般方式,但有类 qdisc 通过设置类别和过滤器为我们提供了更多的控制。
你可能会遇到的一个可能情况是 VoIP 流量变得不稳定,导致通话听起来模糊或完全中断。在这种情况下,你可能希望为你的 VoIP 服务器保证更多的带宽,即使这意味着牺牲来自其他来源的流量。此外,在 Linux 网络中,SSH 也很重要。如果你的服务器被数据包淹没,甚至无法响应通过 SSH 连接到它的请求,那可能是一个非常严重的问题,因为你将无法登录并纠正可能出现的任何问题。这些是许多人在没有优先处理流量的情况下面临的非常真实的情况。如果有一个你的网络或公司依赖的服务,优先处理它是一个很好的措施。
实现这一点最流行的 qdisc 是分层令牌桶(HTB),这是一个有类 qdisc。HTB 允许你控制设备上使用的出口带宽,它基于我们之前讨论的 TBF 风格。HBT 具有一些可以用来控制流量的类,比如设置parent
、priority
、rate
、ceil
和字节的突发数量。查看man htb
以查看完整的列表。
就像我们配置无类 qdisc 一样,类似 HTB 的有类 qdisc 的设置也是通过tc
命令完成的。在大多数系统上,这个命令存储在/sbin
中,可能不在常规用户的路径中。输入which tc
来定位这个二进制文件在你的发行版上的位置。在大多数情况下,如果以 root 用户登录时运行此命令,系统应该能识别这个命令。接下来是一个设置 HTB 作为名为eth0
的网络设备的 qdisc 的过程示例。
# tc qdisc add dev eth0 root handle 1: htb default 10
# tc class add dev eth0 parent 1: classid 1:1 htb rate 2mbit
# tc class add dev eth0 parent 1:1 classid 1:10 htb rate 1mbit ceil 1.5mbit
# tc class add dev eth0 parent 1:1 classid 1:20 htb rate 100kbps ceil 100kbps
在第一个命令中,我们将 qdisc 从默认的pfifo_fast
更改为htb
。在这个命令中,root
表示我们正在设置这个出口流量。1:
的句柄是对htb
的这个特定实例的名称。将默认设置为10
意味着任何没有特别分类的流量将被赋予1:10
的类别 ID。通过第二个命令,我们创建了类别 ID1:1
,并将其调整为使用速率2mbit
。在第三个命令中,我们做了同样的事情,只是我们创建了一个 ID 为1:10
的类别,并设置了一个上限,这将限制这个类别为1.5mbit
。因为我们将默认设置为10
,所以如果我们没有特别指定流量使用其他类别,就会使用这个类别。最后,我还加入了第三个类别1:20
,它的上限要低得多,为100kbps
。通过将rate
和ceil
值设置为相同的值,我们可以合理地期望这个类别的流量消耗100kbps
,但也受到100kbps
的限制。您可以继续使用这种方法向1:
父类添加额外的类别,根据需要将带宽分割成多个类别。
现在我们已经确定了我们的类别,我们应该开始使用它们。通过我们之前的例子,您可能会注意到您的带宽现在比之前少了(假设您的带宽高于我们设置的1.5mbit
的默认值)。但我们的其他两个类别没有使用,因此我们可以根据需要提高或限制其他服务的带宽。因此,让我们为 SSH 添加一个过滤器。由于 SSH 不需要大量带宽,我们可以将我们的1:20
类别分配给它。为此,我们将再次使用tc
命令:
# tc filter add dev eth0 parent 1: protocol ip prio 7 u32 match ip sport 22 0xfff classid 1:20
注意
可以更改服务器用于 SSH 连接的端口,我们将在第九章保护您的网络中讨论。如果更改了 SSH 端口,请相应调整tc
命令。
这留下了两个类别,1:1
和1:10
。我们也可以根据需要为它们分配过滤器,具体取决于我们想要为流量分类的端口:
# tc filter add dev eth0 parent 1: u32 match ip sport 80 0xfff classid 1:1
# tc filter add dev eth0 parent 1: u32 match ip sport 5060 0xfff classid 1:10
在这里,我使用端口80
和5060
分别用于 HTTP 和 VoIP 流量。您的端口可能不同,因此可以根据您的网络需求自由调整命令。但在这个假设的例子中,端口80
上的流量将被分类为1:1
,并被授予最大速率为2mbit
(非常适合 Web 服务器),端口5060
上的流量将被授予1.5mbit
。
总之,无类 qdisc 允许您控制系统上如何管理数据包的一般共识。根据您的环境,您可能会发现切换到无类 qdisc 会提高性能。但真正的好处在于有类 qdisc,它允许您更加精细地控制数据包的处理方式,以及服务器资源提供的速率。调整网络性能是一项耗时的任务,需要通过试错来确定哪些值、类别和过滤器会提高网络性能。
路由 TCP/IP 流量
网络的整个目的是将流量从 A 点传输到 B 点。当一台计算机从另一台计算机请求信息时,数据包被路由到目的地,然后返回。有时,计算机需要一点指导,以确定如何将数据包传输到目的地。这就是所谓的路由。为了帮助实现这一点,节点利用路由表的概念来决定特定目的地应该发送数据包的位置。如果每个网络都使用相同的 IP 方案,那将会非常容易,但事实上,每个网络都是完全不同的。要与不同的网络通信,您的计算机必须知道如何到达该网络。可以将路由表视为外部目的地和到达这些目的地的网关的地图。
为了更好地理解这一点,让我们也谈谈默认网关的概念。通常,默认网关是一个理解如何与其他网络通信的路由器。当您在网络上发送信息请求时,数据包会经过本地默认网关,然后从那里进入其他网络。在小型办公室或家庭网络的情况下,默认网关很可能是位于您的网络和世界其他部分之间的路由器。此外,它还位于您的本地设备和网络内所有其他设备之间。如果没有默认网关,您很可能无法在网络上进行通信。
要查看您的默认网关,请发出ip route
命令,并查找读取default via
的行。
ip route 命令的输出
如果没有默认网关(或者默认网关没有正确配置),您可能会发现无法与网络上的其他节点进行通信。在大多数情况下,一旦通过 DHCP 接收到地址,默认网关就会添加到您的路由表中。如果您使用静态 IP 配置,您可以通过/etc/network/interfaces
在 Debian 中手动设置默认网关,或者在 CentOS 中通过网络卡的 init 脚本(例如/etc/sysconfig/network-scripts/ifcfg-eno1
)。以下是这些配置文件的示例,其中突出显示了相关行:
/etc/network/interfaces
文件(Debian):
iface lo inet loopback
allow-hotplug eth0
iface eth0 inet dhcp
# The primary network interface
allow-hotplug eth1
iface eth1 inet static
address 10.10.96.1
netmask 255.255.252.0
gateway 10.10.96.1
broadcast 10.10.96.255
dns-search local.lan
dns-nameservers 10.10.96.1
/etc/sysconfig/network-scripts/ifcfg-eno1
文件(CentOS):
TYPE=Ethernet
BOOTPROTO=static
DEFROUTE=yes
PEERDNS=yes
PEERROUTES=yes
IPV4_FAILURE_FATAL=no
NAME=eno1
UUID=8e6587dd-74ec-488f-8597-a04c4a4c5091
DEVICE=eno1
ONBOOT=yes
IPADDR="10.10.96.4"
NETMASK="255.255.252.0"
GATEWAY="10.10.96.1"
如果您想要比那更手动地设置默认网关,您也可以通过终端使用 shell 命令来执行此操作,如下所示:
# route add default gw 10.10.10.1 eth0
注意
如果您的系统不识别 route 命令,则需要安装net-tools
软件包。
足够简单。我们使用 route 命令来添加新路由;在这种情况下,我们正在添加我们的默认网关(default gw
)。在这种情况下,我们将该网关设置为10.10.10.1
并将其绑定到接口eth0
。可能不用说,但一旦重新启动此计算机或重新启动网络,除非通过更新接口卡的init
脚本使其永久化,否则此设置可能会丢失,正如我们之前讨论的那样。
要查看您的路由表,只需执行route -n
命令而不带任何参数。如果找不到该命令,您可能需要调用路径(例如/sbin/route
)或以 root 身份运行它。当您执行此命令时,您将看到路由表。这也将显示您的默认网关。
route -n 命令的输出
在讨论此表时,首先要讨论的是0.0.0.0
的 IP 地址。在网络方面,这指的是一切。正如您在前面的示例中所看到的表中所示的,目的地0.0.0.0
的网关在这个网络上是192.168.1.1
。因此,任何通信都会发送到这个 IP(毕竟,这是默认网关)。在此表中还显示了其他网络。在我的情况下,它们指的是在此测试机器上运行的 Docker 实例以及 KVM 虚拟化,并且每个都有自己独立的虚拟网络。由于它们都在同一台机器上运行,它们的网关是本地的:0.0.0.0
。
Linux 机器可以很容易地充当路由器,而无需来自诸如思科公司等公司的昂贵网络设备。这种灵活性使 Linux 成为网络的一个非常突出的选择,基于 Linux 的硬件路由器变得非常普遍。这至少部分是因为配置 Linux 系统成为路由器是多么容易。简而言之,将 Linux 节点变成路由器所需的只是多个网络接口卡。每个接口卡都可以有自己的默认网关,因此你实际上可以像我们在本节前面为eth0
添加默认网关一样配置路由。你只需对eth1
、eth2
或者系统上其他任何接口执行相同的操作。
然而,有一个例外。对于大多数 Linux 发行版,默认情况下通常禁用网络接口之间的路由。在我职业生涯的早期,这给你的作者带来了很多痛苦和挫折,直到这一点变得众所周知,所以我会为你节省麻烦,并向你展示如何在 Linux 系统上启用网络接口之间的路由。
首先,看看这是否已经为你完成。虽然我发现许多发行版默认情况下不启用转发,但有些发行版会启用。检查这一点很容易:
cat /proc/sys/net/ipv4/ip_forward
那个命令的输出是什么?是1
吗?如果是,那就没问题了。如果不是,我们需要进行更改。要做到这一点,只需将值替换为 1(作为 root):
echo 1 > /proc/sys/net/ipv4/ip_forward
就是这样,你完成了。你刚刚启用了网络接口之间的路由(转发)。这并不难。但是,我想你可能更希望这是一个永久性的改变。一旦重新启动系统,这个设置很可能会恢复到默认值。要使这个改变永久生效,用你喜欢的文本编辑器(作为 root)编辑/etc/sysctl.conf
,并在文件末尾添加以下行:
net.ipv4.ip_forward = 1
现在,无论何时重新启动系统,你都将保留这个设置。在我让你做的所有网络调整中,这绝对是最容易的。
最后,让我们花一点时间来讨论网络地址转换(NAT)。NAT 的概念是改变那些目的地是一个主机的数据包,并改变它们的目的地,使其变成其他东西。这种改变实际上是通过改变数据包本身来完成的,对于管理网络路由来说非常有用。NAT 最常见的用途是保留 IP 地址,尤其是考虑到当前 IPv4 地址短缺的情况下。如果你家里有一台路由器,你可能已经很熟悉这个概念了。你的互联网服务提供商(ISP)给你一个 IP,这个 IP 就是世界其他地方看到你的 IP。但是在你的本地网络中,你可能有十几个设备连接并使用同一个互联网连接。你的每个内部设备都有一个由本地 DHCP 服务器分配的 IP 地址,但这个地址只是本地的,不能路由到外部世界。在这种情况下,你的路由器会跟踪每个设备收发的数据包,并改变数据包,使它们不会混淆,并最终到达正确的位置。
例如,假设你有一台笔记本电脑和一台台式机(在同一个网络上),你在笔记本电脑上访问www.packtpub.com/
。你的路由器将请求发送到互联网,并传递结果。基本上,你的路由器代表你的笔记本电脑发出请求。当来自www.packtpub.com/
的返回数据包到达时,数据包的目的地地址会从你的公共 IP 地址更改为请求信息的机器的 IP 地址。这样,你可以相当肯定你的笔记本电脑会得到回复,因为它是最初发出请求的那个。
NAT 的概念很聪明,这甚至不是唯一的用例。您甚至可以手动更改目标地址,这可以帮助您将数据包发送到内部计算机原本无法路由到的其他网络。要手动更改 NAT,我们使用ip rule
命令。利用这个命令只是根据流量的来源改变目的地。考虑以下示例:
# ip rule add nat 10.10.10.1 from 192.168.1.134
这再简单不过了。在这里,我们告诉我们的系统查找任何来自192.168.1.134
的数据包,并将其重写为流向10.10.10.1
。对于您需要执行的任何其他NATing,请重复此操作。
创建冗余的 DHCP 和 DNS 服务器
在第六章中,我们设置了 DHCP 和 DNS 服务器。这很好,但不幸的是有一个主要问题。任何一个都是单点故障。如果 DHCP 服务器崩溃,新设备将无法接收 IP 地址,并且当前连接的客户端将在其当前 IP 租约到期时从网络中断开。如果 DNS 服务器崩溃,客户端将无法通过主机名到达目的地。根据您的网络范围,这种停机时间可能很难处理,因此为这些服务提供冗余可能是一个好主意。
配置了另一台服务器进行冗余的 DHCP 服务器将同步其已发出的 IP 地址列表,并且每台服务器都会检测另一台服务器是否停止响应。在这种情况下,备用服务器将接管发放新的 IP 地址的任务。对于 DNS,只需在网络上添加另一台 DNS 服务器,但我稍后会详细讨论这个问题。
让我们从向我们的 DHCP 服务器添加冗余开始。之前创建的初始服务器可以简单地视为主服务器。接下来要做的是创建另一台服务器作为辅助服务器。这可以是另一台物理服务器,甚至是虚拟机,选择权在你。安装isc-dhcp-server
,就像我们在第六章中讨论的那样,配置网络服务。一旦你有了第二台服务器,我们就可以开始了。
注意
在将 DHCP 服务器投入生产之前,务必确保两台 DHCP 服务器的时钟同步。在继续之前,最好再次检查两者上是否配置了 NTP 并且正常工作。在第六章中,包括了有关设置 NTP 的信息。
从我们的主节点开始,我们应该向我们的/etc/dhcp/dhcpd.conf
文件添加一些额外的代码。我已经加粗了新的配置行,以实现冗余:
default-lease-time 86400;
max-lease-time 86400;
option subnet-mask 255.255.252.0;
option broadcast-address 10.10.99.255;
option domain-name "local.lan";
authoritative;
failover peer "dhcp-failover" {
primary;
address 10.10.96.2;
port 647;
peer address 10.10.96.1;
peer port 647;
max-response-delay 60;
max-unacked-updates 10;
load balance max seconds 3;
mclt 3600;
split 128;
}
subnet 10.10.96.0 netmask 255.255.252.0 {
option routers 10.10.96.1;
option domain-name-servers 10.10.96.1;
pool {
failover peer "dhcp-failover";
range 10.10.99.100 10.10.99.254;
}
}
注意
请注意,以下行已被删除:
range 10.10.99.100 10.10.99.254;
它被同一部分中的{}
块替换了。
在很大程度上,我们在主服务器上做的相同配置可以复制到辅助服务器上。请随意使用我们在这里的/etc/dhcp/dhcpd.conf
文件作为在第二台服务器上开始配置的基础。我将再次强调两者之间的不同之处。代码如下:
default-lease-time 86400;
max-lease-time 86400;
option subnet-mask 255.255.252.0;
option broadcast-address 10.10.99.255;
option domain-name "local.lan";
authoritative;
failover peer "dhcp-failover" {
secondary;
address 10.10.96.1;
port 647;
peer address 10.10.96.2;
peer port 647;
max-response-delay 60;
max-unacked-updates 10;
load balance max seconds 3;
}
subnet 10.10.96.0 netmask 255.255.252.0 {
option routers 10.10.96.1;
option domain-name-servers 10.10.96.1;
pool {
failover peer "dhcp-failover";
range 10.10.99.100 10.10.99.254;
}
}
注意
从辅助服务器的配置中删除了以下行:
mclt 3600;
split 128;
你应该注意到主要和次要的地址在每个配置文件中是颠倒的。在第一个配置文件中,主要是10.10.96.1
,次要设置为10.10.96.2
。在第二个配置文件中,这被更改为10.10.96.2
和10.10.96.1
。此外,要特别注意 IP 地址、子网掩码和任何其他值,这些值可能会因网络而异。如果你在两台服务器上启动 DHCP 服务(在 Debian 上是isc-dhcp-server
,在 CentOS 上是dhcpd
),你应该看到它们通过日志进行通信。要检查的具体日志将在基于 Debian 的系统中是/var/log/syslog
,在 CentOS 系统中是/var/log/messages
。你可以很容易地测试这是否有效,方法是在其中一台服务器上禁用 DHCP 服务,然后你应该看到另一台服务器代替它发放 IP 地址。
现在我们已经为 DHCP 配置了冗余,让我们为 DNS 做同样的事情。事实上,这要容易得多。你所需要做的就是指定另一台服务器作为你的次要 DNS 服务器(你可以创建一台新的机器,或者只是将它添加到你的次要 DHCP 服务器),然后将你的配置文件和区域文件复制到新的服务器上。同样,第六章,“配置网络服务”,包含了这些文件的所有相关细节。如果你想节省一些时间,甚至可以将你的原始 DNS 服务器克隆到一台新的机器上,如果你使用虚拟化或了解如何使用dd
命令,这是很容易做到的。无论你喜欢使用哪种方法来创建次要服务器并复制你的区域文件,都要测试 DNS 是否在新服务器上工作。一旦它工作了,我们就回到我们的 DHCP 配置,将这个次要服务器部署到我们所有的节点上。
在我们的/etc/dhcp/dhcpd.conf
文件中,查找以下行:
option domain-name-servers 10.10.96.1;
将其更改为以下内容:
option domain-name-servers 10.10.96.1, 10.10.96.2;
你完成了。现在,每当你的客户的租约到期或他们请求一个新的 IP 地址时,他们将自动获得次要 DNS 地址。
在这一点上唯一剩下的事情就是配置你可能设置了静态 IP 地址的任何节点来使用次要 DNS 服务器。正如我现在已经提到过大约一千次,出于这个原因和更多原因,我非常喜欢静态租约(为 DHCP 服务器上的各个节点保留 IP 地址)而不是手动静态 IP 分配。你只需要在 DHCP 服务器中配置它们。但是,如果你有任何你手动配置了网络的节点(各有各的方式),只需更新它们的init
脚本。同样,你会在/etc/network/interfaces
(Debian)或/etc/sysconfig/network-scripts/<if-name>.cfg
(CentOS)中找到这个配置。
总结
在我们的旅程中的这一点上,你的网络应该处于更好的状态。在本章中,我们完成了相当多的工作。我们讨论了诸如路由、NAT、子网划分、服务质量等高级主题,甚至为我们的 DHCP 和 DNS 服务器设置了冗余。如果我们了不起的网络发生了什么事情,那真是太遗憾了。这就是为什么在下一章中,我将介绍如何加强我们网络的安全性。到时见!
第九章:保护您的网络
安全漏洞和利用它们的不法分子无处不在。在典型网络上运行的软件中包含数百万行代码,从统计上讲,要想百分之百地安全防范所有可能的威胁是不可能的。然而,一个好的网络管理员会关注网络安全的当前趋势,并采取一切可能的预防措施,以确保网络尽可能安全。在本章中,我们将探讨一些可以增加网络安全性的方法。
在本章中,我们将涵盖:
-
限制攻击面
-
保护 SSH
-
配置 iptables 防火墙
-
使用 fail2ban 保护系统服务
-
了解 SELinux
-
配置 Apache 以利用 SSL
-
部署安全更新
限制攻击面
网络安全的最重要规则是限制攻击面。简而言之,这意味着您安装的软件越少和/或运行的服务越少,就越不容易被利用。更糟糕的是,在某些情况下,服务器软件中的未修补漏洞可能允许不法分子使用您的服务器来攻击其他人。通过限制系统中使用的软件包的数量,您降低了发生不良事件的可能性。
这听起来很简单,而且确实如此,但重要的是要记住,这不仅仅是安装您需要的软件。许多 Linux 发行版都附带了您可能永远不需要使用的软件。这不仅适用于服务器。即使您的最终用户工作站可能运行着不必要的服务,这对攻击者来说将是一个宝藏。一个常见的例子是在系统上运行邮件传输代理(MTA)。令人惊讶的是,许多 Linux 发行版默认情况下都运行着 MTA。除非您明确需要 MTA(例如,您安装了需要向管理员发送电子邮件的脚本),否则应该从系统中删除这些软件包。
在任何网络上部署 Linux 时,您应该首先找出安装了什么以及正在运行什么,然后决定关闭和/或卸载什么。这就是所谓的限制攻击面。的确,Linux 是最安全的系统之一,但如果您不注意系统上正在运行和监听网络连接的内容,那么什么也帮不了您。在本节的其余部分,我将介绍一些限制攻击面的方法。
首先,让我们打印出系统上安装的所有软件包的列表。这将使我们能够看到安装了什么,然后我们可以删除任何突出显示的我们确定不需要的东西。这个列表可能会很长,因为它将包括一切; 我是指一切-甚至是让我们的系统运行的库和各种软件包。您肯定不会理解每个软件包的用途,但随着您对 Linux 的了解越来越多,您将更加理解这些内容,并知道需要删除什么。例如,我知道要从所有的安装中删除exim
或postfix
软件包,因为我个人在任何地方都不需要它们。由于您不会理解系统上安装的所有软件包的用途,我建议您快速查看并删除您确定不需要的软件包。要打印已安装软件包的列表,请运行以下命令之一:
对于基于 Debian 的系统,请执行以下命令:
# dpkg --get-selections > installed_packages.txt
对于 CentOS 系统,请执行以下命令:
# rpm -qa > installed_packages.txt
无论哪种情况,您最终都会在当前工作目录中得到一个名为installed_packages.txt
的文本文件。这个文本文件将包含您系统上安装的所有软件包的列表。请随意检查它,看看是否有什么可以删除的内容。此外,这个文件也可以作为一个方便的备份。如果您需要停用一个服务器并设置一个具有类似目的的新服务器,您可以将一个服务器的软件包与另一个服务器进行比较,以确保正确的软件包已安装。
另一个发现系统上正在运行的内容的好方法是使用netstat
命令。虽然我们将在第十章中进一步讨论这个命令,故障排除网络问题,现在让我们试一试:
netstat -tulpn
您应该看到正在本地计算机上运行的实际上正在监听网络连接的服务列表。这些应该受到重视,因为任何监听外部连接的东西都可能是系统的入口点。如果您看到这里有一些正在监听连接而您不需要它,可以删除该软件包。您可以随时禁用服务,但删除底层软件包更好,因为它们不会被意外启动。如果您发现实际上确实需要它们,软件包总是可以重新安装的。
netstat 命令,列出正在运行和监听的服务。
在我的情况下,我可以看到 Syncthing 和 Chrome 正在监听外部连接。这是预期的。但在生产环境中,比如服务器,需要注意的是 Apache web 服务器(如果服务器实际上不是 web 服务器的话),postfix,或者任何不应该安装的文件传输工具。
另一个有用的工具是ShieldsUP,这是 GRC 在互联网上提供的一项服务。这绝对不是一个特定于 Linux 的工具,但如果您在路由器上使用 Linux,并希望确保它配置为尽可能隐秘,这个工具可以用于测试。您可以在以下网址访问这个工具:
注意
请记住,ShieldsUP 是一个在线工具,不受作者或出版商的控制或管理。因此,它随时可能会发生变化。话虽如此,这个网站已经有一段时间没有变化了,它是一个非常有用的工具。
要使用它,点击继续,然后点击所有服务端口。这项服务通过检查哪些端口回应外部请求来工作。如果一个端口是打开的,它会显示为红色,您应该能够点击它以了解更多关于该端口通常用于什么的信息。这将为您提供有关禁用什么的线索。如果服务不包含有关特定端口的信息,只需在 Google 上搜索以寻找线索。
使用 ShieldsUP!查看哪些端口回应外部请求
最后,systemctl
命令也可以用来查看当前安装在您的机器上的服务:
systemctl list-units -t service
使用前一个命令打印到终端的列表,您将能够看到当前安装的单元文件及其状态。
这基本上总结了如何审问您的系统以找出正在运行的内容。随着时间的推移,您会学到典型服务的名称,可能需要进行一些 Google 搜索以了解每个服务的目的,但随着时间的推移会变得更容易。如果您对可以禁用的内容有任何疑问,请在实际调整运行服务之前先进行研究。最坏的情况是,如果您禁用了一个必要的服务,您的服务器可能在下一次启动时无法启动。如常,在更改系统服务之前,请确保您有良好的备份。
Securing OpenSSH
OpenSSH 是一个很棒的工具;它是 Linux 管理员的好朋友。它可以让你不必走进服务器房间,连接显示器和键盘就可以在网络上进行工作。使用连接到同一网络的任何计算机,你几乎可以做任何你想做的事情,就像你站在机器前面一样。问题是,一个不安全的 SSH 实现给了不法分子同样的便利。在你的网络上运行的所有东西中,SSH 绝对是你想要给予重点关注的。
SSH 的第一个和最常见的安全调整是只使用协议的 2 版本。要确定你的 Linux 安装使用的是哪个版本,可以使用grep
命令查看/etc/ssh/sshd_config
文件:
cat /etc/ssh/sshd_config |grep Protocol
如果答案是 1,你应该编辑这个文件并将Protocol 1改为Protocol 2,然后重新启动 SSH。这很重要的原因是因为协议 1 的安全性比协议 2 要弱得多。值得庆幸的是,SSH 7 版本及更高版本现在默认使用协议 2,所以这不像以前那样常见。但在写这篇文章的时候,7 版本刚刚发布,并且还没有在许多发行版中得到应用。希望到你读到这篇文章的时候,你的发行版已经升级到 7 版本。但如果没有,你需要确保你的所有服务器只使用 SSH 的协议 2。你可以通过更改sshd_conf
文件中的相关行,然后重新启动 SSH 服务来实现这一点。
SSH 的另一个值得改变的地方是改变它监听的端口。默认情况下,SSH 监听在端口 22上。你可以使用以下命令确认:
cat /etc/ssh/sshd_config |grep Port
除非你改变了它,答案将是 22。由于 22 是 SSH 的默认端口,这是每个人(包括坏人)都期望的端口。在/etc/ssh/sshd_config
文件中,顶部附近将有一个端口选项。如果你将它改成其他端口,对外部人员来说就不那么明显了。然而,我不想让你产生一种虚假的安全感。改变 SSH 端口并不能奇迹般地阻止通过 SSH 的入侵。在有针对性的攻击中,不法分子会扫描你服务器上的每个端口,所以如果他们决心的话,他们会找出你将端口改成了什么。我建议这种改变的原因是因为这是一个非常容易的改变。只需要几秒钟就可以改变你的 SSH 端口,任何你可以做的事情来使你的网络对外部人员不那么明显都是受欢迎的。改变 SSH 端口可能成为潜在问题的唯一时机是如果你的网络用户期望它在 22 端口。只要你向每个人传达这个改变,这应该不是问题。
为了连接到一个非标准的 SSH 端口的服务器,使用-p
标志:
ssh -p 63456 myhost.mynetwork
你也可以在使用scp
时指定端口:
scp -P 63456
注意
请注意,-P
参数在scp
命令中是大写的,但在ssh
命令中不是。这是有意为之的。原因是因为在scp
中小写的-p
选项已经被使用了,它用于在传输文件时保留修改时间。
如果你似乎无法养成请求 SSH 的不同端口的习惯,可以为它创建一个别名。然而,如果你的一些主机仍在使用端口 22,这可能会成为一个问题,所以只有当你连接的所有东西都在同一个端口上时才使用这个别名。在下面的例子中,我们可以设置一个别名为ssh
,强制它总是使用端口63456
:
alias ssh="ssh -p 63456"
你的 SSH 配置的另一个非常重要的改变是不允许 root 登录。在任何情况下,都不应该允许在任何 Linux 服务器上以 root 身份登录。如果你的配置要求你通过 SSH 以 root 身份登录到服务器,那么你需要更正你的配置。要检查 SSH 是否允许 root 登录,运行以下命令:
cat /etc/ssh/sshd_config |grep PermitRootLogin
如果启用了 root 登录,则通过更正/etc/ssh/sshd_config
中的以下配置行来禁用它。但是,请确保您能够首先使用普通用户帐户通过 SSH 访问服务器;否则,您将被锁定。sshd_config
中的以下配置行将禁止 root 登录:
PermitRootLogin no
注意
如往常一样,在对其配置进行任何更改后重新启动ssh
。不要担心在使用 SSH 时重新启动它,当前连接不会中断。
对于 Debian 系统,请执行以下命令:
# systemctl restart ssh
对于 CentOS 系统,请执行以下命令:
# systemctl restart sshd
另一个值得实施的做法是将 SSH 限制为仅允许通过特定用户和/或组进行连接。默认情况下,系统上的任何用户都可以通过 SSH 访问。要更改此设置,请将以下行添加到配置文件的最底部:
AllowUsers jdoe
如果您有多个用户,您可以在同一行上添加多个用户:
AllowUsers jdoe bsmith
您还可以允许特定的组。首先,创建一个用于 SSH 访问的组:
groupadd ssh_admins
接下来,将一个或多个用户添加到组中:
usermod -aG ssh_admins jdoe
最后,在 SSH 配置文件的底部添加以下行。重新启动 SSH 后,访问将受到限制,只有属于该组的人才能访问。每次需要向某人授予 SSH 访问权限时,您只需要将其用户 ID 添加到该组中,而无需每次都重新启动sshd_config
配置文件。
AllowGroups ssh_admins
最后,SSH 的最安全选项是根本不允许基于密码的身份验证。相反,用户可以使用公钥/私钥对进行访问。使用这种方法,密码不会通过网络传输,而那些没有与接受的公钥匹配的私钥的用户将不被允许访问。这是我向每个人推荐的做法。不利的一面是,它也带来了最多的管理开销。要实施此更改,每个用户都需要使用以下命令为 SSH 生成密钥对:
ssh-keygen
您将被要求回答几个问题,其中大多数问题您可以保持默认设置。对于密码短语,请想出一个独特的短语,并确保它与您的密码不同。如果您不想在进行连接时被要求输入密码短语,可以将其留空,但我建议创建一个密码短语。
接下来,配置服务器以允许您通过密钥连接的最简单方法是在禁用密码身份验证之前将该密钥导入服务器。要做到这一点,请使用以下变体:
ssh-copy-id -i ~/.ssh/id_rsa.pub myserver.mynetwork.com
在这一点上,您将被要求使用普通密码登录服务器。然后,下次连接时,您将默认使用您想出的密钥对,并且如果您创建了密码短语,系统将要求您输入密码短语。
在所有用户生成并将其密钥导入服务器后,您可以实施此更改。在 SSH 配置文件中查找类似以下内容的行:
PasswordAuthentication yes
只需将该选项更改为 no,重新启动 SSH,您就可以了。这样做的原因是,当您使用ssh-copy-id
命令复制 SSH 密钥时,它实际上是在将本地计算机上的公钥(~/.ssh/id_rsa.pub
)的内容复制到远程计算机上的~/.ssh/authorized_keys
文件的末尾。禁用密码身份验证后,SSH 将检查那里列出的密钥是否与您的私钥(~/.ssh/id_rsa
)匹配,然后允许您访问。
通过这些调整,您的 SSH 实现应该是相当安全的。如果您使用弱密码或密码短语,它肯定不会帮助您,但这些是您应该在所有服务器上采取的一般步骤。
配置 iptables 防火墙
默认情况下,Linux 包括一个防火墙iptables。这个防火墙应该在大多数(如果不是所有)Linux 发行版上自动可用。在这个小活动中,我们将在我们的 Linux 系统上设置一个防火墙。无论你使用哪个主要的发行版,这应该都可以正常工作,但我会指出可能是特定于发行版的任何内容。不过,在我们开始之前,我建议你在测试机器上玩一下,比如虚拟机或者你可以物理访问的东西。如果你使用 SSH,在我们启用防火墙时可能会断开连接,尽管我会按照一个不会断开你连接的顺序提供这些步骤。无论如何,有一个专门的测试机器来玩耍是一个好主意。
有了这个,让我们开始吧。不幸的是,默认情况下,iptables
是完全开放的。事实上,它是如此开放,以至于什么都不阻止。要自己看一下,以 root 身份发出iptables -L
。你的输出可能看起来像这样:
Chain INPUT (policy ACCEPT)
Chain FORWARD (policy ACCEPT)
Chain OUTPUT (policy ACCEPT)
你在这里看到的是iptables
的三个链,分别对应输入、输出和转发。如果你还没有配置这个(并且你的发行版没有提供任何默认配置),你可能会看到每个的默认策略都是ACCEPT
,这意味着它允许一切。
我喜欢实施的第一条规则之一是允许 SSH:
# iptables -A INPUT -i eth0 -p tcp --dport 22 -j ACCEPT
通过这个命令,我们在接口eth0
上的INPUT
链上附加了一个新规则(-A
),使用 TCP 并接受来自dport
(目标端口)22
的流量。如果你之前更改了 SSH 端口,请确保相应地调整这个命令。另外,如果你的接口不是eth0
,也要进行更改。当然,我们的防火墙无论如何都允许任何东西,因为我们从未更改过默认策略。如果你还记得,它默认接受一切。让我们用以下命令来改变这一点:
# iptables -P INPUT DROP
# iptables -P FORWARD DROP
# iptables -P OUTPUT DROP
现在,如果我们查看iptables -L
的输出,我们应该看到默认策略是在所有内容上都是DROP
,并且允许 SSH。
然而,有一个问题——我们无法做其他任何事情。我们已经无法安装软件包。实际上,我们根本无法在互联网上做任何事情。例如,尝试 ping 谷歌。你做不到。如果你跟着做了,我们将默认策略设置为DROP
,这确实意味着DROP
。除了 SSH 之外,目前不允许服务器之间或服务器之外的任何流量。为了恢复网络连接,我们需要允许更多的东西。首先,让我们允许 DNS,它使用端口53
:
# iptables -I INPUT -s 10.10.96.0/22 -p udp --dport 53 -j ACCEPT
# iptables -I OUTPUT -s 10.10.96.0/22 -p udp --dport 53 -j ACCEPT
在这里,我们允许端口53
,但只允许我们内部的10.10.96.0/22
网络。请注意,DNS 使用 UDP,所以我们在命令中包含了-p udp
。不用说,但根据你的网络方案调整10.10.96.0/22
部分。
在这一点上,我们的系统比我们想要的还要严格一些。例如,我们现在有了 DNS,但如果不允许端口80
和443
,我们将无法浏览互联网。让我们接下来处理这个问题。
# iptables -A INPUT -i eth0 -p tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT
# iptables -A OUTPUT -o eth0 -p tcp --dport 80 -m state --state ESTABLISHED -j ACCEPT
# iptables -A INPUT -i eth1 -p tcp --dport 443 -m state --state NEW,ESTABLISHED -j ACCEPT
# iptables -A OUTPUT -o eth1 -p tcp --dport 443 -m state --state ESTABLISHED -j ACCEPT
从这一点开始,你应该能够在这台机器上浏览互联网并通过 SSH 访问它,尽管其他端口和服务不应该是可访问的。如果问题机器是一个路由器,你可能也想配置端口转发。这是一个端口转发的例子:
# iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 65254 -j DNAT --to-destination 10.10.96.10
在这个例子中,我们将在端口65254
上接收的流量转发到10.10.96.10
。如果你有类似 SSH 的东西在除22
之外的端口上可用,并且想要能够使用该端口访问一台计算机(在这种情况下是10.10.96.10
),这个例子就很有用。服务器现在将在该端口接收到的流量转发到该计算机。这使用了PREROUTING
的概念,它处理传入的数据包,并能够通过 NAT 重新分配它们。在这种情况下,我们使用防火墙创建一个 NAT 规则,将这些流量发送到适当的位置。
如果您要在设置此防火墙的服务器上成为路由器,您还需要启用接口之间的路由。我们在上一章中已经从 Linux 级别处理了这个问题,但由于我们将防火墙配置为默认情况下DROP
一切,我们不能再这样做了。为了继续在接口之间进行路由,我们还需要在我们的防火墙中启用路由。为此,我们可以使用以下命令:
# iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
# iptables -A FORWARD -i eth1 -j ACCEPT
在上一个命令中,我们允许在eth0
和eth1
接口之间进行路由。调整前面的命令以适应您的发行版网络接口命名方案,以使其适应您的环境。我们还使用POSTROUTING
,在iptables
方面,这是出站流量的另一个说法。
可能有用的另一个更改是允许 ping。根据我们目前的配置,ICMP ping 数据包被阻止。如果您 ping 您的服务器,您将得不到响应。我们可以通过以下命令重新启用 ping 响应。请确保更改 IP 地址以匹配您的服务器:
# iptables -A INPUT -p icmp --icmp-type 8 -s 0/0 -d 10.10.96.1 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
# iptables -A OUTPUT -p icmp --icmp-type 0 -s 10.10.96.1 -d 0/0 -m state --state ESTABLISHED,RELATED -j ACCEPT
如果由于某种原因您犯了错误,或者您想重新开始这个活动,可以使用以下命令来刷新(重置)iptables
防火墙:
# iptables –flush
请注意,这不会撤消您的默认策略,如果您希望撤消到目前为止所做的一切,可以将默认策略明确设置为ACCEPT
。我们可以使用以下命令将每个表设置为其默认值(ACCEPT
):
# iptables -P INPUT ACCEPT
# iptables -P FORWARD ACCEPT
# iptables -P OUTPUT ACCEPT
我们选择DROP
作为默认策略,因为在这种模式下,防火墙在拒绝流量时不会向发送主机发送状态响应。在某种意义上,当策略设置为DROP
时,数据包被发送到一个无尽的黑洞,几乎就好像没有响应。这是一件好事,因为坏人可以利用从服务器收到的响应更好地针对他们的攻击。最好是他们根本得不到任何响应。
因此,随意使用iptables
进行尝试,直到您能够执行通常能够执行的所有任务为止。一旦您有一个工作正常且经过充分测试的防火墙,就该保存配置了。否则,当您重新启动时,所有这些辛苦工作都会丢失。使用以下命令保存您的防火墙配置:
# iptables-save > /etc/iptables.rules
要导入这些规则,我们可以使用以下命令:
# iptables-restore < /etc/iptables.rules
您可能希望这些更改在系统启动时自动恢复。Debian 和 CentOS 都有各自的方法来实现这一点。以下是保存规则的方法。
在 Debian 中,首先保存规则,就像我们之前做的那样:
iptables-save > /etc/iptables.rules
接下来,创建以下文件:
/etc/network/if-pre-up.d/iptables
在该文件中,放入以下文本:
#!/bin/sh
/sbin/iptables-restore < /etc/iptables.rules
在 CentOS 中,执行以下命令:
# iptables-save > /etc/sysconfig/iptables
从这一点开始,每次重新启动服务器时,您的防火墙规则应该会持久保存。
使用 fail2ban 保护系统服务
防火墙是一件很好的东西,但它对允许的服务的保护作用不大。防火墙只允许或不允许访问。但一旦允许访问某项服务,其安全性取决于其配置以及是否存在任何安全漏洞。一个值得安装的服务是fail2ban,这是一个很好的小工具,可以在后台运行,并监视您的日志是否有异常情况,比如多次尝试访问某项服务失败。fail2ban
最常见的用途是保护 SSH 免受尝试暴力破解的攻击。在很多方面,fail2ban
是denyhosts的继任者,它们的功能基本相同。但fail2ban
能够保护的服务不仅仅是 SSH,另一个例子是 Apache。
当fail2ban
发现某个来源正在尝试访问服务并失败时,它将即时设置防火墙规则来阻止该服务从您的服务器访问。首先,在服务器上安装fail2ban
软件包。在 Debian 系统中,这在默认存储库中可用。CentOS 系统将在我们过去设置的epel
存储库中找到此软件包。安装后,如果尚未使用以下命令启用并启动它:使用systemctl
。
# systemctl start fail2ban
# systemctl enable fail2ban
在/etc/fail2ban
目录中,您应该看到主配置文件jail.conf
。将此配置复制到本地副本是个好主意,因为如果您编辑jail.conf
,可能会被包升级覆盖。如果fail2ban
服务找到jail.local
,它将读取它,并且如果被升级,不会覆盖它:
# cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
现在我们有了本地副本,我们可以配置它来保护我们的服务。让我们从 SSH 开始。为此,请在文本编辑器中打开/etc/fail2ban/jail.local
,并查找[ssh]
部分。在我的系统中,这个部分看起来是这样的:
[ssh]
enabled = true
port = 65256
filter = sshd
action = iptables[name=SSH, port=65256, protocol=tcp]
logpath = /var/log/auth.log
maxretry = 6
如您所见,配置相当简单易懂。第一行启用了 SSH 监狱,它使用sshd
过滤流量,并在/var/log/auth.log
中查找与 SSH 相关的消息。虽然您可能已经注意到,我们需要在此文件中调用 SSH 端口。如果您坚持使用端口 22,可以将文件中相关部分保持原样。但是,如果您将 SSH 端口更改为其他端口,请务必相应调整。SSH 的端口有两个地方需要设置,第一个在第三行,第二个在第五行。
现在我们已经配置好了,我们可以重新启动fail2ban
来开始为我们保护 SSH:
# systemctl restart fail2ban
查看其他我们可能想要启用的服务的配置文件。例如,我们的 Web 服务器可能是 Apache,甚至如果您已经设置了 NGINX。默认配置文件包含许多示例供您使用。要使用其中一个,只需将enabled = false
更改为enable = true
,然后重新启动fail2ban
。
理解 SELinux
安全增强型 Linux(SELinux)是一个旨在通过执行强制访问控制来增加安全性的内核模块。这个概念让您可以控制确保用户和应用程序只能访问他们绝对需要完成任务的东西。虽然防火墙有助于保护系统免受外部入侵,但 SELinux 有助于防止内部资源执行不应该执行的操作。这可能听起来模糊,因为这是 SELinux 的用法,您如何从中受益完全取决于您如何实施它。想要防止用户使一个非常私人的文件变为可全球读取?当然可以。也许确保 Apache 无法访问/var/www
之外的文件?也可以。没有 SELinux,您将完全依赖于组和用户权限。SELinux 通过添加额外的安全层来帮助您实施更精细的安全限制。
SELinux 不是任何一个发行版的专属功能,尽管您最常见的是在 Red Hat、Fedora 和 CentOS 系统上安装它。在 Debian 等系统中,如果您希望使用它,您需要安装selinux
。不幸的是,在撰写本文时,由于一个必需的包(selinux-policy-default
)包含的错误没有及时修复,SELinux 在 Debian 中无法正常工作,因此这个包被省略在官方的 Debian 8.x“Jessie”存储库中。然而,在 Debian 中安装 SELinux 的过程(如果此包在发布后变得可用)就是安装该包以及selinux-basics
。安装这些包后,您应该能够通过运行以下命令并重新启动系统来完成 SELinux 的安装:
# selinux-activate
# systemctl enable selinux-basics.service
SELinux 通过策略来确定是否允许某个操作。策略是使用存在于所谓的SELinux 用户空间中的工具创建的,实际检查是在内核层进行的。每个默认实现 SELinux 的发行版通常都会配备经过测试和支持的一套策略,以确保您合理期望的所有服务都能正常运行。如果没有默认的策略集,手动配置 SELinux 可能会非常麻烦(如果它甚至能启动的话)。正如前面提到的,目前 Debian 的策略包不是主要存储库的一部分,因此在 Debian 中启用 SELinux 可能会很混乱。不过,在 CentOS 的情况下,您需要使用 SELinux 的所有内容都将可以直接使用。实际上,除非您已禁用它,否则您已经在使用它!
SELinux 有三种操作模式,分别是强制执行,宽松和禁用。默认情况下,我最近看到的大多数安装都设置为强制执行
,但您可以通过执行sestatus
来查看您的设置是哪种模式。
在 CentOS 上的 sestatus 输出
在强制执行
模式下,SELinux 配置为启用其策略,并将对违反策略的任何操作进行处理。如果发生违规行为,SELinux 将阻止该操作并记录下来。在宽松
模式下,操作不会被阻止,但仍会记录下来,以便您稍后自行审计服务器。禁用
状态是不言而喻的;在该模式下,SELinux 将在禁用时不会阻止或记录任何操作。管理员通常会简单地禁用 SELinux,认为它会在合法用例受阻时成为负担。但除非您绝对必须这样做,否则不建议禁用 SELinux,因为它是您可以从中受益的另一层安全性。至少,您可能希望从宽松
模式中受益,以便在服务器上出现可疑情况时可以获得更多信息。
要在运行时更改 SELinux 的操作模式,请使用setenforce
命令。例如,使用setenforce Enforcing
将模式更改为强制执行
。通过setenforce
进行的更改不是永久的。一旦重新启动计算机,模式将切换回默认模式或您在配置文件中配置的模式。永久更改模式的配置文件是 Red Hat 风格发行版中的/etc/sysconfig/selinux
文件,或者在 Debian 中是/etc/selinux/config
。该文件允许您配置两个主要设置来确定 SELinux 的配置方式,即模式和类型。要永久更改任一设置,请更新此文件并重新启动服务器。我们已经讨论了模式(可以设置为强制执行
,宽松
或禁用
),而类型是我们配置 SELinux 要使用的策略。这可以设置为targeted
,minimum
或多级安全(mls
)。
关于更新策略,targeted
是默认情况下新安装(至少在涉及 Red Hat/CentOS 时)使用的进程。它得到 Red Hat 的全面支持。在这个策略中,每个进程都在一个称为unconfined_t
的类型下运行,实际上根本没有受到限制。相反,进程将在 Linux 本地的DAC(Discretionary Access Control的缩写)下运行,这使它们与其他进程隔离,以帮助遏制可能被破坏的任何内容。MLS,或多级安全,在启用时会为对象分配一个敏感度等级,由s0
指定。(通过执行sestatus
,您可以看到 MLS 是否已启用)。我们很快将看到一些上下文输出的示例。在最小类型中,只有我们明确选择的进程才会受到保护。
SELinux 启用系统中的每个资源都包含一个标签,这是 SELinux 识别资源并了解如何监管它的方式。您可以通过使用-Z
参数与一个或多个命令(如ls
、id
或ps
)来自己查看这些标签(也称为上下文)。这个特殊的参数仅在系统配置为使用 SELinux 时才对这些命令可用,并且它允许您查看上下文作为正常输出的一部分。例如,您可以在 SELinux 系统上使用ls
命令与-Z
参数,您会看到如下输出:
-rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 myfile
通常,ls
命令的输出会包含诸如修改日期和大小等字段,当查看ls
命令的输出时。但是,-Z
参数是特殊的。它意味着您想要查看命令的输出与 SELinux 相关,而不是通常获得的输出。您还可以尝试使用id
(id -Z
)和ps
(ps auxZ
)来查看这些命令的输出,以及它们的 SELinux 上下文。
标签包含多个字段。在我粘贴的ls
命令的输出中,我们可以看到字段unconfined_u
、object_r
、admin_home_t
和s0
。为了更好地理解这一点,看一下每个字段的最后几个字符。_u
表示用户,_r
表示角色,_t
表示类型。因此,我们可以从之前的输出中看到,名为myfile
的文件具有unconfined_u
的用户上下文;它被分配了object_r
的角色和admin_home_t
的类型。让我们看另一个例子。在我的 CentOS 系统上,通过ps auxZ
命令的输出中,我看到了我的 SSH 会话的以下行:
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 jay 20575 0.0 0.0 135216 2080 ? S 10:40 0:00 sshd: jay@pts/0
再看一下行的开头,我们再次看到用户、角色和类型的上下文。在这种情况下,每个都被命名为 unconfined,但我们可以通过最后两个字符来判断哪个是哪个。
类型是输出中最重要的部分,因为这是 SELinux 执行其强制执行的方式。根据类型,SELinux 知道如何限制(或不限制)对象。在第一个示例中,我们有admin_home_t
,在第二个示例中我们有unconfined_t
。从中我们可以得知,SELinux 并未对我的 SSH 会话(unconfined_t
)执行任何强制,但对我的主目录有一个特定的策略,这也是文件输出的来源。我们在示例输出中看到的另一个上下文是角色,由后缀_r
指定。应用角色时,SELinux 能够将各种上下文组合在一起,并一次性将它们应用到用户对象上。这使得更容易指定用户能够做什么以及他们如何与其他对象进行交互。
有几个命令可以用来重新标记对象的上下文信息。首先是chcon
命令。chcon
命令使用-t
参数,该参数指定您要将对象更改为的类型,后跟对象的名称:
# chcon -t admin_home_t myfile
使用-R
,我们告诉chcon
命令递归地进行更改,这对于更改目录的上下文非常有用。此外,如果您想更改角色而不是类型,还可以使用-r
。如果您犯了错误或者想要恢复更改,restorecon
正是这样做的。restorecon
命令将对象恢复到其策略中定义的默认状态。管理 SELinux 的另一个命令是semanage
。使用此命令,我们可以对对象的处理和标记进行永久更改。需要注意的是,通过chcon
进行的更改可能并不总是持久的。虽然通过chcon
进行的更改可能会在重启后生存,但如果文件系统被重新标记,它们将持久存在。semanage
命令允许我们使这些更改更加持久。使用semanage
,我们可以更改文件上下文、用户映射以及用户上下文。
首先,将用户jdoe
映射到sysadm_u
SELinux 用户的示例:
# semanage login -a -s sysadm
接下来,这是使用fcontext
和semanage
的示例,我们可以更改文件对象所属的类型:
# semanage fcontext -a -t admin_home_t myfile
查看semanage
的 man 页面,了解更多示例。SELinux 是一个庞大的主题,已经有整本书专门写了。完整的 SELinux 演练需要多个章节,但这里提供的信息应该足够作为一个适当的入门。当正确实施时,它可以极大地增强服务器的安全性。
配置 Apache 以利用 SSL
第七章 通过 Apache 托管 HTTP 内容是关于 Apache 的。在那里,我们介绍了如何运行和配置它以在我们的网络上托管站点。但是,如果我们要创建一个可能托管个人可识别信息的站点,我们需要确保使用适当的安全措施来保护这些信息。为我们的站点使用SSL证书可以使其通过安全端口 443 访问,从而增强安全性。利用 SSL 并不是我们可以采取的唯一措施来增加我们的 Web 服务器的安全性,但这绝对是一个开始。
我们可以使用两种类型的证书。我们可以创建自签名证书,或者我们可以向证书颁发机构(CA)注册证书。后者更受青睐,尽管如果您只是为内部使用创建站点,可能会有太多的开销。区别在于自签名证书不受任何浏览器信任,因为它不是来自已知 CA 的。当您访问具有此类证书的站点时,它会抱怨该站点的证书无效。这并不一定是真的,因为自签名证书肯定是有效的;只是浏览器无法确定。注册 CA 的证书可以解决这个问题,但需要付出代价。注册证书的价格可能会很昂贵,具体取决于范围。选择权在您手中。
注意
在 Debian 系统上,确保使用以下命令启用 SSL:
# a2enmod ssl
首先,您需要选择 Web 服务器文件系统上将托管证书文件的位置。这里没有硬性规定,唯一的要求是 Apache 可以访问它(最好其他人不能!)。一些好的候选包括 Debian 中的/etc/apache2/ssl
和 CentOS 中的/etc/httpd/ssl
。我把我的放在/etc/certs
中。无论您选择哪个路径,请切换到该目录,然后我们将继续。
如果您决定创建自签名证书,可以使用以下命令:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout server.key -out server.crt
在生成您的证书时,您将被要求提供有关您的组织、联系信息和域的一些信息。以下是您将被问到的问题和一些示例答案:
-
国家名称:美国
-
州或省名称:密歇根
-
地点名称(城市):怀特湖
-
组织名称:我的公司
-
组织单位名称:IT 部门
-
通用名称(完全合格的域名):myserver.mydomain.com
-
电子邮件地址:webmaster@mycompany.com
这将在您当前的工作目录中为您创建两个文件,server.key
和server.crt
。这些文件的文件名是任意的,您可以随意命名。现在,我们需要确保我们的 Web 服务器能够找到并使用这些文件。
在 Debian Web 服务器上,我们可以通过编辑/etc/apache2/sites-available/default-ssl.conf
来实现这一点。在该文件中,将有一个部分供我们添加启用密钥的指令。查找一个有关 SSL 的注释的部分,在该部分中添加以下行:
SSLCertificateFile /etc/certs/server.crt
SSLCertificateKeyFile /etc/certs/server.key
在 CentOS 中,我们将在/etc/httpd/conf/httpd.conf
文件中添加相同的行,但同时也要加上SSLEngine on
指令。这应该放在自己的VirtualHost
指令中,类似于以下示例。只需确保更改路径以匹配您的 Web 服务器的设置:
<VirtualHost *:443>
SSLEngine On
SSLCertificateFile /etc/certs/server.crt
SSLCertificateKeyFile /etc/certs/server.key
SSLCACertificateFile /etc/certs/ca.pem (Only include this line if the certificate is signed).
DocumentRoot /var/www/
</VirtualHost>
设置签名 SSL 证书类似,但不同之处在于您请求它的方式。该过程涉及创建一个证书请求(CSR),您将提交给您的提供商,提供商将为您提供一个签名证书。最终结果是相同的——文件最终会出现在同一个位置。您只需在提交 CSR 后使用提供商给您的文件。让我们开始创建一个 CSR,我们将使用openssl
命令为我们生成:
openssl req -new -newkey rsa:2048 -nodes -keyout server.key -out server.csr
您将被问到与之前相同的问题,但请注意,我们告诉openssl
给我们一个.csr
,所以我们将在我们的工作目录中有一个server.csr
文件,我们将使用它来向我们的 CA 请求一个密钥。在您从证书提供商那里收到文件之后,您只需像之前一样更新 Apache。
部署安全更新
虽然对于那些在安全方面更有经验的人来说,更新您的分发似乎是常识,但请注意,更新是有原因的。在某些情况下,更新只是为了添加新功能或将软件更新到最新版本。但对于 CentOS 和 Debian 等企业分发来说,这些更新甚至更加重要。
这是消费者分发和企业分发之间的一种区别。像 Ubuntu 的非 LTS 版本、Linux Mint 和 Fedora 这样的分发,比如 CentOS、Debian 和 Red Hat 这样的企业分发,会收到更多的前沿软件包。这是因为最终用户通常希望他们的网络浏览器、电子邮件客户端、文字处理器或游戏的最新版本。但在企业中,这并不重要。在企业中,安全更新至关重要。虽然面向消费者的分发在大多数情况下肯定会与安全补丁保持同步,但这些补丁会与可能会损害稳定性而不是帮助稳定性的功能更新混合在一起。
在 Debian 的情况下,实际上提供了两种风格。被称为Debian stable的主要发行版几乎只接收安全补丁。甚至默认的网络浏览器(Iceweasel)的更新频率也不如其他平台上的 Firefox。这里的想法是,改变代表着潜在的破坏。为了确保您在稳定版中获得的软件包经过了充分的测试,而不是最新和最好的,付出了相当大的努力。这个概念在 CentOS 中也是类似的,尽管它的软件包通常比 Debian 中的软件包更老。举个例子,我写这一章节时,最新的 Linux 内核是 4.1。Debian Jessie(最新的“稳定版”)包括内核 3.16,而 CentOS 7 甚至更老,是 3.10。老内核并不是什么问题,我只是举个例子。红帽和 Debian 都有更前沿的发行版可用。Fedora由红帽赞助,包括更更新的软件包。它面向那些喜欢拥有最新软件的用户。Debian testing也包括更更新的软件包,尽管它不像 Fedora 那样稳定,偶尔会出现软件包破坏。Debian testing 面向那些想要测试下一个 Debian 发布版的人,因为 Debian testing 最终会成为新的 Debian 稳定版。
出于安全目的,安装最新的安全更新至关重要。Linux 确实比许多其他平台更安全和稳定,但无论操作系统有多安全,归根结底,它的安全性取决于管理方式。如果安装了滞后更新的 Linux 发行版,一旦发现可利用的漏洞,它就会成为易受攻击的目标。
考虑到终端用户和企业发行版的存在,管理它们的安全更新可能是一个挑战。如果您的组织在服务器和终端用户设备上都使用 Linux,您很可能会同时使用这两种类型的发行版。这是因为尽管 CentOS 安全稳定,但您不太可能成功地将其部署到终端用户设备上。由于 CentOS 内核较老,它不支持今天可用的所有新硬件。此外,也没有太多的定制来使其适合台式机或笔记本电脑使用。虽然可以做到(许多人都这样做),但在终端用户设备上安装 CentOS 通常是一种令人沮丧的经历。对于终端用户设备,您可能会选择 Ubuntu、Linux Mint 或 Fedora。但对于这些发行版,您需要花更多的时间关注哪些更新是安全更新,哪些更新是应用程序的新功能。根据更新的性质,您可能会选择以不同的方式推出更新。
理想情况下,在一个完美的服务器房间里,服务器的所有更新都会在发布后立即安装,永远不会出现任何问题,一切都会顺利进行。但现实中,保持安全更新的挑战很大。也许会出现导致重要应用程序无法运行的回归。或者,也许在打包过程中出现错误,实际上破坏了 RPM 数据库(这是一种极其令人沮丧的经历!),因此,虽然更新很重要,但也需要谨慎行事。
最好的策略,或者至少我发现对我来说效果很好的一个策略,是创建测试服务器,可以用来在将更改推出到生产环境之前进行测试。在虚拟机服务器的情况下,甚至可以克隆生产服务器并在其上测试更新或其他更改,以查看它们在推出到生产环境时会有什么反应。然后,您可以相当有信心地认为新的更新不会破坏生产服务器。公平地说,这些类型的情况很少发生。但鉴于 Linux 的灵活性以及 Linux 服务器易于克隆,没有理由不进行测试。
在 CentOS 系统中,您可以使用yum update
命令来更新服务器上的所有软件包。您可以使用yum update
以及软件包名称来仅更新该软件包。在 Debian 系统中,您可以使用apt-get update
来刷新您的源,然后您可以使用apt-get install
加上软件包名称来更新软件包。要更新所有内容,您需要更新您的源,然后运行apt-get dist-upgrade
。
在实际安装中,您可能不会更新服务器上的所有可用软件包。相反,一种方法是根据需要更新软件包。这需要管理员进行大量的研究,以关注当前的安全趋势,然后选择影响当前在生产中使用的服务的安全更新。对于基于 Debian 和 Red Hat 的系统,有两个与通用漏洞和暴露(CVE)相关的方便的网站,您应该将其加为书签。
对于 Red Hat,请使用以下 URL:
access.redhat.com/security/cve/
对于 Debian,请使用以下 URL:
security-tracker.debian.org/tracker
两个网站都允许您查看单独的 CVE 报告,这将告知您有关受影响软件包以及它们是否已经修补的信息。在某些情况下,CVE 甚至可能在您特定的发行版中无法被利用,这种情况下您就不需要做任何事情。但是通过遵循这些报告,您可以就潜在的漏洞可能影响您的组织做出明智的决定。这将使您能够制定一个计划,将必要的补丁推出到您的服务器上。
摘要
安全是一个非常复杂的主题。如此复杂,以至于没有一个人可以成为全知的专家,即使是行业中的顶尖人物也在不断学习。同样,创建一个无法被破坏的防弹服务器是统计上不可能的。但作为网络管理员,您有责任尽力使您的节点尽可能安全。安全通常是一种反应性的,这需要您保持警惕。在本章中,我们探讨了一些帮助您保护网络免受风险的方法。我们涵盖了诸如保护 SSH、限制攻击面、使用 SSL 保护 Apache、fail2ban 和部署安全更新等概念。
在下一章中,我们将探讨当出现问题时您可以采取的解决方法。