Linux-秘籍第二版-全-

Linux 秘籍第二版(全)

原文:zh.annas-archive.org/md5/2408bbc59add029ed383a213c2365503

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

在很久以前,我写了Linux Cookbook的第一版,它于 2004 年面世。它卖得很好,我收到了许多读者的喜悦反馈,其中一些至今仍是我的朋友。

对于一本 Linux 书籍来说,17 岁就已经相当古老了。2004 年 Linux 有 14 岁,是一个婴儿般的计算机操作系统。即便如此,它已经是一个流行且广泛使用的强大系统,适应任何角色,从微型嵌入式设备到大型机和超级计算机。Linux 的迅速发展部分原因是它是 Unix 的免费克隆,Unix 是历史最悠久和功能最强大的操作系统。Linux 快速增长和广泛采纳的另一个主要因素是没有障碍。任何人都可以下载和尝试使用它,源代码对任何希望使用和贡献的人都是自由开放的。

那时,它是形式服从功能的一个很好的例子,就像我的第一辆车。它能跑,很可靠,但不够漂亮,需要大量定制的摇摆和摆弄来保持运行。当时运行 Linux 系统意味着要学习各种命令、脚本和配置文件,并且需要大量的手动操作和持续学习。软件管理、存储管理、网络、音频、视频、内核管理、进程管理……所有这些都需要大量的实际操作和不断的学习。

17 年后,Linux 中的每个重要子系统都有了显著的改进和变化。现在,我们用所谓的“它只是工作的子系统”取代了所有那些基本管理的手动操作。运行 Linux 系统的每个方面都更加简单,我们可以专注于利用 Linux 做一些酷炫的事情,而不是为了维持其运行而不得不摇摆不定。

我很高兴向您介绍这本大大更新的Linux Cookbook第二版,希望您喜欢了解所有这些新鲜和精彩的内容。

适合阅读本书的人

这本书适合有一些计算机经验的人士,尽管不一定要有 Linux 经验。我已经尽力使其对 Linux 初学者尽可能易于理解。您应该理解一些基本的网络概念,如 IP 地址、以太网、WiFi、客户端和服务器。您应该了解基本的计算机硬件,并且有一定的命令行使用经验。如果您需要帮助,有大量资源可以学习这些内容;我不想陷入教授已经充分记录的材料之中。

这本书中的食谱都是实践性的。我希望读者第一次尝试就能成功,但如果没有成功也不要感到难过。一般用途的 Linux 计算机是一个非常复杂的机器,有很多东西需要学习。要有耐心,花时间多读一些。很可能你想要的答案就在几句话之内。

每个 Linux 系统都内置了命令的文档,称为man 页(缩写为“手册页”)。例如,man 1 ls记录了ls(或列出目录内容)命令。按照本书中显示的命令精确输入,即可打开正确的 man 页。你也可以在网上找到这些信息。

为什么写这本书

我长期以来一直想写一本像这样的书,集结我认为是最必要的 Linux 技能。Linux 无处不在,无论你在哪里找到它,Linux 都是 Linux,所需的技能是相同的。科技世界变化快速,我认为你会发现这本书提供了一个坚实的基础,无论你的兴趣方向如何,都可以在此基础上建立。

烹饪书籍的格式特别适合教授基础知识,因为它展示了如何解决特定的现实世界问题,并将详细的解释与完成任务所需的步骤分开。

浏览本书

本书不是一个正式的培训课程,你不需要从头开始,可以随时跳进去,希望能找到你所需的内容。

大致上组织如下:

  • 第一章、2 章和 3 章涵盖了安装 Linux、管理引导加载程序、停止和启动,解答了“我从哪里获取 Linux 并让它运行”的问题。

  • 第四章介绍了使用 systemd 管理服务,这是与旧有学习各种脚本、配置文件和命令方式相比的一大进步。

  • 第五章涵盖了用户和组的管理,第六章讲述了文件和目录的管理,第七章介绍了备份和恢复。这三章对系统操作和安全至关重要。

  • 第八章、9 章和 11 章都涉及分区和文件系统,这些对于数据存储管理至关重要。数据管理是计算的最重要方面。

  • 第十章非常有趣。这一章节讲述了如何在不打开机箱的情况下获取计算机硬件的详细信息。现代 PC 硬件能够自动报告大量信息,Linux 通过额外信息的数据库补充这些自动报告。

  • 第十二章和 13 章教授了如何设置安全的远程访问,第十四章介绍了出色的 firewalld,这是一个动态防火墙,能轻松处理各种复杂情景,如在不同网络之间漫游和管理多个网络接口。

  • 第十五章介绍了 CUPS(通用 Unix 打印系统)的新功能,包括“无驱动”打印,特别适合移动设备,因为它们可以连接到打印机而无需下载大量软件。

  • 第十六章展示了如何使用优秀的 Dnsmasq 控制您自己的局域网名称服务。Dnsmasq 通过支持新协议和保持旧命令和配置选项不变而保持当前。它是一个一流的名称服务器,无缝集成了 DNS 和 DHCP,用于集中管理 IP 地址和广告网络服务。

  • 第十七章介绍了 chrony 和 timesyncd,这两个新的网络时间协议(NTP)实现。还包括旧的经过试验和真实检验的ntp服务器和客户端。

  • 第十八章介绍了在树莓派上安装 Linux,这款流行的廉价单板计算机,并利用它构建互联网防火墙/网关。

  • 第十九章展示了如何使用 SystemRescue 重置丢失的 Linux 和 Windows 密码,救援无法启动的系统,救援故障系统上的数据,并定制 SystemRescue 使其更加实用。

  • 第二十章和 21 章介绍了基本的故障排除,重点是搜索日志文件、探测网络以及探测和监控硬件。

  • 附录包含管理软件安装和维护的速查表。

本书使用的约定

本书中使用以下排版约定:

斜体

表示新术语、URL、电子邮件地址、文件名和文件扩展名,以及指向程序元素,如 Linux 变量或函数名、数据库、数据类型、环境变量、语句和关键字。

等宽字体

用于程序清单和某些命令选项。

等宽字体粗体

显示用户应直接输入的命令或其他文本。

等宽字体斜体

显示应由用户提供的值或由上下文确定的值应替换的文本。

提示

此元素表示提示或建议。

注意

此元素表示一般注意事项。

警告

此元素表示警告或注意事项。

使用代码示例

本书旨在帮助您完成工作任务。一般情况下,如果本书提供示例代码,您可以在您的程序和文档中使用它。除非您复制了代码的大部分内容,否则无需征得我们的许可。例如,编写使用本书多个代码片段的程序无需许可。销售或分发来自奥莱利图书的示例则需要许可。引用本书并引用示例代码回答问题无需许可。将本书大量示例代码整合到您产品的文档中则需要许可。

我们感谢,但通常不要求署名。署名通常包括标题、作者、出版社和 ISBN。例如:“Linux Cookbook,第二版,Carla Schroder 著(奥莱利)。版权所有 2021 Carla Schroder,978-1-492-08716-8。”

如果您认为您对代码示例的使用超出了合理使用范围或上述许可,请随时通过permissions@oreilly.com联系我们。

奥莱利在线学习

注意

超过 40 年来,奥莱利传媒 提供技术和商业培训,以及知识和洞察,帮助公司取得成功。

我们独特的专家和创新者网络通过图书、文章和我们的在线学习平台分享他们的知识和专长。奥莱利的在线学习平台为您提供按需访问的实时培训课程、深入学习路径、交互式编码环境以及来自奥莱利和其他 200 多家出版商的大量文本和视频。欲了解更多信息,请访问http://oreilly.com

如何联系我们

请将有关本书的评论和问题寄送给出版商:

  • 奥莱利传媒公司

  • 1005 Gravenstein Highway North

  • Sebastopol, CA 95472

  • 800-998-9938(美国或加拿大)

  • 707-829-0515(国际或本地)

  • 707-829-0104(传真)

我们为本书设置了一个网页,其中列出了勘误、示例和任何其他信息。您可以访问https://oreil.ly/linux-cookbook-2e

发送电子邮件至bookquestions@oreilly.com评论或询问有关本书的技术问题。

欲了解我们的图书和课程的最新信息,请访问http://oreilly.com

在 Facebook 上找到我们:http://facebook.com/oreilly

在 Twitter 上关注我们:http://twitter.com/oreillymedia

在 YouTube 上观看我们:http://www.youtube.com/oreillymedia

致谢

我真的很幸运能得到这本书。我的编辑 Jeff Bleiel 一直非常支持和乐于助人,做出了许多改进,并使整个项目保持有序和顺利进行。如果你觉得管理猫很难,试试做一名图书编辑。

我的实习生凯特·尤尔内斯在这次冒险开始时是一个 Linux 新手,这使她成为了完美的审阅者。她测试了每一个配方,并为配方的准确性和清晰度做出了重大贡献。我们一起喝了很多咖啡,也度过了愉快的时光,这也是一个重要的贡献。

技术编辑丹尼尔·巴雷特非常注重细节,不懈地追求措辞和描述的准确性,并提供了许多改进意见。提供一本充满命令的书很容易,解释它们如何工作却很难。每个作家都应该很幸运能有这样一位技术编辑。

技术编辑乔纳森·约翰逊发现了其他人都忽视的事物,贡献了一些超酷的命令咒语,并提供了幽默感,而我告诉你,我真的需要它。

收购编辑赞·麦克奎德开始了整个疯狂的交易。多年来我们都在谈论更新《Linux Cookbook》,但赞让它成为现实。

特别感谢我的妻子特里,她喂养了骡子、猫、狗和我,给予了我很大的鼓励,并阻止我因为失去理智而同意再写一本书而逃离家庭。

特别感谢我们的猫,公爵夫人(图 P-1),斯塔什(图 P-2)和疯狂麦克斯(图 P-3),它们出现在这本书中。它们通过在我的键盘上睡觉、不让我坐椅子和经常发出神秘的巨响,给了我很大帮助。

公爵夫人为了我自己的好压住了我的脚。

图 P-1. 公爵夫人为了我自己的好压住了我的脚

斯塔什猫,我们的魅力男孩。

图 P-2. 斯塔什猫,我们的魅力男孩

疯狂麦克斯为下一场混战休息。

图 P-3. 疯狂麦克斯为下一场混战休息

第一章:安装 Linux

新 Linux 用户面临的障碍之一是安装 Linux。Linux 是最容易安装的计算机操作系统:插入安装光盘,回答几个问题,然后做其他事情,直到安装完成。在本章中,你将学习如何单独安装 Linux,如何运行 Live Linux,如何在一台计算机上多重引导多个 Linux 发行版,以及如何与 Microsoft Windows 双引导。

尝试 Linux

你需要自由地犯错误,所以如果可能的话,使用第二台计算机来熟悉 Linux。如果这不可能,确保你的数据有新鲜的备份。你可以随时恢复损坏的 Linux 安装,但你的数据是无法替代的。如果要设置与 Windows 的双引导,请确保有 Windows 的安装和恢复介质。

大多数 Linux 发行版提供双重用途的安装镜像:你可以从 USB 硬盘启动并从同一镜像安装到硬盘。Live Linux 不会对你的计算机进行任何更改——只需启动它,查看一下,然后重新启动到你的主机系统。一些 Live Linux,如 Ubuntu,支持将数据存储在 USB 硬盘上,因此你拥有一个完全便携的 Linux,可以在任何计算机上运行。

多重引导是在一台计算机上安装多个操作系统,然后从启动菜单中选择要使用的操作系统。你可以多重引导任何 Linux 系统,任何自由的 Unix 系统(如 FreeBSD、NetBSD、OpenBSD),也可以多重引导 Linux 和 Microsoft Windows。Linux 和 Windows 的双引导是 Windows 用户熟悉 Linux 的常见方式,也适用于需要两者的用户。

你问道:那么苹果的 macOS 呢?抱歉,但是在一台计算机上双引导 Linux 和 macOS 是一种不可靠的尝试,而且随着每个 macOS 版本的发布,变得越来越困难。在同一台机器上运行两者的一个替代方法是在 Parallels 中运行 Linux,这是 macOS 的虚拟机主机。

与其自己安装 Linux,你可以购买已经预装了 Linux 的个人电脑。有许多出售 Linux 笔记本电脑、台式机和服务器的优秀 Linux 专家。System76、ZaReason、Linux Certified、Think Penguin、Entroware 和 Tuxedo Computers 都是 Linux 专家。戴尔一直在扩展其 Linux 产品线,企业 Linux 供应商 Red Hat、SUSE 和 Ubuntu 都与硬件供应商合作,包括戴尔、惠普和 IBM。

但是,了解如何安装 Linux 也是值得的。这将开启一整个实验、定制和灾难恢复的世界。Distro-hopping 是一种历史悠久的消遣,你可以下载和尝试不同的 Linux 发行版。

尽管安装 Linux 只需几个步骤,但在您想要自定义安装时(如以特定方式设置磁盘分区或与其他 Linux 发行版或 Microsoft Windows 多重引导),您需要一定的知识。您需要知道如何进入系统的基本输入输出系统(BIOS)或统一可扩展固件接口(UEFI)设置。您需要良好的互联网访问。所有 Linux 发行版都可以免费下载,即使是商业企业发行版如 Red Hat、SUSE 和 Ubuntu。下载大小从 12 MB 的超小型 Linux 发行版(如 Tiny Core Linux,将完整操作系统和图形桌面捆绑在一起)到 SUSE Linux Enterprise Server 的 10+ GB 不等。大多数 Linux 发行版提供 2-4 GB 的安装镜像,非常适合 DVD 或小型 USB 存储设备。

大多数 Linux 发行版提供网络安装镜像;例如,Debian 的镜像大小约为 200 兆字节。这样安装足以启动 Debian 系统,连接到互联网,然后仅下载你想要的软件包,而不是下载完整的安装镜像。

您可以自由分享任何下载的 Linux 发行版。

你还可以选择购买 DVD 和 USB 媒体上的 Linux 发行版。访问在线 Linux 商店Linux 光盘在线以找到各种 Linux 发行版的物理安装介质。

从安装媒体引导

你必须能够从 USB 或 DVD 安装盘启动系统。你可能需要进入系统的 BIOS 或 UEFI 设置以启用从可移动设备启动。有些设备在不进入 BIOS/UEFI 的情况下可以选择备用启动设备;例如,我的笔记本电脑的 UEFI 在启动时显示一个屏幕,列出所有相关的按键操作:按 F2 或 Delete 进入设置,按 F11 进入备用启动设备菜单。戴尔系统使用 F12 打开一次性启动菜单。每个设备都是特殊且独特的,因此请查阅您的主板手册以了解详情。

您可能需要在 UEFI 设置中禁用安全启动以启用从可移动媒体引导。Fedora、openSUSE 和 Ubuntu 都有自己的签名密钥,并且可以在启用安全启动的情况下引导。其他 Linux 发行版,如 SystemRescue(第十九章),则没有。

安全启动

安全启动是 UEFI 设置的一项安全功能。启用安全启动时,只允许启动提供特殊签名密钥的操作系统。其目的是防止恶意代码控制您的引导加载程序。

大多数 Linux 发行版不提供签名密钥,因此必须禁用安全启动才能运行它们。

Linux 下载位置

有数百种 Linux 发行版,了解它们的好地方是DistroWatch.com,这是最全面的 Linux 发行版资源。DistroWatch 发布评论、详细信息和新闻,并列出了前 100 名最受欢迎的发行版。

新手最佳 Linux 系统

Linux 提供了相当多的好东西,也许有点过多。本书中的配方在 openSUSE、Fedora Linux 和 Ubuntu Linux 上进行了测试。这三者是成熟、流行且得到良好维护的,它们代表了三个不同的 Linux 家族(参见附录)。根据我的经验,Ubuntu 非常适合 Linux 新手,因为它拥有最简单的安装程序、良好的文档和庞大支持的用户社区。

每个 Linux 都有其不同之处:不同的软件安装程序、不同的默认设置、不同的文件位置……但基本原理都是相似的。您在任何特定发行版上学到的大部分内容都适用于所有发行版。

硬件架构

如何作者曾经可以想当然地认为读者在使用 x86 硬件。随着 ARM 处理器的普及,这种情况不再成立了。Linux 支持多种硬件架构,配方 10.11 展示了如何检测您所拥有的硬件。您不能意外安装错误的 Linux 版本,因为安装将在开始时失败,并显示错误消息告知原因。

Linux 安装映像以 ISO 9660 格式打包,并带有**.iso扩展名,例如,对于 x86-64 机器,是ubuntu-20.04.1-desktop-amd64.iso,对于 ARM 机器是ubuntu-20.04.1-live-server-arm64.iso*。这是一个压缩的存档,包含整个文件系统和安装程序。当您将此存档复制到安装介质时,它将被解压缩,您可以看到所有文件。

**.iso*格式最初是用于 CD 和 DVD。曾经,Linux 适合单张 CD 上。(曾经,它适合几个 3.5 英寸软盘!)现在大多数 Linux 发行版都太大了,不适合 CD。USB 存储设备非常适合 Linux 安装,它们价格便宜、可重复使用,比光盘媒体快得多。

1.1 进入系统的 BIOS/UEFI 设置

问题

您希望进入系统的 BIOS/UEFI 设置。

解决方案

通过在启动时按适当的 Fn键进入您的 BIO/UEFI 设置。在戴尔、华硕和宏碁系统上,通常是 F2,而联想则使用 F1. 不过,这会有所不同;例如,某些系统使用 Delete 键,请查看您的机器文档。一些系统在启动屏幕上显示要按哪个键。按对时间有点棘手,所以在按电源按钮后立即开始按键,就像猛按电梯按钮以加快到达速度一样。

每个 UEFI 看起来都不同;例如,联想的亮度和良好的组织结构(参见图 1-1)。

我的测试系统上的 ASRock UEFI 界面深色而戏剧化(图 1-2)。这款特定的主板面向游戏玩家,具有许多 CPU 超频和其他性能增强的设置。此屏幕显示主板浏览器;将光标悬停在任何项目上,它会提供有关该项目的信息。

联想新 ThinkPad 上的 Lenovo UEFI。

图 1-1. 联想新 ThinkPad 上的 Lenovo UEFI

ASRock UEFI 具有主板浏览器。

图 1-2. ASRock UEFI 具有主板浏览器

讨论

当你启动计算机时,第一次启动指令来自存储在计算机主板上的 BIOS 或 UEFI 固件。BIOS 是自 1980 年以来一直存在的旧传统系统。UEFI 是它的现代替代品。UEFI 包括对传统 BIOS 的支持。2000 年代中期后几乎所有的计算机都配备了 UEFI。

UEFI 比旧 BIOS 具有更多功能,类似于一个小型操作系统。UEFI 设置界面控制启动顺序、启动设备、安全选项、安全启动、超频、显示硬件健康状况、网络等许多功能。

参见

1.2 下载 Linux 安装镜像

问题

你需要找到并下载一个 Linux 安装镜像。

解决方案

首先,你需要选择想尝试的 Linux 版本。如果不知道从哪里开始,我推荐Ubuntu LinuxFedora LinuxopenSUSE Linux对于 Linux 新手也是很好的选择。

下载完成后,请验证你下载了一个良好的镜像。这是一个重要的步骤,可以确保你下载的镜像在下载过程中没有损坏或以其他方式被修改。

每个 Linux 发行版都提供签名密钥和下载镜像的校验和。Ubuntu 提供了复制粘贴的验证指令。打开终端并切换到你下载 Ubuntu 的目录。对于 Ubuntu 21.04,验证安装镜像看起来是这样的:

$ echo "fa95fb748b34d470a7cfa5e3c1c8fa1163e2dc340cd5a60f7ece9dc963ecdf88 \
*ubuntu-21.04-desktop-amd64.iso" | shasum -a 256 --check

ubuntu-21.04-desktop-amd64.iso: OK

如果看到“shasum: WARNING: 1 computed checksum did NOT match”,那么你的下载可能有问题,假设你复制了正确的校验和。在大多数情况下,镜像在下载过程中损坏了,因此请尝试重新下载。

其他 Linux 发行版提供略有不同的验证方法,请按照它们的说明进行操作。

讨论

了解数百种 Linux 发行版的一个好网站是Distrowatch.com。Distrowatch 提供关于比任何其他网站更多 Linux 发行版的新闻和信息。

参见

1.3 使用 UNetbootin 创建 Linux 安装 USB 驱动器

问题

你已经下载了一个 Linux 安装**.iso*镜像,并希望将其传输到 USB 存储设备以创建自己的安装介质。你更喜欢使用图形化工具来创建安装介质。

解决方案

尝试使用UNetbootin,通用网络引导安装程序。它可以在 Linux、macOS 和 Windows 上运行,因此你可以在这些操作系统中下载并创建 Linux 安装盘。UNetbootin 可以根据你下载的.iso*文件创建安装 USB 驱动器,或者下载一个新的.iso*文件(图 1-3)。

你可以使用任何大于你的.iso*文件的 USB 存储设备,当然了。.iso文件会覆盖整个设备,因此你不能再用它进行其他用途,并且每个**.iso文件必须使用单独的 USB 存储设备。

使用 UNetbootin 创建可安装的 Linux USB 存储设备

图 1-3. 使用 UNetbootin 创建可安装的 Linux USB 存储设备

UNetbootin 官网提供下载和说明。一些 Linux 发行版提供 UNetbootin 软件包,但从UNetbootin 官网下载更为简单和始终更新。

讨论

其他优秀的图形化应用包括 USB Creator、ISO Image Writer 和 GNOME MultiWriter,后者可以同时复制到多个 USB 驱动器。

在创建了安装 USB 驱动器后,你可以查看其中的文件。单个**.iso*文件会展开为一个完整的文件系统,包含类似 Ubuntu 示例中的文件和目录:

$  ls -C1 /media/duchess/'Ubuntu 21.04.1 amd64'/
boot
casper
dists
EFI
install
isolinux
md5sum.txt
pics
pool
preseed
README.diskdefines
ubuntu

每个 Linux 发行版都以自己的方式设置其安装程序。这个示例展示了 Fedora 的安装文件:

$  ls -C1 /media/duchess/Fedora-WS-Live-34-1-6/
EFI
images
isolinux
LiveOS

拥有一个 USB 存储设备,并载入一群 Linux 安装文件会很不错,而有些程序正是这么做的。我最喜欢的是Ventoy。Ventoy 支持大量 Linux 发行版,可以在 Linux 和 Windows 上运行,你可以使用它创建一个充满 Linux 安装程序的 USB 存储设备,用于运行 Live Linux 和永久安装到硬盘。

参见

1.4 使用 K3b 创建 Linux 安装 DVD

问题

你想要使用图形工具创建 Linux DVD 安装光盘。

解决方案

使用 K3b(KDE 刻录专家)。K3b 是 Linux 下最好的图形化 CD/DVD 写入应用程序。

如果你没有 Linux 系统,可以使用任何能够写入 ISO 9660 镜像的 CD/DVD 写入程序。你选择的 CD/DVD 写入器可能会显示类似“将现有镜像刻录到光盘”的选项。

在 K3b 上你会看到类似图 1-4 的内容。点击“刻录镜像”,并注意左下角的确认信息显示“将 ISO 9660…镜像写入光盘”。

在下一个屏幕(图 1-5)中,在左上角的下拉选择器中选择你的 .iso 镜像。然后在右上角选择 “ISO 9660 文件系统映像”。在底部的设置中,选中 “验证写入数据”。这将在写入图像后计算校验和,并将其与原始 .iso 的校验和进行比较。这是一个重要的步骤,因为如果校验和不匹配,说明你有一个损坏的磁盘,无法使用。

使用 K3b 创建安装 DVD

图 1-4. 使用 K3b 创建安装 DVD

配置刻录

图 1-5. 配置刻录

当磁盘成功写入时,您将看到一个成功消息,如 图 1-6 中所示。如果有任何错误,该屏幕将显示一些有用的错误消息。

成功!

图 1-6. 成功!

讨论

Brasero 和 XFBurn 也是 Linux 上出色的 CD/DVD 刻录应用程序,比 K3b 更简单的界面,但功能仍然很多。

技术世界变化迅速。就在几年前,我还为一切事情刻录 CD 和 DVD。然后 USB 设备席卷市场,多年来我再也没有刻录过光盘,直到我开始写这一章节。

请放心,尽管计算机制造商不再在其机器中包含 CD/DVD 驱动器,但 CD 和 DVD 并未过时。这不是问题,因为你可以购买一个外置 USB CD/DVD 驱动器。您甚至可以找到总线供电的驱动器,因此您只需要一个 USB 线,无需使用电源线。CD/DVD 空白仍然是高质量的,因此如果您喜欢光盘,它们是一个可靠的选择。

另请参阅

1.5 使用 wodim 命令创建可引导的 CD/DVD

问题

您需要一个命令行工具来创建可引导的 CD/DVD。

解决方案

尝试 wodim 命令。你的光学驱动器很可能是 /dev/cdrom,链接到 /dev/sr0。使用符号链接是因为它具有正确的权限:

$ ls -l /dev | grep cdr
lrwxrwxrwx  1 root root           3 Mar  7 12:38 cdrom -> sr0
lrwxrwxrwx  1 root root           3 Mar  7 12:38 cdrw -> sr0
crw-rw----+ 1 root cdrom    21,   2 Mar  7 08:34 sg2
brw-rw----+ 1 root cdrom    11,   0 Mar  7 12:57 sr0

然后将您的安装镜像复制到磁盘:

$ wodim dev=/dev/cdrom -v *ubuntu-21.04-desktop-amd64.iso*

讨论

ls -l 示例中,有 sg2sr0 设备。sg2 是一个字符设备,sr0 是一个块设备。字符设备使用原始内核驱动程序提供对硬件设备的原始访问。块设备通过各种软件程序提供对硬件设备的缓冲访问。用户通过内核的块设备驱动程序与存储设备(如 DVD 和硬盘)进行交互。您可以在 /boot/config-* 文件中看到列出的原始和块内核模块。

另请参阅

  • man 1 wodim

1.6 使用 dd 命令创建 Linux 安装 USB 闪存驱动器

问题

您希望从命令行而不是使用图形工具创建您的安装 USB 驱动器。

解决方案

使用 dd 命令。dd 在每个 Linux 上都适用,并且使用方法相同。

首先用 lsblk 命令验证你的 USB 硬盘的设备名称,以便将映像复制到正确的设备。在下面的示例中,设备名称为 /dev/sdb

$ lsblk -o NAME,FSTYPE,LABEL,MOUNTPOINT

NAME   FSTYPE  LABEL       MOUNTPOINT
sda
├─sda1 vfat                /boot/efi
├─sda2 xfs     osuse15-2   /boot
├─sda3 xfs                 /
├─sda4 xfs                 /home
└─sda5 swap                [SWAP]
sdb
└─sdb1 xfs     32gbusb
sr0

下面的示例创建了一个 USB 安装盘并显示了其进度:

$ sudo dd status=progress if=ubuntu-20.04.1-LTS-desktop-amd64.iso of=/dev/sdb
211509760 bytes (212 MB, 202 MiB) copied, 63 s, 3.4 MB/s

这个过程需要几分钟时间。当完成时,看起来像这样:

2782257664 bytes (2.8 GB, 2.6 GiB) copied, 484 s, 5.7 MB/s
5439488+0 records in
5439488+0 records out
2785017856 bytes (2.8 GB, 2.6 GiB) copied, 484.144 s, 5.8 MB/s

拔出驱动器,然后重新插入并快速查看文件。图 1-7 在 Thunar 文件管理器中显示了 Ubuntu Linux 的安装文件。

Thunar 中的 Ubuntu 安装文件

图 1-7. Thunar 中的 Ubuntu Linux 安装文件

文件被标记为带有挂锁,因为 Ubuntu 安装程序使用 SquashFS 只读文件系统。你可以读取它们,但无法删除或编辑。

准备好使用安装 USB 硬盘。

讨论

识别正确的设备以复制你的安装非常重要。在 lsblk 的示例中,只有两个存储设备。请注意 LABEL 列;你可以在文件系统上创建标签,以便知道它们是什么(参见 Recipe 9.2 和第十一章的文件系统创建配方 Chapter 11 学习如何创建文件系统标签)。

图形化安装媒体创建工具不错,但我更喜欢 dd 命令,因为它简单且可靠。dd 是 Disk Duplicator 的缩写。这是一个古老而实用的 GNU 命令,在 GNU 的 coreutils 包中存在已久。

参见

  • man 1 dd

1.7 尝试简单的 Ubuntu 安装

问题

你想尝试一个简单的 Ubuntu 安装。你的安装介质已经准备好,并且你知道如何引导到你的安装介质。计算机上没有你想保留的任何东西,所以 Ubuntu 可以接管硬盘。

解决方案

下面的示例演示了 Ubuntu Linux 21.04 Hirsute Hippo 的快速简单安装。所有的 Ubuntu 版本都有带有谐音动物名称。

插入你的安装设备,启动机器,并打开系统的一次性启动菜单。选择安装设备并启动(参见 图 1-8)。

启动到安装 USB 硬盘。

图 1-8. 启动到安装 USB 硬盘

所有 UEFI 屏幕看起来都不同

每个厂商的 UEFI 界面看起来都不同,每个版本的外观也会有变化。上面的例子是 Dell UEFI 的一次性启动屏幕。

当 GRUB 菜单出现时,选择默认选项。对于 Ubuntu 21.04,默认为 Ubuntu,如果没有选择则默认启动(参见 图 1-9)。

Ubuntu 安装程序的 GRUB 启动菜单。

图 1-9. Ubuntu 安装程序的 GRUB 启动菜单

然后你将可以选择尝试 Ubuntu 和安装 Ubuntu。尝试 Ubuntu 启动 live 版本,安装 Ubuntu 打开安装程序(参见 图 1-10)。无论选择哪个,因为 live 桌面上有一个大的安装按钮。

选择实时映像或安装程序。

图 1-10. 选择实时映像或安装程序

当你启动安装程序时,它会引导你完成几个步骤。首先是选择语言和键盘布局。

然后,如果你有无线网络接口,你可以选择设置或等到安装完成后再进行设置。

然后配置你的安装。在“更新和其他软件”屏幕上,选择“正常安装”(图 1-11)。

选择正常安装..

图 1-11. 选择正常安装

在下一个屏幕上,选择“擦除磁盘并安装 Ubuntu”,然后点击“立即安装”(图 1-12)。

选择正常安装..

图 1-12. 选择擦除磁盘并安装 Ubuntu

下一个屏幕会询问“写入更改到磁盘?” 点击“继续”。接下来还有几个屏幕:设置时区,创建用户名、密码和主机名,然后安装开始。安装过程中你无需操作,安装完成后重新启动计算机,按提示移除安装设备,然后按 Enter 键。重新启动后,会有几个设置屏幕,然后你就可以使用全新的 Ubuntu Linux 了。

讨论

大多数 Linux 发行版都有类似的安装过程:启动安装介质,然后选择默认的简单安装或选择可定制的安装。有些在开始时就会询问所有问题,如用户名和密码;其他则在重新启动后完成最终设置。

Linux 安装程序通常有返回按钮可以返回并进行更改。你可以随时退出,尽管这可能会使你的系统处于不可用状态。这并不致命;重新开始并进行完整安装即可。

你可以在任意数量的机器上重新安装多次,无需担心许可密钥,除了需要注册密钥的企业发行版(如 Red Hat、SUSE 或带付费支持的 Ubuntu)。

参见

1.8 自定义分区

问题

你可以设置自己的分区方案。

解决方案

在这个方案中,我们将重新做一个例子,安装 Ubuntu 在 1.7 节,并设置我们自己的分区方案。

整个磁盘将被擦除

在这个方案中,创建了一个新的分区表,擦除了整个磁盘。

你可以按照任意方式设置分区。表 1-1 展示了我喜欢在 Linux 工作站上设置的方式。

表 1-1. 示例分区方案

分区名称 文件系统类型 挂载点
/dev/sda1 ext4 /boot
/dev/sda2 ext4 /
/dev/sda3 ext4 /home
/dev/sda4 ext4 /tmp
/dev/sda5 ext4 /var
/dev/sda6 交换

当你到达“安装类型”屏幕时,选择“其他选项”以开始你的自定义安装(图 1-13)。

选择安装类型

图 1-13. 选择安装类型

到达分区屏幕后,通过点击新分区表来擦除整个磁盘。然后您将看到类似图 1-14 的东西。

创建新的分区表。

图 1-14. 创建新的分区表

要创建新分区,请点击“空闲空间”行以选中它,然后点击加号+添加新分区。设置大小、文件系统和挂载点。图 1-15 创建了一个 500 MB 的/boot分区。

创建引导分区。

图 1-15. 创建引导分区

再次点击“空闲空间”,点击加号,一直进行下去,直到创建所有分区。图 1-16 显示的结果:/boot/home/var/tmp 和交换文件都位于各自的分区上。

分区设置完毕,准备继续安装。

图 1-16. 分区设置完毕,准备继续安装

选择要格式化的分区

注意分区屏幕上的“格式化?”复选框。所有新分区必须使用文件系统进行格式化。

讨论

示例来自虚拟机,因此硬盘为vda而不是sda

本示例在所有分区上使用 Ext4 文件系统。您可以使用任何文件系统,请参阅第十一章了解更多信息。

磁盘分区就像有一堆独立的物理磁盘一样。每个都是硬盘的独立部分,每个分区可以有不同的文件系统。您选择的文件系统及其大小都取决于您如何使用系统。如果需要大量数据存储,则/home需要更大。它甚至可以是单独的磁盘。

/boot放在独立分区中可以更轻松地管理多启动系统,因为这使得引导文件与您安装或删除的任何操作系统无关。500 MB 足够了。

/根目录放在独立分区中可以轻松恢复或替换为不同的 Linux。对于大多数发行版来说,30 GB 足够了,但如果使用 Btrfs 文件系统,则应将其增加到 60 GB 以便存储快照。

/home放在独立的分区中以隔离它免受根文件系统的影响,这样您可以更换 Linux 安装而不触及/home/home甚至可以在单独的磁盘上。

/var/tmp 可能因为运行中的进程而填满。将它们放在独立的分区中可以防止它们崩溃其他文件系统。我的通常每个都是 20 GB,并且对于繁忙的服务器,它们需要更大的空间。

将交换文件设置为内存大小的分区,以便支持挂起到磁盘。

参见

  • 在第 3.9 节的讨论中了解挂起和睡眠状态

  • 第八章

  • 第九章

1.9 保留现有分区

问题

你的 /home 单独存在于一个分区,并希望将其保留用于新的 Linux 安装。

解决方案

在 1.7 节 和 1.8 节 中,我们通过创建新的分区表来删除现有安装。当你有想要保留的分区,如 /home 或任何共享目录时,请勿创建新的分区表。而是编辑现有分区。你可以删除现有分区,创建新的分区,或重用现有分区。

在 Ubuntu 安装程序的以下示例中,/dev/sda3 是一个单独的 /home 分区。右键点击它,然后点击“更改…” 然后你可以将其挂载点设置为 /home,并确保“格式化?”框未被选中(图 1-17)。如果你格式化它或更改文件系统类型,分区上的所有数据将被删除。

保存 /dev/sda3,而不是覆盖它。

图 1-17. 保存 /dev/sda3,而不是覆盖它

讨论

在 1.8 节 中的讨论详细介绍了定制分区方案以及哪些文件系统适合在单独的分区上隔离。

参见

  • 第八章

  • 第九章

1.10 自定义软件包选择

问题

你不想要默认的软件包安装,而是更喜欢选择自己要安装的软件。例如,你可能想设置一个开发工作站、web 服务器、中央备份服务器、多媒体制作工作站、桌面发布工作站,或选择自己的办公生产力应用程序。

解决方案

每个 Linux 发行版管理安装选项的方式都有所不同。在本示例中,你将看到 openSUSE 和 Fedora Linux 的示例。openSUSE 支持从单个安装镜像安装多个安装类型,而 Fedora Linux 则有几个不同的安装镜像。

这两个示例代表了通用的 Linux 发行版。

请记住,你可以在安装后随意安装和删除软件。

openSUSE

openSUSE 安装程序支持从默认设置的简单安装和广泛的定制选项。它有两个屏幕来控制软件包选择。第一个屏幕 (图 1-18) 提供了多个系统角色选择,例如带有 KDE 或 GNOME 图形环境的桌面系统,带有 IceWM 窗口管理器的通用桌面,无图形环境的服务器,或者无图形环境的事务服务器。每个角色都有一组预设的软件包。你可以选择按原样安装其中之一,或选择要安装或删除的软件包。

每个角色都是可定制的,稍后你将看到几个屏幕 (图 1-19)。

openSUSE 安装角色

图 1-18. openSUSE 安装角色

openSUSE 安装设置

图 1-19. openSUSE 安装设置

点击“软件”以打开软件包选择屏幕。该屏幕显示了 openSUSE 模式,这些是相关的软件包组,您可以使用单个命令安装。我喜欢 Xfce 桌面环境,所以我将其添加到我的安装中(图 1-20)。

注意左下角的“详细信息”按钮。点击它将打开一个屏幕,具有多个选项卡,用于更精细的软件包选择(图 1-21)。在此屏幕上,您将找到大量信息:每个模式中的单独软件包、软件包组、下载仓库、安装摘要、依赖关系以及每个软件包的信息。在右侧窗口中选择或取消选择每个模式中的软件包后,安装程序将自动解决依赖关系。

openSUSE 软件模式

图 1-20. openSUSE 软件模式

openSUSE 单独软件包选择

图 1-21. openSUSE 单独软件包选择

当您完成软件选择后,将返回到安装摘要屏幕,再次有机会更改安装设置。点击绿色的“下一步”按钮以完成安装。

Fedora Linux

Fedora Linux 工作站和服务器安装程序仅提供分区选项,没有软件包定制功能。您需要下载 600 MB 的网络安装镜像进行可定制的安装,从Fedora 备选下载获取。它被标记为 Fedora 服务器,但它为任何类型的 Fedora 安装提供完整的软件包选择。从安装摘要屏幕设置所有安装选项(图 1-22)。

请注意安装摘要屏幕上的所有选项:软件选择、用户创建、分区、键盘和语言、时区、网络和主机名。点击“软件选择”以打开选择要安装的软件包的屏幕(图 1-23)。

Fedora Linux 网络安装程序

图 1-22. Fedora Linux 网络安装程序

Fedora Linux 软件包选择

图 1-23. Fedora Linux 软件包选择

当完成后,请点击“完成”;您将返回到安装摘要屏幕。设置完成后,请点击“开始安装”,其余安装将无人值守运行。

讨论

无论您想尝试哪种 Linux 版本,请阅读其文档和发布说明。这是重要的信息,可以节省很多麻烦。还要寻找论坛、邮件列表和维基以寻找帮助。

您可以安装任意多个桌面环境,然后在登录时选择要使用的环境。选择桌面环境的按钮通常很小并不明显;例如,默认的 Ubuntu 登录界面(图 1-24)在您点击用户名之前会隐藏桌面选择按钮。Xfce、Lxde、GNOME 和 KDE 是一些流行的图形桌面环境。GNOME 是 Ubuntu、openSUSE 和 Fedora 的默认桌面环境。

选择不同的图形环境。

图 1-24. 选择不同的图形环境

另请参阅

1.11 多启动 Linux 发行版

问题

如果您想在计算机上设置多个 Linux 发行版的多引导系统,请从启动菜单中选择要运行的发行版。

解决方案

不用担心,因为您可以安装尽可能多的 Linux,只要硬盘(或硬盘)有容量。您必须已经安装了一个 Linux,并且必须有一个单独的 /boot 分区。然后按照以下步骤进行操作:

  1. 为新的 Linux 提供足够的免费磁盘空间,可以与您现有的 Linux 放在同一硬盘上,也可以放在另一个硬盘上,无论是内置的还是外置的。

  2. 仔细记录属于您首次安装的 Linux 的分区,以免意外覆盖或删除任何您想保留的分区。

  3. 在每个新安装的 Linux 中挂载 /boot 分区,而不要格式化它。

  4. 启动到安装介质,然后配置新安装以安装在空闲的磁盘空间上。

安装程序会自动找到您现有的 Linux 安装,并将新的 Linux 添加到启动菜单中。安装完成后,您将看到一个启动菜单,例如 图 1-25,其中有选项可以启动 Linux Mint 或 Ubuntu。

新的启动菜单,带有 Linux Mint 和 Ubuntu

图 1-25. 新的启动菜单,带有 Linux Mint 和 Ubuntu

讨论

如果您需要在硬盘上释放空间,可以安全地缩小现有分区(参见 第 9.7 节)。最安全的方法是在未挂载的分区上进行此操作,并且某些文件系统在挂载状态下无法缩小。使用 SystemRescue 缩小分区,参见 第 19.12 节。

大多数 Linux 安装程序足够智能,可以识别现有的 Linux 安装,并提供保留其选项。在 图 1-26 中,您可以看到 Linux Mint 安装程序,提供了选项,可以占用整个硬盘或在不删除 Ubuntu 的情况下安装在其旁边。

在 Ubuntu 旁边安装 Linux Mint

图 1-26. 在 Ubuntu 旁边安装 Linux Mint

另请参阅

  • 第 8.9 节

  • 第 9.7 节

  • 第 19.12 节

  • 你的 Linux 发行版的安装文档

1.12 使用 Microsoft Windows 双启动

问题

你希望在计算机上双启动 Linux 和 Windows。

解决方案

双启动 Linux 和 Windows 会在一台计算机上安装两个系统,然后在启动时从引导菜单中选择要使用的系统。

如果尚未安装 Windows,最好先安装 Windows,然后再安装 Linux。Windows 喜欢控制引导加载程序,因此先安装 Linux 可以让 Linux 控制引导加载程序。

请务必备份重要数据并准备好 Windows 恢复媒体。

安装完 Windows 后,开始 Linux 的安装。你可以按照自己的方式安装 Linux:简单安装或者自定义安装,在这里设置分区和软件包选择。对于多重引导有一个重要的选项:

  1. 如果只有一个硬盘,则“引导加载程序安装设备”是 /dev/sda

  2. 如果你在一块硬盘上有 Windows,而在第二块硬盘上安装 Linux,则“引导加载程序安装设备”是 Linux 硬盘。使用设备名称,例如 /dev/sdb,而不是分区名称,比如 /dev/sdb1

在 图 1-27 中,有两块硬盘,Windows 安装在 /dev/sda,Linux 安装在 /dev/sdb

在 Windows 旁边安装 Ubuntu。

图 1-27. 在 Windows 旁边安装 Ubuntu

请务必确认你正在正确的位置安装 Linux,而不是覆盖 Windows。如果要为 Linux 分区,就像单独安装一样,并且要小心更改哪些分区。

当你设置好分区并满意你的安装配置后,继续完成 Linux 的安装。安装完成并重新启动后,你的 GRUB 菜单将包含两个系统的条目(见 图 1-28)。

openSUSE 和 Windows 在 GRUB 启动菜单中。

图 1-28. openSUSE 和 Windows 在 GRUB 启动菜单中

讨论

你可以在硬盘上为 Linux 和 Windows 安装多个系统,只要硬盘空间足够。

在同一台机器上运行 Linux 和 Windows 还有其他方法。Windows 10 包含了 Windows Subsystem for Linux 2(WSL 2),可以在虚拟环境中运行支持的 Linux 发行版。如果你有 Windows 安装媒体,你可以在 Linux 上运行 Windows 虚拟机。虚拟机非常好用,因为你可以同时运行多个操作系统,尽管这需要高端 CPU 和大量内存。

VirtualBox 和 QEMU/KVM/Virtual Machine Manager 是运行在 Linux 上的优秀的免费虚拟机主机。

参见

1.13 恢复 OEM Windows 8 或 10 产品密钥

问题

您购买了预装有 Windows 8 或 10 的计算机,但找不到您的产品密钥。

解决方案

让 Linux 为您找到它。从安装有 Windows 的同一台计算机上的 Linux 系统或从 SystemRescue 运行以下命令:

$ sudo cat /sys/firmware/acpi/tables/MSDM
MSDMU
DELL  CBX3
AMI
*FAKEP-RODUC-TKEY1-22222-33333*

并且在最后一行就是它。

如果您可以登录 Windows,请在 Windows 中运行以下命令以检索您的产品密钥:

C:\Users\Duchess> wmic path softwarelicensingservice get OA3xOriginalProductKey
OA3xOriginalProductKey
*FAKEP-RODUC-TKEY1-22222-33333*

讨论

如果您没有恢复媒体,Windows 10 是免费下载的。您将需要您的 25 位 OEM 产品密钥进行全新安装。

参见

1.14 在 Linux 上挂载您的 ISO 镜像

问题

你已经下载了一个 Linux **.iso*文件,并且很想知道它在解压后的样子。你可以继续创建一个可启动的 DVD 或 USB 驱动器,然后检查文件,但你真的想要在不复制到另一个设备的情况下解压它。

解决方案

Linux 有一个名为loop设备的伪设备。这使得您的.iso*镜像文件像任何其他文件系统一样可访问。按照以下步骤将您的.iso*镜像文件挂载到一个循环设备中。

首先,在您的家目录中创建一个挂载点,可以为其指定任何名称。在示例中,它称为loopiso

$ mkdir loopiso

在这个新目录中挂载您的**.iso*。在示例中,它是一个 Fedora Linux 安装镜像:

$ sudo mount -o loop Fedora-Workstation-Live-x86_64-34-1.2.iso loopiso
mount: /home/duchess/loopiso: WARNING: device write-protected, mounted read-only

在文件管理器中查看已挂载的文件系统(图 1-29)。

Fedora Linux 34 中的.iso

图 1-29. Fedora Linux 34 中的一个已挂载的.iso

您可以进入目录并阅读文件。您将无法编辑任何文件,因为它们是以只读方式挂载的。

完成后,卸载它:

$ sudo umount loopiso

讨论

循环设备将常规文件映射到虚拟分区,并且您可以在此文件中设置虚拟文件系统。如果您想尝试创建自己的文件,可以通过一些网络搜索找到很多方法。从man 8 losetup开始。

参见

  • man 8 mount

  • man 8 losetup

第二章:管理 GRUB 引导加载程序

引导加载程序是在您打开计算机后加载操作系统的软件。GRUB(GRand Unified Bootloader)引导加载程序是 Linux 上最常用的引导加载程序。

GRUB 支持许多有用的功能:在单个 PC 上引导多个操作系统、实时配置编辑、可主题化界面和救援模式。在本章中,您将了解所有这些内容。

GRUB 与 GRUB 2

GRUB 有两个主要版本,传统的 GRUB 和 GRUB 2。GRUB 2 的版本是 1.99 及以上。传统的 GRUB 在 2005 年版本 0.97 结束。许多 GRUB 如何文档仍然参考传统的 GRUB 并将其与 GRUB 2 进行比较。在本章中,我不会讨论传统的 GRUB。它已经退役很久了,与使用 GRUB 2 几乎没有关系,因此本章将专门讨论 GRUB 2。

一些 Linux 发行版使用纯 GRUB 命名,一些使用 GRUB 2。例如,Ubuntu 有/boot/grub/目录和grub-mkconfig命令,而 Fedora 称之为/boot/grub2/grub2-mkconfig。请检查您的文件路径和名称。在本章中,我使用 Ubuntu 的命名方案,除了特定于发行版的例子。

自从 UNIVAC 在上个千年 40 年代首次建造以来,计算机的启动方式并没有多大改变。启动计算机被称为引导,这是一个“靠自己的靴带拉自己起来”的参考,这是不可能的。可编程计算机的困难在于它需要软件指令来告诉它该做什么,在操作系统加载之前这些指令从哪里来呢?

现代 x86_64 PC 架构的解决方案是将初始启动指令存储在主板上的芯片上,并使用这些指令的地址来编程 CPU。您可以说 CPU 是硬连接接收启动指令的。这个地址在所有 x86_64 机器上都是相同的,这就是为什么您可以混合和匹配主板和 CPU 的原因。(如果您想进行一些研究,这个地址被称为复位向量。)

这是关于它们如何运作的简化描述:

第一阶段在系统上电时启动。CPU 从 BIOS/UEFI 固件获取指令,然后初始化 CPU 缓存和系统内存。当系统内存初始化时,会运行自检(POST),测试内存并测试与键盘、鼠标、显示器和磁盘驱动器等其他硬件的连接。您可能已经注意到键盘和鼠标上的 LED 灯亮起,并听到计算机箱内部的声音,因为您的磁盘驱动器正在被探测。

在 POST 之后,BIOS/UEFI 固件启动启动的第二阶段,并在硬盘上查找引导文件。GRUB 引导加载程序加载必要的文件以启动您的操作系统并完成系统启动。

当启动屏幕出现(图 2-1)时,GRUB 会等待预先配置的时间以等待您的输入,通常为 5–10 秒,如果您不进行任何操作,则会启动默认设置。使用箭头键导航启动菜单。按任意键停止倒计时,然后您可以随意探索启动选项。

在 图 2-1 中,第一项启动系统。接下来的两个条目打开带有更多启动选项的子菜单。在探索子菜单时,按 Esc 键返回主菜单。

某些 Linux 发行版(如 Fedora 和 Ubuntu)在计算机上只安装一个操作系统时不会显示启动屏幕。在这种情况下,按下 Shift 键可查看启动屏幕。有一个配置选项可以始终显示启动屏幕。

您可以通过调整 GRUB 配置文件中的几个选项来自定义 GRUB 菜单的外观和行为。

如果您希望使用图形工具自定义 GRUB 菜单,请尝试 GRUB 自定义工具(图 2-2)。这在大多数 Linux 发行版中都作为 grub-customizer 软件包提供,但 openSUSE 则在 YaST 系统配置实用程序中有一个标记为“引导加载程序”的 GRUB 模块。

openSUSE GRUB 启动屏幕

图 2-1. openSUSE GRUB 启动屏幕

GRUB 自定义工具

图 2-2. GRUB 自定义工具

2.1 重新构建您的 GRUB 配置文件

问题

每当更改 GRUB 配置时,都需要重新构建它。

解决方案

重新构建 GRUB 配置的命令因发行版而异。在 Fedora 和 openSUSE 中,使用此命令:

$ sudo grub2-mkconfig -o /boot/grub2/grub.cfg

一些发行版(如 Ubuntu)使用:

$ sudo grub-mkconfig -o /boot/grub/grub.cfg

Ubuntu Linux 还有一个脚本可以运行 grub-mkconfigupdate-grub

$ sudo update-grub

讨论

一些 Linux 发行版贴心地在 /etc/default/grub 的顶部提供了正确的命令。

在编辑 GRUB 配置文件时,请始终验证正确的文件名和路径,因为它们在不同的 Linux 发行版上可能会有所不同。

参见

  • 要了解您系统的 BIOS/UEFI,请参阅您的主板文档

  • GNU GRUB 手册

  • GRUB 有多个单一用途的手册页面;运行 man -k grub 可查看所有内容。

  • info grubinfo grub2

2.2 取消隐藏的 GRUB 菜单

问题

当您的 Linux 发行版在计算机上只安装了一个操作系统时,默认会隐藏 GRUB 菜单,如果您希望每次启动时都显示它,请进行如下设置。

解决方案

几个 Linux 发行版包括 Ubuntu 和 Fedora 在内的一些发行版会执行此操作。您可以通过在启动时按住 Shift 键来临时取消隐藏 GRUB 菜单。

编辑 /etc/default/grub,使用以下选项永久取消隐藏:

GRUB_TIMEOUT="10"
GRUB_TIMEOUT_STYLE=menu

如果您的文件中包含 GRUB_HIDDEN_TIMEOUT=0GRUB_HIDDEN_TIMEOUT_QUIET=true 这两行,请将其注释掉。

修改 /etc/default/grub 后,重新构建您的 GRUB 配置(配方 2.1)。

讨论

GRUB_HIDDEN_TIMEOUT=0表示不显示 GRUB 菜单,而GRUB_HIDDEN_TIMEOUT_QUIET=true表示不显示倒计时计时器。

如果在多引导配置中安装另一个操作系统,则 GRUB 菜单应该自动显示。

参见

  • Recipe 2.1

  • GNU GRUB 手册

  • GRUB 有多个专用于单个功能的手册页;运行man -k grub查看所有手册页。

  • info grubinfo grub2

2.3 引导到不同的 Linux 内核

问题

您可能对 GRUB 菜单中引用特定 Linux 内核版本的额外条目感到困惑,例如图 2-3 中的条目。您想知道它们的用途以及如何处理它们。

GRUB 内核引导选项

图 2-3. GRUB 内核引导选项

解决方案

随着时间的推移,当您更新您的 Linux 系统时,旧的 Linux 内核会保留并添加到您的 GRUB 菜单中。如果新内核出现问题,这为您提供了一个轻松的方法引导到已知良好的旧内核。您不必保留旧内核,可以使用包管理器将它们删除。

讨论

在过去,内核更新是一件大事,因为它们通常意味着错误修复,对硬件(如视频、网络和音频接口)的额外支持,以及对软件功能(如专有文件格式和新协议)的支持。变化速度很快,新内核不正常工作并不罕见,因此保留引导到旧内核的选项是常规操作。如今这类问题较少见,内核更新通常不会引起轰动。

参见

2.4 理解 GRUB 配置文件

问题

您知道与大多数程序不同,配置 GRUB 有些不同,想知道 GRUB 配置文件在哪里以及哪些文件用于管理 GRUB。

解决方案

GRUB 配置文件位于/boot/grub//etc/default/grub/etc/grub.d/中。GRUB 配置非常复杂,包含许多脚本和模块。

GRUB 与 GRUB 2 的区别

请记住,正如本章介绍中所讨论的,一些 Linux 发行版使用普通的 GRUB 命名,而一些在文件名和命令中使用 GRUB2。在本章中,我使用普通的 GRUB 命名,除了特定于发行版的示例。

/etc/default/grub用于配置启动时显示的 GRUB 菜单的外观,例如隐藏或显示引导菜单、应用主题和背景图像、菜单超时和内核选项。

/etc/grub.d/中的文件支持更复杂的配置,/boot/grub/存储用于自定义 GRUB 菜单外观的映像和主题文件。

主要的 GRUB 配置文件是/boot/grub/grub.cfg,GRUB 在启动时读取此文件。您不应编辑此文件,因为它是从/etc/grub.d//etc/default/grub构建的;每次进行配置更改时,您必须重新构建 GRUB 配置。

当您安装任何影响引导过程的更新(例如安装更新的内核和删除旧内核)时,GRUB 配置会自动重新构建。

讨论

如果您对脚本编写感兴趣,研究 GRUB 文件是组织大量相互依赖脚本的一个极好的课程。

/etc/grub.d/ 中的文件称为 drop-in 文件。与处理一个巨大的单一配置文件不同,每个 drop-in 文件包含特定任务的配置。这些文件按 GRUB 应该读取它们的顺序编号,较低的数字表示较高的优先级。以下示例来自 Fedora 32:

$ sudo ls -C1 /etc/grub.d/
00_header
01_users
08_fallback_counting
10_linux
10_reset_boot_success
12_menu_auto_hide
20_linux_xen
20_ppc_terminfo
30_os-prober
30_uefi-firmware
40_custom
41_custom
backup
README

这些文件都是脚本,每个都必须设置可执行位。您可以通过清除可执行位来禁用其中任何一个,例如:

$ sudo chmod -x 20_linux_xen

通过添加可执行位重新启用脚本:

$ sudo chmod +x 20_linux_xen

参见

  • GNU GRUB 手册

  • GRUB 有许多 man 手册页;运行 man -k grub 可查看所有手册页。

  • info grubinfo grub2

  • 第六章

2.5 编写最小化的 GRUB 配置文件

问题

您想编写最小工作的 GRUB 配置。

解决方案

这是最基本的 /etc/default/grub 文件,只包含启动 Linux 系统并显示 GRUB 菜单所需的必要条目。以下示例适用于 openSUSE Leap 15.2:

# If you change this file, run 'grub2-mkconfig -o /boot/grub2/grub.cfg'
# afterwards to update /boot/grub2/grub.cfg.

GRUB_DEFAULT=0
GRUB_TIMEOUT=10
GRUB_TIMEOUT_STYLE=menu

还记得 图 2-1 吗?图 2-4 是相同系统,但带有最小化的 GRUB 配置。

Minimal GRUB 菜单

图 2-4. 最小化的 GRUB 菜单

您可以尝试更多选项,例如不同的设置默认引导选项的方式,更改背景图像和主题,更改颜色,以及更改屏幕分辨率。请参阅讨论以了解更多信息。

讨论

/etc/default/grub 中有许多可以使用的选项,您可以忽略大多数。以下是我认为最有用的选项:

GRUB_DEFAULT=

设置默认引导条目。在 grub.cfg 中,引导条目从 0 开始计数,但没有编号。如何知道每个引导选项的编号?没有明显的方法来弄清楚这一点;您必须手动计算引导选项。通过计算“menuentry”部分来确定编号。菜单条目看起来像这样:

menuentry 'openSUSE Leap 15.2'  --class opensuse --class gnu-linux
  --class gnu --class os
menuentry_id_option 'gnulinux-simple-102a6fce-8985-4896-a5f9-e5980cb21fdb' {
        load_video
        set gfxpayload=keep
        insmod gzio
        [...]

或者使用 awk 命令为您列出它们,例如适用于 Ubuntu 20.04 的以下示例:

$ sudo awk -F\' '/menuentry / {print i++,$2}' /boot/grub/grub.cfg
0 Ubuntu
1 Ubuntu, with Linux 5.8.0-53-generic
2 Ubuntu, with Linux 5.8.0-53-generic (recovery mode)
3 Ubuntu, with Linux 5.8.0-50-generic
4 Ubuntu, with Linux 5.8.0-50-generic (recovery mode)
5 UEFI Firmware Settings

您可能不希望将恢复模式条目作为默认条目,或者内存测试条目,尽管如果您这样做也不会有任何问题。UEFI 固件设置是到您系统的 BIOS/UEFI 的快捷方式。

GRUB_TIMEOUT=10

设置 GRUB 菜单等待启动默认条目的秒数,GRUB_TIMEOUT_STYLE=menu 在倒计时期间显示菜单。GRUB_TIMEOUT=0 立即启动而不显示菜单,GRUB_TIMEOUT=-1 禁用自动启动并等待用户选择引导条目。

GRUB_DEFAULT=saved

GRUB_SAVEDEFAULT=true 配合使用,GRUB_DEFAULT=saved 将上次引导的菜单项设为下次引导的默认项。

GRUB_CMDLINE_LINUX=

为所有菜单项添加 Linux 内核选项。

GRUB_CMDLINE_LINUX_DEFAULT=

仅将内核选项传递给默认的菜单项。GRUB_CMDLINE_LINUX_DEFAULT="quiet splash" 是一个常见的默认选项,它在启动时禁用详细输出并显示一个图形启动画面。Figure 2-5 展示了详细输出的外观。如果已配置 GRUB_CMDLINE_LINUX_DEFAULT="quiet splash",你可以通过在启动时按 Esc 键来查看此输出,而不需要更改配置。

GRUB_TERMINAL=gfxterm

将你的 GRUB 屏幕设置为支持颜色和图像的图形模式。GRUB_TERMINAL=console 禁用了图形模式。

GRUB_GFXMODE=

设置图形模式的屏幕分辨率,例如,GRUB_GFXMODE=1024x768。运行 set pager=1 命令,然后从你的 GRUB 命令行运行 videoinfo,查看支持的模式(Figure 2-6)。set pager=1 允许你使用箭头键上下翻页查看长命令输出。GRUB_GFXMODE=auto 会计算一个合理的默认值。

启动消息

图 2-5 启动消息

支持的视频模式

图 2-6 支持的视频模式

GRUB_BACKGROUND=

设置 GRUB 菜单的背景图片,使用你选择的图像(参见 Recipe 2.6)。

GRUB_THEME=

用一个完整的主题装饰你的 GRUB 菜单(参见 Recipe 2.8)。

参见

  • Recipe 2.6

  • Recipe 2.8

  • GNU GRUB 手册

  • GRUB 有多个单一用途的手册页;运行 man -k grub 查看所有内容。

  • info grubinfo grub2

2.6 设置自定义背景图片作为你的 GRUB 菜单背景

问题

你不喜欢你的 GRUB 菜单的外观,想要美化它。

解决方案

你需要一个 PNG、8 位 JPG 或 TFA 格式的图像。它可以是任何大小,GRUB 会按比例缩放。在以下示例中,我们在 GRUB 菜单上展示了梅奇斯享受书架的照片。

将你的图像复制到 /boot/grub/,并将你的图像的完整文件路径添加到 /etc/default/grub。梅奇斯的照片是 /boot/grub/duchess-books.jpg

GRUB_BACKGROUND="/boot/grub/duchess-books.jpg"

如果有 GRUB_THEME= 行,请确保已注释掉,然后重新构建你的 GRUB 配置(Recipe 2.1)。

在重建命令的输出中应该看到类似“找到背景:/boot/grub/duchess-books.jpg”的行。如果没有看到这个,那么你的配置有错误。

当看起来正确时,重新构建、重新启动,享受你的新的 GRUB 菜单背景(Figure 2-7)。

梅奇斯读物猫装饰的 GRUB 菜单

图 2-7 梅奇斯读物猫装饰的 GRUB 菜单

示例中的字体几乎无法阅读,因此请跳转至配方 2.7 以了解如何更改它们的颜色。

讨论

您可以使用系统上的任何图像;它不必位于/boot/grub/中。将图像文件放在/boot/grub/中可以将所有 GRUB 自定义集中在一个地方,并使它们在多重引导设置上对所有安装的 Linux 系统可用。

参见

  • GNU GRUB 手册

  • GRUB 有多个单用途手册页;运行man -k grub查看所有手册页。

  • info grubinfo grub2

2.7 更改 GRUB 菜单中的字体颜色

问题

您的新背景很漂亮(图 2-7),但您的字体几乎不可见,因此您需要更改颜色以便读取您的 GRUB 菜单。

解决方案

这很有趣,因为您可以快速从 GRUB 命令行预览颜色。然后,当您知道您想要的颜色时,编辑/etc/default/grub并在/etc/grub.d/中创建一个新文件以加载您的颜色,然后重建/boot/grub/grub/cfg。重新启动以享受带有漂亮彩色字体的背景图像。

启动计算机,当 GRUB 菜单出现时,按 C 打开 GRUB 命令行(图 2-8)。

GRUB 命令行

图 2-8. GRUB 命令行

以下两个命令设置了图 2-9 中的颜色:

grub> menu_color_highlight=cyan/blue
grub> menu_color_normal=yellow/black

从 GRUB 命令行设置 GRUB 菜单颜色

图 2-9. 从 GRUB 命令行设置 GRUB 菜单颜色

您可以逐对设置和测试每个颜色对。从 GRUB 菜单中,按 C 打开 GRUB 命令行。输入您的命令(抱歉,无法复制粘贴),按 Enter,然后按 Esc 返回菜单以查看其效果。您可以使用上下箭头键列出之前的命令,并编辑和重复使用它们,而不是重新键入所有内容。

您必须按照以下顺序指定两种颜色:前景/背景。所有颜色均为实心,没有透明度,只有一种例外:当您选择黑色作为背景颜色时,它是透明的。这就是为什么在具有背景图像时menu_color_normal=必须将黑色作为背景颜色的原因。如果使用其他任何颜色,则您的图像将被背景颜色覆盖。menu_color_highlight=背景颜色仅适用于当前选择的行。

当您确定了您的颜色后,使它们保持永久。启动并在/etc/grub.d/中创建一个新的脚本。在以下示例中,它称为07_font_colors。精确复制如下内容:

#!/bin/sh

        if [ "x${GRUB_BACKGROUND}" != "x" ] ; then
                if [ "x${GRUB_COLOR_NORMAL}" != "x" ] ; then
                echo "set color_normal=${GRUB_COLOR_NORMAL}"
                fi

                if [ "x${GRUB_COLOR_HIGHLIGHT}" != "x" ] ; then
                echo "set color_highlight=${GRUB_COLOR_HIGHLIGHT}"
                fi
        fi

然后使其可执行:

$ sudo chown +x 07_font_colors

现在将以下行添加到您的/etc/default/grub文件中,使用您的颜色:

export GRUB_COLOR_NORMAL="yellow/black"
export GRUB_COLOR_HIGHLIGHT="cyan/blue"

重建您的 GRUB 配置(配方 2.1),然后重新启动以查看是否有效。

讨论

参见配方 2.4 了解/etc/grub.d/中文件及其必须以数字开头的原因。根据我的经验,如果你的字体脚本起得早晚并不重要,但如果它对你不起作用,请尝试更改优先级。确保它是可执行的。选项如下:

  • menu_color_highlight控制菜单框内高亮行的颜色。

  • menu_color_normal控制未高亮行的颜色。

请确保按照表格 2-1 中写的方式使用这些颜色,全部小写且拼写一致。

表格 2-1. GRUB 颜色选项

颜色选项
黑色
蓝色
棕色
青色

参见

  • GNU GRUB 手册

  • GRUB 有多个单一用途的手册页面;运行man -k grub来查看所有页面。

  • info grubinfo grub2

  • 配方 2.4

2.8 将主题应用于你的 GRUB 菜单

问题

你喜欢美化你的 GRUB 菜单,并且想知道是否有适用于 GRUB 菜单的主题以及如何安装它们。

解决方案

你很幸运,因为 GRUB 有很多主题可用。首先使用你的软件包管理器和grep命令来搜索包名。这是 Ubuntu Linux 的一个例子:

$ apt search theme | grep grub

使用theme | grep grub来过滤你的结果,将找到所有相关的包,如grub-theme-breezegrub2-themes-ubuntu-mategrub-breeze-theme。安装主题的方法与安装任何包一样。

讨论

你的新主题应该安装在/boot/grub/themes中。找到你的新主题,例如/boot/grub/themes/ubuntu-mate,并查找theme.txt文件。在/etc/default/grub中输入完整路径,就像这个ubuntu-mate主题的示例一样:

GRUB_THEME=/boot/grub/themes/ubuntu-mate/theme.txt

请务必注释掉任何其他与外观相关的配置行,例如GRUB_BACKGROUND=、任何自定义字体颜色和其他主题。然后重建你的 GRUB 配置(配方 2.1)。你应该会在命令输出中看到类似“Found theme: /boot/grub/themes/ubuntu-mate/theme.txt”的行。

如果一切顺利,重新启动,你将看到像图 2-10 一样的屏幕。如果显示不正确,请重新检查你的配置和命令。

Ubuntu MATE GRUB 主题

图 2-10. Ubuntu MATE GRUB 主题

参见

2.9 从 grub>提示符中救援无法启动的系统

问题

当你启动系统时,它停在 GRUB 提示符grub>处,不能启动。你需要知道如何启动你的系统,然后修复你的配置。

解决方案

当引导过程停在grub>提示符时(图 2-11),这意味着它找到了/boot/grub/但找不到根文件系统。

GRUB 命令 shell

图 2-11. GRUB 命令 shell

你需要找到根文件系统、Linux 内核及其匹配的 initrd 文件。当你在 GRUB 命令 shell 中时,整个文件系统对你是开放的。

第一个命令应该运行的是调用分页器,这样你就可以向上和向下翻页长输出:

grub> set pager=1

列出你的磁盘和分区。GRUB 有自己的方法来标识硬盘和分区。它从 0 开始编号硬盘,从 1 开始编号分区,并将所有硬盘标记为 hd。在运行中的 Linux 系统中,硬盘被标识为 /dev/sda/dev/sdb 等等。

在下面的例子中,GRUB 列出了两个硬盘 hd0hd1,它们与 /dev/sda/dev/sdb 相同。hd0,gpt5 相当于 /dev/sda5,而 hd1,msdos1 相当于 /dev/sdb1

grub> ls
(hd,0) (hd0,gpt5) (hd0,gpt4) (hd0,gpt3) (hd0,gpt2) (hd0,gpt1)
(hd1) (hd1,msdos1)

此输出显示 hd0 有一个 gpt 分区表,而 hd1 有一个老式的 msdos 分区表。在列出分区和文件时,不必使用 gptmsdos 标签。

GRUB 告诉你关于分区的文件系统类型、通用唯一标识符 (UUID) 和其他信息:

grub> ls (hd0,3)
  Partition hd0,3: filesystem type ext* - Last modification time 2021-12-29
  01:17:58 Tuesday, UUID 5c44d8b2-e34a-4464-8fa8-222363cd1aff - Partition start
  at 526336KiB -
Total size 20444160KiB

你需要找到 /boot。假设你记得它在第二个分区的根文件系统中;从那里开始查找。在分区名称后面的斜杠表示列出该分区上的所有文件和目录:

grub> ls (hd0,2)/
bin   dev  home  lib64   media  opt   root  sbin  sys  usr
boot  etc  lib   lost+found  mnt    proc  run   srv   tmp  var

所有启动文件都在 /boot 目录中:

grub> ls (hd0,2)/boot
efi/ grub/ System.map-5.3.18-lp152.57-default config-5.3.18-lp152.57-default
initrd-5.3.18-lp152.57-default vmlinuz vmlinuz-5.3.18-lp152.57-default
sysctl.conf-5.3.18-lp152.57-default vmlinux-5.3.18-lp152.57-default.gz

你需要的一切来启动你的系统都在那里。设置根文件系统分区、内核和 initrd 镜像:

grub> set root=(hd0,2)
grub> linux /boot/vmlinuz-5.3.18-lp152.57-default root=/dev/sda2
grub> initrd /boot/initrd-5.3.18-lp152.57-default
grub> boot

制表符自动补全

就像 Bash shell 一样,GRUB 命令 shell 支持制表符自动补全。这意味着你可以开始输入 /boot/vml,然后按 Tab 键来自动完成该行,或者显示可能的选项列表。

如果有多个 vmlinuzinitrd 文件,请使用版本号匹配最新的两个。如果所有命令都正确,系统将启动,你可以修复你的 GRUB 配置 (Recipe 2.11)。

讨论

/boot 在自己的分区中时,你将看不到任何其他目录,因为它不在根文件系统中。

vmlinuz-5.3.18-lp152.57-default 是压缩的 Linux 内核。

initrd-5.3.18-lp152.57-default 是初始 RAM 磁盘,仅用于启动系统的临时根文件系统。

引导失败是由于文件损坏、添加、删除或移动硬盘、安装或卸载操作系统或重新分区。如果你无法进入 GRUB 提示符,请参阅 第十九章 以学习如何使用 SystemRescue 来拯救你的系统。

你可以在 GRUB 菜单出现时按下 C 键来练习使用 grub> shell。这是安全的,因为你所做的更改不会在重新启动后生效。

参见

2.10 从 grub rescue> 提示符中抢救无法引导的系统

问题

当你启动系统时,它停在一个 GRUB 提示符 grub rescue> 处,并且无法启动。你需要知道如何引导系统,然后修复配置。

解决方案

grub rescue> 提示符(图 2-12)是救援 shell,意味着 GRUB 找不到 /boot。别担心,你可以从 GRUB 提示符找到它,引导系统,然后进行永久修复。

GRUB 恢复 shell

图 2-12. GRUB 恢复 shell

列出你的分区:

grub rescue> ls
(hd0) (hd0,gpt5) (hd0,gpt4) (hd0,gpt3) (hd0,gpt2) (hd0,gpt1)
(hd1) (hd1, msdos1)

在这一点上,没有制表符补全或分页功能,所以你必须输入所有内容。

GRUB 告诉你分区的文件系统类型、UUID 和其他信息:

grub rescue> ls (hd0,3)
    Partition hd0,3: filesystem type ext* - Last modification time 2021-12-29
    01:17:58
Tuesday, UUID 5c44d8b2-e34a-4464-8fa8-222363cd1aff - Partition start at
526336KiB -
Total size 20444160KiB

如果你不知道哪个分区包含 /boot,你将不得不列出每个分区中的文件和目录,直到找到它。你不必使用 gptmsdos 标签。设备名后面跟着一个斜杠表示列出所有文件和目录:

grub rescue> ls (hd0,2)/
bin   dev  home  lib64   media  opt   root  sbin  sys  usr
boot  etc  lib   lost+found  mnt    proc  run   srv   tmp  var

哇,它就在根文件系统中。列出 /boot 中的文件:

grub rescue> ls (hd0,2)/boot
efi/ grub/ System.map-5.3.18-lp152.57-default config-5.3.18-lp152.57-default
initrd-5.3.18-lp152.57-default vmlinuz vmlinuz-5.3.18-lp152.57-default
sysctl.conf-5.3.18-lp152.57-default vmlinux-5.3.18-lp152.57-default.gz

grub rescue> 还有一些额外的命令。你必须告诉它 /boot/grub 的位置,然后加载 normallinux 内核模块,它们位于 /boot/grub/i386-pc 中(以及 GRUB 启动时使用的许多其他内核模块)。normal 将引导模式从救援切换到正常,linux 启动系统加载器:

grub rescue> set prefix=(hd0,2)/boot/grub
grub rescue> set root=(hd0,2)
grub rescue> insmod normal
grub rescue> insmod linux

加载 normallinux 后,你可以使用制表符补全。你也可以打开分页功能,set pager=1,以使用箭头键滚动到以前的命令。现在告诉 GRUB 在哪里找到 kernelinitrd 文件:

grub> linux /boot/vmlinuz-5.3.18-lp152.57-default root=/dev/sda2
grub> initrd /boot/initrd-5.3.18-lp152.57-default
grub> boot

如果有多个 vmlinuzinitrd 文件,请使用版本号匹配最新的两个。如果所有命令都正确,系统将会启动并可以修复 GRUB 配置(Recipe 2.11)。

讨论

/boot 单独存在于一个分区时,你将看不到任何其他目录,因为它位于自己的文件系统中。

参见

2.11 重新安装你的 GRUB 配置

问题

你已经能够从 GRUB 提示符引导系统,现在需要知道如何进行永久修复。

解决方案

仔细检查你的 GRUB 配置是否有误。当它看起来正确时,重新构建你的 GRUB 配置(Recipe 2.1)。然后你需要重新安装 GRUB。在以下示例中,它重新安装到 /dev/sda

$ sudo grub-mkconfig -o /boot/grub/grub.cfg
$ sudo grub-install /dev/sda

使用正确的重建命令

正如 Recipe 2.1 和“GRUB versus GRUB 2”中所讨论的,你必须检查文件路径以确保使用正确的重建命令。

确保将其安装到正确的磁盘上,如果有多个磁盘,请仅使用设备名(例如 /dev/sda ),而不是分区(例如 /dev/sda1)。

讨论

确保有良好的当前备份。如果你的救援努力失败,尝试从 SystemRescue 重新安装 GRUB(Recipe 19.9)。

参见

第三章:启动、停止、重启和将 Linux 置于睡眠模式中

在本章中,您将学习几种停止、启动和重启 Linux 系统的方法,以及如何管理睡眠模式。您将学习传统命令和新的 systemd 命令。

您还将学习如何设置自动启动和关机。自动关机很好地提醒您停止工作,您不必记得晚上关闭计算机。您可以在远程计算机上设置自动唤醒和关机,这样您可以在工作时间内访问它,而不必一直保持运行状态。如果您的用户浪费电力,不关闭计算机,您可以配置它们在非工作时间关机。

"三键敬礼",Ctrl-Alt-Delete,在需要中断启动和重启或进程或应用程序行为不端时非常有用。在图形桌面中,您可以将这些键重新映射为更方便的键组合。

几十年来积累了许多传统关机命令,具有大量重叠功能:shutdownhaltpoweroffrebootshutdown命令提供了有用的选项,可以定时关闭,并向所有登录用户发出警告。这些命令在脚本、SSH 会话中非常有用,以及任何时候您从命令行工作时。

不一定需要根权限

在旧时代,运行关机命令需要根权限。这种情况正在改变,在许多现代 Linux 发行版中,这些命令不需要根权限。本章的示例适用于普通的非特权用户。如果您的 Linux 发行版需要根权限,它会告诉您。

这些权限由现代 Linux 发行版上的 Polkit(以前是 PolicyKit)控制。查看man 8 polkit以了解更多信息。

但这还不是全部,因为在带有 systemd 的 Linux 发行版中(第四章),经典的旧命令没有安装在系统上。相反,它们的名称被符号链接到systemctl命令。您可以使用stat命令来查看,就像这个shutdown的示例一样:

$ stat /sbin/shutdown
  File: /sbin/shutdown -> /bin/systemctl
  Size: 14              Blocks: 0          IO Block: 4096   symbolic link
Device: 802h/2050d      Inode: 1177556     Links: 1
Access: (0777/lrwxrwxrwx)  Uid: ( 0/ root)   Gid: ( 0/ root)

File:行显示了一个指向/bin/systemctl的符号链接。所有传统命令名称,/sbin/shutdown/sbin/halt/sbin/poweroff/sbin/reboot,都被符号链接到/bin/systemctl。这些传统命令名称的符号链接是为了向后兼容而提供的。在没有 systemd 的 Linux 系统上,这些符号链接不存在,这些系统使用传统的可执行文件。

在一些 Linux 发行版中,这些符号链接位于/usr/sbin而不是/sbin。当您使用传统的命令名称时,在有 systemd 和没有 systemd 的系统上它们的行为是相同的。

您的图形桌面上的电源按钮是可配置的;您应该能够自定义可见的按钮以及它们的位置。

3.1 使用 systemctl 关机

问题

您想要使用systemctl命令来关机和重启您的系统。

解决方案

关闭系统并关闭电源:

$ systemctl poweroff

另一种关闭系统并断电的方法:

$ systemctl shutdown

重新启动:

$ systemctl reboot

关闭系统但不断电:

$ systemctl halt

讨论

systemctl 关机命令没有传统命令中的许多选项,这并不太重要,因为传统命令中有很多冗余选项。有一个显著的区别:systemctl shutdown 不支持 shutdown 命令支持的定时关机选项(参见 Recipe 3.2)。

参见

  • man 8 systemd-halt.service

3.2 使用 shutdown 命令进行关机、定时关机和重新启动

问题

你想要定时关机,例如在 10 分钟后或在特定时间,同时警告所有登录用户。或者你只想立即关闭而不需要任何修饰。

解决方案

shutdown 命令无论是链接到 systemctl 还是传统的 shutdown 可执行文件,工作方式都是相同的。

下面的例子展示了如何立即关闭、在一定分钟后关闭、取消关闭、在特定时间关闭、halt 和 reboot。

立即关闭系统,不通知其他登录用户:

$ shutdown -h now

10 分钟后关机并通知:

$ shutdown -h +10
Shutdown scheduled for Sun 2021-05-23 11:04:43 PDT, use 'shutdown -c' to cancel.

其他系统用户可能会看到此消息,具体取决于他们使用的 Linux 版本以及他们是否打开了终端:

Broadcast message from *duchess@client4* on pts/4 (Sun 2021-05-24 10:54:43 PDT):

The system is going down for poweroff at Sun 2021-05-24 11:04:43 PDT!

取消关机:

$ shutdown -c

登录用户可能会看到此消息:

Broadcast message from *duchess@client4* on pts/4 (Sun 2021-05-24 10:56:00 PDT):

The system shutdown has been cancelled

创建你自己的消息:

$ shutdown -h +6 "Time to stop working and go outside to play!"

而不是指定关机的分钟数,你可以按 24 小时制 hh:mm 格式设置关机时间。以下示例在晚上 10:15 关机:

$ shutdown -h 22:15

重新启动:

$ shutdown -r

关闭系统但不断电:

$ shutdown -H

使用无选项运行 shutdown 相当于 shutdown -h +1

讨论

shutdown 仅在使用 -h 选项时发送消息,除非使用 -h now 选项或 -k 选项。这些称为 wall 消息,即“写给所有登录用户”。Linux 发行版在支持此功能方面有所不同,因此你的特定 Linux 上的其他用户可能看不到这些消息。

  • --help 显示选项摘要。

  • -H--halt 执行干净的关机但不断电;你必须按住电源按钮来断电。

  • -P--poweroff 执行干净的关机并断电。

  • -r-reboot 执行干净的关机并重新启动机器。

  • -k 发送一条消息给所有登录用户而不关机。

  • --no-wall 禁用 wall 消息。

参见

  • man 8 shutdown

  • man 1 wall

  • man 8 systemd-halt.service

3.3 使用 halt、reboot 和 poweroff 进行关机和重新启动

问题

你了解 shutdown 命令,现在想知道 haltrebootpoweroff 的用途以及如何使用它们。

解决方案

这些基本上都是相同的。

halt 执行干净的关机,停止所有服务和进程,并卸载文件系统,但不关闭机器。在 halt 命令完成后,您必须按住机器的电源按钮来完成关机。

reboot 执行干净的关机并重新启动系统。

poweroff 执行干净的关机并关闭机器:

$ halt
$ reboot
$ poweroff

haltpoweroff 命令可以重新启动系统:

$ halt --reboot
$ poweroff --reboot

讨论

如果你觉得这看起来有点奇怪和冗余,你是对的。随着软件的老化,垃圾会积累并永远不会消失。Linux 自 1991 年问世以来,起初是 Unix 的免费克隆,Unix 则诞生于 1969 年。这些年来,各种贡献者修改代码并添加他们喜爱的功能。

haltpoweroff 是相同的命令,并支持相同的选项:

  • --help 显示选项摘要。

  • --halt 执行干净的关机但不关闭机器(是的,halthalt --halt 作用相同)。

  • -p--poweroff 执行干净的关机并关闭机器(是的,poweroffpoweroff --poweroff 作用相同)。

  • --reboot 执行干净的关机并重新启动机器。

  • -f--force 强制立即停止或关机。跳过所有运行中的服务关闭,杀死所有进程,并卸载或以只读方式挂载所有文件系统。当正常关机命令失败时,两次运行它来强制非正常关机;例如,poweroff -f -f

  • -w--wtmp-only 不执行关机,只在 /var/log/wtmp 中写入条目。

  • -d--no-wtmp 阻止写入 wtmp 条目。

另请参阅

  • man 8 halt

  • man 8 poweroff

  • man 8 systemd-halt.service

3.4 使用 systemctl 将系统置于睡眠模式

问题

您的 Linux 系统使用 systemd,您希望使用 systemctl 管理系统睡眠模式。

解决方案

systemctl 提供这些节能模式:suspendhibernatehybrid-sleepsuspend-then-hibernate

将您的系统置于挂起模式:

$ systemctl suspend

这会将当前会话存储在内存中,并将所有硬件置于挂起状态。通过按任意键、移动鼠标或打开笔记本盖子来唤醒系统。

将您的系统置于休眠模式:

$ systemctl hibernate

这会将您的会话存储在磁盘上并关闭机器。按下电源按钮唤醒系统,它可能需要一两分钟来恢复,恢复时会回到您离开的位置。

将您的系统置于混合休眠模式:

$ systemctl hybrid-sleep

这会将您的系统挂起到内存和磁盘,并关闭除 RAM 外的所有设备。如果系统 RAM 失去电源,系统将从磁盘恢复。按下电源按钮唤醒系统。

将您的系统置于挂起后休眠模式:

$ systemctl suspend-then-hibernate

suspend-then-hibernate 首先进入挂起模式,然后根据 /etc/systemd/sleep.conf 中的 HibernateDelaySec= 设置的时间间隔进入休眠模式。按下电源按钮唤醒系统。

讨论

详细了解不同睡眠状态,请参见 Recipe 3.9 中的讨论。

桌面环境应该有按钮用于进入省电模式,并有一个图形化配置工具,用于控制诸如屏幕空白、屏幕锁定、电源按钮、鼠标以及笔记本盖盖合等事件。

电源管理在笔记本电脑上效果最佳,可能不符合您的 Linux 发行版的预期行为。电源管理受到您的 UEFI、CPU 功能、udev、高级配置与电源接口(ACPI)、内核编译选项以及可能的其他设备和程序影响;这很大程度上取决于您的特定 Linux 如何实现电源管理。请查阅您的 Linux 发行版文档。

参见

  • man 1 systemctl

  • man 8 systemd-halt.service

3.5 通过 Ctrl-Alt-Delete 重新启动解决问题

问题

您希望一种可靠的重新启动方法,即使在遇到崩溃和运行失控进程等问题时也能正常工作。

解决方案

古老的“三键敬礼”,Ctrl-Alt-Delete,就是为此而生的。按顺序按住这三个键,它们将覆盖大多数问题并重新启动系统。在某些 Linux 发行版中,Ctrl-Alt-Delete 被禁用,您可以进行更改。

在 Linux 控制台中,Ctrl-Alt-Delete 由 systemd 控制。请参见 Recipe 3.6 了解如何管理 systemd 中的 Ctrl-Alt-Delete。

对于没有 systemd 的系统,请参阅本章讨论。

图形环境有其独立的 Ctrl-Alt-Delete 配置工具,与 systemd 无关。例如,在 Xfce4 设置管理器中有一个键盘配置模块(Figure 3-1);在 GNOME 中,请使用 GNOME 设置工具中的键盘设置模块。

在 Xubuntu 中配置 Ctrl-Alt-Delete

图 3-1. 设置 → 键盘 → 应用程序,在 Xubuntu 中配置键盘快捷键

如果您喜欢其他组合键,请使用您喜欢的任何键。您甚至可以使用单个键,尽管这可能会因意外按键而重新启动。

讨论

在不使用 systemd 的 Linux 系统上,Ctrl-Alt-Delete 受 /etc/inittab 文件控制。以下是来自 MX Linux 的典型配置示例:

# What to do when CTRL-ALT-DEL is pressed.
ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now

12345 使其在运行级别 1、2、3、4 和 5 中生效。-t1 表示等待一秒,-a 调用 /etc/shutdown.allow-r 是重新启动。使用 -h 选项配置它以关闭系统,就像从命令行运行 shutdown 一样(参见 Recipe 3.2)。要禁用 Ctrl-Alt-Delete,请注释掉带有 shutdown 命令的行。

注意,-t1-a 并不是所有 shutdown 命令实现中都存在。上述示例来自 MX Linux。MX Linux 支持 Unix System V 初始化系统(SysV init)和 systemd,您可以在引导菜单中选择想要使用的系统。

Ctrl-Alt-Delete 编码到 IBM PC BIOS/UEFI 中,应在启动操作系统之前始终重新启动系统,直到 GRUB 启动操作系统之前。

Ctrl-Alt-Delete 由 IBM 工程师 David Bradley 为 IBM PC BIOS 创建。最初它是开发者工具,不是为用户设计的。它的设计需要用双手操作,以防意外按下。

然后微软采用了它,在第一次按下时弹出任务管理器,并在第二次按下时重启。后来在 Windows NT 中,它用于访问 Windows 登录屏幕。据说这是一种安全措施,防止用户被虚假登录屏幕欺骗,这是一个很久以前的风险,但那时候发生过。在 YouTube 视频中保存了 Bradley 先生和比尔·盖茨关于 Ctrl-Alt-Delete 发明和使用的有趣对话,希望它能永远保留:“Control-Alt-Delete: David Bradley & Bill Gates”

参见

  • man 7 systemd.special

3.6 禁用、启用和配置 Linux 控制台中的 Ctrl-Alt-Delete

问题

systemd 控制 Linux 控制台中 Ctrl-Alt-Delete 的行为,您想知道如何管理它。

解决方案

您可以检查状态,禁用或启用 Ctrl-Alt-Delete,或将其设置为关闭系统。

Ctrl-Alt-Delete 单元文件不是服务,而是一个目标,因此不作为守护程序运行。如果存在/etc/systemd/system/ctrl-alt-del.target符号链接,则启用 Ctrl-Alt-Delete。

以下示例禁用和 mask ctrl-alt-del.target

$ sudo systemctl disable ctrl-alt-del.target
Removed /etc/systemd/system/ctrl-alt-del.target.

$ sudo systemctl mask ctrl-alt-del.target
Created symlink /etc/systemd/system/ctrl-alt-del.target → /dev/null.

取消 mask 并重新启用它:

$ sudo systemctl unmask ctrl-alt-del.target
Removed /etc/systemd/system/ctrl-alt-del.target.

$ sudo systemctl enable ctrl-alt-del.target
Created symlink /etc/systemd/system/ctrl-alt-del.target →
/lib/systemd/system/reboot.target.

更改立即生效。

将其更改为通过将ctrl-alt-del.target单元链接到poweroff.target单元而关闭系统。首先禁用它以删除现有的符号链接,然后创建新的符号链接:

$ sudo systemctl disable ctrl-alt-del.target
Removed /etc/systemd/system/ctrl-alt-del.target.

$ sudo ln -s /lib/systemd/system/poweroff.target \
  /etc/systemd/system/ctrl-alt-del.target

现在它将关闭系统而不是重新启动。

讨论

使用stat命令查看符号链接:

$ stat /lib/systemd/system/ctrl-alt-del.target
  File: /lib/systemd/system/ctrl-alt-del.target -> reboot.target
  Size: 13              Blocks: 0          IO Block: 4096   symbolic link
Device: 802h/2050d      Inode: 136890      Links: 1
Access: (0777/lrwxrwxrwx)  Uid: ( 0/ root)   Gid: ( 0/ root)

您不应更改任何/lib/systemd/system/中的链接。相反,应在/etc/systemd/system/中创建新的符号链接,以便您的更改不会被系统更新覆盖。

参见

  • man 7 systemd.special

3.7 使用 cron 创建定时关机

问题

您希望您的机器在夜间自动关闭,这样您就可以离开而不必担心它。或者,您的用户不爱关心节能,拒绝养成晚上关闭电脑的习惯。

解决方案

使用cron创建定时关机。例如,将以下行添加到/etc/crontab,每晚 10:30 关闭系统,并提前 20 分钟警告。编辑/etc/crontab需要 root 权限,以下示例使用 nano 文本编辑器:

$ sudo nano /etc/crontab
#  m   h   dom mon dow   user    command
 10  22    *   *   *    root    /sbin/shutdown -h +20
警告

在您的工作计算机上执行此操作之前,请查看雇主的政策。如果他们在夜间运行更新和备份,则您的计算机可能需要保持开启状态。

此示例仅在工作日晚上 11 点运行,并立即关闭系统:

#  m   h   dom mon dow   user    command
 00  23    *   *  1-5   root    /sbin/shutdown -h now

另一种方法是以 root 身份或使用sudo运行crontab命令:

$ sudo crontab -e
# m   h     dom mon  dow command
 00  23    *   *    1-5 /sbin/shutdown -h now

运行 crontab 时没有名称字段,就像 /etc/crontab 中那样。前面的示例打开了根用户的 crontab 以编辑模式。编辑并保存,然后完成。

不要试图自己命名文件。编辑时,这是一个临时文件,保存时 crontab 会自动重命名。它将保存在 /var/spool/cron/crontabs 中。

讨论

/etc/crontab 有一个名称字段,因此任何用户都可以在此文件中添加条目,但只有 root 可以编辑 /etc/crontab。希望控制自己个人 crontab 的用户应该使用 crontab 命令,因为个人 crontab 不需要 root 权限。

/etc/crontab 中的字段可能需要一点时间来适应 (表 3-1),这里有更多示例和解释。

表 3-1. crontab 值表

字段 允许值
分钟 0-59
小时 0-23
月份 1-12
每月 1-31
星期 0-7

星号 * 是“全部”的通配符。

仅在周末关闭:

# shutdown at 1:05 am Saturdays and Sundays
00 01   * * 7,0   root /sbin/shutdown -h +5

cron 中有一个怪异之处,即周日为 0 或 7。这可以追溯到很久以前,我不知道为什么会这样持续下去。您必须测试才能确定有效值,因此可能需要使用 6,7 来表示星期六和星期日:

00 01   * * 6,7   root /sbin/shutdown -h +5

使用sat,sun会很方便,但你只能输入一个具体的星期日,而不能在列表中使用名称。星期和月份名称使用首三个字母表示:sat, sun, jan, feb。大小写不敏感。

您可以使用范围:1–4 表示 1, 2, 3 和 4。

范围和列表可以混合使用:1, 3, 5, 6-10。

步长值遵循范围:

  • 10–23/2 表示范围内每隔两个小时

  • */2 在 dow 字段表示每隔一天

  • 2–6/2 等同于 2, 4, 6

下面的字符串是替代前五个字段的好快捷方式:

@reboot
@yearly
@annually
@monthly
@weekly
@daily
@midnight
@hourly

参见

  • man 8 cron

  • man 1 crontab

  • man 5 crontab

3.8 使用 UEFI 唤醒安排自动启动

问题

定时关机是非常方便的,你也希望有定时唤醒。

解决方案

你很幸运,因为 Linux 支持定时唤醒。有三种方法可尝试:网络唤醒(Wake-on-LAN)、实时时钟(RTC)唤醒,或者如果您的计算机具有预定唤醒功能,则可以使用计算机的 UEFI 设置。

UEFI 唤醒是最可靠的。图 3-2 显示了联想 ThinkPad 上预定唤醒的屏幕。

联想 UEFI 唤醒调度器

图 3-2. 在联想 UEFI 中安排唤醒

在启动时按相应的 Fn 键进入 UEFI 设置。在 Dell、ASUS 和 Acer 系统上通常是 F2;联想使用 F1。然而,这会有所不同。例如,某些系统使用删除键,请查看您设备的文档。某些系统在启动屏幕上显示按键信息。要在正确时间按下键可能有点棘手,所以像按电梯按钮那样,尽早按下电源按钮后开始按键。

如果您的系统没有 UEFI 唤醒功能,请尝试使用醒来局域网 (参见 Recipe 3.10,需要第二个设备发送唤醒信号) 或者 RTC 唤醒 (参见 Recipe 3.9)。

讨论

让我们简要讨论一下 BIOS 和 UEFI 的含义。当您启动计算机时,第一批启动指令来自存储在计算机主板上的基本输入输出系统(BIOS)或统一可扩展固件接口(UEFI)固件。BIOS 是自 1980 年以来一直存在的旧系统。UEFI 是其现代替代品。UEFI 包括对传统 BIOS 的支持,尽管有一天这将被移除。几乎所有在 2000 年中期之后制造的计算机都有 UEFI。

UEFI 拥有比旧 BIOS 更多的功能,就像一个小型操作系统。UEFI 设置界面控制启动顺序、启动设备、安全选项、安全启动、超频、显示硬件健康状况、网络以及许多其他功能。

参见

  • Recipe 3.9

  • Recipe 3.10

  • Recipe 3.11

3.9 使用 RTC 唤醒调度自动启动

问题

您希望使用 RTC 设置定时唤醒,因为您的 UEFI 设置没有预定唤醒功能,或者您只是想要这样做。

解决方案

使用 rtcwake 命令,该命令应该已经存在于您系统中的 util-linux 软件包中。rtcwake 停止和唤醒您的系统。您可以设置它在指定的时间间隔后唤醒系统,例如从现在开始的 1800 秒,或者在预定的时间和日期唤醒系统。

您系统的实时时钟(RTC)应设置为协调世界时(UTC)。

rtcwake 停止您的系统时,它会将其送入 ACPI 睡眠状态。查看 /sys/power/state 以查看您的系统支持哪些睡眠状态。在以下示例中,只支持六个 ACPI 睡眠状态中的三个:

$ cat /sys/power/state
freeze mem disk

在非 systemd Linux 上,运行 cat /proc/acpi/info

在上面的示例中,我们有三个待机状态可供尝试。根据以下示例测试每一个:

$ sudo rtcwake -m freeze -s 60

-m 指定待机模式,-s 是系统重新启动之前的秒数。当成功时,你将看到系统进入睡眠状态,然后唤醒,并且会显示成功或错误信息。

以下示例对明天上午 8 点的唤醒进行了模拟运行:

$ sudo rtcwake -n -m disk no -u -t $(date +%s -d "tomorrow 08:00")
rtcwake: wakeup from "disk" using /dev/rtc0 at Mon Nov 23 08:00:00 2021

删除 -n 以禁用模拟运行,并实际运行它。

以下是一个简单的 /etc/crontab 示例,用于自动执行关机和唤醒。rtcwake 命令在工作日的晚上 11 点将系统挂起到磁盘,并在 8 小时后唤醒:

#  m   h   dom mon dow   user    command
 00  23    *   *  1-5   root    /usr/sbin/rtcwake -m disk -s 28800

讨论

查看您系统的 BIOS/UEFI,以验证您的硬件时钟是否设置为 UTC。如果没有按钮或某种设置来将实时时钟更改为 UTC,手动将时间更改为当前的 UTC 时间。

示例中包含的 -u -t +$(date +%s -d “tomorrow 08:00”) 将 Unix 纪元时间转换为人类可读的值。Unix 纪元时间是从 1970 年 1 月 1 日午夜以来经过的秒数(UTC)。date +%s 报告当前的 Unix 纪元时间。-t 选项将 Unix 纪元时间传递给 date 进行转换,-u 指定你的硬件时钟设置为 UTC。

rtcwakeno 选项意味着不进入睡眠状态,只设置唤醒时间。去掉 no 选项即可立即进入睡眠状态。

实时时钟(RTC)唤醒最不可靠。你的系统必须进入 Linux 支持的 ACPI 睡眠状态。ACPI 是现代电源管理标准,用于管理睡眠状态。它应该是供应商中立和硬件无关的,但标准很复杂,硬件供应商通常仅支持其部分功能。增加乐趣的是,不同的 Linux 发行版以不同的方式实现它。

ACPI 有六个睡眠状态,S0-S5。Linux 内核支持最多四个,不同的发行版在支持哪些以及支持多少方面有所不同:

S0

系统正在运行,显示器可能关闭,大多数外设开启。

S1

启动挂起时,CPU 停止运行,CPU 和 RAM 的电源是打开的。

S2

CPU 关闭电源,脏缓存被刷新到 RAM。

S3

也称为待机、休眠和挂起到 RAM。数据可能不会写入磁盘。

S4

休眠,挂起到磁盘。将所有 RAM 中的数据写入磁盘,然后系统关闭电源。

S5

类似于关闭系统电源,但电源按钮和外设(如键盘、网络接口和 USB 设备)仍然供电。

参见

3.10 使用有线以太网设置远程唤醒 Wake-on-LAN

问题

如果你的 UEFI 设置没有预定的唤醒功能,或者功能过于简单,或者你希望在随机时间发送唤醒信号,你可以设置远程触发唤醒使用 Wake-on-LAN。这个方案是为了在与发送唤醒信号设备相同网络上唤醒一台机器,你的目标机器必须使用有线以太网接口。

解决方案

配置你的电脑以监听唤醒请求,然后使用第二个设备,如另一台计算机、智能手机或树莓派发送唤醒信号,称为 魔术数据包。它并不是真正的魔术,只是专门为远程唤醒设计的特殊数据包。(是的,我也很遗憾它并非真正的魔术。)

首先启动你的系统的 UEFI 设置,寻找启用 Wake-on-LAN 的设置。

警告

一个重要的预防措施是禁用所有启用 PXE(预启动执行环境)引导的设置。如果启用了 PXE 引导,并且您的网络上有 PXE 服务器(预启动执行环境服务器,用于从网络安装服务器引导),则可能会导致您的机器唤醒以进行 PXE 引导并安装新的映像,覆盖现有安装。

然后退出并完成启动。安装wakeonlanethtool软件包。

获取您的以太网接口的名称,在本例中为enp0s25,并使用ethtool验证其是否支持 Wake-on-LAN。为了清晰起见,输出进行了缩写:

$ ip addr show
2: enp0s25: <BROADCAST,MULTICAST,UP,LOWER_UP> state UP 0
    link/ether 9c:ef:d5:fe:8f:20 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.97/24 brd 192.168.1.255 scope global dynamic
    [...]

$ sudo ethtool enp0s25 | grep -i wake-on
        Supports Wake-on: pumbg
        Wake-on: g 

记录您接口的 MAC 地址。在前面的ip示例中,“ether”行列出了 MAC 地址,9c:ef:d5:fe:8f:20。您的地址将不同,因为 MAC 地址是唯一的。

“Supports Wake-on: pumbg”是验证您的接口是否具备必要支持的魔法短语,由g开关指示。第二行“Wake-on: g”告诉您已经启用。如果没有启用,请启用它:

$ sudo ethtool -s *enp0s25* wol g

如果重启后未保持启用状态,请像这样向/etc/crontab添加一个条目,以便在每次重启后运行命令:

$ @reboot root /usr/bin/ethtool -s *enp0s25* wol g

关闭计算机,然后从同一网络上的第二设备发送命令唤醒它,使用目标机器以太网接口的 MAC 地址:

$ /usr/bin/wakeonlan *9c:ef:d5:fe:8f:20*

如果目标机器和第二设备在同一网络但不同子网中,需指定目标机器的广播地址:

$ /usr/bin/wakeonlan -i *192.168.44.255 9c:ef:d5:fe:8f:20*

讨论

Wake-on-LAN 是一种通过网络发送唤醒信号远程唤醒计算机的以太网标准。wakeonlan是大多数 Linux 系统上命令和软件包的名称。

当您的计算机关机时,并非真正关闭,而是处于低功耗模式,可以接收和响应魔术包唤醒信号。

wakeonlan通过 UDP 端口 9 发送魔法包。魔法包发送到网络的广播地址,网络上的每台主机都会接收此包。MAC 地址确保只有具有该地址的主机会被唤醒。

目标机器会像按下电源按钮一样唤醒。

参见

  • man 1 wakeonlan

  • man 8 ethtool

  • 配方 3.8

  • 配方 3.9

  • 配方 3.11

3.11 设置通过 WiFi 进行远程唤醒(WoWLAN)

问题

您希望通过其无线接口(Wake-on-Wireless LAN,或 WoWLAN)唤醒远程计算机。

解决方案

此配方适用于在发送唤醒信号的设备与目标机器位于同一网络上时唤醒机器。

您的机器必须具有内置无线接口,可以是主板集成的或者是 PCI(外围组件互连)的。使用 USB 接口将无法工作,因为机器关机时 USB 总线没有供电。

首先,进入要远程唤醒的机器的 UEFI 设置,并启用任何 Wake-on-LAN 设置。

警告

一个重要的预防措施是同时禁用所有启用 PXE 启动的设置。如果启用了 PXE 启动,并且在你的网络上有一个 PXE 服务器,你的机器可能会因为 PXE 启动而唤醒并安装新的镜像,覆盖现有的安装。

然后退出并完成启动。安装 iw 命令,并使用它列出所有的无线设备:

$ iw dev
phy#0
        Interface *wlxcc3fd5fe014c*
                ifindex 3
                wdev 0x1
                addr *9c:bf:25:fe:0e:7c*
                ssid *accesspointe*
                type managed
                channel 11 (2462 MHz), width: 20 MHz, center1: 2462 MHz
                txpower 20.00 dBm 

如果有多个设备,请查询你想要使用的设备。以下示例显示了一个不支持 WoWLAN 的无线接口:

$ iw phy0 wowlan show
command failed: Operation not supported (-95)

下面的示例适用于支持 WoWLAN 的接口,但未启用:

$ iw phy0 wowlan show
WoWLAN is disabled

启用 WoWLAN:

$ sudo iw phy0 wowlan enable magic-packet
WoWLAN is enabled:
  * wake up on magic packet

iw dev 提供了 MAC 地址,你的第二台设备需要发送魔术数据包:

$ /usr/bin/wakeonlan *9c:bf:25:fe:0e:7c*

将魔术数据包发送到同一网络上不同子网中的机器,使用子网的广播地址:

$ /usr/bin/wakeonlan -i *192.168.44.255 9c:bf:25:fe:0e:7c*

讨论

当远程计算机是笔记本时,这种方法效果很好,因为笔记本通常有集成的无线网络接口,通常支持更多功能。台式机通常不配备集成的无线接口,因此你必须仔细挑选支持 WoWLAN 和 Linux 的 PCI/PCIe 无线适配器。

参见

  • man 8 iw

  • man 1 wakeonlan

  • 第 3.8 节

  • 第 3.9 节

  • 第 3.10 节

第四章:使用 systemd 管理服务

每次启动 Linux 计算机时,它的初始化系统都会启动一批进程,从几十个到数百个不等,具体取决于系统设置。您可以在启动屏幕上看到这一过程(Figure 4-1)。按下 Escape 键隐藏图形启动屏幕,查看启动消息。

Linux 启动消息

图 4-1:Linux 启动消息

在过去,我们有 Unix System V 初始化系统(SysV init)、BSD init 和 Linux Standard Base(LSB)初始化系统来启动进程。SysV init 曾经最为常见。但那些日子已经逐渐过去,现在 systemd 是 Linux 的新光辉初始化系统。它已被所有主要的 Linux 发行版采纳,尽管当然仍有一些发行版仍在使用传统的初始化系统。

在本章中,您将了解您的 Linux 发行版是否使用 systemd。您将学习进程、线程、服务和守护程序是什么,并学习如何使用 systemd 管理服务:启动、停止、启用、禁用和检查状态。您将熟悉 systemctl 命令,这是 systemd 系统和服务管理器。

systemd 是为现代复杂的服务器和桌面系统设计的功能性软件,远比传统的初始化系统做得更多。它提供从启动到关闭的完整服务管理,启动进程在启动时、启动后按需启动,并在不需要时关闭服务。它管理诸如系统日志、自动挂载文件系统、自动解决服务依赖关系、名称服务、设备管理、网络连接管理、登录管理等功能。

当你意识到进程在计算机上执行所有操作时,这听起来像是很多事情,而所有这些功能曾由大量其他程序提供。systemd 将所有这些功能集成在一个软件套件中,应在所有 Linux 系统上以相同方式运行,尽管像往常一样,Linux 存在一些细微的例外,如文件位置和服务名称。请注意,你的特定 Linux 可能与本章示例有所不同。

systemd 尝试通过并行启动和仅启动必要的服务来减少启动时间并更有效地分配系统资源,其他服务可以在启动后按需启动。一个依赖于其他服务的服务不再需要等待这些服务可用,因为它所需的只是等待 Unix 套接字可用。Recipe 4.9 展示了如何找到拖慢系统启动的进程。

systemd 的二进制文件使用 C 语言编写,这提供了一些性能增强。传统的初始化系统则是大量的 shell 脚本,而任何编译语言都比 shell 脚本运行得更快。

systemd 兼容 SysV 初始化。大多数 Linux 发行版保留了传统的 SysV 配置文件和脚本,包括 /etc/inittab,以及 /etc/rc.d//etc/init.d/ 目录。当服务没有 systemd 配置文件时,systemd 会寻找 SysV 配置文件。systemd 也与 Linux 标准基础(LSB)初始化兼容。

systemd 服务文件比 SysV 初始化文件更小且更易于理解。比较一下 sshd 的 SysV 初始化文件和其 systemd 服务文件。这是来自 MX Linux 的 sshd 初始化文件片段 /etc/init.d/ssh

#! /bin/sh

### BEGIN INIT INFO
# Provides:		sshd
# Required-Start:	$remote_fs $syslog
# Required-Stop:	$remote_fs $syslog
# Default-Start:	2 3 4 5
# Default-Stop:
# Short-Description:	OpenBSD Secure Shell server
### END INIT INFO

set -e

# /etc/init.d/ssh: start and stop the OpenBSD "secure shell(tm)" daemon

test -x /usr/sbin/sshd || exit 0

umask 022

if test -f /etc/default/ssh; then
[...]

从 Ubuntu 20.04 完整的 systemd 服务文件 /lib/systemd/system/ssh.service 开始,总共有 162 行内容:

[Unit]
Description=OpenBSD Secure Shell server
Documentation=man:sshd(8) man:sshd_config(5)
After=network.target auditd.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run

[Service]
EnvironmentFile=-/etc/default/ssh
ExecStartPre=/usr/sbin/sshd -t
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
ExecReload=/usr/sbin/sshd -t
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartPreventExitStatus=255
Type=notify
RuntimeDirectory=sshd
RuntimeDirectoryMode=0755

[Install]
WantedBy=multi-user.target
Alias=sshd.service

即使没有阅读文档,或者不了解 systemd 的任何信息,您也可以理解此文件应该执行的一些功能。

请查看 Rethinking PID 1 ,由 systemd 的发明者和维护者之一 Lennart Poettering 提供了对 systemd 的详细介绍。《重新思考 PID 1》详细介绍了构建新的初始化系统的原因、其架构、优势,以及如何利用现有 Linux 内核功能来替代重复现有功能。

4.1 查看 Linux 是否使用 systemd

问题

您需要知道您的 Linux 发行版是否使用 systemd 或其他系统。

解决方案

查找 /run/systemd/system/ 目录。如果存在,则您的初始化系统是 systemd。

讨论

如果您的发行版支持多个初始化系统,可能会出现 /run/systemd/ 目录。但是除非您看到 /run/systemd/system/,否则 systemd 不是当前的初始化系统。

还有其他几种方法可以了解您的系统使用的初始化系统。尝试查询 /sbin/init。最初这是 SysV 可执行文件,现在大多数 Linux 发行版保留了该名称并将其链接到 systemd 可执行文件。此示例确认初始化是 systemd:

$ stat /sbin/init
File: /sbin/init -> /lib/systemd/systemd
[...]

在使用 SysV 初始化的系统上,它没有符号链接:

$ stat /sbin/init
File: /sbin/init
[...]

/proc 伪文件系统是您的 Linux 内核的接口,包含正在运行系统的当前状态。它被称为伪文件系统,因为它仅存在于内存中,而不在磁盘上。在此示例中,/proc/1/exe 符号链接到 systemd 可执行文件:

$ sudo stat /proc/1/exe
File: /proc/1/exe -> /lib/systemd/systemd
[...]

在 SysV 系统上,它链接到 init

$ sudo stat /proc/1/exe
File: /proc/1/exe -> /sbin/init
[...]

/proc/1/comm 文件报告您当前的启动初始化系统:

$ cat /proc/1/comm
systemd

在 SysV 系统上,它报告 init

$ cat /proc/1/comm
init

附加到进程 ID(PID)1 的命令是您的初始化。PID 1 是在启动时启动的第一个进程,然后启动所有其他进程。您可以使用 ps 命令查看这一点:

$ ps -p 1
  PID TTY          TIME CMD
    1 ?        00:00:00 systemd

当使用 SysV 初始化时,看起来是这样的:

$ ps -p 1
  PID TTY          TIME CMD
    1 ?        00:00:00 init

查看 Recipe 4.2 以获取有关 PID 1 的更多信息。

Linux 对 systemd 的支持各不相同。大多数主要的 Linux 发行版都采用了 systemd,包括 Fedora、Red Hat、CentOS、openSUSE、SUSE Linux Enterprise、Debian、Ubuntu、Linux Mint、Arch、Manjaro、Elementary 和 Mageia Linux。

一些流行的发行版不支持 systemd,或者包含它但不作为默认的 init 程序,如 Slackware、PCLinuxOS、Gentoo Linux、MX Linux 和 antiX。

参见

  • Distrowatch 提供了关于数百种 Linux 发行版的信息

  • man 5 proc

  • man 1 pstree

  • man 1 ps

4.2 理解 PID 1,所有进程的母体

问题

您想更好地理解 Linux 上的服务和进程。

解决方案

PID 1 是 Linux 系统上所有进程的母体。这是第一个启动的进程,然后它启动所有其他进程。

进程是一个或多个程序的运行实例。Linux 系统中的每个任务都由进程执行。进程可以创建独立的副本,即它们可以 fork。复制的进程称为 子进程,原始进程称为 父进程。每个子进程都有自己独特的 PID,以及分配给它的系统资源,如 CPU 和内存。线程 是在并行中运行的轻量级进程,并与其父进程共享系统资源。

一些进程在后台运行,不与用户交互。Linux 将这些进程称为 服务守护进程,它们的名称通常以字母 D 结尾,如 httpd、sshd 和 systemd。

每个 Linux 系统首先启动 PID 1,然后启动所有其他进程。使用 ps 命令按 PID 排序列出所有运行中的进程:

$ ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 10:06 ?        00:00:01 /sbin/init splash
root         2     0  0 10:06 ?        00:00:00 [kthreadd]
root         3     2  0 10:06 ?        00:00:00 [rcu_gp]
root         4     2  0 10:06 ?        00:00:00 [rcu_par_gp]
[...]

pstree 命令将这些大量信息组织成树形图。此示例显示所有进程及其子进程、PID 和线程,这些信息被包含在花括号中:

$ pstree -p
systemd(1)─┬─ModemManager(925)─┬─{ModemManager}(944)
           │                   └─{ModemManager}(949)
           ├─NetworkManager(950)─┬─dhclient(1981)
           │                     ├─{NetworkManager}(989)
           │                     └─{NetworkManager}(991)
           ├─accounts-daemon(927)─┬─{accounts-daemon}(938)
           │                      └─{accounts-daemon}(948)
           ├─acpid(934)
           ├─agetty(1103)
           ├─avahi-daemon(953)───avahi-daemon(970)
[...]

完整的 pstree 输出非常庞大。您可以查看单个进程,通过其 PID 标识,并显示其父进程、子进程和线程,例如 Kate 文本编辑器的以下示例:

$ pstree -sp 5193
systemd(1)───kate(5193)─┬─bash(5218)
                        ├─{kate}(5195)
                        ├─{kate}(5196)
                        ├─{kate}(5197)
                        ├─{kate}(5198)
                        ├─{kate}(5199)
[...]

这显示了 systemd(1) 是 Kate 的父进程,bash(5218) 是 Kate 的子进程,花括号中的所有进程都是 Kate 的线程。

讨论

进程始终处于多种状态之一,并根据系统活动而更改。下面的 pstree 示例显示 PID、用户、状态和命令字段:

$ ps -eo pid,user,stat,comm
  PID USER       STAT COMMAND
    1 root       Ss   systemd
    2 root       S    kthreadd
   32 root       I<   kworker/3:0H-kb
   68 root       SN   khugepaged
11222 duchess    Rl   konsole
  • R 表示当前正在运行或在运行队列中等待。

  • l 表示进程是多线程的。

  • S 是可中断睡眠状态;进程正在等待事件完成。

  • s 是一个会话领导者。会话是作为一个单元管理的相关进程。

  • I 是空闲的内核线程。

  • < 表示高优先级。

  • N 表示低优先级。

man 1 ps 中还有几种不常用的状态,您可以在其中阅读。

参见

  • Recipe 4.7

  • man 5 proc

  • man 1 pstree

  • man 1 ps

4.3 使用 systemctl 列出服务及其状态

问题

您想要列出系统中安装的所有服务,并了解服务的状态:正在运行、未运行或错误状态。

解决方案

systemctl,systemd 管理器命令,告诉所有信息。无选项运行它以查看所有加载单元的详细列表。systemd 单元是任何在单元配置文件中定义并由 systemd 管理的相关进程批处理:

$ systemctl

这将打印出大量信息:在我的测试系统上,共有 177 个活动加载的单元,包括完整的单元名称、状态和长描述。将输出重定向到文本文件以便更轻松地学习:

$ systemctl > /tmp/systemctl-units.txt

通过列出所有单位(包括活动和非活动状态),使信息超载:

$ systemctl --all

这导致在我的测试系统上列出了 349 个加载的单元,包括 not-foundinactive 单元。总共有多少个单元文件?以下示例显示了 5 个其中的 322 个:

$ systemctl list-unit-files
UNIT FILE                                      STATE
proc-sys-fs-binfmt_misc.automount              static
-.mount                                        generated
mount                                          generated
dev-hugepages.mount                            static
home.mount                                     generated
[...]
322 unit files listed.

我们对服务文件感兴趣,因为 Linux 用户和管理员主要与服务文件交互,并且很少需要处理其他类型的单元文件。安装了多少个?让我们来看看:

$ systemctl list-unit-files --type=service
UNIT FILE                                  STATE
accounts-daemon.service                    enabled
acpid.service                              disabled
alsa-state.service                         static
alsa-utils.service                         masked
anacron.service                            enabled
[...]
212 unit files listed.

前面的示例展示了服务可能处于的四种最常见状态:已启用、已禁用、静态或屏蔽。

只列出已启用的服务:

$ systemctl list-unit-files --type=service --state=enabled
UNIT FILE                                  STATE
accounts-daemon.service                    enabled
anacron.service                            enabled
apparmor.service                           enabled
autovt@.service                            enabled
avahi-daemon.service                       enabled
[...]
62 unit files listed.

只列出已禁用的服务:

$ systemctl list-unit-files --type=service --state=disabled
UNIT FILE                            STATE
acpid.service                        disabled
brltty.service                       disabled
console-getty.service                disabled
mariadb@.service                     disabled
[...]
12 unit files listed.

只列出静态服务:

$ systemctl list-unit-files --type=service --state=static
UNIT FILE                              STATE
alsa-restore.service                   static
alsa-state.service                     static
apt-daily-upgrade.service              static
apt-daily.service                      static
[...]
106 unit files listed.

只列出已屏蔽的服务:

$ systemctl list-unit-files --type=service --state=masked
UNIT FILE                    STATE
alsa-utils.service           masked
bootlogd.service             masked
bootlogs.service             masked
checkfs.service              masked
[...]
36 unit files listed.

讨论

服务单元文件位于 /usr/lib/systemd/system//lib/systemd/system/,具体位置取决于您的 Linux 发行版。这些是您可以阅读的纯文本文件。

已启用

这显示服务已变为可用,并由 systemd 管理。当服务已启用时,systemd 会在 /etc/systemd/system/ 中从 /lib/systemd/system/ 的单元文件创建符号链接。用户可以使用 systemctl 命令启动、停止、重新加载和禁用它。

注意

启用服务并不会立即启动它,而禁用服务也不会立即停止它(参见配方 4.6)。

禁用

禁用意味着在 /etc/systemd/system/ 中没有符号链接,它不会在启动时自动启动。您可以手动停止和启动它。

屏蔽

这意味着服务已链接到 /dev/null/。它完全被禁用,并且无法通过任何方式启动。

静态

这意味着单元文件是其他单元文件的依赖项,用户无法启动或停止它。

您将看到一些不常见的服务状态:

间接

间接状态属于不适合由用户管理的服务,而是由其他服务使用。

生成

生成状态表示服务已从非本地 systemd 初始化配置文件(SysV 或 LSB init)转换而来。

参见

  • man 1 systemctl

4.4 查询所选服务的状态

问题

您想知道一个或几个特定服务的状态。

解决方案

systemctl status 提供了一小段有用的状态信息。以下示例查询了 CUPS 服务。CUPS,即通用 Unix 打印系统,应该在所有 Linux 系统上存在:

$ systemctl status cups.service
● cups.service - CUPS Scheduler
     Loaded: loaded (/lib/systemd/system/cups.service; enabled; vendor preset:
             enabled)
     Active: active (running) since Sun 2021-11-22 11:01:48 PST; 4h 17min ago
TriggeredBy: ● cups.path
             ● cups.socket
       Docs: man:cupsd(8)
   Main PID: 1403 (cupsd)
      Tasks: 2 (limit: 18760)
     Memory: 3.8M
     CGroup: /system.slice/cups.service
             ├─1403 /usr/sbin/cupsd -l
             └─1421 /usr/lib/cups/notifier/dbus dbus://

Nov 22 11:01:48 host1 systemd[1]: Started CUPS Scheduler.

使用以空格分隔的列表查询多个服务:

$ systemctl status mariadb.service bluetooth.service lm-sensors.service

讨论

这少量输出中有大量有用信息(图 4-2)。

CUPS 打印机服务的 systemctl 状态输出。

图 4-2. CUPS 打印机服务的 systemctl 状态输出

服务名字旁边的点是快速状态指示器。它在大多数终端上显示颜色。白色是非活动正在停用状态。红色是失败错误状态。绿色表示活动重新加载正在激活状态。输出中的其余信息如下描述:

已加载

验证单元文件是否已加载到内存中,显示其完整路径,服务是否已启用(参见 4.3 节中关于状态的讨论),vendor preset: disabled/enabled指示安装默认是否在启动时启动。当它被禁用时,供应商默认不会在启动时启动。这仅显示供应商的首选项,不表示当前是否启用或禁用。

活动

告诉您服务是活动还是非活动,并且在该状态中已经多长时间。

进程

报告 PID 及其命令和守护程序。

主 PID

这是 cgroup 切片的进程号。

任务

报告服务启动了多少个任务。任务是 PID。

CGroup

显示服务属于哪个单元切片及其 PID。三个默认单元切片是user.slicesystem.slicemachine.slice

Linux 控制组(cgroups)是一组相关进程及其所有未来子进程。在 systemd 中,slice是 cgroup 的一个子分区,每个 slice 管理特定组的进程。运行systemctl status查看 cgroup 层次结构的图表。

默认情况下,服务和范围单元被分组在/lib/systemd/system/system.slice中。

用户会话分组在/lib/systemd/system/user.slice中。

与 systemd 注册的虚拟机和容器分组在/lib/systemd/system/machine.slice中。

剩余的行是来自journalctl,systemd 日志管理器的最新日志条目。

参见

4.5 启动和停止服务

问题

您希望使用 systemd 停止和启动服务。

解决方案

这是一个 systemctl 的任务。以下示例使用 SSH 服务演示服务管理。

启动服务:

$ sudo systemctl start sshd.service

停止服务:

$ sudo systemctl stop sshd.service

停止然后重新启动服务:

$ sudo systemctl restart sshd.service

重新加载服务的配置。例如,您更改了sshd_config并希望加载新配置而不重新启动服务:

$ sudo systemctl reload sshd.service

讨论

所有这些命令也适用于多个服务,以空格分隔,例如:

$ sudo systemctl start sshd.service mariadb.service firewalld.service

如果您对 systemd 在后台运行的命令好奇,以启动、重新加载或停止各个守护程序,查看它们的单元文件。一些服务在其单元文件中具有启动、重新加载、停止和其他指令,例如此 httpd 的示例:

ExecStart=/usr/sbin/httpd/ $OPTIONS -DFOREGROUND
ExecReload=/usr/sbin/httpd $OPTIONS -k graceful
ExecStop=/bin/kill -WINCH ${MAINPID}

对于这些信息,你不需要特别处理;当你想了解systemctl如何管理特定服务时,它会有所帮助。

参见

  • 配方 4.6

  • man 1 systemctl

4.6 启用和禁用服务

问题

你希望某个服务或多个服务在启动时自动启动,或者你希望阻止某个服务在启动时启动,或者完全禁用它。

解决方案

启用服务会配置它在启动时自动启动。

禁用服务会阻止它在启动时启动,但可以手动启动和停止。

屏蔽服务会禁用它,因此根本无法启动。

以下示例启用了sshd服务:

$ sudo systemctl enable sshd.service
Created symlink /etc/systemd/system/multi-user.target.wants/sshd.service →
/usr/lib/systemd/system/sshd.service

输出显示,启用服务意味着在/lib/systemd/system/中的服务文件和/etc/systemd/system/中创建符号链接。这不会启动服务。你可以使用systemctl start启动服务,或者使用--now选项一条命令启用并启动服务:

$ sudo systemctl enable --now sshd.service

此命令禁用sshd服务。它不会停止服务,所以你必须在禁用后手动停止它:

$ sudo systemctl disable sshd.service
Removed /etc/systemd/system/multi-user.target.wants/sshd.service
$ sudo systemctl stop sshd.service

或者,用一条命令禁用并停止它:

$ sudo systemctl disable --now sshd.service

此命令重新启用mariadb服务,先禁用然后再启用它。如果你已经手动为服务创建了符号链接,则可以快速将它们重置为默认状态:

$ sudo systemctl reenable mariadb.service
Removed /etc/systemd/system/multi-user.target.wants/mariadb.service.
Removed /etc/systemd/system/mysqld.service.
Removed /etc/systemd/system/mysql.service.
Created symlink /etc/systemd/system/mysql.service →
/lib/systemd/system/mariadb.service.
Created symlink /etc/systemd/system/mysqld.service →
/lib/systemd/system/mariadb.service.
Created symlink /etc/systemd/system/multi-user.target.wants/mariadb.service →
/lib/systemd/system/mariadb.service.

以下命令通过屏蔽完全禁用了bluetooth服务,因此它无法启动:

$ sudo systemctl mask bluetooth.service
Created symlink /etc/systemd/system/bluetooth.service → /dev/null.

解除mariadb服务的屏蔽并不会启用它,所以必须手动启动它:

$ sudo systemctl unmask bluetooth.service
Removed /etc/systemd/system/bluetooth.service.
$ sudo systemctl start bluetooth.service

讨论

当你启用、禁用、屏蔽或取消屏蔽一个服务时,它会保持当前状态,除非你使用--now选项。--now选项与enabledisablemask一起使用,可以立即停止或启动服务,但不适用于unmask

参见配方 4.3 中的讨论,了解更多关于 systemd 如何使用符号链接管理服务的信息。

参见

  • man 1 systemctl

  • 参见配方 4.3 中的讨论,了解 systemd 如何使用符号链接管理服务

4.7 停止问题进程

问题

你想知道如何停止问题进程。某个服务可能无响应或者在运行中,生成分支并导致系统挂起。你正常的停止命令不起作用。你该怎么办?

解决方案

在 Linux 系统中,停止进程称为杀死进程。对于带有 systemd 的 Linux 系统,你应该使用systemctl kill。对于没有 systemd 的系统,请使用传统的kill命令。

systemctl kill更好,因为它停止所有属于服务的进程,并且不会留下孤儿进程,也不会重新启动服务并继续造成麻烦。首先尝试不带除服务名称外的任何选项,然后检查状态:

$ sudo systemctl kill mariadb

$ systemctl status mariadb
● mariadb.service - MariaDB 10.1.44 database server
   Loaded: loaded (/lib/systemd/system/mariadb.service; enabled; vendor preset:
enabled)
   Active: inactive (dead) since Sun 2020-06-28 19:57:49 PDT; 6s ago
[...]

服务已干净地停止。如果这样做不起作用,那么尝试核心选项:

$ sudo systemctl kill -9 mariadb

传统的kill命令不识别服务或命令名称,而是需要问题进程的 PID:

$ sudo kill 1234

如果这不能停止它,使用核心选项:

$ sudo kill -9 1234

讨论

使用 top 命令识别失控的进程。无选项运行它,使用最多 CPU 资源的进程将显示在顶部。按下 q 键退出 top

$ top
top - 20:30:13 up  4:24,  6 users,  load average: 0.00, 0.03, 0.06
Tasks: 246 total,   1 running, 170 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.4 us,  0.2 sy,  0.0 ni, 99.4 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem : 16071016 total,  7295284 free,  1911276 used,  6864456 buff/cache
KiB Swap:  8928604 total,  8928604 free,        0 used. 13505600 avail Mem

  PID USER       PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
 3504 madmax     20   0 99.844g 177588  88712 S   2.6  1.1   0:08.68 evolution
 2081 madmax     20   0 3818636 517756 177744 S   0.7  3.2   5:07.56 firefox
 1064 root       20   0  567244 148432 125572 S   0.3  0.9  12:54.75 Xorg
 2362 stash      20   0 2997732 230508 145444 S   0.3  1.4   0:40.72 Web Content
[...]

kill 向进程发送信号,默认信号是 SIGTERM(信号终止)。SIGTERM 是温和的,允许进程清理地关闭。SIGTERM 也可以被忽略,进程不必理会它。信号可以通过名称或数字来标识;对大多数人来说,数字更容易记住,因此默认的拼写方式如下:

$ sudo kill -1 1234

kill -9 是 SIGKILL。SIGKILL 立即且不干净地停止进程,并尝试停止所有子进程。

使用 systemctl kill 杀死服务比使用 kill 更简单且更可靠。你只需要服务名称,不必寻找 PID。它确保停止属于服务的所有进程,而 kill 不能保证这一点。

多年来积累了大量信号,你可以在 man 7 signal 中了解全部内容。根据我的经验,最相关的信号是 SIGTERM 和 SIGKILL,但不要因此停止了解其他信号。

如果你对术语如 kill、parent、child 和 orphan 感到不舒服,我也是。也许总有一天会改变。

参见

  • man 5 systemd.kill

  • man 1 systemctl

  • man 1 kill

  • man 7 signal

4.8 使用 systemd 管理运行级别

问题

你希望以类似于使用 SysV 运行级别的方式重启到不同的系统状态。

解决方案

systemd targets 类似于 SysV 运行级别。这些是引导配置文件,根据不同选项启动系统,例如具有图形桌面的多用户模式、无图形桌面的多用户模式以及紧急和救援模式,用于当前目标无法引导时使用(有关运行级别的更多信息,请参见讨论)。

以下命令检查系统是否正在运行并报告其状态:

$ systemctl is-system-running
running

默认目标是什么?

$ systemctl get-default
graphical.target

获取当前运行级别:

$ runlevel
N 5

重启到救援模式:

$ sudo systemctl rescue

重启到紧急模式:

$ sudo systemctl emergency

重启到默认模式:

$ sudo systemctl reboot

在不改变默认设置的情况下重启到不同的目标:

$ sudo systemctl isolate multi-user.target

设置不同的默认运行级别:

$ sudo systemctl set-default multi-user.target

列出系统上运行级别目标文件及其符号链接:

$ ls -l /lib/systemd/system/runlevel*

列出运行级别目标中的依赖项:

$ systemctl list-dependencies graphical.target

讨论

SysV 运行级别是系统可以引导到的不同状态,例如具有图形桌面、无图形桌面以及在默认运行级别出现问题时使用的紧急运行级别。

systemd targets 大致对应传统的 SysV 运行级别:

  • runlevel0.targetpoweroff.target,关机

  • runlevel1.targetrescue.target,单用户文本模式,所有本地文件系统已挂载,仅 root 用户,无网络连接

  • runlevel3.targetmulti-user.target,多用户文本模式(无图形环境)

  • runlevel5.targetgraphical.target,多用户图形模式

  • runlevel6.targetreboot.target、重新启动

systemctl emergency 是一个特殊的目标,比 rescue 模式更受限:没有服务、没有挂载点,除了根文件系统外,没有网络,只有 root 用户可以使用。它是用于调试问题的最小运行系统。你可能在 GRUB2 引导加载器屏幕上看到启动到救援或紧急模式的选项。

systemctl is-system-running 报告各种系统状态:

  • initializing 表示系统尚未完成启动。

  • starting 表示系统处于启动的最后阶段。

  • running 完全运行,并且所有进程已启动。

  • degraded 表示系统正常运行,但一个或多个 systemd 单元失败了。运行 systemctl | grep failed 查看哪些单元失败了。

  • maintenance 表示要么 rescue 要么 emergency 目标处于活动状态。

  • stopping 表示 systemd 正在关闭。

  • offline 表示 systemd 未运行。

  • unknown 表示 systemd 无法确定操作状态存在问题。

参见

  • man 1 systemctl

  • man 8 systemd-halt.service

4.9 诊断慢启动

问题

systemd 承诺更快的启动,但是你的系统启动缓慢,你想找出原因。

解决方案

你想要执行 systemd-analyze blame。运行它时不加选项,可以看到系统进程列表及其启动所花费的时间:

$ systemd-analyze blame
         34.590s apt-daily.service
          6.782s NetworkManager-wait-online.service
          6.181s dev-sda2.device
          4.444s systemd-journal-flush.service
          3.609s udisks2.service
          2.450s snapd.service
          [...]

仅分析用户进程:

$ systemd-analyze blame --user
          3.991s pulseaudio.service
           553ms at-spi-dbus-bus.service
           380ms evolution-calendar-factory.service
           331ms evolution-addressbook-factory.service
           280ms xfce4-notifyd.service
           [...]

讨论

审查每次启动时启动的所有内容很有用,也许可以找到不希望在启动时启动的服务。我最喜欢禁用的是蓝牙,因为我在服务器或个人电脑上不使用它,但许多 Linux 发行版默认启用它。

参见

  • man 1 systemd-analyze

第五章:管理用户和组

Linux 有两种类型的用户:人类用户和系统用户。每个用户都有唯一的标识(UID),至少一个组标识(GID)。所有用户都有一个主组,并可能是多个组的成员。

每个人类用户拥有一个用于其个人文件的家目录。用户的家目录位于/home中,并以所有者的名字命名,比如我们的示例用户 Duchess 拥有/home/duchess。用户可能属于多个组,额外的组成员称为附加组。组中的用户拥有该组的所有权限。(要了解权限的所有内容,请参阅第六章。)权限控制对文件和命令的访问是系统安全的基础。

系统用户代表系统服务和进程。系统用户需要用户账户来控制其权限,并且不具有/home目录中的登录或目录。

人类用户分为两类:root用户,或超级用户,拥有无限权力,可以在系统上执行任何操作。所有其他用户被称为普通用户或非特权用户。普通用户只被赋予足够的权限来管理自己的文件,并运行允许普通用户使用的命令。普通用户可以被赋予有限或完全的 root 权限,关于susudo的相关内容将在后续章节中详细介绍。

您可以在/etc/passwd中查看系统中的所有用户,以及在/etc/group中查看所有的组。

集中式用户管理

/etc/passwd/etc/group源自 Unix,并自 1992 年移植到 Linux 以来基本未变化。此后,出现了新的工具用于管理用户和组,例如为整个组织提供服务的集中式数据库。本章不涵盖集中式用户管理工具。

Linux 附带了一些用于管理用户和组的命令:

  • useradd 用于创建新用户。

  • groupadd 用于创建新组。

  • userdel 用于删除用户。

  • groupdel 用于删除组。

  • usermod 用于对现有用户进行更改。

  • passwd 用于创建和更改密码。

这些属于Shadow Password Suite/etc/login.defs是其主要配置文件。

useradd 在不同系统上的行为不同,根据其配置方式而定。传统上,它将所有新用户归并到同一个主组users(100)中。这意味着用户必须小心文件的权限,以避免将其暴露给其他组的用户。Red Hat 通过其User Private Group方案改变了这一点,为每个新用户创建了一个个人私有组。大多数 Linux 发行版将其设为默认值,但也有例外,比如 openSUSE。

Shadow Password Suite是由 Julianne Frances Haugh 在上世纪 80 年代创建的,早在 Linux 诞生之前,旨在提高 Unix 密码安全性并简化用户账户管理。1992 年,随着 Linux 刚刚一岁,它被移植到 Linux 上。

在影子密码套件出现之前,所有相关文件都必须单独编辑,存在多个密码管理命令,并且哈希密码存储在/etc/passwd/etc/group中。这两个文件必须对所有人可读,因此即使密码被哈希,也会引发问题。任何人都可以复制一个全局可读文件,然后随意破解密码。将哈希密码重新定位到只有 root 用户才能访问的影子文件/etc/shadow/etc/gshadow中,增加了强大的保护层。影子密码套件的长期存在证明了其设计和编码的优秀。

对于 Debian 来说,新的到来者是adduseraddgroup。它们是useraddgroupadd的 Perl 脚本包装器。这些脚本将引导您完成完整的新用户和新组配置。

在本章中,您将学习如何创建和删除人类和系统用户,管理密码,查找 UID 和 GID,设置创建新用户的所需默认值,更改组成员身份,定制新用户需要的公共文件,清理已删除用户的内容,成为 root 用户,并向普通用户授予有限的 root 权限。

5.1 查找用户的 UID 和 GID

问题

您想要列出用户的 UID 和 GID。

解决方案

使用id命令而无需选项即可查看自己的 UID 和 GIDs。在以下示例中,用户是 Duchess:

duchess@pc:~$ id
uid=1000(duchess) gid=1000(duchess)
groups=1000(duchess),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),118(lpadmin),
126(sambashare),131(libvirt)

通过将其用户名作为参数提供来显示另一个用户的 UID 和 GIDs:

duchess@pc:~$ id madmax
uid=1001(madmax) gid=1001(madmax) groups=1001(madmax),1010(composers)

显示您的有效 ID。这是您作为另一个用户运行命令时的 ID。您可以使用sudo查看这一点:

duchess@client4:~$ sudo id -un
root

duchess@client4:~$ sudo -u madmax id -gn
madmax

讨论

Linux 中有三种类型的用户 ID:

  • 真实的 UID/GID

  • 有效的 UID/GID

  • 保存的 UID/GID

真实 ID是在用户创建时分配给用户的 UID 和主要 GID。这些是您运行id命令(作为您自己)时看到的内容,无需选项。

有效 ID是用于运行需要与启动进程的用户不同权限的进程的 UID,例如passwd命令。passwd需要 root 权限,但使用特殊权限模式允许用户更改自己的密码。

您可以自己查看这一点。首先,看看passwd命令的权限:

$ ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 68208 May 27  2020 /usr/bin/passwd

这表明passwd的所有者是 root,无论是 UID 还是 GID。现在键入passwd命令并按 Enter 键。

打开第二个终端以查找passwd进程,然后打印其进程 ID、有效 ID 和真实 ID:

$ ps -a|grep passwd
12916 pts/1    00:00:00 passwd

$ ps -eo pid,euser,ruser,rgroup | grep 12916
  12916 root     root     root

即使一个非特权用户在运行passwd,它也会以 root 权限运行。(有关特殊权限模式的信息,请参见 Recipe 6.11。)

saved ID 被需要提升权限的进程使用,通常是 root 权限。当进程需要执行需要较少权限的工作时,它可以临时切换到非特权用户 ID。有效的 UID 被更改为较低的特权值,并且原始的有效 UID 被保存到 SUID,即 saved user ID。当进程再次需要提升权限时,它切换到 SUID。

id 命令有几个选项:

  • -u 显示有效的 UID 号码。

  • -g 显示有效的 GID 号码。

  • -G 显示所有组 ID。

  • -n 打印名称而不是数字。您可以与 -u-g-G 一起使用。

  • -un 显示有效的 UID 用户名。

  • -gn 显示有效的组名。

  • -Gn 显示所有有效 GID 名称。

  • -r 显示真实的 ID 而不是有效的 ID。您可以与 -u-g-G 一起使用。

参见

  • Recipe 6.11

  • man 1 id

  • man 1 ps

5.2 使用 useradd 创建一个普通用户

问题

您想要创建一个新用户,并且希望用户私有组的主目录中包含一组默认文件,例如 .bashrc.profile.bash_history,以及您希望他们拥有的其他文件。

解决方案

大多数 Linux 发行版都包含 useradd 命令,并且可根据您的需求进行配置。不同 Linux 发行版的默认配置不同,因此了解您的系统设置的最快方法是创建一个新的测试用户:

$ sudo useradd test1

现在运行 id 命令,然后查看 useradd 是否创建了主目录。以下示例来自 Fedora 34:

$ id test1
uid=1011(test1) gid=1011(test1) groups=1011(test1)

$ sudo ls -a /home/test1/
.  ..  .bash_logout  .bash_profile  .bashrc

在这个例子中,默认配置满足了问题中列出的所有要求。现在您只需要设置一个密码:

$ sudo passwd test1
Changing password for user test1.
New password: *password*
Retype new password: *password*
passwd: all authentication tokens updated successfully.

您可以选择在第一次登录后强制用户重置他们的密码,创建用户密码之后:

$ sudo passwd -e test1
Expiring password for user test1.
passwd: Success

将登录信息提供给您的用户,他们可以开始使用他们的新账户。新用户账户在 /etc/passwd 中的表示如下:

test1:x:1011:1011::/home/test1:/bin/bash

例如 openSUSE 等一些 Linux 系统,默认配置 useradd 不会创建用户的主目录,并将所有用户放入 users (100) 组。如果文件的组权限允许,这可能会暴露文件给其他用户。下面的示例创建了一个用户私有组:

$ sudo useradd -mU test2

-m 创建用户的主目录,-U 创建与用户名相同的用户私有组。

讨论

所有新用户账户在您设置密码之前都是不活跃的。

对于用户创建的第一个组,无论是用户私有组还是所有用户的通用组,都是他们的 primary 组。用户分配的所有其他组都是 supplementary 组。

还有一些其他有用的选项:

  • -G--groups 用于将用户添加到以逗号分隔的多个补充组中。这些组必须已经存在:
$ sudo useradd -G group1,group2,group3 test1
  • -c--comment 接受任何文本字符串。用于用户的全名,或者任何注释或描述:
$ useradd -G group1,group2,group3 -c 'Test 1,,,,' test1

四个逗号定义了五个字段:全名、房间号、工作电话、家庭电话和其他信息。很久以前,这被称为 GECOS 数据。GECOS 是 General Electric Comprehensive Operating Supervisor 的缩写,是一个大型机操作系统。您可以在这些字段中输入任何文本字符串,或者什么都不输入,尽管包括用户的全名很有用。查看您的/etc/passwd文件,了解其他条目如何使用 GECOS 字段。

useradd的默认设置分散在多个配置文件中;查看 Recipe 5.4 以了解如何更改这些默认设置。

另请参见

  • man 8 useradd

  • man 5 login.defs

  • /etc/default/useradd

  • /etc/skel

  • /etc/login/defs

5.3 使用 useradd 创建系统用户

问题

您想使用useradd命令创建系统用户。

解决方案

下面的示例创建一个没有主目录、没有登录 shell,并使用正确的系统用户 UID 编号范围的新系统用户:

$ sudo useradd -rs /bin/false service1

-r意味着创建一个具有正确数值范围内真实 ID 的系统用户,-s指定登录 shell。/bin/false是一个什么都不做的命令,防止用户登录系统。

有关 UID 和 GID 编号的信息,请参见 Recipe 5.6 中的讨论。

讨论

在过去,大多数服务都以nobody用户身份运行。现在,服务通常会使用自己的唯一用户,这比nobody用户拥有多个服务提供了更强的安全性。您很少需要创建系统用户,因为安装服务时应该由服务自行创建其唯一用户。

nobody用户始终分配 UID 65534 和 GID 65534。

另请参见

  • man 8 useradd

  • man 1 false

  • Recipe 5.6 中的讨论

5.4 修改useradd的默认设置

问题

默认的useradd设置对您不适用,您希望进行更改。

解决方案

useradd的配置分布在多个配置文件中:/etc/default/useradd/etc/login.defs/etc/skel目录中的文件。

下列值出现在/etc/default/useradd中。以下示例展示了 openSUSE 的默认设置:

$ useradd -D
GROUP=100
HOME=/home
INACTIVE=-1
EXPIRE=
SHELL=/bin/bash
SKEL=/etc/skel
CREATE_MAIL_SPOOL=yes

GROUP=100将一个单一的共享组设置为所有新用户的默认组,传统上为100。该组必须首先存在,并且在/etc/login.defs中必须设置USERGROUPS_ENAB no。然后在/etc/default/useradd中将GROUP=设置为用户组的 GID。如果我们的 Duchess 用户在一个共享组中,她的id输出将显示uid=1000(duchess) gid=100(users)

通过在/etc/login.defs中设置USERGROUPS_ENAB yes并注释掉/etc/default/useradd中的GROUP=,启用私有用户组。这样每个用户都会创建一个非共享的私有组。如果我们的 Duchess 用户拥有自己的私有组,她的id输出将显示uid=1000(duchess) gid=1000(duchess)

HOME=

设置所有用户主目录的默认目录。默认为/home

INACTIVE=-1

设置密码过期后多少天锁定帐户。值为 0 表示密码过期后立即禁用帐户,值为 -1 表示不锁定帐户。

EXPIRE=

在 YYYY-MM-DD 格式中设置帐户过期日期。例如,如果设置为 2021-12-31,则帐户将在该日期禁用。将 EXPIRE= 留空表示帐户永不过期。

SHELL=/bin/bash

设置默认命令 shell。/bin/bash 是最常用的 Linux shell。其他值是用户系统中安装的任何 shell,如 /bin/zsh/usr/bin/tcshcat /etc/shells 列出所有安装的 shell。

SKEL=/etc/skel

设置要自动分发给新用户的文件的位置。大多数 Linux 系统将它们放在 /etc/skel 中。这些文件如 .bash_logout.bash_profile.profile.bashrc,以及任何其他您希望新用户拥有的文件。您可以编辑这些文件以满足自己的需求。SKEL 是 skeleton 的缩写。

CREATE_MAIL_SPOOL=yes

是旧时代的遗留物,应设置为 yes,因为仍可能存在需要它的某些旧进程。

/etc/login.defs 中以下值与用户创建默认值相关:

  • USERGROUPS_ENAB yes 启用私人用户组。

  • CREATE_HOME yes 配置 useradd 自动创建私人用户主目录。这不适用于系统用户(参见 5.3 节)。

讨论

UID 编号范围在 /etc/login.defs 中定义。每个 UID 必须是唯一的,因此用户帐户创建命令从此文件中定义的范围分配 UID。通常,人类 UID 从 1000 开始,并由 useradd 自动分配。您可以使用 -u 选项覆盖此设置,但必须选择未使用的数字,遵循配置的编号方案(参见 5.6 节 中的讨论)。

在第一次登录时强制要求密码更改是防止原始密码可能落入错误手中的简单预防措施,因为它从管理员传递到用户。

参见

  • man 8 useradd

  • man 5 login.defs

  • /etc/default/useradd

  • /etc/skel

  • /etc/login/defs

5.5 自定义文档、音乐、视频、图片和下载目录

问题

您已按照 5.2 节 的方法创建了新用户,现在您希望为新用户定制文档、音乐、视频、图片和下载目录。

解决方案

创建这些目录不是 useradd 的功能,而是 X 桌面组(XDG)用户目录工具的功能。文档、音乐、视频等目录称为 well-known user directories。这些目录是从 /etc/xdg/user-dirs.defaults 配置文件设置的,该文件为所有用户建立了默认配置:

$ less /etc/xdg/user-dirs.defaults
# Default settings for user directories
#
# The values are relative pathnames from the home directory and
# will be translated on a per-path-element basis into the users locale
DESKTOP=Desktop
DOWNLOAD=Downloads
TEMPLATES=Templates
PUBLICSHARE=Public
DOCUMENTS=Documents
MUSIC=Music
PICTURES=Pictures
VIDEOS=Videos
# Another alternative is:
#MUSIC=Documents/Music
#PICTURES=Documents/Pictures
#VIDEOS=Documents/Videos

这些是名称-值对。 名称不能更改。 值是名称映射到的目录,相对于用户的主目录。 例如,DOCUMENTS 映射到/home/username/Documents。 当用户第一次启动他们的图形桌面环境时,这些目录会自动为每个新用户创建。 您可以注释掉任何要排除的目录,或更改名称映射到的目录。

用户可以在~/.config/user-dirs.dirs中创建自己的个人配置。 在应用更改之前,这些目录必须存在。 以下示例是我们的示例用户公爵夫人创建的,她不喜欢无聊的默认值。 请注意,在~/.config/user-dirs.dirs中,名称-值对语法不同:

XDG_DESKTOP_DIR="$HOME/table"
XDG_DOWNLOAD_DIR="$HOME/landing-zone"
XDG_DOCUMENTS_DIR="$HOME/omg-paperwork"
XDG_MUSIC_DIR="$HOME/singendance"
XDG_PICTURES_DIR="$HOME/piccies"

当您的更改完成并创建了新目录后,请使用xdg-user-dirs-update命令应用您的更改:

duchess@pc:~$ xdg-user-dirs-update --set DOWNLOAD $HOME/landing-zone
duchess@pc:~$ xdg-user-dirs-update --set DESKTOP  $HOME/table
duchess@pc:~$ xdg-user-dirs-update --set DOCUMENTS  $HOME/omg-paperwork
duchess@pc:~$ xdg-user-dirs-update --set MUSIC  $HOME/singendance
duchess@pc:~$ xdg-user-dirs-update --set PICTURES  $HOME/piccies

注销,然后重新登录,您将看到类似于图 5-1 的东西。 XDG 为著名目录应用特殊图标。

lcb2 0501

图 5-1. 自定义著名目录

侧栏中的快捷方式不会更改,旧目录也不会更改,除了它们没有特殊图标。 您将需要更改快捷方式并手动迁移旧目录内容。

恢复到/etc/xdg/user-dirs.defaults中的默认值,使用以下命令:

$ xdg-user-dirs-update --force

退出并重新登录以查看更改。 除了标记著名用户目录的特殊图标外,您的任何目录都不会被移除或以任何方式更改。

讨论

运行xdg-user-dirs-update --set命令时,必须仅使用man 5 user-dirs.default中列出的名称:

DESKTOP
DOWNLOAD
TEMPLATES
PUBLICSHARE
DOCUMENTS
MUSIC
PICTURES
VIDEOS

只有目标目录即可配置的值。 目标目录必须相对于用户的主目录。 如果要使用主目录之外的目录,请创建符号链接。 例如,公爵夫人拥有/users/stuff/duchess并在其中存储音乐文件。 以下示例将此目录链接到/home/duchess/singendance

duchess@pc:~$ ln -s /users/stuff/duchess /home/duchess/singendance

参见

5.6 使用 groupadd 创建用户和系统组

问题

您想使用groupadd创建组。

解决方案

以下示例创建了一个名为musicians的新用户组:

$ sudo groupadd musicians

使用groupadd和* -r*选项创建系统组:

$ sudo groupadd -r service1

讨论

系统组与人类用户组在分配给它们的 UID 和 GID 编号范围上有所不同。 这在 Fedora 34 中的/etc/login.defs配置为groupadduseradd,如下所示:

# Min/max values for automatic uid selection in useradd(8)
#
UID_MIN                  1000
UID_MAX                 60000
# System accounts
SYS_UID_MIN               201
SYS_UID_MAX               999
# Extra per user uids
SUB_UID_MIN                100000
SUB_UID_MAX             600100000
SUB_UID_COUNT               65536

#
# Min/max values for automatic gid selection in groupadd(8)
#
GID_MIN                  1000
GID_MAX                 60000
# System accounts
SYS_GID_MIN               201
SYS_GID_MAX               999
# Extra per user group ids
SUB_GID_MIN                100000
SUB_GID_MAX             600100000
SUB_GID_COUNT               65536

这些定义了系统管理员可用的数字范围。 所有其他范围均为系统保留和管理。

GID 编号由groupadd根据/etc/login.defs中定义的数字范围自动管理。您可以使用-g选项覆盖此设置,但所选的 GID 必须落在定义的范围内,并且不能已经被使用。

参见

  • man 8 groupadd

  • /etc/login.defs

5.7 使用 usermod 将用户添加到组中

问题

您希望将用户分配到组。

解决方案

使用usermod命令。以下示例将 Duchess 添加到musicians组中:

$ sudo usermod -aG musicians duchess

此示例将 Duchess 添加到多个组:

$ sudo usermod -aG musicians,composers,stagehands duchess

或者,您可以编辑/etc/group,并在适当的组或组后键入 Duchess 的名称。当列出多个组成员时,列表必须以逗号分隔,名称之间不能有空格。

musicians:x:900:stash,madmax,duchess

小心追加而不是替换

如果忘记了-a选项,仅使用-G,所有用户现有的组将被移除并替换为新组。如果这将用户从其sudo组中移除,尤其具有破坏性。

当您更改登录用户的组成员资格时,用户必须注销然后重新登录以激活更改。有各种解决方法可以在不注销的情况下激活新的组分配,但它们都有限制,比如仅限于当前 shell。组在登录时枚举,因此最可靠的解决方案是注销并重新登录。

讨论

-a选项表示追加,-G是组或组。

参见

  • man 8 usermod

5.8 在 Ubuntu 上使用 adduser 创建用户

问题

您正在运行 Debian 或基于 Debian 的 Linux,并且需要知道如何使用adduser创建新用户。

解决方案

adduser会为您完成完整的新用户设置,就像这个 Stash Cat 的示例:

$ sudo adduser stash
Adding user 'stash' ...
Adding new group 'stash' (1009) ...
Adding new user 'stash' (1009) with group 'stash' ...
Creating home directory '/home/stash' ...
Copying files from '/etc/skel' ...
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
Changing the user information for stash
Enter the new value, or press ENTER for the default
        Full Name []: Stash Cat
        Room Number []:
        Work Phone []:
        Home Phone []:
        Other []:
Is the information correct? [Y/n]

Stash 在/etc/passwd中看起来像这样:

stash:x:1009:1009:Stash Cat,,,:/home/stash:/bin/bash

讨论

adduser的默认设置在/etc/adduser.conf中管理。这提供了许多有用的默认设置,如:

DSHELL=

设置默认登录 shell。/bin/bash是最常用的 Linux shell。其他值是用户系统上安装的任何 shell,例如/bin/zsh/usr/bin/tcshcat /etc/shells列出了所有安装的 shell。

USERGROUPS=yes

创建用户私有组,no将所有用户放入同一组中。

USERS_GID=100

当设置USERGROUPS=no时需要。

EXTRA_GROUPS=

这是您新用户的补充组列表,例如EXTRA_GROUPS="audio video plugdev libvirt"

ADD_EXTRA_GROUPS=1

EXTRA_GROUPS=中列出的组设置为新用户的默认组。

/etc/adduser.conf包含以下用户和组编号方案:

FIRST_SYSTEM_UID=100
LAST_SYSTEM_UID=999

FIRST_SYSTEM_GID=100
LAST_SYSTEM_GID=999

FIRST_UID=1000
LAST_UID=59999

FIRST_GID=1000
LAST_GID=59999--

Fedora Linux 包含adduser,但实际上不是adduser,只是一个到useradd的符号链接:

$ stat /usr/sbin/adduser
  File: /usr/sbin/adduser -> useradd
  Size: 7    Blocks: 0    IO Block: 4096   symbolic link
[...]

参见

  • man 5 adduser.conf

5.9 在 Ubuntu 上使用 adduser 创建系统用户

问题

您希望在 Ubuntu(或 Debian、Mint 或其他 Debian 衍生版)系统上使用adduser创建系统用户。

解决方案

以下示例使用adduser创建了一个名为service1的新系统用户,没有家目录,并拥有独立的主要组:

$ sudo adduser --system  --no-create-home --group service
Adding system user 'service1' (UID 124) ...
Adding new group 'service1' (GID 135) ...
Adding new user 'service1' (UID 124) with group 'service1' ...
Not creating home directory '/home/service1'.

/etc/passwd中的显示如下:

service1:x:124:135::/home/service1:/usr/sbin/nologin

讨论

系统用户没有家目录。

在古老的时代,服务通常作为nobody用户和组运行,除了 Debian 使用nobodynogroup。将同一用户用于多个服务是一种安全弱点。您不太可能需要创建系统用户,因为现在的常见做法是在安装新服务时由软件包安装程序创建唯一的用户和组。但是现在您知道了,以防万一您需要。

nobodynogroup的真实 ID 始终为 65534。

参见

  • man 8 adduser

5.10 使用 addgroup 创建用户和系统组

问题

您想知道如何使用 Debian 的addgroup命令创建用户和系统组。

解决方案

以下示例创建一个人类用户组:

$ sudo addgroup composers
Adding group 'composers' (GID 1010) ...
Done.

/etc/group中看起来是这样的:

composers:x:1010:

此示例创建一个新的系统组:

$ sudo addgroup --system service1
Adding group 'service1' (GID 136) ...
Done.

讨论

用户组和系统组之间的区别在于它们各自具有不同的 UID 和 GID 编号范围,这些范围在/etc/adduser.conf中配置。

参见

  • man 8 addgroup

5.11 检查密码文件的完整性

问题

所有这些用户文件和组文件中都有很多内容,您想知道是否有某种检查程序来验证这些文件是否被正确写入。

解决方案

pwck命令检查/etc/passwd/etc/shadow的完整性,grpck检查/etc/group/etc/gshadow。它们查找正确的格式、有效的数据、有效的名称和有效的 GID(请参阅 man 手册以获取完整的列表)。当您不带任何选项运行它们时,它们会报告警告和错误:

$ sudo pwck
user 'news': directory '/var/spool/news' does not exist
user 'uucp': directory '/var/spool/uucp' does not exist
user 'www-data': directory '/var/www' does not exist
user 'list': directory '/var/list' does not exist

$ sudo grpck
group mail has an entry in /etc/gshadow, but its password field in /etc/group is
not set to 'x'
grpck: no changes

添加-q选项以仅报告错误:

$ sudo pwck -q

$ sudo grpck -q
group mail has an entry in /etc/gshadow, but its password field in /etc/group
is not set to 'x'

这显示了/etc/gshadow中的错误。这不是一个非常有用的消息,因为它实际上并不是一个错误。将密码放在用户组上不是一个常见的做法,因此将其报告为错误只会令人困惑。其他检查非常有用,例如正确的字段数和唯一的有效组名。

您永远不会编辑/etc/shadow/etc/gshadow,而只会编辑/etc/passwd/etc/group

讨论

下面的示例显示了必须纠正的错误。当提示时,键入n以防止删除条目。第一个“删除行”示例来自/etc/passwd,第二个示例来自/etc/shadow

$ sudo pwck -q
invalid password file entry
delete line 'fakeservice:x:996:996::/home/fakeservice'? n
delete line 'fakeservice:!:18469::::::'? n
pwck: no changes

然后修正/etc/passwd中的行,这将修复两个错误消息。例如,fakeservice❌996:996::/home/fakeservice缺少最后一个字段,应为fakeservice❌996:996::/home/fakeservice:/bin/false

“目录不存在”警告通常指的是未使用的默认系统用户。例如:

user 'www-data': directory '/var/www' does not exist

当您未运行 HTTP 服务器时,www-data用户未使用,并且没有/var/www目录,直到安装 HTTP 服务器。

“无更改”消息意味着未对密码文件进行任何更改。

请参阅 man 手册以获取完整的检查列表。

参见

  • man 8 pwck

  • man 8 grpck

5.12 禁用用户帐户

问题

您希望禁用用户帐户而不是删除它。

解决方案

若要临时停用帐户,请使用 passwd 命令禁用用户的密码:

$ sudo passwd -l stash
passwd: password expiry information changed.

现在用户无法登录。下面的示例解锁用户的帐户:

$ sudo passwd -u stash
passwd: password expiry information changed.

这不会阻止用户通过其他认证方法(如 SSH 密钥)登录。要完全禁用用户帐户,请使用 usermod

$ sudo usermod --expiredate 1 stash

当用户尝试登录时,他们会看到“您的帐户已过期,请联系系统管理员”消息。恢复他们的帐户:

$ sudo usermod --expiredate -1 stash

讨论

禁用用户的另一种方法是在 /etc/passwd 的密码字段中用星号(*)替换 x:

stash:*:1009:1009:Stash Cat,,,:/home/stash:/bin/bash

通过将星号替换为 x 来重新启用 Stash。

参见

  • man 1 passwd

5.13 使用 userdel 删除用户

问题

您需要删除一个用户,可能还包括他们的主目录及其内容。

解决方案

下面的示例使用 userdel 命令从 /etc/passwd 删除用户 Stash,Stash 的主要组和所有组成员,以及影子文件:

$ sudo userdel stash

如果 Stash 属于共享的主用户组(见 Recipe 5.4 讨论),则该组不会被删除。

使用 -r 选项删除用户的主目录及其内容,以及其邮件邮筒:

$ sudo userdel -r stash

如果用户拥有其主目录之外的文件,则必须分别查找并处理它们(参见 Recipe 5.16)。

讨论

在删除用户之前和之后,请阅读您的 /etc/passwd/etc/group 文件,以查看用户的消失。

删除用户后进行清理是一个良好的做法。

参见

  • man userdel

5.14 在 Ubuntu 上使用 deluser 删除用户

问题

您正在运行 Ubuntu(或其他 Debian 派生版),并希望使用 deluser 删除用户。

解决方案

下面的示例从 /etc/passwd 删除用户 Stash,从 /etc/group 删除 Stash 的主要组,以及相应的影子文件:

$ sudo deluser stash
Removing user 'stash' ...
Warning: group 'stash' has no more members.
Done.

deluser 不会删除现有用户的主要组,因此如果 Stash 属于共享的主用户组,则不会被删除。

本示例删除了 Stash 的主目录并备份了所有已删除文件:

$ sudo deluser --remove-all-files --backup stash

讨论

--backup 在当前目录创建用户文件的压缩归档。使用 --backup-to 选项选择其他目录:

$ sudo deluser --remove-all-files --backup-to /user-backups stash

如果用户拥有其主目录之外的文件,则必须手动查找并处理它们(参见 Recipe 5.16)。

参见

  • man 8 deluser

5.15 在 Ubuntu 上使用 delgroup 删除组

问题

您有一个 Ubuntu 系统,并希望使用 delgroup 命令删除组。

解决方案

下面的示例移除了 musicians 组:

$ sudo delgroup musicians

delgroup 不会删除现有用户的主要组。即使它们有成员,它也会删除附加组。如果不想删除有成员的组,请使用 --only-if-empty 选项:

$ sudo delgroup --only-if-empty musicians

讨论

delgroup的默认行为已在/etc/deluser.conf/etc/adduser.conf中配置。

参见

  • man 8 delgroup

5.16 查找和管理用户的所有文件

问题

您想删除一个用户,但不希望留下一堆孤立的文件,并且需要找到它们的所有位置。

解决方案

find命令将根据 UID 或 GID 在本地系统上定位所有文件。以下示例在整个根目录中搜索用户 UID 所有者的所有文件:

$ sudo find / -uid 1007

如果要搜索大量文件,可能需要一些时间。如果确定不需要搜索整个文件系统,可以将搜索范围缩小到特定的子目录,如/etc/home/var

$ sudo find /etc -uid 1007
$ sudo find /home -uid 1007
$ sudo find /var -uid 1007

您还可以按 GID、用户名或组名搜索:

$ sudo find / -gid 1007
$ sudo find / -name duchess
$ sudo find / -group duchess

现在知道所有文件的位置,该怎么处理呢?一种选择是将它们的所有权更改为另一个用户,让新用户处理它们:

$ sudo find /backups -uid 1007 -exec chown -v 1010 {} \;
changed ownership of '/backups/duchess/' from 1007 to 1010
changed ownership of '/backups/duchess/bin' from 1007 to 1010
changed ownership of '/backups/duchess/logs' from 1007 to 1010

您可以结合findcp来查找并复制所有文件到不同的目录:

$ sudo find / -uid 1007 -exec cp -v {} /orphans \;

使用cp -v会打印进度消息,并仅复制文件而不复制它们的父目录。如果希望复制父目录,请使用-r选项:

$ sudo find / -uid 1007 -exec cp -rv {} /orphans \;

复制会保留原始文件的位置。在安全复制后,您可能希望删除原始文件。一种方法是再次运行find并使用rm删除原始文件:

$ sudo find / -uid 1007 -exec rm -v {} \;

这将删除文件但不会删除目录。如果确定这些目录中没有其他想要保留的文件,请使用-r选项删除目录:

$ sudo find / -uid 1007 -exec rm -rv {} \;

另一个选择是使用findmv将文件移动到其他位置:

$ sudo find / -uid 1007 -exec mv {} /orphans \;

如果看到“找不到文件或目录”消息,通常是因为文件或目录已移动,您可以通过查看它们被移动到的目录来进行验证。

查找由不存在的用户或组拥有的文件:

$ find / -nouser
$ find / -nogroup

讨论

要小心使用mvrm,因为它们没有撤销功能。如果出错,恢复的最佳希望是从备份中恢复。

清理离开的用户后可能会很麻烦,因为计算机使得创建尽可能多的文件变得太容易。如果发现find花费的时间太长,可以考虑让它在后台运行。

参见

  • man 1 find

  • man 1 mv

  • man 1 cp

  • man 1 rm

5.17 使用 su 切换到 root 用户

问题

你需要知道如何获取根权限以执行一些管理任务。

解决方案

当需要执行系统任务时,请使用su命令切换到 root 用户:

duchess@pc:~$ su -l
Password:
root@pc:~#

如果不知道 root 密码,或者没有 root 密码,请参见 Recipe 5.21 了解如何使用sudo设置 root 密码。

完成后,请退出 root 用户并返回到您自己的帐户:

root@pc:~# exit
logout
duchess@pc:~$

使用-l选项调用 root 用户的环境,切换到 root 的主目录并加载 root 的环境变量。省略-l以保留您自己的环境:

duchess@pc:~$ su
Password:
root@pc:/home/duchess~#

讨论

您可以切换到任何用户,只要您有他们的密码。

使用 su 切换到 root 给予您对系统的绝对控制,您运行的每个命令都是以 root 权限运行的。考虑使用 sudo(见 Recipe 5.18),它提供一些安全功能,如保护 root 的密码和留下审计日志。

另请参阅

  • man 1 su

5.18 使用 sudo 授予有限的 root 权限

问题

您想将一些系统管理任务委派给其他用户,并希望将他们的 root 权限限制在他们特定任务所需的范围内。

解决方案

使用 sudo 命令。sudosu 更安全,因为它为特定任务授予特定用户有限的 root 权限,记录活动并缓存用户的密码一段有限的时间,默认为 15 分钟。15 分钟后,用户必须再次向 sudo 提供密码。缓存持续时间可配置。sudo 保护 root 的密码,因为 sudo 用户使用自己的密码。

注意

一些 Linux 发行版(例如 openSUSE)默认要求 sudo 输入 root 用户的密码。参见 Recipe 5.22 了解如何更改此设置。

/etc/sudoers 是配置文件,您应该使用特殊命令 visudo 进行编辑。这将使用您的默认文本编辑器打开 /etc/sudoers,您可以查看和编辑默认配置。再一次,Duchess 为我们演示:

duchess@pc:~$ sudo visudo
[sudo] password for duchess:
[...]
##Allow root to run any commands
root    ALL=(ALL) ALL

# Allow members of group sudo to execute any command
%sudo   ALL=(ALL) ALL
[...]

%sudo ALL=(ALL) ALL 表示任何加入 sudo 组的用户都拥有与 root 相同的完全 sudo 权限。百分号表示 %sudo/etc/group 中的一个组,而不是 /etc/sudoers 中配置的组。

假设您有一位初级管理员 Stash,其工作是安装和删除软件并保持系统更新。您可以为 Stash 创建一个系统组。或者您可以配置 Stash 在 /etc/sudoers 中执行此任务。以下示例授予 Stash 运行列出命令的 sudo 权限。您需要用户名、本地机器的主机名以及允许的命令的逗号分隔列表:

stash server1 = /bin/rpm, /usr/bin/yum, /usr/bin/dnf

假设您想让 Stash 承担更多管理服务等的管理任务。允许的命令列表将变得很长,因此您可以创建一些命令别名。以下示例将软件管理命令别名为 SOFTWARE,服务管理命令别名为 SYSTEMD:

Cmnd_Alias SOFTWARE = /bin/rpm, /usr/bin/yum, /usr/bin/dnf
Cmnd_Alias SYSTEMD = /usr/bin/systemctl start, /usr/bin/systemctl stop,
/usr/bin/systemctl reload, /usr/bin/systemctl restart, /usr/bin/systemctl
status, /usr/bin/systemctl enable, /usr/bin/systemctl disable,
/usr/bin/systemctl mask, /usr/bin/systemctl unmask

现在 Stash 的配置看起来像这样:

stash server1 = SOFTWARE, SYSTEMD

您可以在 /etc/sudoers 中创建用户组(与 /etc/group 中的系统组无关),然后为它们分配一些命令别名:

User_Alias  JRADMIN = stash, madmax

JRADMIN server1 = SOFTWARE, SYSTEMD

您可以创建一个Host_Alias来给用户在多台机器上赋予sudo权限:

Host_Alias SERVERS = server1, server2, server3

然后引入 JRADMINs:

JRADMIN SERVERS = SOFTWARE, SYSTEMD

讨论

当您的有限 sudo 用户尝试运行不允许的命令时,他们会看到此消息:“对不起,用户 duchess 无法在 server2 上以 root 身份执行 */some/command*。”

不要对将用户限制在特定命令集合中抱有过多信心。许多日常应用程序通过 shell 脱逃提供特权升级的方法,您的用户可以获得完全的 root 权限。此示例展示了如何使用 awk 进行演示:

$ sudo awk 'BEGIN {system("/bin/bash")}'
root@client4:/home/duchess# 

就这样,公爵夫人就拥有了完整的 root 权限。谦卑的 less 命令还提供了一个 shell 转义。使用 less 读取足够大需要分页的文件:

$ sudo less /etc/systctl.conf
#
# /etc/sysctl.conf - Configuration file for setting system variables
# See /etc/sysctl.d/ for additional system variables.
# See sysctl.conf (5) for information.
/etc/sysctl.conf

输入 !*sh*,然后当提示符更改时,输入 whoami

duchess@client4:~$ sudo less /etc/systctl.conf
#
# /etc/sysctl.conf - Configuration file for setting system variables
# See /etc/sysctl.d/ for additional system variables.
# See sysctl.conf (5) for information.
!'sh'
duchess@client4:~$ sudo less /etc/sysctl.conf
# whoami
root

输入 exit 返回到您的正常 shell。

根据我的经验,难以跟踪到能够提供 shell 转义的许多应用程序。journalctl 记录所有内容,如果您希望监视您的 sudo 用户(参见 Recipe 20.1)。

在某些 Linux 发行版(如 Fedora)中,wheel 组是默认的 sudo 组。检查您的 /etc/sudoers 文件以了解您的发行版如何配置。您还可以创建自己的 sudo 组,并将其命名为任何您想要的名称。

/etc/sudoers 文件仅控制本地机器上的用户。包括其他机器,如 SERVERS 别名,允许您在多台机器上共享单个配置文件。sudo 会忽略任何在本地机器上不存在的项,比如主机或用户。

让我们解析 root ALL=(ALL) ALL,以了解所有这些 ALL 意味着什么。

root

在用户字段中,(ALL) 表示该用户或用户可以作为任何其他用户运行命令,或者您可以指定特定用户。

ALL=

是主机字段中的内容。ALL 表示任何主机的任何位置,或者您可以使用主机别名,或命名单个主机。

(ALL)

是可选用户字段中的内容。(ALL) 表示用户或用户可以作为任何其他用户运行命令,或者您可以指定某些用户。

ALL

在命令字段中。ALL 表示无限制,或者您可以指定允许的命令列表。

参见

  • man 8 sudo

  • man 5 sudoers

5.19 延长 sudo 密码超时时间

问题

在大多数 Linux 发行版上,sudo 缓存密码的默认间隔是 15 分钟。15 分钟后,您需要再次输入密码。在您有很多工作要做时,您厌倦了频繁输入密码,并希望增加缓存间隔。

解决方案

更改 /etc/sudoers 中的缓存间隔。使用 visudo 打开文件进行编辑:

$ sudo visudo

然后查找 Defaults 行并设置新的缓存间隔。以下示例将其设置为 60 分钟:

$ Defaults timestamp_timeout=60

如果将其设置为 0,sudo 每次使用时都会要求输入密码。

如果将 timestamp_timeout 设置为负数,如 -1,则您的密码永不过期。

讨论

sudo 密码缓存是一种有用的保护措施,可以防止意外事件,例如忘记以 root 身份运行或者离开时让其他人玩弄您的计算机。

参见

  • man 8 sudo

  • man 5 sudoers

5.20 创建个别 sudoers 配置

问题

您想为用户设置一些不同的 sudo 配置;例如,您希望您的初级管理员有一个不同的密码超时设置。您的设置很长,而您希望他们的设置很短。

解决方案

您可以在 /etc/sudoers.d 中创建个别配置。以下示例为 Stash 创建了一个 30 分钟的密码超时:

$ cd /etc/sudoers.d/
$ sudo visudo -f stash

输入Defaults timestamp_timeout=30,保存文件,完成。您可以查看新文件:

$ sudo ls /etc/sudoers.d/
README stash

您只需要输入与/etc/sudoers中条目不同的配置项,而不是复制整个文件。

讨论

这是一个管理多个用户的好功能。与其管理一个大的配置文件,不如将其分解为更小的每个用户文件。

另请参阅

  • man 8 sudo

  • man 5 sudoers

5.21 管理根用户的密码

问题

在安装过程中,您的 Linux 发行版将您设置为系统管理员,具有无限制的sudo特权,并且未创建根密码。或者,您的根用户有密码但您忘记了。您需要知道如何为根用户设置新密码。

解决方案

当您想要作为“真正的”根用户运行时,请使用sudosu到根:

duchess@pc:~$ sudo su -l
[sudo] password for duchess:
root@pc:~#

在这一点上,您可以使用passwd命令为根用户设置密码,以便直接以根用户身份登录,或者重置丢失的根密码。

讨论

有时您需要根密码而不是sudo;例如,当您引导到紧急运行级别时。

另请参阅

  • man 8 sudo

  • man 5 sudoers

  • man 1 passwd

5.22 将 sudo 设置为不要求根密码

问题

您希望您的sudo用户使用自己的密码进行身份验证,但您的 Linux 系统要求使用根用户的密码,如下例所示:

$ sudo visudo
[sudo] password for root:

解决方案

这是某些 Linux 发行版(如 openSUSE)上的默认行为。

当您安装 Ubuntu Linux 并在安装过程中将用户设置为管理员时,Ubuntu 会使用您自己的密码为您的用户适当配置完全的sudo权限,相当于根用户。而 openSUSE 则不会这样做,而是配置您的用户使用目标用户即根用户的密码。

要设置sudo用户始终要求其自己的密码,请编辑/etc/sudoers并注释掉以下两行:

duchess@pc:~$ sudo visudo

# Defaults targetpw
# ALL   ALL=(ALL) ALL 

在 openSUSE 和 Fedora 中,通过将用户添加到/etc/group中的wheel组来创建具有完整根权限的sudo用户。(对于有限用户,请参阅 Recipe 5.18。)

更改将在保存更改并关闭文件后立即生效。

讨论

保护根用户的密码是使用sudo而不是su的主要原因。

另请参阅

  • Recipe 5.18

第六章:管理文件和目录

Linux 提供了强大的基本控制来访问可配置权限的文件和目录。每个文件和目录都有三个所有权级别,包括用户、组和其他;以及多个访问级别,包括读取、写入和执行。您可以保护个人文件并控制谁可以访问它们,而根用户可以管理对命令、脚本、共享文件和系统文件的访问。

即使您正在使用更强的访问控制工具——如 SELinux 或 AppArmor,正确掌握基本原理仍然很重要。

在 Linux 系统上,人类用户和系统服务都有用户账户。一些系统服务需要用户账户来控制权限,就像人类用户一样。

每个文件都有三种类型的所有权:所有者、组和其他(有时其他表示为全球)。所有者是单个用户,组所有者是单个组,其他是所有能够访问文件的其他人。

每个文件有六种权限模式——读取、写入和可执行——以及三种特殊模式:粘性位设置用户 ID设置组 ID

文件权限控制哪些用户可以创建、读取、编辑或删除文件,以及哪些用户可以执行命令。特殊模式控制谁可以移动、删除或重命名文件,以及谁可以以提升的权限执行命令。

目录权限控制哪些用户可以编辑或进入目录,以及谁可以读取、编辑、添加或删除目录中的文件。

记住基本的 Linux 安全原则:使用最小必要的权限来完成工作。

特权的限制

任何能够读取文件的人都可以复制它。

您无法阻止根用户或具有足够权限的sudo用户访问您的文件。

权限和所有权是文件系统的功能,并可以通过从另一个 Linux 实例读取存储设备来绕过,例如通过从可移动介质引导 Live Linux 来访问主机系统,或者将硬盘移除并连接到不同的机器。您只需要在挂载存储设备的系统上拥有根权限,并不需要了解原始文件的所有者和权限。

在 Linux 系统中,根用户,也称为超级用户,拥有至高无上的权力。根用户几乎可以做任何事情,包括编辑和删除其他用户的文件,进入任何目录和运行任何命令。普通或非特权用户可以通过sudosu命令临时拥有根权限(见 Recipe 5.17 和 5.18)。

每个用户都有唯一的标识符(UID),并且至少属于一个组(见 Recipe 5.1)。组内的每个用户共享该组的权限。

要查看这一切是什么样子,请看/etc,其中包含系统配置文件:

 $ stat --format=%a:%A:%U:%G /etc
755:drwxr-xr-x:root:root

命令输出显示目录的模式,或者说权限集合,有两种表示方式,755:drwxr-xr-x755 是八进制表示法,drwxr-xr-x 是符号表示法。这两种方式表示相同的模式,在这个例子中,表示目录所有者有无限制权限,而组和其他用户只能进入该目录。文件模式在本章节中有详细讨论。

root:root 是所有者和组。文件和目录可以有不同的所有者和组;例如,/etc/cups 的所有者是root:lp

在本章中,你将学习特殊模式:粘滞位setuidsetgid。setuid 和 setgid 模式将用户和组权限提升到与文件所有者相同的级别。这些只在特殊情况下使用,并且非常谨慎,因为特权升级可能是潜在的安全风险。粘滞位防止除文件所有者或具有 root 特权外的任何人删除、重命名或移动目录中他们不拥有的文件,比如 /tmp

你将学习如何设置所有权和模式,创建和删除文件和目录,配置默认权限,将文件所有权转移到不同的用户或组,以及复制、移动和重命名文件和目录。

使用 sudo

本食谱中的大多数示例使用美元符号命令提示符$,表示非特权用户。根据你自己的文件权限,某些操作可能需要使用sudo

6.1 创建文件和目录

问题

你希望通过将文件放入目录中来组织你的文件。

解决方案

使用mkdir命令创建目录。以下示例在当前目录中创建一个新的子目录:

$ mkdir -v presentations
mkdir: created directory 'presentations'

在当前目录下创建一个距离两层的子目录及其父目录,使用-p(父级)选项:

$ mkdir -p presentations/2020/august
mkdir: created directory 'presentations/2020'
mkdir: created directory 'presentations/2020/august'

创建一个新的顶级目录,相对于根目录 /。你需要 root 权限才能执行此操作:

$ sudo mkdir -v /charts
mkdir: created directory '/charts'

在创建目录时,可以设置权限:

$ mkdir -m 0700 /home/duchess/dog-memes

文件由应用程序(如文字处理器和图像编辑器)和特殊命令(如touch)创建。touch命令创建一个新的空文件:

$ touch newfile.txt

参见食谱 6.2 学习如何使用touch快速创建批量文件进行测试。

讨论

如果你对文件树的可视化和所有目录如何相对于/而言感到困惑,请尝试tree命令。根目录 / 在顶部:

$ tree -L 1 /
/
├── backups
├── bin
├── boot
[...]

你可能已经注意到这个有些颠倒。在现实世界中,树是从根部分支出来的,但是tree命令显示的是目录树向下分支。这有其原因:我们从屏幕顶部向下阅读。

此示例仅列出根目录下的顶级目录。-L 2 显示第二级目录,-L 3 则显示到第三级,依此类推。

参见

  • 食谱 6.2

  • man 1 mkdir

  • man 1 touch

  • man 1 yes

  • man 1 tree

6.2 快速创建批量文件进行测试

问题

您想要批量创建文件以测试文件权限,以及任何需要快速大量文件的测试。

解决方案

使用touch命令。以下示例创建一个新的空文件:

$ touch newfile.txt

创建 100 个空文件:

$ touch file{00..99}

这将创建 100 个新文件,命名为file00file01file02等。您可以给它们添加文件扩展名,并随意命名它们:

$ touch test{00..99}.doc
$ ls
test00.doc
test01.doc
test02.doc
[...]

在文件名中首先放置数字以便于排序:

$ touch {00..99}test.doc
$ ls
00test.doc
01test.doc
02test.doc
[...]

yes命令快速填充文件内容。以下示例创建一个填充了重复行“This is a test file”的 500 MB 文件:

$ yes This is a test file | head -c 500 MB > testfile.txt

每个文件内容为 1 MB,批量创建 100 个文件:

$ for x in {01..100};
> do yes This is a test file | head -c 1MB > $x-testfile.txt;
> done 

新文件看起来像这样:

001-testfile.txt
002-testfile.txt
003-testfile.txt
[...]

讨论

您可以根据需要自定义此命令的多种方式:文件名、文件大小、编号以及yes的文本。

配方中的示例将文件名中的数字填充 0 以正确排序。大多数图形文件管理器正确处理带编号的文件名排序,但ls的默认排序是词典顺序。以下示例演示了一个 1 到 3 位数的数字范围:

$ touch {0..150}test.doc
$ ls -C1
0test.doc
100test.doc
101test.doc
102test.doc
103test.doc
104test.doc
105test.doc
106test.doc
107test.doc
108test.doc
109test.doc
10test.doc
110test.doc
111test.doc
112test.doc
113test.doc
114test.doc
115test.doc
116test.doc
117test.doc
118test.doc
119test.doc
11test.doc
120test.doc
121test.doc
[...]

词典排序将文件名视为文本字符串而不是整数和字符,并逐个比较每个数字和字母,从左到右。词典排序不知道 10 比 100 小,只知道 101 在 100 之后,102 在 101 之后,以及 10t 在 109 之后,因为字母跟在数字后面,所以t跟在9后面。

您可以使用前导零使所有数字具有相同的字符数,或者使用ls -v列出文件。这将把文件名中的数字视为整数而不是字符,因此它们将按正确的数字顺序列出。

参见

  • man 1 ls

  • man 1 touch

  • man 1 yes

6.3 使用相对路径和绝对路径

问题

您需要理解相对路径和绝对路径的区别,以及如何确定文件系统中的当前位置。

解决方案

绝对路径始终从根目录(//)开始,例如/boot/etc。相对路径相对于当前目录,没有前导斜杠。假设您在您的主目录中,并且它包含以下子目录:

madmax@client2:~$ ls --group-directories-first
 Audiobooks
 bin
 Desktop
 Documents
 Downloads
 games
 Music
 Pictures
 Public
 Templates
 Videos

在这个例子中,Audiobooks的绝对路径是/home/madmax/Audiobooks,相对路径是Audiobooks。可以使用cd命令以绝对路径或者相对路径进入这个目录:

$ cd /home/madmax/Audiobooks

或者相对路径:

$ cd Audiobooks

您所在的目录是当前工作目录(cwd)。使用pwd(打印工作目录)命令确认您的cwd

$ pwd
/home/madmax

讨论

绝对路径和相对路径常常让人困惑。请记住,当文件路径以斜杠(/)开头时,这是绝对路径。如果没有前导斜杠,则相对于当前工作目录。

某些应用程序和命令要求相对路径;例如,rsync includeexclude列表使用相对于正在复制的目录的文件路径。

参见

  • man 1 pwd

  • 第七章

6.4 删除文件和目录

问题

你玩得很开心创建了一堆文件和目录,现在想要摆脱它们。

解决方案

谨慎使用rm(删除)命令,因为rm会乐意删除你告诉它的所有内容,所以确保你正确地告诉它要删除的文件或目录。

删除单个文件,并显示详细输出:

$ rm -v aria.ogg
removed 'aria.ogg'

使用-i标志在删除前提示确认:

 $ rm -iv intermezzo.wav
rm: remove regular file 'intermezzo.wav'? y
removed 'intermezzo.wav' 

添加-r(递归)标志以删除目录及其所有文件和子目录。将-r-i结合使用将在每次删除之前提示确认:

$ rm -rvi rehearsals
rm: descend into directory 'rehearsals'? y
rm: remove regular file 'rehearsals/brass-section'? y
[...]

如果你确信不需要为每个删除操作提示确认,请省略-i选项。

此示例仅删除jan子目录:

$ rm -rv rehearsals/2020/jan

此示例删除rehearsals目录及其所有文件和子目录:

$ rm -rv rehearsals

使用通配符匹配要删除的文件名,例如按文件扩展名:

$ rm -v *.txt

或者通过同一文本字符串命名的文件:

$ rm -v aria*

如果rm拒绝删除文件或目录,并且你确定要删除它,请添加-f(强制)选项。

讨论

rm -rf / 将擦除整个根文件系统(如果你有根权限)。有些人认为告诉新手这样做很有趣,但实际上并不好笑。在测试机器或虚拟机上运行它,观察内存中的进程仍在运行,即使文件系统已从磁盘中删除。

另请参阅

  • man 1 rm

6.5 复制、移动和重命名文件和目录

问题

你有目录,也有文件。你想将文件移动到目录中,更改文件名并进行复制。

解决方案

使用cp命令进行复制,mv命令进行移动或重命名。

此示例将两个文件从当前工作目录复制到~/songs2目录:

$ cp -v aria.ogg solo.flac ~/songs2/
'aria.ogg' -> '/home/duchess/songs2/aria.ogg'
'solo.flac' -> '/home/duchess/songs2/solo.flac' 

波浪号代表你的主目录

波浪号简写为你的主目录,所以在示例中,~/songs2 等同于 /home/duchess/songs2/

使用-r(递归)选项复制目录及其所有内容:

$ cp -rv ~/music/songs2 /shared/archives

递归示例仅复制目录及其文件。使用--parents选项保留父目录。以下示例复制songs1及其内容,并保留文件路径duchess/music/songs2/

$ cp -rv --parents duchess/music/songs2/ shows/
duchess -> shows/duchess
duchess/music -> shows/duchess/music
'duchess/music/songs2' -> 'shows/duchess/music/songs2'
'duchess/music/songs2/intro.flac' -> 'shows/duchess/music/songs2/intro.flac'
'duchess/music/songs2/reprise.flac' -> 'shows/duchess/music/songs2/reprise.flac'
'duchess/music/songs2/solo.flac' -> 'shows/duchess/music/songs2/solo.flac'

duchessmusic的其他内容不会被复制,只有songs2及其内容。

使用mv命令移动和重命名文件。此示例将两个文件移动到另一个目录:

$ mv -v aria.ogg solo.flac ~/songs2/
renamed 'aria.ogg' -> '/home/duchess/songs2/aria.ogg'
renamed 'solo.flac' -> '/home/duchess/songs2/solo.flac' 

以下示例将一个目录移动到另一个目录:

$ mv -v ~/songs2/ ~/music/

讨论

一些有用的cp选项包括:

  • -a, --archive 保留所有文件属性,如模式、所有权和时间戳。

  • -i, --interactive 在覆盖目标文件之前提示。

  • -u, --update 只有当源文件更新时才覆盖现有的目标文件。这在重新复制一批文件时节省时间,而一些副本未更改。(rsync 更适合通过仅复制更改来进行有效文件传输,见第七章。)

mv 有一些有用的选项:

  • -i, --interactive 在覆盖目标文件之前提示。

  • -n, --no-clobber 防止覆盖目标文件。

  • -u, --update 只有当您的文件比目标文件更新或首次移动时,它才会移动。

参见

  • man 1 cp

  • man 1 mv

6.6 使用 chmod 的八进制表示设置文件权限

问题

你知道chmod(改变模式)命令支持八进制和符号表示法,你想使用八进制表示法来管理文件权限。

解决方案

下面的例子展示了如何使用八进制表示法在文件上设置不同的权限。第一个例子将对file.txt文件的所有者授予读写访问权限,并排除组和世界的所有访问权限:

$ chmod -v 0600 file.txt
mode of 'file.txt' changed from 0644 (rw-r--r--) to 0600
(rw-------)

文件所有者可以读取、编辑和删除文件,而其他用户无法对其进行任何操作,甚至无法读取它,尽管他们可以在文件管理器中看到它列出。

让一个文件对所有人都可读和可写,允许每个人都可以对其进行任意操作:

$ chmod 0666 file.txt

在下一个例子中,file.txt 被更改为对文件所有者可读写,对组和世界只读:

$ chmod -v 0644 file.txt
mode of 'file.txt' changed from 0666 (rw-rw-rw-) to 0644 (rw-r--r--)

常见的权限设置是给所有者和组相同的权限,比如读写,并排除其他人:

$ chmod 0660 file.txt

命令和脚本需要设置可执行位。这个例子使backup.sh脚本对所有者可执行和读写,对组可执行和可读,而对其他人不可访问:

$ chmod 0750 backup.sh

八进制表示法有四个字段,但你可能最常使用最后三个字段,很少使用第一个字段。第一个字段保留用于特殊模式(参见配方 6.8)。

讨论

八进制表示法使用整数 0-7。表 6-1 显示了所有者和权限之间的关系。

表 6-1. 八进制字段

模式 所有者 其他
读取 4 4 4
写入 2 2 2
执行 1 1 1
没有权限 0 0 0

一个文件或目录有一个用户所有者和一个组所有者。其他是所有其他人。一个无限制对所有人开放的目录或可执行文件是模式 0777,无限制的文件是模式 0666。

当你对 Linux 文件权限不熟悉时,可能帮助你以另一种视角查看它们,比如在表 6-2 中。

表 6-2. Linux 文件权限

权限 描述
7 读、写、执行。目录与文件不同,因为所有目录都需要设置可执行位。您可以为目录分配任何权限,就像为文件分配权限一样,但如果没有可执行位,没有人可以进入该目录(使用cd命令或文件管理器)。脚本和二进制命令必须设置可执行位,否则它们将被视为普通文件。
6 读和写。
5 读和执行。这是命令常见的权限。
4 阅读。
3 写入和执行。
2 写入。
1 执行。
0 无权限。

另请参阅

  • man 1 chmod

  • 示例 6.8

6.7 使用 chmod 的八进制表示法设置目录权限

问题

您知道目录上的权限管理有些不同,并希望使用 chmod 的八进制表示法来管理它们。

解决方案

目录必须设置可执行位。这听起来有些奇怪,但是对于使用cd命令或文件管理器进入目录是必要的。

以下示例创建了一个共享目录:

$ sudo mkdir /shared

该示例使/shared对所有者为读写,对其他所有人为只读:

$ chmod 0755 /shared

所有者对目录有无限制的特权。组和全局可以进入目录并读取文件,但不能编辑或添加文件。

该示例使用-R(递归)选项将相同的权限应用于目录中现有的内容:

$ chmod -R 0755 /shared

下一个示例将目录及其现有内容限制为目录所有者。目录内的文件和目录可能具有不同的所有者和权限,但仍然无法访问组和全局:

$ chmod 0700 /shared

一个常见的权限集是为所有者和组分配相同的权限,例如读-写-执行,并排除其他用户:

$ chmod 0770 /shared

讨论

您可以通过组和目录具有大量权限来控制文件访问。按功能设置组,例如各个团队可以各自拥有独占的共享目录。大多数情况下不需要超精细的控制,而是默认更多的共享。无论您的需求如何,旧的chmod命令仍然是控制文件权限的基本工具。

另请参阅

  • man 1 chmod

6.8 使用特殊模式处理特殊用例

问题

您想设置一些传统用户-组-其他权限集不支持的权限,例如允许非特权用户运行需要高级权限的命令,保护多用户共享目录中的文件,或者在目录中强制执行某些文件权限。

解决方案

特殊模式包括粘滞位setuidsetgid(见表 6-3)。粘滞位适用于包含多用户拥有文件的目录,以防止用户移动、重命名或删除他们不拥有的文件:

$ chmod -v 1770 /home/duchess/shared
mode of '/home/duchess/shared changed from 0770 (rwxrwx---) to 1770 (rwxrwx--T)

setuid 应用于可执行文件,以将运行该命令的任何用户提升到与所有者相同的权限:

$ chmod 4750 backup-script
mode of 'backup-script' changed from 0750 (rwxrw----) to 4770 (rwsrwx---)

setgid 应用于目录,以便在目录中创建的所有新文件都分配给与目录组所有者相同的组。这是在共享目录中强制正确所有权的一个好方法:

$ chmod 2770 /home/duchess/shared
mode of '/home/duchess/shared' changed from 0770 (rwxrwx---) to 2770 (rwxrws---)

setgid 也可以应用于文件,将用户的有效组更改为与文件所有者相同的组。

讨论

setgidsetuid 有可能为入侵者或不可信用户创建安全漏洞。最佳实践是只有在无法想到更安全的方法来完成所需操作时,才使用它们,比如使用组分配或 sudo

setuid 对可执行文件很有用。

setgid 对目录和文件都很有用。

粘性位仅适用于目录。表 6-3 显示了权限与所有者的关系。

表 6-3. 八进制字段

模式 特殊模式 所有者 世界
读取 4 4 4
写入 2 2 2
执行 1 1 1
设置 UID 4
setgid 2
粘性位 1
无权限 0 0 0 0

可以组合特殊模式值(参见 表 6-4)。

表 6-4. 粘性位/setgid/setuid 值

选项名称 八进制值
无选项设置 0
设置粘性位 1
setgid 2
粘性位和 setgid 3
设置 UID 4
粘性位和设置 UID 5
setgid 和 setuid 6
粘性位、setgid 和 setuid 7

粘性位的更具描述性的名称是 受限删除位。此位防止非特权用户在目录中删除或重命名文件,除非它们拥有该文件。您可以在 /tmp 目录上看到这一点,该目录对所有用户都可读和可写,并包含由多个用户拥有的文件。使用粘性位防止用户移动、重命名或删除他们不拥有的文件,即使他们对某些他们不拥有的文件有写权限:

 $ stat --format=%a:%A:%U:%G /tmp
1777:drwxrwxrwt:root:root

粘性位是 1777 中的 1。

setgid 意味着设置组用户标识,而 setuid 是设置用户标识。它们用于将非特权用户的权限提升到与用户或组所有者相同的级别。这就是非特权用户如何能够使用 passwd 命令更改自己的密码,即使只有 root 对 /etc/passwd 有写权限,而其他人只有读和执行权限:

 $ stat --format=%a:%A:%U:%G /usr/bin/passwd
4755:-rwsr-xr-x:root:root

/etc/passwd 中的 4755 中的 4 是 setuid,这意味着所有用户在运行命令时具有 root 权限,尽管它们的权限仅限于更改自己的密码。

另请参阅

  • man 1 chmod

6.9 使用八进制表示法删除特殊模式

问题

您想要从文件或目录中删除特殊模式。

解决方案

删除特殊模式与设置不同,因为您需要使用额外的前导零,如以下示例:

$ chmod -v 00770 backup.sh
mode of 'backup.sh' changed from 1770 (rwxrwx--T) to 0770 (rwxrwx---)

或者用等号替换前导零:

$ chmod -v =770 backup.sh
mode of 'backup.sh' changed from 1770 (rwxrwx--T) to 0770 (rwxrwx---)

另请参阅

  • man 1 chmod

6.10 使用 chmod 符号表示设置文件权限

问题

你知道 chmod(更改模式)命令支持八进制和符号表示法,而你希望使用符号表示法来管理文件权限。

解决方案

符号表示法比八进制表示法更复杂,并且根据使用的操作符行为不同。

有三个操作符:+、- 和 =。你可以使用 a 标志更改每个人的权限,或者使用 u 为文件所有者,g 为组,-o 为其他人(即所有其他人)逐个更改。

  • + 添加到现有权限。

  • - 从现有权限中减去。

  • = 添加新权限,并删除未列出的任何权限位。

假设 file.txt 是所有者读写,组读取,其他人读取,或者 -rw-r--r--

$ stat --format=%a:%A:%U:%G file.txt
664:-rw-r--r--:stash:stash

你想把它改成 -rw-rw-rw-。给组和其他人增加写权限:

$ chmod -v g+w,o+w file.txt
mode of 'file.txt' changed from 0644 (rw-r--r--) to 0666 (rw-rw-rw-)

你也可以使用 a=rw

在下一个例子中,file.txt 的所有者将其从全局可读可写更改为仅文件所有者可编辑,组和全局只能读取:

$ chmod -v g-w,o-w file.txt
mode of 'file.txt' changed from 0666 (rw-rw-rw-) to 0644 (rw-r--r--)

常见的权限设置是给所有者和组相同的权限,比如读写,并排除其他人:

$ chmod -v u=rw,g=rw,o-r file.txt
mode of 'file.txt' changed from 0644 (rw-r-r--) to 0660 (rw-rw----)

命令和脚本需要设置可执行位。此示例为文件所有者添加可执行位到现有权限:

$ chmod -v u+x file.txt
mode of 'file.sh' changed from 0660 (rw-rw----) to 0760 (rwxrw----)

= 操作符用于覆盖现有权限:

$ chmod -v u=rw,g=rw,o=r file.txt
mode of 'file.sh' changed from 0760 (rwxrw----) to 0664 (rw-rw-r--)

讨论

使用 chmod 符号表示法的关键是始终要明确,并且要注意现有权限。添加和减去现有权限(除了使用 = 操作符会覆盖之外),并指定 ugo-a

符号 表示法设计为助记,r 代表读取,w 代表写入,x 代表执行(参见 表 6-5)。

表 6-5. 符号表示权限

模式
r 读取
w 写入
x 执行

用户和组的表示法也是助记的(参见 表 6-6)。

表 6-6. 符号表示所有者

所有者 表示
用户 u
g
其他 o
所有 a

就像八进制表示法一样,符号表示法也支持特殊模式(参见 食谱 6.11)。

符号表示法中有 10 个值,未设置的值(表示没有权限)用破折号表示,例如杜切斯的主目录示例:

$ stat --format=%a:%A:%U:%G /home/duchess
755:drwxr-xr-x:duchess:duchess

drwxr-xr-x 中,d 表示这是一个目录。在八进制表示法中没有可比值。

剩下的九个值被分为三个三重组,每个三重组中的三个值代表读、写和执行。

参见

  • man 1 chmod

6.11 使用 chmod 符号表示法设置特殊模式

问题

你想要使用 chmod 的符号表示法设置特殊模式。

解决方案

特殊模式包括粘着位、setuidsetgid。这些都在可执行字段中设置。(如果您不确定可执行字段是什么,请参阅 Recipe 6.10 讨论的末尾。)

粘着位适用于包含由多个用户拥有的文件的目录,以防止非所有者移动、重命名或删除文件:

$ chmod o+t /shared/stickydir
mode of '/shared/stickydir' changed from 0775 (rwxrwxr-x) to 1775 (rwxrwxr-t)

setgid 应用于目录,以使目录中所有新创建的文件的组与目录相同。这是一个很好的技巧,可以强制在共享目录中确保正确的所有权:

$ chmod -v g+s /shared
mode of '/shared' changed from 0770 (rwxrwx---) to 2770 (rwxrws---)

setuid 应用于可执行文件,以允许非 root 用户运行该可执行文件:

$ chmod -v u+s backup-script
mode of 'backup-script' changed from 0755 (rwxr-xr-x) to 4755 (rwsr-xr-x)

setuidsetgid 有可能会存在安全漏洞;请参见讨论了解更多信息。

讨论

setuid 对可执行文件很有用。

setgid 对目录和文件都很有用。

粘着位仅适用于目录。

表 6-7 显示所有者和模式之间的关系。

表 6-7. 所有符号模式

模式 用户 其他
读取 r r r
写入 w w w
执行 x x x
setuid s
setgid s
粘着位 t

粘着位的一个更具描述性的名称是 restricted deletion bit。这可以防止用户在不拥有文件的情况下删除或重命名目录中的文件。您可以在您的 /tmp 目录中看到这一点,该目录是全局可读写的,并包含多个用户的文件。使用粘着位可以防止用户移动、重命名或删除他们不拥有的文件:

$ stat --format=%a:%A:%U:%G /tmp
1777:drwxrwxrwt/:root:root 

setgid 意味着设置组标识,setuid 意味着设置用户标识。这些用于将非特权用户的权限提升到与文件所有者相同的级别。这就是非特权用户如何能够使用passwd命令来更改自己的密码,尽管只有 root 用户对 /etc/passwd 具有写权限,而其他所有用户仅具有读和执行权限:

$ stat --format=%a:%A:%U:%G /usr/bin/passwd
4755:-rwsr-xr-x:root:root

用户字段中的 rws 表示对所有用户具有与文件所有者相同的读、写和执行权限。

setgidsetuid 有可能会造成安全漏洞。最好的做法是只有在无法想出更安全的方法来完成所需操作时才使用它们,例如使用组分配或 sudo

参见

  • man 1 chmod

6.12 使用 chmod 批量设置权限

问题

您想要一次设置多个文件的权限。

解决方案

chmod 支持对文件列表进行操作。您也可以使用 find 命令和 shell 通配符选择要更改的文件。

您可能需要 sudo

如果看到“权限被拒绝”消息,请使用 sudo

以下示例将以空格分隔的文件列表设置为所有用户均只读:

$ chmod -v 444 file1 file2 file3

设置目录及其内容(包括子目录)的权限,使用-R(递归)标志:

$ chmod -vR 755 /shared

您可以使用通配符选择文件;例如,使当前目录中的所有.txt文件对所有者可读写,并使组和其他人可读:

$ chmod -v 644 *.txt

使用通配符选择所有以相同字符串开头的文件名:

$ chmod -v 644 abcd*

此示例使当前目录中的所有文件对所有者和组可读写,而不更改目录权限:

$ find . -type f -exec chmod -v 660 {} \;

您可以更改属于特定用户的所有文件的模式。您可以使用用户的数字 ID 或用户名命名用户。此示例从文件系统的根目录开始:

$ sudo find / -user madmax -exec chmod -v 660 {} \;
$ sudo find / -user 1007 -exec chmod -v 660 {} \;

讨论

您需要具有根权限才能在所有目录中搜索文件。

点号(find .)告诉find从当前目录开始搜索。您可以从任何目录开始搜索。

-type 将结果限制为文件,而不是目录。

-user 查找由指定用户拥有的文件。

-exec chmod -v 660 {} ; 是一个神奇的小咒语,它接受find搜索的结果并在结果上运行chmod -v 660命令。您可以将其用于几乎任何您想要应用于find搜索结果的命令。

参见

  • man 1 chmod

  • man 1 find

6.13 使用 chown 设置文件和目录所有权

问题

您需要更改文件或目录的所有权。

解决方案

使用chown(更改所有者)命令更改文件所有权。基本命令语法为chown 用户:组 文件名。您可以仅更改所有者,chown 用户: 文件名,或仅更改组,chown :组 文件名

更改所有者需要根权限:

duchess@client1:~$ sudo chown -v madmax: song.wav
changed ownership of 'song.wav' from duchess:duchess to madmax:duchess

更改组所有者:

$ sudo chown -v :composers song.wav
changed ownership of 'song.wav' from madmax:duchess to :composers

更改用户和组所有者:

$ sudo chown stash:stash song.wav

讨论

您需要根权限才能更改您不拥有的文件,并将文件所有权转移给另一个用户。如果您属于原始组和新组,则可以在没有根权限的情况下更改组文件所有权。

当您仅更改所有者时冒号是可选的,而更改组时则是必需的。

参见

  • man 1 chown

6.14 使用 chown 批量更改所有者

问题

您希望更改目录及其内容的所有权,或仅更改目录内容,文件列表,或将文件所有权从一个用户更改为另一个用户。

解决方案

chown支持操作文件列表。您还可以使用find命令和 shell 通配符列出要更改的文件。

要使用chown同时更改多个文件的所有者,请使用空格分隔的文件列表:

$ sudo chown -v madmax:share file1 file2 file3

将当前目录中具有特定文件扩展名的文件更改为新组:

$ sudo chown -v :share *.txt

将一个目录中一个用户的所有文件转移到另一个用户,使用其数字 UID 或用户名:

$ chown -Rv --from duchess stash /shared/compositions

$ chown -Rv --from 1001 1005 /shared/compositions

使用-find_命令遍历整个文件系统,或任何目录及其子目录,将一个用户的所有文件转移到另一个用户:

$ sudo find / -user duchess -exec chown -v stash {} \;

$ sudo find / -user 1001 -exec chown -v 1005 {} \;

讨论

将所有用户文件的所有权转移给另一个用户,或转移到不同的组,对于清理不再在系统上有帐户的用户非常有用。

参见

  • man 1 chown

6.15 使用 umask 设置默认权限

问题

你想要理解为什么文件以一定的默认权限创建,以及如何自己配置这些默认设置。

解决方案

umask(用户文件创建模式掩码)控制这种行为。要查看你的 umask 是什么,请运行 umask 命令:

$ umask
0002

这是用符号表示法表示的样子:

$ umask -S
u=rwx,g=rwx,o=rx

这将将你的默认权限设置为目录 0775 和文件 0664,因为 umask “掩盖” 了硬编码的默认权限 0777 和 0666。或者你可以将其看作减法,0777 - 0002 = 0775。

要在当前会话期间临时更改你的 umask,请按以下方式设置:

$ umask 0022

在你的 ~/.bashrc 文件中插入一行 umask 0022 或你想要的任何值来永久设置 umask。

/etc/login.defs 中为所有用户设置默认的 umask:

UMASK 022

表 6-8 显示了一些常见的 umask 值。

讨论

umask 是 Bash shell 的内置命令,不是存储在 /bin/usr/bin 或任何其他 bin(二进制)目录中的可执行程序。

表 6-8 列出了一些常用的 umask 值。

表 6-8. 常见 umask 值

umask 目录 文件
0002 0775 0664
0022 0755 0644
0007 0770 0660
0077 0700 0600

参见

  • man 1 chmod

  • 参见 man 1 bash 的 Shell 内置命令部分,了解 umask 和其他 Bash 内置命令的更多信息。

6.16 创建文件和目录的快捷方式(软链接和硬链接)

问题

你想要创建文件的快捷方式或链接。

解决方案

Linux 中有两种链接类型:软链接和硬链接。软链接适用于文件和目录。硬链接仅适用于文件。

使用 ln(链接)命令创建软链接和硬链接。以下示例在 Mad Max 的主目录中创建一个指向外部目录 /files/userstuff 的软链接:

$ ln -s /files/userstuff stuff

/files/userstuff 是目标,而 stuff 是目标或软链接名称。你可以任意命名你的软链接,并且移动或删除它们而不影响它们的目标。当你打开一个软链接时,它的行为与打开目标相同。

硬链接是文件的副本。 ln 命令的默认设置是创建硬链接:

$ ln /files/config1.txt myconf.txt

讨论

软链接适用于文件和目录,而硬链接仅适用于文件。

软链接

软链接更常被称为 symlinks,是 symbolic links 的缩写。

符号链接指向文件和目录。当符号链接的目标被删除、重命名或移动时,符号链接就会断开。如果你用一个与已删除文件同名但内容不同的新文件替换它,符号链接就会恢复。

符号链接可以跨文件系统。你甚至可以创建指向永久不可用的文件或目录(如 USB 存储设备或网络文件共享)的符号链接。

当目标更改(重命名、移动或删除)时,符号链接不会更新。你需要创建一个新的符号链接并删除旧的符号链接。

您不需要管理符号链接的权限或所有权,因为只有目标的权限才重要。

符号链接看起来像这样:

$ stat stuff
  File: stuff -> /files/userstuff
  Size: 4               Blocks: 0          IO Block: 4096   symbolic link
Device: 804h/2052d      Inode: 877581      Links: 1
Access: (0777/lrwxrwxrwx)  Uid: ( 1000/ madmax) Gid: ( 1000/ madmax)

File: stuff → /files/userstuff 显示符号链接指向的目标。

第三行标识这是一个符号链接。

Access: lrwxrwxrwx 中的 l 标识这是一个符号链接。

文件列表中的符号链接如下所示:

$ ls -l
[...]
lrwxrwxrwx 1 madmax madmax  4 Apr 26 12:42 stuff -> /files/userstuff

硬链接

文件通过索引节点唯一标识,而硬链接指向的是索引节点,而不是文件名。ls 命令通过 -i 选项显示索引节点。在这个例子中,索引节点是 1353,三个硬链接的索引节点相同:

$ ls -li
1353 -rw-rw-r--   3 madmax madmax  11208 Apr 26 13:06  config.txt
1353 -rw-rw-r--   3 madmax madmax  11208 Apr 26 13:06  config2.txt
1353 -rw-rw-r--   3 madmax madmax  11208 Apr 26 13:06  config3.txt

因为所有三个索引节点指向同一数据块。

硬链接总是有效,因为它们直接指向索引节点。具有多个硬链接的文件可以被移动、重命名和编辑,所有硬链接因指向同一数据块而保持同步。

Linux 系统上的每个文件都以硬链接开始。当您创建一个硬链接时,实际上是为现有数据块创建一个新的文件名。

硬链接不能跨文件系统,而只存在于单个文件系统内。例如,如果您的 //home 在不同的分区上,您不能在 /home 中为 / 中的文件创建硬链接。

您可以为文件创建任意多的硬链接,它们指向的数据块的磁盘空间始终相同,不管有多少硬链接。

将硬链接与复制文件进行对比:每个副本都会使用更多磁盘空间,每个副本都是独立的,副本可以存放在任何位置。

直到所有硬链接都被删除,文件才算完全删除。您可以使用 ls 查看这一点。以下示例显示了我们的例子索引节点及其三个硬链接的另一视图:

$ stat config3.txt
  File: config3.txt
  Size: 11208           Blocks: 24         IO Block: 4096   regular file
Device: 804h/2052d      Inode: 1353        Links: 3

将文件、大小和符号链接与硬链接进行比较。硬链接是常规文件,注意 Links: 3。这表明有三个硬链接指向同一数据。当您删除具有多个硬链接的文件时,只有在删除所有硬链接之后,该文件才会被删除。使用 find 命令定位所有相关的硬链接:

$ find */etc* -xdev -samefile *config3.txt*
./config
./config2
./config3

在 Linux 中,符号链接被广泛使用,而硬链接则不那么常见。一些备份应用程序使用索引节点进行重复数据删除。在旧时代,当文件系统较小时,索引节点不足并不罕见。在这种情况下,硬链接更可取,因为每个符号链接都有自己的索引节点,而硬链接共享索引节点。

您可以使用 du 命令查看文件系统有多少个索引节点,以及使用了多少个:

$ df -i /dev/sda4
Filesystem        Inodes  IUsed     IFree IUse% Mounted on
/dev/sda4      384061120 389965 383671155    1% /home

由于使用率仅为 1%,我不会很快用完索引节点。

参见

  • man 1 ls

6.17 隐藏文件和目录

问题

您希望隐藏某些文件和目录,以便其他人看不见。

解决方案

要隐藏文件,以便其他人看不见,将它们放在只有您访问权限的存储设备上。

要在文件管理器中减少混乱,请使用 点文件 来忽略文件。您已经有这些文件。在图形文件管理器中查找类似“显示隐藏文件”的设置,或者对 ls 使用 -a 选项:

$ ls -a
.
..
Audiobooks
.bash_history
.bash_logout
.bashrc
bin
.bogofilter
.cache
Calibre-Library
cat-memes
.cddb
.cert

.作为任何文件的前缀,它就成为了隐藏文件,尽管它实际上并不隐藏,但在你想要查看它之前会被忽略。这主要用于用户的主目录,以减少显示配置文件所带来的混乱。这些都是你可以编辑、删除或者做任何想做的正常文件。

讨论

注意文件列表顶部的单点和双点。单点代表当前目录,双点代表父目录。试着用cd命令操作一下。第一个例子保持在当前目录,第二个例子切换到父目录:

stash@client4:~$ cd .
stash@client4:~$

stash@client4:~$ cd ..
stash@client4:/home$

运行cd而不带选项可以返回到你的主目录,或者运行cd -返回到你上次所在的目录。

参见

  • 查看man 1 bash中的 Shell 内建命令部分,了解更多关于cd和其他 Bash 内建命令的信息。

第七章:使用 rsync 和 cp 进行备份和恢复

您知道您需要对计算机文件进行良好的备份,并定期测试以查看是否可以还原文件。但是在 Linux 上如何实现这一点?不用担心,在 Linux 上备份和恢复非常容易理解,并且您的备份文件易于搜索和还原。

对于练习本章命令,拥有几个 USB 闪存驱动器和几个充满文件的目录是很有帮助的,这些文件如果出现问题也不会遗憾。

我们将使用rsynccp。这两者都是基本的 Linux 工具,您可以放心它们已得到良好维护并且随处可用。

cp是 GNU coreutils包中包含的复制命令,默认安装在几乎所有 Linux 发行版上。cp用于简单的复制。这可能是您维护常规备份所需的全部功能。

rsync是一款高效的文件传输程序,其主要目的是保持不同文件系统之间的同步。当您用它来进行备份时,它会将本地文件与备份设备保持同步。由于它仅传输文件中的更改,因此速度快且效率高。与许多备份软件不同的是,它甚至可以镜像删除操作。正是由于这些特点,rsync 成为更新和镜像用户主目录、网站、git 仓库以及其他大型复杂文件树的首选工具。

有两种方法可以通过网络使用 rsync:通过 SSH 进行身份验证的登录和传输,或者将其作为守护进程运行。使用 SSH 需要用户在每台需要 rsync 访问的机器上拥有登录账户。当 rsync 以守护进程模式运行时,您可以使用其内置的身份验证方法来控制访问,以便用户无需在 rsync 服务器上拥有登录账户。守护进程模式非常适合局域网备份服务器。在不受信任的网络上访问是不安全的,除非您使用 VPN(参见第十三章)。

您会将备份存储在什么设备上?这取决于您的需求。对于单个用户,我喜欢使用 USB 存储介质。假设您有一台台式 Linux PC、一台笔记本、一台平板和一部智能手机。将手机和平板备份到您的 PC,然后将 PC 备份到 USB 硬盘驱动器上。重要的文件可以备份到在线备份服务。

对于多用户,一个好的解决方案是一个中央备份服务器。这可以是任何 Linux PC。

考虑长期性。您不能依赖数字存储介质的长期存储,因为即使介质(硬盘、USB 存储驱动器、CD/DVD)存活下来,也不能保证能够持久读取。硬件和文件格式会发生变化。您还能读取软盘吗?还记得 ZIP 盘吗?还有那些旧版 Microsoft Word 和 Powerpoint 文档的档案?使用开源文件格式,您总能找到恢复它们的方法。但是在供应商决定停止支持它们时,专有格式的恢复就很困难了。

纸张仍然是长期存储的冠军,值得考虑用于你最重要的文件和照片。

长期数字存储中,计划定期将你的存档转移到新的媒体,可能需要新的命令和新的文件系统格式。

那么备份你的备份服务器怎么样?没问题。建立一个远程 rsync 镜像来备份备份是一种常见策略,如果你的互联网连接足够强大来处理流量的话。但在建立大规模备份基础设施之前,请考虑你真正需要多少级冗余。离站点备份是对你站点灾难的保险。这可以是你控制的远程备份服务器,也可以是朋友的站点,或者是数据中心的租用空间。也要考虑恢复:你能快速获取你的备份吗?

永远记住备份的目的是恢复。定期测试你的备份,避免以最艰难的方式发现你的备份方法失败。

在本章中,你将学习如何使用cp简单地将文件复制到 USB 存储设备。对一些用户来说,这可能是他们所需要的全部。

大部分章节讲述使用rsync命令进行更快、更有效的复制。你可以使用rsync将文件备份到本地媒体或远程服务器。你将学习哪些文件应该备份,如何微调文件选择,保持文件的相同权限和时间戳,如何为多用户建立一个 rsync 备份服务器,以及如何进行安全的远程备份。

7.1 选择需要备份的文件

问题

你不确定应该备份哪些文件。是否需要备份系统文件?你真的需要备份所有的个人文件吗?有些文件是不需要备份的吗?

解决方案

任何你会后悔丢失的文件都是需要备份的文件。你的个人文件和系统数据文件是最重要的。恢复系统文件,如命令、应用程序和库,相对不那么重要,因为你总是可以重新下载和安装这些文件。

以下目录包含诸如配置文件、服务器数据文件(如 web、FTP 和邮件服务器)、日志文件、安装在非标准位置的应用程序以及共享目录等文件,都应该进行备份:

  • /boot/grub,如果其中包含任何自定义内容,如主题、背景图片或字体。

  • /etc 包含系统配置文件。

  • /home,用户的个人文件。

  • /mnt,临时文件系统挂载点。如果你有想要保留的挂载点,也需要备份它。

  • /opt,用于专有或其他非标准安装的应用程序。

  • /root,root 用户的个人文件。

  • /srv,服务器数据,如 web、FTP 和 rsync 服务器的数据。

  • /tmp 包含临时数据,根据需要会自动更新或删除。/tmp 中的一些数据是持久的,例如用户创建的文件和一些系统服务,它们应该备份。

  • /var 存储许多类型的数据,如日志文件、邮件池、cron 作业和系统服务的数据,尽管大多数发行版已经迁移到使用 /srv 用于系统服务。

如果你有任何共享目录、自定义命令和脚本,或者之前未列出的任何数据文件或目录,请备份它们。

/proc/sys/dev 是存在于内存中的伪文件系统,不应备份。

/media 用于挂载可移动存储介质,应由系统管理,因此无需备份。如果你在 /media 手动创建挂载点,则确实需要将它们移动到 /mnt

许多数据库不应该使用简单复制备份,因为它们有专门的实用程序和流程用于复制、备份和恢复。使用专为你的数据库制作的工具。一些示例是 PostrgreSQL、MariaDB 和 MySQL。

从备份中恢复

有些文件不应从备份中恢复;参见配方 7.2。

如果备份存储足够大,复制一切是简单的方法。你还可以通过创建文件复制或排除列表来精确调整文件选择;参见配方 7.8 和 7.9。

讨论

存储媒体现在价格很便宜,你可能不必关心存储空间的保留。如果你需要注意存储限制,请参阅本章关于文件选择的配方。

参见

7.2 从备份中选择要恢复的文件

问题

你正在从备份中恢复文件,并且想知道是否有文件不应该被恢复。

解决方案

根据情况,有些文件不应该被恢复。

在重新安装 Linux 后不要恢复 /etc/fstab(配置静态文件系统挂载的文件)。每次安装 Linux 时,所有文件系统都会获得新的通用唯一标识符(UUID),因此它们将无法被识别,你的新安装将失败。

注意,恢复任何 /etc 中的文件或家目录中的点文件(如 /home/.config/home/.local),如果你要将其从备份恢复到不同版本或不同 Linux 发行版的新安装中,可能会存在配置选项或文件位置的不兼容性。逐个恢复它们,这样你可以快速发现任何问题。

参见

  • 第一章

7.3 使用最简单的本地备份方法

问题

你想知道最简单、最简便的方法来定期备份到本地 USB 存储设备。

解决方案

答案是使用简单复制。弄一个好用的 USB 硬盘或 USB 存储棒。插上它,用你的文件管理器复制你的文件。简单易行,没麻烦,恢复文件也很简单。或者,使用 cp 命令(参见第 7.4 节)。

讨论

简单复制并不完全适合所有情况,但对于少量设备,如个人电脑、笔记本电脑和手机,效果还不错。重要的是定期进行备份,验证你可以从备份中恢复文件,并且不必担心是否足够“极客”。

从前,备份更复杂,因为存储空间昂贵,所以备份程序使用了很多技巧来节省空间。现在你可以花不到 200 美元购买支持多 TB 容量的外部 USB 3.0 硬盘。

参见

  • man 1 cp

7.4 自动化简单的本地备份

问题

你喜欢使用简单复制来将文件备份到外部 USB 存储驱动器,并且希望自动化这个过程。

解决方案

这需要使用 cp 命令和 crontab 来安排你的备份。

你可以列出要复制的单个文件和目录,用空格分隔:

duchess@pc:~$ cp -auv Pictures/cat-desk.jpg Pictures/cat-chair.png \
  ~/cat-pics /media/duchess/2tbdisk/backups/

下面的示例将 Duchess 的整个主目录复制到名为2tbdisk的外部 USB 驱动器上的backups目录中:

duchess@pc:~$ cp -auv ~ /media/duchess/2tbdisk/backups/

这将在备份设备上创建 /media/duchess/2tbdisk/backups/duchess/

复制目录内容而不复制目录本身:

duchess@pc:~$ cp -auv /home/duchess/* /media/duchess/2tbdisk/backups/

创建一个个人 cron 作业,在每晚 10:30 运行你的备份:

duchess@pc:~$ crontab -e
# m h  dom mon dow   command
30 22  *   *   *   /bin/cp -au /home/duchess /media/duchess/2tbdisk/backups/

讨论

如果你想保留文件属性(如所有权和权限),请使用支持文件属性的 Linux 文件系统格式化你的备份驱动器,例如 Ext4、XFS 或 Btrfs(见第十一章)。FAT 文件系统不保留所有权或权限。

留意备份运行的时间长短。如果超过了预定的备份间隔时间,cron 会按计划启动下一次备份,然后你就有麻烦了。

第一次运行时间最长,因为所有文件都是新的。随后的备份将更快,因为只会复制新文件和时间戳更新的文件。

波浪线,~,是当前用户主目录的快捷方式,在这个示例中,它是 /home/duchess 的缩写。

/home/duchess/ 中的星号表示复制 /home/duchess 中的所有文件,但不包括目录 /home/duchess

-a-u-v 选项用于 cp 的含义是:

  • -a, --archive 递归复制并保留所有文件属性:模式、所有权、时间戳和扩展属性。

  • -u, --update 告诉 cp 仅复制比备份目录中的副本更新的文件,或尚未备份的新文件。

  • -v, --verbose 在复制操作期间打印活动消息。

还有一些其他有用的选项:

  • -R, -r 递归;当你不使用 -a 选项时,用它来复制目录。-a 保留文件属性,-R, -r 则不保留。FAT 和 exFAT 文件系统不支持文件属性,因此在这些文件系统中使用 -R, -r

  • --parents 在目标上创建丢失的父目录。

  • -x, --one-file-system 这可以防止递归到其他分区和挂载的网络文件系统中。例如,如果你挂载了一个 NFS 共享,你可能不希望将其添加到备份中。

大多数 Linux 发行版在 /run/media/media 中挂载 USB 设备。找到你的 USB 驱动器的文件路径的简单方法是查看文件管理器或使用 lsblk 命令:

$ lsblk
NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
[...]
sdb      8:16   0  1.8T  0 disk
└─sdb1   8:17   0  1.5T  0 part /media/duchess/backups

参见

  • Recipe 3.7 了解更多关于使用 cron 的信息

  • man 1 crontab

  • man 1 cp

7.5 使用 rsync 进行本地备份

问题

你想要将备份存储到 USB 闪存或 USB 硬盘,并且你希望比简单复制更快更高效。你还希望使用标准 Linux 工具进行简单的文件恢复,而不需要特殊软件。

解决方案

rsync 是你想要的。它可以同步文件系统,无论是本地还是远程。rsync 快速高效,因为它只传输文件中的更改,你可以使用 rsync 命令、cp 命令、你的文件管理器或者你喜欢的任何复制工具来恢复文件。

下面的示例展示了如何备份一个主目录。首先,命名你的源目录,即你想要备份的目录,然后命名目标目录。这个示例将 Duchess 的 /home 复制到名为 2tbdisk 的 USB 驱动器中:

duchess@pc:~$ rsync -av ~ /media/duchess/2tbdisk/
sending incremental file list
duchess/
duchess/Documents/
duchess/Downloads/
duchess/Music/
[...]

sent 27,708,209 bytes  received 20,948 bytes  11,091,662.80 bytes/sec
total size is 785,103,770,793  speedup is 28,313.29

你可以指定两个或更多的目录,用空格分隔的列表,传输到目标目录:

duchess@pc:~$ rsync -av ~/arias ~/overtures /media/duchess/2tbdisk/duchess/

将文件从备份设备复制到计算机上,反转源和目标:

duchess@pc:~$ rsync -av /media/duchess/2tbdisk/duchess/arias /home/duchess/

你可以安全地使用 --dry-run 选项测试你的 rsync 命令,而不复制任何文件:

duchess@pc:~$ rsync -av --dry-run \
~/Music/scores ~/Music/woodwinds /media/duchess/2tbdisk/duchess/

如果从源目录删除了任何文件,rsync 将不会从目标目录中删除它们,除非你使用 delete 选项显式告诉它要删除:

duchess@pc:~$ rsync -av --delete /home/duchess /media/duchess/2tbdisk/

讨论

波浪号 ~ 是你的家目录的快捷方式,所以在例子中它意味着 /home/duchess

带有换行的命令示例使用斜杠 \ 表示命令在下一行继续。你可以复制整个带有斜杠的命令,它应该可以工作。

如果在你的个人电脑上挂载了网络文件系统,比如 NFS 或 Samba,使用 -x 选项仅从本地文件系统复制,而不递归到远程文件系统。

添加尾部斜杠~//home/duchess/)只复制duchess/目录的内容,但不包括目录本身,结果为/media/duchess/2tbdisk/[files]。省略尾部斜杠会传输/home/duchessduchess目录的内容,结果为/media/duchess/2tbdisk/duchess/[files]。尾部斜杠只在源目录上有影响,在目标目录上没有影响。

如果你不得不用手指计数或进行多次测试来提醒自己尾部斜杠的行为,不要感到难过,因为这困扰着每个人。可以将尾部斜杠想象成一个小篱笆,防止源目录逃逸。

-a-v选项对rsync的含义是:

  • -a, --archive保留模式、时间戳、权限和所有权,并进行递归复制。这与-rlptgoD相同,它进行递归复制、复制符号链接、保留权限、保留文件修改时间、保留文件所有权和保留设备文件等特殊文件。

  • -v, --verbose显示活动消息。

你可能希望使用其中一些选项:

  • -q, --quiet抑制非错误消息。

  • --progress显示每个文件传输时的信息。

  • -A, --als保留访问控制列表(ACLs)。

  • -X, --xattrs保留扩展文件属性(xattrs)。

当然,你的文件名会与示例不同。2tbdisk是用户创建的文件系统标签(参见第 9.4 节)。它是“2TB 硬盘”的缩写。如果你没有创建标签,udev会创建一个,例如/media/duchess/488B-7971/

你可以使用正常的 Linux 工具,比如rsync、文件管理器或cp命令来恢复文件。

参见

  • man 1 rsync

7.6 使用 rsync 通过 SSH 进行安全的远程文件传输

问题

你想使用rsync将文件复制到本地网络上的另一台计算机或通过互联网,并且希望进行加密传输和身份验证。

解决方案

rsync在向另一台机器传输文件时默认使用 SSH。远程机器必须运行 SSH 服务器,源机器必须已经设置好 SSH 客户端(参见第十二章)。

这个例子在本地网络上从 Duchess 的 PC 传输文件到她的笔记本电脑。Duchess 在她的笔记本电脑上的用户名是 Empress,她正在从她的 PC 的主目录复制文件到她笔记本电脑的主目录:

duchess@pc:~$ rsync -av ~/Music/arias empress@laptop:songs/
duchess@laptop's password:
building file list ... done
arias/
arias/o-mio-babbino-caro.ogg
arias/deh-vieni-non-tardar.ogg
arias/mi-chiamano-mimi.ogg
wrote 25984 bytes  read 68 bytes  7443.43 bytes/sec
total size is 25666  speedup is 0.99

如果目标目录不存在,rsync会创建它。

要通过互联网上传文件,请使用你要登录的服务器的完全限定域名:

duchess@pc:~$ rsync -av ~/Music/woodwinds \
 empress@remote.example.com:/backups/

从远程主机复制文件的语法是相反的。这个例子将远程主机的/woodwinds目录及其内容复制到 Duchess 的主目录:

duchess@pc:~$ rsync -av empress@remote.example.com:/backups/woodwinds \
 /home/duchess/Music/

讨论

你可能还记得以前必须显式指定 SSH 选项,例如rsync -a -e ssh [options]。现在不再需要这样做。

您可能会发现以下一些选项很有用:

  • --partial 在网络连接中断时保留部分下载的文件,并在恢复连接时从中断处恢复文件传输。

  • -h, --human-readable 显示文件大小为千字节、兆字节和千兆字节,而不是字节。

  • --log-file= 将每次传输的完整记录存储在文本文件中。像这样将它们放在一起:

duchess@pc:~$ rsync --partial --progress \
 --log-file=/home/duchess/rsynclog.txt \
 -hav ~/Music/arias empress@remote.example.com:/backups/

SSH 同时加密验证和传输。用户需要在所有要传输文件的机器上拥有 shell 帐户。请参见第十二章了解使用 SSH 进行安全远程管理的内容。

考虑设置一个中央备份服务器来简化管理。您的用户拥有自己的帐户和自己的/home目录,并可以管理自己的备份和还原,而不会打扰您。

作为备份服务器的另一个选择是将rsync作为服务运行。这样做的优点是rsync用户不需要服务器上的登录帐户。缺点之一是不支持加密传输。请参见 Recipe 7.13 了解详情。

参见

  • man 1 rsync

  • Recipe 12.5

  • Recipe 12.7

7.7 使用 cron 和 SSH 自动化 rsync 传输

问题

您希望创建 crontabs 以自动运行您的安全rsync传输。

解决方案

您需要在目标机器上设置 SSH 以进行无密码验证(请参阅 Recipe 12.10 和 Recipe 12.11),并且客户端需要访问目标机器的网络。

然后使用/etc/crontab来进行需要 root 权限的传输。以下示例每晚 10 点将/etc备份到名为server1的 LAN 服务器:

# m h dom mon dow user  command
00 22 * * * root /usr/bin/rsync -a /etc server1:/system-backups

使用个人 crontabs 来传输您自己的文件(请参阅 Recipe 3.7)。

讨论

OpenSSH 是一个很好的工具,提供安全的网络传输服务,适用于各种任务。任何可以在网络上运行的内容都可能可以通过 SSH 运行。

参见

  • 第十二章

  • Recipe 12.10

  • Recipe 12.11

7.8 从备份中排除文件

问题

到目前为止,示例已经展示了如何传输整个目录。您想知道如何排除文件和目录以防止复制。

解决方案

为简单起见,以下示例演示了向 USB 驱动器进行本地传输的操作,但也适用于通过 SSH 进行远程传输;参见 Recipe 7.6。

当只有几个文件时,您可以使用命令行列出它们,并使用--exclude=来排除一个文件。例如,此示例从/home/duchess/Music/arias排除一个文件:

duchess@pc:~$ rsync -av --exclude=lho-perduta.wav \
 ~/Music/arias /media/duchess/2tbdisk/duchess/Music/

这很简单和可靠。但是,有一个需要注意的地方:如果源目录中有与排除文件相同名称的多个文件,则所有这些文件都将被排除。如果您不想排除重复文件,需要指定要排除的文件。在以下示例中,您只想排除arias/源目录中的复制文件:

duchess@pc:~$ rsync -av --exclude=arias/lho-perduta.wav \
 ~/Music/arias /media/duchess/2tbdisk/duchess/Music/

通过用单引号和逗号分隔它们来排除多个文件,将它们放在大括号中。等号和大括号之间不能有空格,逗号和单引号之间也不能有空格:

duchess@pc:~$ rsync -av \
--exclude={'arias/lho-perduta.wav','non-mi-dir.wav','un-bel-di-vedremo.flac'} \
~/Music/arias /media/duchess/2tbdisk/duchess/Music/

排除目录的工作方式与排除文件相同,您可以在排除列表中混合文件和目录:

duchess@pc:~$ rsync -av \
--exclude={'soprano/','tenor/','non-mi-dir.wav'} \
~/Music/arias /media/duchess/2tbdisk/duchess/Music/

参见 Recipe 7.11 了解如何将您的排除列表放入文件中。

讨论

rsync传输中的根目录是您从中传输文件的顶级目录。在本例中,这是~/Music/ariasrsync检查根目录中的所有文件和目录,并将它们与排除指令(rsync称为模式)进行比较。模式与根目录中的文件和目录进行匹配,从根目录开始并沿着目录层次结构向下进行。每次匹配模式时,它都会从传输中排除。如果模式arias/lho-perduta.wav在另一个位置重复,例如2arias/lho-perduta.wav,它也将被排除。当模式以斜杠(/)结尾时,rsync将仅匹配目录。

参见

  • man 1 rsync

  • Recipe 7.10

7.9 包括选定的备份文件

问题

您希望在备份中包含一组选定的文件,而不是定义要排除的文件列表。

解决方案

当您只想备份几个文件时,可以在命令行上执行此操作。--include= 操作与--exclude= 不同,因为它实际上并不意味着“包括”,而是“不排除”。它需要两个额外选项,--include=/* 和 --exclude='',如此单个文件的传输示例所示:

duchess@pc:~$ rsync -av --include=*/ --include=lho-perduta.wav \
 --exclude='*' ~/Music/arias /media/duchess/2tbdisk/duchess/Music/

您可以传输文件列表:

duchess@pc:~$ rsync -av --include=*/ \
--include={'lho-perduta.wav','non-mi-dir.wav','un-bel-di-vedremo.flac'} \
--exclude='*' ~/Music/arias /media/duchess/2tbdisk/duchess/Music/

等号和大括号之间不能有空格,逗号和单引号之间也不能有空格。

如果在源目录中的不同位置有多个同名文件,则rsync将传输所有这些文件。在此示例中,仅传输了/home/duchess/Music/arias/sopranos/lho-perduta.wav,因为arias/sopranos/lho-perduta.wav模式在/Music/arias中是唯一的:

duchess@pc:~$ rsync -av --include=*/ --include=soprano/lho-perduta.wav
--exclude='*' ~/Music/arias /media/duchess/2tbdisk/duchess/Music/
Music/
Music/arias/
Music/arias/baritone/
Music/arias/soprano/
Music/arias/soprano/lho-perduta.wav
Music/arias/tenor/
[...]

仅传输一个文件,但所有子目录在~/Music/arias都会被复制。使用-m, --prune-empty-dirs选项来防止复制空目录,如下例:

duchess@pc:~$ rsync -avm --include=*/ --include=soprano/lho-perduta.wav
--exclude='*' ~/Music/arias /media/duchess/2tbdisk/duchess/Music/
Music/
Music/arias/soprano/
Music/arias/soprano/lho-perduta.wav

当您有多个要包含的文件时,请将列表存储在纯文本文件中(参见 7.10 和 7.11 的示例)。

讨论

--include=/* 告诉rsync遍历整个源目录。

--include=[files] 意味着不排除这些文件。

--exclude=''* 告诉 rsync 排除所有未被包含的内容。

记住所有文件路径都是相对于你的源目录而不是系统的根目录。

参见

  • man 1 rsync

  • 配方 7.10

  • 配方 7.11

7.10 使用简单包含文件管理包含内容

问题

你的包含内容对于命令行来说太多了,你希望将列表维护在一个 rsync 能读取的文件中。你也希望如果可能的话,这一切都简单些,多亏了以前与 rsync 的包含/排除文件的经验,那些东西从来就不会正常工作。

解决方案

维护清单的最简单方法,不要因为要理解 rsync 的包含/排除语法而感到烦躁,就是创建一个纯文本文件清单,然后将其提供给 --files-from= 选项。你不必担心它们的顺序,也不用使用 rsync 的过滤符号,只需一个包含你想要的文件和目录的简单清单即可。唯一需要注意的是你清单中的每个条目都必须是相对于你的源目录的路径。在下面的示例中,所有清单条目都相对于 /home/duchess

# include file list
#
/Documents/compositions/jazz/
/Documents/schedule.odt
/Videos/concerts/
.config
.local
/Music/courses/bassoon.avi</strong>
[...]

然后使用带有 --files-from 选项的列表:

duchess@pc:~$ rsync -av ~ --files-from ~/include-list.txt \
 duchess@remote.example.com:/backups/

讨论

这是维护备份文件和目录列表的最简单方法。没有排除项,没有通配符,没有奇怪的语法,只是一个清晰易懂的干净列表。

当你使用波浪线表示你的主目录时,与配方中的最后一个示例一样,不要加上 --files-from= 中的等号。

参见

  • man 1 rsync

  • 配方 7.9

  • 配方 7.11

7.11 使用排除文件管理包含和排除内容

问题

你喜欢配方 7.10 中的简单包含文件概念,但你真的想要同时包含和排除。

解决方案

你想要一个 rsync 排除文件。排除文件提供了更多的灵活性,并包含包括和排除的内容。下面的示例展示了一个基本的配置。每个条目必须以源根目录开始,本示例中为 /home/duchess,并以排除源根目录结束:

# exclude file list
#
# include home directory
+ /duchess/
#
# include .config and .local, exclude all other dotfiles
+ /duchess/.config
+ /duchess/.local
- /duchess/.*
#
# include jazz/, exclude all other files in Documents
+ /duchess/Documents/
+ /duchess/Documents/compositions/
+ /duchess/Documents/compositions/jazz/
- /duchess/Documents/compositions/*
- /duchess/Documents/*
#
# include schedule.odt, include all .ogg files in
# arias/, exclude all other files in Music
+ /duchess/Music/
+ /duchess/Music/schedule.odt
+ /duchess/Music/arias/*.ogg
- /duchess/Music/arias/*
- /duchess/Music/*
#
# includes courses/, exclude all other files in Videos
+ /duchess/Videos/
+ /duchess/Videos/courses/
- /duchess/Videos/*
#
# exclude everything else
- /duchess/*

将其输入 rsync--exclude-from= 选项:

duchess@pc:~$ rsync -av ~ \
 --exclude-from=/home/duchess/exclude-list.txt \
 /media/duchess/2tbdisk/

讨论

exclude-list.txt 示例演示了备份:

  • 两个点文件,.config.local

  • /Documents/jazz 中的单个子目录

  • /Music 中的单个文件 schedule.odt,以及 /Music/arias/ 中的 .ogg 文件

  • /Videos/courses 中的单个目录

行间不应该有空格,评论符号(#)对于提醒每个部分的目的以及增加一些空白是有用的。包含的部分前面要加上加号,排除的部分前面要加上减号。

所有其他位于/home/duchess中的文件都被排除在备份之外。必须首先包括。

+ /duchess/Documents/compositions/
- /duchess/*

尝试包括/Documents

+ /duchess/Documents/
+ /duchess/Documents/compositions/
- /duchess/*

现在/Documents中的所有子目录及其内容都被传输,而不仅仅是/compositions。要仅复制/compositions,您必须排除/Documents;仅排除/duchess是不够的。以下示例仅复制/duchess/Documents/compositions/而不复制其他任何内容:

+ /duchess/Documents/
+ /duchess/Documents/compositions/
- /duchess/Documents/*
- /duchess/*

您可以使用通配符按类型包括或排除文件。例如,包括所有.ogg.flac文件,排除所有.wav文件,以及排除所有cachetemp目录:

# include home directory
+ /duchess/
#
# include all ogg and flac files
+ *.ogg
+ *.flac
#
# exclude wav files, all cache and temp dirs
- *.wav
- cache*
- temp*

您可以有多个源目录。

始终只有一个目标目录。

另请参见

  • man 1 rsync

  • Recipe 7.10

7.12 限制 rsync 的带宽使用

问题

大文件传输可能会使用大量网络带宽并减慢所有操作。您希望有一种简单的方法来限制rsync的带宽使用,而不实施像流量整形这样复杂的东西。

解决方案

使用rsync--bwlimit选项。以下示例将其限制为 512 Kbps:

$ rsync --bwlimit=512 -ave ssh ~/Music/arias empress@laptop:songs/

讨论

--bwlimit只接受以千位为单位的值。

参见

  • man 1 rsync

7.13 构建 rsyncd 备份服务器

问题

您希望用户在中央备份服务器上备份自己的数据,但又不想在备份服务器上给他们提供 shell 帐户。

解决方案

设置一个中央备份服务器,并以守护进程模式运行rsync。您应该已经设置了名称服务,并且网络上的主机可以访问备份服务器。用户不需要在服务器上有登录帐户,因为您将使用rsync自己的访问控制和用户授权来控制对rsync存档的访问。

仅限局域网使用

这仅适用于局域网使用,不适用于不受信任的网络,因为rsync守护程序不会对认证或文件传输进行加密。要进行加密传输,您需要 OpenVPN(第十三章)。

在所有机器上必须安装rsyncrsyncd在备份服务器上运行,客户端将使用rsync命令连接服务器。

在备份服务器上编辑或创建/etc/rsyncd.conf以创建定义存档的rsync模块:

# modules
[*backup_dir1*]
   path = */backups*
   comment = *"server1 public archive"*
   list = yes
   read only = no
   use chroot = no
   uid = 0
   gid = 0

创建您的/backups目录,模式为 0700,由 root 所有,以防止任何有权访问服务器的人员未经授权访问:

$ sudo mkdir /backups/
$ sudo chmod 0700 /backups/

在服务器上以守护进程模式使用 systemd 启动rsyncd

$ sudo systemctl start rsyncd.service

在 Debian/Ubuntu 上,它是rsync.service

如果您的 Linux 系统没有 systemd,请使用rsync命令启动它:

admin@server1:~$ sudo rsync --daemon

在备份服务器上测试rsyncd是否正在监听并接受连接:

admin@server1:~$ rsync server1::
backup_dir1     "server1 public archive"

然后从网络上的另一台 PC 上使用服务器的主机名或 IP 地址进行测试:

duchess@pc:~$ rsync server1::
backup_dir1     "server1 public archive"

duchess@pc:~$ rsync 192.168.10.15::
backup_dir1     "server1 public archive"

现在您知道它已准备好传输文件。测试您是否可以将文件复制到您的新rsyncd服务器:

duchess@pc:~$ rsync -av ~/drawings server1::backup_dir1
building file list.....done
drawings/
drawings/aug_03
drawings/sept_03

wrote 1126399 bytes  read 104 bytes  1522.0 bytes/sec
total size is 1130228  speedup is 0.94

现在查看漂亮的新上传文件:

duchess@pc:~$ rsync server1::backup_dir1/drawings/
drwx------    4,096  2021/01/04  06:06:55    .
-rw-r--r--   21,560  2021/09/17  08:53:18    aug_03
-rw-r--r--   21,560  2021/10/14  16:42:16    sept_03

向服务器上传更多文件,然后从 rsyncd 服务器下载文件到另一台计算机:

madmax@buntu:~$ rsync -av server1::backup_dir1/drawings ~/downloads
receiving incremental file list
created directory /home/madmax/downloads
drawings/
drawings/aug_03
drawings/sept_03

sent 123 bytes  received 11562479 bytes  1755.00 bytes/sec
total size is 1141776 speedup is 1.00

一切顺利。休息一下,享受您的成功。

讨论

这不是一种安全的文件传输形式,因为没有加密,网络上的任何人都可以访问文件。适合在本地网络上进行简单的归档和文件共享。

连接到运行在守护程序模式下的 rsync 服务器时,rsync [hostname]:: 需要双冒号。这告诉 rsync 查找模块名称。

这些是 /etc/rsyncd.conf 示例中的命令选项:

[backup_dir1]

模块名称可以随意设置。

path =

定义模块要使用的目录。

comment =

这是一个简要描述,提醒您模块属于谁,或者用于什么用途。

list=yes

允许用户查看模块中的文件列表。no 将隐藏模块。

read only = no

允许用户上传文件到服务器。

use chroot = no

覆盖了 use chroot = yes 的默认设置。chrootchange root,有时被称为 chroot jailchroot jail 是您文件系统内的一个独立环境,包含其自己的根文件系统、命令、库以及所有其他所需内容。虽然通常被视为安全工具,但这并不是一个安全的环境。对于 rsync,手册页面将其描述为对配置错误有用的保护措施。折衷之处在于,rsync 被阻止跟随符号链接到 chroot 环境外的文件,且通过名称保存 UID 和 GID 复杂化。正如人们所说,效果因人而异,对您可能是一个不错的选择。参见 rsyncd.conf (5)use chroot 部分。

uidgid 都设置为 root0。这样可以保留 UID 和 GID,并正确管理权限。

如果您的任何传输失败,请查看 rsync 错误消息。它们会告诉您是否在文件路径中出错、拼写错误或无法连接到服务器,并提供有用的修正提示。

如果您使用的是没有 systemd 的 Linux,请查阅其文档,了解如何启动和停止 rsyncd。

参见 7.14 节 了解如何设置访问控制。

参见

  • man 5 rsyncd.conf

7.14 限制对 rsyncd 模块的访问

问题

您不希望开放 rsyncd 服务器,并希望用户拥有自己的受保护模块,其他用户无法访问。

解决方案

rsyncd 自带简单的身份验证和访问控制。创建一个新文件,包含用户名/密码对,并将 auth userssecrets file 指令添加到 /etc/rsyncd.conf

首先创建密码文件。在下面的示例中,/etc/rsyncd-users 设置了三个用户及其密码:

# rsync-users for server1
duchess:12345
madmax:23456
stash:34567

设置权限为仅根用户读写:

$ sudo chmod 0600 /etc/rsyncd-users

现在在/etc/rsyncd.conf为您的一个用户创建一个模块。此示例为 Duchess 创建了一个模块,使用rsync服务器上的/backups/duchess目录:

[*duchess_backup*]
   path = */backups/duchess*
   comment = *Duchess's private archive*
   list = yes
   read only = no
   auth users = *duchess*
   secrets file =*/etc/rsyncd-users*
   use chroot = no
   strict modes = yes
   uid = root
   gid = root

创建您的用户备份目录,例如 Duchess 的此示例,权限设置为 0700:

$ sudo mkdir */backups/duchess/*
$ sudo chmod -R 0700 */backups/duchess/*

现在尝试登录:

$ rsync *duchess@server1::duchess_backup*
Password: *12345*
drwxr-xr-x      4,096 2020/06/29   18:24:43 .

尝试传输一些文件:

$ rsync -av ~/logs *duchess@server1::duchess_backup*
Password:
sending incremental file list
logs/
logs/irc.log
logs/irc_#core-standup.log
logs/irc_#core.log
logs/irc_#desktop.log
logs/irc_#engineering.log
logs/irc_#mobile.log

sent 130,507 bytes  received 305 bytes  37,374.86 bytes/sec
total size is 129,383  speedup is 0.99

成功了!如果文件传输失败,请查看rsync日志了解原因。在 systemd Linux 上,阅读状态输出中的最新日志条目:

$ systemctl status rsyncd.service

在其他 Linux 发行版上,rsyncd 日志应该位于 /var/log

讨论

用户名/密码对是任意的,与系统用户帐户无关。rsyncd用户在其rsync共享之外没有访问主机系统的权限。

为了增加安全性,在/etc/rsyncd.conf中添加以下指令:

hosts allow

使用此选项列出允许访问rsyncd档案的主机。例如,您可以限制对单个子网上的主机的访问:

hosts allow = **.local.net*
hosts allow = *192.168.1.*

所有未允许的主机都会被拒绝,因此您不需要一个hosts deny指令。

hosts deny

通常情况下,如果使用hosts allow,则不需要这个。但对于拒绝访问引起麻烦的特定主机,它很有用。

密码文件以明文存储,因此必须限制为超级用户。

参见

  • man 5 rsyncd.conf

  • 第 7.13 节中的讨论了解命令选项。

7.15 为 rsyncd 创建一条消息的尝试

问题

您正在运行一个rsyncd服务器,并且您认为向用户致以愉快的问候会很好。

解决方案

在一个纯文本文件中创建您的每日消息(MOTD),例如/etc/rsync-motd

*Welcome to your local backup server! Please remember to actually back up
your files!*

然后在/etc/rsyncd.conf的顶部配置 MOTD 文件的位置:

[global]
motd file = */etc/rsync-motd*

当用户连接到您的服务器时,他们会看到您的消息:

$ rsync *server1::backup_dir1/*
Welcome to your local backup server! Please remember to actually backup your
files!

drwx------          4,096 2020/06/29 18:24:43 .
-rwxr-xr-x          6,400 2015/03/13 08:21:21 keytool
drwx------          4,096 2020/06/17 06:07:41 WIP
drwx------          4,096 2020/06/17 06:06:55 bin
drwxr-xr-x          4,096 2020/06/30 09:47:42 duchess
[...]

讨论

每日消息是一个古老的 Unix 传统。您可以用它来欢迎问候、维护停机公告、安全提示、备份技巧或任何您认为重要的事情。

参见

  • man 5 rsyncd.conf

第八章:使用 parted 管理磁盘分区

所有的存储驱动器——SATA 硬盘、固态硬盘、USB 驱动器、SD(安全数字)卡、NVMe(非易失性内存表达式)和 CompactFlash 卡——在使用前都必须进行分区和格式化。它们都预装了某种分区和文件系统,可能不符合你的需求。随着需求变化,你可能需要重新分区并使用不同的文件系统。在本章中,你将学习使用 parted(分区编辑器)管理分区。

概述

parted 只管理分区;参见第十一章学习文件系统。第九章介绍了图形前端工具 GParted,它可以同时管理分区和文件系统。

你还将了解到 Master Boot Record(MBR)的现代替代品,即老旧而不足的传统分区表。MBR 已被新的全局唯一标识分区表(GUID Partition Table 或 GPT)取代。

parted 显示分区信息,并添加、删除和调整分区大小。parted 只有一个需要注意的地方:它会立即将更改写入磁盘,所以你必须小心。GParted 则不会立即应用更改,直到你点击一个按钮。

尽管很多存储设备不再是磁盘而是固态设备,如 USB 闪存,但称它们为“磁盘”仍是一种常见的便利说法。为什么不呢?我们还在用电话拨号,用智能手机录制磁带录音和视频呢?

磁盘分区是存储磁盘的逻辑分割,是将磁盘划分为一个或多个独立区域的方法。一个磁盘必须至少有一个分区。分区的数量取决于你的需求和喜好。分区完成后,你必须在每个分区上创建文件系统,然后才能使用它。一个单独的磁盘可以有多个分区,每个分区可以有不同的文件系统。

在 Linux 上,磁盘名称始终为 /dev 后跟一些内容,这缩写自 device。例如,硬盘为 /dev/sda,光驱为 /dev/sr0。分区是磁盘名称加上一个数字。如果 /dev/sda 有三个分区,它们分别为 /dev/sda1/dev/sda2/dev/sda3

分区方案

一些 Linux 发行版的默认分区方案是将整个安装内容放入单个分区。这样做没问题,但在安装过程中设置几个更多的分区有其优点:

  • /boot 单独分区使得管理多重启动系统更加容易,因为启动文件与安装或移除的操作系统独立。

  • /home 放在单独的分区中可以隔离它与根文件系统,这样你可以在不触及 /home 的情况下替换 Linux 安装。/home 甚至可以在一个独立的驱动器上。

  • /var/tmp 可能因为进程失控而填满。将它们放在独立的分区上可以防止它们影响其他文件系统。

  • 将交换文件放在独立的分区上可以启用挂起到磁盘的功能。

参见第 1 章了解更多关于设计分区布局的信息。

分区表:GPT 和 MBR

GUID 分区表(GPT)于 2010 年首次发布,是古老的 PC-DOS 主引导记录(MBR)的现代替代品。如果您只有 MBR 的使用经验,那么准备好迎接新体验,因为 GPT 是一个重大进步。

MBR 是在上个世纪 80 年代初期 IBM PC 诞生时创建的,当时的硬盘容量为 10 兆字节(MB),是一个激动人心的时代。MBR 放置在磁盘的第一个扇区的前 512 字节之内,在第一个分区之前,包含引导加载程序和分区表。引导加载程序占用 446 字节,分区表使用 64 字节,剩余的 2 字节存储引导签名。

64 字节的存储空间并不多,所以 MBR 限制为四个主分区。一个主分区可以容纳一个扩展分区,扩展分区可以进一步划分为逻辑分区。Linux 理论上支持无限数量的逻辑分区。即使有大量的逻辑分区,MBR 也只能寻址最大 2.2 TiB 的磁盘空间,这在今天勉强能够容纳您的猫咪表情包。为什么会有这个限制?您可以自己算一下:MBR 只能寻址 32 位,可以寻址 2³² 个块(我们稍后会讨论块和扇区),所以对于每个 512 字节块的磁盘,计算公式为 2³² x 512 = 2.199023256×10¹² 字节。

BIOS 和 UEFI

GPT 是 UEFI(统一可扩展固件接口)规范的一部分。UEFI 取代了您计算机的基本输入输出系统,更为人熟知的是 PC BIOS 或简称 BIOS。图 8-1 是旧的传统 BIOS,图 8-2 是现代的 UEFI,充满了闪亮的先进功能,就像一个小操作系统一样。

GPT 相比于 MBR 有很多优势:

  • Linux 上最多可以有 128 个分区,编号为 1–128,不涉及主分区和扩展分区

  • 容错性:分区表的副本存储在多个位置

  • 磁盘和分区的唯一标识符

  • 传统 BIOS/MBR 启动模式

  • 验证自身完整性和分区表

  • 安全启动

传统 BIOS 设置

图 8-1. 传统 BIOS 设置

UEFI 设置

图 8-2. UEFI 设置

MBR 几乎已经过时,你应该使用 GPT。在 GPT 中,磁盘的第一个扇区保留为保护性 MBR,支持 BIOS 计算机上的 GPT,因此我们可以在老式系统上使用 GPT,这些系统使用 BIOS 而非 UEFI。引导加载程序和操作系统都必须支持 GPT,Linux 多年来一直支持这一点。只有在不支持 GPT 的旧计算机和旧操作系统上才需要使用 MBR。

如果你有一台带有 BIOS 的旧系统,无法将其升级为 UEFI,而必须更换主板以获得 UEFI。UEFI 和 BIOS 都集成在主板中。

块和扇区

现在我们将讨论块和扇区,以及它们对磁盘、文件和分区的最大大小的影响。是文件系统可以使用的磁盘上最小的存储单元。这些是逻辑上的划分,而非物理上的。最小的物理存储单元是扇区。块可以跨越多个扇区,文件可以跨越多个块。

当文件跨越多个块时,会有一定的浪费,因为文件很少与块大小匹配。例如,一个比四个块大一字节的文件将使用五个块。第五个块仅包含一个字节,并且该块专用于该文件。因此,你可能会认为 512 字节的块比较节省空间。但一个块中存储的信息比文件还要多。

每个块除了文件数据外,还存储时间戳、文件名、所有权、权限、块 ID、以及它与其他块的正确顺序、inode 和其他元数据。

4096 字节块使用 512 字节块的八分之一的元数据。在 4 TiB 硬盘上,你需要 8,000,000,000 个 512 字节块。而使用 4096 字节块大小时,只需要 1,000,000,000 个块,这表示了相当大的元数据节省。

扇区大小限制了存储卷的大小。硬盘的标准扇区大小多年来一直是 512 字节,现在则是 4096 字节,因为硬盘已经变得如此之大。

GPT 提供 64 位寻址,支持单个磁盘上的总块数为 2⁶⁴,因此具有 512 字节块的硬盘可以达到多达 9 ZB 的大小。使用 4096 字节块时,最大磁盘大小为 64 ZB,我敢说即使是最狂热的猫视频收藏者也足够用了。这些是理论上的最大限制,受可用硬件、操作系统限制以及文件系统对大容量卷的支持所限制。例如,Ext4 文件系统对单个文件系统的最大容量为 1 EiB,对 4096 字节块大小的文件的最大大小为 16 TiB。XFS 支持最大文件系统和文件大小为 8 EiB 减去 1 字节。

CD 和 DVD 有 2048 字节的扇区。像 USB 闪存、SD 卡、CompactFlash 和固态硬盘(SSD)这样的固态设备也有扇区和块。SSD 上最小的单位称为。常见的页大小有 2 KB、4 KB、8 KB 及更大。块包含 128 到 256 页,块大小通常为 256 KB 到 4 MB。

所有这些庞大的数字都有点让人眼花缭乱。表 8-1 总结了用于测量磁盘容量的十进制和二进制测量。

表 8-1. 字节的十进制和二进制倍数

Value Decimal Value Binary
1 B 字节 1 B 字节
1000 kB 千字节 1024 KiB 基比字节
1000² MB 百万字节 1024² MiB 兆比字节
1000³ GB 十亿字节 1024³ GiB 吉比字节
1000⁴ TB 兆字节 1024⁴ TiB 提比字节
1000⁵ PB 百万亿字节 1024⁵ PiB 皮比字节
1000⁶ EB 百亿字节 1024⁶ EiB 伊比字节
1000⁷ ZB 十亿亿字节 1024⁷ ZiB 泽比字节
1000⁸ YB 十亿亿亿字节 1024⁸ YiB 佑比字节

十进制值是 10 的幂;例如,千字节是 1000 字节,即 10³。二进制值是 2 的幂,因此基比字节是 2¹⁰,1024 字节。硬盘制造商喜欢使用十进制格式来使他们的驱动器看起来更大。

谁想出这种奇怪的“bibyte”命名方案几乎保证没有人愿意说这些名字。总之,人们喜欢互换使用它们。无论如何,现在您知道了区别。

8.1 使用 parted 前卸载您的分区

问题

您知道在使用parted之前必须卸载您的分区或分区,您需要知道如何操作。

解决方案

从图形文件管理器卸载分区,或使用umount命令。以下示例卸载/dev/sdc2

$ sudo umount /dev/sdc2

如何确定正确的设备名称?参见 Recipe 8.3 学习如何列出您连接的磁盘和分区。

如果您在磁盘上创建新的分区表,应先卸载所有分区。

更改运行中的系统

如果您在分离分区上有活动根文件系统(如/home/var/tmp),卸载这些文件系统是有风险的。在另一个 Linux 实例中执行分区操作更安全,例如 SystemRescue(第十九章),或同一台机器上的第二个 Linux(第一章)。

讨论

从技术上讲,您挂载和卸载文件系统而不是分区。但是,如果您说“分区”,我也不会怪您。

另请参阅

8.2 选择 parted 的命令模式

问题

您知道可以启动parted命令以交互模式启动,启动parted命令 shell,或者将其作为普通命令运行,您想知道如何做这两件事。

解决方案

以无选项运行 parted 启动交互式 parted shell。您需要 root 权限:

$ sudo parted
GNU Parted 3.2
Using /dev/sda
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted)

当您的正常命令提示符更改为 (parted) 时,您就处于 parted shell 中。输入 help 查看命令列表及其描述。对于单个 parted 命令也有帮助,例如,help print。输入 quit 退出 parted。大多数 parted 命令可以缩写为它们的第一个字母,如 hq

输入完整的命令以在常规 shell 中运行 parted,例如,列出所有磁盘的以下示例:

$ sudo parted /dev/sdb print devices
/dev/sdb (2000GB)
/dev/sda (4001GB)
/dev/sdc (4010MB)
/dev/sdd (15.7GB)
/dev/sr0 (425MB)

命令运行并退出,然后返回到正常的命令提示符。

讨论

无论在哪种模式下都要小心,因为 parted 会立即应用您的更改。在使用 parted 前务必做好完整的备份。

参见

8.3 查看现有磁盘和分区

问题

您希望查看现有的分区、它们的大小以及它们上面的文件系统。

解决方案

如果不知道系统上磁盘的名称,请以无选项运行 parted

$ sudo parted
GNU Parted 3.2
Using /dev/sda
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted)

当您未选择设备时,parted 会猜测您想要的设备,通常是第一个,并告诉您已选择了哪一个(请参阅前面示例中的 Using /dev/sda)。

print devices 列出您的磁盘名称和大小:

(parted) print devices
/dev/sda (256GB)
/dev/sdb (1000GB)
/dev/sdc (4010MB)

选择您要查看的设备,然后显示其信息:

(parted) select /dev/sdb
Using /dev/sdb
(parted) print
Model: ATA ST1000DM003-1SB1 (scsi)
Disk /dev/sdb: 1000GB
Sector size (logical/physical): 512B/4096B
Partition Table: gpt
Disk Flags:

Number  Start   End     Size    File system     Name  Flags
 1      1049kB  525MB   524MB   fat16                 boot, esp
 2      525MB   344GB   343GB   btrfs
 3      344GB   998GB   654GB   xfs
 4      998GB   1000GB  2148MB  linux-swap(v1)        swap

(parted)

输入 quit 退出。

您可以打开 parted shell 到特定的磁盘:

$ sudo parted /dev/sda
GNU Parted 3.2
Using /dev/sdb
Welcome to GNU Parted! Type 'help' to view a list of commands.

输入 print 无选项查看有关此磁盘的信息:

(parted) print
 Model: ATA SAMSUNG SSD SM87 (scsi)
Disk /dev/sda: 256GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
[...]

print all 列出所有设备上的所有分区:

(parted) print all
 Model: ATA SAMSUNG SSD SM87 (scsi)
Disk /dev/sda: 256GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags:

Number  Start   End    Size    File system  Name                    Flags
 1      1049kB  524MB  523MB   fat16        EFI system              legacy_boot,
                                            partition               msftdata

 2      524MB   659MB  134MB                Microsoft reserved      msftres
                                            partition
 3      659MB   253GB  253GB   ntfs         Basic data partition    msftdata

 4      253GB   256GB  2561MB  ntfs                                 diag

Model: ATA ST1000DM003-1SB1 (scsi)
Disk /dev/sdb: 1000GB
Sector size (logical/physical): 512B/4096B
Partition Table: gpt
Disk Flags:

Number  Start   End     Size    File system     Name  Flags
 1      1049kB  525MB   524MB   fat16                 boot, esp
 2      525MB   344GB   343GB   btrfs
 3      344GB   998GB   654GB   xfs
 4      998GB   1000GB  2148MB  linux-swap(v1)        swap

Model: General USB Flash Disk (scsi)
Disk /dev/sdc: 4010MB
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags:

Number  Start   End     Size    Type     File system  Flags
 1      1049kB  4010MB  4009MB  primary  fat32

查找任何未分区的空闲空间在任何磁盘上:

(parted) print free
Model: ATA ST4000DM000-1F21 (scsi)
Disk /dev/sda: 4001GB
Sector size (logical/physical): 512B/4096B
Partition Table: gpt
Disk Flags:

Number  Start   End     Size    File system     Name  Flags
        17.4kB  1049kB  1031kB  Free Space
 1      1049kB  500MB   499MB   ext4
 2      500MB   60.5GB  60.0GB  ext4
 3      60.5GB  2061GB  2000GB  xfs
 4      2061GB  2069GB  8000MB  linux-swap(v1)
        2069GB  4001GB  1932GB  Free Space

讨论

让我们看看所有这些输出意味着什么:

  • Model 是设备的制造商名称。

  • Disk 给出设备名称和大小。

  • Sector size 给出逻辑和物理块大小。逻辑块大小为 512B,用于与旧版磁盘控制器和软件的兼容性。

  • Partition table 告诉您分区类型,可以是 msdosgpt

  • Flags 对 Windows 比 Linux 更重要。它们标识分区类型,在某些情况下是必需的,以便 Windows 减少混乱。完整列表在 Parted 用户手册 中。

这些是示例中的分区标志的含义:

  • legacy_boot 将 GPT 分区标记为可引导。

  • msftdata 标记包含 Microsoft 文件系统(NTFS 或 FAT)的 GPT 分区。

  • msftres 是微软预留分区。这是一个特殊分区,微软在 GPT 分区上要求使用,用于操作系统。在小于 16 GB 的分区上,MSR 为 32 MB,在更大的驱动器上为 128 MB。

  • diag 是 Windows 的恢复分区。

  • boot, esp 都将分区标记为引导分区。boot 是 MBR 标签,esp 是 GPT 标签。

  • swap 标记交换分区。

参见

8.4 在无法引导的磁盘上创建 GPT 分区

问题

你想要重新分区一个磁盘,删除所有数据,并使用新的 GUID 分区表(GPT)重新开始。这不是一个具有操作系统的可引导磁盘,只用于数据存储。

解决方案

首先创建新的分区表,然后创建你的分区,最后验证所有的操作是否正确。非常确保你选择了正确的磁盘;参见食谱 8.3 了解如何列出你的磁盘和分区。

在以下示例中,有一个用于数据存储的 USB 存储器位于/dev/sdc。它不是一个具有操作系统的可引导磁盘。在运行parted之前,你必须卸载你的设备。第一步是卸载它,然后创建一个新的 GPT 分区表:

$ sudo umount /dev/sdc
$ sudo parted /dev/sdc
GNU Parted 3.2
Using /dev/sdc
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) mklabel gpt
Warning: The existing disk label on /dev/sdc will be destroyed and all data on
this disk will be lost. Do you want to continue?
Yes/No? Yes
(parted) p
Model: General USB Flash Disk (scsi)
Disk /dev/sdc: 4010MB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags:

Number  Start  End  Size  File system  Name  Flags

现在你可以创建新的分区了。以下示例创建了大致相同大小的两个分区。你必须为分区指定名称,并指定两个分区的起始和结束位置:

(parted) mkpart "images" ext4 1MB 2004MB
(parted) mkpart "audio files" xfs 2005MB 100%

然后检查你的工作,并退出:

(parted) print
Model: General USB Flash Disk (scsi)
Disk /dev/sdc: 4010MB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags:

Number  Start   End     Size    File system  Name         Flags
 1      1049kB  2005MB  2004MB  ext4         images
 2      2006MB  4009MB  2003MB  xfs          audio files

(parted) q
Information: You may need to update /etc/fstab.

如果你的起始或结束点太靠近另一个分区,你将看到一个错误消息。在以下示例中,第二个分区的起始点与第一个分区的结束点相同:

(parted) mkpart "images" ext4 2004MB 100%
Warning: You requested a partition from 2004MB to 4010MB (sectors
3914062..7831551).
The closest location we can manage is 2005MB to 4010MB (sectors
3915776..7831518).
Is this still acceptable to you?
Yes/No? Yes

将其更改为 200 5MB 可以修复这个错误。

讨论

start 设置新分区的起始位置。这总是一个数值。例如,示例中的1MB表示从磁盘开头算起的一兆字节。你不能从零开始,因为前 33 个扇区用于 EFI 标签,所以第一个分区从第 34 个扇区或更高开始。我从一兆标记开始,因为这样更容易记住。

end 可以使用大小值或百分比。例如,第一个分区的结束位置是从第一个分区的起始位置算起的 200 5MB。第二个分区的结束位置是剩余空间的 100%。创建新的分区表会清除磁盘上的所有数据。

在分区可用之前,你必须在新的分区上放置文件系统(参见第十一章)。

警告“您可能需要更新/etc/fstab”仅适用于更改了在/etc/fstab文件中的分区。

创建新的 GPT 分区的语法是mkpart name fs-type start end

name 是必需的。可以任意选择一个名称,以便记住这个分区的用途。

fs-type标签不是必需的,但你应该指定它,以便为分区分配正确的文件系统类型代码。在parted shell 中运行help mkpart以查看文件系统标签的列表。

即使你创建了文件系统标签,但是磁盘上还没有文件系统。创建文件系统是一个单独的步骤。

文件系统标签有时会消失。在分区上放置文件系统后,它们将保持不变。

parted 的帮助和文档在创建 GPT 分区和 MS-DOS 分区之间的差异上有些混乱。当创建 GPT 分区时,必须为其创建一个 名称。当创建 MS-DOS 分区时,必须指定一个 part-type,它可以是 primaryextendedlogical 中的一个。关于这一点存在相当多的混淆,结果是管理员为 GPT 分区创建了 primaryextendedlogical 的名称。这是不正确的,你应该为 GPT 分区创建 names

无论如何,你不应该创建 MS-DOS 分区表,因为它们已过时,除非是旧计算机和不支持 GPT 的旧软件。

另请参阅

8.5 创建用于安装 Linux 的分区

问题

你想在磁盘上安装 Linux 并需要知道如何对其进行分区。

解决方案

使用 Linux 安装程序中的分区管理器。你可以在运行安装程序之前设置分区,但使用安装程序的分区管理器可以确保正确操作,并且会显示任何错误的警告。参见 Recipe 1.8 获取建议的分区方案。

讨论

大多数 Linux 安装程序提供了关于新安装分区和手动自定义的指导。

另请参阅

  • 本章的分区建议介绍

  • 第一章

8.6 删除分区

问题

你想删除一些分区。

解决方案

在你想要进行更改的磁盘上启动 parted 交互模式,然后打印分区表:

$ sudo parted /dev/sdc
GNU Parted 3.2
Using /dev/sdc
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) p

Model: General USB Flash Disk (scsi)
Disk /dev/sdc: 4010MB
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags:

Number  Start   End     Size    Type     File system  Flags
 1      1049kB  2005MB  2004MB  primary
 2      2005MB  4010MB  2005MB  primary

在这个例子中,通过输入 rm 2 删除第二个分区。该分区将立即被移除,并且不会有确认。然后输入 p 进行验证:

(parted) rm 2
(parted) p
Model: General USB Flash Disk (scsi)
Disk /dev/sdc: 4010MB
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags:

Number  Start   End     Size    Type     File system  Flags
 1      1049kB  2005MB  2004MB  primary

讨论

在开始之前一定要非常确定你要删除的是正确的分区。可以写下笔记并检查多次。

如果尝试删除已挂载的分区,parted 会发出警告:“警告:分区 /dev/sdc2 正在使用。你确定要继续吗?”你可以继续删除它。任何打开的文件会保留在内存中,直到重新启动或关闭它们,这有点有趣,因为你仍然可以读取并将文件保存到另一个分区。

另请参阅

8.7 恢复已删除的分区

问题

你删除了一个分区,现在希望没有这样做,并且想要恢复它。

解决方案

如果意外删除了一个新的空分区,不必尝试恢复它,只需重新创建它。如果你的分区中有文件系统和数据,则最好立即尝试恢复。在 parted shell 中,使用 rescue 命令,并给出分区的起始和结束位置。这些可以是大致的位置:

(parted) rescue 2000MB 4010MB
searching for file systems... 40%       (time left 00:01)Information: A ext4
primary partition was found at 2005MB -> 4010MB.  Do you want to add it to the
partition table?
Yes/No/Cancel? Yes

parted 不会给出任何反馈,因此请打印分区表以查看丢失的分区是否恢复:

(parted) p
Model: General USB Flash Disk (scsi)
Disk /dev/sdc: 4010MB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags:

Number  Start   End     Size    File system  Name    Flags
 1      1049kB  2005MB  2004MB  xfs          images
 2      2005MB  4010MB  2005MB  ext4

就是这样。稍微有点运气,您所有的文件都是完整的。

讨论

等待恢复分区的时间越长,越可能无法恢复,因为可能会意外覆盖。如果需要延迟救援操作,请将其放在安全的地方。

与往常一样,最佳实践是始终保持良好的备份。

另请参阅

8.8 增加分区大小

问题

您想要增加具有文件系统的现有分区的大小。

解决方案

以下示例增加了带有文件系统的分区的大小。有两个步骤:首先调整分区大小,然后调整文件系统以匹配。每个文件系统都有其自己的工具集,您必须使用正确的工具来增加大小。在本示例中,我们将调整 Ext4、XFS、Btrfs 和 FAT16/32 分区的大小。

Ext4、XFS 和 Btrfs 可以在线或离线扩展。FAT16/32 只能离线调整大小,并且必须先卸载。

您需要在要增加的分区末端有空闲空间。打开 parted shell 到您选择的磁盘,并查找空闲空间:

$ sudo parted /dev/sdc
GNU Parted 3.2
Using /dev/sdc
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) print free
Model: General USB Flash Disk (scsi)
Disk /dev/sdc: 4010MB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags:

Number  Start   End     Size    File system  Name    Flags
[...]
        1024MB  2005MB  981MB   Free Space
 2      2005MB  3500MB  1495MB  ext4         audio
        3500MB  4010MB  510MB   Free Space

这显示第二分区之前有 981 MB 的空闲空间,后面有 510 MB 的空闲空间。您只能更改分区的结束点,因此以下示例扩展了第二分区以使用末端的所有 510 MB 空闲空间。

首先,将分区扩展到新的结束点:

(parted) resizepart 2 4010MB

您不会看到成功消息,但如果出错,您会看到错误消息。键入 p 查看分区表,并验证 resizepart 是否达到您的预期。

现在,您必须使用适合文件系统的适当命令将文件系统扩展到新的分区大小。表 8-2 显示了每个文件系统使用的命令,以扩展到其分区的大小。

表 8-2. 增加文件系统大小的命令

文件系统 调整大小命令
Ext4 sudo resize2fs /dev/sdc2
XFS sudo xfs_growfs -d /dev/sdc2
Btrfs sudo btrfs filesystem resize max /dev/sdc2
FAT16/32 sudo fatresize -i /dev/sdc2

请记住,FAT16/32 必须先卸载。

parted 中打印分区表以检查您的工作。

讨论

本章和 配方 8.9 中的示例都很小,使用的是 4 GB 的 USB 闪存。这对测试很好,但在实际应用中,您可能会使用更大的磁盘。命令相同,只是分区大小不同。

在开始之前,请务必备份数据。

你可以将文件系统调整为比分区更小,但这没有意义。查看第十一章以了解创建和管理文件系统的全部内容。

如果您想知道“我的最爱文件系统在哪里?”我选择了 Ext4、Btrfs、XFS 和 FAT16/32,因为它们是最常用的 Linux 文件系统,而且它们都有很好的维护。

参见

  • 第十一章

  • man 8 resize2fs

  • man 8 parted

  • man 8 xfs_growfs

  • man 8 btrfs

  • man 8 fsck.vfat

8.9 缩小分区

问题

您有一个带有文件系统的分区,并且想要缩小它。

解决方案

XFS 文件系统无法缩小,只能增加。您可以缩小 Ext4、Btrfs 和 FAT16/32。在缩小 Ext4 和 FAT16/32 之前,必须卸载它们。Btrfs 可以在线缩小,但最好先卸载。

确保要缩小的文件系统的已使用部分小于您要缩小到的大小。使用 du 命令查看您的文件占用了多少空间:

$ du -sh /media/duchess/shrinkme
922.6M    /media/duchess/shrinkme

您应该为元数据、浪费的块空间以及可能出现的情况留出约 40% 的额外空间,因此在此示例中,新大小不应小于 1.4 GB。如果需要空间添加更多文件,则还要考虑这一点。

缩小分区比扩展它们更复杂一些。有更多的步骤,并且文件系统必须离线缩小。如果分区位于外部存储设备(如 USB 棒)上,请卸载它然后再缩小它。如果它是属于您正在运行的系统的分区,则必须从可启动的救援磁盘或多启动系统的第二个 Linux 中运行 parted,以便您可以卸载要缩小的文件系统。

在卸载您选择的文件系统后,按照以下步骤操作:

  • 运行文件系统检查

  • 缩小文件系统

  • 缩小分区

运行以下命令以检查 Ext4 文件系统的健康状态:

$ sudo e2fsck -f /dev/sdc2

检查 Btrfs 文件系统:

$ sudo btrfs check /dev/sdc2

检查 FAT16/32 文件系统:

$ sudo fsck.vfat -v /dev/sdc2

当一切都符合要求时,缩小您的文件系统。表 8-3 中的示例将文件系统缩小到 2000 MB。

表 8-3. 减少文件系统大小的命令

文件系统 缩小命令
Ext4 sudo resize2fs /dev/sdc2 2g
Btrfs sudo btrfs filesystem resize 2g /dev/sdc2
FAT16/32 sudo fatresize -s 2G /dev/sdc2

现在,您可以缩小分区以匹配文件系统大小。在您的设备上打开 parted shell,然后运行 resize 命令。指定分区号和终点:

(parted) resizepart 1 2000MB
Warning: Shrinking a partition can cause data loss, are you sure you want to
continue?
Yes/No? y

通过在 parted 中打印分区表来检查您的工作。

讨论

存储介质越来越大且价格便宜。在过去,为了将更多文件塞入磁盘,需要调整分区大小。现在我们可以根据自己的需求定制它们的大小。

参见

  • 第十一章

  • man 8 resize2fs

  • man 8 parted

  • man 8 btrfs

  • man 8 fsck.vfat

第九章:管理分区和文件系统与 GParted

GParted,GNOME 分区管理器,是我在 Linux 上最喜欢的工具之一。GParted 是parted分区管理器命令及所有文件系统管理命令的一个优秀图形前端。你可以通过几个点击操作来创建、删除、移动、复制和调整分区和文件系统,并创建新的分区表。其他功能包括数据恢复、管理标签和 UUID。

分区和文件系统上的标签对于以友好的方式识别分区和文件系统,以及为文件系统提供简短易记的名称非常有用。如果没有标签,文件系统将通过其长 UUID 进行识别。例如,当你插入一个没有文件系统标签的 USB 闪存时,它显示为类似/media/username/1d742b2d-a621-4454-b4d3-469216a6f01e。给它一个好记的短标签,比如mystuff,然后它会挂载为/media/username/mystuff

在 GParted 完成操作后,状态窗口会提供保存操作日志的选项。保存这些信息并仔细研究,因为它显示了所使用的命令。

更改正在运行的系统

对于某些操作,例如复制、检查和修复、设置标签和 UUID,需要先卸载文件系统。不能卸载运行系统所需的文件系统。在这种情况下,请使用可引导的 SystemRescue CD/USB(第十九章)。如果你运行的是安装了多个 Linux 发行版的多引导系统,请启动到另一个 Linux,并从那里运行 GParted(参见第一章)。

GParted 需要 root 权限。当你启动 GParted 时,会打开一个对话框要求输入你的 sudo 或 root 密码(图 9-1)。

应用程序启动器要求输入密码

图 9-1. 应用程序启动器要求输入密码

通常将所有存储介质称为“磁盘”,即使是固态介质如 SSD、USB 驱动器、SD(安全数字)、NVMe(非易失性内存表达)和 CompactFlash。GParted 可以管理任何物理连接到您系统的这些磁盘,无论是内部还是外部。

如果您对分区和管理文件系统的基础不熟悉,第八章的介绍提供了详细的概述。

小心!

在尝试本章中的任何操作之前,请确保有当前的备份,并非常确定你正在操作正确的磁盘和分区。

创建新的分区表会清除整个磁盘上的所有数据。

删除或损坏分区会丢失该分区上的所有数据。虽然有可能恢复数据,但不保证成功。

USB 闪存驱动器非常适合用于实践和测试。

9.1 查看分区、文件系统和空闲空间

问题

您希望查看所有连接到系统的磁盘上的所有分区、文件系统和空闲空间。

解决方案

启动 GParted,并使用右上角的下拉菜单查看所有已连接的磁盘(图 9-2)。点击“查看” → “设备信息”以打开左侧面板查看磁盘信息,如型号、序列号、大小和分区表类型。

在 GParted 上查看磁盘

图 9-2. 在 GParted 上查看磁盘

您将看到大量信息:设备名称、挂载点、文件系统、标签、分区类型和大小、已用空间和总空间以及空闲空间。右键单击任何分区以打开操作菜单,并在菜单底部点击“信息”按钮以查看有关该分区的更多信息(图 9-3)。

查看分区信息

图 9-3. 在 GParted 上查看分区信息

讨论

GParted 在您点击顶部工具栏中的绿色对号之前不会应用更改,因此可以放心探索和浏览。如果您不小心点击了某个命令,请点击对号旁边的小弯曲黄色箭头来撤销。

当您打开右键操作菜单时,一些命令会显示为灰色,因为它们仅适用于未挂载的文件系统。点击“卸载”命令,然后这些命令将变为可用。请注意,任何对运行系统必需的文件系统都无法卸载;在这种情况下,请使用 SystemRescue CD/USB(第十九章)。

参见

9.2 创建新分区表

问题

您想要使用新的 GPT 分区表重新格式化磁盘。您现有的分区表是 MS-DOS,您希望用 GPT 替换它,或者这是一个带有旧安装的已用磁盘,您希望用一个干净的磁盘重新开始。

解决方案

首先,非常确定您要在哪个磁盘上创建新的分区表,因为这将擦除磁盘上的所有数据。这是 GParted 立即执行的一个操作,在仅有一个警告后,且没有撤销功能,因此请小心操作。

在顶部右侧下拉菜单中选择您的磁盘,然后点击“设备” → “创建分区表”(图 9-4)。

创建新分区表

图 9-4. 创建新分区表

选择 GPT 分区表类型并点击应用(图 9-5)。

这不会花费很长时间,然后您将拥有一个新的、干净的、空白的磁盘,可以准备分区并格式化为新的文件系统。

选择新的分区表类型

图 9-5. 选择分区表类型

讨论

除非您有使用其他分区表的理由,否则始终创建 GPT 分区表。GParted 支持多种分区表类型,包括 MS-DOS、BSD、Amiga 和 AIX。在 x86 平台上,GPT 和 MS-DOS 最常用。GPT 适用于现代大容量硬盘,比旧的 MS-DOS 分区表更易管理和更具弹性。详细了解分区表,请参阅第八章的介绍。

参见

9.3 删除分区

问题

您需要删除一个或多个分区。

解决方案

选择要删除的分区,右键单击以打开操作菜单。如果它上面有挂载的文件系统,您必须先卸载它,方法是点击菜单中的卸载。然后点击删除,点击绿色复选标记,分区就删除了(图 9-6)。

删除分区

图 9-6. 删除分区

删除完成后,您将看到状态消息。

讨论

删除分区会删除分区内的所有内容,因此如果分区上有文件系统和数据,请务必确定您要删除它。

参见

9.4 创建新分区

问题

您希望创建新分区。

解决方案

只需磁盘上有空闲空间。以下示例创建一个新的 400 GB 分区,并使用 Ext4 文件系统格式化它(图 9-7)。

创建新分区

图 9-7. 创建新分区

点击分区 → 新建在顶部菜单。这将打开一个新窗口,在此窗口中,您输入分区大小,选择文件系统,并创建分区和文件系统标签。使用滑块或“新大小(MiB)”字段设置文件系统大小。新大小字段中的值以 Mibibytes 为单位,因此 400,000 是 400 GiB。然后点击添加,再点击绿色复选标记。

完成后,请参阅第六章,了解如何在新文件系统上设置正确的所有权和权限。

讨论

使用 GPT 分区表,您只会创建主文件系统。另外两个选项,逻辑分区和扩展分区,仅适用于 MS-DOS 分区表。如果不确定您的磁盘使用哪种分区表,请点击查看 → 设备信息。这将在左侧打开一个面板,显示关于您的磁盘的信息,包括分区表类型。

在文件系统选择器中,您还可以选择创建一个没有文件系统的空分区。这在最底部,“未格式化”旁边是“清除”,清除现有文件系统并保留分区。

GParted 将创建分区和在其上创建文件系统合并为一个单一且快速的操作。这比只创建分区的 parted 更快,后者需要您单独创建文件系统。

参见

9.5 删除文件系统而不删除分区

问题

您希望删除文件系统而不删除其底层分区,因为您想要使用不同的文件系统格式化分区,或者现有的文件系统损坏,需要重新格式化然后将文件复制回去(图 9-8)。

删除文件系统

图 9-8. 删除文件系统而不删除分区

解决方案

必须先卸载文件系统。右键单击分区以打开操作菜单,然后点击卸载。完成后,点击格式化为。滚动到列表底部,点击清除。这将删除文件系统但不会删除分区。

参见

9.6 恢复已删除的分区

问题

您删除了一个分区,现在希望还原它。

解决方案

如果意外删除了一个新的空分区,请不要试图恢复它,只需重新创建。如果您的分区上有文件系统和数据,则最好立即尝试恢复。点击删除 → 尝试数据救援。

这可能需要很长时间,且无法保证成功。parted 似乎更快完成此操作;参见 Recipe 8.7。

讨论

通常更快地创建一个新分区和文件系统,然后从备份中替换文件。但首先尝试恢复也无妨。

参见

9.7 调整分区大小

问题

您希望调整分区的大小。

解决方案

使用 GParted,这只需几次点击即可完成。调整分区大小时,必须同时调整其上的文件系统大小。GParted 可以一次完成这一操作。

要扩大分区,必须在其末尾有空闲空间。Ext4、Btrfs 和 XFS 可以在线扩展。FAT16/32 必须先卸载。

始终要备份!

记住,始终要有当前的备份!

图 9-9 显示一个有足够的空闲空间可以扩展的 FAT32 文件系统。

选择要调整大小的分区

图 9-9. 选择要调整大小的分区

右键单击所选分区以打开菜单,然后点击调整/移动。这将打开一个对话框,在“新大小”字段中设置新大小,可以通过拖动滑块或输入值(以 Mibibytes 为单位)进行设置(图 9-10)。

单击调整大小/移动,然后单击绿色复选标记。扩展分区只需一两分钟,完成时会显示状态消息。

用于缩小分区的过程相同,但不需要任何结束时的空闲空间。您的新分区大小应至少比文件使用的空间大 10%。即使您不打算向此文件系统添加任何新文件,也必须保留一定量的未使用容量,因为如果文件系统完全填满,您可能无法访问它。缩小分区比扩展分区需要更长的时间。

配置新大小。

图 9-10. 配置新分区大小

讨论

Ext4 文件系统为根用户保留了一小部分空间。如果文件系统填满了,那么根用户仍然可以访问文件系统并删除文件。FAT16/32、Btrfs 和 XFS 没有预留块。

Ext4 和 Btrfs 可以在线收缩。XFS 只能扩展,不能收缩。在调整大小之前卸载它们是更安全的。

参见

9.8 移动分区

问题

您在分区之间有一些空闲空间,例如在 /dev/sda1/dev/sda2 之间。您希望将 /dev/sda2 移入空闲空间中,以便它们之间没有间隙。或者,您希望扩展 /dev/sda1,但其后没有空闲空间,因此您必须移动 /dev/sda2 以腾出空间。

解决方案

右键单击要移动的分区以打开操作菜单,然后单击调整大小/移动(图 9-11)。

选择要移动的分区

图 9-11. 选择分区

在调整大小/移动对话框中,您可以向左拖动滑块,或在“前置空闲空间(MiB)”字段中输入 0。然后单击调整大小/移动(图 9-12)。

移动分区

图 9-12. 移动分区

这将需要一些时间,取决于分区上有多少数据,可能需要几个小时。

讨论

移动分区比调整分区更复杂。调整分区时,仅移动其端点,但移动分区还需要更改其起始点,这对操作系统而言是一个重大变化。GParted 通常可以可靠地处理此操作,但是存在风险,因此始终要有良好的备份。

参见

9.9 复制分区

问题

您想克隆分区或几个分区,作为备份或将数据移动到新硬盘。

解决方案

使用 GParted 的复制命令。例如,您希望将 /dev/sdb2 复制到连接到系统的 USB 硬盘驱动器中。将其复制到与要复制的分区大小相等或更大的空闲空间。

右键单击要复制的分区(参见 图 9-13)。如果已挂载,请先卸载,然后点击复制。

复制分区

图 9-13. 复制分区

切换到要复制到的磁盘,并点击粘贴。这将打开配置对话框,提供增加大小和更改新分区位置的选项(参见 图 9-14)。当设置满意后,点击粘贴。

最后一步是点击绿色复选标记开始复制。如果改变主意,点击撤销。复制操作将根据需要复制的数据量而耗费一些时间。

新分区的设置

图 9-14. 新分区的设置

讨论

复制的分区必须放入大小相等或更大的新分区中。将分区复制到空闲空间可以省去创建目标分区的麻烦。

根据我的经验,复制分区的实用性有限。分区和文件系统的 UUID 保持不变,因此您无法在与原始系统相同的系统上使用复制的分区而不更改 UUID。 (您可以在 GParted 的右键操作菜单中更改 UUID。)如果更改 /etc/fstab 中列出的文件系统的 UUID,则必须更新它们的条目。我认为,在大多数情况下,最好创建新的分区和文件系统,然后将文件复制到其中。

参见

9.10 使用 GParted 管理文件系统

问题

您需要一个用于创建新文件系统的良好图形工具。

解决方案

使用 GParted 管理分区和文件系统。找到要格式化为新文件系统的分区,右键单击,选择要使用的文件系统(参见 图 9-15)。

GParted 创建文件系统

图 9-15. GParted 显示文件系统类型

点击工具栏中的绿色复选标记来创建新文件系统。创建新文件系统会销毁现有文件系统上的所有内容,因此请确保您操作的位置正确。

讨论

GParted 是任何类别中最好的图形应用程序之一。它是一款良好组织的前端工具,用于管理分区和文件系统,使复杂的任务变得简单和快速。

GParted 显示挂载和未挂载卷的文件系统类型,一次显示一个磁盘(参见 图 9-16)。点击右上角的下拉菜单可以查看其他磁盘。

GParted 显示文件系统类型

图 9-16. GParted 显示文件系统类型

第十章:获取计算机硬件的详细信息

Linux 自带了几个好用的工具,用于获取计算机中各个硬件组件的详细信息。您可以坐在计算机旁,几分钟内就能了解其组件及其规格,而无需打开机箱。

这些实用程序用于提供技术支持的详细信息,查找设备的正确驱动程序以及了解它是否完全在 Linux 中受支持。您不能指望制造商及时提供其产品的准确信息。例如,他们经常更改芯片组而不更改型号号码,这可能会将在 Linux 上正常工作的设备变成在 Linux 上不起作用的设备。幸运的是,在现代这些时代,Linux 支持要比过去少得多的麻烦。

理想情况下,您还应该有您的计算机文档,或至少是主板手册。主板手册通常充满了照片,图表和有用的信息,您应该能够在线找到它们。

在本章中,您将了解 lshw(列出硬件)、lspci(列出 PCI)、hwinfo(硬件信息)、lsusb(列出 USB)、lscpu(列出 CPU)和 lsblk(列出块设备)命令。

lshwhwinfo 提供了最完整的信息。

lshw 报告内存配置,固件版本,主板配置,CPU 版本和速度,缓存配置,总线速度,硬件路径,附加设备,分区和文件系统。

hwinfo 报告计算机显示器信息,RAID 数组,内存配置,CPU 信息,固件,主板配置,缓存,总线速度,附加设备,分区和文件系统。

lsusb 探测 USB 总线及其连接的设备。

lspci 探测 PCI 总线及其连接的设备。

lsblk 列出物理驱动器,分区和文件系统。

lscpu 列出有关您的 CPU 的信息。

10.1 使用 lshw 收集硬件信息

问题

您想要系统上硬件的清单以及有关每个项目的详细信息。

解决方案

尝试使用没有选项的 lshw(硬件列表)命令,并将输出存储在文本文件中:

$ sudo lshw | tee hardware.txt
duchess
    description: Laptop
    product: Latitude E7240 (05CA)
    vendor: Dell Inc.
    version: 00
    serial: 456ABC1
    width: 64 bits
[...]

您将获得数百行输出,其中包括固件,驱动程序,功能,序列号,版本号和总线信息。 lshw 不会探测通过无线网络接口连接的任何设备,例如无线打印机或通过蓝牙连接的智能手机,但它会报告无线和蓝牙接口。

您可能更喜欢以硬件路径树视图的摘要形式:

$ sudo lshw -short
H/W path         Device           Class          Description
============================================================
                                  system         To Be Filled By O.E.M.
/0                                bus            H97M Pro4
/0/0                              memory         64KiB BIOS
/0/b                              memory         16GiB System Memory
/0/b/0                            memory         DIMM [empty]
/0/b/1                            memory         8GiB DIMM DDR3 Synchronous
1333
MHz (0.8 ns)
[...]
/0/100/14/0/5                     bus            USB3.0 Hub
/0/100/14/0/5/1                   generic        SAMSUNG_Android
/0/100/14/0/5/2                   printer        MFC-J5945DW
/0/100/14/0/5/4  wlx9cefd5fe8f20  network        802.11 n WLAN
/0/100/14/0/b                     input          USB Optical Mouse
/0/100/14/0/c                     input          QuickFire Rapid keyboard
[...]

或者尝试摘要总线视图,而不是硬件路径视图:

$ sudo lshw -businfo
Bus info          Device           Class          Description
=============================================================
[...]
cpu@0                              processor      Intel(R) Core(TM) i7-4770K
CPU
@ 3.50GHz
usb@3:5.4         wlx9cefd5fe8f20  network        802.11 n WLAN
usb@3:b                            input          USB Optical Mouse
usb@3:c                            input          QuickFire Rapid keyboard
pci@0000:00:19.0  enp0s25          network        Ethernet Connection (2) I218-V
pci@0000:00:1a.0                   bus            9 Series Chipset Family USB
scsi@0:0.0.0      /dev/sda         disk           4TB ST4000DM000-1F21
scsi@0:0.0.0,1    /dev/sda1        volume         476MiB EXT4 volume
[...]

lshw 有一个图形界面,您可以用 sudo lshw -X 打开。这通常是一个单独的软件包,例如在 Ubuntu 上是 lshw-gtk,在 openSUSE 和 Fedora 上是 lshw-gui

讨论

lshw 将大量信息打包到其输出中。访问 Hardware Lister (lshw) 了解所有内容的含义。

lshw 无法检测到 FireWire 接口或计算机显示器。

示例中说“系统待填充”,因为它是一台自制机器。例如联想或戴尔等品牌计算机应该有品牌名称和型号。

H/W 路径列包含硬件路径,类似于文件路径。/0 是 /system/bus,表示计算机和主板。然后所有后续条目都以树形视图显示,类似于文件树。正如您在示例输出中看到的那样,/0/0 是 /system/bus/BIOS memory,/0/b 是第一个已填充的 RAM 插槽,/0/b/1 是第二个已填充的 RAM 插槽。这些路径对应于主板上的物理连接点,通常被称为插槽,尽管大多数都已焊接到主板上,没有物理插槽可插入扩展卡。

参见

10.2 过滤 lshw 输出

问题

lshw 确实会输出大量信息,您希望限制输出到您想要查看的内容。

解决方案

运行 sudo lshw -shortsudo lshw -businfo 查看设备类别列表,然后命名一个或多个您想要查看的设备类别:

$ sudo lshw -short -class bus -class cpu

删除 -short 选项以查看详细信息。

将长输出格式化为 HTML、XML 或 JSON,并将其存储在文件中,以便您可以使用您喜爱的脚本技巧解析输出:

$ sudo lshw -html -class bus -class cpu | tee lshw.html
$ sudo lshw -xml -class printer -class display -class input | tee lshw.xml
$ sudo lshw -json -class storage | tee lshw.json

使用 -sanitize 选项移除敏感信息(例如 IP 地址和序列号),使其更安全地与技术支持共享:

$ sudo lshw -json -sanitize  -class bus -class cpu | tee lshw.json

讨论

tee 命令在屏幕上显示输出并将其存储在文本文件中。

参见

10.3 使用 hwinfo 检测硬件,包括显示器和 RAID 设备

问题

您希望获取有关计算机显示器和 RAID 设备以及系统上其他设备的信息。

解决方案

hwinfo命令提供详细的硬件清单,包括系统中的监视器和 RAID 设备。以下示例探测您的显示器:

$ hwinfo --monitor
[...]
  Hardware Class: monitor
  Model: "VIEWSONIC VX2450 SERIES"
  Vendor: VSC "VIEWSONIC"
  Device: eisa 0xe226 "VX2450 SERIES"
[...]

完整输出比本示例要长得多,包括所有支持的屏幕分辨率、制造日期、同步范围、显示器类型和刷新频率。

另一个很好的功能是检测 RAID 设备。它默认不会检测到它们,因此请使用 --listmd 选项:

$ hwinfo --listmd

如果没有返回任何内容,则系统上没有 RAID 设备。如果有,它会打印大量信息。

创建硬件摘要:

$ hwinfo --short
keyboard:
  /dev/input/event4    CM Storm QuickFire Rapid keyboard
mouse:
  /dev/input/event5    CM Storm QuickFire Rapid keyboard
  /dev/input/mice      Logitech Optical Wheel Mouse
printer:
                       Brother Industries MFC-J5945DW
monitor:
                       VIEWSONIC VX2450 SERIES
graphics card:
                       Intel Xeon E3-1200 v3/4th Gen Core Processor Integrated
[...]

获取一个或多个硬件组件的详细信息:

$ hwinfo --mouse --network --cdrom

参阅 man 8 hwinfo 获取设备名称列表,或运行 hwinfo --help

$ hwinfo --help
Usage: hwinfo [OPTIONS]
Probe for hardware.
Options:
    --<HARDWARE_ITEM>
        This option can be given more than once. Probe for a particular
        HARDWARE_ITEM. Available hardware items are:
        all, arch, bios, block, bluetooth, braille, bridge, camera,
        cdrom, chipcard, cpu, disk, dsl, dvb, fingerprint, floppy,
        framebuffer, gfxcard, hub, ide, isapnp, isdn, joystick, keyboard,
        memory, mmc-ctrl, modem, monitor, mouse, netcard, network, partition,
        pci, pcmcia, pcmcia-ctrl, pppoe, printer, redasd,
        reallyall, scanner, scsi, smp, sound, storage-ctrl, sys, tape,
        tv, uml, usb, usb-ctrl, vbe, wlan, xen, zip
[...]

讨论

hwinfo 提供有用且完整的信息。例如,对于网络接口,它显示它们的 /sys 路径、驱动程序、链路状态和 MAC 地址。CD-ROM 输出包括型号名称、版本号、驱动程序、设备文件、驱动速度、功能列表以及驱动器中是否有磁盘。hwinfo 通常比制造商的产品信息提供更多信息。

参见

10.4 使用 lspci 检测 PCI 硬件

问题

你想列出连接到计算机 PCI 总线上的设备及其供应商和版本信息。

解决方案

运行 lspci(列出 PCI)命令。以下示例打印所有 PCI 设备的摘要列表:

$ lspci
00:00.0 Host bridge: Intel Corporation 4th Gen Core Processor DRAM Controller
(rev 06)
00:02.0 VGA compatible controller: Intel Corporation Xeon E3-1200 v3/4th Gen
Core Processor Integrated Graphics Controller (rev 06)
00:03.0 Audio device: Intel Corporation Xeon E3-1200 v3/4th Gen Core Processor
HD Audio Controller (rev 06)
[...]

增加详细信息以查看更多细节:

$ lspci -v
$ lspci -vv
$ lspci -vvv

当你看到“拒绝访问”消息时,尝试使用 sudo lspci 查看你错过了什么。

讨论

lspci 从 PCI 总线读取信息,包括主板上的内置组件以及插入 PCI 插槽的扩展卡。

lspci 从其硬件 ID 数据库中显示额外信息,如供应商、设备、类别和子类信息。此信息存储在文本文件中,具体位置因 Linux 发行版而异。Ubuntu 存放在 /usr/share/misc/pci.ids,Fedora 使用 /usr/share/hwdata/pci.ids,openSUSE 使用 /usr/share/pci.ids。你的 Linux 的 man 手册应该告诉你具体位置,或者搜索 pci.ids 文件(locate pci.ids)。

lspci 的维护者欢迎提交更新信息;阅读你的 pci.ids 文件获取说明。定期运行 sudo update-pciids 命令更新 PCI ID 数据库。

PCI 是外围组件互连的缩写。PCI 是一种本地硬件总线,用于计算机中各种硬件设备与 Linux 内核的通信。lspci 主要检测控制器、总线和部分个别设备,包括:

  • SATA 控制器

  • 音频控制器和设备

  • 视频控制器和设备

  • 以太网控制器

  • USB 控制器

  • 通信控制器

  • 以太网控制器

  • RAID 控制器

  • 集成的 SD/MMC 卡阅读器

  • PCI FireWire 控制器

多年来出现了几个 PCI 协议。当前标准是 PCIe,即 PCI Express,于 2003 年推出。它与所有传统 PCI 协议向后兼容,取代了 PCI、PCI-X 和 AGP。还记得 AGP,加速图形端口协议吗?AGP 显卡比 PCI 显卡快,因为 AGP 为视频处理提供了专用链路。

PCIe 与早期协议有显著区别,与 AGP 类似,每个设备都有专用链路。旧协议使用共享并行总线,速度较慢。

参见

  • man 8 lspci

  • man 8 update-pciids

10.5 理解 lspci 输出

问题

lspci 的大多数输出都是有意义的,因为它是设备规格。但您想知道每个设备行开头的数字是什么,就像这个例子:

$ lspci
[...]
00:1f.2 SATA controller: Intel Corporation 9 Series Chipset Family SATA
Controller [AHCI Mode]
[...]

解决方案

00:1f.2 是设备的 BDF 号,总线:设备.功能。总线号为 00,设备号为 1f,功能号为 2。功能号为 2 表示设备有两个功能,每个功能都有自己的 PCI 地址。

使用树状视图查看 PCI 总线与设备之间的关系:

$ lspci -tvv
-[0000:00]-+-00.0  Intel Corporation 4th Gen Core Processor DRAM Controller
           +-02.0  Intel Corporation Xeon E3-1200 v3/4th Gen Core Processor
                   Integrated Graphics Controller
           +-03.0  Intel Corporation Xeon E3-1200 v3/4th Gen Core Processor HD
                   Audio Controller
           +-14.0  Intel Corporation 9 Series Chipset Family USB xHCI Controller
           +-16.0  Intel Corporation 9 Series Chipset Family ME Interface #1
           +-19.0  Intel Corporation Ethernet Connection (2) I218-V
           +-1a.0  Intel Corporation 9 Series Chipset Family USB EHCI
                   Controller #2
           +-1b.0  Intel Corporation 9 Series Chipset Family HD Audio Controller
           +-1c.0-[01]--
           +-1c.3-[02-03]----00.0-[03]--
           +-1d.0  Intel Corporation 9 Series Chipset Family USB EHCI
                   Controller #1
           +-1f.0  Intel Corporation H97 Chipset LPC Controller
           +-1f.2  Intel Corporation 9 Series Chipset Family SATA Controller
                   [AHCI Mode]
           \-1f.3  Intel Corporation 9 Series Chipset Family SMBus Controller

大多数 PC 通常只有一个 PCI 总线,总是为 00。

讨论

在树的根部被括号括起来的零,[0000:00],标识了总线。前四个零是域号,冒号后的两个零是总线号。域是主机桥。PCI 主机桥将 PCI 控制器连接到 CPU。是 Linux 特有的术语,更常被称为段组。您也可以使用-D选项查看这一点:

$ lspci -D
0000:00:00.0 Host bridge: Intel Corporation 4th Gen Core Processor DRAM
 Controller (rev 06)
0000:00:02.0 VGA compatible controller: Intel Corporation Xeon E3-1200 v3/4th Gen
 Core Processor Integrated Graphics Controller (rev 06)
0000:00:03.0 Audio device: Intel Corporation Xeon E3-1200 v3/4th Gen Core
 Processor HD Audio Controller
[...]

在具有多个物理 CPU 的服务器上,您将看到多个主机桥,有时在单个域上有多个总线。

参见

  • man 8 lspci

10.6 过滤 lspci 输出

问题

lspci 输出了大量信息,您希望筛选出您想要看到的内容。

解决方案

使用awk命令来削减杂乱。以下示例只找到与 USB 相关的条目:

$ lspci -v | awk '/USB/,/^$/'
00:14.0 USB controller: Intel Corporation 9 Series Chipset Family USB xHCI
Controller (prog-if 30 [XHCI])
        Subsystem: ASRock Incorporation 9 Series Chipset Family USB xHCI
Controller
        Flags: bus master, medium devsel, latency 0, IRQ 26
        Memory at efc20000 (64-bit, non-prefetchable) [size=64K]
        Capabilities: <access denied>
        Kernel driver in use: xhci_hcd

00:1a.0 USB controller: Intel Corporation 9 Series Chipset Family USB EHCI
Controller #2 (prog-if 20 [EHCI])
        Subsystem: ASRock Incorporation 9 Series Chipset Family USB EHCI
Controller
        Flags: bus master, medium devsel, latency 0, IRQ 16
        Memory at efc3b000 (32-bit, non-prefetchable) [size=1K]
        Capabilities: <access denied>
        Kernel driver in use: ehci-pci

您必须使用从lspci输出中显示的类(音频、以太网、USB 等),并注意大小写,因为使用awk进行大小写不敏感搜索比较复杂。此示例显示音频控制器和设备:

$ lspci -v | awk '/Audio/,/^$/'
00:03.0 Audio device: Intel Corporation Xeon E3-1200 v3/4th Gen Core Processor
HD Audio Controller (rev 06)
        Subsystem: ASRock Incorporation Xeon E3-1200 v3/4th Gen Core Processor
HD Audio Controller
        Flags: bus master, fast devsel, latency 0, IRQ 31
        Memory at efc34000 (64-bit, non-prefetchable) [size=16K]
        Capabilities: <access denied>
        Kernel driver in use: snd_hda_intel
        Kernel modules: snd_hda_intel

00:1b.0 Audio device: Intel Corporation 9 Series Chipset Family HD Audio
Controller
        Subsystem: ASRock Incorporation 9 Series Chipset Family HD Audio
Controller
        Flags: bus master, fast devsel, latency 0, IRQ 32
        Memory at efc30000 (64-bit, non-prefetchable) [size=16K]
        Capabilities: <access denied>
        Kernel driver in use: snd_hda_intel
        Kernel modules: snd_hda_intel

根据需要调整详细程度。

您还可以根据供应商、设备或类号选择项目。使用-nn选项找到这些数字。在这个例子中,0300(用方括号括起来)是类号,8086 是供应商号,0412 是设备号:

$ lspci -nn
[....]
00:02.0 VGA compatible controller [0300]: Intel Corporation
Xeon E3-1200 v3/4th Gen Core Processor Integrated Graphics Controller
[8086:0412] (rev 06)
[...]

以下示例分别通过类、供应商和设备进行过滤:

$ lspci -d ::0604
00:1c.0 PCI bridge: Intel Corporation 9 Series Chipset Family PCI Express Root
Port 1 (rev d0)
00:1c.3 PCI bridge: Intel Corporation 82801 PCI Bridge (rev d0)
02:00.0 PCI bridge: ASMedia Technology Inc. ASM1083/1085 PCIe to PCI Bridge (rev
03)

$ lspci -d 8086::
00:00.0 Host bridge: Intel Corporation 4th Gen Core Processor DRAM Controller
(rev 06)
00:02.0 VGA compatible controller: Intel Corporation Xeon E3-1200 v3/4th Gen
Core Processor Integrated Graphics Controller (rev 06)
00:03.0 Audio device: Intel Corporation Xeon E3-1200 v3/4th Gen Core Processor
HD Audio Controller (rev 06)
[...]

$ lspci -d :0412:
00:02.0 VGA compatible controller: Intel Corporation Xeon E3-1200 v3/4th Gen
Core Processor Integrated Graphics Controller (rev 06)

查找这些数字的另一种方法是在PCI ID 仓库中查找它们。

讨论

awk 是从命令输出或文档中提取特定文本字符串的神奇工具。插入符号^是一个正则表达式锚点,匹配字符串的开头,而\(*匹配结尾,所以在这个例子中,*/^\)/查找换行符,文本块开头和结尾的空白。这是从具有在段落之间有空格的源中提取文本块的一个很棒的技巧。

参见

10.7 使用 lspci 识别内核模块

问题

您想知道您的 PCI 设备正在使用哪些内核模块,以及系统上有哪些可用。

解决方案

使用-k选项。以下示例仅查询以太网控制器:

$ lspci -kd ::0200
00:19.0 Ethernet controller: Intel Corporation Ethernet Connection (2) I218-V
        Subsystem: ASRock Incorporation Ethernet Connection (2) I218-V
        Kernel driver in use: e1000e
        Kernel modules: e1000e

您也可以像这个例子一样使用awk来查找您的显卡控制器:

$ lspci -vmmk| awk '/VGA/,/^$/'
Class:  VGA compatible controller
Vendor: Intel Corporation
Device: Xeon E3-1200 v3/4th Gen Core Processor Integrated Graphics Controller
SVendor:        ASRock Incorporation
SDevice:        Xeon E3-1200 v3/4th Gen Core Processor Integrated Graphics
Controller
Rev:    06
Driver: i915
Module: i915

讨论

-k 选项显示正在使用的内核模块以及每个设备的所有可用内核模块。通常,正在使用的和可用的条目是相同的,但有时会有多个可用模块。

使用 awk 时记得添加一些详细信息,否则可能看不到所需的信息。参见 第 10.6 节 的讨论了解 awk 的选项。

参见

  • man 1 awk

  • man 8 lspci

10.8 使用 lsusb 列出 USB 设备

问题

您需要一个快速简便的工具来列出系统上的 USB 设备。

解决方案

lsusb 列出 USB 总线和连接的 USB 设备,包括鼠标、键盘、USB 闪存驱动器、打印机、智能手机和其他连接的外设。以下两个示例展示了相同设备的两种不同视图。

不带任何选项运行 lsusb 可以查看系统上 USB 设备的摘要信息。在下一个示例中,连接了三个外部 USB 设备:键盘、鼠标和无线网络接口:

$ lsusb
[...]
Bus 003 Device 011: ID 148f:5372 Ralink Technology, Corp. RT5372 Wireless Adapter
Bus 003 Device 002: ID 0bda:5401 Realtek Semiconductor Corp. RTL 8153 USB 3.0
 hub with gigabit ethernet
Bus 003 Device 006: ID 046d:c018 Logitech, Inc. Optical Wheel Mouse
Bus 003 Device 005: ID 2516:0004 Cooler Master Co., Ltd. Storm QuickFire Rapid
 Mechanical Keyboard
[...]

此示例显示了相同内容,以 USB 总线层次结构格式呈现更详细信息,包括内核驱动程序、设备代码和供应商编号以及端口号:

$ lsusb -tv
[...]
/:  Bus 03.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/14p, 480M
    ID 1d6b:0002 Linux Foundation 2.0 root hub
    |__ Port 3: Dev 2, If 0, Class=Hub, Driver=hub/4p, 480M
        ID 0bda:5401 Realtek Semiconductor Corp. RTL 8153 USB 3.0 hub with
        gigabit ethernet
    |__ Port 7: Dev 11, If 0, Class=Vendor Specific Class, Driver=rt2800usb, 480M
        ID 148f:5372 Ralink Technology, Corp. RT5372 Wireless Adapter
    |__ Port 11: Dev 5, If 0, Class=Human Interface Device, Driver=usbhid, 1.5M
        ID 2516:0004 Cooler Master Co., Ltd. Storm QuickFire Rapid Mechanical
        Keyboard
    |__ Port 12: Dev 6, If 0, Class=Human Interface Device, Driver=usbhid, 1.5M
        ID 046d:c018 Logitech, Inc. Optical Wheel Mouse
[...]

下面的示例展示了插入带有蓝牙接口和连接三星智能手机的外部 USB 集线器时的情况:

$ lsusb
[...]
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 003 Device 012: ID 04e8:6860 Samsung Electronics Co., Ltd Galaxy series,
 misc. (MTP mode)
Bus 003 Device 013: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle
 (HCI mode)
Bus 003 Device 002: ID 0bda:5401 Realtek Semiconductor Corp. RTL 8153 USB 3.0
 hub with gigabit ethernet
[...]

$ lsusb -tv
[...]
/:  Bus 03.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/14p, 480M
    ID 1d6b:0002 Linux Foundation 2.0 root hub
    |__ Port 3: Dev 2, If 0, Class=Hub, Driver=hub/4p, 480M
        ID 0bda:5401 Realtek Semiconductor Corp. RTL 8153 USB 3.0 hub with
        gigabit ethernet
        |__ Port 4: Dev 12, If 0, Class=Imaging, Driver=, 480M
            ID 04e8:6860 Samsung Electronics Co., Ltd Galaxy series, misc. (MTP
            mode)
        |__ Port 2: Dev 13, If 0, Class=Wireless, Driver=btusb, 12M
            ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)
        |__ Port 2: Dev 13, If 1, Class=Wireless, Driver=btusb, 12M
            ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)
[...]

讨论

总线和端口号始终相同。每次插入设备时,设备号都会更改。

例如,ID 号码 0a12:0001 是供应商和设备代码。制造商必须向 https://usb.org 申请新代码。您可以在 linux-usb.org 找到当前 USB ID 列表并贡献更新信息。

类代码也由 https://usb.org 管理;参见 USB 类代码。我觉得有趣的是,Dev 57,即三星安卓手机,被归类为影像设备。然而,这是有道理的,因为大多数 Linux 发行版使用媒体传输协议(MTP)从安卓手机传输文件。

本节示例来自具有 USB 2.0 和 USB 3.1 端口的 PC。lsusb 输出显示设备正在使用的协商速度,因此当您看到类似 usbhid, 1.5M 而不是 480M5000M 时,那是正常的,因为那是键盘,不需要 USB 连接的全部速度。对于存储设备(如 USB 闪存驱动器和外部硬盘),您应该看到更高的速度。

参见

10.9 使用 lsblk 列出分区和硬盘

问题

您需要一种快速的方法来列出所有连接的存储驱动器及其分区。

解决方案

使用 lsblk (列出块设备)命令。不带任何选项运行它,以生成计算机上所有块设备的列表:

$ lsblk
NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
sda      8:0    0   3.7T  0 disk
├─sda1   8:1    0   476M  0 part /boot
├─sda2   8:2    0  55.9G  0 part /
├─sda3   8:3    0   1.8T  0 part /home
└─sda4   8:4    0   7.5G  0 part [SWAP]
sdb      8:16   0   1.8T  0 disk
├─sdb1   8:17   0   102M  0 part
├─sdb2   8:18   0   6.5G  0 part
├─sdb3   8:19   0   1.1G  0 part [SWAP]
└─sdb4   8:20   0   1.8T  0 part
sdc      8:32   0   3.7T  0 disk
├─sdc1   8:33   0   128M  0 part
├─sdc2   8:34   0 439.7G  0 part
└─sdc3   8:35   0   3.2T  0 part
sdd      8:48   1   3.8G  0 disk
└─sdd1   8:49   1   3.8G  0 part
sr0     11:0    1 159.3M  0 rom

显示所选设备上的文件系统标签和 UUID:

$ lsblk -f /dev/sdc
NAME   FSTYPE LABEL                 UUID                MOUNTPOINT
sdc
├─sdc1
├─sdc2 ntfs   Seagate Backup Plus   2E203F82203F5057
└─sdc3 ext4   backup                0451d428-9716-4cdd  /media/max/backup

仅列出 SCSI 设备及其类型:

$ lsblk -S
NAME HCTL       TYPE VENDOR   MODEL             REV TRAN
sda  0:0:0:0    disk ATA      ST4000DM000-1F21 CC54 sata
sdb  2:0:0:0    disk ATA      SAMSUNG HD204UI  0001 sata
sdc  6:0:0:0    disk Seagate  BUP SL           0304 usb
sr0  4:0:0:0    rom  ATAPI    iHAS424   B      GL1B sata

讨论

sdasdb是 SATA 硬盘,sdc是 USB 闪存驱动器。在 Linux 上,如 SATA 硬盘和闪存介质等大容量存储设备使用 SCSI 驱动器。sr0romATAPI标识光盘/DVD 播放器。

定义术语块设备而不引发争论,相当困难,因为它是一个编程术语,不易转换为简明的用户界面概念。依我看来,将块设备视为大容量存储设备及其分区最为实用。

MAJ:MIN是主设备号和次设备号。主设备号标识类别,例如 8 用于sd设备,次设备号按顺序标识每个设备。(运行lsblk -l以树形结构查看。)

RM显示是否为可移动驱动器,1 表示可移动驱动器。

SIZE是块设备的大小。

RO = 0表示设备不是只读的,1 表示只读。sr0,即 CD/DVD 驱动器,是可读写驱动器,但lsblk无法告诉您sr0中的光盘是否可写。

TYPE标识磁盘类型。

MOUNTPOINT显示路径,如果设备已挂载。

参见

  • man 8 lsblk

10.10 获取 CPU 信息

问题

您想知道系统上有哪些 CPU 及其规格。

解决方案

使用无选项运行lscpu(列出 CPU)命令:

$ lscpu
Architecture:        x86_64
CPU op-mode(s):      32-bit, 64-bit
Byte Order:          Little Endian
CPU(s):              8
On-line CPU(s) list: 0-7
Thread(s) per core:  2
Core(s) per socket:  4
Socket(s):           1
Vendor ID:           GenuineIntel
CPU family:          6
Model:               60
Model name:          Intel(R) Core(TM) i7-4770K CPU @ 3.50GHz
[...]
L1d cache:           128 KiB
L1i cache:           128 KiB
L2 cache:            1 MiB
L3 cache:            8 MiB
[...]

这会输出大量信息;您还会看到许多标志,列出功能,并列出 L 缓存信息。

讨论

CPU 缓存有三种类型:L1、L2 和 L3。这些是 CPU 上的小型内存缓存。它们非常快,比系统 RAM 快许多倍,并且存储 CPU 下次操作最可能需要的数据。L1 最快且最昂贵,通常最小。L2 其次,成本较低,通常比 L1 大。L3 最慢且成本最低,通常最大。

在上述示例中的 CPU 有四个缓存。使用-C选项查看更详细的缓存信息:

$ lscpu -C
NAME ONE-SIZE ALL-SIZE WAYS TYPE        LEVEL
L1d       32K     128K    8 Data            1
L1i       32K     128K    8 Instruction     1
L2       256K       1M    8 Unified         2
L3         8M       8M   16 Unified         3

这显示了四个缓存,这些缓存由四个物理 CPU 核心共享。L1i 缓存存储 CPU 指令,L1d 缓存存储数据。L2 和 L3 存储数据。

CPU 核心数量有点令人困惑。在这个示例中,CPU(s): 8并不意味着有 8 个物理核心;相反,这是 Linux 内核看到的核心数。以下几行讲述了全貌:

Thread(s) per core:  2
Core(s) per socket:  4
Socket(s):           1

这是一个单处理器,有四个物理核心和每个核心两个线程,总共八个逻辑 CPU。

参见

  • man 1 lscpu

10.11 识别您的硬件架构

问题

您不确定机器的硬件架构是什么;可能是 x86-64 或 ARM,您需要确定其具体类型。

解决方案

使用uname命令。此示例在 x86-64 机器上运行:

$ uname -m
x86_64

以下列表包含您可能看到的一些常见结果:

  • arm

  • aarch64

  • armv7* (arm7 及以下为 32 位)

  • armv8* (arm8 及以上为 64 位)

  • ia64

  • ppc

  • ppc64

  • s390x

  • sparc

  • sparc64

  • i386

  • i686

  • x86_64

如果设备未运行 Linux,请尝试使用 SystemRescue USB 启动盘引导,然后运行uname -m

你可以在 Chromebook 上安装 Linux。Chromebook 使用 Intel 和 ARM 处理器。查看你的设备信息的一种方法是打开网页浏览器到chrome://system。这会显示所有系统信息,可能比你想要的还要多。

更友好的工具是Cog 系统信息查看器,它可以在 Chromebook 上显示硬件和网络信息。

讨论

Linux 支持比任何其他操作系统更多的硬件架构,从微小的嵌入式系统和 SoC(系统芯片)到大型机和超级计算机,应有尽有。无论你拥有多么冷门的计算硬件,都很有可能有某种 Linux 版本可以运行在上面。

参见

  • man 1 uname

第十一章:创建和管理文件系统

Linux 支持许多文件系统,比任何其他操作系统都多。文件系统对计算至关重要,执行了大量的工作。计算机文件系统存储、组织和保护我们的数据,并且由于常年被广泛使用而承受着持续的压力。作为 Linux 用户,我们有幸可以从许多一流的文件系统中进行选择。

本章将介绍用于创建和管理以下通用文件系统的命令行工具,这些文件系统在 Linux 上得到完全支持和良好维护:

  • Ext4,扩展文件系统

  • XFS,X 文件系统;X 只代表 X

  • Btrfs,b 树文件系统,发音为 Butter FS

  • FAT16/32,文件分配表 16 位和 32 位

  • exFAT,扩展文件分配表,Microsoft 最新的 64 位文件系统

本章不包括 Microsoft 的 NTFS 或 Apple 的 HFS/HFS+/APFS。Linux 对 Microsoft 的 NTFS 有很好的支持,包括读写。要尝试,请搜索ntfs-3g(NTFS 第三代)软件包。

对于 Apple 的 HFS/HFS+/APFS 的支持不可靠。要试用,请搜索名称中带有hfsapfs的软件包,并确保描述中指定它们是为 Apple 文件系统而设计的。

还有许多特殊用途的文件系统,例如用于 CompactFlash 设备的 UBIFS 和 JFFS2;压缩文件系统 SquashFS,用于分布式计算的 HDFS,CephFS 和 GlusterFS;用于网络文件共享的 NFS 等等。这些内容本身就可以轻松填满一本大书,不在此列出。它们可供自由试用和学习。

文件系统概述

在您可以使用任何存储设备(例如硬盘、USB 闪存驱动器或 SD 卡)之前,它必须分区并格式化为文件系统。每个文件系统必须有自己的磁盘分区。一个分区可以覆盖整个磁盘,或者一个磁盘可以分成多个分区。每个分区就像一个独立的磁盘,每个分区可以有不同的文件系统。

在文件系统可以访问之前,必须将其挂载或附加到正在运行的文件系统上。文件系统需要一个挂载点,这是为该文件系统创建的目录。这个目录可以放在任何地方,尽管传统的位置是/mnt/media

每个挂载点只能挂载一个文件系统。如果挂载第二个文件系统,则会覆盖第一个文件系统。

一个文件系统可以在系统启动时自动挂载,当您连接可移动媒体时动态挂载,通过命令行手动挂载,或者通过桌面上的按钮或文件管理器点击挂载。大多数 Linux 发行版都很好地处理可移动媒体。插入您的 USB 设备或光盘,Linux 会负责设置挂载点并自动挂载,或者设置您点击按钮进行挂载(参见图 11-1)。

Xfce 桌面上的可移动媒体按钮

图 11-1。Xfce 桌面上的可移动媒体按钮

Ext4、XFS、Btrfs 和 exFAT 是64 位文件系统。这意味着它们支持 64 位块寻址空间,可以支持比 32 位和 16 位文件系统更大的文件和文件系统大小。64 位计算至少自上世纪 70 年代以来就存在于超级计算机上,后来又出现在高端商用机器如 IBM Power 和 Sun Microsystems UltraSPARC 上。

我的第一台 Windows 3.1/DOS 个人电脑是在上世纪 90 年代中期,它是一台 16 位系统。Windows 95 以成为第一个 32 位消费者操作系统而自豪。第一个面向 x86 个人电脑的 64 位文件系统开始出现在 Linux 中,大约是在 2001 年。请参见Ext4 高级设计,在 Linux 内核文档中查看漂亮的表格,详细比较 32 位和 64 位文件系统。

64 位文件系统向后兼容 32 位应用程序。这些年来,你不太可能遇到 32 位应用程序,但如果遇到的话,它们可以在现代 Linux 上运行,前提是它提供了必要的包来设置 32 位环境。

Ext4 和 XFS 是日志文件系统,而 Btrfs 是写时复制(CoW)文件系统。日志和 CoW 可以使你的文件系统在断电或系统崩溃后保持一致的状态。文件系统是复杂且繁忙的,中断会影响不仅仅是你正在操作的文件。中断会导致大量带有未完成任务的文件,而在旧时代,这可能意味着可能会丢失整个文件系统。

Ext4 是 Linux 上最广泛使用的文件系统,在大多数 Linux 发行版上都是默认的。它并不令人兴奋。它经过充分测试、有良好的支持,并且在没有剧烈波动的情况下完成它的工作。Ext4 日志记录更改,直到它们被写入磁盘,从而在中断事件中提供数据丢失保护。Ext4 文件系统可以调整大小,无论是变大还是变小。

XFS 最初是一个高性能 Unix 64 位文件系统,2001 年移植到 Linux。XFS 是一个快速、高效、可靠的日志文件系统,适用于从小型个人机器到多磁盘数据中心设置的系统。XFS 可以调整大小变大,但不能调整大小变小。

Btrfs 是一个先进的写时复制(CoW)文件系统,包含一系列在本章其他文件系统中不存在的功能,包括快照;RAID 0、1 和 10;以及子卷。子卷非常灵活,因为它们允许在单个分区上创建多个文件系统根。CoW 是一种通过高效方式创建快照的方式,其中每个快照只包含与前一个快照的更改。当遇到问题时,你可以回滚到一个较旧的已知良好的快照。Btrfs 可以调整大小,无论是变小还是变大。

FAT16/32是微软老旧的 16 位和 32 位文件系统。FAT32 是最通用的文件系统,支持 Microsoft Windows、Apple 的 macOS、Linux、Unix 和 DOS 操作系统。在便携媒体上使用 FAT32 进行最简单的文件共享。它有一个限制,某些用途可能会成为瓶颈,即文件大小最大为 4 GB(在具有 4K 块的介质上)。

exFAT是微软最新的 64 位文件系统,是 FAT32 的一个很好的升级。exFAT 是 USB 闪存和 SD 媒体的快速轻量级文件系统,支持比 FAT32 更大的文件和卷大小。维基百科引用了 16 EiB 的最大文件大小和 128 PiB 的最大卷大小。它没有日志或写时复制(CoW)功能。

exFAT 对 Linux 用户来说很麻烦,因为它是一种专利的专有文件系统,直到 2020 年才作为本地文件系统出现在 Linux 上。只有当你想要读取和复制使用 exFAT 格式化的 USB 闪存驱动器或 SDXC 卡到你的 Linux 电脑时,你才需要担心 Linux 的兼容性。例如,你想要在你的数码相机或音频录制设备上使用 exFAT 格式化的 SDXC 卡。

要在 Linux 中使用 exFAT,你有两个选择。一个是使用exfatprogsexfat-fuseexfat-utils包,这些在大多数发行版上都可以找到。exFAT FUSE 是在美国之外开发和维护的,因此不受美国专利法的影响。exFAT FUSE 利用了用户空间文件系统(FUSE),允许非特权用户在用户空间运行文件系统。它不如完全集成到内核中的文件系统效率高,但它可以读写 exFAT 文件。一些勇敢的人尝试在共享分区中使用 exFAT FUSE 与 Windows 和 macOS 共享文件。理论上这应该可以工作,尽管有时与特定的 Windows 或 macOS 版本实现 exFAT 的程度有关可能会出现一些小问题。

另一个选择是稍等片刻以获得本地支持。微软在 2006 年发布了 exFAT,并主要授权给制造嵌入式系统和嵌入式媒体的公司。但时过境迁。微软已成为开源贡献者,并成为开放发明网络(OIN)的成员。微软在 2019 年发布了 exFAT 规范。通过发布规范,绕过了现有 exFAT 代码的许可问题,Linux 内核开发人员迅速编写了新代码。这种全新闪亮的代码在 Linux 内核 5.7 中实现了对 exFAT 的本地支持。这应该很快出现在你喜爱的发行版中;运行uname -r查看你的内核版本。

11.1 列出支持的文件系统

问题

你需要知道你的 Linux 系统上安装了哪些文件系统。

解决方案

阅读/proc/filesystems以查看已安装的文件系统列表:

$ cat /proc/filesystems
nodev   sysfs
nodev   tmpfs
nodev   bdev
nodev   proc
nodev   cgroup
nodev   cgroup2
nodev   cpuset
nodev   devtmpfs
nodev   debugfs
nodev   tracefs
nodev   securityfs
nodev   sockfs
nodev   bpf
nodev   pipefs
nodev   ramfs
nodev   hugetlbfs
nodev   devpts
        ext3
        ext2
        ext4
nodev   autofs
nodev   mqueue
nodev   pstore
        btrfs
        vfat
        xfs
        fuseblk
nodev   fuse
nodev   fusectl
        jfs
        nilfs2

讨论

看到所有这些nodev条目了吗?这些都是只存在于内存中并且未连接到像/dev/sda1这样的物理设备的虚拟文件系统。Systemd 管理所有这些虚拟文件系统。

其他文件系统,如 Ext4、XFS 等,是我们在存储设备上用来存储、组织和保护数据的文件系统。

参见

11.2 辨识现有文件系统

问题

你不知道系统上已有哪些文件系统,或者可移动存储磁盘上有哪些,需要知道如何列出它们。

解决方案

使用 lsblk 命令。你可以仅列出设备名称和文件系统,使用 NAMEFSTYPE 选项:

$ lsblk -o NAME,FSTYPE
NAME   FSTYPE
sda
├─sda1 vfat
├─sda2 btrfs
├─sda3 xfs
└─sda4 swap
sdb
├─sdb1 ext2
├─sdb2 ext4
├─sdb3 swap
└─sdb4 LVM2_member
sdc
└─sdc1 vfat
sr0

查询单个磁盘:

$ lsblk -o NAME,FSTYPE /dev/sdb
├─sdb1 ext2
├─sdb2 ext4
├─sdb3 swap
└─sdb4 LVM2_member

或单个分区:

$ lsblk -o NAME,FSTYPE /dev/sda1
NAME FSTYPE
sda1 vfat

这是我喜欢的 lsblk 咒语。它显示所有设备名称、文件系统类型、文件系统大小、使用百分比、标签和挂载点:

$ lsblk -o NAME,FSTYPE,LABEL,FSSIZE,FSUSE%,MOUNTPOINT
NAME   FSTYPE   LABEL     FSSIZE FSUSE% MOUNTPOINT
loop0  squashfs           646.5M   100% /run/archiso/sfs/airootfs
sda
├─sda1
└─sda2 ntfs
sdb
├─sdb1 vfat     BOOT
├─sdb2 btrfs    root
├─sdb3 xfs      home
└─sdb4 swap
sdc    iso9660  RESCUE800
└─sdc1 iso9660  RESCUE800   708M   100% /run/archiso/bootmnt
sr0

讨论

运行 lsblk --help 可以看到列出的信息,如 PATH、LABEL、UUID、HOTPLUG、MODEL、SERIAL 和 SIZE。

在某些发行版上,可能需要 root 权限来查看文件系统类型、UUID 和标签。

lsblk 总是打印 vfat 作为 FAT16 和 FAT32 文件系统。使用 GParted 或 parted 查看文件系统是 FAT16 还是 FAT32。

vfat 是虚拟 FAT,内核的 FAT16 和 FAT32 文件系统驱动程序。

参见

11.3 调整文件系统大小

问题

你想要扩大或缩小文件系统的大小。

解决方案

每种文件系统都有其自己的调整大小命令。查看配方 8.8、8.9 和 9.7 了解调整文件系统大小的方法。

讨论

文件系统的分区也必须调整大小以匹配。GParted 在一个操作中完成此操作(参见 配方 9.7)。

配方 8.8 和 8.9 使用 parted 和文件系统工具来分两步调整文件系统及其分区大小。

参见

  • 配方 8.8

  • 配方 8.9

  • 配方 9.7

  • man 8 resize2fs

  • man 8 parted

  • man 8 xfs_growfs

  • man 8 btrfs

  • man 8 fsck.vfat

11.4 删除文件系统

问题

你需要删除一个文件系统及其底层分区。

解决方案

要删除文件系统及其分区,使用 parted。在此示例中,/dev/sdb1 被删除。确认要删除哪个分区和文件系统,然后确保文件系统已卸载。在示例中,挂载点是 /media/duchess/stuff

$ lsblk -f
sda
├─sdb1 ext4   /media/duchess/stuff
[...]
$ umount /media/duchess/stuff

然后使用 parted 删除分区:

$ sudo parted /dev/sdb
GNU Parted 3.2
Using /dev/sdb
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) print 
Model: ATA SAMSUNG HD204UI (scsi)
Disk /dev/sdb: 2000GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags:

Number  Start   End     Size    File system  Name  Flags
 1      1049kB  1656GB  1656GB  ext4          stor-1
 1      1656GB  2656GB  1000GB  ext4          stor-2
(parted) rm 1

如果你偏爱图形工具,可以使用 GParted(第九章)。

讨论

是的,命令是umount,而不是unmountumount来自古老的 Unix 时代,那时标识符的长度限制为六个字符。

删除分区中的所有文件并不会删除文件系统。文件系统结构仍然存在。

参见

  • man 1 dd

11.5 使用新的文件系统

问题

您刚刚创建了一个漂亮的新文件系统,并且需要挂载它。

解决方案

创建完新文件系统后,您必须创建一个挂载点,并可选择配置自动挂载。如本章介绍的那样,新文件系统必须挂载或附加到正在运行的文件系统才能使用。

Ext4、XFS 和 Btrfs 都有访问控制。如果您希望这些文件系统上的文件对除 root 用户之外的任何人可用,则必须调整所有权和权限。FAT16/32 和 exFAT 没有访问控制,对任何人都是开放的。

首先挂载您的新文件系统。创建一个挂载点,即一个目录,然后像这个疯狂麦克斯的示例一样挂载文件系统:

$ sudo mkdir -p */mnt/madmax/newfs*
$ sudo mount */dev/sdb1 /mnt/madmax/newfs* 

以下示例将新文件系统的所有权设置为疯狂麦克斯,读写执行权限,组和全局只读权限:

$ sudo chown -R *madmax:madmax /mnt/madmax/newfs*
$ sudo chmod -R 0755 */mnt/madmax/newfs*

现在,疯狂麦克斯可以访问新的文件系统。这种挂载仅持续到下次系统重启;请参阅配方 11.6 以了解如何配置自动文件系统挂载。

仅一个挂载点对应一个文件系统

每个文件系统都需要有自己独特的挂载点;您不能在单个挂载点上放置多个文件系统。

讨论

请参阅第六章以获取有关管理所有权和权限的详细配方。

包含挂载点的传统目录为/mnt/media/mnt传统上用于静态挂载(在/etc/fstab中配置),/media用于自动挂载可移动介质。您可以在任何地方创建自己的挂载点。使用传统目录的好处是在有限数量的可预测位置拥有您的挂载点。

一个共享目录,为多个用户提供挂载点,可能如下所示,每个用户有一个目录:

$ tree /shared
/shared
├── duchess
├── madmax
└── stash

然后,每个文件系统都需要在用户子目录中拥有自己的挂载点。例如,疯狂麦克斯在madmax1madmax2上分别挂载了两个文件系统:

$ tree -L 2 /mnt
/mnt
├── duchess
├── madmax
│   ├── madmax1
│   └── madmax2
└── stash

挂载点可以有任何您想要的名称。例如,疯狂麦克斯的挂载点可以是fs1fs2,或者fredethel,或者max1max2,任何有助于您记住它们的名称。

使用stat命令查看文件系统的权限,例如疯狂麦克斯的新文件系统的示例:

$ stat /shared/madmax/madmax1
[...]
Access: (0755/drwxr-xr-x) Uid: ( 0/ madmax) Gid: ( 0/ madmax)

使用mount列出所有文件系统挂载:

$ mount
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
udev on /dev type devtmpfs
[...]

使用mountpoint命令来判断一个目录是否为挂载点:

$ mountpoint madmax1/
madmax1/ is a mountpoint

参见

  • man 1 chown

  • man 1 chmod

  • man 1 stat

11.6 创建自动文件系统挂载

问题

您已经添加了一个新的文件系统,并希望在系统启动时自动挂载它。

解决方案

这就是/etc/fstab文件的用途。以下示例添加到现有的/etc/fstab文件中,以在 Recipe 11.5 中创建文件系统的静态挂载,并将在启动时自动挂载:

#<file system>    <mount point>        <type>   <options>       <dump>  <pass>
LABEL=xfs-ehd     /mnt/madmax/newfs    xfs      defaults,user   0       2

使用findmnt命令测试您的新配置:

$ sudo findmnt --verbose --verify 
/
   [ ] target exists
   [ ] UUID=102a6fce-8985-4896-a5f9-e5980cb21fdb translated to /dev/sda2
   [ ] source /dev/sda2 exists
   [ ] FS type is btrfs
   [W] recommended root FS passno is 1 (current is 0)
/mnt/madmax/newfs
   [ ] target exists
   [ ] LABEL=xfs-ehd translated to /dev/sdb1
   [ ] source /dev/sdb1 exists
   [ ] FS type is xfs
[...]
0 parse errors, 0 errors, 1 warning

警告“推荐的根文件系统 passno 为 1(当前为 0)”不重要。如果这是唯一的警告,并且没有错误,请重新启动以进行测试,或者运行以下命令以挂载您的新/etc/fstab条目:

$ sudo mount -a

讨论

这是六个fstab列的用途:

设备

UUID 或文件系统标签。不要使用/dev名称,因为它们不唯一,有时会更改。运行lsblk -o UUID,LABEL以列出要在device:列中使用的 UUID 和文件系统标签。

mountpoint

您为文件系统创建的目录。

类型

文件系统类型,例如xfsext4btrfs。您可以使用auto作为文件系统类型,内核将自动检测文件系统类型。

选项

您的挂载选项以逗号分隔的列表(请参阅下文的列表)。

dump

如果您正在使用dump命令进行备份,这告诉dump备份间隔,单位为天。因此,1 表示每天,2 表示隔天,3 表示每三天,依此类推。您很可能没有使用dump,应该输入 0。

pass

这告诉文件系统检查器在启动时首先检查哪个文件系统,如果有必要的话。将根文件系统设置为 1,任何其他 Linux 文件系统设置为 2,非 Linux 文件系统设置为 0。

以下选项定义权限:

defaults

默认选项是rw, suid, dev, exec, auto, nouser, 和 asyncdefaults的值通过追加额外的选项被覆盖,例如defaults,user允许用户有权挂载和卸载文件系统。您可以追加尽可能多的选项,或省略defaults并仅列出您想要的选项。

rw

读/写。

ro

只读。

suid

允许设置 uid 和 gid 位操作。

dev

解释块和字符设备。

exec

允许运行二进制文件。

auto

指示哪些文件系统应在启动时启动。

nouser

非根用户不能挂载或卸载文件系统。

async

异步 I/O,这是 Linux 的标准设置。

user

非根用户可以挂载和卸载设备,如果他们已经挂载了它。

users

任何用户都可以挂载和卸载设备。

noauto

不自动在启动时挂载。

ro

将文件系统挂载为只读。

noatime

不更新“访问时间”的文件属性。在过去,noatime用于提高性能。如果您使用的是现代计算机,可能不会有太大差异。

gid

限制对组的访问(从/etc/group);例如,gid=group1

参见

11.7 创建 Ext4 文件系统

问题

您想在内部或外部存储磁盘上创建一个新的 Ext4 文件系统。

解决方案

从您想要的文件系统大小开始分区。然后使用 mkfs.ext4 命令创建新的 Ext4 文件系统。

下面的示例将使用新的 Ext4 文件系统覆盖现有的 XFS 文件系统。当覆盖现有文件系统时,必须首先卸载它。在此示例中,/dev/sdb1 上的文件系统挂载在/media/duchess/stuff,您可以使用 df 命令查看:

$ df -Th /media/duchess/stuff/
Filesystem     Type  Size  Used Avail Use% Mounted on
/dev/sdb1      xfs   952M  7.9M  944M   1% /media/duchess/stuff

您可能需要 root 权限来卸载:

$ sudo umount /media/duchess/stuff

创建新的 Ext4 文件系统:

$ sudo mkfs.ext4 -L *'mylabel' /dev/sdb1*
mke2fs 1.44.1 (24-Mar-2018)
/dev/sdb1 contains a XFS file system labelled 'stuff'
        created on Sun Sep 20 19:37:43 2020
Proceed anyway? (y,N) y
Creating filesystem with 466432 4k blocks and 116640 inodes
Filesystem UUID: 99da2e5d-f96a-4fb6-990d-599cf56247a2
Superblock backups stored on blocks:
        32768, 98304, 163840, 229376, 294912

Allocating group tables: done
Writing inode tables: done
Creating journal (8192 blocks): done
Writing superblocks and filesystem accounting information: done

您还可以创建一个新的分区,并在其中放置新的文件系统;请参阅配方 8.4 和 9.4 中创建新分区的示例。

讨论

覆盖文件系统会销毁其中的所有数据。

-L 选项用于创建卷标。这可以是您想要的任何内容,最多 16 个字符(FAT32 限制为 11 个字符)。虽然文件系统标签很有用,并且在某些操作中(如/etc/fstab中),可以替代长 UUID 使用。

-n 选项执行干运行,因此您可以查看实际创建新文件系统时会发生什么。

mke2fs 有很多选项,但您可能只会使用其中几个:设备名称、卷标、干运行以及创建外部日志。其默认设置在/etc/mke2fs.conf中,建议在彻底研究可用设置之前不要更改它们。

参见

  • man 8 mke2fs

  • 配方 8.4

  • 配方 11.5

11.8 配置 Ext4 日志模式

问题

您知道 ext4 的默认日志模式是 data=ordered,它不记录数据,只记录元数据。这是安全性和速度之间的良好平衡,但您希望将其设置为 data=journal,这是最安全的选项。

解决方案

使用 tune2fs 命令。首先使用 dmesg 检查您的现有日志模式。文件系统必须被挂载:

$ dmesg | grep sdb1
[25023.525279] EXT4-fs (sdb1): mounted filesystem with ordered data mode.

这证实了/dev/sdb1 格式化为 Ext4,并具有默认的 data=ordered 日志模式。现在将其更改为 data=journal 模式:

$ sudo tune2fs -o journal_data /dev/sdb1
tune2fs 1.44.1 (24-Mar-2018)

卸载并重新挂载,然后使用 dmesg 再次检查:

$ dmesg | grep sdb1
[25023.525279] EXT4-fs (sdb1): mounted filesystem with ordered data mode.

如果您看到像这样的多行冲突信息:

[  206.076123] EXT4-fs (sdb1): mounted filesystem with journalled data mode.
[  206.076433] EXT4-fs (sdb1): mounted filesystem with ordered data mode.

重新启动,然后您应该只看到“以日志数据模式挂载的文件系统”行。

讨论

不同文档中命名不同的日志模式命令选项。在 man 8 tune2fs 中列出了以下选项:

  • journal_data

  • journal_data_ordered

  • journal_data_writeback

在内核文档中,以及大量的 how-to 中,这些是选项:

  • data=journal

  • data=ordered

  • data=writeback

data= 选项应该在启动时传递给内核,要么在您的引导程序配置中,要么在/etc/fstab中。我倾向于使用 tune2fs,因为它快速简便,并且适用于所有 Ext4 文件系统,无论它们的挂载配置如何。

这些是按数据安全性顺序排列的日志模式:

data=journal

为您的数据提供最大的保护。所有数据和元数据首先写入日志,然后写入文件系统。在发生故障时,这为您提供了恢复数据的最佳机会。这也是资源消耗最大的,因为您的更改会被写入两次。

data=ordered

这不会将您的数据写入日志。数据首先写入文件系统,然后元数据写入日志。元数据逻辑上按顺序组合在单个事务中。当元数据写入磁盘时,其关联的数据块首先被写入。

data=writeback

这是最快但最不安全的方法。数据首先写入文件系统,然后元数据写入日志。不保留数据顺序。我认为这种小的性能增益不值得额外的风险。

参见

11.9 查找您的 Ext4 文件系统附加到哪个日志

问题

您有几个 Ext4 文件系统,其中一些具有内部日志,一些具有外部日志,您想知道它们使用的是哪些日志。

解决方案

遇到一个新命令,dumpe2fs。这是 ext2/3/4 工具集e2fsprogs的一部分。查询您的 Ext4 文件系统:

$ sudo dumpe2fs -h /dev/sda1 | grep -i uuid
dumpe2fs 1.43.8 (1-Jan-2018)
Filesystem UUID:          8593f3b7-4b7b-4da7-bf4a-cc6b0551cff8
Journal UUID:             f8e42703-94eb-49af-a94c-966e5b40e756

Journal UUID属于日志。运行lsblk来验证详细信息:

$ lsblk -f | grep  f8e42703-94eb-49af-a94c-966e5b40e756
└─sdb5 ext4    journal1 f8e42703-94eb-49af-a94c-966e5b40e756

就是这样。使用内部日志的 Ext4 文件系统如下所示,没有 Journal UUID 行:

$ sudo dumpe2fs -h /dev/sda2 | grep UUID
dumpe2fs 1.44.1 (24-Mar-2018)
Filesystem UUID:          64bfb5a8-0ef6-418a-bb44-6c389514ecfc

讨论

在 Linux 中总是有一种方法可以找出事物的位置。dumpe2fs命令显示有关您的 Ext4 文件系统的大量有用信息,包括 UUID、文件系统创建时间、块计数、空闲块、日志大小等等。

参见

  • man 8 dumpe2fs

11.10 使用 Ext4 的外部日志来提高性能

问题

您听说将 Ext4 日志放在不同的磁盘上比文件系统可以提高性能,并且您想要这样做。

解决方案

当您的日志模式是data=journal时,外部日志会提高性能。(有关日志模式的更多信息,请参见讨论。)您可以创建新的 Ext4 文件系统和外部日志,或者将现有文件系统转换为使用外部日志。

两个磁盘必须在同一台机器上,并且具有相似的读写速度。如果日志磁盘比文件系统磁盘慢,您将看不到多少性能提升,如果有的话。您可以使用两个类似的固态硬盘(SSD),两个类似的机械硬盘(HDD),或者将小型 SSD 用作日志和大型 HDD 用作文件系统,因为 SSD 比 HDD 快得多。

将 Ext4 日志定位在单独的磁盘上需要几个步骤。在以下示例中,我们将创建两个新分区,一个用于日志,一个用于新的 Ext4 文件系统。然后创建日志,然后文件系统,并将其连接到日志。

第一个分区用于/dev/sdb5上的日志,大小为 200 GB,第二个分区用于/dev/sda1上的 Ext4 文件系统,大小为 500 GB:

$ sudo parted
(parted) select /dev/sdb
Using /dev/sdb
(parted) mkpart "journal1" ext4 1600GB 1800GB
(parted) select /dev/sda
Using /dev/sda
(parted) mkpart "ext4fs" ext4 1MB 500GB

外部日志和文件系统必须具有相同的块大小,在以下示例中指定为-b 4096。如果您不知道块大小,请使用tune2fs找到它。以下命令在 Bash shell 中运行,而不是parted shell 中运行:

$ sudo tune2fs -l /dev/sda1  | grep -i 'block size'
Block size:               4096

现在创建日志,可能需要几分钟时间,然后创建新文件系统:

$ sudo mke2fs -b 4096 -O journal_dev /dev/sdb5
mke2fs 1.43.8 (1-Jan-2018)
/dev/sdb2 contains a ext4 file system labelled 'ext4'
        created on Mon Jan  4 18:25:30 2021
Proceed anyway? (y,N) y
Creating filesystem with 48747520 4k blocks and 0 inodes
Filesystem UUID: f8e42703-94eb-49af-a94c-966e5b40e756
Superblock backups stored on blocks:
Zeroing journal device:

$ sudo mkfs.ext4 -b 4096 -J device=/dev/sdb5 /dev/sda1
mke2fs 1.43.8 (1-Jan-2018)
Creating filesystem with 35253504 4k blocks and 8814592 inodes
Filesystem UUID: 8593f3b7-4b7b-4da7-bf4a-cc6b0551cff8
Superblock backups stored on blocks:
        32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
        4096000, 7962624, 11239424, 20480000, 23887872

Allocating group tables: done
Writing inode tables: done
Adding journal to device /dev/sdb2: done
Writing superblocks and filesystem accounting information: done

您已经完成并可以使用您的新文件系统。

您可以使用tune2fs命令将外部日志附加到现有文件系统。首先清除现有文件系统上的日志,然后将文件系统链接到外部日志:

$ sudo tune2fs -O ^has_journal /dev/sda1
$ sudo tune2fs -b 4096 -J device=/dev/sdb5 /dev/sda1

讨论

在磁盘或系统故障时,Ext4 日志通过跟踪尚未写入磁盘的更改来为您的数据提供额外保护。即使它丢失了您最近的更改,它也保护文件系统免受损坏,这样您只会失去一点而不是全部内容。

将日志移动到同一台机器上的单独磁盘可以显著提升性能,当日志模式为data=journal时尤为明显。Ext4 有三种日志模式:journalorderedwriteback。默认是ordered。参见 Recipe 11.8 了解这些模式及如何选择您想要使用的模式。

插入符号^禁用一个功能。在本配方示例中,它清除现有的内部日志。

Ext4 日志不能共享,并且只能被一个文件系统使用。

参见

  • man 8 mke2fs

  • man 8 tune2fs

  • 第八章

  • 第九章

11.11 在 Ext4 文件系统上释放保留块的空间

问题

大多数 Linux 发行版为根用户和系统服务保留了 Ext4 文件系统的 5%。在大型现代硬盘上,这是很多空间,您可能希望释放其中的一些空间。

解决方案

使用tune2fs命令调整 Ext4 文件系统上空闲空间的大小。您可以按百分比进行配置,例如以下示例将其减少到 1%:

$ sudo tune2fs -m 1 /dev/sda1
tune2fs 1.44.1 (24-Mar-2018)
Setting reserved blocks percentage to 1% (820474 blocks)

这依然是大约 3 GB,使用 4K 块(820,474 x 4,096 = 3,360,661,504 字节)。找到您的块大小:

$ sudo tune2fs -l /dev/sda1  | grep -i 'block size'
Block size:               4096

您可以设置一个分数百分比:

$ sudo tune2fs -m .25 /dev/sda1
tune2fs 1.44.1 (24-Mar-2018)
Setting reserved blocks percentage to 0.25% (205118 blocks)

大约是 800 MB。或者,指定一个块数:

$ sudo tune2fs -r 250000 /dev/sda1
tune2fs 1.44.1 (24-Mar-2018)
Setting reserved blocks count to 250000

250,000 个 4K 块大约是 1 GB。检查您的工作:

$ sudo tune2fs -l /dev/sda1 | grep -i 'reserved block'
Reserved block count:     250000

讨论

如果您的磁盘空间不足,仍可以以 root 用户身份登录并释放空间,如果不保留这 5%,则无法执行此操作。然而,这 5%是从兆字节硬盘时代遗留下来的。现在硬盘如此之大,您不需要所有这些保留空间。例如,1 TB 磁盘的 5%约为 50 GB。只需要几百兆字节的保留空间即可。我将我的设置为 1 GB。这很容易记住并提供足够的空间。

使用dumpe2fs命令检查您的 Ext4 文件系统中保留块的设置:

$ sudo dumpe2fs -h /dev/sda1
[...]
Block count:              82047488
Reserved block count:     250000
[...]

参见

  • man 8 dumpe2fs

  • man 8 tune2fs

11.12 创建新的 XFS 文件系统

问题

您喜欢 XFS,并且想要创建一个新的 XFS 文件系统。

解决方案

您需要在系统上安装 xfsprogs 软件包,并为新文件系统创建一个分区。然后使用 mkfs.xfs 创建您的新 XFS 文件系统。以下示例在 Ubuntu 上演示了所有这些步骤。示例新分区为 /dev/sda1,新文件系统标签为 xfstest

$ sudo apt install xfsprogs
$ sudo parted /dev/sda mkpart testxfs xfs 1MB 500GB
$ sudo mkfs.xfs -L xfstest /dev/sda1
meta-data=/dev/sdb5              isize=512    agcount=4, agsize=640000 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=1, sparse=0, rmapbt=0,
reflink=0
data     =                       bsize=4096   blocks=2560000, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=1
log      =internal log           bsize=4096   blocks=2560, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0

使用 lsblk 检查您的工作:

$ lsblk -f | grep -w sda1
├─sda1 xfs    xfstest  bb5dddb3-af74-4bed-9d2a-e79589278e84

挂载您的新文件系统,调整所有者和权限,它就可以使用了。以下示例将其挂载到 /mnt/xfstest,将所有权设置为 Duchess,对 Duchess 为读写,对其他人为只读:

$ sudo mkdir /mnt/xfstest
$ sudo mount /dev/sda1 /mnt/xfstest 
$ sudo chown -R duchess:duchess /mnt/xfstest
$ sudo chmod -R -755 /mnt/xfstest

讨论

创建新的 XFS 文件系统的命令输出包含几个有用的项目,如块大小、块数和扇区大小。

参见

  • man 8 mkfs.xfs

11.13 调整 XFS 文件系统大小

问题

您想要调整一个 XFS 文件系统的大小。

解决方案

您只能增加 XFS 文件系统的大小。如果您需要缩小它,您必须将数据复制到安全位置,创建较小的分区,格式化为 XFS,然后恢复您的数据。

增加大小工作较少。您需要在 XFS 文件系统所在的分区末尾有空闲空间。在以下示例中,分区的新端点为 2700 GB,并且文件系统挂载在 /media/duchess/xfs

启动 parted。打印分区信息以验证正确的分区和端点,增加分区大小,然后退出 parted

$ sudo parted */dev/sdb*
GNU Parted 3.3
Using /dev/sdb
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) p free 
Model: ATA SAMSUNG HD204UI (scsi)
Disk /dev/sdb: 4000GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags:

Number  Start   End     Size    File system  Name   Flags
        17.4kB  1049kB  1031kB  Free Space
 1      1049kB  1656GB  1656GB  xfs          files
 2      1656GB  1759GB  103GB   xfs          files2
        1759GB  4000GB  242GB   Free Space

(parted) resizepart 2
(parted) Warning: Partition /dev/sdb2 is being used. Are you sure you want to
continue?
Yes/No? Yes
End?  [1759GB]? 1900GB
(parted) q

现在,扩展文件系统以匹配新的分区大小:

$ sudo xfs_growfs /media/duchess/xfs

搞定!享受您的新更大文件系统。

讨论

您还可以卸载文件系统并离线调整大小。这样做更安全一些。

使用 GParted 调整文件系统大小快速而简便;参见 配方 9.7。

参见

  • 配方 8.8

  • 配方 9.7

11.14 创建 exFAT 文件系统

问题

您的数码相机闪存驱动器格式化为 exFAT 文件系统,或者您有其他使用 exFAT 的闪存设备,并且您希望在 Linux 系统上读取、写入和编辑这些设备上的文件。

解决方案

有两种可能的解决方案:一种是使用在用户空间运行的 exFAT 实现(FUSE)。另一种解决方案是使用在 Linux 内核中而不是用户空间运行的本地实现。在这个配方中,我们将使用 exFAT FUSE,因为在撰写本文时,本地实现尚未包含在大多数发行版中。查看内核版本 5.7,并检查您的发行版发布说明和新闻。 (运行 uname -r 命令查看您的内核版本。)

exFAT 包的名称各不相同。exfat-fuseexfat-utils 是旧版软件包。exfatprogs 是最新的实现,替代了 exfat-fuseexfat-utils。无论您安装了什么版本,请继续安装。

创建新的 exFAT 文件系统的命令对于两者是相同的。以下示例将 /dev/sdc1 格式化为 exFAT:

$ sudo mkfs.exfat /dev/sdc1
mkexfatfs 1.2.8
Creating... done.
Flushing... done.
File system created successfully.

exFAT 被设计得很简单,因此选项不多。您可以为其命名标签:

$ sudo exfatlabel /dev/sdc2 exfatfs

使用 lsblk 验证您的更改:

$ lsblk -f
NAME   FSTYPE LABEL   UUID
sdc
├─sdc1
├─sdc2 exfat  exfatfs 8178-51D4
└─sdc3 

讨论

您不需要专门的 exFAT 分区来读取其他设备上的 exFAT 文件,但只需在您的 Linux 系统上安装 exFAT 即可。

如果您更喜欢图形化分区工具,由于法律原因,GParted 不支持 exFAT。GNOME Disks,在大多数 GNOME 实现中称为 Disks,支持 exFAT。您不必安装 GNOME 即可获得 Disks;请查找 gnome-disk-utility 软件包。

Microsoft 在 2019 年发布了 exFAT 规范。Samsung 编写了 exfatprogs 并在 2020 年初发布了它。当您阅读本文时,最新版本的 Fedora、Ubuntu 和 openSUSE Tumbleweed 应该具有本地的 exFAT 支持。

参见

  • man 8 exfat

  • man 8 exfatlabel

11.15 创建 FAT16 和 FAT32 文件系统

问题

您需要知道如何创建 FAT16 和 FAT32 文件系统。

解决方案

您需要 dosfstools 软件包,在大多数 Linux 上默认安装。以下示例演示了使用 parted 创建一个新的 500 MB 分区,然后用 FAT32 格式化该分区。

创建新分区,并注意如何将测量单位更改为 MB,以及如何交互地使用 mkpart

$ sudo parted /dev/sdb
GNU Parted 3.2
Using /dev/sdb
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) print
Model: ATA SAMSUNG HD204UI (scsi)
Disk /dev/sdb: 2000399MB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags:

Number  Start    End     Size    File system  Name   Flags
1       0.00GB   1656GB  1656GB  xfs          files

(parted) unit mb
mkpart 
Partition name?  []?
File system type?  [ext2]? fat32
Start? 1656331MB
End? 1656831MB
(parted) print
Model: ATA SAMSUNG HD204UI (scsi)
Disk /dev/sdb: 2000399MB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags:

Number  Start      End        Size       File system  Name  Flags
 1      1.05MB     1656331MB  1656330MB  xfs          bup
 2      1656331MB  1656831MB  500MB      fat32

(parted) q

分区 名称是可选的;在本例中为空。现在创建一个漂亮的新 FAT32 文件系统:

$ sudo mkfs.fat -F 32 -n fat32test /dev/sdb2
mkfs.fat 4.1 (2017-01-24)
mkfs.fat: warning - lowercase labels might not work properly with DOS or Windows

使用 lsblk 进行验证:

$ lsblk  -f /dev/sdb
NAME   FSTYPE LABEL       UUID                          FSAVAIL FSUSE% MOUNTPOINT
sdb
├─sdb1 xfs    xfstest     1d742b2d-a621-4454-b4d3-469216a6f01e
└─sdb2 vfat   fat32test   AB39-1808

讨论

如果您想要 FAT16 文件系统,请使用 -F 16

FAT16 文件和文件系统最多支持 4 GB。

FAT32 支持最大 4 GB 的文件大小,最大 16 TB 的分区大小,使用 4 KB 扇区和 64 KB 簇。

参见

  • 第八章

  • 第九章

  • man 8 mkfs.fat

11.16 创建 Btrfs 文件系统

问题

Btrfs 听起来很酷,您想尝试一下。

解决方案

这很酷,也很复杂。SUSE Linux Enterprise Server (SLES) 和 openSUSE 是尝试 Btrfs 的最佳 Linux 发行版。SLES 和 openSUSE 是最大的 Btrfs 支持者和开发者,他们为管理 Btrfs 快照创建了优秀的 Snapper 工具。他们还提供了最详尽的文档。在 openSUSE/SLES 上的默认分区设置了 Btrfs 子卷和自动快照。

开始下载最新的 openSUSE Tumbleweed。启动安装程序,在建议分区屏幕时,查看安装程序的第一个建议(Figure 11-2)。

openSUSE 的首次分区建议

图 11-2. openSUSE 的首次分区建议

点击“引导设置”以修改此建议。跳过“启用逻辑卷管理(LVM)/启用磁盘加密”屏幕,并停留在文件系统选项屏幕。选择“建议单独的家目录分区”,并将其格式化为 Btrfs。勾选“建议单独的交换分区”的两个框,然后点击“下一步”(见 图 11-3)。

创建家目录分区

图 11-3. 创建一个家目录分区

这将带您返回“建议的分区”屏幕。如果您希望调整分区大小,请点击专家分区程序 → 以当前建议开始(见 图 11-4)。否则,请点击“下一步”继续安装。

使用当前建议进行自定义分区

图 11-4. 使用当前建议进行自定义分区

当您完成时,您将拥有一个已设置好良好默认值的可用 Btrfs Linux 系统。

讨论

手动设置 Btrfs 稍显繁琐,但当你了解它时,你可能会想尝试手动设置它。我喜欢通过一个可工作的实现来学习新事物。对我来说,提供几个 Btrfs 的实用方法是不可能的。Btrfs 如此灵活和强大,它需要一本专门的书籍。多亏了 SUSE 的热心人,它有了自己的书。请参阅启动指南进行安装,以及 openSUSE 文档 中的“系统恢复和快照管理”部分。Snapper + Btrfs 是 Btrfs 管理和快速故障恢复的绝佳组合。

参见

第十二章:使用 OpenSSH 进行安全远程访问

OpenSSH 是安全远程管理的首选工具。它在会话期间加密认证和所有流量,并保证数据传输的完整性。如果有什么问题影响了你的数据包,SSH 会告诉你。在本章中,你将学习如何设置 SSH 访问远程主机,管理 SSH 加密密钥,配置登录到多个远程主机,自定义 Bash 提示以显示 SSH 会话等好用的功能。

OpenSSH 支持大量强加密算法。所有这些算法都没有专利限制,因为 OpenSSH 团队已经尽最大努力确保 OpenSSH 内部没有受专利或其他限制的代码。Recipe 12.16 展示了如何打印所有支持算法的列表。

OpenSSH 是一套远程传输实用程序:

  • sshd,OpenSSH 服务器守护进程。

  • ssh,安全外壳的缩写,虽然它实际上并不包含外壳,但提供了与远程系统上的命令外壳的安全通道。

  • scp,加密文件传输的安全副本。

  • sftp,安全文件传输协议,提供文件访问。

  • ssh-copy-id,一个非常好的小程序,用于将你的公钥安装到远程 SSH 服务器的authorized_keys文件中。

  • ssh-keyscan,在网络上查找和收集公共主机密钥,免去了手动查找的麻烦。

  • ssh-keygen,生成和管理认证密钥。

  • ssh-add,将你的身份添加到认证代理ssh-agent中。

在本章中,你将了解关于sshsshdssh-copy-idssh-keygen以及两个有用的相关实用程序:sshfsssh-agent

sshfs,将远程文件系统挂载到本地 PC 上,而ssh-agent则记住了多个 SSH 登录中私有 SSH 密钥的密码。ssh-agent绑定到单个登录会话,因此登出或打开另一个终端意味着重新开始。一个更好的用于自动化操作的实用程序是 Keychain,它是ssh-agent的前端。Keychain 会重用ssh-agent直到你重新启动机器,因此你只需要在启动时输入密码(参见 Recipe 12.10)。

OpenSSH 支持不同类型的身份验证:

密码认证

使用你的 Linux 登录名和密码进行身份验证。这是最简单和最灵活的方式,因为你可以从任何机器登录。但是要注意不要从不可信任的计算机(如图书馆或网吧)打开 SSH 会话,因为如果被键盘记录器感染,它会捕获你的凭据。

公钥认证

使用个人 SSH 公钥进行身份验证,而不是系统登录。这需要更多的设置工作,因为你需要创建和分发你的公钥,并且只能从保存有你私钥的机器上登录。一些商业服务要求客户使用某种形式的公钥认证。

无密码认证

公钥认证无需密码短语。这对于自动化服务如脚本和 cron 作业非常有用。任何成功窃取私钥的人都可以轻松冒充你,因此你需要非常谨慎地保护没有密码短语的私钥。

另一种使用无密码短语的密钥的替代方法是 Keychain,它会为您记住私钥(见 Recipe 12.10)。

认证密钥有两种不同的用途:主机密钥用于认证计算机,公钥用于认证用户。SSH 密钥是成对出现的,私钥和公钥。传输使用公钥加密,私钥解密,这是一个非常简单却精巧的方案。你可以安全地分发你的公钥,而私钥则需要保护,不让任何人获取。

服务器和客户端由事务的方向定义。服务器运行 SSH 守护程序并监听连接请求,客户端是通过 SSH 登录到这台机器的任何人。

12.1 安装 OpenSSH 服务器

问题

你想要安装一个 OpenSSH 服务器。

解决方案

大多数 Linux 发行版默认安装 OpenSSH 客户端,但不总是安装服务器。不同的 Linux 发行版以不同方式打包 OpenSSH,因此请使用你的软件包管理器列出 Linux 的软件包(见附录)。安装服务器后,检查是否已启动:

$ systemctl status sshd
● sshd.service - OpenSSH Daemon
   Loaded: loaded (/usr/lib/systemd/system/sshd.service; disabled; vendor preset
   Active: inactive (dead)
   [...]

这表明服务器未运行且未启用。在大多数 Linux 上,安装后 OpenSSH 未配置自动启动是件好事,因为在打开接收连接请求之前,你需要正确配置服务器。如果在检查服务器配置之前它已运行,请停止它或使用防火墙阻止其监听端口。

接下来的步骤是设置主机加密密钥并配置你的服务器。参见 12.2 和 12.3。

讨论

请记住,服务器和客户端不仅仅是硬件问题,而是由事务的方向定义的。服务器运行 SSH 守护程序并监听连接请求,客户端是通过 SSH 登录到服务器的任何人。任何 Linux PC 都可以是服务器、客户端或两者兼有。

参见

  • 第十四章

  • OpenSSH

  • sshd (8)

  • 附录

12.2 生成新的主机密钥

问题

在你的 Linux 发行版安装时未自动创建主机密钥,或者你想替换现有的主机密钥,或者当你克隆一个安装或虚拟机时,克隆需要拥有自己独特的主机密钥。

解决方案

使用ssh-keygen命令。有四种不同类型的密钥:RSA、DSA、ECDSA 和 ED25519。首先,如果存在旧密钥,请删除:

$ sudo rm /etc/ssh/ssh_host*

使用以下命令一次性创建所有新密钥:

$ sudo ssh-keygen -A
ssh-keygen: generating new host keys: RSA DSA ECDSA ED25519

讨论

如果您感到无聊并需要做点什么,请尝试研究“我应该使用哪种 SSH 密钥格式?” 论点是无穷无尽的。简短的答案是使用 RSA、ECDSA 和 ED25519,避免使用 DSA。删除您的 DSA 主机密钥并保留其余内容。

RSA 是最古老的。它强大且提供了最广泛的兼容性。

ECDSA 和 ED25519 是更新的,非常强大且计算成本较低。

一些较旧的 SSH 客户端不支持 ECDSA 和 ED25519. 希望您不使用这样的古老客户端,因为 ECDSA 和 ED25519 是 2014 年 OpenSSH 6.5 发布的。保持安全服务更新并且不允许不安全的旧客户端非常重要。

参见

12.3 配置您的 OpenSSH 服务器

问题

您希望尽可能安全地配置您的 OpenSSH 服务器并安全地进行测试。

解决方案

首先,请验证您服务器的私有主机密钥是否由 root 拥有,只读:

$ ls -l /etc/ssh/
-r-------- 1 root root    227 Jun  4 11:30 ssh_host_ecdsa_key
-r-------- 1 root root    399 Jun  4 11:30 ssh_host_ed25519_key
-r-------- 1 root root   1679 Jun  4 11:30 ssh_host_rsa_key

它们应该是这样的。然后检查您的公钥,这些公钥由 root 拥有,对 root 为读写,对其他人为只读:

$ ls -l /etc/ssh/
-rw-r--r-- 1 root root    174 Jun  4 11:30 ssh_host_ecdsa_key.pub
-rw-r--r-- 1 root root     94 Jun  4 11:30 ssh_host_ed25519_key.pub
-rw-r--r-- 1 root root    394 Jun  4 11:30 ssh_host_rsa_key.pub

这些都是正确的。

现在看一看 /etc/ssh/sshd_config。当您更改此文件时,请重新加载 sshd 以加载您的更改:

$ sudo systemctl reload sshd.server

取消注释要使用或更改的选项。

配置 sshd 以检查用户文件和主目录的文件模式和所有权是否正确,然后才接受其登录:

StrictModes yes

如果文件权限不正确,此设置将不允许它们登录。

如果您的机器有多个 IP 地址,请定义它监听的地址或地址:

ListenAddress *192.168.10.15*
ListenAddress 1*92.168.10.16*

您可以为 sshd 指定非标准端口进行侦听。仅使用高于 1024 的端口,并检查 /etc/services 查找未使用的端口,然后将您的新端口添加到 /etc/services 中:

*sshd 2022*
*sshd 2023*

然后将它们添加到 /etc/ssh/sshd_config

Port *2022*
Port *2023*

您可以限制访问仅限于指定的组(在 /etc/group 中创建这些组):

AllowGroups *webadmins backupadmins*

或使用 DenyGroups 拒绝访问。

不允许 root 登录。作为非特权用户登录然后在登录后使用 sudo 更安全:

PermitRootLogin no

另一种选择是仅允许公钥认证的 root 登录:

PermitRootLogin prohibit-password

您可以禁用所有用户的密码登录,并仅允许公钥认证(参见 Recipe 12.7):

PasswordAuthentication no

您可以拒绝指定的用户,无论是用户名,用户在主机名或 IP 地址:

DenyUsers *duchess madmax stash@example.com cagney@192.168.10.25*

或允许使用 AllowUsers。您可以同时使用 DenyUsers 总是首先处理。

限制服务器等待用户登录并完成连接的时间长度。默认为 120 秒:

LoginGraceTime 90

您可以限制失败的连接尝试次数。默认为 6 次:

MaxAuthTries 4

讨论

任何端口扫描器都会找到你的开放端口,并且攻击者会尝试暴力破解密码。攻击者仍然最频繁地攻击默认的 SSH 端口 22。改变端口不会显著降低这种风险,但它应该会减少日志文件中的条目数。当你使用备用端口号时,首先查看/etc/services以找到未使用的端口,然后将你使用的端口记录在该文件中。

公钥认证非常安全,无法像密码登录那样被暴力破解(参见 Recipe 12.7)。但是这样做的代价是不太方便,因为你只能从有你私钥的机器上登录。

参见

  • OpenSSH

  • man 5 sshd_config

  • Recipe 12.5

  • Recipe 12.7

12.4 检查配置语法

问题

每个人都会犯错,你想要一个用于 /etc/ssh/sshd_config 的语法检查器。

解决方案

你应该有一个。在做出更改后,运行以下命令:

$ sudo sshd -t

如果没有语法错误,它会静默退出。如果发现错误,它会告诉你:

$ sudo sshd -t
/etc/ssh/sshd_config: line 9: Bad configuration option: Porotocol
/etc/ssh/sshd_config: terminating, 1 bad configuration options

你可以在 SSH 守护进程运行时执行这些操作,因此你可以在发出重新加载或重启命令之前纠正你的错误。

讨论

-t代表测试。它不会影响 SSH 守护进程,只会检查/etc/ssh/sshd_config的语法错误,因此你可以随时使用它。

参见

12.5 设置密码认证

问题

你想要设置你的 OpenSSH 客户端,使用它支持的最简单的方法登录远程主机。

解决方案

密码认证是设置远程 SSH 访问的最简单方法。你需要:

  • 在你想要登录的机器上安装并正确配置了 OpenSSH 服务器(参见 Recipe 12.3)

  • 远程机器上运行的 SSH 守护进程,以及端口 22,或者sshd使用的任何端口,不受防火墙阻挡

  • 客户端机器上安装的 SSH 客户端

  • 远程机器上的你自己的用户账户

  • 服务器上的主机密钥(参见 Recipe 12.2)

公共主机密钥必须分发给客户端。最简单的方法是从客户端登录,并让 OpenSSH 传输密钥:

duchess@pc:~$ ssh *duchess@server1*
  The authenticity of host '*server1 (192.168.43.74)*' can't be established.
  ECDSA key fingerprint is SHA256:8iIg9wwFIzLgwiiQ62WNLF5oOS3SL/aTw6gFrtVJTx8.
  Are you sure you want to continue connecting (yes/no)? *yes*
  Warning: Permanently added '*server1,192.168.43.74*' (ECDSA) to the list of
  known hosts.
  Password: password
  Last login: Wed Jul  8 19:22:39 2021 from *192.168.43.183*
  Have a lot of fun...

现在,Duchess 可以在server1上工作,就像她坐在server1的键盘旁一样。所有的流量和认证都是加密的。

主机密钥交换只会发生一次,第一次登录时。除非密钥被替换为新密钥或从个人的~/.ssh/known_hosts文件中删除,否则不应再次询问。

讨论

server1的公共主机密钥存储在客户端 PC 上的~/.ssh/known_hosts文件中。该文件可以包含任意数量的主机密钥。

通过 SSH 以 root 身份登录是不安全的;最好以普通用户身份登录,然后在登录后使用susudo。如果你知道他们的密码,你可以作为任何在远程机器上有账户的用户登录:

duchess@pc:~$ ssh *madmax@server1*

当你在两台机器上有相同的用户名时,你不需要指定用户,可以像这样登录:

duchess@pc:~$ ssh *server1*

我习惯于始终指定用户名,以防万一出错。

不要对clientserver太过纠结。这与硬件无关。服务器是您登录的任何机器,客户端是您登录的位置。sshd不需要在客户端运行。

有风险主机密钥传输可能被拦截并替换为伪造密钥,这将允许攻击者访问您的系统。您可以在键入yes之前验证公钥指纹。可以使用老式方法如写下并比较,或新潮方法如用手机拍摄主机密钥进行比较,或使用手机作为实际电话,联系拥有远程机器访问权限的人员读取指纹给您听。

查看配方 12.6 以了解如何检索密钥指纹。

另请参阅

  • 配方 12.6

  • OpenSSH

  • man 1 ssh

  • man 1 ssh-keygen

  • man 8 sshd

12.6 检索密钥指纹

问题

您需要主机密钥的指纹,以便为客户端验证该密钥的合法性。

解决方案

在服务器上使用希望查询的主机密钥使用ssh-keygen命令:

duchess@server1:~$ ssh-keygen -lf /etc/ssh/ssh_host_rsa_key
4096 SHA256:32Pja4+F2+MTdla9cs4ucecThswRQp6a4xZ+5sC+Bf0 *backup server1* (RSA)

讨论

在这里,像电话和悄悄网这样的老式通信方法非常有用。不要使用电子邮件,除非您已经使用了自己的独立加密和认证的加密电子邮件,因为未加密的电子邮件容易被拦截和阅读。

另请参阅

12.7 使用公钥认证

问题

想要使用公钥认证,因为它比密码认证更加安全,而且不使用您的 Linux 密码。您希望能够使用单个公钥访问多个系统,或者为每台远程机器创建一个唯一的公钥。

解决方案

是的,Linux 用户,您可以拥有一切。您可以创建任意数量的 SSH 密钥,并根据需要使用它们。这是我创建新 RSA 密钥对的最喜欢的咒语。当然,您会创建自己的评论和密钥名称。(查看讨论了解是否需要在私钥上设置密码。)

duchess@pc:~/.ssh $ ssh-keygen -C "*backup server2*" -f *id-server2* -t rsa -b 4096
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in *id-server2*.
Your public key has been saved in *id-server2.pub*.
The key fingerprint is:
SHA256:32Pja4+F2+MTdla9cs4ucecThswRQp6a4xZ+5sC+Bf0 *backup server2*
The key's randomart image is:
+---[RSA 4096]----+
|          ..     |
|          ....   |
|           o. . .|
|          +  .  o|
|        S* .o o o|
|        +.+..Bo*+|
|         *.+*EX=o|
|        o *o.Oo+.|
|         o.o=+*+.|
+----[SHA256]-----+

下一步是将您的新密钥复制到远程机器,例如本地备份服务器server1。您必须已经通过主机密钥认证等方式访问远程机器,然后使用ssh-copy-id命令将您的公钥传输到服务器:

duchess@pc:~/.ssh $ ssh-copy-id -i *id-server1 duchess@server1*
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "*.ssh/id-server1*"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter
out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are
prompted now it is to install the new keys

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh '*duchess@server1*'"
and check to make sure that only the key(s) you wanted were added.

尝试登录:

duchess@pc:~/.ssh $ ssh -i *id-server1 duchess@server1*
Enter passphrase for key '*id-server1*':
Last login: Sat Jul 11 11:09:53 2021 from *192.168.43.234*
Have a lot of fun...
duchess@server1:~$

您可以使用此新密钥访问多个远程主机,或为每个远程主机创建唯一的密钥。使用相同的密钥访问多台机器很方便,但在多个主机上更改时会很麻烦。如果唯一密钥被泄露或丢失,您只需要替换一次。

讨论

对于为人类用户创建的 SSH 密钥,始终使用密码短语,因为任何获取您私钥的人如果没有密码短语,可以冒充您。

ssh-copy-id 是一个非常方便的实用工具,确保您的公钥以正确的格式和权限复制到远程主机的 ~/.ssh/authorized_keys 中。它还确保您的私钥不会被误复制。

选项如下:

  • -C 用于向您的密钥添加注释,这有助于您记住密钥的用途。

  • -f 是密钥的名称,可以任意设置。请注意当前工作目录;如果不在 ~/.ssh 下,请包括路径。

  • -t 是密钥类型:rsaecdsaed25519

  • -b 是位强度,只有 rsa 可以使用此选项。默认值为 2048,最大为 4096。比特数越多,处理开销就越大,但在除旧硬件或繁忙服务器外,使用 4096 比特可能不会感觉到任何差异。

  • -i 告诉您的 SSH 客户端要使用哪个密钥。当您拥有多个密钥时,必须使用此选项。如果不指定任何密钥,当 SSH 尝试使用所有密钥时,您可能会看到“Too many authentication failures”错误消息。

参见

  • OpenSSH

  • man 1 ssh

  • man 1 ssh-keygen

12.8 管理多个公钥

问题

您希望为不同的服务器使用不同的密钥。如何管理具有不同名称的密钥?

解决方案

创建新密钥对时,请使用 ssh-keygen 命令的 -f 选项为密钥命名:

duchess@pc:~/.ssh $ ssh-keygen -t rsa -f *id-server2*

然后,在登录远程主机时使用 -i 选项指定要使用的密钥:

duchess@pc:~/.ssh $ ssh -i *id-server2 duchess@server2*

要更轻松地管理多个公钥,请创建一个新文件,~/.ssh/config。此文件配置了您各个远程主机的登录信息,因此您可以使用 ssh foo 而不是冗长的命令字符串进行登录。以下示例配置了一个更简单的登录方式,让 Duchess 访问 server2

Host server2
  HostName server2
  User duchess
    IdentityFile ~/.ssh/id-server2
    IdentitiesOnly yes

现在 Duchess 使用 Host 值这样登录:

$ ssh *server2*

继续向该文件添加其他公钥登录信息,如下所示:

Host server3
  HostName server3
  User duchess
    IdentityFile ~/.ssh/id-server3
    IdentitiesOnly yes

Host server3
  HostName server3
  User madmax
    IdentityFile ~/.ssh/id-server3
    IdentitiesOnly yes

讨论

在上述解决方案片段中:

  • Host 行定义了每个配置的开始。这是您用于登录的标签,可以是任何您喜欢的名称。

  • HostName 是远程机器的主机名、完全限定域名或 IP 地址。

  • User 是远程机器上的用户名。

  • IdentityFile 是您公钥的完整路径。

  • IdentitiesOnly yes 告诉 ssh 使用 ~/.ssh/config 中的设置或通过命令行传递的设置,而不使用其他提供者(如果有的话)。

默认的 SSH 端口号是 22。当您需要连接到非标准端口(例如 2022)时,请使用 Port 指定:

Port 2022

您可以按任意名称命名您的密钥。我喜欢使用描述性名称,以便知道它们属于哪些机器。

请记得为您个人的私钥始终设置一个密码短语。

参见

  • OpenSSH

  • man 1 ssh_config

  • man 1 ssh

12.9 更改密码短语

Problem

你想要更改一个私钥的密码短语。

Solution

使用 -p 选项与 ssh-keygen 命令:

$ ssh-keygen -p -f ~/.ssh/*id-server2*
Enter old passphrase:
Key has comment '*backup server2*'
Enter new passphrase (empty for no *passphrase*):
Enter same passphrase again: *passphrase*
Your identification has been saved with the new passphrase.

Discussion

密码短语无法恢复。如果你丢失了密码短语,你唯一的选择就是用新密码创建一个新的密钥。

另请参阅

  • OpenSSH

  • man 1 ssh_

  • man 1 ssh-keygen

12.10 使用 Keychain 自动管理 Passphrase

Problem

你希望有些东西能为你记住私钥的密码短语,并在需要时使用它们。

Solution

Keychain 实用程序专为此而制作。安装 keychain 软件包,然后将以下示例中的行复制到你的 .bashrc 文件中。

在下面的示例中,你想要在登录时无需每次输入密码短语即可访问 server1server2server3。复制这些行,但使用你自己的密钥名称:

keychain ~/.ssh/*id-server1* ~/.ssh/*id-server2* \
 ~/.ssh/*id-server3* . ~/.keychain/$HOSTNAME-sh

Keychain 会保持你的私钥可用,直到你关机,因此每次启动系统时都必须输入你的密码短语。

当你启动到图形环境时,可能不会提示你输入密码短语。尝试打开终端,如果仍然看不到 Keychain 提示输入密码短语,请进入 Linux 控制台。按下 Ctrl-Alt-F2 并登录。登录后,你应该看到类似于以下内容:

* keychain 2.8.5 ~ http://www.funtoo.org
 * Found existing ssh-agent: 2016
 * Adding 3 ssh key(s): */home/duchess/.ssh/id-server1
/home/duchess/.ssh/id-server2 /home/duchess/.ssh/id-server3*
Enter passphrase for */home/duchess/.ssh/id-server1*:
Enter passphrase for */home/duchess/.ssh/id-server2*:
Enter passphrase for */home/duchess/.ssh/id-server3*:
 * ssh-add: Identities added: */home/duchess/.ssh/id-server1
/home/duchess/.ssh/id-server2 /home/duchess/.ssh/id-server3*

Discussion

. ~/.keychain/$HOSTNAME-sh 中的前导点是 source 的简写,意味着使用指定的文件。

$HOSTNAME 告诉 Keychain 在用户的环境变量中查找他们的主机名。你可以自己看到这一点:

$ echo $HOSTNAME
pc

Keychain 是 ssh-agentgpg-agent 的管理器,缓存你的 SSH 和 GPG 密码短语,只要你的计算机开机。你可以注销然后重新登录,只需在重新启动后重新输入密码短语。

一个很好的替代方案是 gnome-keyring,它运行在图形环境中。这提供了一个图形界面来查看和管理 SSH 和 GPG 密钥,还包括一个密码管理器。在大多数系统上,它显示为“密码和密钥”。它有两个缺点:不适合在无头系统上使用,并且不会使密码短语对 cron 可用(参见 Recipe 12.11)。

另请参阅

12.11 使用 Keychain 使密码短语可用于 Cron

Problem

你需要使用 cron 自动化任务,例如运行 rsync 备份到远程主机。但无论你尝试什么,都只会得到麻烦的失败备份和身份验证错误。

Solution

要配置 Keychain 来管理你的私钥用于 cron 作业,请创建一个供 cron 使用的脚本。以下示例是针对一个 rsync 备份,并命名脚本为 duchess-backup-server1

#!/bin/bash
source $HOME/.keychain/${HOSTNAME}-sh
/usr/bin/rsync -ae "ssh -i /home/duchess/.ssh/id-server3" /home/duchess/ \
duchess@server1:/backups/

使用 chmod 使此脚本可执行。

$ chmod +x duchess-backup-server1

此示例将一行添加到你的 crontab 中,以在每晚 10:15 运行脚本:

15 22 * * * /home/duchess/duchess-backup-server1

Discussion

在示例脚本中,以 /usr/bin/rsync 开头的行必须放在一行上。

Cron 在其自己的特殊限制环境中运行,并且需要 Keychain 提供所需的密钥和环境变量。

参见

12.12 安全地通过 SSH 隧道传输 X 会话

问题

您想要从远程主机运行图形应用程序。您知道 X 窗口系统具有内置的网络功能,但它发送的所有流量都是明文的,这是不安全的,您希望安全地执行此操作。

解决方案

通过 SSH 隧道传输 X 不需要额外的软件。首先,使用这些命令查看您的客户机是否正在运行 X11 或 Wayland 协议。以下示例显示了两种结果:

$ echo $XDG_SESSION_TYPE
x11
$ echo $XDG_SESSION_TYPE
wayland
$ loginctl show-session "$XDG_SESSION_ID" -p Type
Type=x11
$ loginctl show-session "$XDG_SESSION_ID" -p Type
Type=wayland

loginctl 是 systemd 的一部分。

如果您正在使用 Wayland,则无法通过 SSH 隧道传输,因为它不具备网络支持。

如果您的系统使用 X11,则在远程机器的 /etc/ssh/sshd_config 中配置 X11 转发:

X11Forwarding yes

以下示例使用 -Y 选项通过 SSH 隧道传输 X:

duchess@pc:~$ ssh -Yi *id-server1 duchess@server1*
Last login: Thu Jul  9 09:26:09 2021 from 192.168.43.80
Have a lot of fun..
duchess@server1:~$

现在您可以运行图形应用程序,尽管一次只能运行一个,例如 图 12-1 中的游戏。

duchess@server1:~$ kmahjongg

KMahjongg 通过 SSH 隧道传输

图 12-1. 在远程服务器上玩 KMahjongg 游戏

讨论

X 服务器以 /etc/ssh/sshd.conf 中指定的偏移量运行,X11DisplayOffset 10。这避免了与现有 X 会话的冲突。您的常规本地 X 会话是 :0.0,因此您的第一个远程 X 会话是 :10.0。您可以亲眼看到这一点。在本地机器上运行以下命令。第一个命令在您的本地命令提示符下:

duchess@pc:~$ echo $DISPLAY
:0.0

第二个示例在您的 SSH 命令提示符下:

duchess@server1:~ssh $ echo $DISPLAY
localhost:10.0

远程系统只需处于开机状态。您不需要任何本地用户登录,甚至不需要 X 运行。X 仅需要在客户端 PC 上运行。

参见

  • man 1 sshd

  • man 1 ssh_config

12.13 在一行中打开 SSH 会话并运行命令

问题

您有一个在远程机器上运行的单个命令,您认为直接运行它而不是登录、运行命令,然后退出会更好。毕竟,系统管理员的懒惰难道不是一种美德吗?

解决方案

OpenSSH 可以做到这一点。此示例显示如何重新启动 Postfix:

$ ssh *mailadmin@server2.example.com* sudo systemctl restart postfix

您将被要求输入 sudo 密码,但仍然可以省去一个步骤。

这演示了如何在 X 窗口系统中快速打开 GNOME Sudoku 游戏:

$ ssh -Y *duchess@laptop* /usr/games/gnome-sudoku

讨论

另一种方法是为 root 用户使用公钥认证,这样您就不必调用 sudo (Recipe 12.7)。

参见

  • man 1 ssh

12.14 使用 sshfs 挂载整个远程文件系统

问题

OpenSSH 是快速高效的,即使通过 OpenSSH 隧道传输 X 应用程序也不会太卡顿。但是您希望有一种更快的方式来编辑多个远程文件,而不是通过 SSH 运行图形文件管理器。

解决方案

sshfs 就是为您准备的工具。sshfs 用于挂载整个远程文件系统,然后像本地文件系统一样访问它,而无需设置 NFS 或 Samba 服务器的麻烦。

安装 sshfs 软件包,这应该也会安装 FUSE(用户空间文件系统)。您需要一个本地目录,您对其具有写权限作为挂载点:

duchess@pc:~$ mkdir *sshfs*

然后在本地 sshfs 目录中挂载您选择的远程目录。此示例将 duchess@server2 的主目录挂载到 duchess@pcsshfs 目录中:

duchess@pc:~$ sshfs *duchess@server2: sshfs/*

远程文件系统与本地文件系统一样易于访问:

duchess@pc:~$ ls sshfs
Desktop
Documents
Downloads
[...]

从命令行或图形文件管理器中访问这些文件,就像访问本地文件一样。

您的命令提示符不会更改为远程提示符。

完成后,卸载远程文件系统:

duchess@pc:~$ fusermount -u sshfs/

这将挂载 Duchess 的整个主目录。指定一个子目录:

duchess@pc:~$ sshfs *duchess@server2:/home/duchess/arias sshfs/*

您不能使用波浪号,~,作为 /home/user 的快捷方式,因为 sshfs 不支持它。

如果您的网络连接不可靠,请告诉 sshfs 在中断后自动重新连接:

duchess@pc:~$ sshfs *duchess@server2:/home/duchess/arias sshfs/ -o reconnect*

讨论

对于新手用户来说,他们总是会问这些问题:为什么不直接通过 SSH 运行 X,或者为什么不直接使用 NFS?答案是:它比通过 SSH 运行 X 更快,比 NFS 更容易设置,您可以使用 NFS、Samba 或任何您喜欢的东西。

参见

  • man 1 sshfs

12.15 为 SSH 自定义 Bash 提示符

问题

当您通过 SSH 登录时,您知道提示符会更改以显示远程主机名。但它只是一个普通的提示符,很容易出错,因此您希望有一个自定义的、彩色的提示符来指示您何时有活动的 SSH 登录。

解决方案

在远程机器上自定义 Bash 提示符。此示例将提示符变为紫色并添加“ssh”。

将这些行复制到您想要登录的远程帐户的 .bashrc 文件中:

if [ -n "$SSH_CLIENT" ]; then text=" ssh"
fi
export PS1='\[\e[0;36m\]\u@\h:\w${text}$\[\e[0m\] '

当您登录到这台机器时,提示符将显示为图 12-2 中所示。

自定义 SSH 提示符

图 12-2. 自定义的 SSH 提示符

只有提示符是紫色的,所有其他文本将是您正常的 shell 颜色。

讨论

自定义 Bash 提示符实际上是一个独立的书籍主题。本示例可以根据您的喜好进行编辑。您不必使用术语“ssh”或命名变量为“text”; 这些可以是任何您喜欢的东西。如果愿意,您可以说“超级加密会话”并将变量命名为“sekkret-squirl”。

[\e[0;31m] 是确定文本颜色的代码块。您只需更改数字即可更改颜色。

[\e[0m] 关闭自定义颜色,这样您的命令和命令输出将恢复到正常的 shell 颜色。以下是颜色代码:

  • 黑色 0;30

  • 蓝色 0;34

  • 绿色 0;32

  • 青色 0;36

  • 红色 0;31

  • 紫色 0;35

  • 棕色 0;33

  • 浅灰色 0;37

  • 深灰色 1;30

  • 浅蓝色 1;34

  • 浅绿色 1;32

  • 浅青色 1;36

  • 浅红色 1;31

  • 浅紫色 1;35

  • 黄色 1;33

  • White 1;37

此自定义通过检查SSH_CLIENT环境变量的存在来工作,只有在有活动 SSH 连接时才存在。您可以在远程主机上自行查看:

$ echo $SSH_CLIENT
192.168.43.234 51414 22

然后 Bash 会使用自定义的 SSH 提示而不是默认的提示。当您在没有任何活动的 SSH 会话的机器上运行此命令时,它会返回一个空行。

参见

12.16 列出支持的加密算法

问题

您必须遵循合规规定,并且需要知道 OpenSSH 支持哪些加密算法。

解决方案

OpenSSH 包括一个命令来查询和列出所有支持的算法,ssh -Q <query_option>。使用help选项列出它们:

$ ssh -Q help
cipher
cipher-auth
compression
kex
kex-gss
key
key-cert
key-plain
key-sig
mac
protocol-version
sig

下面的示例列出了sig签名算法:

$ ssh -Q sig
ssh-ed25519
sk-ssh-ed25519@openssh.com
ssh-rsa
rsa-sha2-256
rsa-sha2-512
ssh-dss
ecdsa-sha2-nistp256
ecdsa-sha2-nistp384
ecdsa-sha2-nistp521
sk-ecdsa-sha2-nistp256@openssh.com

讨论

下面的列表简要描述了每个选项:

  • cipher 列出支持的对称密码。

  • cipher-auth 列出支持的对称密码,还支持身份验证加密。

  • compression 列出支持的压缩类型。

  • mac 列出支持的消息完整性代码。这些保护了您消息的数据完整性和真实性。

  • kex 列出密钥交换算法。

  • kex-gss 列出 GSSAPI(通用安全服务应用程序接口)密钥交换算法。

  • key 列出密钥类型。

  • key-cert 列出证书密钥类型。

  • key-plain 列出非证书密钥类型。

  • key-sig 列出所有密钥类型和签名算法。

  • protocol-version 列出支持的 SSH 协议版本,目前只支持版本 2。

  • sig 列出支持的签名算法。

参见

  • OpenSSH

  • 《严谨的密码学》 by Jean-Philippe Aumasson(No Starch Press)

第十三章:安全远程访问与 OpenVPN

Open Virtual Private Network(OpenVPN)在不同物理位置的两个不同网络之间创建 TLS/SSL 加密连接,例如将分支办公室连接到总部,或远程工作者从家中登录公司网络。这种连接称为加密 隧道,是一种安全的传输方式,保护您免受互联网的威胁。OpenVPN 依赖于 OpenSSL,因此具备 OpenSSL 知识将会有所帮助。

注意

如果您已经熟悉 OpenVPN,可以直接跳到配方 13.5、13.6 和 13.7 查看如何创建您的加密证书以及客户端和服务器配置。如果您对 VPN 还不熟悉,请按顺序尝试每个配方。耐心点,VPN 很复杂也很挑剔。在投入生产系统之前进行大量测试。

OpenVPN 概述

VPN 是网络的安全扩展,使远程工作者可以访问与本地用户相同的所有服务,因此远程用户的体验与实际位于您位置的用户相同。他们可以访问您的本地 Web 服务器、电子邮件、文件共享、聊天服务器、视频会议应用程序、内部维基等所有对外界隔离的服务,这些服务仅供内部网络用户使用。VPN 不同于连接个人计算机的 SSH。VPN 连接的是网络和个别主机。

在本章中,您将学习如何设置 OpenVPN 服务器,配置客户端,并创建和管理适当的公钥基础设施(PKI)进行身份验证和加密。您的服务器将验证和保护各种客户端:Linux、macOS、Windows PC、Android 和 iOS 设备。

OpenVPN 是一个开源项目,提供免费下载和商业选项。免费的服务器和客户端是 openvpn 软件包,适用于所有 Linux 发行版,并可以从 OpenVPN 社区下载。商业选项包括 OpenVPN Access Server,这是一个带有额外管理工具和云选项的本地服务器。托管的个人计划只需安装客户端,即可访问全球的 OpenVPN 服务器网络。

真正的 VPN 很强大,因为它不信任任何人,并要求经过身份验证的端点,在这里服务器和客户端相互验证。大多数商业 TLS/SSL VPN 并不这样做,而是信任所有客户端,就像购物网站一样。这样做更加灵活,允许用户从任何地方使用任何设备登录。这样做省去了安装和配置客户端软件以及复制加密密钥的麻烦。但是对于您的内部网络来说,这种做法是短视的——最后一件您需要的事情是用户从带有键盘记录器和间谍软件的随机 PC 或智能手机登录,然后被热情地欢迎进入您的局域网。

证书颁发机构

证书颁发机构(CA)是运行 OpenVPN 服务器的最重要部分。CA 颁发数字证书并认证公钥的所有权。在网页浏览器中点击小锁图标可以查看网站的公共证书及其由哪个 CA 签署。CA 是一个受信任的机构,这就是为什么很多网站使用商业 CA 的原因。像我们在本章创建的自签名证书可以在你的组织内部使用。面向客户的站点应使用商业 CA。使用 CA 可以避免在 OpenVPN 服务器上保存客户端证书的麻烦;服务器只需知道客户端证书由你的 CA 认证即可。

SSL 与 TLS

安全套接字层(SSL)和传输层安全性(TLS)是加密协议。TLS 是从 SSL 进化而来的。所有版本的 SSL 都已被弃用,包括 TLS 1.0 和 TLS 1.1。请使用 TLS 1.2 或 1.3,并禁用所有其他版本(配方 13.10)。由于安全漏洞,旧版本已被弃用,请不要让任何人说服你支持弃用的版本。

TUN/TAP

TUNTAP设备是虚拟网络接口。这些已经集成到 Linux 内核中,你无需进行任何操作即可使用。TUN设备用于路由网络,TAP设备用于桥接网络。你的服务器和客户端配置文件会指定使用哪种设备。

好的安全措施需要工作。

良好的安全性需要持续学习和维护。本章旨在向你展示如何设置一个强大且相对用户友好的 VPN。还有许多其他方法可以使你的 VPN 更加安全,如使用短寿命的客户端证书、额外的认证、硬件设备、SELinux、chroot 监狱、短密码超时等等。如果你需要超高安全性,请咨询专业的专家。

13.1 安装 OpenVPN,服务器和客户端

问题

你需要知道如何安装 openVPN。

解决方案

OpenVPN 网站提供了社区开源的 OpenVPN 和商业 OpenVPN Access Server。社区版 OpenVPN 免费且开源。本章介绍了社区版 OpenVPN。

在 Linux 上安装openvpn软件包。(像往常一样,请验证你特定 Linux 发行版上的软件包名称。)尽可能获取最新版本,从 2.4.5 版本开始。这提供了服务器和客户端。源代码 tarball 和 Windows 安装程序可以从OpenVPN 社区下载获取。

对于你的客户端,你可以尝试免费的OpenVPN Access Clients,适用于 Linux、macOS、Android、iOS 和 Windows。这些客户端设计用于商业 OpenVPN Access Server,也与社区版 OpenVPN 服务器兼容。

你也可以在 Google Play 商店找到安卓的 OpenVPN 社区客户端。

参见 Recipe 13.9 了解如何使用 .ovpn 内联文件格式来更轻松地配置客户端。

讨论

在 Linux 上,OpenVPN 必须安装在您的 OpenVPN 服务器和所有客户端上。OpenVPN 软件包提供客户端和服务器功能。

Ubuntu、Fedora 和 openSUSE 包含额外的软件包,提供与 NetworkManager 的集成,这使得管理、连接和断开 VPN 变得非常简便。

NetworkManager-openvpn (Fedora、openSUSE) 和 network-manager-openvpn (Ubuntu) 将 OpenVPN 与 Network Manager 集成。如果您使用 GNOME 环境(如 GNOME、Xfce、Cinnamon 或 Mate),您还需要 NetworkManager-openvpn-gnome (openSUSE、Fedora),或者 network-manager-openvpn (Ubuntu)。

OpenVPN Access Server 是免费下载的,您可以同时连接最多两个客户端而无需购买许可证。它带有额外的功能,如 Web 管理界面和与免费 OpenVPN Access Client 的自动配置。如果您从社区版 OpenVPN 开始,然后决定迁移到 OpenVPN Access Server,那么您在社区版 OpenVPN 服务器上学到的所有内容也适用于 Access Server。

参见

13.2 设置一个简单的连接测试

问题

您希望运行最简单的 OpenVPN 连接测试,以了解其工作原理并验证连接性。

解决方案

以下简单测试创建了两台位于同一网络上的 Linux 计算机之间的未加密隧道。这两台计算机都必须安装 OpenVPN。首先确保 OpenVPN 守护进程在任一主机上都没有运行,如果运行了,请停止它:

$ systemctl status *openvpn@.openvpn1.service*
● openvpn.service - OpenVPN service
     Loaded: loaded (/lib/systemd/system/openvpn.service; enabled; vendor prese>
     Active: active (exited) since Sun 2021-01-10 13:43:18 PST; 33min ago
[...]
$ sudo systemctl stop *openvpn@.openvpn1.service*

使用不同的子网用于您的 VPN

使用不同的子网用于您的 OpenVPN 隧道;例如,host1host2 在 192.168.43.0/24 上,因此示例使用 10.0.0.0/24 私有地址空间作为 VPN 隧道。

在以下示例中,两台计算机分别命名为 host1host2。第一个示例创建了从 host1host2 的 VPN 隧道:

[madmax@host1 ~]$ sudo openvpn  --remote *host2* --dev tun0 --ifconfig *10.0.0.1 \
10.0.0.2*
Sat Jan  9 14:40:34 2021 disabling NCP mode (--ncp-disable) because not in P2MP
  client or server mode
Sat Jan  9 14:40:34 2021 OpenVPN 2.4.8 x86_64-redhat-linux-gnu [SSL (OpenSSL)]
  [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] built on Jan 29 2020
Sat Jan  9 14:40:34 2021 library versions: OpenSSL 1.1.1d FIPS  10 Sep 2019,
  LZO 2.10
Sat Jan  9 14:40:34 2021 ******* WARNING *******: All encryption and
  authentication features disabled -- All data will be tunnelled as clear text
  and will not be protected against man-in-the-middle changes. PLEASE DO
  RECONSIDER THIS CONFIGURATION!
Sat Jan  9 14:40:34 2021 TUN/TAP device tun0 opened
Sat Jan  9 14:40:34 2021 /sbin/ip link set dev tun0 up mtu 1500
Sat Jan  9 14:40:34 2021 /sbin/ip addr add dev tun0 local 10.0.0.1 peer 10.0.0.2
Sat Jan  9 14:40:34 2021 TCP/UDP: Preserving recently used remote address:
  [AF_INET]192.168.122.239:1194
Sat Jan  9 14:40:34 2021 UDP link local (bound): [AF_INET][undef]:1194
Sat Jan  9 14:40:34 2021 UDP link remote: [AF_INET]192.168.122.239:1194

这个示例创建了从 host2host1 的链接:

[stash@host2 ~]$ sudo openvpn --remote *host1* --dev tun0 --ifconfig *10.0.0.2 \
10.0.0.1*
Sat Jan  9 14:50:53 2021 disabling NCP mode (--ncp-disable) because not in P2MP
  client or server mode
Sat Jan  9 14:50:53 2021 OpenVPN 2.4.7 x86_64-pc-linux-gnu [SSL (OpenSSL)] [LZO]
  [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] built on Sep  5 2019
Sat Jan  9 14:50:53 2021 library versions: OpenSSL 1.1.1f  31 Mar 2020, LZO 2.10
Sat Jan  9 14:50:53 2021 ******* WARNING *******: All encryption and
  authentication features disabled -- All data will be tunnelled as clear text
  and will not be protected against man-in-the-middle changes. PLEASE DO
  RECONSIDER THIS CONFIGURATION!
Sat Jan  9 14:50:53 2021 TUN/TAP device tun0 opened
Sat Jan  9 14:50:53 2021 /sbin/ip link set dev tun0 up mtu 1500
Sat Jan  9 14:50:53 2021 /sbin/ip addr add dev tun0 local 10.0.0.2 peer 10.0.0.1
Sat Jan  9 14:50:53 2021 TCP/UDP: Preserving recently used remote address:
  [AF_INET]192.168.122.52:1194
Sat Jan  9 14:50:53 2021 UDP link local (bound): [AF_INET][undef]:1194
Sat Jan  9 14:50:53 2021 UDP link remote: [AF_INET]192.168.122.52:1194
Sat Jan  9 14:51:03 2021 Peer Connection Initiated with
  [AF_INET]192.168.122.52:1194
Sat Jan  9 14:51:04 2021 WARNING: this configuration may cache passwords in
  memory -- use the auth-nocache option to prevent this
Sat Jan  9 14:51:04 2021 Initialization Sequence Completed

当两台主机显示“Initialization Sequence Completed”消息时,您就建立了成功的连接。通过在两台主机上的 tun0 接口进行 ping 测试您的连接:

[madmax@host1 ~]$ ping -I tun0 *10.0.0.2*
PING 10.0.0.2 (10.0.0.2) from 10.0.0.1 tun0: 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.515 ms
64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=0.436 ms

[stash@host2 ~]$ ping -I tun0 *10.0.0.1*
PING 10.0.0.1 (10.0.0.1) from 10.0.0.2 tun0: 56(84) bytes of data.
64 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=0.592 ms
64 bytes from 10.0.0.1: icmp_seq=2 ttl=64 time=0.534 ms

在每台主机上按 Ctrl-C 停止 ping,并再次关闭隧道。

讨论

这个简单测试展示了 OpenVPN 的工作原理。它在两台主机上创建了虚拟网络接口 tun0,然后通过该接口路由网络流量。这个简单测试不会创建加密连接,您可以从命令输出中的“******* 警告 *******: 所有加密和认证功能已禁用”消息中看到。

参见

13.3 设置 Easy Encryption with Static Keys

问题

您希望为 OpenVPN 创建和管理加密的简便方法。

解决方案

最简单的方法是使用共享的静态密钥。共享的静态密钥对于测试很有用,但不适合生产系统。(有关它们的缺点,请参阅讨论。)在这个示例中,您将学习如何创建和共享静态密钥,以及如何创建简单的服务器和客户端配置文件。

按照以下步骤操作:

  1. 创建并在两台主机之间分发共享的静态密钥。

  2. 创建服务器和客户端配置文件。

  3. 在两台主机上启动 OpenVPN,引用其配置文件。

在以下示例中,OpenVPN 服务器在server1上,客户端在client1上,新密钥为myvpn.key。您可以按照自己的喜好命名您的密钥。

在 OpenVPN 服务器上创建一个新目录来存储密钥,然后创建一个新的静态密钥:

$ sudo mkdir */etc/openvpn/keys*
$ sudo openvpn --genkey --secret *myvpn.key*

将密钥复制到客户端机器:

$ scp *myvpn.key* *client1:/etc/openvpn/keys/*
Password:
myvpn.key                         100%  636   142.7KB/s   00:00

创建服务器配置文件。示例为/etc/openvpn/server1.conf,您可以根据需要命名。为您的 OpenVPN 隧道使用不同的子网;例如,server1client1使用 192.168.43.0/24,因此示例使用 10.0.0.0/24 私有地址空间用于 VPN 隧道。服务器的tun地址为 10.0.0.1:

# server1.conf
dev tun
ifconfig *10.0.0.1 10.0.0.2*
secret */etc/openvpn/keys/myvpn.key*
local *192.168.43.184*

local是服务器的局域网 IP 地址。

在客户端机器上创建客户端配置文件。客户端的tun地址为 10.0.0.2:

# client1.conf
dev tun
ifconfig *10.0.0.2 10.0.0.1*
secret */etc/openvpn/keys/myvpn.key*
remote 192.168.43.184

确保 OpenVPN 守护程序在服务器或客户端上未运行:

$ sudo systemctl stop openvpn

在服务器和客户端上启动 OpenVPN:

[server1 ~] $ sudo openvpn */etc/openvpn/server1.conf*

[client1 ~] $ sudo openvpn */etc/openvpn/client1.conf*

当您在两台主机上看到“Initialization Sequence Completed”时,表示已建立连接。通过tun虚拟网络接口对每个主机进行 ping 测试:

[server1 ~] $ ping -I tun0 *10.0.0.1*
[client1 ~] $ ping -I tun0 *10.0.0.2*

在两台主机上按 Ctrl-C 关闭连接。

讨论

如果您在命令输出中看到“WARNING: INSECURE cipher with block size less than 128 bit (64 bit). This allows attacks like SWEET32. Mitigate by using a cipher with a larger block size (e.g. AES-256-CBC)”,请在服务器和客户端配置文件中进行以下条目更正:

cipher AES-256-CBC

使用静态密钥的最大问题是您失去了完美的前向保密性,因为您的静态密钥从不更改。如果攻击者找到方法来嗅探和捕获您的网络流量,然后捕获并破解您的加密密钥,攻击者可以解密他们捕获的所有内容,包括过去和未来的内容。OpenVPN 的 PKI 使用复杂的过程生成会话密钥,这些密钥不是持久的,而是定期更改。因此,最多,成功的攻击者一次只能解密一个会话的流量,然后必须重新开始。

另一个缺点是每个客户端需要不同的密钥,并在服务器上复制每个客户端的密钥。通过正确的 PKI,管理多个客户端的工作量更少且更安全。

参见

13.4 安装 EasyRSA 来管理你的 PKI

问题

你将使用 EasyRSA 来创建和管理你的公钥基础设施(PKI),并希望正确安装和设置它。

解决方案

你的 PKI 可以放在任何地方,不一定要在 OpenVPN 服务器上。你将在 PKI 上创建服务器和客户端证书,然后将它们复制到各自的主机上。

你可以安装 easy-rsa 软件包,或者从 EasyRSA 发布页面 获取最新版本。

Fedora 和 Ubuntu 将所有 EasyRSA 文件都放在 /usr/share/。这不是一个好的工作目录,并且会被系统更新覆盖。创建一个你控制且不需要 root 权限的新目录,比如我们优秀的示例用户 Duchess 创建的 /home/duchess/mypki

~$ mkdir *mypki*

在 Fedora 和 Ubuntu Linux 上,复制 /usr/share/easy-rsa 目录到你的新目录:

~$ sudo cp -r /usr/share/easy-rsa *mypki*

这将创建 mypki/easyrsa。检查你的权限;你应该是目录中所有内容的所有者和组所有者。

openSUSE 通过在 /etc/easy-rsa 中放置配置文件,将 easyrsa 命令放在 /usr/bin,并在 /usr/share/ 中放置文档和许可文件来进行适当的安装。你无需移动任何文件或担心权限问题。

讨论

创建和管理你的 PKI 不需要 root 权限。你可以把它放在任何你想要的地方,应与你的 OpenVPN 配置分开,可以是在单独的目录或另一台机器上。OpenVPN 的开发者建议将其放在一个不会暴露于互联网的、受保护良好的机器上。

参见

13.5 创建 PKI

问题

你已经安装了 EasyRSA(13.4 节),现在你想知道如何设置一个合适的公钥基础设施(PKI)。

解决方案

在安全地运行 OpenVPN 服务器时,一个合适的 PKI 至关重要。在这个示例中,我们将使用 EasyRSA 来创建 PKI,相比使用 openssl 命令,这大大简化了整个过程。创建 PKI 包括以下步骤:

  1. 创建你自己的证书颁发机构(CA)证书来签署服务器和客户端证书。这应该放在与你的 OpenVPN 服务器配置分开的目录中,或者在另一台机器上。

  2. 创建并签署 OpenVPN 服务器证书。

  3. 创建并签署客户端证书。

  4. 将服务器证书和客户端证书复制到各自机器上的 /etc/openvpn/keys 目录。(你可以创建一个不同于 keys 的目录。)

在以下示例中,所有命令均从 /home/duchess/mypki/ 目录运行。

切换到你的 PKI 目录,并运行命令来初始化一个新的 PKI:

~$ cd *mypki*
~/mypki $ easyrsa init-pki

init-pki complete; you may now create a CA or requests.
Your newly created PKI dir is: /home/duchess/mypki/pki

这将为您的新 PKI 创建一个空结构。接下来,构建您的新 CA。CA 创建并签署服务器和客户端证书。用强密码保护它,并创建您想要的新 CA 的通用名称:

~/mypki $ easyrsa build-ca
[...]
Enter New CA Key Passphrase:*passphrase*
Re-Enter New CA Key Passphrase:*passphrase*
[...]
Common Name (eg: your user, host, or server name) [Easy-RSA CA]: *vpnserver1*
[...]
CA creation complete and you may now import and sign cert requests.
Your new CA certificate file for publishing is at:
/home/duchess/mypki/pki/ca.crt
提示

如果您看到“RAND_load_file:Cannot open file:crypto/rand/randfile.c:98:Filename=/mypki/pki/.rnd”消息,请忽略它,因为它毫无意义。您可以通过找到 openssl-easyrsa.cnf 并在开头注释掉 RANDFILE 行来解决这个问题。

为您的 OpenVPN 服务器生成密钥对和证书签名请求。习惯上,不在服务器的私钥上设置密码。如果您希望可以省略 nopass 选项来保护您的服务器,请用密码保护。密码提供了强大的保护,但这意味着每次重启服务器时都需要输入密码:

~/mypki $ easyrsa gen-req *vpnserver1* nopass

Using SSL: openssl OpenSSL 1.1.1d  10 Sep 2019
Generating a RSA private key
.............................+++++
................................................................++++++
writing new private key to '/home/duchess/mypki/pki/private/vpnserver1.key.NYjr5y
c9kj'
[...]
Common Name (eg: your user, host, or server name) [*vpnserver1*]:

Keypair and certificate request completed. Your files are:
req: /home/duchess/mypki/pki/reqs/vpnserver1.req
key: /home/duchess/mypki/pki/private/vpnserver1.key

为客户端生成密钥对和证书签名请求。尤其是移动客户端的客户端私钥应该有密码保护:

~/mypki $ easyrsa gen-req *vpnclient1*

Using SSL: openssl OpenSSL 1.1.1d  10 Sep 2019
Generating a RSA private key
................+++++
....................................................................+++++
writing new private key to '/home/duchess/mypki/pki/private/vpnclient1.key.bicpOc
EC5S'
Enter PEM pass phrase:*passphrase*
Verifying - Enter PEM pass phrase:*passphrase*
[...]
Common Name (eg: your user, host, or server name) [*vpnclient1*]:

Keypair and certificate request completed. Your files are:
req: /home/duchess/mypki/pki/reqs/vpnclient1.req
key: /home/duchess/mypki/pki/private/vpnclient1.key

使用它们的通用名称签署请求。仅使用它们的名称;如果输入它们的路径会导致错误:

~/mypki $ easyrsa sign-req server *vpnserver1*
Using SSL: openssl OpenSSL 1.1.1d  10 Sep 2019

You are about to sign the following certificate.
Please check over the details shown below for accuracy. Note that this request
has not been cryptographically verified. Please be sure it came from a trusted
source or that you have verified the request checksum with the sender.

Request subject, to be signed as a server certificate for 1080 days:

subject=
    commonName                = vpnserver1

Type the word 'yes' to continue, or any other input to abort.
  Confirm request details: *yes*
Using configuration from /home/duchess/mypki/pki/safessl-easyrsa.cnf
Enter pass phrase for /home/duchess/mypki/pki/private/ca.key:
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName            :ASN.1 12:'vpnserver1'
Certificate is to be certified until Jan 27 20:09:12 2024 GMT (1080 days)

Write out database with 1 new entries
Data Base Updated

Certificate created at: /home/duchess/mypki/pki/issued/vpnserver1.crt

mypki $ easyrsa sign-req client *vpnclient1*
[...]
Certificate created at: /home/duchess/mypki/pki/issued/vpnclient1.crt

为服务器生成 Diffie-Hellman 参数;这需要一到两分钟。此命令必须在您的 OpenVPN 服务器上运行:

$ easyrsa gen-dh
Using SSL: openssl OpenSSL 1.1.1d  10 Sep 2019
Generating DH parameters, 2048 bit long safe prime, generator 2
This is going to take a long time
...........................................+...........
..........+............................................
[...]
DH parameters of size 2048 created at /home/duchess/mypki/pki/dh.pem

在您的服务器上也创建一个基于哈希的消息认证码(HMAC)密钥:

$ openvpn --genkey --secret ta.key

vpnclient1.keyvpnclient1.crtca.crtta.key 复制到 client1 上的 /etc/openvpn/keys

vpnserver1.keyvpnserver1.crtca.crtdh.pemta.key 复制到 server1 上的 /etc/openvpn/keys

当您签署了证书签名请求后,您可以删除所有的 *.req 文件。

表 13-1 应该帮助您记住文件的存放位置。

表 13-1. 服务器和客户端密钥位置

名称 位置 公共 私有
ca.crt 服务器和客户端 X
ca.key PKI 机器 X
ta.key 服务器和客户端 X
dh.pem 服务器 X
server.crt server X
server.key server X
client1.crt client1 X
client1.key client1 X
client2.crt client2 X
client2.key client2 X

讨论

什么是 Diffie-Hellman ?它是一种加密机制,允许两台主机创建和共享一个秘密密钥。一旦 OpenVPN 客户端和服务器相互验证,将生成额外的发送和接收密钥以加密会话。

HMAC 计算消息认证码。HMAC 验证消息的完整性和真实性。

easyrsa init-pki 创建一个新的 PKI,您还可以使用它来干净地删除和重建现有的 PKI。

您可以在任何地方设置您的 PKI,而 OpenVPN 的专家建议将其放在不直接连接到互联网且受到良好保护的机器上,防止任何不应该操作您的 PKI 的人员进行入侵。如果您的 CA 受到攻击,攻击者可以轻松渗透到您的网络中。显然,您必须有一种安全的方法来分发这些文件:USB 棒、scp 命令、从安全服务器下载的加密压缩包或通过电子邮件发送给用户。

查看您的 PKI 目录,了解所有这些项目的组织方式。

~/mypki $ ls */*
pki/ca.crt               pki/index.txt            pki/index.txt.old
pki/serial               pki/dh.pem               pki/index.txt.attr
pki/openssl-easyrsa.cnf  pki/serial.old           pki/extensions.temp
pki/index.txt.attr.old   pki/safessl-easyrsa.cnf  pki/ta.key

pki/certs_by_serial:
4954C26DB44106B20F1B9DA17CE515E5.pem  DA68CBE53E30923C9BCC3B9F1C5C9011.pem

pki/issued:
vpnclient1.crt  vpnserver1.crt

pki/private:
ca.key  vpnclient1.key  vpnserver1.key

pki/renewed:
certs_by_serial  private_by_serial  reqs_by_serial

pki/reqs:
vpnclient1.req  vpnserver1.req

pki/revoked:
certs_by_serial  private_by_serial  reqs_by_serial

签名请求文件扩展名为 .req,公钥为 .crt,私钥为 .key。密钥始终成对出现,公钥和私钥。

公钥加密,私钥解密

公钥加密,私钥解密。私钥必须受到保护,绝不能共享。公钥则是供共享使用。

单击文件管理器中的任何签名证书,以查看类似 Figure 13-1 的内容。这提供了大量信息:签署它的 CA、到期日期、序列号、指纹、签名等。

查看签名证书

图 13-1. 查看签名证书

或使用 openssl 命令读取它:

$ openssl x509 -noout -text -in *vpnserver1.crt*

证书是由 CA 签署的请求,其中包含公钥和 CA 的数字签名。请求包含公钥和对应私钥的数字签名。通过比较它们,您可以看到所有这些内容。

EasyRSA 最初是 OpenVPN 的一部分,后来作为独立项目分离出来。如果您习惯使用 OpenSSL 管理 PKI,您会欣赏 EasyRSA 如何简化该过程。

参见

13.6 自定义 EasyRSA 默认选项

问题

EasyRSA 的默认设置并非您想要的,您想知道如何更改它们。

解决方案

查找您的 vars.example 文件,这是 EasyRSA 的一部分。将此文件的副本另存为 vars,保存在本章示例中的 PKI 目录中(/home/duchess/mypki/pki/)。vars 文件定义了创建和签署证书的默认设置。

该文件有很好的注释。在 # DO YOUR EDITS BELOW THIS POINT 行下进行编辑。所有以 set_var 开头的内容均可编辑。取消注释对您更改的所有内容。

例如,默认配置仅使用通用名称,而不是完整的 org 配置。以下示例创建了传统的 org 配置:

set_var EASYRSA_DN      "org"

set_var EASYRSA_REQ_COUNTRY    "*US*"
set_var EASYRSA_REQ_PROVINCE   "*Oregon*"
set_var EASYRSA_REQ_CITY       "*Walla Walla*"
set_var EASYRSA_REQ_ORG        "*MyCo*"
set_var EASYRSA_REQ_EMAIL      "*me@example.com*"
set_var EASYRSA_REQ_OU         "*MyOU*"

当您使用 org 配置时,请记住在运行 easyrsa build-ca 时输入您的通用名称,否则您将被困在默认的 Easy-RSA CA 中。

Common Name (eg: your user, host, or server name) [Easy-RSA CA]:*myCN*

讨论

根据您自己的政策和偏好使用 cnorg;这对服务器操作没有影响。

查看 Recipe 13.10 了解如何加固您的服务器。

参见

13.7 创建和测试服务器和客户端配置

问题

现在您已经有了一个完整的 PKI,您想知道如何配置您的 OpenVPN 服务器和客户端。

解决方案

在这个示例中,我们将在同一子网上的两台主机 server1client1 上设置一个简单的测试实例。这是测试服务器配置的一个简单方法,而不必处理路由和越过互联网网关的麻烦。

下面的示例是一个简单的 OpenVPN 服务器配置。请注意,只要在配置文件中正确引用,您可以将服务器密钥存储在服务器的任何位置:

# *vpnserver1.conf*
port 1194
proto udp
dev tun
user nobody
group nobody

ca /etc/openvpn/keys/ca.crt
cert /etc/openvpn/keys/*vpnserver1.crt*
key /etc/openvpn/keys/*vpnserver1.key*
dh /etc/openvpn/keys/dh.pem
tls-auth /etc/openvpn/keys/ta.key 0

server *10.10.0.0 255.255.255.0*
ifconfig-pool-persist ipp.txt
keepalive 10 120
persist-key
persist-tun
tls-server
remote-cert-tls client

status openvpn-status.log
verb 4
mute 20
explicit-exit-notify 1

一个客户端配置示例:

# *vpnclient1.conf*
client
dev tun
proto udp
remote *server1* 1194

persist-key
persist-tun
resolv-retry infinite
nobind

user nobody
group nobody
tls-client
remote-cert-tls server
verb 4

ca /etc/openvpn/keys/ca.crt
cert /etc/openvpn/keys/*vpnclient1.crt*
key /etc/openvpn/keys/*vpnclient1.key*
tls-auth /etc/openvpn/keys/ta.key 1

如果服务器正在运行,请停止您的 OpenVPN 服务器:

$ sudo systemctl stop *openvpn@.openvpn1.service*

使用 openvpn 命令在两台主机上启动 OpenVPN:

$ sudo openvpn */etc/openvpn/vpnserver1.conf*
Tue Feb 16 16:50:49 2021 us=265445 Current Parameter Settings:
Tue Feb 16 16:50:49 2021 us=265481   config = '/etc/openvpn/vpnserver1.conf'
[...]
Tue Feb 16 16:50:49 2021 us=270212 Initialization Sequence Completed

$ sudo openvpn */etc/openvpn/vpnclient1.conf*
Tue Feb 16 16:56:22 2021 OpenVPN 2.4.3 x86_64-suse-linux-gnu [SSL (OpenSSL)]
[LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] built on Jun 20 2017
Tue Feb 16 16:56:22 2021 library versions: OpenSSL 1.1.1d  10 Sep 2019, LZO 2.10
Enter Private Key Password: *******
[...]
Tue Feb 16 16:56:26 2021 Initialization Sequence Completed

以上配置都是正确的,您已经成功建立了连接。在两台主机上按下 Ctrl-C 停止连接。

讨论

OpenVPN 安装时会附带一批示例配置文件,存放在 /usr/share/doc/openvpn/ 目录下。这些配置文件有详细注释,是很好的参考资料。虽然有数十个选项可供选择,但在实际应用中只会用到其中几个。在本文的示例中,有几点需要注意。

port 1194 是默认端口,proto udp 优先于 proto tcp。UDP 更安全,可以一定程度上防止端口扫描和拒绝服务攻击,同时提供更高的吞吐量和更低的延迟。TCP 在远程用户使用像酒店和咖啡店这样有限制的公共网络时很有用。

tls-auth /etc/openvpn/keys/ta.key 在服务器上必须始终为 0,在客户端上必须为 1。tls-auth 强制使用 TLS 连接。

verb 4 是日志记录级别。1 是最低级别,9 是最详细的。在确认一切设置正确之前,请将其保持在 4-6。当您从命令行启动 OpenVPN 时,将会看到大量消息。

有很多过时的指南建议使用 comp_lzo 选项来启用压缩。不必费心,因为它并没有提供太多好处。大多数流量要么已经被压缩,要么已经加密且无法被压缩。压缩还存在至少一种由于压缩引起的漏洞,VORACLE。

另请参阅

13.8 使用 systemctl 控制 OpenVPN

问题

您希望像管理其他守护程序一样管理 OpenVPN 守护程序,使用 systemctl,但您看不到 OpenVPN 单元文件。或者,您看到一个看起来奇怪的单元文件,如 openvpn-server@.service,当您尝试启动它时,它会抛出错误消息。

解决方案

双引号符@创建了参数化单元文件。这意味着您可以通过调用不同的配置文件轻松创建同一服务的多个单元文件。例如,假设您的服务器配置文件是/etc/openvpn/austin.conf。您的单元文件是openvpn@austin.service,使用systemctl创建:

$ sudo systemctl enable openvpn@austin
Created symlink /etc/systemd/system/multi-user.target.wants/openvpn@austin.service
→ /usr/lib/systemd/system/openvpn@.service.
Created symlink /etc/systemd/system/openvpn.target.wants/openvpn@austin.service
→ /usr/lib/systemd/system/openvpn@.service.

请注意,不要在 OpenVPN .conf文件的文件扩展名中输入文件扩展名。现在您可以像任何其他服务一样使用systemctl来控制您的 OpenVPN 守护程序。

讨论

这是一种相当巧妙的方法,使您能够在无需编写多个单元文件的情况下创建多个配置。您可以“参数化”任何 systemd 单元文件。

您可以在同一台计算机上同时运行多个隧道。每个配置需要一个不同的tun设备,例如tun0tun1tun2,每个隧道需要一个不同的子网和一个不同的 UDP 端口。使用不同的配置文件及其对应的参数化单元文件控制所有这些隧道。

参见

13.9 通过.ovpn 文件更轻松地分发客户端配置

问题

设置客户端需要相当多的工作,您想知道是否有更快的方法,使用户可以自行完成而无需太多帮助。

解决方案

将客户端配置和密钥捆绑到扩展名为.ovpn 的单个文件中。所有客户端,包括 Linux、Windows、macOS、iOS 和 Android,都可以导入这些文件。

首先创建用户的证书,然后按照此模板创建他们的.ovpn 文件。此示例基于 Recipe 13.7 中的示例。而不是链接到所有他们的证书,请将它们复制到此文件中。所有证书都是明文的,因此您只需将 BEGIN/END 部分复制到.ovpn 文件中:

#*vpnclient1.ovpn*
client
dev tun
proto udp
remote server2 1194

persist-key
persist-tun
resolv-retry infinite
nobind

user nobody
group nobody
tls-client
remote-cert-tls server
verb 4

# ca.crt
<ca>
-----BEGIN CERTIFICATE-----
MIIDSDCCAjCgAwIBAgIUD2UxdEwgvhhr0zq5fAxIDIueB2EwDQYJKoZIhvcNAQEL
BQAwFTETMBEGA1UEAwwKdnBuc2VydmVyMTAeFw0yMTAyMjExODU1MjNaFw0zMTAy
MTkxODU1MjNaMBUxEzARBgNVBAMMCnZwbnNlcnZlcjEwggEiMA0GCSqGSIb3DQEB
AQUAA4IBDwAwggEKAoIBAQDpQJo+Izt8v0zriSWwrChc1tnVj3E3h3XuyEHub7hj
y4bMu2PqKByFNr+iikEF3u0d6HrCRSDKt1BcLzL3TsTJ/hJBHAlTyqEgVce1knjL
2g9NnDbekRtJSJCxS9j+RWtP43Xdg5edb5hTCZqdNFHD8oNuSMGFBbHN4oi9eDXl
rvyVHJe+UkI1Ow6mW0+ln/IoKNFPovz+l+ds3fJ5+UHe2TaQPQc7tGZ33j7wfJQd
es8baFdK+lnmGdUOrW9BQE6ReMSezkz6dKdIZdy7jEs6xoflOzyWlgydmnkAvLnx
MBQDgDUbc5MuooVMAWa4yhtz0B9ZmdJDb8jzHDpTPqdRAgMBAAGjgY8wgYwwHQYD
VR0OBBYEFF8KPhl1xxV0110JiBs5iUEPoJ1IMFAGA1UdIwRJMEeAFF8KPhl1xxV0
110JiBs5iUEPoJ1IoRmkFzAVMRMwEQYDVQQDDAp2cG5zZXJ2ZXIxghQPZTF0TCC+
GGvTOrl8DEgMi54HYTAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjANBgkqhkiG
9w0BAQsFAAOCAQEAMnRLz3CBApSrjfUKsWYioNGQGvh77Smh/1hPGIu4eEldQSmZ
Aj7qclEaORdBxmqrVtA3Z9cX1L0xFrg14nLyddmuWHG3ZChc5ZMpYtD2YpOH265B
FFjDp96vK13dpixWKrVpvakLCCA4EvnC8CEjbm0oNFiCgSwKAoJFCcUzwC33swsU
B2w5/iT6CZKuKhSmET1IDpG8krGC/Ib2GNAS0szMI94P0ajZgVznMcXOJ7gUg4rM
sEB8OzM6GBEZTqbAa9uVMZnOZvZA5jGIbBuelUo0bqGdAyx2B68zzuL//qvsHsvw
kZCyKIaXH0NBV7vexMKWcwFLLBzWizFQbbFpFA==
-----END CERTIFICATE-----
</ca>

# vpnclient1.cert
<cert>
-----BEGIN CERTIFICATE-----
MIIDVjCCAj6gAwIBAgIQLhO4FTrqN5WZiQETULAwnzANBgkqhkiG9w0BAQsFADAV
MRMwEQYDVQQDDAp2cG5zZXJ2ZXIxMB4XDTIxMDIyMTE4NTYzM1oXDTI0MDIwNjE4
NTYzM1owFTETMBEGA1UEAwwKdnBuY2xpZW50MTCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBALUFYXwk6JW/hRtoMs0Ug5jMcWXsjMUsCz8L8CeXNOs3wQrf
YBWF1TYCLPd2/vwXsvbqCE85IZwjsJ5mEx9YgQ5M1teDkLZqBn8y7VIyDAAU8RsN
NcrnpeMDV0LgZIBeUrHi4ZTooaw4FdJ5BBYRHR1APVaaHDWx59ohJuBDpriWhvWk
lWX0rpSJltXriIOCzky/yEwfw6ah5jWaTgfe41fXq8j3lx2IbgIL7I4//jhC6JYz
N7huTdT2uB2MUbYX0XWBffMG8wcBZtMI2XryZmPvFYWP7N5nZZsBXkLz/UngAu3k
jkYJOnJy/hdOFLN/yXj7VFydmivUSeekdjjxyAECAwEAAaOBoTCBnjAJBgNVHRME
AjAAMB0GA1UdDgQWBBSnLIQoTPLyECbJHfgYBHvQpcmfgzBQBgNVHSMESTBHgBRf
Cj4ZdccVdNddCYgbOYlBD6CdSKEZpBcwFTETMBEGA1UEAwwKdnBuc2VydmVyMYIU
D2UxdEwgvhhr0zq5fAxIDIueB2EwEwYDVR0lBAwwCgYIKwYBBQUHAwIwCwYDVR0P
BAQDAgeAMA0GCSqGSIb3DQEBCwUAA4IBAQBaBpYZXVYUzOcXOVSaijmOZAIVBTeJ
meQz9xBQjqDXaRvypWlQ1gQtO8WnK9ruafc1g/h7LtvqtiALnGiJ0NbshkH8C1KE
yen46UCau5B/Xi0gA7FoPildvYdKSn/jI6KySCsplubjnJK9H/6DjAcEuqFLcsaY
5vpKQGP9Vl7H7hEVs4f1aory1T4Ma/bdXEOqgzHmIARLmxYeJm90sUT/n7e7VXfy
fILZ+8D1fMxCbeQRBkg1e8wJfgEbMRY9aGGt1qAs9gkm9RPelGB18v4iCbyebv3X
4hVHmfjcixdbWiABC7yq/gisooQ0robW/92dgemcwO0awHZX+opNBgwr
-----END CERTIFICATE-----
</cert>

# vpnclient1.key
<key>
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIFHDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQInjFvz5a4mY8CAggA
MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECNsxQXxvMpN0BIIEyEZdgFwPnGup
vyhywXR6l6ihvHK2GRczIgH0mFIiwQDgDjZj2YsEnvSA/P3MHplkU/bgv9DJ5j2T
C5wPDmGN4yG1boHx9BQKbXqxGwdz/UcHwmNKur9qnSFrSVEvMDwvum+rmzWuKykf
gkKKBCT1JZ2DWKtjjDNYG9qhBn3S2zYVq311dDuLbBcruvo1UL031sDDYWTpVuuf
zZc0ozng0Nzb35bNkG6Ib+LYLzJi4stxzw0DTFl52lKv++R6xhmqb81IJE3vBs4H
DOutkYfifO1eGqEKksPQRl8n03UVkOtB5pH8VdQeLqEBBaq3qeIfU6FkH9XrPR/E
8VOg9BNpbyuUW7bQu0MzuJ8Ofkjy9K+HHdwFtGPyOatkeaXT/qcKVMvzWcbr8bPc
VncavzXdzo0Sb8FigsKYU1lNjgo00Phd3m0AOfptrweK6ucBds5SmqNrUFXiQ2JA
Ms3LUw4CXBBgvdu5TsA2xLGysip0RPKLyTnUPGnXxbBaaHMv8Jz3XRCrWgZbtAE3
XhE9fKw+ZMEP+2jpC/1mjN/N9VuJfYZEhgA84wzYMu6pt3zPkWZqR6yGTDFEDhvh
OAZYEpqrhe++nxDpuQlpCCl4IndSg9L9oX1ydrvPNHGbRVztd3+r9wr4Ub3fJ1g/
9ckCdanohEymKbjw34HEMmdx+fn5k2T9bLnl8fsYtcESkg04ChON3yOnZFKl6chT
BQ9X2Qmeg7FoawWiUY5o+7OHNKL7QpRt4jXPbXNuXFK9EYvuRzUqubLhL5DdmjuO
Se1vvZg7fT4C8qjYsoCa18idA00EN3ePFFf9AssHCoVW92GiUTTKG+qURCjtNtG6
dnPvxiSf98OBkkjeX3ni0cKdfMGoQTSdEy5GexvfRMF5HJrGO+CWXmqSBsuIlPUe
quqCsPmpaT2Ws/0UU9cKe4qaKjTL7CghtFmUEhH7t6Cd41Ki9gKi33j3541l9w7l
J1bgca4rRUCecp2BPF3IjJc/RnTvHkbUK4mDX9s8xJhYf9WE6JYsk3NBSNNIj/9G
FMJlo71x8H3OAdFzRN5bjV797HByZ+YidZIgGAx2dSko3PQPy7RSxdmzFbxfUvzj
9jcYEu+V9unbtDK2qZ9I+LqXGE+EXjPBui40IWp8XIYNlSLn2qgroH079lXhXKBY
+DzcBzyT7GTX2QeYE+yqqPRIFWHnbnsnD6dMnAa46h+Si+f5sq33rfRsF7UpK4gV
IhzFkncCM47/Taqi0OY04Q40LuSCDjmjFL+VzZOsAtWGRNYNzIgniThEehElJwfI
ErzClcVptjhtCer8BPuO7YaMIHk1hKecHFqw3RrimWzroL1iu9Q29m2oM+bVc6mD
we6r+t8JbaAFxoHBK4i6M0rcdJPICxDTIOjPC3Fg/MeqiCi7F0DFZvXwPGRD+0Of
MBnsDplEUjK06jbE5BjGQ7n7P+dwDxyp/aVO4CfX7ZOco6h9r3b6nqlzPVNE9erw
kS7WwT/TWraw/sfIO9sNSgle7PoRh2s/w/oGVhC6ymlMdXe+mhMzHFnGEbBRh2Rd
kd/EdYNubHg0k9+RLTwbgwZ+176cIJyOpqaoJGv0bsKM8X26Pk/fkyF6xgdQYQOx
8i9Whea8OjUOQAcgc7gUyA==
-----END ENCRYPTED PRIVATE KEY-----
</key>

# ta.key
<tls-auth>
-----BEGIN OpenVPN Static key V1-----
4eb35b44d1d8a82cfa51af394d4f58f3
69bf8fe8c0a0a032f38b0ee104889628
8a5dc89486736b39d64ad3c6831bf9ba
9f3f96c3307d322a5bf055b9bc3bfa74
929faf361c14de97445f5927794264bb
e3f71c925f2236cfb0109ecfd6406cef
857dfb39783a09ecd56d3cf09ebbc853
0f43b1c787f0db99dbecabcd2090cfbb
54c86d8102a5430fd6a7f37ab5ce8ed9
f6bec8984bde4267f78913ff702dd396
a205b6be9e7ab41cf1ebad3953c27c7c
f3b435345e02aede049ef7c9f1c2704f
2ed91110ccb19d0d3bd46a00f54c73e2
07b31160cdc54c3f5a7989bb999ac5f3
89c6de7e79fc93399924a8d298eab462
231234e690c319d5cbd832788f0dbcfb
-----END OpenVPN Static key V1-----
</tls-auth>

现在您只需要向客户分发一个文件。 (请参阅 Recipe 13.1 了解如何为 Linux、macOS、Windows、iOS 和 Android 客户端安装所需内容。)

在 Linux 中导入新的.ovpn文件的简便方法是使用 NetworkManager。打开“VPN Connections” → “Add a VPN connection”。这将打开“选择 VPN 连接类型”。选择“导入保存的 VPN 连接”,点击“创建”,然后在文件选择器中找到您的.ovpn文件。在“通用”和“VPN”选项卡上查看设置。

在“通用”选项卡上,请确保未选中“所有用户都可以连接到此网络”。这是一个简单但重要的安全措施,要求每个用户都有自己的独立 OpenVPN 配置。

在 VPN 选项卡上,请注意 NetworkManager 将内联证书转换为.pem 文件(Figure 13-2)。这是正常的,不是错误。您可以将这些与原始文件进行比较;单击右侧的小文件夹图标即可查看转换后的文件存储位置。

将 .ovpn 客户端配置文件导入 NetworkManager

图 13-2. 将 .ovpn 客户端配置文件导入 NetworkManager

对于所有其他客户端,该过程类似。按照他们的说明操作,如果一切顺利,您的客户端将在几分钟内运行起来。

NetworkManager 导入功能也适用于不是内联的客户端配置文件,例如第 13.7 节。在这种情况下,证书不会被转换,它们保留其原始文件名。

如果只有 Linux 客户端,则内联文件可能具有 .conf 扩展名。

另请参阅

13.10 加固您的 OpenVPN 服务器

问题

您想了解一些使您的 OpenVPN 更安全的选项。

解决方案

OpenVPN 的默认设置相当不错,但它们设计用于更广泛的兼容性。您可以做一些改动,使您的服务器更强大。

下面的示例适用于服务器和客户端配置文件。这些选项最大化了 TLS 的效果。所有低于 TLS 1.2 的 SSL 和 TLS 协议均已废弃,不应允许。仅接受 TLS 1.2 或更高版本:

tls-version-min 1.2
tls-version-max 1.3 or-highest

使用更强大的数据通道密码,并通过禁用密码协商来强制使用它:

AES-128-GCM
ncp-disable

TLS 1.3 有许多变化,因此您需要为 TLS 1.2 和 1.3 配置两种不同的配置文件。这些都是更强大和更高效的加密密码:

# TLS 1.3
tls-ciphersuites TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256
# TLS 1.2
tls-cipher TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256:TLS-ECDHE-RSA-
WITH-CHACHA20-POLY1305-SHA256:TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256:
TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256

使用椭圆曲线 Diffie-Hellman 瞬态(ECDHE)代替旧的静态 Diffie-Hellman 密钥。您不必像在第 13.5 节中创建 ta.key 那样操作:

dh none
ecdh-curve secp384r1
# use tls-server on the server, tls-client on the client
tls-server

在服务器配置中添加 float 选项,允许客户端在不丢失连接的情况下漫游到不同的网络,只要它们通过所有其他身份验证测试。

opt-verify 选项仅在服务器配置中检查服务器和客户端设置的兼容性,并断开不匹配的客户端。opt-verify 检查 dev-type, link-mtu, tun-mtu, proto, ifconfig, comp-lzo, fragment, keydir, cipher, auth, keysize, secret, no-replay, no-iv, tls-auth, key-method, tls-servertls-client

查看讨论以获取完整的示例配置。

讨论

将这些增强功能全部整合到服务器配置中:

# *vpnserver1.conf*
port 1194
proto udp
dev tun
user nobody
group nobody

ca /etc/openvpn/keys/ca.crt
cert /etc/openvpn/keys/*vpnserver1.crt*
key /etc/openvpn/keys/*vpnserver1.key*

server 10.10.0.0 255.255.255.0
ifconfig-pool-persist ipp.txt
keepalive 10 120
persist-key
persist-tun
tls-server

remote-cert-tls client
verify-client-cert require
tls-cert-profile preferred
tls-version-min 1.2
tls-version-max 1.3 or-highest

float
opt-verify
AES-128-GCM
ncp-disable
dh none
ecdh-curve secp384r1

# TLS 1.3
tls-ciphersuites TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256
# TLS 1.2
tls-cipher TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256:TLS-ECDHE-RSA-
WITH-CHACHA20-POLY1305-SHA256:TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256:
TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256

status openvpn-status.log
verb 4
mute 20
explicit-exit-notify 1

一个示例客户端配置,使用内联文件格式(第 13.9 节):

# *vpnclient1.conf*
client
dev tun
proto udp
remote *server1* 1194

persist-key
persist-tun
resolv-retry infinite
nobind

user nobody
group nobody
tls-client
remote-cert-tls server
verb 4

# Using inline keys
# ca.crt
<ca>
[...]
</ca>

# *client.crt*
<cert>
[...]
</cert>

# *client.key*
<key>
[...]
</key>

tls-version-min 1.2
tls-version-max 1.3 or-highest
AES-128-GCM
ncp-disable
dh none
ecdh-curve secp384r1

# TLS 1.3 encryption settings
tls-ciphersuites TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256
# TLS 1.2 encryption settings
tls-cipher TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256:TLS-ECDHE-RSA-WITH-
CHACHA20-POLY1305-SHA256:TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-RSA-
WITH-AES-128-GCM-SHA256

status openvpn-status.log
verb 4
mute 20
explicit-exit-notify 1

这些选项加强了客户端和服务器之间的认证,并强制使用 TLS 1.2 及更高版本。如果您想知道使用哪些密码和密码套件,可以向专家询问。您可以进一步限制您的设置。例如,禁止用户保存密码,增加客户端-服务器认证的限制,使用 SELinux 或使用 chroot。这些都是此处未涵盖的高级主题。

另请参阅

13.11 配置网络

问题

您的 OpenVPN 服务器正在运行,所有连接测试都正常工作,现在您需要知道如何设置您的网络,以便远程客户端可以找到您的服务器并正确路由流量。

解决方案

没有一种适合所有情况的解决方案。配置您的网络必须考虑到您的局域网设置,无论是连接个体客户端还是链接网络,IPv4、IPv6,您的互联网网关设置以及更多因素。请参阅 Jan Just Keijser 的优秀著作 OpenVPN Cookbook,第二版(O'Reilly),以找到您需要的答案。本书涵盖了 TUN 与 TAP、Windows 客户端、PAM 和 LDAP、IPv6、路由以及站点间配置。

讨论

网络是运行任何服务器的最具挑战性的部分,尤其是一个重要的安全服务器。学习和确保正确配置网络是非常值得的。OpenVPN 文档也有很多关于网络的有用信息。

参见

第十四章:使用 firewalld 构建 Linux 防火墙

本章介绍使用 firewalld 构建主机防火墙的基础知识。不同的主机有不同的需求。例如,服务器必须允许各种类型的传入连接请求,而不运行服务的个人电脑则不需要接受任何连接请求。连接多个网络的笔记本电脑需要动态防火墙管理。

firewalld 概述

像所有防火墙一样,firewalld 具有非常多的功能。我们主要学习如何使用 firewalld 的zones来控制进入系统的流量。区域是一种信任级别的容器;例如,某些区域允许各种传入连接请求,而某些区域则非常限制。系统上的每个网络接口只能分配一个区域,并且一个区域可以分配给多个接口。

需要的网络知识

理解的最重要的网络概念包括端口、服务、TCP、UDP、端口转发、伪装、路由和 IP 地址。当您理解这些概念时,您将了解如何配置防火墙。如果您需要关于计算机网络的指导,请参考 Gordon Davies 的Networking Fundamentals(Packt 出版社)或 Doug Lowe 的Networking All-in-One For Dummies第 7 版(For Dummies)。如果您有O’Reilly Learning Platform 订阅,您将找到大量优质信息。

传统的 Linux 防火墙建立在 Linux 内核的netfilter数据包过滤框架和用于创建和管理规则表的iptables软件之上,用于过滤传入和传出的网络流量。

时代变迁,iptables正逐渐被诸如ufw(简易防火墙)、nftables(Netfilter 表)、firewalld(防火墙守护程序)等新的规则管理器所取代。与 iptables 和 nftables 类似,firewalld 利用规则表来管理流量过滤。它提供了命令行界面和一个漂亮的图形界面firewall-config。firewalld 同时是 iptables 和 nftables 的前端。nftables 是对 iptables 的重大改进,并计划成为 firewalld 的默认后端,但在某些 Linux 发行版中,iptables 仍然是默认选项。您可以在/etc/firewalld/firewalld.conf中使用FirewallBackend选项设置您的首选后端(Recipe 14.4)。

firewalld 附带预定义的一组规则集,称为zones,用于不同的用例,例如不运行服务的机器、运行服务的机器,以及同一机器上不同网络接口的不同区域。您可以编辑这些区域以满足自己的需求。

firewalld 区域管理services,这些是针对常见服务(如 ssh、imaps 和 rsync)的配置。大多数预定义服务仅包括标准端口分配。您可以根据需要编辑这些服务,并创建自己的自定义区域。

firewalld 与 NetworkManager 集成,因此您无需担心管理动态连接,比如当您随身携带笔记本电脑并连接到不同的网络时。

NetworkManager 服务

自 2004 年以来,NetworkManager 一直是 Linux 的重要组成部分。NetworkManager 取代了一堆繁琐的网络客户端工具,并管理着你的所有网络接口和网络连接。如果你对 NetworkManager 不熟悉,请参阅GNOME NetworkManager

如果您在商业托管服务上运行公共服务器,则您的防火墙设置取决于您的服务提供商支持的内容。保护公共服务器(例如 Web 服务器和在线商店),无论是远程托管还是位于您自己的数据中心,都需要超出本书范围的大量技能和关注。请进行深入学习和培训,或者聘请专家。

防火墙的工作原理

曾几何时,Ubuntu Linux 没有随附防火墙,因为默认安装没有公共服务,因此没有监听的网络端口。其理由是没有监听端口就没有攻击点。幸运的是,这个决定在后来的版本中被改变,因为用户会做出更改,即使是最专业的用户也会犯错误,而攻击者总是在发现新的漏洞。安全是一个多层次的过程。

让我们来看看防火墙的工作原理。基本原则是拒绝一切,只允许必要的。

网络服务,比如 SSH 服务器,需要打开一个网络端口以允许远程用户登录。你在允许其他人进入你的系统。sshd 的默认端口是 TCP 端口 22。你可以使用netstat命令查看系统上所有监听的端口。以下是显示 SSH 端口的片段:

$ sudo netstat -untap | sed '2p;/ssh/!d'
Proto Recv-Q Send-Q Local Address  Foreign Address  State   PID/Program name
tcp        0      0 0.0.0.0:22     0.0.0.0:*        LISTEN  1296/sshd: /usr/sbi
tcp6       0      0 :::22          :::*             LISTEN  1296/sshd: /usr/sbi

这个例子显示没有活动连接,因为外部地址字段都是零,并且状态是 LISTEN。sshd在所有网络接口和所有 IP 地址上监听传入的 IPv4 和 IPv6 连接,TCP 端口为 22。IP 地址和端口号的组合是一个地址,告诉 Linux 内核将 SSH 数据包发送到哪里。

这个例子显示了一个活动的 SSH 连接,状态为 ESTABLISHED。它列出了远程机器连接的本地地址和端口,以及远程机器的外部地址和端口(为了清晰起见,已删除了 Recv-Q 和 Send-Q 列):

$ sudo netstat -untap | sed '2p;/ssh/!d'
Proto  Local Address     Foreign Address      State       PID/Program name
tcp    0.0.0.0:22        0.0.0.0:*            LISTEN      1296/sshd: /usr/sbi
tcp    192.168.1.97:22   192.168.1.91:56142   ESTABLISHED 13784/sshd: duchess
tcp6   :::22             :::*                 LISTEN      1296/sshd: /usr/sbi

有几种方法可以控制哪些 TCP/IP 数据包可以访问特定的 IP 地址和端口。大多数服务器都有配置选项,只监听特定的网络接口或 IP 地址,并接受来自特定地址和地址范围的请求。防火墙添加了额外的控制,同时使用防火墙和服务器配置是最佳实践。

网络端口和编号

Linux 系统上有 65536 个可能的网络端口,编号为 0-65535,其中许多端口保留用于特定服务。0 被保留且未使用。您可以在每个 Linux 上的 /etc/services 文件中看到所有这些信息。请参阅IANA 服务名称和传输协议端口号注册表获取完整的官方列表。

端口编号范围的组织方式如下:

  • 0-1023 称为众所周知的端口。这些是常见服务的系统端口,例如 FTPS(安全文件共享)、SSH(安全远程登录)、NTP(网络时间协议)、POP3(电子邮件)、HTTPS(加密的 Web 服务器)等。

  • 1024-49151 是注册端口,用于额外的服务。

  • 49152-65535 是临时端口,也称为私有端口和动态端口。这些由您的系统用于与远程服务完成连接。例如,在您进行网页浏览时,netstat 显示如下(已删除 Recv-Q 和 Send-Q 列以增加清晰度):

$ sudo netstat -untap
Proto  Local Address         Foreign Address    State        PID/Program name
[...]
tcp    192.168.43.234:50586  72.21.91.66:443    ESTABLISHED  2798/firefox
tcp    192.168.43.234:38262  52.36.174.147:443  ESTABLISHED  6481/chrome
tcp    192.168.43.234:53232  99.86.33.45:443    ESTABLISHED  2798/firefox
[...]

这说明了来自您的计算机的出站请求的响应。当您访问网站时,您发起连接请求,远程 Web 服务器将响应发送到您系统上的临时网络端口。列表中的第一个连接连接到示例本地计算机的 IP 地址 192.168.43.234,端口 50586。外部地址是远程服务器的 IP 地址和端口。状态 ESTABLISHED 表示它已连接到另一台计算机。会话结束后,在关闭 Web 浏览器后,端口 50586 被释放并准备再次使用。

临时端口不是服务的监听端口。与临时端口的连接是临时的,仅作为回复您的计算机发出的出站连接请求(例如访问网站)。防火墙可以阻止临时端口,但这样您将无法访问计算机外的主机或站点。

14.1 查询当前运行的防火墙

问题

您需要知道您的 Linux 系统正在使用哪种防火墙。

解决方案

从您特定的 Linux 发行版文档开始,因为大多数 Linux 发行版都会安装防火墙。最常见的三种是 iptables(Internet Protocol tables)、ufw(Uncomplicated Firewall)和 nftables(Netfilter tables)。这三种都管理 netfilter 框架上的过滤规则,netfilter 是 Linux 内核的一部分。

然后查看 systemd 说了什么。此示例显示 nftables 正在运行:

$ systemctl status nftables.service
    ● nftables.service - Netfilter Tables
     Loaded: loaded (/usr/lib/systemd/system/nftables.service; disabled; vendor>
     Active: active (exited) since Sat 2020-10-17 13:15:05 PDT; 4s ago
       Docs: man:nft(8)
    Process: 3276 ExecStart=/sbin/nft -f /etc/sysconfig/nftables.conf (code=exi>
   Main PID: 3276 (code=exited, status=0/SUCCESS)
   [...]

这显示 firewalld 正在运行:

$ systemctl status firewalld.service
● firewalld.service - firewalld - dynamic firewall daemon
Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; vendor>
     Active: active (running) since Sat 2020-10-17 12:36:20 PDT; 37min ago
       Docs: man:firewalld(1)
   Main PID: 775 (firewalld)
      Tasks: 2 (limit: 4665)
     Memory: 40.9M
     [...]

此示例检查 ufw 并显示它已安装但未激活:

$ systemctl status ufw.service
● ufw.service - Uncomplicated firewall
     Loaded: loaded (/lib/systemd/system/ufw.service; disabled; vendor preset:
enabled)
     Active: inactive (dead)
       Docs: man:ufw(8)

如果其中任何一个未安装,您将看到相关消息。

您可以移除 ufw 和 nftables,或者将它们掩盖,使其无法启动:

$ sudo systemctl stop ufw.service
$ sudo systemctl mask ufw.service

$ sudo systemctl stop nftables.service
$ sudo systemctl mask nftables.service

讨论

最好只运行一个防火墙,除非您喜欢解决冲突的防火墙规则。

参见

14.2 安装 firewalld

问题

您需要在 Linux 系统上安装 firewalld。

解决方案

如果您的系统没有安装 firewalld,请安装 firewalld 软件包,并安装 firewall-config 以获得良好的图形界面。

讨论

到目前为止,主要的 Linux 发行版都幸运地使用相同的软件包名称,firewalldfirewall-config

firewalld 的启动方式可能会因 Linux 发行版的不同而有所不同。必须运行它才能创建和测试规则。

如果可能,请在完成初始 firewalld 配置之前禁用您的计算机网络连接。通过点击 NetworkManager 小程序来断开网络连接,默认情况下大多数 Linux 发行版都安装了它(图 14-1)。

断开网络连接。

图 14-1. 使用 NetworkManager 断开网络连接

或使用 nmcli 命令。以下示例查找并断开 WiFi 连接。在您的命令中使用 CONNECTION 名称:

$ nmcli device status
DEVICE  TYPE  STATE        CONNECTION
wlan0   wifi  connected    ACCESS_POINTE

$ nmcli connection down ACCESS_POINTE
Connection 'ACCESS_POINTE' successfully deactivated
(D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/4)

恢复连接:

$ nmcli connection up ACCESS_POINTE
Connection successfully activated
(D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/7)

使用 systemd 正常管理 firewalld。以下是命令:

  • systemctl status firewalld.service

  • sudo systemctl enable firewalld.service

  • sudo systemctl start firewalld.service

  • sudo systemctl stop firewalld.service

  • sudo systemctl restart firewalld.service

参见

14.3 查找您的 firewalld 版本

问题

您需要已安装的 firewalld 版本号。

解决方案

使用您的包管理器查询已安装的软件包,或使用 firewall-cmd

$ sudo firewall-cmd --version
0.9.3

讨论

firewalld 必须运行才能使 firewall-cmd 命令生效。如果未运行,则会显示“FirewallD is not running”消息。

参见

14.4 配置 iptables 或 nftables 作为 firewalld 后端

问题

您可以选择您自己的 firewalld 后端,可以是 iptables 或 nftables。

解决方案

使用您的偏好编辑 /etc/firewalld/firewalld.conf

FirewallBackend=nftables

或:

FirewallBackend=iptables

然后重新启动 firewalld。

讨论

您可能需要安装您首选的后端。

即使您不关心系统使用哪一个,也应该使用 nftables,因为这是 firewalld 开发人员正在积极开发的内容。

参见

14.5 列出所有区域以及每个区域管理的所有服务

问题

您想要查看 firewalld 配置中所有可用的区域以及每个区域管理的服务。

解决方案

列出默认区域:

$ firewall-cmd --get-default-zone
public

列出所有区域:

$ firewall-cmd --get-zones
block dmz drop external home internal public trusted work

列出所有活动区域,当前正在使用的区域:

$ firewall-cmd --get-active-zones
internal
  interfaces: eth1
work
  interfaces: wlan0

列出区域的配置:

$ sudo firewall-cmd --zone=public --list-all
public
  target: default
  icmp-block-inversion: no
  interfaces:
  sources:
  services: dhcpv6-client ipp ipp-client mdns ssh
  ports:
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:

列出所有区域的配置:

$ sudo firewall-cmd --list-all-zones
[...]

讨论

firewalld 区域定义了网络连接的信任级别。每个区域包含区域描述和其他项目,如上述示例中的public区域。区域文件以 XML 格式存在,并且必须具有.xml文件扩展名。查看/usr/lib/firewalld/zones以查看它们的源文件。

下面的列表定义了区域选项:

  • target: 定义不匹配任何规则的数据包的默认操作。它可以取四个值之一:defaultACCEPTDROPREJECT。例如,在public区域中,当连接请求 dhcpv6-client、ipp、ipp-client、mdns 或 ssh 数据包时,这些数据包将被接受。任何不匹配允许服务的数据包将被默认目标拒绝,并发送拒绝消息。

    • ACCEPT 接受所有未明确被规则阻止的数据包。

    • DROP 静默丢弃所有未明确允许的数据包。

    • REJECT类似于DROP,但还会发送拒绝消息。

  • icmp-block-inversion反转您的 ICMP 请求设置。被阻止的请求被改为未阻止,未阻止的请求被反转为阻止。通常设置为no

  • interfaces: 定义应用此区域的网络接口。每个接口可能仅绑定到一个区域,并且您可以在多个接口上使用相同的区域。

  • source: 接受 IP 和 MAC 地址以及 IP 地址范围。例如,您可以仅接受来自本地网络的数据包,来自特定主机的数据包,或者阻止主机或网络。

  • services: 是由此区域管理的服务列表。

  • ports: 列出此区域管理的端口号。

  • protocols: 列出由此区域管理的其他 TCP 协议,如/etc/protocols中所示。

  • masquerade: 可以设置为yesno。Masquerade 用于共享 IPv4 互联网连接。除了路由器外,所有主机都应将其设置为no

  • forward-ports: 用于将进入一个端口的数据包转发到另一个端口。

  • source-ports: 用于列出源端口。

  • icmp-blocks: 用于列出要阻止的 ICMP 类型。

  • rich rules 是您编写的自定义规则。

参见

14.6 列出和查询服务

问题

您想查看 firewalld 支持的服务列表。

解决方案

使用firewall-cmd命令:

$ sudo firewall-cmd --get-services
RH-Satellite-6 amanda-client amanda-k5-client amqp amqps apcupsd audit bacula
bacula-client bb bgp bitcoin bitcoin-rpc bitcoin-testnet bitcoin-testnet-rpc
bittorrent-lsd ceph ceph-mon cfengine cockpit condor-collector ctdb dhcp dhcpv6
[...]

那是一个相当大的全局视图。将其转换为整洁的单列:

$ sudo firewall-cmd --get-services| xargs -n1
RH-Satellite-6
amanda-client
amanda-k5-client
amqp
amqps
apcupsd
[...]

使用xargs -n2xargs -n3等命令创建更多列。

firewalld 服务不仅限于简单的端口地址。例如,bittorrent-lsd服务包括两个目标 IP 地址:

$ sudo firewall-cmd --info-service bittorrent-lsd
bittorrent-lsd
  ports: 6771/udp
  protocols:
  source-ports:
  modules:
  destination: ipv4:239.192.152.143 ipv6:ff15::efc0:988f
  includes:
  helpers:

ceph-mon服务打开了两个监听端口:

$ sudo firewall-cmd --info-service ceph-mon
ceph-mon
  ports: 3300/tcp 6789/tcp
  [...]

您可以编辑任何预定义服务以满足您的需求。

讨论

当您向区域添加服务时,请确保使用它们在列表中显示的名称。您可以创建自己的自定义服务;请参阅“在firewalld 文档中添加服务”。

参见

14.7 选择和设置区域

问题

您想知道如何选择和设置正确的区域。

解决方案

您选择的 firewalld 区域取决于您的机器运行哪些服务。如果您的机器未运行任何网络服务且仅需要网络连接,请使用dropblock区域。drop区域最为严格,拒绝所有传入连接请求,并仅允许回复来自计算机发起的连接。block类似于drop,但它发送拒绝消息。

不同 Linux 发行版上的其他区域配置不同,因此您需要查看系统上如何配置,例如work区域的示例:

$ sudo firewall-cmd --zone=work --list-all
work
  target: default
  icmp-block-inversion: no
  interfaces:
  sources:
  services: dhcpv6-client ssh
  ports:
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:

您必须将区域绑定到网络接口。以下示例将work区域分配给 eth0,然后进行验证:

$ sudo firewall-cmd --zone=work --permanent --change-interface=eth0
success

$ sudo firewall-cmd --zone=work --list-interfaces
eth0

如果您希望在永久应用更改之前测试更改,请省略--permanent选项。这将创建一个运行时配置,并立即应用更改。重新启动 firewalld 和运行firewall-cmd --reload时,运行时更改将丢失。将运行时更改转换为永久更改:

$ sudo firewall-cmd --runtime-to-permanent

绑定区域到网络接口或重新启动 firewalld 时,不需要重新加载 firewalld 配置。

讨论

如何知道选择哪个区域?这些是 Ubuntu 20.04 上带有 firewalld 的预定义区域,按照从最严格到最不严格的顺序排列。在您的 Linux 上,区域可能会稍有不同;查看 Recipe 14.5 以了解如何查看您的区域配置。

以下列出了默认区域:

drop

所有未经请求的传入网络数据包将被丢弃,并且不会有回复。仅允许回复到您的计算机发起的连接的传入数据包。当您连接到不受信任的网络并且不需要允许传入 SSH 连接、共享文件或任何其他外部连接请求时,这是最强的保护措施。

block

拒绝所有传入的网络连接请求,对于 IPv4 发送icmp-host-prohibited消息,对于 IPv6 发送icmp6-adm-prohibited消息。仅允许从您的系统发起的网络连接。

public

接受传入的 dhcpv6-client、ipp、ipp-client、mdns 和 ssh 连接,拒绝所有其他连接。

external

这是一个简单的互联网网关,结合了防火墙和简单的路由功能。仅接受传入的 SSH 连接,并且启用 IPv4 地址共享以共享互联网连接。

dmz

用于公开访问的您的非军事区域中的计算机。仅接受传入的 SSH 连接。(DMZ 是您网络上面向互联网服务器的单独网络段。)

work

只接受传入的 ssh 和 dhcpv6-client 连接。

home

只接受传入的 ssh、mdns samba-client 和 dhcpv6-client 连接请求。

internal

仅接受传入的 ssh、mdns、samba-client 和 dhcpv6-client 连接请求。

trusted

所有网络连接请求均被接受。

您可以自定义任何这些区域或创建新区域;参见 第 14.9 节。

参见

14.8 更改默认的 firewalld 区域

问题

您不喜欢默认的 firewalld 区域,想要更改它。

解决方案

验证您当前的默认设置:

$ firewall-cmd --get-default-zone
internal

假设您希望将 drop 作为默认区域,因为它是最严格的。使用 firewall-cmd 命令设置新默认值:

$ sudo firewall-cmd --set-default-zone drop
success

当您使用此命令时,不需要重新加载 firewalld 配置或重新启动 firewalld。

讨论

使用 NetworkManager(第 14.11 节)可以分配区域。NetworkManager 会将默认区域分配给所有未显式分配区域的连接。

参见

14.9 自定义 firewalld 区域

问题

默认区域都不符合您的需求,您想修改预定义区域。

解决方案

假设您喜欢 internal 区域,但默认配置不完全符合您的要求。当前配置允许 sshmdnssamba-clientdhcpv6-client

$ firewall-cmd --zone=internal --list-all
internal
  target: default
  icmp-block-inversion: no
  interfaces:
  sources:
  services: ssh mdns samba-client dhcpv6-client
[...]

下面的示例显示如何删除 samba-client,因为您不使用 Samba:

$ sudo firewall-cmd --remove-service=samba-client --zone=internal
success

您正在运行一个小型本地 389 目录服务器,因此需要添加 LDAPS 服务:

$ sudo firewall-cmd --zone=internal --add-service=ldaps
success

这些是临时更改,不会在重新启动或重新加载配置后生效。但它们会立即应用,以便您可以测试它们。测试您的更改,如果一切按预期运行,请将更改变为永久:

$ sudo firewall-cmd --runtime-to-permanent
success

要放弃更改,请不要使用 --runtime-to-permanent。而是使用 --reload 来丢弃运行时更改,并恢复到原始配置:

$ sudo firewall-cmd --reload
success

讨论

--reload 不会中断任何活动连接。

--complete-reload 完全重新加载 firewalld,包括重新加载内核模块,并终止活动连接。当您的运行时变更混乱无法解决时,这是一个好选择。

参见

14.10 创建新区域

问题

您想创建一个新的自定义区域。

解决方案

创建包含您的区域配置的 XML 文件,然后重新加载 firewalld,即可使用。

下面的示例创建了一个用于本地名称服务的区域,具有同一台机器上的 DNS 和 DHCP 服务器以及 SSH 访问权限。示例文件名为 /etc/firewalld/zones/names.xml

<?xml version="1.0" encoding="utf-8"?>
<zone>
  <short>Name Services</short>
  <description>
    DNS and DHCP servers for the local network, IPv4 only.
  </description>
  <service name="dns"/>
  <service name="dhcp"/>
  <service name="ssh"/>
</zone>

运行 sudo firewall-cmd --get-zones 命令,您的新区域将不会列出。 添加 --permanent 选项以查看尚未被 firewalld 读取的任何新区域,现在新的“names”区域出现了。 区域名称是没有 .xml 扩展名的文件名:

$ sudo firewall-cmd --permanent --get-zones
block dmz drop external home internal names public trusted work

重新加载 firewalld:

$ sudo firewall-cmd --reload
success

现在 firewalld 可以读取它,并且您可以看到它与其他区域一起:

$ sudo firewall-cmd --get-zones
block dmz drop external home internal names public trusted work

并列出其配置:

$ sudo firewall-cmd --zone=names --list-all
names
  target: default
  icmp-block-inversion: no
  interfaces:
  sources:
  services: dhcp dns ssh
  ports:
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:

您的新区域已准备就绪,您可以像任何其他区域一样修改它。

讨论

查看 man 5 firewalld.zone 了解配置选项,并查看 /usr/lib/firewalld/zones/ 中预定义区域的源文件作为示例。 唯一放在 /etc/firewalld/zones/ 中的文件是用户自定义文件。

通过删除其 .xml 文件来删除区域,然后重新加载 firewalld。

另请参阅

14.11 集成 NetworkManager 和 firewalld

问题

您在多个网络之间旅行,例如多个工作地点、咖啡店、酒店和共享工作场所。 您需要知道如何设置 NetworkManager 来跟上这些变化,并始终确保新连接分配到正确的防火墙区域。

解决方案

NetworkManager 包含 firewalld 集成。 当您连接到新网络时,NetworkManager 将其分配给您的默认 firewalld 区域。

您可以使用 NetworkManager 将非默认区域分配给特定连接。 如果您的面板中有 NetworkManager 小程序,请单击它以显示“编辑连接”对话框(Figure 14-2)。

在 NetworkManager 中编辑连接。

Figure 14-2. 在 NetworkManager 中编辑网络连接

或者,运行 nm-connection-editor 命令打开编辑器。 点击“编辑连接”,点击要编辑的连接,然后点击齿轮图标打开编辑器。 这将打开编辑对话框(Figure 14-3)。

更改防火墙区域。

Figure 14-3. 更改防火墙区域

转到“常规”选项卡并使用防火墙区域下拉菜单选择您要为该连接选择的区域。 保存更改,完成设置。

另请参阅

14.12 允许或阻止特定端口

问题

您正在使用非标准端口,例如 SSH 服务器的端口 2022。 您希望阻止端口 22 并允许端口 2022。

解决方案

任何未明确允许的端口将被所有 firewalld 区域拒绝,除了 trusted 区域允许所有内容。 如果您正在使用默认的 SSH 服务,它使用 TCP 端口 22,请先从相关区域中移除端口 22,然后添加端口 2022,然后重新加载 firewalld。 在这个例子中,非标准端口分配给 work 区域:

$ sudo firewall-cmd --zone=work --remove-port=22/tcp
success
$ sudo firewall-cmd --zone=work --add-port=2022/tcp
success

通过列出区域配置来验证:

$ sudo firewall-cmd --list-all --zone=work
work
  target: default
  icmp-block-inversion: no
  interfaces:
  sources:
  services: ssh
  ports:2022/tcp
[...]

当您满意时,请使您的更改永久化。

$ sudo firewall-cmd --runtime-to-permanent

讨论

如果您尝试删除该端口时看到类似“警告:NOT_ENABLED: 22:tcp”的消息,则表示该端口未在该区域启用,您可以继续添加您的新端口。

当您使用非标准端口时,连接到服务的客户端必须指定该端口号。例如,对于 SSH:

$ ssh -p 2022 *server1*

如何知道使用哪些端口?每个服务都有其自己的默认端口,在服务的文档和 /etc/services 文件中可以找到。您可以使用非标准端口,这些端口必须是在 1024 到 49151 之间未使用的端口。请记录您对 /etc/services 的更改。您还需要在服务器配置中设置您的非标准端口。参见 Recipe 12.3 以查看示例。

参见

14.13 使用丰富规则阻止 IP 地址

问题

您想要阻止某些 IP 地址。

解决方案

创建一个定义要阻止的地址和目标(例如 reject)的 rich rule。以下示例阻止了单个地址,并将其添加到内部区域中。

$ sudo firewall-cmd --zone=internal \
 --add-rich-rule='rule family="ipv4" source address=192.168.1.91 reject'
success

通过从被阻止的主机进行 ping 测试来测试它。被阻止的主机应该看到“目标端口不可达”的消息。

如果您不想保留该规则,请运行 sudo firewall-cmd --reload 来删除它。

要使其永久化,使用 --runtime-to-permanent 选项:

$ sudo firewall-cmd --runtime-to-permanent

列出区域中的丰富规则:

$ sudo firewall-cmd --zone=internal --list-rich-rules
rule family='ipv4' source address='192.168.1.91' reject

要删除永久的丰富规则,请使用 --remove-rich-rule 选项:

$ sudo firewall-cmd --zone=internal \
        --remove-rich-rule="rule family='ipv4' \
        source address='192.168.1.91' reject"
success

您无需完全阻止有问题的主机,但可以将阻止应用于特定服务。以下示例仅为 SSH 服务的源地址阻止:

$ sudo firewall-cmd --zone=internal --add-rich-rule='rule family="ipv4" \
 source address=192.168.1.91 service name="ssh" protocol=tcp reject'
success

讨论

您可以在一个区域中创建多个丰富规则,但请注意避免冲突。

曾经,我曾与一个有幸一起工作的人合作,他觉得在同事身上进行渗透测试很有趣。我们团队在工作站上运行了许多测试服务器,并向团队提供了这些服务器。我们那位想成为渗透测试员的人非常讨厌,我们都在防火墙上封锁了他。

参见

  • 参见 Recipe 14.7 了解 firewalld 的区域和选项

  • https://firewalld.org

  • man 5 firewalld.richlanguage

14.14 更改区域的默认目标

问题

您想要更改区域的默认目标。

解决方案

列出当前的目标:

$ sudo firewall-cmd --zone=internal --list-all
internal
  target: ACCEPT
[...]

将其从 ACCEPT 更改为 REJECT,然后重新加载并验证:

$ sudo firewall-cmd --permanent --zone=internal --set-target=REJECT
success

$ sudo firewall-cmd --reload

$ firewall-cmd --zone=names --list-all
names
  target: %%REJECT%%
[...]

讨论

区域目标定义了不匹配任何规则的数据包的默认操作。它可以是以下四个值之一:defaultACCEPTDROPREJECT

参见

第十五章:Linux 上的打印

Linux 依赖于 CUPS(通用 Unix 打印系统)来管理打印机。在本章中,你将学习如何安装和管理打印机,以及如何通过网络共享它们。你将了解到 Linux 打印的 无驱动 未来,其中打印机将可以在客户端设备上使用,而无需安装驱动程序。

概述

在 Linux 上愉快打印的关键是选择在 Linux 上得到良好支持的高质量打印机和多功能设备(打印机、扫描仪、复印机、传真机)。值得庆幸的是,现在选择受支持设备比过去要容易得多。当你选择一个受支持良好的设备时,驱动程序已经包含在 CUPS 中,你不必费力去寻找和下载制造商的驱动程序。

下一个最佳选择是购买具有供应商提供的 Linux 驱动程序的机器。这不是我喜欢的选项,因为这些驱动程序通常都很老旧且不再维护,你必须手动安装它们。这在多功能设备(MFDs)中更为常见。例如,我的个人机器是 Brother MFC-J5945DW,它没有原生的 CUPS 驱动程序,尽管支持无驱动打印。它是一笔不错的交易,墨盒便宜,尽管事后我真的应该购买一个有原生 Linux 支持的机器。原生支持更可靠,因为一旦设备在 CUPS 中受支持,就始终受支持,你不会受到那些不维护驱动程序或停止驱动下载的制造商的影响。

最不理想的选择是在没有做足功课的情况下购买并希望它能正常工作。在这种情况下,你可能可以使用 macOS 驱动程序(PPD 文件)来驱动 Linux 不支持的打印机,尽管如果 Macintosh 的 PPD 文件包含 macOS 特定条目(例如调用 macOS 可执行文件、库或过滤器),你可能需要进行一些工作来替换为 Linux 的等效物。如果你想尝试这种方法,可以参考 cupsFilter 获取一些有用的信息。

如果你需要一个共享设备,最少麻烦的方法是选择一个具有网络功能和内置控制功能的设备,可以进行复印、设置网络、查看墨水量、清洁打印头以及其他设置和维护任务。这些设备比需要从计算机设置和控制的设备更易于使用和更愉快。

查找受支持的打印机和扫描仪

惠普(HP)打印机和多功能设备通过 hpliphplip-hpijshplip-sanehplip-scan-utils 软件包拥有优秀的 Linux 支持。当然,每个 Linux 版本都有特别的名称,例如 hpijs-ppdshplip-dataprinter-driver-hpcupshplip-commonlibsane-hpaio。搜索 hplip 应该能找到它们。

并非所有 HP 打印机和多功能设备都在 Linux 上得到支持;请查看下面的链接获取 HP 的 Linux 支持数据库。

Brother 有良好的设备、体面的客户支持和良好的墨水价格。他们既有原生 Linux 支持的机器,也有需要 Brother 驱动程序的机器。

佳能、爱普生、霍尼韦尔、富士通、IBM、雷克萨姆、柯达、德科尼克斯、三星、夏普、施乐、东芝等许多品牌都在某种程度上支持 Linux。了解哪些型号得到支持可能很困难。一些供应商在其产品规格中告知您。有几个网站可供查询,尽管它们通常不完整也不时效,但它们是一个很好的起点:

CUPS 打印机驱动

Linux 打印机驱动由 CUPS(通用 Unix 打印系统)提供。自大约 2000 年以来,CUPS 一直是 Linux 的标准打印子系统。苹果在大约 2002 年开始使用 CUPS,然后雇用了 CUPS 的创始人 Michael Sweet,并在 2007 年购买了源代码。Sweet 在 2019 年离开了苹果,苹果的参与因此停滞不前,详情请见 apple/cups on GitHub。Sweet 先生并没有闲着,而是在 OpenPrinting.org 的 CUPS 分支 OpenPrinting/cups 上努力工作。

CUPS 中的打印机驱动程序由一个或多个特定于打印机的过滤器组成,这些过滤器封装在 PPD(PostScript 打印机描述)文件中。即使是非 PostScript 打印机,在 CUPS 中也需要一个 PPD。PPD 包含有关打印机、打印机命令和过滤器的描述。

打印机工作组OpenPrinting 是 CUPS 和打印标准开发的中心。

过滤器将打印作业转换为打印机可以理解的格式,如 PDF、HP-PCL、光栅和图像文件,并传递命令以执行操作,如页面选择、纸张大小、颜色、对比度和媒体类型。PPD 是纯文本文件,所有支持的打印机的 PPD 都在 /usr/share/cups/model/ 中。安装的打印机在 /etc/cups/ppd/ 中有 PPD。

PPDs Are Doomed

CUPS 从创建开始就依赖于 PPD 文件,并且它们运行良好。然而,现在正在开发一种新的方法称为 无驱动 打印。打印机不再使用静态的 PPD 文件,而是广播其能力,客户端机器无需安装驱动程序。这个想法就像使用 NetworkManager 连接新网络一样简单,它自动查找可用网络,并且不需要您安装驱动程序或手动配置每个新网络。对于手机和平板电脑等存储空间有限、屏幕尺寸有限的移动设备来说,这尤为有利。

无驱动在 CUPS 2.2.0 中引入。为了可靠性能,您应该至少使用 CUPS 2.2.4(2017 年 6 月发布)。您可以在以下资源中了解更多:

15.1 使用 CUPS Web 界面

问题

您需要找到 CUPS 管理工具。

解决方案

在您的网络浏览器中打开 CUPS Web 界面http://localhost:631/(图 15-1)。

CUPS Web 控制面板

图 15-1. CUPS Web 控制面板

讨论

有许多图形工具可用于管理打印机,例如 system-config-printer 和 openSUSE 中的 YaST 打印机模块。CUPS Web 管理页面提供了最完整的管理选项,在所有 Linux 发行版上保持一致。

参见

15.2 安装本地连接的打印机

问题

您需要安装一个连接到您的 PC 的新打印机。您明智地选择了一个原生支持 CUPS 的打印机。

解决方案

使用 CUPS Web 控制面板。您的打印机应该已连接并开机。以下示例基于 Linux Mint 系统。

转到管理选项卡,然后点击添加打印机。它会要求您登录(图 15-2)。(如果您的登录不起作用,只有 root 登录成功,请参阅 Recipe 15.7 了解如何配置 CUPS 接受非 root 登录。)选中“保存调试信息以进行故障排除”,并选中“共享直接连接到此计算机的打印机”以直接共享连接到您计算机的打印机。这仅启用共享功能,然后您必须在每台要共享的打印机上启用共享。

添加打印机

图 15-2. 添加打印机

在接下来的屏幕上,CUPS 在本地打印机部分发现并列出您的打印机(图 15-3)。选择您的打印机并点击继续。

现在您应该看到一个屏幕,类似于图 15-4,具有名称、描述和位置字段。名称和描述字段已自动填写,您可以更改为您想要的内容。名称字段在您打印文档时出现在打印机对话框中。

CUPS 找到您的本地打印机

图 15-3. CUPS 找到您的本地打印机

配置名称、描述和位置。

图 15-4. 指定名称、描述和位置

选择您的打印机驱动程序。CUPS 会显示一个巨大的列表供您选择。在图 15-5 中,驱动程序来自epson-inkjet-printer-escpr包(在 Ubuntu 上是printer-driver-escpr),适用于精工爱普生彩色喷墨打印机。

选择打印机驱动程序

图 15-5. 选择打印机驱动程序

最终配置屏幕用于设置默认选项,例如纸张类型、纸张尺寸、彩色或黑白、打印质量以及其他根据打印机和打印机驱动程序支持的选项。完成后,点击设置默认选项(图 15-6)。

设置默认打印机选项

图 15-6. 设置默认打印机选项

完成后,您将看到打印机页面,列出了所有安装的打印机(图 15-7)。

所有安装的打印机

图 15-7. 所有安装的打印机

点击您的新打印机,并从维护下拉菜单中打印一张测试页。当它正确打印时,您就完成了。

讨论

在图 15-2 中,您会看到两个按钮,添加打印机和查找新打印机。它们基本上是一样的,只是已发现的打印机列表组织方式不同。

您可能有多个打印机驱动程序可供选择;例如,对于同一台打印机,常见的是同时看到 CUPS+Gutenprint 和 Foomatic 驱动程序。以前 Gutenprint 是彩色打印机的更好选择;请尝试两种看您喜欢哪种。CUPS+Gutenprint 简化版驱动程序比完整版功能和选项较少。

参见

15.3 给打印机起有用的名称

问题

当您在文档中打开打印机对话框时,有几台打印机可供选择,其中一些看起来相似,您不确定应该使用哪一个。

解决方案

安装打印机时,在名称字段中输入一个描述性名称(图 15-8)。您必须在安装时执行此操作,因为安装后无法更改名称。

使用打印机名称识别您的打印机。

图 15-8. 使用打印机名称识别您的打印机

讨论

当您首次使用 CUPS Web 控制面板安装打印机时,有描述和位置字段可供使用,并且这些字段显示在 CUPS Web 控制面板中。但许多打印应用程序不读取这些字段,只读取名称字段。一些例外包括 Evolution 邮件客户端以及 Firefox 和 Chromium 网络浏览器,它们会显示名称、位置和状态。

另请参阅

15.4 安装网络打印机

问题

在您的网络上有一个共享网络打印机,并且您想在您的计算机上安装它。

解决方案

此过程与安装本地连接的 USB 打印机相同(配方 15.2),只是您选择了发现的网络打印机。打印机必须开启并且与您的计算机处于同一网络段下。您会在 Discovered Network Printers 下看到它列出(图 15-9)。

安装共享网络打印机。

图 15-9. 安装共享网络打印机

您需要在所有客户端的防火墙中打开 TCP 端口 631。

讨论

如果 CUPS 无法发现您的打印机怎么办?请参阅配方 15.11 获取一些故障排除帮助。如果 CUPS 无法看到您的打印机,则无法安装它。

另请参阅

15.5 使用无驱动打印

问题

您的打印机在 CUPS 中不受支持,您想尝试无驱动打印选项。或者,您想将 Android 或 iOS 设备连接到打印机。

解决方案

您可能已经在 CUPS 打印机驱动程序选择器中看到了无驱动选项。以下示例适用于我的 Brother MFC-J5945DW,它没有本机 CUPS 支持。

在 CUPS Web 控制面板中,转到管理 → 添加打印机。CUPS 在发现的网络打印机中看到我的 Brother 设备(图 15-10)。有一个driverless选项,那是正确的选择。

CUPS 看到我的不受支持的网络打印机

图 15-10. CUPS 看到我的不受支持的网络打印机

继续安装,并选择正确的驱动程序,在图 15-11 中是“Brother MFC-J5945DW, driverless, cups-filters 1.25.0 (en)”。

打印测试页,如果显示正确,安装就完成了。

选择无驱动打印机驱动程序

图 15-11. 选择无驱动打印机驱动程序

讨论

严格来说,这并不是无驱动,因为 CUPS 会为您的“无驱动”打印机在/etc/cups/ppd中创建 PPD 文件。然而,您无需维护充满 OpenPrinting.org 和 Gutenprint PPD 的目录。

你的打印机必须支持无驱动打印,这意味着它必须支持 Mopria、AirPrint、IPP Everywhere 或 WiFi Direct Print 标准。这些标准都类似:打印机通过 Avahi 守护进程广播自己、其网络地址和基本功能。Avahi 在你的本地网络上提供服务发现,使用 mDNS/DNS-SD 协议套件。(苹果称此服务为 Bonjour 和 Zeroconf。)

CUPS 中的无驱动打印适用于 Android 和 iOS 设备。你只需要安装一个打印机应用程序。如果你的打印机启用了无驱动功能,特别是如果它是 Mopria 认证的,那么你的移动设备将可以轻松找到它。Mopria 认证意味着你的打印机支持从移动设备发送的无线打印。如果你的打印机文档没有告诉你它是否是 Mopria 认证的,运行以下命令来检查:

$ avahi-browse -rt _ipp._tcp
[...]
txt = ["mopria-certified=1.3"
[...]

参见

15.6 共享非网络打印机

问题

你想要共享一个没有内置网络连接的打印机。

解决方案

CUPS 共享那些没有网络连接但连接到网络上的 PC 的打印机。首先,你必须使你的名称服务正常工作,以便你的 LAN 主机可以互相 ping 到彼此。

确保在 Administration 屏幕上通过“Share printers connected to this system”选项启用打印机共享。然后在你想要共享的打印机上启用共享(图 15-12)。

启用打印机共享

图 15-12. 启用打印机共享

CUPS 将会在你的网络上广播打印机。任何网络上的 Linux 客户端想要使用这台打印机,都必须像安装网络或本地连接的打印机一样进行安装;从 Administration → Add Printer 开始,然后按照正常的安装过程进行操作。

你也可以与 Windows 和 macOS 客户端共享。macOS 通过 DNS-SD/mDNS 和 IPP 本地支持发现。Linux 上由 Avahi 提供 DNS-SD/mDNS,Macintosh 称为 Bonjour。使用 Macintosh 控制面板找到并安装共享的 CUPS 打印机。

Windows 10 本地支持 DNS-SD/mDNS。旧版本的 Windows 支持通过 Internet 打印协议(IPP)进行共享。使用 Windows 打印机控制面板找到并安装共享的 CUPS 打印机。

讨论

在过去,网络打印机尚不普及且价格昂贵之前,管理员使用专用的打印机服务器。这些可以是旧 PC、旧笔记本电脑、小型单板计算机或商用打印机服务器设备。现在你仍然可以购买小型打印机服务器设备,而且价格比过去便宜得多。

现在大多数打印机都内置了网络功能,管理起来更简单。

参见

15.7 修正“Forbidden”错误信息

问题

当您尝试在 CUPS Web 控制面板中执行任何管理任务时(例如添加新打印机),您的登录失败并显示“添加打印机错误 无法添加打印机:Forbidden”消息。

解决方案

在一些 Linux 发行版(如 openSUSE)中,默认配置只允许 root 用户执行 CUPS 管理任务。编辑 /etc/cups/cups-files.conf 以允许非 root 用户执行 CUPS 管理任务。查找以下行:

# Administrator user group, used to match @SYSTEM in cupsd.conf policy rules...
# This cannot contain the Group value for security reasons...
SystemGroup root

这就是为什么只有 root 登录有效的原因。您可以添加您自己的私有用户组,例如我们的示例用户 Duchess,其私有组是 duchess

SystemGroup root duchess

在保存对 /etc/cups/cups-files.conf 的更改后,重新启动 CUPS 服务:

$ sudo systemctl restart cups.service

现在 Duchess 可以执行 CUPS 管理任务。

另一种方法是使用专门为此目的创建的系统组。在 Ubuntu Linux 发行版中,这是 lpadmin 组,而 Fedora 使用 syswheel 组。您可以创建自己的用于 CUPS 管理的组,例如创建 cupsadmin 组,并将用户 Mad Max 添加到该组中:

$ sudo groupadd -r cupsadmin
$ sudo usermod -aG cupsadmin madmax

Mad Max 必须注销,然后重新登录以激活新的组成员资格。将 cupsadmin 组添加到 /etc/cups/cups-files.conf 中的 SystemGroup

SystemGroup root duchess cupsadmin

重新启动 CUPS,Mad Max 就可以开始工作了。

讨论

/etc/cups/cups-files.conf 中应该还有这样一个部分:

# Default user and group for filters/backends/helper programs; this cannot be
# any user or group that resolves to ID 0 for security reasons...
#User lp
#Group lp

SystemGroup 中列出的任何组都无法与 Group 匹配。如果尝试使用前面的示例中的 lp,CUPS 将无法启动,并且您会在 /var/log/cups/error_log 或系统日志中看到错误消息,具体取决于 /etc/cups/cups-files.conf 中的配置方式。

如果您的 Linux 使用 SysV init 而不是 systemctl,请使用以下命令重新启动:

$ sudo /etc/init.d/cups restart

参见

15.8 安装打印机驱动程序

问题

您需要知道安装 CUPS 是否也安装了完整的打印机驱动程序集,或者是否还有更多您可能想要但未包含在 CUPS 中的驱动程序。

解决方案

大多数 Linux 发行版仅安装了所有可用打印选项的子集。每个 Linux 发行版在可用的打印机驱动程序、默认安装的驱动程序以及包名称的具体使用上都有所不同,特别是在 Ubuntu 与其他发行版之间。

下面的列表包括一组基本的 CUPS 软件包和打印机驱动程序:

  • cups(服务器和客户端)

  • cups-filters(OpenPrinting CUPS 过滤器和后端)

  • gutenprint(Gutenprint 打印机驱动程序)

  • foomatic(Foomatic 打印机驱动程序)

  • OpenPrinting.org PPDs;例如,OpenSUSE 提供:

    • OpenPrintingPPDs

    • OpenPrintingPPDs-ghostscript(用 PostScript 语言编写的打印机驱动程序解释器)

    • OpenPrintingPPDs-hpijs(HP 打印机)

    • OpenPrintingPPDs-postscript

  • cups-client(用于设置和管理打印机的命令行实用程序)

OpenPrinting.org 包括 Foomatic。Fedora 和 Ubuntu 发行 foomatic 软件包,而 OpenSUSE 包括 OpenPrinting 软件包。名称可能会变,但功能是相同的。

这些软件包可能提供您所需的一切。以下是您可能会发现有用的其他打印机软件包:

  • gimp-gutenprint(为 GIMP 提供更丰富的打印机对话框,GNU 图像处理程序)

  • bluez-cups(连接蓝牙打印机)

  • cups-airprint(与 iOS 设备共享打印机)

  • ptouch-driver(Brother P-touch 标签打印机)

  • rasterview(查看 Apple 光栅图像,如 GIF、JPEG 和 PNG,请参见 MSweet.org/rasterview

  • c2esp(某些柯达多功能打印机)

Ubuntu 打包了最大的打印机驱动程序集合。许多但不是所有软件包名称以 printer-driver 开头:

  • openprinting-ppds(OpenPrinting 打印机支持,PostScript PPD 文件)

  • printer-driver-all(打印机驱动程序元包)

  • printer-driver-brlaser(某些 Brother 激光打印机)

  • printer-driver-c2050(Lexmark 2050 Color Jetprinter)

  • printer-driver-foo2zjs(基于 ZjStream 的打印机)

  • printer-driver-c2esp(柯达 ESP AiO 彩色喷墨系列)

  • printer-driver-cjet(佳能 LBP 激光打印机)

  • printer-driver-cups-pdf(通过 CUPS 编写 PDF)

  • printer-driver-dymo(DYMO 标签打印机)

  • printer-driver-escpr(使用 ESC/P-R 的爱普生喷墨打印机)

  • printer-driver-foo2zjs(基于 ZjStream 的打印机)

  • printer-driver-fujixerox(富士施乐打印机)

  • printer-driver-gutenprint(CUPS 打印机驱动程序)

  • printer-driver-hpcups(HP Linux 打印与影像,CUPS 栅格驱动程序(hpcups))

  • printer-driver-hpijs(HP Linux 打印与影像,打印机驱动程序(hpijs))

  • printer-driver-indexbraille(用于 Index Braille 打印机的 CUPS 打印)

  • printer-driver-m2300w(Minolta magicolor 2300W/2400W 彩色激光打印机)

  • printer-driver-min12xxw(KonicaMinolta PagePro 1[234]xxW)

  • printer-driver-oki(OKI Data 打印机)

  • printer-driver-pnm2ppa(HP-GDI 打印机)

  • printer-driver-postscript-hp(HP 打印机 PostScript 描述)

  • printer-driver-ptouch(Brother P-touch 标签打印机驱动程序)

  • printer-driver-pxljr(HP Color LaserJet 35xx/36xx)

  • printer-driver-sag-gdi(理光 Aficio SP 1000s/SP 1100s)

  • printer-driver-splix(三星和施乐 SPL2 和 SPLc)

讨论

如果您在 CUPS 网页界面的驱动程序选择器中找不到您的打印机,请尝试在软件包管理器中搜索您的打印机品牌名称。这可能看起来有些混乱,但在所有计算平台上(不仅仅是在 Linux 上),设置打印机都是一团糟。

另请参阅

15.9 修改已安装的打印机

问题

您想要更改已安装的打印机的配置。例如,您想要共享它。

解决方案

在 CUPS Web 控制面板中打开打印机,然后点击管理 → 修改打印机。这与安装新打印机类似,不同之处在于它显示当前打印机的设置。图 15-13 可以启用打印机共享。(请注意,首先必须在管理 → 高级页面上启用共享。)

修改已安装的打印机

图 15-13. 修改已安装的打印机

讨论

除了打印机名称外,您可以更改一切。

参见

15.10 通过打印保存文档为 PDF 文件

问题

您想将网页或任何文档保存为 PDF 文件,而不是发送到打印机。

解决方案

查看任何应用程序中的文件 → 打印对话框,您将看到打印到 PDF 文件的选项(图 15-14)。

打印到 PDF 文件。

图 15-14. 打印到 PDF 文件

您可以更改常规选项,如文件名和位置、页边距、打印质量、彩色或单色以及页面方向。打印对话框在不同的应用程序中看起来不同;例如,Firefox Web 浏览器的打印对话框包括文档预览。在其他应用程序中,预览通常是单独的按钮。

讨论

打印到文件对于保存网页确认表单和收据,并从任何类型的文档创建 PDF 非常有用。

参见

15.11 故障排除

问题

打印不工作!如何解决?

解决方案

这些是 Linux 上打印机最常见的问题:

  • 对于共享打印机,请确保正确设置了网络并且防火墙允许 TCP 端口 631. 如果您有多个网络,请验证打印机是否与计算机处于同一网络中。

  • 对于连接 USB 的打印机,请尝试更换不同的 USB 端口或使用不同的电缆。

  • 确保您正在使用正确的打印机驱动程序,或尝试无驱动。

  • CUPS 守护进程由 systemd 管理。尝试重新启动守护进程:

    $ sudo systemctl restart cups.service
    

    或重新启动,并同时对打印机进行电源循环。

  • 在 CUPS Web 管理页面上检查日志文件;您可以查看错误日志和访问日志。将日志级别提升至 Debug 以获取更多信息。(点击编辑配置文件,然后设置 LogLevel debug。)

讨论

最重要的因素是使用支持良好的 Linux 打印机。这可以避免大多数问题。

参见

第十六章:使用 Dnsmasq 和 hosts 文件管理本地名称服务

Dnsmasq是 LAN 名称服务的优秀服务器,包括域名系统(DNS)和动态主机配置协议(DHCP)。Dnsmasq 还提供 BOOTP、PXE 和 TFTP,用于从网络服务器引导和安装操作系统。Dnsmasq 支持 IPv4 和 IPv6,提供本地 DNS 缓存,并充当存根解析器。

本章介绍如何使用 Dnsmasq 和/etc/hosts文件设置本地 DNS 和 DHCP。/etc/hosts是设置 DNS 的非常古老的方式,它在静态文件中将主机名映射到 IP 地址。对于非常小的网络来说,/etc/hosts本身已经足够了。

Dnsmasq 专为 LAN 名称服务而设计。它轻巧且配置简单,特别是与权威 DNS 服务器 BIND 相比,后者功能强大且学习曲线较陡。

Dnsmasq 和/etc/hosts很好地配合在一起。Dnsmasq 会将/etc/hosts中的条目读入 DNS 中。

Dnsmasq 中的 DHCP 服务器会自动与 DNS 集成。您只需配置 DHCP 客户端将其主机名发送到 DHCP 服务器即可,这在大多数 Linux 发行版中是默认设置。

有四种类型的 DNS 服务器:递归解析器、根名称服务器、顶级域(TLD)名称服务器和权威名称服务器。

递归解析器响应 DNS 请求。像 Dnsmasq 和 systemd-resolved 这样的存根解析器会将其无法从缓存中回答的任何请求转发到上游解析器。当您访问一个网站时,递归解析器通过查询其他三种类型的 DNS 服务器来查找该站点的 DNS 信息。递归解析器会缓存这些信息以加快访问速度。您的 ISP 的名称服务器以及像OpenDNSCloudflare,和Google Public DNS这样的服务都是递归解析器。

有 13 种类型的根名称服务器,分布在全球各地,目前有数百个根名称服务器。根服务器接受来自递归解析器的查询,然后根据顶级域名(.com,.net,.org,.me,.biz,.int,.biz,.gov,.edu 等)将请求转发给适当的顶级域服务器。互联网名称与数字地址分配机构(ICANN)监管所有这些服务器和域名。

权威名称服务器是域的源记录,由域所有者控制。虽然 Dnsmasq 可以作为您的权威名称服务器,但我建议使用 BIND。请参阅man 8 dnsmasq中的权威配置部分以了解更多信息。

太多的名称服务工具。

Linux 发行版仍在从传统的resolvconf转向 NetworkManager 和systemd-resolved,后者长期以来一直是 Linux 系统上的默认 DNS 解析器。这对 Linux 用户来说有些混乱,各个发行版的过渡速度不同。请密切关注您特定 Linux 版本的文档、论坛和发行说明。

可以使用 Dnsmasq 作为 NetworkManager 的 DNS 后端,因为 NetworkManager 有一个针对此功能的插件。但在某些 Linux 发行版上,这还不能正常工作(配方 16.5)。

您不需要在您的 Dnsmasq 服务器上运行 systemd-resolved,因为它会与 Dnsmasq 竞争系统的 stub DNS 解析器的控制权。

当您阅读此文时,所有这些可能已经不同,但目前这些配方旨在可靠而非尖端。

16.1 使用/etc/hosts进行简单名称解析

问题

您希望有一种简单快捷的方式设置名称解析,而无需运行 DNS 服务器。

解决方案

这就是/etc/hosts文件的用途。您的 LAN 计算机必须具有静态 IP 地址。以下是三台计算机的示例:

127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
192.168.43.81 host1
192.168.43.82 host2
192.168.43.83 host3

将这些条目复制到所有三个主机,然后尝试通过主机名进行 ping,例如从host3ping host2的示例:

host3:~$ ping -c2 host2
PING host2 (192.168.43.82) 56(84) bytes of data.
64 bytes from host2 (192.168.43.82): icmp_seq=1 ttl=64 time=3.00 ms
64 bytes from host2 (192.168.43.82): icmp_seq=2 ttl=64 time=3.81 ms

--- host2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 3.001/3.403/3.806/0.402 ms

/etc/hosts 还管理域名,因此您可以为您的 LAN 提供一个酷炫的域名。在以下示例中,这是sqr3l.nut。首先输入 IP 地址,然后是完全限定域名(FQDN),然后是主机名:

127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
192.168.43.81 host1.sqr3l.nut host1
192.168.43.82 host2.sqr3l.nut host2
192.168.43.83 host3.sqr3l.nut host3

现在您的主机可以使用它们的主机名连接到彼此,例如host1,或者它们的 FQDN,例如host1.sqr3l.nut

共享和个体主机条目

您可以在/etc/hosts中同时拥有共享和私有条目。您希望共享的内容必须复制到所有相关的主机。否则,您主机文件中的其他内容仅对您有效。参见配方 16.2 以了解更多信息。

讨论

127.0.0.1 localhost::1 localhost ip6-localhost ip6-loopback 是必需的。您的可能看起来略有不同,但无论如何,请不要删除它们。它们分配给回环设备,这是您的 Linux 系统用于与自身通信的特殊虚拟网络接口。

您可以通过 ping 它们并使用它们连接到本地服务器。例如,当您使用 CUPS Web 管理页面时,您正在使用回环设备。输入127.0.0.1:631localhost:631来打开它(图 16-1)。

使用回环设备打开本地网页

图 16-1. 使用回环设备打开本地网页

回环设备的虚拟网络接口是lo。使用ip命令查看它:

$ ip addr show dev lo
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group
  default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever

您的系统不需要回环设备的物理网络接口才能工作。

使用hostname命令确认您的配置是否正确。检查计算机的主机名:

$ hostname
host1

检查完全限定域名:

$ hostname -f
host1.sqr3l.nut

检查域名:

$ hostname -d
sqr3l.nut

/etc/hosts 不适合大规模使用,但对于小型网络可能是您的本地 DNS 所需的一切。

参见

  • man 5 hosts

  • man 8 ping

  • Recipe 16.2

16.2 使用/etc/hosts进行测试和阻止烦人的事物

问题

您正在处理开发服务器,并且希望轻松管理它们的 DNS。或者,您希望通过简单的方式阻止烦人的网站。

解决方案

假设您正在使用的开发服务器的名称是dev.stashcat.com。在您的/etc/hosts文件中为它添加一个条目:

*192.168.10.15 dev.stashcat.com*

您不必打扰网络管理员或修改 DNS 服务器,只需根据需要在/etc/hosts中创建和删除条目。

另一个有趣的技巧是将烦人的网站映射到虚假的 IP 地址:

*12.34.56.78  badsite.com*
*12.34.56.78  www.badsite.com*

这使得从您的计算机无法访问该站点。大多数操作指南使用回环地址 127.0.0.1,它可以工作,但我更喜欢将烦人的站点保持单独。您可以为多个烦人的站点使用相同的虚假 IP 地址。

如果将其添加到/etc/hosts后,您的 Web 浏览器仍然能访问该站点,请清除浏览器缓存并重试。

讨论

在运行 LAN Dnsmasq 服务器时,请记住 Dnsmasq 服务器上/etc/hosts中的所有条目将应用于所有 Dnsmasq 客户端,因此不要在开发计算机上放置您的名称服务器。

Linux 有多个 DNS 管理器,/etc/hosts首先读取。顺序在/etc/nsswitch.conf文件的hosts行中设置。以下示例来自 Ubuntu 20.04:

hosts: files mdns4_minimal [NOTFOUND=return] dns mymachines

files/etc/hosts

mdns4_minimal 使用 Avahi 自动发现服务来定位网络服务。

[NOTFOUND=return] 表示如果mdns4_minimal正在工作但未找到请求的主机,则 DNS 查找应停止并返回错误。如果未找到mdns4_minimal服务,则继续查找。

dns 使用任何可用的 DNS 服务器。

mymachines 指的是systemd-machined服务,用于跟踪本地虚拟机和容器。

您应该在您的 Dnsmasq 服务器上首先放置files dns

参见

  • man 5 hosts

  • man 5 nsswitch.conf

  • man 8 systemd-machined.service

16.3 查找您网络上的所有 DNS 和 DHCP 服务器

问题

您想知道您的 LAN 上是否有任何 DNS 和 DHCP 服务器,除了您的 Dnsmasq 服务器。

解决方案

使用nmap探测您的 LAN。以下示例在本地网络中搜索所有开放的 TCP 端口,并找到一个开放的 TCP 端口 53,这是 DNS 使用的端口。这由“53/tcp open domain”指示:

$ sudo nmap --open *192.168.1.0/24*
Starting Nmap 7.70 ( https://nmap.org ) at 2021-05-23 13:25 PDT
[...]
Nmap scan report for dns-server.sqr3l.nut (192.168.1.10)
Host is up (0.12s latency).
Not shown: 998 filtered ports
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT   STATE SERVICE
22/tcp open  ssh
53/tcp open  domain
[...]

Nmap done: 256 IP addresses (3 hosts up) scanned in 81.38 seconds

默认情况下,nmap 只查找 TCP 端口。DNS 服务器监听 TCP 和 UDP 53 端口,而 DHCP 监听 UDP 67 端口。以下示例仅查找 UDP 53 和 67 端口:

$ sudo nmap -sU -p 53,67 *192.168.1.0/24*
Starting Nmap 7.80 ( https://nmap.org ) at 2021-05-27 18:05 PDT

Nmap scan report for dns-server.sqr3l.nut (192.168.1.10)
Host is up (0.085s latency).

PORT   STATE         SERVICE
53/udp open          domain
67/udp open|filtered dhcps

Nmap done: 256 IP addresses (3 hosts up) scanned in 13.85 seconds

nmap 发现了一个 DNS/DHCP 服务器,位于 dns-server.sqr3l.nut 上。

以下命令在网络上搜索所有开放的 TCP 和 UDP 端口:

$ sudo nmap -sU -sT *192.168.1.0/24*

这需要几分钟的时间来完成,然后您将得到网络中所有活动主机的活动服务列表,包括在非标准端口上运行的任何服务。

讨论

在进行端口扫描时要非常小心,并且只在你有权限的网络上使用。在其他网络上进行端口扫描通常被视为敌对行为,就像你在探测漏洞以利用一样。

多个名称服务器可能会导致冲突,在任何情况下,了解用户是否运行任何服务器都是很好的。

在大多数 Linux 系统上,安装包是nmap

另请参阅

  • man 1 nmap

16.4 安装 Dnsmasq

问题

你希望安装 Dnsmasq 并处理任何先决条件。

解决方案

安装dnsmasq包。在本示例中,Dnsmasq 服务器命名为dns-server。你将同时使用 Dnsmasq 和/etc/hosts文件配置你的 DNS 服务器。

安装后,如果运行了 Dnsmasq,请停止它:

$ systemctl status dnsmasq.service
● dnsmasq.service - dnsmasq - A lightweight DHCP and caching DNS server
     Loaded: loaded (/lib/systemd/system/dnsmasq.service; enabled; vendor
     preset: enabled)
     Active: active (running) since Mon 2021-05-24 05:49:36 PDT; 6h ago
[...]
$ sudo systemctl stop dnsmasq.service

如果你的 Dnsmasq 服务器还没有静态 IP 地址,请给它分配一个。可以使用 NetworkManager 的图形控制面板(nm-connection-editor)或nmcli命令来完成。

以下示例使用nmcli来查找你的活动连接:

$ nmcli connection show --active
NAME       UUID                     TYPE      DEVICE
*1local*     3e348c97-4c5f-4bbf-967e  wifi      *wlan1*
*1wired*     0460d735-e14d-3c3f-92c0  ethernet  *eth1*

然后使用名称来分配你希望你的 DNS 服务器使用的静态 IP 地址,使用 NAME 来识别正确的连接:

$ nmcli con mod "*1wired*" \
  ipv4.addresses "*192.168.1.30/24*" \
  ipv4.gateway "*192.168.1.1*" \
  ipv4.method "manual"

然后重新启动 NetworkManager:

$ sudo systemctl restart NetworkManager.service

接下来,检查你的 Linux 是否运行systemd-resolved.service

$ systemctl status systemd-resolved.service

如果是这样,请在配置 Dnsmasq 之前查看 Recipe 16.5,还要了解如何在你的 Dnsmasq 服务器上配置 NetworkManager。

讨论

systemd 在各种 Linux 发行版中实现方式不同。例如,openSUSE Leap 15.2 不使用systemd-resolved.service,因此不需要对 systemd 进行任何更改来启用 Dnsmasq 以控制你的 LAN DNS。Fedora 33 及更高版本,以及 Ubuntu 17.04 及更高版本,运行systemd-resolved.service,你应该在 Dnsmasq 服务器上禁用它。

另请参阅

  • Recipe 16.5(玩得和谐)

  • Dnsmasq

16.5 让 systemd-resolved 和 NetworkManager 与 Dnsmasq 协调工作

问题

systemd-resolved和 NetworkManager 与 Dnsmasq 冲突,你希望它们不再干扰。

解决方案

检查是否运行systemd-resolved.service

$ systemctl status systemd-resolved.service

● systemd-resolved.service - Network Name Resolution
     Loaded: loaded (/usr/lib/systemd/system/systemd-resolved.service; enabled;
     vendor preset: enabled)
     Active: active (running) since Sat 2021-05-22 12:57:34 PDT; 1min 21s ago
[...]

这表明它正在运行。systemd-resolved.service非常适合为客户机提供桩 DNS 解析器,但不适合 DNS 服务器。禁用它:

$ sudo systemctl stop systemd-resolved.service
$ sudo systemctl disable systemd-resolved.service

然后查看/etc/resolv.conf,它应该是一个符号链接:

$ ls -l /etc/resolv.conf
lrwxrwxrwx 1 root root 39 May 21 20:38 /etc/resolv.conf ->
   ../run/systemd/resolve/stub-resolv.conf

当它是一个符号链接时,它由systemd-resolved.service管理。要从systemd-resolved.service中删除控制权,请删除符号链接,并创建一个同名的纯文本文件:

$ sudo rm /etc/resolv.conf
$ sudo touch /etc/resolv.conf

现在/etc/resolv.conf是一个文件而不是一个符号链接,由 NetworkManager 管理。打开你的 NetworkManager 配置文件,查找[main]部分,然后添加或更改dns=值为none

$ sudo nano /etc/NetworkManager/NetworkManager.conf

[main]
dns=none

/etc/resolv.conf中输入你的 Dnsmasq 服务器的 IPv4 和 IPv6 本地主机地址,以及你的本地域(如果有):

search *sqr3l.nut*
nameserver 127.0.0.1
nameserver ::1

然后重新启动并配置你的新 Dnsmasq 安装。

讨论

NetworkManager 和 systemd-resolved 在客户端机器上很棒。在您的 Dnsmasq 服务器上,您必须控制 /etc/resolv.conf,并且 Dnsmasq 应该是唯一的存根解析器。

参见

  • man 8 systemd-resolved.service

  • man 8 networkmanager

16.6 配置 LAN DNS 的 Dnsmasq

问题

您希望将 Dnsmasq 设置为 LAN DNS 服务器。

解决方案

您在 /etc/hosts 中输入的任何主机都需要静态 IP 地址,Dnsmasq 将自动将它们输入到 DNS 中。至少输入您的 Dnsmasq 服务器。以下示例包括 Dnsmasq 服务器、备用服务器和内部 Web 服务器:

127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
192.168.43.81 dns-server
192.168.43.82 backups
192.168.43.83 https

从 DHCP 配置静态主机

参见 Recipe 16.12 以了解如何从 DHCP 管理静态 IP 地址分配,而不是 /etc/hosts

现在是配置 Dnsmasq 的时候了。重命名默认配置文件,这样您可以从新的空文件开始,并将原始文件用作参考:

$ sudo mv /etc/dnsmasq.conf /etc/dnsmasq.conf-old
$ sudo nano /etc/dnsmasq.conf

复制以下配置,用您自己服务器的 IP 地址替换第二个 listen-address,并使用您自己的域名。上游名称服务器是 OpenDNS,您可以使用任何上游名称服务器。Dnsmasq 默认查找 /etc/resolv.conf,但明确指定也无妨:

# global options
resolv-file=/etc/resolv.conf
domain-needed
bogus-priv
expand-hosts
domain=*sqr3l.nut*
local=/*sqr3l.nut*/
listen-address=127.0.0.1
listen-address=*192.168.43.81*

# upstream name servers
server=*208.67.222.222*
server=*208.67.220.220*

运行 Dnsmasq 的语法检查器:

$ dnsmasq --test
dnsmasq: syntax check OK.

语法检查器不会找到配置错误,但只会找到打字错误。启动 Dnsmasq,如果有错误它将无法启动。以下示例显示了一个成功启动的情况:

$ sudo systemctl start dnsmasq.service
$ systemctl status dnsmasq.service
● dnsmasq.service - dnsmasq - A lightweight DHCP and caching DNS server
     Loaded: loaded (/lib/systemd/system/dnsmasq.service; enabled; vendor preset:
     enabled)
     Active: active (running) since Mon 2021-05-24 17:13:48 PDT; 1min 0s ago
    Process: 11023 ExecStartPre=/usr/sbin/dnsmasq --test (code=exited,
     status=0/SUCCESS)
    Process: 11024 ExecStart=/etc/init.d/dnsmasq systemd-exec (code=exited,
     status=0/SUCCESS)
    Process: 11033 ExecStartPost=/etc/init.d/dnsmasq systemd-start-resolvconf
     (code=exited, status=0/SUCCESS)
   Main PID: 11032 (dnsmasq)
      Tasks: 1 (limit: 18759)
     Memory: 2.5M
     CGroup: /system.slice/dnsmasq.service
             └─11032 /usr/sbin/dnsmasq -x /run/dnsmasq/dnsmasq.pid -u dnsmasq -7
              /etc/dnsmasq.d,.dpkg-dist,.dpkg-old,.dpkg-new --local->

May 24 17:13:48 dns-server systemd[1]: Starting dnsmasq - A lightweight DHCP and
 caching DNS server...
May 24 17:13:48 dns-server dnsmasq[11023]: dnsmasq: syntax check OK.
May 24 17:13:48 dns-server systemd[1]: Started dnsmasq - A lightweight DHCP and
 caching DNS server.

在您的 Dnsmasq 服务器上使用 nslookup 运行一些测试,使用您服务器的主机名和 FQDN:

$ nslookup *dns-server*
Server:         127.0.0.1
Address:        127.0.0.1#53

Name:   *dns-server*
Address: *192.168.43.81*

$ nslookup *dns-server.sqr3l.nut*
Server:         127.0.0.1
Address:        127.0.0.1#53

Name:   *dns-server.sqr3l.nut*
Address: *192.168.43.81*

$ nslookup *192.168.43.81*
*18.43.168.192*.in-addr.arpa       name = *host1.sqr3l.nut.*

使用 ss 命令验证监听端口。在以下示例中,为了清晰起见,已删除了 Recv-Q、Send-Q 和 Peer Address:Port 列:

$ sudo ss -lp "sport = :domain"
Netid  State   Local Address:Port    Process
udp    UNCONN     127.0.0.1:domain   users:(("dnsmasq",pid=1531,fd=8))
udp    UNCONN  *192.168.1.10*:domain   users:(("dnsmasq",pid=1531,fd=6))
tcp    LISTEN     127.0.0.1:domain   users:(("dnsmasq",pid=1531,fd=9))
tcp    LISTEN  *192.168.1.10*:domain   users:(("dnsmasq",pid=1531,fd=7))

您应该看到您的服务器地址、本地主机地址,并且在进程列中只有 dnsmasq。添加 -r 选项以查看主机名而不是 IP 地址。

当所有这些命令成功执行时,您的配置就是正确的。

讨论

如果 Dnsmasq 启动失败,请运行 journalctl -ru dnsmasq 查看原因。(如果您的 Dnsmasq 日志发送到其他地方,请查看那里;参见 Recipe 16.14。)

nslookup 包含在 bindutils 包中。

ss,套接字统计,包含在 iproute2 包中。

如果您的 nslookup 命令失败,请尝试重新启动网络,然后重新启动 Dnsmasq。如果它们仍然失败,请重启。如果这不能解决问题,请重新检查所有配置。

domain-needed 防止 Dnsmasq 转发对您的纯主机名的查询到上游名称服务器。如果名称在 /etc/hosts 或 DHCP 中未知,则返回“未找到”答案。这可以防止您 LAN 地址的请求泄漏到全球,并且如果您的 LAN 域名与公共域名相同,可能会被错误地回答。

bogus-priv 阻止虚假的私有反向查找。对于未在 /etc/hosts 或 DHCP 租约文件中找到的私有 IP 范围的所有反向查找,都将返回“无此域”而不是转发到上游。

expand-hosts 自动将您的私有域名添加到/etc/hosts 中的纯主机名。

domain= 是您的本地域名。

local=/[domain]/ 告诉 Dnsmasq 直接解析本地域的查询,而不将其转发到上游。

另请参阅

16.7 配置 firewalld 允许 DNS 和 DHCP

问题

您需要打开您的 Dnsmasq 服务器防火墙,以允许您的 LAN 客户端访问它。

解决方案

开放 TCP 和 UDP 端口 53 用于 DNS,以及 UDP 端口 67 用于 DHCP。如果您正在运行firewalld,请使用以下命令:

$ sudo firewall-cmd --permanent --add-service=\{dns,dhcp\}

讨论

在您遇到连接问题时,首先要检查的是防火墙设置。

另请参阅

  • 第十四章

16.8 从客户端机器测试您的 Dnsmasq 服务器

问题

您希望从客户端计算机测试您全新的 Dnsmasq DNS 服务器。

解决方案

使用dig 命令从网络中的任何主机查询任何网站,通过您的 Dnsmasq 服务器的 IP 地址:

$ dig @*192.168.1.10* oreilly.com

; <<>> DiG 9.16.6 <<>> @*192.168.1.10* oreilly.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 29387
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;oreilly.com.                   IN      A

;; ANSWER SECTION:
oreilly.com.            240     IN      A       199.27.145.65
oreilly.com.            240     IN      A       199.27.145.64

;; Query time: 108 msec
;; SERVER: *192.168.1.10*#53(*192.168.1.10*)
;; WHEN: Mon May 24 17:49:32 PDT 2021
;; MSG SIZE  rcvd: 72

这是一次成功的测试,确认为“status: NOERROR”,并显示了您的 Dnsmasq 服务器的 IP 地址的 SERVER 行。

讨论

您还可以使用您服务器的主机名和完全限定域名(FQDN)进行测试:

$ dig @*dns-server* oreilly.com
$ dig @*dns-server.sqr3l.nut* oreilly.com

另请参阅

  • man 1 dig

16.9 使用 Dnsmasq 管理 DHCP

问题

您的 DNS 已经工作正常,现在您想设置 DHCP。

解决方案

没问题。将以下行添加到您的/etc/dnsmasq.conf 文件中,定义一个地址池,替换为您自己想要的地址:

# DHCP range
dhcp-range=*192.168.1.25,192.168.1.75,12h*
dhcp-lease-max=*25*

重新启动 Dnsmasq:

$ sudo systemctl restart dnsmasq.service

尝试在 LAN 计算机上获取地址。首先确保它配置为通过 DHCP 获取其 IP 地址:

$ nmcli con show --active
NAME    UUID                     TYPE     DEVICE
*1net*    de7c00e7-8e4d-45e6-acaf  ethernet eth0

$ nmcli con show *1net* | grep ipv..method
ipv4.method:           auto
ipv6.method:           auto

auto 确认它是一个 DHCP 客户端。(如果显示manual 则不是。)将接口关闭然后再次打开:

$ sudo nmcli con down *1net*
Connection '1net' successfully deactivated (D-Bus active path: /org/freedesktop/
NetworkManager/ActiveConnection/11

$ sudo nmcli con up *1net*
Connection successfully activated (D-Bus active path: /org/freedesktop/NetworkMan
ager/ActiveConnection/15)

检查您的 Dnsmasq 服务器日志:

$ journalctl -ru dnsmasq
-- Logs begin at Sun 2021-02-28 14:35:01 PST, end at Mon 2021-05-31 17:36:04
 PDT. --
May 31 17:34:56 dns-server dnsmasq-dhcp[8080]: DHCPACK(eth0) 192.168.1.45
 9c:ef:d5:fe:01:7c client2
May 31 17:34:56 dns-server dnsmasq-dhcp[8080]: DHCPREQUEST(eth0) 192.168.1.45
9c:ef:d5:fe:01:7c

这显示了从dns-server 成功向client2 分配 IP 地址。

讨论

您可以使用 NetworkManager 面板小程序而不是nmcli,或运行nm-connection-editor 命令打开 NetworkManager 的图形配置程序,然后通过鼠标点击断开连接并重新连接(图 16-2)。

大多数 Linux 发行版使用 NetworkManager 控制客户端的 DHCP。如果您的发行版没有使用,可能使用dhclient。查找一个dhclient.conf 配置文件,如果存在,则使用dhclient 命令请求一个新的租约:

$ sudo dhclient -v
Internet Systems Consortium DHCP Client 4.3.6-P1
Copyright 2004-2018 Internet Systems Consortium.
All rights reserved.
For info, please visit https://www.isc.org/software/dhcp/

Listening on LPF/*eth0/9c:ef:d5:fe:01:7c*
Sending on   LPF/*eth0/9c:ef:d5:fe:01:7c*
Sending on   Socket/fallback
DHCPREQUEST on *eth0* to 255.255.255.255 port 67 (xid=0xec8923)
DHCPACK from *192.168.1.10* (xid=0xec8923)
bound to *192.168.1.27* -- renewal in 1415 seconds.

您可以通过 DHCP 发送一些客户机器需要的信息以访问网络服务。参见食谱 16.10 了解更多信息。

使用 nm-connection-editor 管理网络连接

图 16-2. 使用 nm-connection-editor 管理网络连接

dhcp-range=192.168.1.25,192.168.10.75,24h 定义了一个包含 50 个可用地址租约的范围,租约时间为 24 小时。此范围不得包括您的 Dnsmasq 服务器或任何具有静态 IP 地址的主机。定义租约时间的单位可以是秒、分钟或小时。默认为一小时,最小为两分钟。如果希望租约永不过期,请不要指定租约时间。

dhcp-lease-max=25定义同时活动的租约数量。您可以拥有一个大的地址池,并限制活动租约的数量。

参见

  • Recipe 16.10

  • Dnsmasq

  • man 8 dhclient

16.10 在 DHCP 上宣传重要服务

问题

您希望向 LAN 客户端通过 DHCP 宣传各种服务器。

解决方案

一些服务(如默认的网关、DNS 服务器和 NTP 服务器)可以向您的 LAN 客户自动宣传,使其自动使用它们。以下示例显示如何配置/etc/dnsmasq.conf以宣传一些服务。

设置默认路由器:

dhcp-option=3,*192.168.1.1*

宣传您的 DNS 服务器:

dhcp-option=6,*192.168.1.10*

此示例指向您的本地 NTP 服务器的方法:

dhcp-option=42,*192.168.1.11*

您如何知道要使用哪些数字?使用此命令列出所有这些数字:

$ dnsmasq --help dhcp
Known DHCP options:
  1 netmask
  2 time-offset
  3 router
  6 dns-server
  7 log-server
  9 lpr-server
  [...]

讨论

dnsmasq --help dhcp 显示已知的 DHCPv4 配置选项。有关 DHCPv4 配置选项的更多信息,请参见 Recipe 16.11 中的讨论。

参见

16.11 为子网创建 DHCP 区域

问题

您有两个子网,希望配置 Dnsmasq 为它们应用不同的选项,如不同的默认路由器和服务器。

解决方案

定义您想要给它们的任何名称的区域,比如 zone1zone2,并设置它们的地址范围:

dhcp-range=*zone1,192.168.50.20,192.168.50.120*
dhcp-range=*zone2,192.168.60.20,192.168.60.50,24h*

两个区域有不同的路由器:

dhcp-option=*zone1,3,192.168.50.1*
dhcp-option=*zone2,3,192.168.60.2*

他们使用相同的 DNS 服务器:

dhcp-option=*zone1,6,192.168.1.10*
dhcp-option=*zone2,6,192.168.1.10*

zone2 获取一个 NTP 服务器:

dhcp-option=*zone2,42,192.168.60.15*

讨论

只有少数 DHCP 选项是有用的。它们非常古老,有些神秘,例如:

选项 default-url string;

此选项的格式和含义未在任何标准文档中描述,但据称被苹果电脑使用。不知道客户端如果提供此选项可能会做出什么合理的反应。使用需谨慎。

man 5 DHCP 选项

对许多客户端支持不一致。我只使用 NTP、路由器和 DNS 服务器。

参见

16.12 从 DHCP 分配静态 IP 地址

问题

您希望尽可能集中 IP 地址分配,包括分配静态 IP 地址。

解决方案

/etc/dnsmasq.conf 中使用 dhcp-host 选项。通过主机名标识客户机,并从您的 LAN 地址块中分配一个未使用的地址。(对于静态地址,不必使用您在 /etc/dnsmasq.conf 中使用 _dhcp-range= 选项定义的 DHCP 地址范围。)以下示例将一个地址分配给位于 192.168.3.0/24 网络中的server2

dhcp-host=*server2,192.168.3.45*

重新启动 Dnsmasq,那么下次server2请求地址时,将收到dhcp-host=选项指定的地址。

使用多个 dhcp-host= 行来配置多个客户端,每行一个。

您可以使用客户端的 MAC 地址代替主机名。

讨论

一般来说,集中管理行政事务可以节省时间和麻烦。

参见

16.13 配置 DHCP 客户端以自动输入 DNS 条目

问题

您希望您的 DHCP 客户端由 Dnsmasq 自动输入 DNS。

解决方案

客户端唯一需要做的事情是将其主机名发送到 Dnsmasq 的 DHCP 服务器,这在大多数 Linux 系统中是默认的。

假设本地sqr3l.nut域上的 DHCP 客户端使用主机名client4client4启动,并从 Dnsmasq 接收其 IP 地址和其他网络信息。Dnsmasq 接收client4的主机名并将其输入 DNS。现在网络上的其他主机可以访问client4client4.sqr3l.nut

/etc/hosts中不能有client4的重复条目。

有三种不同的方法可以检查您的 DHCP 客户端配置:在dhclient.conf中,使用 NetworkManager 的图形配置工具nm-connection-editor,以及使用nmcli命令。

首先检查dhclient,它多年来一直是 Linux 上的默认 DHCP 客户端。在大多数 Linux 系统中,其配置文件位于/etc/dhcp/dhclient.conf。查找此行,自动找到系统的主机名并将其发送到 DHCP 服务器:

send host-name = gethostname();

Or a line like this, specifying the system’s hostname:

send host-name = *myhostname*

如果没有dhclient.conf文件,那么 NetworkManager 是您的 DHCP 客户端管理器。您可以在图形的nm-connection-editor中检查此设置(图 16-3)。

NetworkManager 将客户端主机名发送到 DHCP 服务器

图 16-3. NetworkManager 将客户端主机名发送到 DHCP 服务器

当连接方式为“自动(DHCP)”时,NetworkManager 会将主机名发送到 DHCP 服务器。“仅自动(仅地址)”不会将主机名发送到 DHCP 服务器,但仅为客户端提供 DNS。

您也可以使用nmcli命令。首先找到您的活动网络连接:

$ nmcli connection show --active
NAME    UUID                                  TYPE      DEVICE
*wifi1   3e348c97-4c5f-4bbf-967e-7624f3e1e4f0*  wifi      *wlan1*

然后验证它是否将主机名发送到您的 DHCP 服务器。以下示例确认它确实这样做:

$ nmcli connection show *wifi1* | grep send-hostname
ipv4.dhcp-send-hostname:                yes
ipv6.dhcp-send-hostname:                yes

如果它显示no,则运行以下命令将其设置为yes。之后重新加载配置:

$ sudo nmcli con mod *wifi1* ipv4.dhcp-send-hostname yes
$ sudo nmcli con mod *wifi1* ipv6.dhcp-send-hostname yes
$ sudo nmcli con reload

讨论

如果您更喜欢使用 NetworkManager 的图形工具来管理 NetworkManager,则最好使用 NetworkManager 的图形配置实用程序nm-connection-editor,而不是其他图形工具,例如 GNOME 控制面板中的网络模块。nm-connection-editor提供了最完整的配置选项,并且在所有 Linux 发行版上都是相同的。

参见

  • man 1 nmcli

  • man 1 nmcli-examples

  • man 5 nm-settings

16.14 管理 Dnsmasq 日志记录

问题

Dnsmasq 有选项使用传统的syslog守护程序将其消息发送到您选择的文件,而不是journalctl,您想知道哪种是最佳选项。

解决方案

无论您使用哪种方法,都会记录相同的信息。默认行为是记录到 systemd 日志中。

将 Dnsmasq 的日志独立放在自己的目录中会更方便,比如 /var/log/dnsmasq/dnsmasq.log。在 /etc/dnsmasq.conf 中使用 log-facility= 选项指定你想要使用的日志文件,然后重新启动 Dnsmasq。文件必须已经存在,否则 Dnsmasq 将无法启动。

如果不设置日志轮换,你的日志文件会变得非常大。下面是一个简单的每周轮换的例子配置,/etc/logrotate.d/dnsmasq

/var/log/dnsmasq/dnsmasq.log {
    missingok
    compress
    notifempty
    rotate 4
    weekly
    create
    }

使用 logrotate 命令进行测试:

$ sudo /etc/logrotate.conf --debug
[...]
rotating pattern: /var/log/dnsmasq/dnssmasq.log  weekly (4 rotations)
empty log files are not rotated, old logs are removed
switching euid to 0 and egid to 4
considering log /var/log/dnsmasq/dnssmasq.log
Creating new state
  Now: 2021-06-01 13:08
  Last rotated at 2021-06-01 13:00
  log does not need rotating (log has been already rotated)
switching euid to 0 and egid to 0
[...]

没有显示错误,一切正常工作。

讨论

systemd 同时支持 journalctlsyslog 守护程序。它们可能长期共存,因此你可以按照你喜欢的方式设置日志记录。

参见

  • man 8 rsyslog

  • Dnsmasq

  • man 1 journalctl

  • 第二十章

16.15 配置通配符域名

问题

你想在 Dnsmasq 中创建一个通配符域名,这样请求该域的子域将无需手动添加即可解析到你的 DNS。

解决方案

/etc/dnsmasq.conf 中使用 address 选项创建顶级域名(TLD):

address=/*wildcard.net/192.168.1.35*

重新启动 Dnsmasq,然后运行 nslookup 进行测试:

$ sudo systemctl restart dnsmasq.service
$ nslookup *foo.wildcard.net*
Server:         127.0.0.1
Address:        127.0.0.1#53

Name:   *foo.wildcard.net*
Address: 192.168.1.35

foo.wildcard.net 被解析,证明工作正常。

讨论

谨慎使用 DNS 通配符。在处理像 Kubernetes 这样复杂服务的开发工作时,通配符非常有用。确保使用的地址范围不同于你 LAN 上的名称服务器范围,并且仅对 LAN 客户端可用。

参见

第十九章:SystemRescue 与 SystemRescue 的系统恢复

SystemRescue DVD 或 USB 驱动器是一个必备工具,您可以使用它来救援非启动的 Linux 和 Windows 系统。在本章中,您将学习如何创建 SystemRescue 引导介质,如何在 SystemRescue 中找到您所需的内容,自定义引导选项,修复 GRUB,从故障磁盘中恢复文件,重置 Linux 和 Windows 密码,以及将 SystemRescue 从只读文件系统转换为带有数据分区的读写文件系统。

任何 Live Linux 都可以用作救援系统。SystemRescue 的优势在于其小巧的体积,专为救援操作而设计。

root 用户的 SystemRescue 文件系统是只读的,因此关闭后会丢失所有更改。您将学习如何设置以保留更改,如配置、外观和添加软件。

SystemRescue 最初基于 Gentoo Linux,自 6.0 版本起改为基于 Arch Linux 构建。Arch Linux 以其可靠和高效的特性而闻名,拥有一流的文档。请访问https://archlinux.org获取文档和论坛。

我更喜欢使用 USB 设备进行 SystemRescue,包括 U 盘和 USB 硬盘。它们速度快,而且容量足够大,可以满足你复制文件的需求。

19.1 创建您的 SystemRescue 可引导设备

问题

您希望制作一个 SystemRescue DVD 或 USB 驱动器。

解决方案

https://system-rescue.org下载最新的 SystemRescue .iso文件。

创建可引导 SystemRescue USB 存储设备的最可靠方法是使用dd命令(参见 Recipe 1.6)。参见 1.4 和 1.5 中的 Recipes,了解创建可引导 DVD 的说明。第一章还描述了如何引导到新介质以及如何禁用安全启动。SystemRescue 不包括签名密钥,因此您必须禁用安全启动。

当您从 USB 存储设备引导时,请将其插入计算机的 USB 端口,而不是 USB 集线器,因为在集线器上可能无法识别。

讨论

使用 SystemRescue 完成后,请记得重新启用安全启动。

参见

19.2 开始使用 SystemRescue

问题

您已启动 SystemRescue,并停留在简单的控制台提示符处,需要知道接下来该做什么。

解决方案

SystemRescue 在初始登录屏幕上为您提供说明(图 19-1)。您会自动以 root 用户登录,无需输入 root 密码。

您可以在控制台工作,也可以输入startx来启动 Xfce4 桌面环境(参见图 19-2)。

SystemRescue 登录屏幕。

图 19-1. SystemRescue 登录屏幕

SystemRescue Xfce4 桌面环境。

图 19-2. SystemRescue Xfce4 桌面环境

探索应用程序菜单,调整 Xfce 的外观,使用 NetworkManager 连接网络,并像任何 Linux 系统一样关闭或重新启动。

讨论

使用存储在压缩只读 SquashFS 文件系统中的系统救援镜像,唯一不能做到的是对其自身配置进行持久更改。因此,任何更改都不会在重启后保存。然而,你可以设置以保留你的更改;参见第 19.14 节。

SquashFS 是许多 Live Linux 发行版的基础,如 Ubuntu、Debian、Mint、Fedora 和 Arch。它还被开源路由器固件项目 DD-WRT 和 OpenWRT 使用。SquashFS 轻量且快速。

我喜欢使用 Xfce4,因为它提供了轻量级的图形环境和应用程序,以及用于命令行操作的 X 终端。

参见

19.3 理解 SystemRescue 的两个引导屏幕

问题

在测试 SystemRescue 时,你注意到有两个不同的引导屏幕,想知道它们的作用是什么。

解决方案

根据启动 SystemRescue 的方式,有两个不同的引导屏幕。你将看到一个传统 BIOS 引导屏幕(见图 19-3)和一个 UEFI 引导屏幕(见图 19-4)。

当我戴尔系统上的 UEFI 设置允许启动传统设备时,一次性引导菜单(启动时按 F12)将显示所有可能的启动选项(见图 19-5)。SystemRescue 支持 UEFI,因此不需要启用传统引导。(请记住,要启动 SystemRescue,必须禁用安全启动。)

你的系统的 BIOS/UEFI 可能与我的不同,因为它们各不相同。

SystemRescue 的传统引导屏幕。

图 19-3. SystemRescue 传统 BIOS 引导屏幕

SystemRescue 的 UEFI 引导屏幕。

图 19-4. SystemRescue 的 UEFI 引导屏幕

戴尔一次性引导菜单显示所有可能的启动选项。

图 19-5. 戴尔一次性引导菜单显示所有可能的启动选项

两个引导屏幕的主要区别在于 SystemRescue 的 UEFI 引导屏幕具有“启动 EFI Shell”和“EFI 固件设置”选项,这些选项不适用于传统 BIOS 引导。

传统 BIOS 引导屏幕没有两个 EFI 选项,但包括 Memtest86+用于测试系统内存。

参见第 19.4 节了解不同的 SystemRescue 引导选项。

讨论

你可以将可移动介质配置为默认启动设备。然后,你无需麻烦地进入 BIOS/UEFI 以启用不同的启动设备或等待合适的时机调用一次性启动菜单;只需在需要时插入可移动启动介质即可。

如果你正在使用没有 UEFI 的旧系统,你不必选择或麻烦于安全启动。

参见

19.4 理解 SystemRescue 的引导选项

问题

您想知道所有这些 SystemRescue 引导选项是用来做什么的(第 19.3 节)。

解决方案

引导菜单选项是最常用的引导选项的快捷方式,省去了打开编辑表单和输入它们的麻烦。在大多数情况下,您将使用第一个引导选项,“使用默认选项启动 SystemRescue”。

第二个选项,“启动 SystemRescue 并将其复制到 RAM 中 (copytoram)” 通过将 SystemRescue 完全加载到内存中来加快性能。当您从 DVD 运行 SystemRescue 时,这尤其有用。它大约使用 2GB RAM。

第三个选项,“引导 SystemRescue 并验证介质的完整性 (checksum)” 检测自身是否损坏。使用此选项验证您的 SystemRescue 是否健康。

第四个选项,“使用基本显示驱动程序启动 SystemRescue (nomodeset)” 使用低分辨率的基本视频驱动程序。如果您的视频显示不正确,因为 SystemRescue 没有正确的图形驱动程序,请使用此选项。

第五个选项,“引导已安装在磁盘上的 Linux 操作系统 (findroot)” 是检查非引导 Linux 安装问题的良好方法。它将找到可引导的分区,如果有多个分区,它会列出所有分区,您可以选择要使用的分区。

第六个选项,“在挂载根文件系统之前停止根过程” 是 SystemRescue 无法启动时的修复模式。我认为准备一些额外的 SystemRescue 驱动比尝试修复损坏的 SystemRescue 更容易。

UEFI 启动屏幕有两个额外选项:“启动 EFI Shell” 和 “EFI 固件设置”。 “启动 EFI Shell” 可访问多个 EFI 实用工具,“EFI 固件设置” 可进入系统的 UEFI 设置。

然后重新启动和关机。

BIOS 启动屏幕有两个额外选项:“启动现有操作系统” 和 “运行 Memtest86+”。 “启动现有操作系统” 通过绕过系统的引导加载程序来帮助诊断引导加载程序问题,“Memtest86+” 测试系统内存。

两个屏幕都包括“重新启动”和“关机”,用于重新启动或关闭 SystemRescue 而不是启动它。

讨论

我认为使用 EFI Shell 并没有太大的价值,因为它支持远远超出您需要用于救援非引导系统的高级操作。参见 Intel 的使用可扩展固件接口的基本说明以了解更多信息。

所有这些菜单选项都是 SystemRescue 的一些引导选项的快捷方式,这些选项在https://system-rescue.org中有文档记录。您可以在本章的几个示例中看到,可以在任何 SystemRescue 引导菜单项中附加引导选项。

您可以在启动 SystemRescue 后执行这些任务,或传入启动选项。在传统 BIOS 屏幕上,选择您的启动条目,然后按 Tab 键打开编辑字段。输入`rootpass=yourpassword nofirewall,然后按 Enter 键继续启动。

在 UEFI 启动屏幕上,按 E 键以传递您自己的启动选项。

参见

19.5 识别文件系统

问题

您需要知道如何识别硬盘上的文件系统,以确保在救援操作中使用正确的文件系统。

解决方案

使用经典的lsblk命令:

# lsblk -f
NAME   FSTYPE   FSVER LABEL     UUID                SAVAIL FSUSE% MOUNTPOINT
loop0  squashfs 4.0                                      0   100% /run/archiso/sf
s/airootfs
sda
├─sda1
└─sda2 ntfs                     5E363
sdb
├─sdb1 vfat     FAT16 BOOT      5E2F-1E75
├─sdb2 btrfs          root      02bfdc9a-b8bb-45ac-95a8
├─sdb3 xfs            home      cc8acf0b-529e-473c-b484
└─sdb4 swap     1               7a5519ae-efe6-45e6-b147
sdc    iso9660        RESCUE800 2021-03-06-08-53-50-00
└─sdc1 iso9660        RESCUE800 2021-03-06-08-53-50-00    0   100% /run/archiso/
bootmnt

讨论

使用文件系统标签可以更轻松地找到正确的文件系统。例如,在/etc/fstab中,您也可以使用标签代替 UUID。有关管理文件系统标签的信息,请参阅第 9.4 节和第十一章。

lsblk不需要 root 权限,并且可以以几乎任何您想要查看的方式显示有关块设备的信息。

参见

  • 第 9.4 节

  • 第 11.2 节

  • 第十一章

19.6 重置 Linux 根密码

问题

您忘记了 Linux 的根密码,需要重置它。

解决方案

启动 SystemRescue,然后挂载正确的根文件系统。在以下示例中,根文件系统位于/dev/sdb2。在/mnt中创建一个挂载点,然后挂载您的文件系统:

# mkdir /mnt/*sdb2*
# mount /dev/*sdb2* /mnt/*sdb2*

从 SystemRescue 的根文件系统切换到您挂载的文件系统:

# chroot /mnt/sdb2/ /bin/bash
:/ #

重置根密码:

:/ # passwd root
New password:
Retype new password:
passwd: password updated successfully
:/ #

输入exit返回到 SystemRescue 的根文件系统。

重新启动,登录,然后尝试您的新密码。

讨论

您无法恢复忘记的密码,只能创建一个新密码。

这适用于任何用户的密码。

切换到主机系统的根文件系统后,您可以运行一些命令,但不是所有命令,因为这不是完整的文件系统。它缺少所有仅存在于内存中的伪文件系统,如sysfsproc。参见第 19.9 节了解如何设置更完整的chroot环境。

曾经,您可以通过删除/etc/shadow中的密码哈希来重置根密码。那时候是这样,现在pam子系统更复杂并控制授权。如果您感兴趣,请研究 SystemRescue 的pam配置,了解如何设置允许空根密码。

参见

19.7 在 SystemRescue 中启用 SSH

问题

您希望访问 SystemRescue 的 SSH。

解决方案

SSH 默认启用,防火墙也是如此。禁用防火墙以允许传入的 SSH 会话。

启动 SystemRescue 后,使用systemctl禁用防火墙:

[root@systemrescue ~]# systemctl stop iptables.service

在 SystemRescue 上,默认情况下,root 没有密码。您必须创建一个密码才能启用 SSH 会话:

[root@systemrescue ~]# passwd root
New password:
Retype new password:
passwd: password updated successfully

现在您可以从另一台计算机登录到 SystemRescue:

$ ssh root@*192.168.10.101*
ssh root@192.168.1.91
The authenticity of host '192.168.1.91 (192.168.1.91)' can't be established.
ECDSA key fingerprint is SHA256:LlUCEngz5NHg98xv.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.1.91' (ECDSA) to the list of known hosts.
root@192.168.1.91's password:
[root@sysrescue ~]# 

讨论

每次启动 SystemRescue,它都像一个全新的系统,具有不同的 SSH 主机密钥。如果重新启动 SystemRescue,然后从同一台计算机向 SystemRescue 打开第二个 SSH 系统,您将看到此警告:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!

这还要继续几行,并告诉您补救方法:

Offending ECDSA key in /home/duchess/.ssh/known_hosts:12
  remove with:
  ssh-keygen -f "/home/duchess/.ssh/known_hosts" -R "192.168.10.101"

按照它说的做,然后您可以通过 SSH 连接到 SystemRescue。

您可以从引导菜单禁用防火墙。按 Tab 键(传统引导)或 E 键(UEFI 引导)添加nofirewall引导选项(请参见屏幕底部的引导参数行,图 19-6)。

在引导时禁用防火墙。

图 19-6. 在引导时禁用防火墙

另请参阅

19.8 通过 scp 和 sshfs 在网络上复制文件

问题

您已经在要救援的系统上运行 SystemRescue,并希望通过网络复制文件来救援它们。

解决方案

没问题,就像在任何 Linux 上一样操作。首先启用 SSH(第 19.7 节)。然后使用scpsshfs移动您想要保存的文件。本配方中的所有命令都是从 SystemRescue 运行的。

使用lsblk找到要从中复制文件的文件系统。如果您不记得要复制哪个分区,请挂载每个分区以查看文件,直到找到正确的分区:

# lsblk -f
NAME   FSTYPE   FSVER LABEL     UUID                SAVAIL FSUSE% MOUNTPOINT
loop0  squashfs 4.0                                      0   100% /run/archiso/sf
s/airootfs
sda
├─sda1
└─sda2 ntfs                     5E363E30363E0993
sdb
├─sdb1 vfat     FAT16 BOOT      5E2F-1E75
├─sdb2 btrfs          root      02bfdc9a-b8bb-45ac-95a8
├─sdb3 xfs            home      cc8acf0b-529e-473c-b484
└─sdb4 swap     1               7a5519ae-efe6-45e6-b147
sdc    iso9660        RESCUE800 2021-03-06-08-53-50-00
└─sdc1 iso9660        RESCUE800 2021-03-06-08-53-50-00    0   100% /run/archiso/b
ootmnt
sr0 

以下示例将在 SystemRescue 上将包含/home的分区挂载到/mnt,列出挂载点中的文件,然后使用scp将整个/home目录复制到 Duchess 的 PC 上:

# mkdir /mnt/*sdb3*
# mount /dev/*sdb3* /mnt/*sda3*
# ls /mnt/*sdb3*
bin   dev  home  lib64       media  opt   root  sbin  sys  usr
boot  etc  lib   lost+found  mnt    proc  run   srv   tmp  var
# scp -r /mnt/sdb3/home/ duchess@pc:

结果是/home/duchess/home

永远在/mnt 中创建子目录

永远不要在/mnt中挂载任何文件系统;这会使 SystemRescue 冻结。始终为您的挂载点创建子目录。

您可以复制一个以空格分隔的文件和目录列表,并将它们混合复制到duchess@pc上的rescue目录。远程目录必须已经存在:

# cd /mnt/sdb3/home/
# scp -r *file1.txt directory1 file2.txt* duchess@pc:rescue/

sshfs很方便,因为它挂载远程文件系统,使其看起来像本地文件系统一样,并且您可以像操作本地文件一样复制文件。在 SystemRescue 上创建一个挂载点,然后在其上挂载远程目录(该目录必须已经存在)。您将从 SystemRescue 复制文件到远程系统:

# mkdir /mnt/*remote*
# sshfs duchess@pc:rescue/ /mnt/*remote*/
# ls /mnt/*remote*
rescue

现在您可以在 SystemRescue 上使用cp命令,或使用图形文件管理器复制文件(图 19-7)。

使用图形文件管理器在 SystemRescue 上复制文件。

图 19-7. 使用图形文件管理器在 SystemRescue 上复制文件

完成后,运行fusermount -u *remote*以安全卸载sshfs文件系统。

讨论

如果您已在要将文件复制到的系统上禁用了 SSH 密码身份验证,请通过在/etc/ssh/sshd_config中注释掉PermitRootLogin no来临时重新启用它。

连接到远程目录的语法与您登录的用户帐户相关。duchess@pc: 等同于 duchess@pc:/home/duchessduchess@pc:/ 访问根文件系统。当您需要编辑系统配置文件时,请使用duchess@pc:/etc;对于引导文件,请使用duchess@pc:/boot等等。

您可以使用ssh从 SystemRescue 创建远程目录:

# ssh *duchess@pc*
duchess@pc's password:
duchess@pc:~$ mkdir remote

参见

  • Recipe 6.5

  • 第十二章

19.9 从 SystemRescue 修复 GRUB

问题

您的 GRUB 引导加载程序损坏,系统无法启动。

解决方案

启动 SystemRescue,创建chroot环境,并重新安装 GRUB。

在启动 SystemRescue 后,为主机上的根文件系统创建chroot环境:

# mkdir /mnt/linux
# mount /dev/*sda2* /mnt/linux
# mount -o bind /proc /mnt/linux/proc
# mount -o bind /dev /mnt/linux/dev
# mount -o bind /sys /mnt/linux/dev

进入chroot环境:

# chroot /mnt/linux /bin/bash
:/ #

如果/boot位于单独的分区上,请将其挂载:

:/ # mount /dev/sda1 /boot/

现在重新安装 GRUB:

:/ # grub-install /dev/sda

完成后,键入exit退出chroot环境,然后卸载所有文件系统。重新启动您的系统,GRUB 应该正常工作。

讨论

创建chroot环境时一定要非常小心,并确保使用正确的分区和文件系统。chroot,即 change root,是一个在不重启的情况下切换到不同根文件系统的强大工具。

您必须卸载所有chroot文件系统,以便它们能够干净卸载。简单重启应该没问题,但手动卸载它们是一种廉价的保险措施。

参见

  • man 1 chroot

19.10 重置 Windows 密码

问题

您忘记了 Windows 密码,并且不想按照通常的 Windows 步骤重置密码。

解决方案

不用担心,SystemRescue 将使您迅速恢复正常。在 Windows 机器上启动 SystemRescue,然后挂载您的 Windows 系统目录:

# mkdir /mnt/windows
# mount /dev/*sda2*

导航到/mnt/windows/Windows/System32/config目录,然后使用chntpw(更改 NT 密码)命令列出用户:

# cd /mnt/windows/Windows/System32/config
# chntpw -l SAM
chntpw version 1.00 140201, (c) Petter N Hagen
Hive <SAM> name (from header): <\SystemRoot\System32\Config\SAM>
ROOT KEY at offset: 0x001020 * Subkey indexing type is: 686c <lh>
File size 65536 [10000] bytes, containing 7 pages (+ 1 headerpage)
Used for data: 318/31864 blocks/bytes, unused: 29/12968 blocks/bytes.

| RID -|---------- Username ------------| Admin? |- Lock? --|
| 01f4 | Administrator                  | ADMIN  |          |
| 03e9 | duchess                        | ADMIN  |          |
| 01f7 | DefaultAccount                 |        | dis/lock |
| 01f5 | Guest                          |        | dis/lock |
| 01f8 | WDAGUtilityAccount             |        | dis/lock |

检查您要更改的用户信息:

# chntpw -u Administrator SAM
chntpw version 1.00 140201, (c) Petter N Hagen
Hive <SAM> name (from header): <\SystemRoot\System32\Config\SAM>
ROOT KEY at offset: 0x001020 * Subkey indexing type is: 686c <lh>
File size 65536 [10000] bytes, containing 9 pages (+ 1 headerpage)
Used for data: 321/33816 blocks/bytes, unused: 34/27336 blocks/bytes.

================= USER EDIT ====================

RID     : 0500 [01f4]
Username: Administrator
fullname:
comment : Built-in account for administering the computer/domain
homedir :

00000220 = Administrators (which has 2 members)

Account bits: 0x0210 =
[ ] Disabled        | [ ] Homedir req.    | [ ] Passwd not req. |
[ ] Temp. duplicate | [X] Normal account  | [ ] NMS account     |
[ ] Domain trust ac | [ ] Wks trust act.  | [ ] Srv trust act   |
[X] Pwd don't expir | [ ] Auto lockout    | [ ] (unknown 0x08)  |
[ ] (unknown 0x10)  | [ ] (unknown 0x20)  | [ ] (unknown 0x40)  |

Failed login count: 0, while max tries is: 0
Total  login count: 5

- - - - User Edit Menu:
 1 - Clear (blank) user password
 2 - Unlock and enable user account [probably locked now]
 3 - Promote user (make user an administrator)
 4 - Add user to a group
 5 - Remove user from a group
 q - Quit editing user, back to user select
Select: [q] ^

输入1以删除现有密码:

Select: [q] ^ 1
Password cleared!
[...]

q退出,按y“写入 hive 文件”,保存您的更改。

现在管理员或您选择的用户必须登录并设置新密码。

讨论

您无法使用chntpw创建新密码或恢复旧密码,只能删除密码。然后您可以无密码登录并创建新密码,或者如果您的用户存在,让他们完成。

参见

19.11 使用 GNU ddrescue 拯救失败的硬盘

问题

您怀疑您的硬盘即将损坏,并希望在其失效之前将数据从中复制出来。

解决方案

您需要优秀的 GNU ddrescue实用工具。ddrescue首先尝试复制所有良好的数据块,尽可能保存更多数据,并跳过坏块,将其位置记录在日志文件中。您可以进行多次尝试以获取更多数据。

你正在尝试救援的磁盘必须卸载。你需要另一个也卸载的磁盘,比如 USB 存储设备或者内部硬盘,来复制已救援的数据。你的目标分区必须已经存在,并且比你尝试救援的分区大至少 50%。

以下示例将/dev/sdb1复制到/dev/sdc1

# ddrescue -f -n /dev/sdb1 /dev/sdc1 ddlogfile
GNU ddrescue 1.25
Press Ctrl-C to interrupt
     ipos:   100177 MB, non-trimmed: 0 B    current rate:   207 MB/s
     opos:   100177 MB, non-scraped: 0 B    average rate: 83686 kB/s
non-tried:    47868 MB,  bad-sector: 0 B,     error rate:      0 B/s
  rescued:   100177 MB,   bad areas: 0,         run time:    23m 56s
pct rescued:    66.77%, read errors: 0,   remaining time:      6m 4s
                         time since last successful read:         0s
Copying non-tried blocks... Pass 1 (forwards)

这将花费一些时间。当完成时,最后一行会显示“Finished.”。

这个示例进行了一次复制,尽快地复制最容易读取的块。在有很多错误的驱动器上,这是一个很好的策略,因为ddrescue不会花费大量时间来恢复最受损块。在进行第一次复制后,再运行三次,尝试恢复更多数据:

# ddrescue -d -f -r3 /dev/sdb1 /dev/sdc1 ddlogfile

当完成时,在恢复磁盘上运行文件系统检查,该磁盘应保持未挂载状态。此示例检查并自动修复 Ext4 文件系统:

# e2fsck -vfp /dev/sdc1

-f 强制检查,以防e2fsck认为文件系统是干净的。-p 是 preen(修复)的简写,-v 是详细模式。如果它发现需要你干预的问题,它会打印问题的描述并退出。

e2fsck -vf [device] 启动交互式检查和修复。

fsck.vfat -vfp [device] 适用于 FAT16/32。

xfs_repair [device] 适用于 XFS 文件系统。

如果你恢复的文件系统通过了文件系统检查,那么可以将文件复制到最终位置。如果仍然存在问题,请以只读方式挂载它:

# mkdir /mnt/sdc1-copy
# mount -o ro /dev/sdc1 /mnt/sdc1-copy

然后尽可能多地复制文件到另一个磁盘。

讨论

确保你安装的是 GNU ddrescue,作者是 Antonio Diaz Diaz,而不是 Kurt Garloff 的dd-rescuedd-rescue 是一个很棒的工具,但使用起来更复杂。

ddrescue 在块级别复制,所以你尝试救援的文件系统是什么并不重要。ddrescue会无论你的 Linux 支持哪些文件系统,都会做一个精确的复制。

如果ddrescue在最后一刻空间不足,它将失败,所以确保你的恢复驱动器有足够的空间。

你可以在 USB 存储设备,CompactFlash 和 SD 卡上使用ddrescue

另请参阅

19.12 从 SystemRescue 管理分区和文件系统

问题

你想要对硬盘进行分区或者对文件系统进行更改,并且你需要从一个外部 Linux 系统来完成。

解决方案

使用 SystemRescue。SystemRescue 包括 GParted 和parted。你不需要挂载任何文件系统,SystemRescue 会直接在你的主机系统的块设备上操作。使用lsblk来查看你的主机块设备:

[root@systemrescue ~]# lsblk -p -o NAME,FSTYPE,LABEL
NAME          FSTYPE     LABEL
/dev/loop/0   squashfs
/dev/sr0
/dev/sr1      iso9660    RESCUE800
/dev/sda
├─/dev/sda1   vfat
├─/dev/sda2   xfs        osuse15-2
├─/dev/sda3   xfs        home
├─/dev/sda4   xfs
└─/dev/sda5   swap
/dev/sdb
└─/dev/sdb1   xfs        backups
/dev/sr0

按照第 8,9 和 11 章的说明来管理分区和文件系统。

另请参阅

  • 第八章

  • 第九章

  • 第十一章

19.13 在你的 SystemRescue USB 驱动器上创建一个数据分区

问题

USB 驱动器上的 SystemRescue 对你很有效,但你想知道如何将设备分区,使得 SystemRescue 根文件系统在第一个分区上,第二个分区上有可写文件系统。然后你只需一个设备来复制文件。

解决方案

你只需几个步骤就可以完成这个操作。

标准的 SystemRescue 镜像无法从分区引导。它使用的空间不到 1 GB,因此任何 USB 闪存都会有大量的空间浪费。使 SystemRescue 从分区引导的技巧是使你的 SystemRescue ISO 能够从分区引导,添加主引导记录(MBR),然后安装引导代码 mbr.bin

你需要 isohybridmbr.bin,它们由 syslinux 提供。在 Fedora 和 openSUSE 上由 syslinux 包提供,在 Ubuntu 上由 syslinux-utilsinstall-mbr 提供。

在下面的示例中,将 /dev/sdc 替换为你自己的设备。

首先,使 SystemRescue 镜像可以从分区引导:

$ isohybrid --partok *systemrescuecd-8.01-amd64.iso*

在你的 USB 驱动器上创建一个 msdos 分区表。使用 GParted(Recipe 9.2)或 parted

$ sudo parted /dev/*sdc*
(parted) mklabel msdos

在你的 USB 驱动器上创建两个分区。将第一个分区的文件系统类型设置为 FAT32,并设置 boot 标志。下面的示例创建了一个大约 2 GB 的引导分区:

(parted) mkpart "sysrec" fat32 1MB 2000MB
(parted) set 1 boot

为数据存储添加第二个分区,使用你喜欢的任何文件系统类型。下面的示例创建了一个 2 GB 的分区,然后退出 parted

(parted) mkpart "data" xfs 2001MB 4000MB
(parted) q

创建你的文件系统。第一个分区是带有标签 SYSRESCUE 的 FAT32,第二个分区是带有标签 data 的 XFS:

$ sudo mkfs.fat -F 32 -n *SYSRESCUE /dev/sdc1*
$ sudo mkfs.xfs -L *data /dev/sdc2*

将 SystemRescue 安装到第一个分区:

$ sudo dd status=progress if=*systemrescuecd-8.01-amd64.iso* of=/dev/*sdc1*

在 Ubuntu 上,将 MBR 安装到 USB 驱动器上:

$ sudo install-mbr /dev/*sdc*

在其他 Linux 上,使用 dd

$ sudo if=*/usr/share/syslinux/mbr.bin* of=/dev/*sdc*

mbr.bin 可能位于不同目录,具体取决于你使用的 Linux 发行版。

启动你的 SystemRescue 驱动器,它应该正常启动。

讨论

你的文件系统不需要标签;它们是方便帮助你记住它们的用途。

你可以在第一个分区上使用任何文件系统。FAT32 是通用的,因此你可以在 Linux、macOS 和 Windows 上引导 SystemRescue。对于从 macOS 和 Windows 复制文件,将数据分区格式化为 FAT32 或 exFAT。

你必须手动挂载第二个分区,然后你可以按照你的意愿使用它。它方便地用于从主机系统复制文件,拥有这个可写分区的最酷的事情是你可以将其用作存储 SystemRescue 中所做更改的后备存储,例如配置更改和安装软件。查看 Recipe 19.14 详细了解。

参见

19.14 在 SystemRescue 中保留更改

问题

SystemRescue 对你很有效,但你希望能保留一些更改,而不必每次启动 SystemRescue 时重新开始。

解决方案

参见 Recipe 19.13,学习如何在你的 SystemRescue USB 驱动器上创建一个可写分区。给这个分区取一个文件系统标签,比如data。设置好后,启动 SystemRescue,选择你的启动菜单选项,按 Tab 键,并在你的启动选择中添加cow_label=*data*(见图 19-8)。

添加引导选项。

图 19-8. 添加引导选项

SystemRescue 挂载你的两个分区到/run/archiso/

# lsblk -p
lsblk
NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
[...]
sdc      8:32   1   3.7G  0 disk
├─sdc1   8:33   1     2G  0 part /run/archiso/bootmnt
└─sdc2   8:34   1   152G  0 part /run/archiso/cowspace

你对 SystemRescue 所做的所有更改都存储在/run/archiso/cowspace/persistent_RESCUE800中,而根文件系统保持不变。RESCUE800对于每个 SystemRescue 发布版本都是不同的,根据发布编号而定。

你可以像配置任何 Linux 系统一样配置 SystemRescue:启用和禁用服务,设置 root 密码,更改外观,安装新软件,更改网络配置或编写新文档。

讨论

大容量 USB 驱动器价格便宜,只需要一个救援设备非常方便。你可以使用 USB 闪存驱动器或 USB 硬盘驱动器。

参见

第十七章:使用 ntpd、chrony 和 timesyncd 进行时间保持

通过 NTP,网络时间协议,在你的计算机和网络上所有主机上保持精确的时间是容易且自动的。在 Linux 上,NTP 被实现为 ntpd,即 NTP 守护进程,chrony,即 ntpd 的现代替代品,以及 systemd 的 timesyncd。没错,朋友们,有三种(至少),数一数,三种方式可以自动管理你的 Linux 计算机上的时间。

ntpdchrony 可以作为局域网时间服务器,而 timesyncd 则是一个更简单的轻量级客户端,没有服务器功能。ntpdchrony 是完整的 NTP 实现,而 timesyncd 使用简单网络时间协议 SNTP。

大多数 Linux 发行版提供一个默认配置,指向它们维护的时间服务器。这些服务器的名称如 2.fedora.pool.ntp.org0.ubuntu.pool.ntp.org。你不必做任何事情,只需确保在安装过程中不要禁用它们。在本章中,您将学习如何检查当前设置,如何更改它们以及如何设置局域网时间服务器。

有一个全球网络的时间服务器供每个人免费使用,并且它们按照 strata 组织,从第 0 级开始。第 0 级是所有时间保持的源头,是一个原子钟、调谐到原子钟的无线接收器,以及使用 GPS 卫星广播信号的 GPS 接收器的网络。

接下来是第 1 级,那里是主要的时间服务器所在。第 1 级的主要时间服务器直接连接到第 0 级的来源。

第 2 级包含成千上万个公共服务器,并且它们与第 1 级同步。与第 2 级服务器连接是良好的礼仪,以防止第 1 级服务器不堪重负,并且不要没有充分理由地使用第 1 级服务器。

层次结构沿着这条线继续,例如有第 4、5 和 6 级公共服务器,以及与它们同步的私人局域网服务器。实际情况并不那么有条理;你可以将你的私人局域网 NTP 服务器指定为第 10 级,并且它不必连接到第 9 级服务器,而是任何它能够到达的服务器。你不必担心选择正确的服务器,因为你将使用 服务器,这些服务器是 NTP 服务器的集群,而不是单个服务器。

当你深入研究计算机上的时间保持时,它会变得令人困惑和不知所措,或许取决于你想要多么迷恋这个话题。访问NTP 池项目NTP:网络时间协议来学习这些技术和如何运行自己的公共时间服务器。

你的 Linux 系统上至少有两个时间管理器。一个是你主板上的硬件时钟,也称为实时时钟(RTC)。另一个是由 Linux 内核管理的系统时间。即使你的机器关闭了,RTC 也会始终有电,这得益于主板上的电池或电容器。当你的 Linux 计算机启动时,你选择的 NTP 客户端从 RTC 获取时间。然后,在网络可用后,它会根据其上游时间服务器纠正时间。

你的 RTC 时间由 BIOS/UEFI 设置,并且使用本章中将学到的某些命令。它应该始终设置为协调世界时(UTC),然后 Linux 内核从 UTC 计算你的时区时间。UTC 类似于格林尼治平均时间(GMT),尽管它们不完全相同。UTC 是一个时间标准,而 GMT 是一个时间区域。UTC 和 GMT 都不会因夏令时改变。

时区数据来自IETF.org 时区。这是一个动态的目标,因为各国改变其夏令时日期、选择退出夏令时或重新加入。大多数 Linux 系统将这些信息存储在/usr/share/zoneinfo/中。互联网工程任务组(IETF)跟踪这些变化并免费提供他们的数据库。

17.1 确定你的 Linux 系统上使用了哪个 NTP 客户端

问题

你已经阅读了章节介绍,现在你知道在 Linux 上,时间同步由ntpdchronytimesyncd管理,你需要知道你的 Linux 系统使用的是哪一个。

解决方案

使用ps命令查看系统上是否有这三个时间同步守护进程之一正在运行:

$ ps ax|grep -w ntp
$ ps ax|grep -w chrony
$ ps ax|grep -w timesyncd

如果有任何一个正在运行,请跳到本章的相关小节,学习如何管理你的时间守护进程。

如果没有任何一个在运行,请查看你的系统是否在使用timedatectl,它是 systemd 的一部分:

$ timedatectl status
                      Local time: Sun 2020-10-04 10:59:48 PDT
                  Universal time: Sun 2020-10-04 17:59:48 UTC
                        RTC time: Sun 2020-10-04 17:59:48
                       Time zone: America/Los_Angeles (PDT, -0700)
       System clock synchronized: no
systemd-timesyncd.service active: no
                 RTC in local TZ: no

这个输出显示timedatectl在运行,没有任何时间守护进程,显示systemd-timesyncd.service active: no。通过查询systemd-timesyncd的状态再次确认:

$ systemctl status systemd-timesyncd
● systemd-timesyncd.service - Network Time Synchronization
   Loaded: loaded (/lib/systemd/system/systemd-timesyncd.service; disabled;
vendor preset: enabled)
   Active: inactive (dead)
     Docs: man:systemd-timesyncd.service(8)

这表明systemd-timesyncd没有运行,这意味着你的系统没有时间同步,而是从你系统的实时时钟(RTC)获取时间。在这种情况下,你需要设置ntpdchronytimesyncd

讨论

一些 Linux 发行版不使用 systemd;查看第 4.1 节了解如何知道你的 Linux 是否安装了它。如果你运行的是没有 systemd 的 Linux 系统,则你的 NTP 选择是ntpdchrony

如果你发现系统上同时运行ntpdchrony,请删除ntpd,因为chrony更新更快、更可靠。同时使用两者会造成冲突。

timedatectl的输出包含大量有用信息。示例显示 RTC 已正确设置为协调世界时(UTC)协议,并且系统时区为太平洋夏令时,PDT。systemd-timesyncd.service未运行,并且系统未同步。

参见

17.2 使用 timesyncd 进行简单时间同步

问题

您想知道如何设置最简单的 NTP 客户端以保持计算机上的正确时间。

解决方案

使用systemd-timesyncd守护程序启用与公共 NTP 服务器的同步,该守护程序需要 systemd。检查systemd-timesyncd的状态:

$ systemctl status systemd-timesyncd
● systemd-timesyncd.service - Network Time Synchronization
     Loaded: loaded (/usr/lib/systemd/system/systemd-timesyncd.service;
       disabled; vendor preset: enabled)
     Active: inactive (dead)
       Docs: man:systemd-timesyncd.service(8)

使用timedatectl启用它,并验证systemd-timesyncd已启动:

$ timedatectl set-ntp true
$ systemctl status systemd-timesyncd
● systemd-timesyncd.service - Network Time Synchronization
   Loaded: loaded (/lib/systemd/system/systemd-timesyncd.service; enabled;
vendor preset: enabled)
   Active: active (running) since Sun 2020-10-04 18:17:51 PDT; 16min ago
     Docs: man:systemd-timesyncd.service(8)
 Main PID: 3990 (systemd-timesyn)
   Status: "Synchronized to time server 91.189.89.198:123 (ntp.ubuntu.com)."
    Tasks: 2 (limit: 4915)
   CGroup: /system.slice/systemd-timesyncd.service
           └─3990 /lib/systemd/systemd-timesyncd

Oct 04 18:17:51 pc systemd[1]: Starting Network Time Synchronization...
Oct 04 18:17:51 pc systemd[1]: Started Network Time Synchronization.
Oct 04 18:33:01 pc systemd-timesyncd[3990]: Synchronized to time server
91.189.89.198:123 (ntp.ubuntu.com).

如果systemd-timesyncd未启动,请启动它:

$ sudo systemctl start systemd-timesyncd

现在查看timedatectl报告的内容:

$ timedatectl status
                      Local time: Sun 2020-10-04 18:35:56 PDT
                  Universal time: Mon 2020-10-05 01:35:56 UTC
                        RTC time: Mon 2020-10-05 01:35:56
                       Time zone: America/Los_Angeles (PDT, -0700)
       System clock synchronized: yes
systemd-timesyncd.service active: yes
                 RTC in local TZ: no

一切看起来都正确。您的系统已同步,所有时间都正确,并且systemd-timesyncd.service处于活动状态。

配置多个公共时间服务器以增强冗余性是一种良好的实践。编辑/etc/systemd/timesyncd.conf以通过取消注释NTP行并输入空格分隔的公共服务器池列表来添加更多 NTP 服务器:

[Time]
NTP=0.north-america.pool.ntp.org 1.north-america.pool.ntp.org
2.north-america.pool.ntp.org
#FallbackNTP=ntp.ubuntu.com
#RootDistanceMaxSec=5
#PollIntervalMinSec=32
#PollIntervalMaxSec=2048

讨论

在您原始的/etc/systemd/timesyncd.conf文件中,注释选项记录了默认配置。

由于它们是单个池中的多个服务器,而不是单个服务器,因此池服务器非常可靠。为了获得最佳性能,请使用适合您地区的池服务器,可以通过单击大陆池链接或国家池找到它们。

您的 Linux 发行版可能会配置多个自己的服务器池,例如:

0.opensuse.pool.ntp.org 1.opensuse.pool.ntp.org 2.opensuse.pool.ntp.org

这是很好的,您不需要更改它,但通常更多样化的配置通常更可靠。

参见

17.3 使用 timedatectl 手动设置时间

问题

你希望手动设置系统和 RTC 时间。

解决方案

使用timedatectl。它通过单个命令设置日期、系统时间和 RTC 时间:

$ timedatectl set-time "2020-10-04 19:30:00"
Failed to set time: Automatic time synchronization is enabled

systemd-timesyncd正在运行时,您无法执行此操作,因此必须停止它:

$ sudo systemctl stop systemd-timesyncd

然后按照示例中显示的格式 YYYY-MM-DD HH:MM:SS 输入新的设置,并验证其是否有效:

$ timedatectl set-ntp false
$ timedatectl set-time "2020-10-04 19:30:00"
$ timedatectl status
                      Local time: Sun 2020-10-04 19:30:06 PDT
                  Universal time: Mon 2020-10-05 02:30:06 UTC
                        RTC time: Mon 2020-10-05 02:30:06
                       Time zone: America/Los_Angeles (PDT, -0700)
       System clock synchronized: no
systemd-timesyncd.service active: no
                 RTC in local TZ: no

如果重新启动systemd-timesyncd,它将覆盖您的手动设置。

讨论

timedatectl有一组少量的命令。如果您习惯于使用date命令设置时间以及其他时间和日期操作,那么timedatectl可能会显得轻量级。它设计简单,您仍然可以使用date及其众多选项执行复杂任务。

参见

  • man 5 timesyncd.conf

17.4 使用 chrony 作为您的 NTP 客户端

问题

您希望拥有功能齐全的 NTP 客户端/服务器,并且想知道如何将chrony设置为您的 NTP 客户端。

解决方案

首先,检查是否安装了 ntpd。如果安装了,请将其删除。如果您有 systemd-timesyncd,请将其禁用:

$ sudo systemctl disable systemd-timesyncd
$ sudo systemctl stop systemd-timesyncd

然后安装 chrony。大多数 Linux 发行版的软件包名称是 chrony。安装后,使用 chronyc 命令来检查其状态:

$ chronyc activity
200 OK
8 sources online
0 sources offline
0 sources doing burst (return to online)
0 sources doing burst (return to offline)
0 sources with unknown address

成功!它已经在工作中,如 8 sources online 所示。(如果未启动,请参阅讨论。)找到您的 chrony.conf,可能是 /etc/chrony.conf(Fedora)或 /etc/chrony/chrony.conf(Ubuntu),查看设置。如果需要,您不需要做太多更改就可以用它作为客户端。检查 NTP 服务器列表,您将看到 server 选项或 pool。在 Ubuntu 系统上的以下示例包括默认的 Ubuntu NTP 服务器池和本地 LAN 服务器:

pool 0.ubuntu.pool.ntp.org iburst
pool 1.ubuntu.pool.ntp.org iburst
pool 1.ubuntu.pool.ntp.org iburst
server ntp.domain.lan iburst prefer

您可以使用一些公共服务器池替换一些 Ubuntu 服务器池,以提高可靠性和多样性:

pool 0.ubuntu.pool.ntp.org iburst
pool 1.ubuntu.pool.ntp.org iburst
pool 0.north-america.pool.ntp.org iburst
pool 1.north-america.pool.ntp.org iburst
server ntp.domain.lan iburst prefer

在更改配置文件后重新启动 chronyd

讨论

iburst 意味着在网络中断后快速同步,prefer 意味着除非不可用,否则始终使用此服务器。

这确实是客户端设置所需的全部操作。chrony 是一个完整的 NTP 实现,并拥有许多选项;详细描述请参阅 man 5 chrony.conf

管理 chronyd 就像使用以下命令管理任何其他服务一样:

  • systemctl status chrony

  • sudo systemctl stop chrony

  • sudo systemctl start chrony

  • sudo systemctl restart chrony

Chrony 在客户端方面比 ntpd 有几个优点。主要优点包括更好地处理网络连接中断和在恢复连接时更快地重新同步。

另请参阅

  • chrony

  • man 5 chrony.conf

  • man 1 chronyc

17.5 使用 chrony 作为 LAN 时间服务器

问题

您想将 chrony 设置为您的 LAN 时间服务器。

解决方案

就像在 Recipe 17.4 中一样,如果系统中存在 systemd-timesyncd,请禁用它并删除 ntpd。然后安装 chrony 软件包。

查找配置文件,可以是 /etc/chrony.conf(Fedora、openSUSE)或 /etc/chrony/chrony.conf(Ubuntu)。以下示例是一个基本的配置:

*pool 0.north-america.pool.ntp.org iburst
pool 1.north-america.pool.ntp.org iburst
pool 2.north-america.pool.ntp.org iburst

local stratum 10
allow 192.168.0.0/16
allow 2001:db8::/56*

driftfile /var/lib/chrony/chrony.drift
maxupdateskew 100.0
rtcsync
logdir /var/log/chrony
log measurements statistics tracking
leapsectz right/UTC
makestep 1 3

然后,您的客户端需要将您的服务器名称添加到其 chrony.conf 文件中:

server *ntp.domain.lan* iburst prefer

prefer 选项意味着只要该服务器可用,始终使用此服务器。保留本地时间服务器的原因之一是减轻公共时间服务器的负载。使用 prefer 选项,您可以将一些公共服务器配置为备用服务器,以防本地服务器不可用,并且无需担心给它们带来负担,如下所示:

server *ntp.domain.lan* iburst prefer
pool 1.north-america.pool.ntp.org iburst
pool 2.north-america.pool.ntp.org iburst

讨论

local stratum 10 配置 chrony 以继续充当您的本地 NTP 服务器,即使您的互联网连接中断,stratum 10 将您的服务器安全地放在层次结构中的较低位置,以便它低于您使用的任何外部 NTP 服务器。允许的值为 1–15。请使用除 10 以外的数字,以防此设置使 stratum 10 大受欢迎。

allow 选项定义允许使用你的 NTP 服务器的网络。

rtcsync 告诉 chrony 保持 RTC 与系统时间同步。

log 启用日志记录并定义需要记录的事件。

你可以在 man 5 chrony.conf 或默认的 chrony.conf 中查找其他选项,通常这些文件都有详细的注释。

参见

  • chrony

  • man 5 chrony.conf

  • man 1 chronyc

17.6 查看 chrony 统计信息

问题

你想要调用一些实时的 chrony 活动和统计信息,如上游 NTP 服务器、偏移、偏差、当前与之同步的服务器以及其他信息。

解决方案

使用 chronyc 命令。tracking 子命令显示已应用的校正量、RTC 时间、偏差等信息:

$ chronyc tracking
Reference ID    : A29FC87B (time.cloudflare.com)
Stratum         : 4
Ref time (UTC)  : Tue Oct 06 02:20:23 2020
System time     : 0.002051390 seconds fast of NTP time
Last offset     : +0.002320110 seconds
RMS offset      : 0.017948814 seconds
Frequency       : 28.890 ppm fast
Residual freq   : +0.252 ppm
Skew            : 1.250 ppm
Root delay      : 0.069674924 seconds
Root dispersion : 0.003726898 seconds
Update interval : 838.2 seconds
Leap status     : Normal

列出当前源服务器:

$ chronyc sources
chronyc sources
210 Number of sources = 19
MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================================
^- golem.canonical.com           2   9     0   37m    +55ms[  +58ms] +/-  209ms
^- alphyn.canonical.com          2   9     0   34m    +23ms[  +25ms] +/-  158ms
^- pugot.canonical.com           2   9     0   44m    +92ms[  +80ms] +/-  229ms
^- chilipepper.canonical.com     2   9    11    31    +48ms[  +48ms] +/-  181ms
[...]

列出当前源服务器及其描述:

$ chronyc sources -v
210 Number of sources = 19

  .-- Source mode  '^' = server, '=' = peer, '#' = local clock.
 / .- Source state '*' = current synced, '+' = combined , '-' = not combined,
| /   '?' = unreachable, 'x' = time may be in error, '~' = time too variable.
||                                                 .- xxxx [ yyyy ] +/- zzzz
||      Reachability register (octal) -.           |  xxxx = adjusted offset,
||      Log2(Polling interval) --.      |          |  yyyy = measured offset,
||                                \     |          |  zzzz = estimated error.
||                                 |    |           \
MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================================
^- golem.canonical.com           2   9     0   46m    +67ms[  +58ms] +/-  209ms
^- alphyn.canonical.com          2   9     0   44m    +35ms[  +25ms] +/-  158ms
^* pugot.canonical.com           2   9     1   54m   +104ms[  +80ms] +/-  229ms
^- chilipepper.canonical.com     2   9    11   587    +60ms[  +48ms] +/-  181ms
^- ntp.wdc1.us.leaseweb.net      2   7     4   327    +26ms[  +15ms] +/-  198ms
^- 216.126.233.109               2   9     1   459   +106ms[  +95ms] +/-  171ms
^- 157.245.170.163               3   9     1   476  +1191us[  -10ms] +/-  145ms

星号显示你的系统当前正在与哪个服务器同步。

讨论

chrony 调整网络延迟、间歇连接、以及客户端机器的睡眠和休眠模式。chrony 时钟从不停止,即使外部名称服务器不可用也能保持网络同步。

参见

17.7 使用 ntpd 作为你的 NTP 客户端

问题

是的,你已经了解 chronytimesyncd,以及它们的优点,但你仍然希望将 ntpd 作为你的 NTP 客户端。

解决方案

没问题,因为 ntpd 正在积极维护,并且能很好地完成工作。首先确保 ntpd 是系统上唯一的 NTP 客户端(参见 Recipe 17.1)。在大多数 Linux 发行版中,查找 ntp 包进行安装。

在大多数 Linux 发行版中,ntpd 配置有用的配置,并且在安装后启动。用 ps 命令检查:

$ ps ax | grep -w ntpd
3754 ?        Ssl    0:00 /usr/sbin/ntpd -u ntp:ntp -g

如果不会自动启动,请手动启动:

$ systemctl start ntpd

ntpd 运行时,请查看你的配置文件,通常是 /etc/ntp.conf。Linux 发行版的默认配置应该能正常工作,不需要更改。如果你的网络有自己的 LAN 服务器,以下配置将本地服务器设置为主服务器,Fedora Linux 服务器池作为备用:

server *ntp.domain.lan* iburst prefer
pool 2.fedora.pool.ntp.org iburst

大多数情况下,你可以保持默认配置,这对大多数情况都适用。Linux 发行版通常会维护自己的 NTP 服务器池,并在默认配置中提供这些信息。如果你希望替换或添加一些外部公共服务器,请查看continental pools以获取大洲 NTP 服务器池的列表,或者使用你国家的池,你可以通过点击大洲池链接找到它们。

当更改 /etc/ntp.conf 时,重新启动 ntpd

$ systemctl restart ntpd

$ sudo /etc/init.d/ntp restart

使用 ntpq 检查其是否工作。星号显示该机器正在与 LAN NTP 服务器同步:

$ ntpq -p

     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
 2.fedora.pool.n .POOL.          16 p    -   64    0    0.000   +0.000   0.000
**ntp.domain.lan*. 172.16.16.3      2 u   34  256  203   80.324  -49.772  54.508
+138.68.46.177 ( 80.153.195.191   2 u   92  256  123   90.932  -15.534  39.947
+vps6.ctyme.com  216.218.254.202  2 u  453  256   46   69.927  -29.296  84.811
+ec2-3-217-79-24 132.163.97.6     2 u  426  256  202  165.888  -51.442  93.224

讨论

iburst 告诉 ntpd 在系统启动时快速同步。

prefer 意味着使用这个服务器,并且只在其不可用时使用其他服务器。

参见

17.8 使用 ntpd 作为您的 NTP 服务器

问题

您想知道如何为您的 LAN 运行 ntpd 服务器。

解决方案

在 LAN 时间服务器上使用 ntpd 与作为 NTP 客户端使用它类似。配置几乎相同,只需添加一些访问控制。以下示例是完整的 /etc/ntp.conf 配置:

driftfile /var/lib/ntp/drift

restrict default nomodify notrap nopeer noquery
restrict -6 default nomodify notrap nopeer noquery
restrict 127.0.0.1
restrict ::1

pool 0.north-america.pool.ntp.org
pool 1.north-america.pool.ntp.org
pool 2.north-america.pool.ntp.org

leapfile /usr/share/zoneinfo/leap-seconds.list

statistics clockstats loopstats peerstats
filegen loopstats file loopstats type day enable
filegen peerstats file peerstats type day enable
filegen clockstats file clockstats type day enable
statsdir /var/log/ntpstats/

讨论

driftfile 是 ntpd 跟踪由主板上石英晶体振荡频率波动引起的时间漂移的地方。您有以下选项:

  • restrict default 拒绝所有,只允许显式允许的内容,并设置默认值。

  • nomodify 不允许其他时间服务器对您的系统进行任何更改。允许查询。

  • notrap 禁用远程记录。

  • nopeer 不允许对等。对等服务器彼此同步,因此唯一允许提供时间服务的服务器由 serverpool 指令指定。

  • noquery 禁止远程查询和远程记录。

  • restrict 127.0.0.1restrict ::1 表示信任本地主机。

statistics 部分将您选择的统计信息记录到 /var/log/ntpstats/ 中。这并非必需,但跟踪哪些上游 NTP 服务器性能最佳可能很有趣。

参见

17.9 使用 timedatectl 管理时区

问题

您想列出所有时区,查看当前时区并更改时区。

解决方案

使用 timedatectl。查看当前时区:

$ timedatectl | grep -i "time zone"
     Time zone: America/Los_Angeles (PDT, -0700)

列出所有时区:

$ timedatectl list-timezones
Africa/Abidjan
Africa/Accra
Africa/Addis_Ababa
Africa/Algiers
[...]

列表超过 400 行。当您知道您要查找什么时,请使用 grep 命令。例如,列出主要城市,如柏林:

$ timedatectl list-timezones | grep -i berlin
Europe/Berlin

将此设置为您的时区:

$ sudo timedatectl set-timezone Europe/Berlin

变更立即生效。再次运行 timedatectl 验证。

讨论

当您与不同时区的人们合作时,请使用 UTC 协调会议时间。有几个在线时区转换器,例如 时区转换器

您必须使用区域/城市格式,如 timedatectl list-timezones 所示,来设置您的时区。这由 ISO 8601 标准定义,该标准定义了一种清晰表达时区、时间和日期的标准。该标准使用“降序表示法”,即从最大值到最小值的顺序。例如,对于时区,顺序是大洲/国家/城市。美国习惯将日期写为年-日-月不符合此标准。年-月-日 是标准格式,年份为四位数,YYYY-MM-DD。时间为 HH:MM:SS,采用 24 小时制。

官方发布的 ISO 8601 标准需付费,但通过一些网页搜索应该可以免费找到信息。

参见

  • man 1 timedatectl

17.10 不使用 timedatectl 管理时区

问题

您的 Linux 系统没有 systemd,需要了解如何使用哪些命令来管理时区。

解决方案

使用 date 命令查看当前时区:

$ date
Wed Oct  7 08:32:40 PDT 2020

或查看 /etc/localtime 链接到的内容:

$ ls -l /etc/localtime
lrwxrwxrwx 1 root root 41 Oct  7 08:06 /etc/localtime ->
../usr/share/zoneinfo/America/Los_Angeles

/usr/share/zoneinfo 目录包含所有时区:

$ ls /usr/share/zoneinfo
total 324
drwxr-xr-x  2 root root  4096 May 21 23:02 Africa
drwxr-xr-x  6 root root 20480 May 21 23:02 America
drwxr-xr-x  2 root root  4096 May 21 23:02 Antarctica
drwxr-xr-x  2 root root  4096 May 21 23:02 Arctic
[...]

查看子目录以找到与您所在城市接近的城市,例如,马德里:

$ ls /usr/share/zoneinfo/Europe
[...]
-rw-r--r-- 1 root root 2637 May  7 17:01 Madrid
-rw-r--r-- 1 root root 2629 May  7 17:01 Malta
lrwxrwxrwx 1 root root    8 May  7 17:01 Mariehamn
-rw-r--r-- 1 root root 1370 May  7 17:01 Minsk
[...]

通过更改链接到 /etc/localtime 来更改您的时区:

$ sudo ln -sf /usr/share/zoneinfo/Europe/Madrid/etc/localtime

更改立即生效。

讨论

这个很酷的命令按字母顺序列出所有时区:

$ php -r 'print_r(timezone_identifiers_list());'
Array
(
    [0] => Africa/Abidjan
    [1] => Africa/Accra
    [2] => Africa/Addis_Ababa
    [3] => Africa/Algiers
    [4] => Africa/Asmara
[...]

php 命令位于 php-cli 包中。

您的图形桌面应该有一个很好的图形实用程序来管理时间、日期和时区。如果桌面上显示了时钟,请尝试右键单击它以打开属性或设置面板。

参见

  • man 1 date

  • man 1 ln

第十八章:在 Raspberry Pi 上构建 Internet 防火墙/路由器

Raspberry Pi(RPi)非常适合小型网络的 Internet 防火墙/路由器,成本不高。您可以使用任何 Raspberry Pi,但我推荐 Raspberry Pi 4B,因为它比旧版 Pi 更强大,并且是第一个配备专用千兆以太网端口的 Pi。

概述

在本章中,您将学习如何安装 Raspberry Pi OS,将您的 Pi 连接到计算机显示器或电视,使用 Raspberry Pi OS 恢复模式,无头运行您的 Pi,添加第二个以太网口,共享 Internet 连接,并使用 Pi 进行 LAN 名称服务。

注意

本章的示例均基于 Raspberry Pi 4 Model B,在 Raspberry Pi OS 上运行。Raspberry Pi OS 以前称为 Raspbian。其底层是 Debian Linux,因此如果您习惯于 Debian、Ubuntu、Mint 或其他任何 Debian 变体,它都是相同的 Linux。

Raspberry Pi 防火墙/路由器的优缺点

Raspberry Pi 是通用计算机,而不是专用防火墙/路由器。它具有 WiFi、以太网和蓝牙,并运行 Linux。相比之下,小型网络的常见选择是类似 Linksys AC1900 或 TP-Link Archer AX20 的小型组合防火墙/路由器/无线接入点/以太网交换机,它们具有 WiFi、千兆以太网、多个天线,并支持像 Alexa 和智能手机管理应用程序等“智能”服务。

这些设备的缺点在于其不灵活性,特别是存储和操作系统支持有限。如果您想替换供应商软件,必须使用像 OpenWRT、DD-WRT、pfSense 或 OPNsense 这样的专门的路由器发行版,这些都非常出色,但并不容易,并且您必须找到受支持的设备。

Raspberry Pi 相比于一体化设备具有以下优势:

  • 灵活性,就像任何通用 Linux 计算机一样

  • 更多的内存和存储

  • 连接到计算机显示器或电视、键盘和鼠标

  • 运行多种 Linux 发行版,因此您可以利用现有的知识,无需学习一些奇怪的新界面或命令集

  • 运行多种*bsd 操作系统、Windows 10、Android、Chromium 和其他操作系统

  • 连接到移动热点

  • 支持 64 位

您可以像任何 Linux 系统一样,通过图形桌面、无图形桌面和 SSH 无头运行 Raspberry Pi。

Raspberry Pi 的缺点:

  • 不能像一体化设备那样作为以太网交换机运行

  • WiFi 不如一体化设备强

  • Raspberry Pi 模型 3 及更早版本的以太网性能较差,因为以太网端口共享 USB 总线;RPi 4 通过专用千兆以太网端口解决了这个问题

树莓派有许多定制的 Linux 操作系统。官方操作系统是基于 Debian Linux 的树莓派 OS。SUSE、Ubuntu、Fedora、Arch Linux ARM 和 MX Linux 都有树莓派变种。此处我们将专注于树莓派 OS,因为它针对树莓派进行了优化,在旧款树莓派上也能提供良好的图形桌面性能。树莓派 OS 就像其他任何 Linux 一样,您可以在树莓派上做任何您在大型 Linux 机器上可以做的事情。

硬件架构

树莓派由 Broadcom SoC 提供动力。CPU、GPU 和 I/O 都集成在一颗芯片上。在树莓派 4 Model B 上尤为引人注目,支持同时运行两个屏幕,并能轻松处理高清电影。

Broadcom SoC 是一款 ARM 芯片,而不是主导 PC 市场的 x86_64 架构。ARM 处理器较少复杂,采用精简指令集(RISC)。x86_64 处理器是 CISC,复杂指令集计算机。x86_64 处理器工作更加艰苦,复杂度更高,耗电量更大。

树莓派产品盛宴

每款曾发布的树莓派型号仍然可供购买,包括树莓派 1 的更新版本,A 和 B 型号。A 型号是每个发布的低成本版本,而 B 型号则因具备更多功能而稍贵。

您可以选择许多其他的树莓派产品,例如:

  • 树莓派 Zero,价格仅为 $5,是最小的树莓派

  • 树莓派 Zero W 集成了 WiFi 功能,售价 $10

  • 树莓派 400 个人电脑套件,集成在一个紧凑的键盘内(您需要添加的只是显示器),售价 $100

自第一款树莓派发布以来,其价格保持稳定,尽管当然可能会发生变化。

有大量的配件可供选择:外壳、触摸屏、散热器、风扇、扩展板(HATs)、各种电缆和适配器、电机、摄像头、音频板、带触摸板的小型无线键盘、游戏模拟器、RGB 矩阵、带电源的 USB 集线器、实时时钟、小尺寸显示器……这是一个绝佳的玩乐场。

历史与目的

树莓派是一个真正的现象。其创始人 Eben Upton 最初的目的是生产一台小巧廉价的计算机,以鼓励年轻学生学习计算机,特别是那些买不起 PC 的学生。第一款树莓派,版本 1 Model B,约售价 $35。添加键盘和鼠标,连接至电视或显示器,价格不到 PC 的十分之一,您就拥有了一台可以工作的 Linux 计算机,具备音频、视频、以太网和 USB 接口。开放的硬件设计和开源软件鼓励了黑客和学习活动。

注意

驱动 Pi 的 Broadcom 芯片组并非开源。自第一代 Pi 发布以来,这一点一直存在争议。电路图是公开的,可以在RaspberryPi.org找到,操作系统和 BIOS 是开源的。以我适度谦虚的看法,一个完全开源的平台更可取,目前可用的东西总比没有可用的东西好。

第一代 Raspberry Pi 立即取得了成功,在 2012 年 2 月发布后的首 6 个月内销售了超过 50 万台。此后大约销售了 3000 万台 Raspberry Pi。当前版本,Version 4 Model B,是一个重大升级,是迄今为止性能最强大的型号,具有以下特点:

  • 2 个 USB 2 端口

  • 2 个 USB 3 端口

  • 2 个 Micro HDMI 端口,支持 2 个 4K 显示器

  • 1 个专用千兆以太网端口

  • 支持 2 GB 至 8 GB 的 RAM

  • Broadcom BCM2711,1.5 GHz 四核 Cortex-A72(ARM v8)64 位 SoC

  • 支持 2.4 GHz 和 5.0 GHz IEEE 802.11ac WiFi

  • 蓝牙

  • 40 针 GPIO 引脚头

与现代的 Intel 和 AMD CPU 相比,这些规格远不能称为令人自豪的,但足以运行 Linux 图形桌面,播放音乐、电影,浏览网页,撰写文档……它在尺寸和价格上非常有能力。

Raspberry Pi 由 Raspberry Pi 基金会开发和生产,这是一个注册的非营利慈善组织。该基金会支持多个教育项目,供教师和学生使用;访问https://raspberrypi.org获取当前的教育资料和信息。

18.1 启动和关闭 Raspberry Pi

问题

在你的 Raspberry Pi(RPi)上看不到电源开关,你想要打开和关闭它。

解决方案

通过插入电源连接器来启动它。从操作系统菜单中关闭它,然后拔掉电源插头。

讨论

当你关闭你的 RPi 时,你必须断开然后重新连接电源才能重新启动它。

如果有为 RPi 设计的电源开关,我一点也不会感到惊讶,尽管我没见过。一个替代方案是将其插入一个带开关的电源插排。

参见

18.2 查找硬件和操作指南

问题

你购买了一台 Raspberry Pi 4 Model B,并想知道你需要哪些其他硬件设备才能使用它。

解决方案

据推测,你已经有了一台计算机显示器或电视、鼠标和键盘。你还需要:

  • Raspberry Pi 电源适配器

  • HDMI 至 Micro HDMI 电缆

  • 至少 16 GB 的 Micro SD 卡

  • 冷却风扇,或者在 CPU、RAM 模块和 USB 控制器上安装散热片

  • 机箱

  • Micro SD 卡读卡器

首先,在另一台计算机上将 Raspberry Pi OS 安装到你的 Micro SD 卡上。当这个过程运行时,组装你的硬件。当一切准备就绪时,连接电源,看着你的新系统启动。(查看 18.4 和 18.5 章节,了解如何安装 Raspberry Pi OS 的方法。)

要全面了解 RPi,有很多源提供电路图、规格、操作指南和巧妙点子。本篇的“参见”部分列出了一个不错的选择,可以帮助你入门。

讨论

如果你的显示器没有 HDMI 接口,请参见 Recipe 18.6。

你可以使用至少 16 GB 大小的任何 micro SD 卡。高速卡可以显著提高性能。16 GB 相当小,你可以使用任意大的卡。

RPi 4B 有三种内存选项,2 GB、4 GB 和 8 GB。它不可升级,所以你购买的就是你会拥有的。2 GB 对于作为互联网网关和轻量级 Linux 桌面的 Pi 已经足够了。更多内存适合多媒体处理、编译代码、游戏和其他内存密集型任务。

RPi 4B 比旧版 RPi 强大得多,运行时也更热。参见 Recipe 18.3 了解如何保持其冷却。

RPi 4B 有 4 个 USB 端口,非常灵活。你可以使用标准 USB 键盘和鼠标,带有触控板的键盘,以及 USB 到 PS/2 转接器用于旧键盘和鼠标。你可以连接 USB 硬盘进行更多存储或备份,以及像在大型计算机上一样连接任何其他 USB 设备。40 针 GPIO 头支持连接几乎任何扩展板。

有许多很棒的套件捆绑了你开始所需的一切。我最喜欢的商店是Adafruit.com,你还可以在https://raspberrypi.org上找到更多。

参见

这些网站发布了优秀的树莓派教程:

18.3 冷却树莓派

问题

你的树莓派摸起来很热,你想为它安装一些冷却设备。

解决方案

在机箱内安装冷却风扇,或在 CPU、RAM 模块和 USB 控制器上安装散热片。在比旧版 RPi 更热的 RPi 4 上安装风扇和散热片。

使用内置的vcgencmd命令,在安装冷却装置之前和之后,以及编译代码或播放视频等计算密集任务之前和之后,来测量 CPU 温度。以下示例是在无风扇板载状态下,打开机箱盖后的空闲状态,以及在播放 1080p 电影 5 分钟后的状态:

$ vcgencmd measure_temp
temp=48.3'C

$ vcgencmd measure_temp
temp=61.9'C

这个示例展示了在播放同一部电影时,使用冷却风扇的效果:

$ vcgencmd measure_temp
temp=52.1'C

温度不应超过 70°C。40°C 到 60°C 是一个良好的操作范围。

参见

18.4 使用 Imager 和 dd 安装树莓派 OS

问题

你已经准备好硬件,想要安装操作系统。

解决方案

您将在另一台计算机上创建一个可启动的微型 SD 卡,然后将 SD 卡插入树莓派并启动。

有四种方法可以获得可启动的 SD 卡:

  • 使用树莓派 Imager(目前仅适用于 .deb 系统,如 Debian、Ubuntu 或 Mint)

  • 使用 NOOBS 安装程序(Recipe 18.5)

  • 使用 dd 命令将安装镜像复制到微型 SD 卡

  • 购买已加载安装程序的微型 SD 卡

我喜欢 NOOBS,因为它适用于所有的 Linux 发行版,并创建了一个救援引导模式。

要从 .deb 包安装树莓派 Imager,请从 https://raspberrypi.org 下载它。然后安装该软件包:

$ sudo dpkg -i *imager_1.5_amd64.deb*

另外,Ubuntu 用户可以使用 apt 安装树莓派 Imager:

$ sudo apt install rpi-imager

将您的 SD 卡插入计算机。使用 lsblk -p 定位它(参见 Recipe 10.9)。

从系统菜单启动树莓派 Imager,并享受其可爱的树莓 Logo。点击操作系统选择您想要安装的操作系统,Imager 将下载并复制到您的 SD 卡。如果您已经下载了映像,请在选择菜单中向下滚动到使用自定义以选择您下载的映像。您将看到类似 图 18-1 的屏幕。

使用树莓派 Imager 创建可启动微型 SD 卡

图 18-1. 使用树莓派 Imager 创建可启动微型 SD 卡

点击 SD 卡选择设备,然后点击写入以安装操作系统。

如果您没有 Ubuntu 系统,请从 https://raspberrypi.org 下载您选择的操作系统映像,并使用 dd 命令将其复制到 SD 卡。以下示例解压并将 2021-03-24-raspios-buster-armhf.zip 复制到 SD 卡:

$ sudo unzip -p 2021-03-24-raspios-buster-armhf.zip | \
  sudo dd of=/dev/*foo* bs=4M conv=fsync status=progress

当 SD 卡准备就绪后,将其插入树莓派并开机。开机后,您将完成简短的设置,然后可以开始使用。

默认用户为 pi。在 /home/pi/Bookshelf 中可以找到 Gareth Halfacree(Raspberry Pi Press)撰写的《官方树莓派初学者指南》的 PDF 版本。

讨论

在使用树莓派 Imager 之前,您不必格式化 SD 卡。

Imager 创建两个分区:一个 256 MB 的 FAT32 /boot 分区,一个刚好足够容纳文件系统的 Ext4 rootfs 分区。在我的测试系统上为 3.4 GB,卡片的其余空间未分配。

当您首次启动新系统时,根文件系统将被扩展以填充所有未分配空间。您可以使用 GParted(第九章)或 parted(第八章)缩小根文件系统并创建更多分区。

参见

18.5 使用 NOOBS 安装树莓派

问题

您想要使用 NOOBS 安装树莓派。

解决方案

NOOBS(New Out Of the Box Software)是一个较旧的安装程序。它适用于所有 Linux 发行版,并创建了一个恢复引导模式,而 Raspberry Pi Imager 则不会这样做。

在另一台计算机上下载 NOOBS,解压下载的存档文件,将所有文件复制到 micro SD 卡上,然后将 SD 卡插入您的 Raspberry Pi 并启动它。

https://raspberrypi.org 下载 NOOBS。有两个版本:NOOBS 和 NOOBS Lite。NOOBS 包括 Raspberry Pi OS 和其他操作系统的网络安装程序。NOOBS Lite 仅包括网络安装程序。

在下载后解压缩 NOOBS:

$ unzip *NOOBS_lite_v3_5.zip*

将您的 SD 卡插入计算机中。使用 lsblk -p 查找它(参见 配方 10.9)。

将您的 micro SD 卡格式化为单个 FAT32 分区。

将所有 NOOBS 文件复制到您的 SD 卡,然后使用它启动您的 Raspberry Pi。首先,您会看到一个酷炫的彩虹色屏幕,然后 NOOBS 启动安装菜单(图 18-2)。设置网络以使用网络安装程序或在安装后获取更新。选择您的操作系统,然后找些事情做,直到安装完成。

NOOBS 安装屏幕。

图 18-2. NOOBS 安装屏幕

安装完成后,您将进行简短的设置过程,然后您的 Raspberry Pi 就可以使用了。

默认用户是 pi。在 /home/pi/Bookshelf 中查找由 Gareth Halfacree(Raspberry Pi Press)编写的 The Official Raspberry Pi Beginner’s Guide 的 PDF 版本。

讨论

NOOBS 是一个简单的解压和复制过程,因此适用于任何计算机。

将 NOOBS 文件复制到您的 SD 卡可能需要很长时间。通常情况下,将 ZIP 文件复制到 SD 卡上,然后在卡上解压缩会更快。安装完成后,您可以删除 ZIP 文件。

参见

18.6 连接到没有 HDMI 的视频显示器

问题

您有一台没有 HDMI 端口的电视或计算机显示器,并且想要将您的 Raspberry Pi 连接到它。

解决方案

有四种方法可以将屏幕连接到 RPi 4B。您可以使用以下方法之一:

  • 为 Raspberry Pi 制造的小屏幕

  • DVI 到 HDMI 适配器

  • VGA 到 HDMI 适配器

  • RCA 复合视频(使用专为 Raspberry Pi 制作的电缆)

有多种适用于 RPi 的屏幕类型:触摸屏、LED、LCD、OLED、电子墨水等等,应有尽有。遵循随屏幕附带的安装说明进行安装。

DVI 到 HDMI 和 VGA 到 HDMI 适配器连接到您的屏幕,然后您的 HDMI 到 micro-HDMI 电缆连接到适配器。当您连接到 RPi 4B 上的单个 HDMI 显示器时,请插入 HDMI 0 端口,即靠近电源端口的端口。

由于默认情况下在 RPi 4B 上禁用复合视频,因此复合视频需要额外的步骤。简便的方法是在首次启动 Pi 并完成安装时找到一个 HDMI 屏幕。安装完成后,打开配置工具以启用复合视频:

$ sudo raspi-config

向下箭头键到 6 高级选项,然后选择 A8 HDMI/Composite。选择 V2 启用复合。退出 raspi-config,关闭您的 Pi,连接您的 Pi 到复合视频屏幕,然后再次启动。它应该默认显示在您的复合视频屏幕上。

讨论

较老的平板显示器通常具有 VGA 和复合视频连接器,因此您可以使用复合视频或 VGA 到 HDMI 适配器。从技术上讲,HDMI 提供比复合视频更高质量的图像,但大多数人分辨不出区别。

图 18-3 显示了 Rocketfish DVI 到 HDMI 适配器,一个复合电缆捆绑包,一个带有拆下顶部的 CanaKit 外壳的 Rasberry Pi 4B 和一个 micro SD 卡。

带有配件的 Raspberry Pi 4B

图 18-3. 带有配件的 Raspberry Pi 4B

RCA 复合音频/视频电缆套件,带有黄色、红色和白色连接器,插入 RPi 上的巧妙小型 3.5 mm TRRS 端口。您需要为 RPi 制作一个,因为 TRRS 插头的排列方式没有标准。您可能会发现一些不起作用的电缆,因为它们的黄色用于视频,红色和白色用于音频。避免为摄像机和 MP3 播放器制作的复合电缆,它们具有自己的奇怪排列顺序,将地面环放在错误的位置。TRRS(尖端-环-环-套筒)插头应该配置如下:

Tip          Ring 1        Ring 2   Sleeve
Left audio   Right audio   Ground   Video

/boot/config.txt 中有几个调整复合视频设置的选项。如果打算使用复合视频,请使用 NOOBS 安装程序。然后,如果需要更正设置,可以启动到恢复模式(配方 18.7)并访问 /boot/config.txt

sdtv_mode= 设置了电视标准。sdtv_mode=0 是北美的默认设置。大部分世界使用 PAL;请参阅 表 18-1 中的设置。

表 18-1. sdtv_mode 设置

模式
0 普通 NTSC(默认)
1 NTSC 的日文版
2 普通 PAL
3 PAL 的巴西版
16 逐行扫描 NTSC
18 逐行扫描 PAL

sdtv_aspect= 命令定义了显示比例(参见 表 18-2)。

表 18-2. sdtv_aspect 屏幕比例设置

比例
1 4:3(默认)
2 14:9
3 16:9

另请参阅

18.7 进入恢复模式

问题

您希望了解如何进入恢复模式以防有问题时。

解决方案

您必须使用 NOOBS 安装操作系统,因为这是唯一可以设置恢复模式的安装程序。打开您的 Pi 并观看启动屏幕。屏幕会短暂显示树莓派标志和“要进入恢复模式,请按住 Shift 键”的消息。按住 Shift 键直到出现恢复屏幕(图 18-2; 恢复屏幕与 NOOBS 安装屏幕相同)。

恢复屏幕是一个很好的图形实用程序,用于执行一些基本操作。您可以连接到互联网,浏览在线帮助,编辑/boot/cinfig.txt,或者彻底清除您的安装并安装其他内容。

讨论

恢复屏幕与 NOOBS 安装屏幕相同。只有在使用 NOOBS 安装树莓派时才有此恢复选项,尽管在您阅读此文时可能已有所不同。

参见

18.8 添加第二个以太网接口

问题

您想要将树莓派用作互联网防火墙/路由器,但它只有一个以太网口,您确实希望有两个以太网口。

解决方案

获取第二个以太网口有两种方法:使用 USB 转以太网适配器或安装连接到 GPIO 引脚的以太网口。

USB 转以太网很简单;只需插入即可。

有线以太网端口需要更多工作。您需要一个由 ENC28J60 以太网控制器模块驱动的以太网适配器(图 18-4)。

ENC28J60 以太网适配器。

图 18-4. ENC28J60 以太网适配器

照片中的 HanRun HR911105A 适配器需要七根母对母跳线连接到 GPIO 引脚。您可以购买提供各种颜色线束的多色捆绑包,价格便宜。

在连接电线之前,通过在您的树莓派上运行pinout命令生成您自己的便捷引脚布局图(图 18-5)。

图 18-6 显示了来自 RaspberryPi.org 的图表,标记了 GPIO 引脚排列。

由 pinout 命令生成的引脚布局图。

图 18-5. 由 pinout 命令生成的引脚布局图

来自 raspberrypi.org 的引脚布局图。

图 18-6. 来自 RaspberryPi.org 的引脚布局图

编辑/boot/config.txt以启用新的以太网口并加载驱动程序:

dtparam=spi=on
dtoverlay=enc28j60

保留引脚布局图的副本,并关闭您的树莓派电源。在您的 RPi 和 ENC28J60 模块上以下位置连接跳线线:

RPi           ENC28J60
----------------------------
+3V3          VCC
GPIO10        SI
GPIO9         SO
GPIO11        SCK
GND           GND

GPIO25        INT
CE0#/GPIO8    CS

注意 GPIO 引脚的方向:引脚#1 位于 RPi 板的 SD 卡插槽同一端。从 3V3 引脚 17 开始,然后所有电线都在同一区域,另一个 3V3 引脚可用于机箱风扇。

当所有电线都就位后,启动您的 RPi。运行ifconfig命令查看您的新以太网接口。它应该是eth1

$ ip link show dev eth1
2: eth1: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel
state DOWN mode DEFAULT group default qlen 1000
    link/ether d0:50:99:82:e7:2b brd ff:ff:ff:ff:ff:ff

这就是,所有配置都已准备好。

讨论

ENC28J60 以太网控制器仅支持 10 MBps。如果您的互联网速度不超过 10 MBps,则这没问题。在树莓派 4 上,使用 USB 3.0 以太网适配器可以获得高达 900 MBps 的速度。

较旧的树莓派因通过 USB 2.0 总线运行而具有较慢的以太网速度。树莓派 4B 是第一台具有专用以太网总线的树莓派。

密切关注双千兆以太网选项的新产品发布,很可能很快会有一些产品。

pinout命令由python3-gpiozero包提供。这在树莓派 OS 桌面镜像中默认安装,但在树莓派 OS Lite 上没有安装。您可以使用apt install python3-gpiozero进行安装。

参见

18.9 使用 firewalld 设置互联网连接共享防火墙

问题

您希望在您的树莓派上配置一个简单的防火墙,共享您的互联网连接,并阻止不良信息。

解决方案

我们将使用firewalld来过滤传入的数据包,只允许 LAN 内部起始的流量响应,并禁止外部连接请求。

您的互联网网关设置类似于图 18-7。

树莓派防火墙/路由器

图 18-7. 树莓派防火墙/路由器

互联网通过连接您与 ISP 的任何设备进入,然后连接到您的树莓派,树莓派通过以太网交换机将流量过滤和路由到您的 LAN。

您的 RPi 需要两个网络接口,一个连接从互联网盒子到 RPi,第二个接口连接从 RPi 到 LAN。在这个步骤中,我们将使用两个以太网接口。

安装firewalld,以及可选的firewall-configfirewall-appletfirewall-config提供了一个图形化配置工具,firewall-applet位于面板上,提供了一些命令的快速访问,如紧急按钮和锁定:

$ sudo apt install firewalld firewall-config firewall-applet

找到你的默认路由器/网关:

$ ip r show
default via 192.168.1.1 dev eth0 proto dhcp src 192.168.1.43 metric 303 mtu 1500
192.168.1.0/24 dev eth0 proto dhcp scope link src 192.168.1.43 metric 303 mtu
1500cat

default via 192.168.1.1是您的默认网关。

eth1设置为外部接口,连接到您的互联网盒子。eth0是您的内部接口,连接到 LAN 交换机。这两个接口应该位于不同的子网上。eth1应该位于与您的互联网盒子相同的子网上。假设您的互联网盒子的 LAN 接口是 192.168.1.1,则eth1可以是 192.168.1.2。

eth0位于您的 LAN 子网上,例如 192.168.2.1。

/etc/dhcpcd.conf中配置两个接口:

# external interface
interface eth1
static ip_address=192.168.1.2/24
static routers=192.168.1.1

# internal interface
interface eth0
static ip_address=192.168.2.1/24
static routers=192.168.1.1

重新启动以应用更改。

下一步是设置firewalld。这两个接口必须位于两个不同的防火墙区域。eth1放在external区域,eth0放在internal区域,然后验证您的更改:

$ sudo firewall-cmd --zone=external --change-interface=eth1
success
pi@raspberrypi:~ $ sudo firewall-cmd --zone=internal --change-interface=eth0
success
pi@raspberrypi:~ $ sudo firewall-cmd --get-active-zones
external
  interfaces: eth1
internal
  interfaces: eth0

列出每个区域的配置:

$ sudo firewall-cmd --zone=external --list-all
external (active)
  target: default
  icmp-block-inversion: no
  interfaces: eth1
  sources:
  services: ssh
  ports:
  protocols:
  masquerade: yes
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:

$ sudo firewall-cmd --zone=internal --list-all
internal (active)
  target: default
  icmp-block-inversion: no
  interfaces: eth0 wlan0
  sources:
  services: dhcpv6-client mdns samba-client ssh
  ports:
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:

注意ssh访问是外部区域的默认设置。您可以添加或删除任何希望的服务。您必须保持masquerade启用,因为这是实现互联网访问的方法。

使您的更改永久化:

$ sudo firewall-cmd --runtime-to-permanent
success

IPv4 转发在external区域也是默认启用的,您可以通过读取/proc来验证。IPv4 转发启用后,才能进行路由;否则,进入您的 RPi 的所有数据包将无法路由到网络中的其他主机。

$ cat /proc/sys/net/ipv4/ip_forward
1

1 表示启用,0 表示未启用。

讨论

IPv4 伪装是网络地址转换(NAT)。NAT 的创建是为了扩展有限的 IPv4 地址池(正式耗尽)。NAT 允许我们在内部网络上自由使用私有 IPv4 地址空间,而无需购买公共 IPv4 地址。您的互联网供应商提供至少一个公共 IPv4 地址。您的私有地址被转换为显示为您的一个公共 IPv4 地址;否则,您的内部主机将无法访问互联网。

您可以在各个区域中添加和删除服务;详见第十四章。

参见

18.10 在您的树莓派上运行无头模式

问题

您将您的树莓派用作互联网防火墙/路由器、LAN 路由器或某种轻量级 LAN 服务器,并希望通过无图形桌面运行来减少负载。

解决方案

按照以下步骤操作:

  1. 在您的 RPi 上设置 SSH 访问(参见第十二章)。

  2. 运行raspi-config来禁用图形桌面。

  3. 重新启动。

  4. 启动sudo raspi-config,然后导航至 1. 系统选项 → S5. 启动/自动登录(参见图 18-8)。

  5. 设置下次启动为控制台,而不是 GUI,然后重新启动。

只要您能够通过 SSH 会话访问您的 RPi,即使没有屏幕,也能访问它。

您可以通过输入startx命令从文本控制台启动图形环境。

设置下次启动为控制台,无 GUI

图 18-8. 设置下次启动为控制台,而不是 GUI。

讨论

rpi-config使用ncurses界面。ncurses是一个看起来像简单 GUI 的控制台界面。

当您将树莓派设置为无头模式时,它只需要电源和网络连接,因为您可以从另一台计算机上的 SSH 会话中控制它。

参见

18.11 使用树莓派构建 DNS/DHCP 服务器

问题

您的互联网路由器在管理功能方面提供的功能不多,您希望控制本地名称服务 DNS 和 DHCP。

解决方案

在你的互联网盒子上禁用命名服务,并设置第二台树莓派来使用 Dnsmasq 提供你的局域网命名服务(第十六章)。使用 DHCP 为所有局域网主机提供所有服务和地址,包括静态地址,但不包括你的互联网网关,它应独立于任何内部服务。

讨论

你可以将你的域名服务器安装在你的互联网防火墙/网关上,但是把内部服务放在直接连接到互联网的主机上并不是一个良好的安全实践。你的树莓派 DNS/DHCP 服务器只需要一个单独的网络接口,就像任何其他局域网服务器一样。

另请参阅

  • 第十六章

第二十章:故障排除 Linux PC

Linux 包含许多实用程序来帮助诊断和修复问题,足以填满几本厚厚的书。本章重点介绍使用系统日志来查找问题的原因,建立一个集中的 systemd 日志服务器,监控硬件健康状况,查找和停止问题进程,以及获得硬件最佳性能的技巧和窍门,以及诊断硬件问题。

概述

熟悉你的系统日志,你将找到问题的根本原因。如果找到问题的原因没有指向解决方案,你就有了寻求帮助所需的信息,无论是产品文档、发行版文档、付费支持还是社区支持。

深入了解你所使用的 Linux 发行版的文档,特别是变更日志和发布说明,以及你使用的服务器和应用程序的文档。Ubuntu、Fedora 和 openSUSE 都擅长维护他们的文档和详细的发布说明。还要熟悉你的发行版、服务器和应用程序的论坛、维基和聊天室。对于你遇到的每个问题,很可能其他许多用户也曾经遇到过相同的问题。

预防措施

大多数错误是由软件引起的。即使是消费者级别的硬件也相当坚固,但它最常由于滥用和老化而失效。最常见的硬件故障是带有运动部件的组件:

  • SATA 和 SCSI 磁盘驱动器

  • CPU 冷却器

  • 电源供应器

  • 机箱风扇

  • CD/DVD 驱动器

有一些简单的措施可以延长硬件的使用寿命。过热和不可靠的电源会损坏电子设备。良好的冷却对于保持计算机的健康至关重要。良好的冷却来自设计良好的机箱,提供适当的空气流动、散热器和 CPU 冷却器,以及正确定向的机箱风扇,使空气能够正确地进入和排出。这可能会有些噪音,你可以购买运行更安静的机箱、电源和风扇。定期用非静电吸尘器吸尘,并清洁机箱过滤器。如果你喜欢用压缩空气吹灰尘,要小心风扇。如果旋转得太快,会损坏它们的轴承。

电源调节器提供持续的电压波动和尖峰保护,以及来自无线电和电磁干扰的保护。避雷器成本较低,但只提供过载保护。电压下降和尖峰一样有害。电源调节器通过更长的使用寿命和稳定的运行方式来回报自己的成本。

耐心

当调试问题时,耐心是你最好的朋友。最好是缓慢而系统地进行:

  • 审查说明并确保没有漏掉任何步骤或出错。

  • 是否有可用的更新?很多时候这就是解决方案。

  • 复制错误消息和日志文件条目,并在网上搜索和故障工单中使用它们。

  • 错误发生前最后发生了什么?造成错误的确切步骤是什么?是否可以复现?

  • 最近发生的事情是否可逆?如果是,逐个撤销并测试。一次性进行多个更改意味着您可能无法发现导致错误的原因。

  • 作为最后的手段,请重新启动。真的!这个方法奇迹般地解决了许多问题,尽管您可能不知道问题的根源。

一些图形应用程序,如出色的 digiKam 照片管理和编辑器,在从终端启动时会发出各种细节,就像此片段显示的那样,当 digiKam 启动失败后:

$ digikam
Object::connect: No such signal org::freedesktop::UPower::DeviceAdded(QString)
Object::connect: No such signal org::freedesktop::UPower::DeviceRemoved(QString)
digikam: symbol lookup error: digikam: undefined symbol:
_ZNK11KExiv2Iface14AltLangStrEdit8textEditEv

我不知道这意味着什么,但有人知道,所以我可以在网络搜索中引用这个,或者在 digiKam 论坛上寻求帮助。

当您请求帮助时,请记住耐心和礼貌。当您被要求提供额外信息时,请准确提供所需的内容。解决问题后,请分享解决方案,并感谢帮助您的人。

20.1 在日志文件中查找有用信息

问题

发生奇怪的事情,您需要知道从何处开始解决问题。

解决方案

记录所有内容,然后阅读您的日志文件。/var/log包含日志文件,dmesgjournalctl命令显示日志消息。systemd 通过journald管理所有日志,因此您会在dmesg/var/log中看到很多重复信息。

dmesg读取内核环形缓冲区,这是一个特殊的内存位置,用于记录内核活动。查看dmesg以查看启动时发生的所有事情;启动后的硬件活动,如连接和移除 USB 设备;以及网络接口活动。内核环形缓冲区是固定大小的,因此新条目会覆盖最旧的条目。没有数据会丢失,因为内核日志存储在/var/log/messages/var/log/dmesgjournalctl中。

以这种方式阅读dmesg

$ dmesg | less
[    0.000000] microcode: microcode updated early to revision 0x28,
date = 2019-11-12
[    0.000000] Linux version 5.8.0-45-generic (buildd@lcy01-amd64-024) (gcc
(Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0, GNU ld (GNU Binutils for Ubuntu) 2.34)
#51~20.04.1-Ubuntu SMP Tue Feb 23 13:46:31 UTC 2021
(Ubuntu 5.8.0-45.51~20.04.1-generic 5.8.18)
[...]

当您寻找特定内容时,请使用grep,比如当您在处理存储驱动器的问题时:

$ dmesg | grep -w sd
[11236.888910] sd 7:0:0:0: [sdd] Attached SCSI removable disk
[11245.095341] FAT-fs (sdd1): Volume was not properly unmounted. Some data may
be corrupt. Please run fsck.

使用 grep 查找完整单词

当您想要使用grep查找单词时,请使用-w开关。例如,当您 grep ping时,您会得到类似 piping、escaping、sleeping 的结果。-w只返回完整的单词匹配项。

运行dmesg -T以查看可读的时间戳:

$ dmesg -T | less
[Tue Mar 23 15:25:17 2021] PCI: CLS 64 bytes, default 64
[Tue Mar 23 15:25:17 2021] Trying to unpack rootfs image as initramfs...
[Tue Mar 23 15:25:17 2021] Freeing initrd memory: 56008K
[...]

默认是启动后的秒数和纳秒数。运行dmesg --follow以监视新事件的发生,如插入和拔出 USB 设备。按 Ctrl-C 停止。

查找特定的日志级别,如错误和警告:

$ dmesg -l err,warn

运行dmesg -h以查看命令和选项。

/var/log是日志文件的传统位置,根据您的 Linux 发行版管理方式,您仍然会在那里找到日志。/var/log易于搜索,因为大多数文件都是纯文本。当您不确定从哪里开始搜索时,请在整个目录中grep

例如,假设您认为已安装graphicsmagick,但找不到它。快速查看/var/log,您会找到它的安装记录:

$ sudo grep -ir graphicsmagick /var/log
apt/history.log:Install: libgraphicsmagick-q16-3:amd64 (1.4+really1.3.35-1,
automatic), graphicsmagick:amd64 (1.4+really1.3.35-1)
[...]
/var/log/dpkg.log:2021-03-11 17:00:57 install libgraphicsmagick-q16-3:amd64
1.4+really1.3.35-1
[...]

systemd 把所有日志都装进 journalctl,因此你可以专门使用它,不必再麻烦 dmesg/var/log

$ journalctl

使用 sudo 调用它,看看是否增加了更多信息。通常不会。

journalctl 默认按照最老的条目显示。按空格键或 PageUp/Down 键以逐屏导航,或使用箭头键逐行滚动。Ctrl-End 到达最新,Ctrl-Home 返回最老。按 Q 键退出。

首先查看最新的条目:

$ journalctl -r

默认情况下它不换行长行,因此你必须使用箭头键来阅读长行。通过将其输出导入 less 来实现换行:

$ journalctl -r | less

查看最近的条目,并显示解释消息(如果有的话)。这展示了一个解释消息的例子:

$ journalctl -ex | less

-- The unit grub-initrd-fallback.service has successfully entered the 'dead'
state.
Mar 27 10:14:29 client4 systemd[1]: Finished GRUB failed boot detection.
-- Subject: A start job for unit grub-initrd-fallback.service has finished
successfully
-- Defined-By: systemd

搜索特定服务,比如 MariaDB:

$ sudo journalctl -u mariadb.service
Mar 19 16:07:27 client4 /etc/mysql/debian-start[7927]: Looking for 'mysql' as:
/usr/bin/mysql
Mar 19 16:07:27 client4 /etc/mysql/debian-start[7927]: Looking for 'mysqlcheck'
as: /usr/bin/mysqlcheck
[...]

选择日期范围,你可以用几种方式定义:

$ journalctl -u mariadb.service -S today
$ journalctl -u ssh.service -S '1 week ago'
$ journalctl -u libvirtd.service -S '2021-03-05'
$ journalctl -u httpd.service -S '2021-03-05' -u '2021-03-09'
$ journalctl -u nginx.service -S '2 hours ago'

当未指定时间时,默认为 00:00:00,即午夜。以 HH:MM:SS 格式指定时间:

$ journalctl -u httpd.service -S '2021-03-05 13:15:00' -U now

查看从一小时前到五分钟前的活动,并显示单位文件名:

$ journalctl -S '1h ago' -U '5 min ago' -o with-unit

journalctl 按系统启动时间排序日志。查看自最近启动以来的 HTTP 服务器活动,并将显示的行数限制为最近的 50 行:

$ journalctl -b -n 50 -u httpd.service

查看三次启动前发生了什么:

$ journalctl -b -2 -u httpd.service

列出所有记录的启动会话,并带有时间戳:

$ journalctl --list-boots

你可以筛选特定的严重级别。当你指定单个级别时,在这个例子中是 crit,它显示从 crit 到最严重级别 emerg 的所有消息:

$ journalctl -b -1 -p "crit" -u nginx.service

自定义你的范围,例如从 critwarning

$ journalctl -b -3 -p "crit".."warning"

跟随记录的新事件,从最近的 10 个条目开始记录:

$ journalctl -n 10 -u mariadb.service -f

Ctrl-C 停止它。

当然,使用好老式的 grep 来查找东西,比如用户名或任何你希望搜索的术语:

$ journalctl -b -1 | grep madmax

讨论

严重级别遵循标准的 syslog 级别,从 0 到 7,其中 0 最严重,7 最不严重:

emerg      (0)
alert      (1)
crit       (2)
err        (3)
warning    (4)
notice     (5)
info       (6)
debug      (7)

journalctl 提供了数十种过滤和解析输出的方法,你可以在 man 1 journalctl 中了解更多。

参见

20.2 配置 journald

问题

不确定 journald 的默认配置是什么,需要知道如何查看当前配置和如何更改它。

解决方案

journald 的配置在 /etc/systemd/journald.conf 中。一些默认选项被注释掉,所有编译时默认值在 man 5 journald.conf 中有文档。我们将查看最常用的选项。

Storage=auto 在不同的发行版上有不同的含义。Ubuntu 和 Fedora 使用 /run/log/journal/ 作为易失性存储,持久性存储在 /var/log/journal 中。使用 systemctl 查看日志文件的位置,已用空间和空闲空间:

$ systemctl status systemd-journald.services
● systemd-journald.service - Journal Service
   Loaded: loaded (/usr/lib/systemd/system/systemd-journald.service; static;
   vendor preset: disabled)
   Active: active (running)
   [...]
Mar 27 15:04:40 server2 systemd-journald[508]: Runtime journal (/run/log/journal/
1181e27c52294e97a8ca5c5af5c92e20) is 8.0M, max 2.3G, 2.3G free.
Mar 27 15:04:55 server2 systemd-journald[508]: Time spent on flushing to /var is
381.408ms for 1176 entries.
Mar 27 15:04:55 server2 systemd-journald[508]: System journal (/var/log/journal/
1181e27c52294e97a8ca5c5af5c92e20) is 16.0M, max 4.0G, 3.9G free.

openSUSE 将易失性存储放在 /run/log/journal/ 中,并将持久性存储放在 /var/log/messages 中。如果你喜欢使用 /var/log/journal,请创建它并将组所有者更改为 systemd-journal

$ sudo mkdir /var/log/journal
$ sudo chgrp /var/log/journal/ systemd-journal

您不必更改其他任何内容,存储在重启后会发生变化。其他选项为 volatilepersistentnone

volatile 只在内存中的 /run/log/journal/ 中存储日志。

persistent 在磁盘上存储日志,并在磁盘不可用时(例如系统启动早期)使用 /run/log/journal/

none 禁用所有本地日志记录,并可选择将日志消息发送到中央日志服务器。

SystemMaxUse= 控制磁盘上日志存储的大小,RuntimeMaxUse= 控制易失性存储的大小。默认值为文件系统中可用空间的 10%,最多为 4 GB。

SystemKeepFree=RuntimeKeepFree= 控制留给其他用途的磁盘空间量。默认值为 15% 和 4 GB。您可以通过指定字节数量进行更改,或使用 K、M、G、T、P 和 E;例如,25 G(千兆字节)。

MaxRetentionSec= 控制文件保留时间。默认值为 0(禁用),文件的保留时间由其他设置(如可用磁盘空间)决定。您可以配置一个时间值,例如 6 month 使用 yearmonthweekdayhm

讨论

journald 自动处理日志轮换。活动文件会被轮换为存档文件,并根据您的配置删除存档文件。

参见

  • man 5 journald.conf

20.3 使用 systemd 构建日志服务器

问题

您希望设置一个中央日志服务器,以便在系统崩溃时保留日志,并进行集中管理。

解决方案

systemd 提供了一个远程日志守护进程 journald。客户端机器将其日志消息发送到 journald 服务器。前提条件如下:

  • 用于托管日志文件的机器

  • 客户端访问日志服务器的网络访问权限

  • 在日志服务器和所有客户端上安装 systemd-journal-remote

  • 您的公钥基础设施(PKI)已经就位(Recipe 13.5),密钥和证书已分发到服务器和客户端

安装 systemd-journal-remote 后,在服务器上编辑 /etc/systemd/journal-remote.conf。我喜欢将加密密钥和证书存储在 /etc/pki/journald/ 中:

[Remote]
Seal=false
SplitMode=host
ServerKeyFile=/etc/pki/journald/*log-server.key*
ServerCertificateFile=/etc/pki/journald/*log-server.crt*
TrustedCertificateFile=/etc/pki/journald/*ca.crt*

设置服务器密钥和证书的权限:

$ sudo chmod -R 0755 /etc/pki/journald
$ sudo chmod 0440 /etc/pki/journald/*log-server.key*

将服务器私钥的组所有者更改为 systemd-journal-remote

$ sudo chgrp systemd-journal-remote /etc/pki/journald/*log-
server.key*

启用并启动 systemd-journal-remote 服务,首先启动 systemd-journal-remote.socket

$ sudo systemctl enable --now systemd-journal-remote.socket
$ sudo systemctl enable --now systemd-journal-remote.service

检查两者的状态,确保它们已正确启动。在服务器防火墙中打开必要的端口:

$ sudo firewall-cmd --zone=*internal* --add-port=19532/tcp
$ sudo firewall-cmd --zone=*internal* --add-port=80/tcp
$ sudo firewall-cmd --runtime-to-permanent
$ sudo firewall-cmd --reload

在每个客户端上创建一个新用户 systemd-journal-upload。这是 systemd-journal-upload 进程用来将日志消息传输到中央服务器的用户:

$ sudo useradd -r -d /run/systemd -M -s /usr/sbin/nologin -U \
systemd-journal-upload

设置客户端密钥和证书的权限:

$ sudo chmod -R 0755 /etc/pki/journald
$ sudo chmod 0440 /etc/pki/journald/*client.key*

编辑 /etc/systemd/journal-upload.conf,填写日志服务器的 URL 和 TCP 端口,以及客户端密钥和证书的位置:

[Upload]
URL=https://*logserver.example.com:19532*
ServerKeyFile=/etc/pki/journald/*client1.key*
ServerCertificateFile=/etc/pki/journald/*client1.crt*
TrustedCertificateFile=/etc/pki/journald/*ca.crt*

重新启动 systemd-journal-upload.service

$ sudo systemctl restart systemd-journal-upload.service

如果成功重启且无错误,运行以下步骤来测试客户端是否将日志条目发送到服务器。检查服务器上的日志目录:

$ sudo ls -la /var/log/journal/remote/
total 7204
drwxr-xr-x  2 systemd-journal-remote systemd-journal-remote  6 Mar 26 16:41 .
drwxr-sr-x+ 4 root                   systemd-journal        60 Mar 26 16:41 ..
rw-r-----  1 systemd-journal-remote systemd-journal-remote 8388608 Mar 26  1
10:46 'remote-CN=client1.example.com'

看起来不错。现在,从客户端向服务器发送一条消息:

$ sudo logger -p syslog.debug "Hello, I am client1! Do you hear me?"

在服务器上运行您喜欢的 journalctl 命令,调用最近的条目。如果看到客户端消息,说明您已正确设置:

Mar 27 18:30:11 client1 madmax[15228]: Hello, I am client1! Do you hear me?

讨论

中央日志服务器保存客户端日志,并集中日志存储,便于维护和分析。每个客户端在服务器上有自己的目录。

Seal=false 禁用日志条目的加密签名。要尝试,请参阅 man 1 journalctl 中的 --setup-keys 选项。我找不到是否提供实质性好处的明确答案,但了解它也不会有坏处。

SplitMode=host 将每个客户端的日志存储在其自己的文件中。将其设置为 false 可以将所有内容转储到单个文件中。

ServerKeyFile=ServerCertificateFile=TrustedCertificateFile= 是存储加密密钥和证书的位置。

另请参阅

  • man 5 journal-remote.conf

  • man 5 journald.conf

  • man 1 journalctl

20.4 使用 lm-sensors 监控温度、风扇和电压

问题

您想要测量计算机机箱内部的温度、风扇转速和电压。

解决方案

使用 lm-sensors 持续监控 CPU、硬盘和机箱温度。这由 openSUSE 上的 sensors 包、Fedora 上的 lm_sensors 和 Ubuntu 上的 lm-sensors 提供。

安装完 lm-sensors 后,运行 sensors-detect 命令来校准 lm-sensors 到您的硬件:

$ sudo sensors-detect
# sensors-detect version 3.6.0
# Board: ASRock H97M Pro4
# Kernel: 5.8.0-45-generic x86_64
# Processor: Intel(R) Core(TM) i7-4770K CPU @ 3.50GHz (6/60/3)

This program will help you determine which kernel modules you need
to load to use lm_sensors most effectively. It is generally safe
and recommended to accept the default answers to all questions,
unless you know what you're doing.

Some south bridges, CPUs or memory controllers contain embedded sensors.
Do you want to scan for them? This is totally safe. (YES/no):
[...]

按 Enter 接受所有默认设置。当完成时,您会看到类似于这样的内容:

To load everything that is needed, add this to /etc/modules:
#----cut here----
# Chip drivers
coretemp
nct6775
#----cut here----
If you have some drivers built into your kernel, the list above will
contain too many modules. Skip the appropriate ones!

Do you want to add these lines automatically to /etc/modules? (yes/NO) yes
Successful!

模块将在重新启动后加载,或者您可以立即加载它们:

$ sudo systemctl restart systemd-modules-load.service

现在运行 sensors 命令并查看结果:

$ sensors
coretemp-isa-0000
Adapter: ISA adapter
Package id 0:  +42.0°C  (high = +86.0°C, crit = +96.0°C)
Core 0:        +34.0°C  (high = +86.0°C, crit = +96.0°C)
Core 1:        +35.0°C  (high = +86.0°C, crit = +96.0°C)
Core 2:        +32.0°C  (high = +86.0°C, crit = +96.0°C)
Core 3:        +31.0°C  (high = +86.0°C, crit = +96.0°C)

nouveau-pci-0300
Adapter: PCI adapter
GPU core:     +1.01 V  (min =  +0.70 V, max =  +1.20 V)
fan1:        2850 RPM
temp1:        +51.0°C  (high = +95.0°C, hyst =  +3.0°C)
                       (crit = +105.0°C, hyst =  +5.0°C)
                       (emerg = +135.0°C, hyst =  +5.0°C)

dell_smm-virtual-0
Adapter: Virtual device
Processor Fan: 1070 RPM
Other Fan:        0 RPM
Other Fan:      603 RPM
CPU:            +41.0°C
SODIMM:         +25.0°C
SODIMM:         +35.0°C
SODIMM:         +34.0°C

这显示了 CPU 核心、显卡适配器、风扇和内存模块的信息。您可以看到当前温度以及高、临界和紧急温度范围。CPU 有内置的自我保护机制,当温度过高时会自动关闭。

使用 watch 命令每两秒查看更新的状态,并突出显示任何差异:

$ watch -d sensors

设置不同的更新间隔,如 10 秒:

$ watch -d -n 10 sensors
Every 10.0s: sensors
[...]

按 Ctrl-C 停止。

讨论

lm_sensors 并非魔法,它只读取带有温度传感器和 Linux 驱动程序的设备。大多数温度传感器精度不高,因此不必担心小的波动。

监控温度、电压和风扇转速可以提前预警问题。更换风扇比重建过热的计算机便宜。电压下降可能表示电源供应器故障或连接不良。

在修改 /etc/modules 文件之前,请检查你的内核配置,看看 sensors-detect 建议的模块是否已经加载或静态编译。你的内核配置文件位于 /boot 目录中,命名为 config-kernel-version,例如 config-5.8.0-45-generic。例如,搜索 nct6775 模块:

$ grep -i nct6775 config-5.8.0-45-generic
CONFIG_SENSORS_NCT6775=m

m 表示可加载的内核模块。检查是否已加载:

$ lsmod | grep nct6775

如果返回空白,请将其添加到 /etc/modules。如果是静态编译的,它会像这样在 config-* 中显示:

CONFIG_SENSORS_NCT6775=y

y 表示它内建于内核中,因此不要将其添加到 /etc/modules

参见

20.5 添加一个图形界面到 lm-sensors

问题

你需要一个可配置的图形显示界面来显示 lm-sensors 并自动更新。

解决方案

你有几个很好的选择。图形界面的 lm-sensors 也支持其他监视器,比如 smartmontoolshddtemp。Psensor 提供了大屏显示、彩色图表和简单配置,可以重命名标签并显示你想看到的内容(图 20-1)。

Psensor 支持警报。通过点击每个监视器以显示首选项菜单,分别启用 CPU 核心和风扇的警报(图 20-2)。

Psensor 追踪多个硬件监视器。

图 20-1. Psensor 追踪多个硬件监视器

启用警报和警报阈值。

图 20-2. 启用警报和警报阈值

你需要编写一个简单的脚本来设置警报,就像以下示例:

#!/bin/bash
# toohot.sh, plays a mad klavichord riff when a sensor monitor
# exceeds its upper limit

play /home/madmax/Music/klavichord-4.wav

安装 sox 以获取 play 命令。将你的脚本设为可执行:

$ chmod +x *toohot.sh*

测试它:

$ play *toohot.sh*

当满意时,配置 Psensor 使用它。打开 Psensor → 首选项 → 传感器(图 20-3)。

设置一个警报。

图 20-3. 设置一个警报

在 Psensors 中测试它的一个简单方法是将一些最大温度设置得太低。

许多桌面环境,如 Xfce4、GNOME 和 KDE,都有漂亮的小任务栏插件,例如 Xfce4 中显示的内容(图 20-4)。

Xfce 任务栏插件适用于 lm-sensors。

图 20-4. Xfce 任务栏插件适用于 lm-sensors

它们的包名都含有 sensor,除了 gnome-shell-extension-freon

讨论

你可以编写脚本,在触发警报时自动关闭系统,就像下面这个简单的例子:

#!/bin/bash
echo "Help, too hot, I am shutting down right now!" && shutdown -h now

参见

20.6 使用 smartmontools 监控硬盘健康

问题

你需要知道硬盘何时出现故障,或更好的是,何时可能出现故障,以便在丢失数据之前替换它。

解决方案

大多数硬盘和固态硬盘都配备了 S.M.A.R.T.(自我监控分析与报告技术)。S.M.A.R.T. 跟踪并记录某些性能属性,您可以监视这些属性来(希望)预测即将发生的故障。Linux 用户可以使用 smartmontools 读取这些信息并提供警告。

smartmontools 是由 smartmontools 包提供的。它应该会自动安装并启动一个 systemd 服务,您可以用 systemctl 来检查:

$ systemctl status smartd.service

使用 smartctl 命令查看您的磁盘是否支持 S.M.A.R.T.。查找 SMART 支持行:

$ sudo smartctl -i /dev/*sda*
smartctl 7.1 2019-12-30 r5022 [x86_64-linux-5.8.0-45-generic] (local build)
Copyright (C) 2002-19, Bruce Allen, Christian Franke, www.smartmontools.org

=== START OF INFORMATION SECTION ===
Model Family:     Seagate Desktop HDD.15
Device Model:     ST4000DM000-1F2168
[...]
SMART support is: Available - device has SMART capability.
SMART support is: Enabled

为要监视的每个磁盘启用和禁用 smartctl

$ sudo smartctl -s on /dev/*sda*
$ sudo smartctl -s off /dev/*sda*

使用 -x 标志进行完整数据转储:

$ sudo smartctl -x /dev/*sda*

运行短健康检查:

$ sudo smartctl -H /dev/*sda*
smartctl 7.1 2019-12-30 r5022 [x86_64-linux-5.8.0-45-generic] (local build)
Copyright (C) 2002-19, Bruce Allen, Christian Franke, www.smartmontools.org

=== START OF READ SMART DATA SECTION ===
SMART overall-health self-assessment test result: PASSED

使用 -Hc 标志查看完整报告。

检查日志文件:

$ sudo smartctl -l error /dev/*sda*
smartctl 7.0 2019-05-21 r4917 [x86_64-linux-5.3.18-lp152.66-preempt] (SUSE RPM)
Copyright (C) 2002-18, Bruce Allen, Christian Franke, www.smartmontools.org

=== START OF READ SMART DATA SECTION ===
SMART Error Log Version: 1
No Errors Logged

有一个短自检和一个长自检。它们告诉您启动它们时每个测试将花费多长时间:

$ sudo smartctl -t long /dev/*sda*
[...]
=== START OF OFFLINE IMMEDIATE AND SELF-TEST SECTION ===
Sending command: "Execute SMART Extended self-test routine immediately in
off-line mode".
Drive command "Execute SMART Extended self-test routine immediately in off-line
mode" successful.
Testing has begun.
Please wait 109 minutes for test to complete.
Test will complete after Thu Mar 25 17:06:33 2021

Use smartctl -X to abort test.

当其完成时不会通知您,您可以随时检查日志文件:

$ sudo smartctl -l selftest /dev/*sda*

[sudo] password for carla:
[...]
=== START OF READ SMART DATA SECTION ===
SMART Self-test log structure revision number 1
Num  Test_Description    Status                  Remaining  LifeTime(hours)
 # 1  Extended offline    Self-test routine in progress 70%      7961
 # 2  Short offline       Completed without error       00%      7960
 # 3  Short offline       Completed without error       00%      7952
 [...]

记得定期更新硬盘数据库:

$ sudo update-smart-drivedb
/usr/share/smartmontools/drivedb.h updated from branches/RELEASE_7_0_DRIVEDB

讨论

S.M.A.R.T. 大约有 60% 的可靠性。它可能会更好,但是 S.M.A.R.T. 标准对解释留有很大余地,每个驱动器制造商都以不同方式实施它。制造商文档稀缺,我找到的最佳资源是维基百科和 https://smartmontools.org。像往常一样,您最好的保险是定期备份。

即便如此,它是免费的,易于使用,并且通常很有用。注意 Pre-fail 属性(如下面的片段所示),并查看本章介绍如何提高系统性能和可靠性。

运行 sudo smartctl -a /dev/sda 来转储所有 S.M.A.R.T. 数据。这部分通常会引起警报:

SMART Attributes Data Structure revision number: 10
Vendor Specific SMART Attributes with Thresholds:
ID# ATTRIBUTE_NAME          FLAG     VALUE WORST THRESH TYPE      UPDATED
  1 Raw_Read_Error_Rate     0x000f   119   099   006    Pre-fail  Always
  3 Spin_Up_Time            0x0003   092   091   000    Pre-fail  Always
  4 Start_Stop_Count        0x0032   099   099   020    Old_age   Always
  5 Reallocated_Sector_Ct   0x0033   100   100   010    Pre-fail  Always
  7 Seek_Error_Rate         0x000f   059   057   030    Pre-fail  Always
  9 Power_On_Hours          0x0032   089   089   000    Old_age   Always
 10 Spin_Retry_Count        0x0013   100   100   097    Pre-fail  Always
 12 Power_Cycle_Count       0x0032   099   099   020    Old_age   Always
183 Runtime_Bad_Block       0x0032   100   100   000    Old_age   Always
184 End-to-End_Error        0x0032   100   100   099    Old_age   Always
187 Reported_Uncorrect      0x0032   100   100   000    Old_age   Always
188 Command_Timeout         0x0032   100   099   000    Old_age   Always
189 High_Fly_Writes         0x003a   100   100   000    Old_age   Always
190 Airflow_Temperature_Cel 0x0022   072   059   045    Old_age   Always
191 G-Sense_Error_Rate      0x0032   100   100   000    Old_age   Always
192 Power-Off_Retract_Count 0x0032   100   100   000    Old_age   Always
193 Load_Cycle_Count        0x0032   096   096   000    Old_age   Always
194 Temperature_Celsius     0x0022   028   041   000    Old_age   Always
197 Current_Pending_Sector  0x0012   100   100   000    Old_age   Always
198 Offline_Uncorrectable   0x0010   100   100   000    Old_age   Offline
199 UDMA_CRC_Error_Count    0x003e   200   200   000    Old_age   Always
240 Head_Flying_Hours       0x0000   100   253   000    Old_age   Offline
241 Total_LBAs_Written      0x0000   100   253   000    Old_age   Offline
242 Total_LBAs_Read         0x0000   100   253   000    Old_age   Offline

TYPE 列告诉属性的类型,可以是 Pre-failOld_age。当您看到所有这些 Pre-failOld_age 标签时,并不意味着您的磁盘注定要失败,那只是该行的属性类型。

Pre-fail 是一个关键属性,可能表明即将发生的故障,并且始终包含在健康评估中。

Old_age 是一个非关键属性;它不包含在磁盘健康报告中。

ID#ATTRIBUTE_NAME 标识每个属性。这些因制造商而异。

FLAG 是属性处理标志,与磁盘健康无关。

VALUE 列显示属性的当前值。这些值范围从 0 到 255,除了 0、254 和 255。253 表示“未使用”,例如当你有一块新的硬盘时。VALUE 是一个从好到坏的评分,数字越高表示越好,数字越低表示越差,除了温度属性,它们表示摄氏温度。

WORST 是记录该属性的最低值。

THRESH 是每个属性的最低阈值,当 Pre-fail 属性低于 THRESH 时,磁盘可能会即将故障。

UPDATED 应该指示属性何时被更新。始终在线和离线,离线通常只意味着在运行离线测试时。通常这不准确,而且在任何情况下都不是特别有帮助。

如果某个属性进入故障状态,失败时间会记录在WHEN_FAILED中。

RAW_VALUE是特定于每个制造商的。忽略它。

另请参见

  • man 8 smartctl

  • man 8 smartd

  • man 8 update-smart-drivedb

  • man 5 smartd.conf

20.7 配置 smartmontools 发送电子邮件报告

问题

你希望收到由smartd通过电子邮件发送给你的任何问题的电子邮件通知。

解决方案

首先,通过向系统上的另一个用户(如 root)发送测试消息,检查系统邮件是否已经设置并正常工作:

$ echo "Hello, this is my message" | mail -s "Message subject" root@localhost

[root@localhost ~]# mail
"/var/mail/root": 1 message 1 unread
>U "/var/mail/root": 1 message 1 new
>N   1 stash    Mon Mar 29 15:26  13/429   Message subject
?

按 1 阅读消息,按 q 退出。这表明系统邮件已经设置。如果没有,请安装mailxpostfixmailx是一个邮件用户代理(MUA),类似于 Evolution、Thunderbird、KMail、Mutt 等邮件客户端。postfix是一个邮件传输代理(MTA)。你需要这两个。安装后,使用systemctl检查它们是否正在运行:

$ systemctl status smartd.service
$ systemctl status postfix.service

如果它们没有运行,启用并启动它们,然后再次尝试测试消息。

$ sudo systemctl enable --now smartd.service
$ sudo systemctl enable --now postfix.service

smartd/etc/smartd.conf/etc/smartmontools/smartd.conf中进行配置。默认情况下是扫描所有可能的设备,并将错误报告通过电子邮件发送给 root 用户。最好配置你想要监控的设备。每个 Linux 系统都有其特殊的配置。以下配置应该适用于所有系统,当然你必须指定自己的磁盘和电子邮件地址:

DEFAULT -a -o on -S on -s (S/../.././02|L/../../5/01):
/dev/*sda*
/dev/*sdb*
/dev/*sdc*
DEFAULT -H -m root -M test

保存您的配置更改并重新加载smartd.service

$ sudo systemctl reload smartd.service

讨论

smartd.conf中的默认行为是扫描所有可用的驱动器。指定要监控的驱动器会更有效。

-a选项与所有这些选项组合在一起:

  • -H,检查 S.M.A.R.T. 健康状态

  • -f,报告使用属性(VALUEWORST)故障

  • -t,报告前故障和使用属性的变化

  • -l,报告 ATA 错误的增加

  • -l selftest,报告自检日志错误的增加

  • -l selfteststs,报告自检执行状态的变化

  • -C 197,报告当前待处理扇区计数的非零值

  • -U 198,报告离线待处理扇区计数的非零值

这涵盖了所有重要内容,当然你可以调整它以报告你喜欢的任何属性。

-M test在每次启动时向指定用户发送测试消息(在前面的示例中,-m root@localhost)。当你确信它按照你想要的方式工作时,可以删除此选项。

有几个软件包提供mail二进制文件:mailutilsmailxbsd-mailxs-nail,其中一些而已。对于系统守护进程使用的简单本地邮件发送器,任何一个都可以完成任务,mail二进制文件在所有这些中使用相同的选项。

你不必使用postfix,也可以使用你喜欢的任何 MTA,如 Exim 或 Sendmail。

另请参见

  • man 8 smartd

  • man 5 smartdconf

20.8 使用 top 诊断系统变慢问题

问题

你的系统通常运行良好,但现在一切都变得缓慢且耗时很长。应用程序启动或关闭时花费大量时间,或者对用户输入响应缓慢。你需要找出原因,然后解决它。

解决方案

执行 top 命令以查看哪些进程正在使用过多的系统资源。CPU 和内存消耗大的进程会让你强大的系统感觉像老旧的:

$ top
Tasks: 284 total,   1 running, 283 sleeping,   0 stopped,   0 zombie
%Cpu(s):  6.4 us,  4.8 sy,  0.0 ni, 88.9 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
MiB Mem :  15691.4 total,   6758.9 free,   4913.0 used,   4019.6 buff/cache
MiB Swap:  15258.0 total,  15258.0 free,      0.0 used.  10016.5 avail Mem

    PID USER      PR  NI   VIRT    RES    SHR S    %CPU  %MEM   TIME+ COMMAND
   1299 duchess      9  0 2803912  22296  17904 S  80.5   0.1  172:25 Web Content
   1685 duchess     20  0 3756840 543124 241296 S   7.6   3.4   27:53 firefox
  15926 libvirt+    20  0 5151504   2.3g  25024 S   1.7  15.3    1:39 qemu
  [...]

top 运行直到你停止它,每隔几秒刷新一次,并按活动程度从最高到最低显示进程。按 q 键退出。

这显示了大量的信息。相关部分是 Web Content 正在使用 80.5% 的 CPU 时间。构造不良的网站是导致系统停滞的常见原因。快速修复的方法是终止那些有问题的进程。

进程 ID 在左列显示。按下 k 键打开终止对话框。如果默认的要终止的 PID 是正确的,请按 Enter 键。按 Enter 接受默认的 15/sigterm 终止进程:

PID to signal/kill [default pid = 1299]
Send pid 1299 signal [15/sigterm]

如果这不能终止进程,使用核心选项 9,即 sigkill

PID to signal/kill [default pid = 1299]
Send pid 1299 signal [15/sigterm] 9

如果你没有足够的权限来终止进程,请使用 sudo 启动 top。或者,在另一个终端运行 sudo kill

讨论

终止进程并不总是最好的解决方案。如果进程由 systemd 控制,systemd 可能会立即重新启动它,或者其他进程可能依赖于它,那么你可能会引发混乱。如果可能,请使用 systemctl stop 将其关闭。如果问题进程不受 systemd 控制,则可以终止它。

默认要终止的 PID 总是顶部的 PID,即使用最多系统资源的 PID。如果这不是你想要停止的 PID,你可以输入一个不同的 PID。

"这个 sigterm 是什么东西?" 你会问。信号 是从 Unix 继承而来的,非常陈旧,多年来添加了许多变种,你可以在 man 2 signal 中详细了解,例如 SIGHUPSIGINTSIGQUIT 和许多其他信号。

对用户和系统管理员来说,最相关的两个是 SIGKILLSIGTERM。始终首先尝试 SIGTERM,因为它可以优雅地停止进程,确保任何子进程都被移交给 INIT 而不是变为孤儿,并且通知父进程。SIGTERM 的唯一缺点是进程可以选择忽略它。

仅当 SIGTERM 无效时才使用 SIGKILLSIGKILL 不能被忽略,并且会终止子进程,这可能会影响其他进程。由于父进程没有通知,一个进程可能被留在僵尸状态。僵尸进程本身并不是什么大问题,它们只是无所作为地存在着。你可以在 top 的标题中看到是否有这样的进程,在 Tasks 行的右侧。以下示例显示了两个僵尸进程:

Tasks: 249 total, 1 running, 248 sleeping, 0 stopped, 2 zombie

您不需要做任何事情,因为父应用程序应该会自动清理它们。如果没有清理,这也不是什么大问题,除非它产生了一大堆僵尸进程。这告诉您应用程序存在问题。您无法杀死僵尸进程,因为它们已经死了。它们只使用微小的系统资源,但如果您想尝试清除它们,请尝试发送SIGCHLD信号:

$ sudo kill -s SIGCHLD *1299*

如果同一个进程继续使用过多的系统资源,请检查其程序的配置文件或设置,看看是否存在错误,或者您是否可以调整其以提高效率。检查您的日志文件(配方 20.1)以获取线索。

参见

  • man 1 top

  • man 1 kill

20.9 在 top 中查看选定的进程

问题

您只想跟踪一个或少量进程。

解决方案

用逗号分隔的进程列表启动top以跟踪进程:

$ top -p *4548, 8685, 9348*
top - 10:57:39 up 44 min,  2 users,  load average: 0.10, 0.11, 0.21
Tasks:   3 total,   0 running,   3 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.2 us,  0.2 sy,  0.0 ni, 99.6 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
MiB Mem :  15691.4 total,  12989.5 free,   1467.4 used,   1234.4 buff/cache
MiB Swap:  15258.0 total,  15258.0 free,      0.0 used.  13601.1 avail Mem

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
   2907 mysql     20   0 1775688  78584  18396 S   0.0   0.5   0:00.22 mysqld
    927 root      20   0 1569764  39072  29320 S   0.0   0.2   0:00.16 libvirtd
    822 root      20   0   11040   6384   4732 S   0.0   0.0   0:00.02 smartd

现在您可以专注于想要查看的内容,而无需浏览其余的进程群。按等号键(=)返回完整的进程列表。

参见

  • man 1 top

  • man 1 kill

20.10 从冻结的图形桌面中恢复

问题

在您开心工作时,图形桌面却冻结了。光标移动,但非常缓慢,或根本不动。

解决方案

这是我最喜欢的 Linux 功能之一:从图形会话切换到控制台。按下 Ctrl-Alt-F2,您应该会发现自己在图形会话下方的纯文本控制台(图 20-5)。

Linux 控制台。

图 20-5. Linux 控制台

登录,现在您可以运行一些故障排除命令。从top开始,找到阻塞系统的流浪进程并将其终止,检查日志文件,运行其他诊断,无论您需要做什么。解决问题后,按下 Alt-F7 返回到图形桌面。最坏的情况是您将不得不关闭或重新启动,这比从按电源按钮强制关闭要好。

各种 Linux 系统以不同方式映射这些键组合。Alt-F7 是图形会话的传统方式。Fedora 使用 Alt-F1。尝试它们都不会有任何损害。

讨论

另一个选择是从另一台计算机打开 SSH 会话,尝试解冻您的图形桌面。

对我来说,同时拥有控制台和图形环境是最好的选择。

强制关闭不一定像以前那样是灾难,特别是当您使用日志文件系统如 Ext4、XFS 或 Btrfs 时。

标准配置是七个控制台,从 F1 到 F7。每个都是独立的登录会话。

使用 Ctrl-Alt-Fn离开图形会话并进入控制台,在控制台中使用 Alt-Fn

20.11 硬件故障排除

问题

您认为硬件出现故障,并且需要知道如何进行测试。

解决方案

当您怀疑有硬件问题时,首先尝试本章关于硬件监控的建议。一些系统的 UEFI 固件包括硬件健康监视器。

如果监视器没有明确指出问题的方向,请关闭计算机,打开机箱,清除灰尘,清洁过滤器(如果有),然后移除并重新插入所有可拔插并重新连接的部件:电源电缆、SATA 电缆、显卡和其他 PCI 扩展卡、内存模块和风扇连接器。仔细重新连接所有部件,并特别注意正确重新插入内存模块。

如何不毁坏您的硬件或自己

谨慎!接地后触摸其他物体以释放静电。戴上防静电腕带,将组件放在防静电垫上。拔掉电源插头,在插入的情况下绝对不要触碰机箱内任何东西。

如果您知道如何使用万用表,请使用它测试电源供应器,或者尝试更换不同的电源供应器。使用万用表测试相对容易,并且有许多操作指南。如果有备用零件,更换疑似组件并尝试不同的组件可以准确定位故障硬件。

在完成所有操作并重新组装后,请检查问题是否已解决。在我的电脑冒险中,许多问题通过重新插拔内存模块或将其移至不同插槽来解决。请注意,在大多数主板上,您必须在特定插槽中安装 RAM 对。与 RAM 相关的一些问题包括数据损坏、不完整引导以及奇怪的行为,例如当您按下电源开关启动系统时,电源波动似乎像是电源供应器故障一样,无法启动。

确保您的机箱风扇朝向正确。空气通常从前面和侧面吸入机箱,然后从后面排出。

Linux 中有相当多的硬件测试工具。一些供应商提供他们自己的硬件和系统测试工具;例如,联想 ThinkPad 配备了全面的测试工具,可以测试系统中的每个组件。

GtkStressTesting 是一个用于压力测试 CPU、内存和其他组件的实用工具,并提取详细的主板信息。请按照设置指南中的说明将其安装在您的系统上。它包括类似于lm-sensors的监视器。

它没有的一个功能是 I/O 监控,您需要用iotop来检测性能瓶颈。iotop可以在类似于top的界面中监视磁盘性能。

讨论

确定问题是软件问题还是硬件问题可能很困难。要有条不紊地进行彻底检查,因为赶忙会花费更多时间。利用您 Linux 发行版的可用帮助,因为每个发行版都有其特定的问题。始终阅读发布说明。

参见

  • man 8 iotop

  • GtkStressTesting

  • 您的硬件组件的文档

  • 您的 Linux 发行版文档、论坛、维基和发布说明

  • 第十章

  • 食谱 20.6

第二十一章:网络故障排除

解决网络问题就像任何故障排除一样。了解你的网络,熟练使用基本工具,耐心和系统性十分重要。

在本章中,我们学习如何使用ping,FPing,Nmap,httpingarpingmtr测试连通性,映射网络,找到不良服务,测试网站性能,找到重复 IP 地址以及找到路由瓶颈。

诊断硬件

如果你发现自己被神秘的未标记以太网和电话线缠绕住了,那么请获取一台以太网/电话线缆测试和音频跟踪器。有很多款售价低于 100 美元。这些设备由两部分组成:一个发射器和一个接收器。两人合作使用会更快,一个在每条电缆的一端。当你找到电缆的两端时,请给它贴上标签并继续下一步。你也可以一个人完成,但两个人会更快。

万用表在很多工作中都很有用,比如找短路和断路、测试连通性和衰减、确定电线是否正确终端、测试电源插座以及测试计算机电源和主板。Adafruit是一个非常好的网站,提供关于使用万用表和学习电子学的优秀教程。

如果可能的话,保留一些备用零件。有时更换网络接口、电缆或交换机可以更快地找出有问题的硬件。

21.1 使用 ping 测试连通性

问题

你的网络上的某些服务或主机无法访问或出现间歇性故障。你想弄清楚这是否是硬件问题,名称服务问题,路由问题还是其他问题。

解决方案

当你调试网络问题时,从近处开始,系统地逐步从近到远解决。这指的是物理距离和需要经过的路由器数量。首先从本地 LAN 段开始。然后到下一个 LAN 段,如果有多个,则跨越一个路由器。然后到下一个距离两个路由器的地方,依此类推。

首先使用传统的ping测试连通性。首先 ping localhost

$ ping localhost
PING localhost (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.065 ms
64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.035 ms

通过按 Ctrl-C 停止ping。首先 ping localhost确认你的网络接口已经启动并正常运行。如果看到“connect: Network is unreachable”,那么你的网络接口有问题。备有一些备用的 USB 网络接口可以快速确认是否有损坏的接口。

一旦网络接口设置好,就 ping 你的主机名以测试名称解析,并告诉ping在三次 ping 后停止:

$ ping -c 3 *client4*
PING client4 (192.168.1.97) 56(84) bytes of data.
64 bytes from client4 (192.168.1.97): icmp_seq=1 ttl=64 time=0.087 ms
64 bytes from client4 (192.168.1.97): icmp_seq=2 ttl=64 time=0.059 ms
64 bytes from client4 (192.168.1.97): icmp_seq=3 ttl=64 time=0.061 ms

--- client4 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2046ms
rtt min/avg/max/mdev = 0.059/0.069/0.087/0.012 ms

如果返回正确的 IP 地址,则你的名称解析已正确设置。如果返回一个类似于 127.0.1.1 的本地主机地址或者“Name or service not known”,则你的 DNS 配置有问题。

当你的本地 DNS 修复后,通过主机名 ping 你的网络主机之一。如果ping失败并显示“Destination Host Unreachable”,尝试 ping 它的 IP 地址。如果成功了,请检查你的 DNS。如果仍然失败并显示相同的消息,则你的主机名和地址可能不正确,或者主机已关闭。

如果您无法到达任何外部 IP 地址,您的网络接口可能正常,问题可能出在上游:您的以太网电缆、无线接入点或交换机上。“网络不可达”意味着您的机器未连接到网络。

当你追踪间歇性中断的源头时,设置 ping 运行一段时间,比如 500 次 ping,间隔 2 秒,这样你就不会超载主机或网络,并将结果输出到文本文件中。下面的示例追加了额外的信息到文件中,以便你可以停止和重新开始:

$ ping -c 500 -i 2 *server2* >> server2-ping.txt

或者,使用 tee 命令查看输出并将其记录到文件中:

$ ping -c 500 -i 2 *server2* | tee server2-ping.txt

在多宿主主机上,使用 ping -i 接口名称 来指定要使用的接口。

讨论

不要阻塞 echo-requestecho-replytime-exceededdestination-unreachable ping 消息。一些管理员在其防火墙上阻止所有 ping 消息,这是一个错误,因为许多网络功能至少需要这四种 ping 消息才能正常运行。

如果使用 -a(可听见)开关,则 ping 命令实际上会发出 ping,尽管您可能需要做一些设置才能使其工作。在早期,我们的 PC 机箱内置了电脑主板,直接连接到主板,自动加载了激活机箱扬声器的内核模块。你可能熟悉这个扬声器发出的低保真烦人的蜂鸣声,也许您甚至运行了一些黑客技术来让它播放音乐。

现在,在现代,桌面音箱大多数已经消失了,大多数笔记本电脑也不再有主板蜂鸣声了。但是大多数 PC 主板仍然支持它们,现代蜂鸣器是一个小东西(图 21-1)。你可能需要购买一个。

计算机主板的蜂鸣器。

图 21-1. 计算机主板的蜂鸣器

一旦安装了蜂鸣器,加载 pcspkr 内核模块,然后确认已加载:

$ sudo modprobe pcspkr
$ lsmod|grep pcspkr
pcspkr                 16384  0

现在试一试。切换到纯文本控制台使用 Ctrl-Alt-F2,或启动 X 终端,并使用 echo 命令播放 ASCII 响铃字符。所有示例都是同样的事情,ASCII 字符代码 7 的不同表示:

$ echo -e "\a"
$ tput bel
$ echo -e '\007'

或按下 Ctrl-G。

如果在图形终端中听不到任何声音,请检查其设置以启用声音。xfce4-terminalgnome-terminal 都会播放 ASCII 响铃。Konsole 支持使用您选择的声音文件进行通知,但不支持蜂鸣器。

参见

21.2 使用 fping 和 nmap 对您的网络进行分析

问题

您希望生成网络上所有主机和 IP 地址的列表,并探测 MAC 地址和开放端口。

解决方案

使用 fpingnmap 探测您的 LAN,并记录结果。

fping 按顺序对一个范围内的所有地址进行 ping。本示例对一个子网进行一次 ping,报告哪些主机是活动的,查询主机名的 DNS,并打印汇总:

$ fping -c1 -gAds 192.168.1.0/24 2>1 | egrep -v "ICMP|xmt" >> *fping.txt*
client1.net (192.168.1.15)     : [0], 84 bytes, 3.12 ms (3.12 avg, 0% loss)
server2.net (192.168.1.91)     : [0], 84 bytes, 5.34 ms (5.34 avg, 0% loss)
client4.net (192.168.1.97)     : [0], 84 bytes, 0.03 ms (0.03 avg, 0% loss)

     254 targets
       3 alive
     251 unreachable
       0 unknown addresses

     251 timeouts (waiting for response)

 0.03 ms (min round trip time)
 2.83 ms (avg round trip time)
 5.34 ms (max round trip time)
        3.575 sec (elapsed real time)

要查看未经过滤的输出,请省略 2>1 | egrep -v “ICMP|xmt” 部分。任何离线的机器都不会被找到,所以你可以在不同时间运行这个命令来尝试捕获所有内容。>> fping.txt 将每次运行的新结果追加到文件中。

这个 nmap 示例执行了类似的任务,输出较少:

$ sudo nmap -sn 192.168.1.0/24 > *nmap.txt*
Starting Nmap 7.70 ( https://nmap.org ) at 2021-03-31 18:30 PDT
Nmap scan report for client1.net (192.168.1.15)
Host is up (0.0052s latency).
MAC Address: 44:A5:6E:D7:8F:B9 (Unknown)
Nmap scan report for BRW7440BBC7CA75.net (192.168.1.39)
Host is up (1.0s latency).
MAC Address: 74:40:BB:C7:CA:75 (Unknown)
Nmap scan report for client4.net (192.168.1.97)
Host is up (0.47s latency).
MAC Address: 9C:EF:D5:FE:8F:20 (Panda Wireless)
Nmap scan report for server2.net (192.168.1.91)
Host is up.
Nmap done: 256 IP addresses (6 hosts up) scanned in 15.19 seconds

这是一个相当难消化的块,所以在每个主机之前插入一个换行符,并将输出存储在一个新文件中:

$ awk '/Nmap/{print ""}1' *nmap.txt* > *nmap2.txt*

现在你有了良好的分组:

Nmap scan report for client1.net (192.168.1.15)
Host is up (0.0052s latency).
MAC Address: 44:A5:6E:D7:8F:B9 (Unknown)

Nmap scan report for BRW7440BBC7CA75.net (192.168.1.39)
Host is up (1.0s latency).
MAC Address: 74:40:BB:C7:CA:75 (Unknown)

Nmap scan report for client4.net (192.168.1.97)
Host is up (0.47s latency).
MAC Address: 9C:EF:D5:FE:8F:20 (Panda Wireless)

Nmap scan report for server2.net (192.168.1.91)
Host is up.

Nmap done: 256 IP addresses (6 hosts up) scanned in 15.19 seconds

探测你网络中主机的开放端口:

$ sudo nmap -sS  *192.168.1.**
Starting Nmap 7.70 ( https://nmap.org ) at 2021-03-31 19:36 PDT
Nmap scan report for client2.net (192.168.1.15)
Host is up (0.027s latency).
Not shown: 997 closed ports
PORT     STATE    SERVICE
53/tcp   open     domain
80/tcp   open     http
MAC Address: 44:A5:6E:D7:8F:B9 (Unknown)

Nmap scan report for 192.168.1.39
Host is up (0.074s latency).
Not shown: 994 closed ports
PORT     STATE SERVICE
25/tcp   open  smtp
80/tcp   open  http
443/tcp  open  https
515/tcp  open  printer
631/tcp  open  ipp
9100/tcp open  jetdirect
MAC Address: 74:40:BB:C7:CA:75 (Unknown)
[...]

client2.net 正在运行 DNS 和 Web 服务器。你可以从防火墙外运行相同的探测,看它们在你的网络之外是否可见。

第二项条目很有趣,因为它是一个运行多个服务的网络打印机。打印机文档说它们都有各自的目的。打印机支持通过 Web 控制面板进行远程管理,因此如果需要,它们可以被禁用。

收集主机及其 IP 地址的列表:

$ nmap -sn 192.168.43.0/24 | grep 'Nmap scan report for' |cut -d' ' -f5,6
server2 (192.168.43.15)
dns-server (192.168.43.74)
client4 (192.168.43.14)

讨论

nmap 具有多种选项用于探测网络。未经允许不要探测其他人的网络,因为这可能被视为一种敌对行为,探测漏洞。

运行端口扫描需要一些时间,但定期执行此操作以查看网络上正在发生的情况是一个好主意。运行只有必要服务并禁用所有其他服务是基本的安全措施。

参见

21.3 使用 arping 查找重复的 IP 地址

问题

你想搜索你的网络中重复的 IP 地址。

解决方案

这个例子搜索你的网络中的 192.168.1.91 并发送四个 ping:

$ sudo arping -I wlan2 -c 4 192.168.1.91
ARPING 192.168.1.91
42 bytes from 9c:ef:d5:fe:01:7c (192.168.1.91): index=0 time=49.463 msec
42 bytes from 9c:ef:d5:fe:01:7c (192.168.1.91): index=1 time=458.306 msec
42 bytes from 9c:ef:d5:fe:01:7c (192.168.1.91): index=2 time=73.938 msec
42 bytes from 9c:ef:d5:fe:01:7c (192.168.1.91): index=3 time=504.482 msec

--- 192.168.1.91 statistics ---
4 packets transmitted, 4 packets received,   0% unanswered (0 extra)
rtt min/avg/max/std-dev = 49.463/271.547/504.482/210.659 ms

所有的 MAC 地址都相同,因此它没有找到重复的。这是 arping 找到重复 IP 地址的一个例子:

$ sudo arping -I wlan2 -c 4 192.168.1.91
ARPING 192.168.1.91
42 bytes from 9c:ef:d5:fe:01:7c (192.168.1.91): index=0 time=49.463 msec
42 bytes from 2F:EF:D5:FE:8F:20 (192.168.1.91): index=1 time=458.306 msec
42 bytes from 9c:ef:d5:fe:01:7c (192.168.1.91): index=2 time=73.938 msec
42 bytes from 2F:EF:D5:FE:8F:20 (192.168.1.91): index=3 time=504.482 msec
[...]

--- 192.168.1.91 statistics ---
4 packets transmitted, 4 packets received,   0% unanswered (0 extra)
rtt min/avg/max/std-dev = 49.463/271.547/504.482/210.659 ms

使用 nmap 来识别具有相同 IP 地址的两台机器:

$ nmap -sn *192.168.43.0/24* | grep 'Nmap scan report for' |cut -d' ' -f5,6

讨论

arp 是地址解析协议,将 IP 地址匹配到 MAC 地址。

使用 DHCP 动态分配 IP 地址的优势在于,比手动设置静态 IP 地址少了创建重复的风险。你可以使用 DHCP 分配静态地址;参见 第十六章。

arping 用于在 ping 找不到主机时查看主机是否在线。有些人喜欢阻止 ping,这是不好的,因为它对网络功能至关重要。arping 无法阻止而不禁用网络主机之间的通信能力。arp,地址解析协议,维护一个 MAC 地址表。当网络主机向另一个主机发送数据包时,arp 将 IP 地址与 MAC 地址匹配,然后可以传递数据包。

你可以通过像 tcpdump 这样的数据包嗅探器看到 arp 探测你的网络以更新其地址表时的情况。

$ sudo tcpdump -pi eth1 arp
listening on eth1, link-type EN1000MB (Ethernet), capture size 262144 bytes
21:19:36.921293 ARP, Request who-has client4.net tell m1login.net, length 28
21:19:36.921309 ARP, Reply client4.net is-at 9c:ef:d5:fe:8f:20

参见

  • 第十六章

  • man 8 arping

21.4 使用 httping 测试 HTTP 吞吐量和延迟

问题

您想测试您托管的网站是否能在合理的时间内加载。

解决方案

httping 测量 HTTP 服务器的吞吐量和延迟。它最简单的调用测试延迟:

$ httping -c4 -l -g www.oreilly.com
PING www.oreilly.com:443 (/):
connected to 184.86.29.153:443 (453 bytes), seq=0 time=292.25 ms
connected to 184.86.29.153:443 (453 bytes), seq=1 time=726.35 ms
connected to 184.86.29.153:443 (452 bytes), seq=2 time=629.11 ms
connected to 184.86.29.153:443 (453 bytes), seq=3 time=529.95 ms
--- https://www.oreilly.com/ ping statistics ---
4 connects, 4 ok, 0.00% failed, time 6179ms
round-trip min/avg/max = 292.2/544.4/726.3 ms

这并不告诉您页面加载时间,只告诉您服务器响应头部的时间(以毫秒计),而不包含内容。GET(-G)请求会获取整个页面:

$ httping -c4 -l -Gg www.oreilly.com
PING www.oreilly.com:443 (/):
connected to 104.112.183.230:443 (453 bytes), seq=0 time=2125.72 ms
connected to 104.112.183.230:443 (453 bytes), seq=1 time=701.94 ms
connected to 104.112.183.230:443 (453 bytes), seq=2 time=470.66 ms
connected to 104.112.183.230:443 (453 bytes), seq=3 time=433.11 ms
--- https://www.oreilly.com/ ping statistics ---
4 connects, 4 ok, 0.00% failed, time 7733ms
round-trip min/avg/max = 433.1/932.9/2125.7 ms

添加 -r 开关以最小化 DNS 延迟,仅解析一次主机名:

$ httping -c4 -l -rGg www.oreilly.com
PING www.oreilly.com:443 (/):
connected to 23.10.2.218:443 (452 bytes), seq=0 time=961.29 ms
connected to 23.10.2.218:443 (452 bytes), seq=1 time=1091.16 ms
connected to 23.10.2.218:443 (452 bytes), seq=2 time=925.46 ms
connected to 23.10.2.218:443 (452 bytes), seq=3 time=913.26 ms
--- https://www.oreilly.com/ ping statistics ---
4 connects, 4 ok, 0.00% failed, time 7894ms
round-trip min/avg/max = 913.3/972.8/1091.2 ms

如果最小化 DNS 延迟有很大的差异,则需要查看您的域名服务器。

通过将其附加到 URL 来测试备用端口,例如 8080:

$ httping -c4 -l -rGg www.oreilly.com:8080

使用 -s 开关显示返回码,例如 200 OK,表示成功加载页面:

$ httping -c4 -l -srGg www.oreilly.com
PING www.oreilly.com:443 (/):
connected to 23.10.2.218:443 (452 bytes), seq=0 time=920.88 ms 200 OK
connected to 23.10.2.218:443 (452 bytes), seq=1 time=857.60 ms 200 OK
connected to 23.10.2.218:443 (452 bytes), seq=2 time=1246.69 ms 200 OK
connected to 23.10.2.218:443 (452 bytes), seq=3 time=1134.91 ms 200 OK
--- https://www.oreilly.com/ ping statistics ---
4 connects, 4 ok, 0.00% failed, time 8249ms
round-trip min/avg/max = 857.6/1040.0/1246.7 ms

讨论

在不同时间运行多次测试,收集具有代表性的用户体验数据。

httping 不是一个深入分析您站点瓶颈的超级复杂的测试工具。它是一个快速简单的工具,可帮助您了解整体站点性能,并告诉您是否需要深入诊断性能问题。

参见

21.5 使用 mtr 查找有问题的路由器

问题

有一个您正在尝试访问的站点,但它非常缓慢或无法访问。

解决方案

使用 mtr(My Traceroute)查看数据包走错的位置。这在您控制的网络上效果更好,因为互联网辽阔,路由会发生变化,但当您无法访问站点时,它将提供有用信息。

让我们看看漫游的路径如何带我们到 carlaschroder.com

$ mtr -wo LSRABW carlaschroder.com
Start: 2021-03-31T09:54:17-0700
HOST: client4                               Loss%   Snt   Rcv   Avg  Best  Wrst
  1.|-- m1login.net                            0.0%    10    10  55.5   1.2 199.6
  2.|-- 172.26.96.169                          0.0%    10    10  92.3  29.0 243.6
  3.|-- 172.18.84.60                           0.0%    10    10  84.5  29.3 220.3
  4.|-- 12.249.2.25                            0.0%    10    10  80.7  36.4 215.5
  5.|-- 12.122.146.97                          0.0%    10    10  65.6  34.8 156.6
  6.|-- 12.122.111.33                          0.0%    10    10  49.3  35.5  97.6
  7.|-- cr2.st6wa.ip.att.net                   0.0%    10    10  46.7  35.9  64.0
  8.|-- 12.122.111.109                         0.0%    10    10  57.9  31.4 215.4
  9.|-- 12.122.111.81                          0.0%    10    10  72.3  27.6 231.4
 10.|-- 12.249.133.242                         0.0%    10    10 101.2  31.7 263.1
 11.|-- ae6.cbs01.wb01.sea02.networklayer.com  0.0%    10    10  93.7  31.6 202.7
 12.|-- fc.11.6132.ip4.static.sl-reverse.com   0.0%    10    10 106.0  86.1 171.2
 13.|-- ae1.cbs02.eq01.dal03.networklayer.com 60.0%    10     4 102.0  86.5 115.8
 14.|-- ae0.dar01.dal13.networklayer.com       0.0%    10    10 103.7  80.3 230.8
 15.|-- 85.76.30a9.ip4.static.sl-reverse.com   0.0%    10    10 114.8  82.8 305.7
 16.|-- a1.76.30a9.ip4.static.sl-reverse.com   0.0%    10    10 122.7  83.7 278.4
 17.|-- hs17.name.tools                        0.0%    10    10 145.9  74.9 277.2

m1login.net 是我的网络的互联网网关路由器。之后就是广阔的互联网世界。第 13 跳可能是一个瓶颈,丢包率为 60%。第 13 跳可能是负载均衡集群的一部分;注意第 11 跳和第 14 跳具有相同的域名。如果它是集群的一部分,那么丢包并不重要。

Ping 最后一跳,hs17.name.tools。以下示例看起来一切正常:

$ ping -c 3 hs17.name.tools
PING hs17.name.tools (169.61.1.230) 56(84) bytes of data.
64 bytes from hs17.name.tools (169.61.1.230): icmp_seq=1 ttl=46 time=319 ms
64 bytes from hs17.name.tools (169.61.1.230): icmp_seq=2 ttl=46 time=168 ms
64 bytes from hs17.name.tools (169.61.1.230): icmp_seq=3 ttl=46 time=166 ms
[...]

如果 mtr 显示问题,请使用 whois 查询域名所有者及其联系信息:

$ whois -H networklayer.com

whois 也适用于 IP 地址。-H 开关可以禁用烦人的法律术语。

在每个条目末尾附上日期和时间,将 mtr 输出保存到文件中:

$ mtr -r -c25 oreilly.com >> mtr.txt && date >> mtr.txt

通过创建一个 cron 作业(Recipe 3.7)每小时运行前述的 mtr 并让其运行一天或两天来随时间收集数据。别忘了关闭它。

讨论

mtr -wo LSRABW 限制列数,以便示例更好地适应本页。mtr -w 是报告的宽格式。

如果需要报告问题,请保存您的记录;whois 示例显示如何找到联系人。

mtr 生成大量流量,因此请小心不要频繁运行它。

参见

  • man 8 mtr

附录:软件管理备忘单

Linux 上的软件以 软件包 形式存在。这些软件包包含属于特定应用程序的所有文件,如网页浏览器、文字处理器和游戏。Linux 系统使用共享库,这些库被多个应用程序共享使用。大多数 Linux 上的软件包都不是自包含的,而是依赖于共享文件。

大多数 Linux 发行版上的图形软件管理器是 GNOME-软件,也称为 Software(见图 A-1)。软件组织良好,具有分类和良好的搜索功能。

GNOME-软件

图 A-1. GNOME-软件

软件包管理命令

每个 Linux 发行版都使用三种类型的软件管理命令:

  • 软件包管理器,仅管理单个软件包。Fedora 和 openSUSE 使用 rpm 软件包管理器,Ubuntu 使用 dpkg

  • 一个解决依赖关系的软件包管理器。Fedora 使用 dnf,openSUSE 使用 zypper,Ubuntu 使用 apt。依赖解决的软件包管理器会自动解析特定软件包的所有依赖关系。例如,gedit 文本编辑器有一长串依赖项,如 apt 的这个例子所示:

    $  apt depends gedit
    gedit
      Depends: gedit-common (<< 3.37)
      Depends: gedit-common (>= 3.36)
      Depends: gir1.2-glib-2.0
      Depends: gir1.2-gtk-3.0 (>= 3.21.3)
      Depends: gir1.2-gtksource-4
      Depends: gir1.2-pango-1.0
      Depends: gir1.2-peas-1.0
      Depends: gsettings-desktop-schemas
      Depends: iso-codes
    [...]
    

    手动管理依赖关系很困难;解决依赖关系的软件包管理器大大简化了 Linux 用户的生活。

  • 用于管理相关软件包组的命令,例如图形桌面、音频和视频,或服务器堆栈。openSUSE 称其为 patterns。Fedora 称其为软件包组。Ubuntu 称其为 tasks。以下示例显示了一些 openSUSE 的 patterns:

$ zypper search --type pattern
S  | Name                 | Summary                        | Type
---+----------------------+--------------------------------+--
[...]
   | mail_server          | Mail and News Server           | pattern
   | mate                 | MATE Desktop Environment       | pattern
i+ | multimedia           | Multimedia                     | pattern
   | network_admin        | Network Administration         | pattern
   | non_oss              | Misc. Proprietary Packages     | pattern
   | office               | Office Software                | pattern
   | print_server         | Print Server                   | pattern
[...]

软件包是从 仓库 分发的,这些是公共服务器,我们从中下载软件包。您可以在线浏览它们:

每个 Linux 发行版都有官方仓库,还有一整个世界的第三方仓库。本附录介绍了在 Linux 系统上管理软件和仓库的基本命令。

在 Ubuntu 上管理软件

在本书中,Ubuntu Linux 代表了整个基于 Debian 的发行版系列。Debian 最早,然后出现了数百个衍生版。主要的 Debian 衍生版使用相同的软件包管理系统,本附录中的命令应在所有这些系统上同样有效。

本附录中的三个软件管理命令是 dpkgapttasksel

使用 add-apt 安装和删除仓库

添加软件仓库时,您需要知道您的 Ubuntu 版本的代号。使用以下命令获取它:

$ lsb_release -sc
*focal*

您需要仓库的确切 URL,这应由仓库维护者提供:

$ sudo add-apt-repository *"deb http://us.archive.ubuntu.com/ubuntu/ focal \
universe multiverse"*

删除仓库:

$ sudo add-apt-repository -r *"deb http://us.archive.ubuntu.com/ubuntu/ focal \
universe multiverse"*

当您安装或删除仓库时,请更新您的软件包缓存:

$ sudo apt update

定期运行此命令以下载仓库更新,然后安装更新:

$ sudo apt upgrade

使用 dpkg 安装、删除和检查软件包

从“软件包管理命令”中记得 dpkg 只能操作单个软件包,不能解决依赖关系。

安装一个软件包:

$ sudo dpkg -i *packagename*

移除一个软件包(不移除配置文件):

$ sudo dpkg -r *packagename*

移除一个软件包及其配置文件:

$ sudo dpkg --purge *packagename*

列出软件包的内容:

$ dpkg -L *packagename*

列出所有已安装的软件包:

$ dpkg-query --listdpkg

使用 apt 搜索、查看、安装和移除软件包

apt 是一个解决依赖关系的软件包管理器,是你日常的软件管理命令。

搜索软件包:

$ apt search *packagename*

限制搜索结果只包含指定搜索词的软件包名称:

$ apt search *packagename* --names-only

获取软件包的详细信息:

$ apt show *packagename*

安装一个软件包:

$ sudo apt install *packagename*

移除一个软件包(不移除配置文件):

$ sudo apt remove *packagename*

移除一个软件包及其配置文件:

$ sudo apt remove purge *packagename*

使用 tasksel

tasksel 管理 任务,这些是软件包组。

列出可用的任务:

$ tasksel --list-tasks

安装一个任务:

$ sudo tasksel install *task*

移除一个任务:

$ sudo tasksel remove *task*

在 Fedora 上管理软件

在本书中,Fedora Linux 代表基于 Red Hat Linux 的一系列发行版。Red Hat、CentOS、Scientific Linux、Oracle Linux 等都使用相同的软件包管理系统,这些命令应该在所有这些系统上都可以使用。

本章中的两个软件管理命令是 rpmdnf

使用 dnf 管理软件源

列出所有已安装的软件源,包括已启用和已禁用的:

$ dnf repolist --all

列出已启用的软件源:

$ dnf repolist --enabled

显示已启用的软件源的详细信息:

$ dnf repolist --enabled

添加一个软件源:

$ sudo dnf config-manager --add-repo */etc/yum.repos.d/fedora_extras.repo*

启用软件源:

$ sudo dnf config-manager --set-enabled *fedora-extras*

禁用软件源:

$ sudo dnf config-manager --set-disabled *fedora-extras*

使用 dnf 管理软件

搜索软件包:

$ dnf search *packagename*

安装一个软件包:

$ sudo dnf install *packagename*

移除一个软件包:

$ sudo dnf remove *packagename*

获取软件包的信息:

$ dnf info *packagename*

安装更新:

$ sudo dnf upgrade

获取软件包组的列表:

$ dnf grouplist

安装一个软件包组:

$ sudo dnf groupinstall *"package-group"*

移除一个软件包组:

$ sudo dnf groupremove *"package-group"*

使用 rpm 安装和移除软件包

安装一个软件包:

$ sudo rpm -i *package*

升级一个软件包:

$ sudo rpm -U *package*

移除一个软件包:

$ sudo rpm -e *package*

使用 rpm 获取关于软件包的信息

列出已安装的 rpm 中的所有文件:

$ rpm -ql *package*

获取已安装软件包的完整信息:

$ rpm -qi *package*

查看软件包的变更日志:

$ rpm -q --changes *package*

在 openSUSE 上管理软件

openSUSE 使用 RPM 软件包格式,类似于 Fedora,但有不同的依赖关系解决软件包管理器 zypper

使用 zypper 管理软件源

列出所有已安装的软件源:

$ zypper repos

列出已安装的软件源并显示它们的 URL:

$ zypper repos -d

启用一个软件源:

$ sudo zypper modifyrepo -e *repo*

禁用一个软件源:

$ sudo zypper modifyrepo -d *repo*

添加一个新的软件源:

$ sudo zypper adderepo -name "*MyNewRepoName" \
http://download.opensuse.org/distribution/leap/15.3/repo/oss/*

移除一个软件源:

$ sudo zypper removerepo *MyNewRepoName*

下载软件源更新:

$ sudo zypper refresh

使用 zypper 管理软件

更新系统(首先运行 sudo zypper refresh):

$ sudo zypper update

搜索软件包(不精确搜索):

$ zypper search *packagename*

搜索软件包(精确搜索):

$ zypper search -x *packagename*

安装一个软件包:

$ sudo zypper install *packagename*

移除一个软件包:

$ sudo zypper remove *packagename*

列出所有软件模式:

$ sudo zypper -t patterns

安装一个模式:

$ sudo zypper -t pattern *pattern-name*
posted @ 2025-11-16 08:59  绝不原创的飞龙  阅读(3)  评论(0)    收藏  举报