精通 Ubuntu 服务器(一)
原文:
annas-archive.org/md5/118307b747c51933266231837979f8d8译者:飞龙
前言
Linux 是一个令人兴奋的平台。你几乎可以在任何地方找到它——桌面、笔记本、手机、嵌入式设备,尤其是服务器。Linux 服务器为全球许多著名的技术提供动力,并且在物理和云服务器环境中具有庞大的存在。Linux 服务器具有可扩展性、稳定性和强大功能。
早在 1991 年,芬兰一位名为 Linus Torvalds 的计算机科学学生将 Linux 内核作为学校项目创建了。那个时候他并不知道,Linux 将帮助我们见证一些基础设施设计领域最激动人心的创新。诸如多核处理器、虚拟化、容器化和云计算(仅举几例)等技术,已经改变了全球的数据中心,而 Linux 一直是这些进步的一部分。
Ubuntu 是一个流行的 Linux 发行版,一直是 Linux 被广泛采用的重要推动力。自 2004 年首次发布以来,Ubuntu 使得 Linux 更加易于新手使用,同时为服务器管理员提供了强大的功能。Ubuntu 不仅可以在笔记本电脑和工作站上找到,还可以在服务器上运行。
Ubuntu Server 使管理员能够创建高效、灵活且高度可用的服务器,为组织提供开源的强大力量。作为 Ubuntu 管理员,我们身处良好的环境——根据 W3Techs 的数据,Ubuntu 是 Linux 系统中在网络上最广泛部署的发行版。随着 Ubuntu 22.04 的发布,这一平台变得更加令人兴奋!
在本书中,我们将深入探讨 Ubuntu Server,你将学习所有管理服务器所需的概念,并配置它们以执行各种有趣的任务,例如提供网页服务、管理虚拟机、运行容器、自动化配置、与其他用户共享文件,甚至在云中运行 Ubuntu。
我们将从第一章开始我们的旅程,在这一章中,我们将走过安装 Ubuntu Server 22.04 的过程,它将作为本书其余部分的基础。在接下来的旅程中,我们将学习如何管理用户、连接网络和控制进程。随后,我们将实现一些重要的技术,如 DHCP、DNS、Apache、MariaDB 等。我们甚至会在过程中设置自己的 Nextcloud 服务器。
最后,本书的结尾部分将讨论我们可以做些什么来排除故障,以及如何防止和从灾难中恢复。
本书适合谁阅读
本书适合具备中级或高级初学者 Linux 技能的读者,帮助他们了解如何使用 Ubuntu Server 设置服务器。本书假设读者已经掌握 Linux 的基础知识,例如编辑配置文件和运行基本命令。此外,本书假设读者具备基础的网络概念理解,如 DHCP、DNS、IP 地址等。并且假设读者理解基本网络硬件的用途,如路由器、交换机以及类似设备。
本书涵盖的内容
第一章,部署 Ubuntu 服务器,介绍了 Ubuntu 服务器的安装过程。本章将带你完成创建启动介质和安装过程。
第二章,管理用户和权限,全面介绍了用户管理。本章内容包括创建和删除用户、配置密码策略、使用sudo命令、进行组管理以及在用户之间切换。
第三章,管理软件包,引导读者完成搜索、安装和管理软件包的过程。内容包括管理 APT 仓库、安装软件包,甚至包括 Snap 软件包的介绍。
第四章,导航和基本命令,教授了在目录树中导航、查看日志文件内容以及浏览日志文件所需的基本命令。
第五章,管理文件和目录,在前一章的基础上扩展了知识,并通过讲解如何编辑、复制、移动和重命名文件,完善了你的必备命令工具集。
第六章,提升命令行效率,介绍了一些额外的技巧、窍门和方法,以增强读者在使用命令行时的效率。内容包括管理输出、查看 Bash 历史记录等。
第七章,控制和管理进程,教你如何管理服务器上正在运行的程序,并且如何停止不正常的进程。内容包括查看 htop、使用 systemd 以及管理作业。
第八章,监控系统资源,介绍了如何管理服务器上的重要系统资源,例如查看磁盘和内存使用情况、理解负载平均值以及它如何影响 CPU。
第九章,管理存储卷,介绍了存储卷的相关内容。你将学习如何查看磁盘使用情况、格式化卷、管理/etc/fstab文件、使用 LVM 等。此外,我们还将讨论如何管理交换空间(swap)。
第十章,连接到网络,探讨了 Ubuntu 中的网络配置,特别是如何连接到其他节点的资源。我们将讨论如何分配 IP 地址、通过 OpenSSH 连接其他节点以及名称解析。
第十一章,设置网络服务,重新探讨了更高级的网络概念。在本章中,读者将学习更多关于将我们的网络连接在一起的技术,如 DHCP 和 DNS。读者将设置自己的 DHCP 和 DNS 服务器,并安装 NTP。
第十二章,共享与传输文件,专注于如何与他人共享文件。内容包括 Samba 和 NFS 网络共享的设置,我们还将介绍如何使用rsync和scp手动传输文件。
第十三章,管理数据库,带领读者完成通过 MariaDB 设置和管理数据库的过程。读者将学习如何安装 MariaDB、如何设置数据库以及如何创建辅助数据库服务器。
第十四章,提供 Web 内容,介绍了如何使用 Apache 提供内容。此外,读者还将学习如何使用 SSL 证书来保护 Apache,如何管理模块,甚至在章节结束时搭建一个 Nextcloud 服务器。
第十五章,使用 Ansible 自动化服务器配置,将向读者展示如何设置一个用于存储配置管理脚本的 Git 仓库,如何使用强大的 Ansible 工具来自动化常见的管理任务,并且还会介绍如何使用ansible-pull。
第十六章,虚拟化,讲解了虚拟化的所有内容(不出所料!)。读者将学习如何设置自己的 KVM 安装,以及如何使用 virt-manager 管理虚拟机。
第十七章,运行容器,讨论了容器的相关内容,并展示了如何在 Docker 和 LXD 中管理容器。
第十八章,容器编排,教你如何将容器提升到一个新的水平,并通过 Kubernetes 的强大功能进行管理。你不仅会学到如何安装 Micro K8s,还会学会如何从零开始构建自己的 Kubernetes 集群。
第十九章,在云中部署 Ubuntu,展示了如何在云中启动 Ubuntu 服务器,并介绍了亚马逊网络服务(AWS)。
第二十章,使用 Terraform 自动化云部署,讲解了如何通过 Terraform 自动化构建云基础设施的过程。
第二十一章,保护服务器安全,介绍了读者可以采取的各种措施来加强 Ubuntu 服务器的安全性。话题包括减少攻击面、保护 OpenSSH、设置防火墙等内容。
第二十二章,故障排除 Ubuntu 服务器,包含了当我们的部署没有按照计划进行时,可以采取的措施。读者还将研究问题空间、查看系统日志并追踪网络问题。
第二十三章,防范灾难,向读者介绍了可以用于预防和恢复灾难的各种策略。这包括利用 Git 进行配置管理、实施备份计划等内容。
为了最大限度地利用本书
本书适合已经有一定 Linux 经验的读者,尽管不一定非要是 Ubuntu 的经验。理想情况下,读者应了解基本的 Linux 命令行技能,例如切换目录、列出内容以及以普通用户或 root 用户身份执行命令。还希望读者了解基础的网络概念,如 DHCP、DNS 的作用以及 IP 地址分配。即使您觉得自己需要复习,仍然应该阅读本书——开头几章会涵盖许多这些概念。
本书将带您了解我们可以部署 Ubuntu Server 的实际场景。这将包括安装过程、提供网页服务、设置数据库等内容。具体而言,目标是提高生产力。每一章都会教会读者一个新的、有价值的概念,使用与实际组织相关的实用示例。基本上,我们专注于完成任务,而不是仅仅专注于理论。尽管 Linux 及其许多发行版的理论非常有趣,但本书的目标是让您处于这样一个位置:当同事或客户要求您在基于 Ubuntu 的服务器上执行工作时,您能够顺利完成任务。因此,如果您的目标是快速上手 Ubuntu Server 并学习真正重要的概念,那么本书绝对适合您。
若要跟随本书的教程,您需要一台安装了 Ubuntu Server 的服务器、一台来自云服务提供商的虚拟 Ubuntu 实例,或者一台至少能够运行一个虚拟机的笔记本或台式机。
下载示例代码文件
本书的代码包托管在 GitHub 上,链接为 github.com/PacktPublishing/Mastering-Ubuntu-Server-Fourth-Edition
我们还有其他来自我们丰富书籍和视频目录的代码包,您可以在 github.com/PacktPublishing/ 查看。赶快去看看吧!
下载彩色图片
我们还提供了一个 PDF 文件,包含本书中使用的屏幕截图/图表的彩色图片。您可以在这里下载:static.packt-cdn.com/downloads/9781803234243_ColorImages.pdf
使用的约定
本书中使用了若干文本约定。
CodeInText:表示文本中的代码字词、数据库表名、文件夹名称、文件名、文件扩展名、路径名、虚拟 URL、用户输入以及 Twitter 用户名。以下是一个例子:“总之,回到我们的/etc/passwd文件。第五列用于用户信息,最常见的是用户的名字和姓氏。”
一段代码的设置如下:
description: External access profile
devices:
eth0:
name: eth0
nictype: bridged
parent: br0
type: nic
当我们希望特别强调代码块中的某一部分时,相关的行或项目会被高亮显示:
- name: Start the apache2 services
ansible.builtin.service:
name: apache2
state: started
**enabled: true**
任何命令行输入或输出都如下所示:
sudo apt install docker.io
粗体:表示新术语、重要词汇或屏幕上出现的词语。例如,在菜单或对话框中出现的词汇会以这种方式显示在文本中。例如:“从管理面板中选择系统信息。”
警告或重要说明如下所示。
提示和技巧如下所示。
联系我们
我们始终欢迎读者的反馈。
一般反馈:请发送电子邮件至feedback@packtpub.com,并在邮件主题中注明书名。如果您对本书的任何内容有疑问,请通过questions@packtpub.com与我们联系。
勘误:尽管我们已尽一切努力确保内容的准确性,但难免会有错误。如果您发现本书中有错误,欢迎向我们报告。请访问www.packtpub.com/submit-errata,点击提交勘误并填写表格。
盗版:如果您在互联网上发现任何非法的作品复制品,我们将非常感谢您提供相关的网址或网站名称。请通过copyright@packtpub.com联系并提供链接。
如果您有兴趣成为作者:如果您在某个领域拥有专业知识,并且有兴趣写书或参与书籍的创作,请访问authors.packtpub.com。
分享您的想法
阅读完*《Mastering Ubuntu Server, 第四版》*后,我们希望听听您的想法!请点击这里直接访问亚马逊评论页面并分享您的反馈。
您的评价对我们和技术社区都非常重要,它将帮助我们确保提供优质的内容。
第一章:1
部署 Ubuntu Server
Ubuntu Server 是一款功能极其强大的 Linux 发行版,专为服务器和网络设备设计。无论你是在设置高端数据库还是小型办公室文件服务器,Ubuntu Server 的灵活性都能够满足并超越你的需求。在本书中,我们将介绍所有常见的使用案例,帮助你最大限度地发挥这个令人兴奋的平台的优势。Ubuntu Server 结合了现代开发框架和稳定性,硬件支持使得它可以安装在最新的服务器硬件上。
在本章中,我将引导你完成从头到尾部署 Ubuntu Server 的过程。我们将从一些最佳实践的讨论开始,然后我们将获取软件并创建我们的安装介质。接下来,我将为你提供一个逐步的安装过程。到本章结束时,你将拥有一个属于你自己的 Ubuntu Server 安装,可以在本书的其余部分中使用。此外,由于 Canonical(Ubuntu 的开发者)现在为 Raspberry Pi 提供官方支持,我们也将探讨如何设置 Raspberry Pi。
本章中,我们将涵盖:
-
技术要求
-
确定服务器的角色
-
选择服务器设备
-
获取安装介质
-
创建可启动的闪存驱动器
-
安装 Ubuntu Server
-
在 Raspberry Pi 上安装 Ubuntu Server
为了开始,我们将首先查看一些部署 Ubuntu 服务器的技术要求。
技术要求
为了跟随本书中的示例,你需要安装一个 Ubuntu Server 进行操作。一般来说,以下规格是成功安装 Ubuntu Server 的估计最低要求:
-
64 位 CPU
-
1 GB RAM
-
10 GB 硬盘(推荐 16 GB 或更多)
64 位 CPU 支持现在成为一个要求,唯一的例外是 Raspberry Pi 版本。这是因为 Canonical 不再为 32 位 PC 和服务器处理器提供 Ubuntu 版本。虽然这看起来像是一个缺点,但如今所有售出的计算机都支持 64 位操作系统,并且自 2003 年起,消费级 CPU 就已经具备 64 位能力。即使你有一台旧 PC,觉得它可能无法运行 64 位操作系统,实际上你会惊讶地发现,甚至是较旧的 Pentium IV(尽管已经很老)也支持这一点,所以这个要求应该不难满足。现在不用担心这些细节,我们将在本章后面详细讨论这些要求。
现在我们了解了 Ubuntu Server 的技术要求,接下来让我们考虑一下我们的服务器将在组织中扮演什么角色。
确定服务器的角色
你很兴奋要设置一个 Ubuntu Server 安装,这样你可以按照本书中的示例进行操作。同样重要的是了解在现实世界中如何执行典型的服务器推出。每台服务器都必须有一个目的或角色。这个角色可以是数据库服务器、Web 服务器、文件服务器等等。简而言之,角色是服务器为你或你的组织增加的价值。有时,服务器可能仅用于测试实验性代码的目的。这也很重要——拥有测试环境是一个非常常见(也是值得的)做法。
一旦你了解了服务器在组织中的角色,你可以为其实施计划。这个系统是关键任务吗?如果由于某种原因这个服务器出现故障,它将如何影响你的组织?根据这个问题的答案,你可能只需为这个任务设置一个服务器,或者你可能希望计划冗余,以使服务器不成为故障的中心点。一个例子是 DNS 服务器,它会影响同事解析本地主机名和访问所需资源的能力。在某些情况下,添加第二个 DNS 服务器以在主服务器出现故障时接管可能是合理的。
另一个需要考虑的项目是服务器上驻留数据的机密性对你的环境有多重要。这直接关系到我们即将执行的安装过程,因为你将被询问是否想要使用加密。Ubuntu Server 在安装过程中提供的加密称为静态加密,它指的是存储在服务器内部存储卷中的数据。如果你的服务器注定要存储机密数据(会计信息、信用卡号码、员工或客户记录等),你可能要考虑利用这个选项。
加密你的硬盘是一个非常好的主意,可以防止那些有本地访问权限的坏人窃取数据。只要攻击者没有你的加密密钥,他们就无法窃取这些机密信息。然而,值得一提的是,任何有物理访问权限的人都可以轻松地销毁数据(无论是否加密),所以请记住保持服务器房间上锁!
在这本书的这一部分,我绝对不是要求你创建详细的实施图表或类似的东西,而是要记住在设置新服务器时应始终包含在对话中的一些概念。它需要有存在的理由,必须了解服务器数据的关键性和机密性,然后相应地设置服务器。一旦你练习了这些概念以及安装过程,你可以制定自己的服务器推出计划,以便在你的组织中使用。总而言之,理解基础设施中每个组件的目的是一种很好的思维方式。
到此为止,我们已经了解了如何为我们的服务器确定角色以及它如何融入我们的组织。在接下来的部分,我们将实际查看安装 Ubuntu Server 的过程,这样我们至少可以有一台测试机器用于书中的示例。
为我们的服务器选择设备
我敢打赌,你一定很兴奋想要设置自己安装的 Ubuntu Server,并深入探索。但在我们开始之前,我们必须决定到底要安装在哪个设备上。就本书的目的而言,硬件没有特别要求。你只需要一个 Ubuntu Server 安装版本,如果可以,设置多个服务器也是有益的——它们不必都是同一种设备类型。拥有多个服务器将帮助你在后续章节中进行网络实验。但现在,关键是利用你现有的设备来启动 Ubuntu 安装。
特别地,以下列表包括了你可以考虑用于安装 Ubuntu Server 的最常见设备:
-
物理服务器
-
物理桌面
-
笔记本电脑
-
虚拟机
-
虚拟私人服务器
-
树莓派
让我们更详细地看看这些选项。
物理服务器
现在,找到价格合理的二手物理服务器非常容易。戴尔 PowerEdge 是一种非常常见的型号,特别是 R610 和 R710 是很好的选择,二手市场上很容易找到。这些服务器通常在公司升级到更新型号后进入转售市场。虽然 R610 和 R710 已经有些年头,但它们的配置仍然适合测试用途。如果你能以合理的价格找到更新型号(如 R720),那就更好了。
物理服务器的缺点是它们占用大量空间,且往往消耗大量电力(并且噪音较大)。确保在不使用时关闭它们,并查看你所在地区的电力费用——这些服务器的运行成本可以非常低,也可以非常高,具体取决于你的电价。
物理桌面
如果你没有物理服务器,可以考虑在桌面上运行 Ubuntu Server。一些电脑用户在升级到新的设备后,往往会继续保留旧的 PC。因此,与其让你的旧桌面电脑积灰,不如让它发挥作用?当然,你的老旧电脑可能无法运行当今的高端游戏,但对于我们的目的来说这并不重要。Ubuntu Server 在老旧硬件上也能运行得非常好。实际上,很多家庭学习者都使用小型机箱 PC(如英特尔 NUC)来实现这一目的。此外,使用物理桌面也相较于物理服务器有一些优势。它们通常比服务器硬件消耗更少的电力,且噪音也较小。
在生产服务器(用于你组织内部的 Ubuntu Server 安装)方面,台式电脑通常并不是一个好的选择。根据不同的型号,实际的服务器硬件可能会具备一些台式电脑所没有的额外硬件和功能。例如,真正的服务器构建通常会配备硬件 RAID、错误更正码 (ECC) 内存、多处理器等功能。尽管台式电脑机箱通常缺少这些功能,但如果你在旧电脑上安装 Ubuntu Server,它仍然是一个有效的服务器,和实际的服务器机箱没有什么不同——尽管它在数据中心的扩展性较差。不过,由于我们现在只是学习,所以这些对我们当前的使用场景并不重要。
笔记本电脑
另一个值得考虑的选择是将 Ubuntu Server 安装在笔记本电脑上。如果你有一台不再使用的旧笔记本电脑,它可能是学习 Ubuntu Server 的一个很好的选择。如果你决定使用笔记本电脑来完成这个任务,那么与使用台式电脑时相同的因素也适用于此。
然而,我之所以决定在这里单独列出笔记本电脑,是因为它们具备一些额外的优势,值得我们利用。对于真实的数据中心服务器机架,你通常会接入键盘、视频和鼠标 (KVM) 。这可能意味着你可以将物理显示器、键盘和鼠标连接到服务器,或者使用集成这三者的特殊设备。数据中心内的服务器还会配备不间断电源 (UPS),即使断电,它们也能继续运行一段时间。
当谈到笔记本电脑时,它具备了相同的功能。笔记本电脑内置了键盘、鼠标和显示器。如果笔记本电脑中安装的电池正常工作,那么你也就有了不间断电源(UPS)。正因为这些原因,笔记本电脑可能在整体上相较于台式电脑具有一定的优势。
然而,就像台式电脑一样,笔记本电脑通常不适合在实际的数据中心使用。对于我们的使用场景而言,我们只需要安装一个或多个 Ubuntu Server 实例来完成本书中的示例任务。为了这个目的,专门使用任何你当前不使用的电脑就足够了。
虚拟机
如果你无法访问物理机器,可以考虑使用虚拟机 (VM)。如今大多数计算机都支持运行虚拟机的能力。VirtualBox 是一个很好的解决方案,它易于使用,并且可以在所有主要操作系统上使用。就像 Ubuntu 本身一样,VirtualBox 是免费的,因此通常是开始的最低成本选项。而且,VirtualBox 允许你轻松创建 Ubuntu 安装的快照,这样你可以在进行本书中的示例之前创建一个时间点备份,并在需要时恢复它,以便重复执行任务。仅仅是快照功能,就使得虚拟机对我们的需求尤其有吸引力。
使用 VirtualBox 的缺点是,您需要至少分配 1GB RAM 给您的 Ubuntu 服务器 VM,并且您的 CPU 需要支持虚拟化扩展,如果您的设备支持,则需要在计算机设置中启用它。
可以在这里下载 VirtualBox:www.virtualbox.org。
虚拟专用服务器
诸如 Amazon Web Services、Google Cloud、Linode、Microsoft Azure、Digital Ocean 等的服务允许您在云中设置 Ubuntu 服务器,以便通过 OpenSSH 连接和管理。选择虚拟专用服务器(VPS)选项有一些好处;您无需为大型物理服务器寻找空间,也不必担心电力使用问题。另一个好处是,在本章中甚至无需经历安装过程;当您选择在其平台上部署 Ubuntu 服务器时,云提供商将为您执行此操作。然而,主要缺点是 VPS 实例并非免费——您需要查看在此类服务器上运行 Ubuntu 的相关成本,并决定这种成本是否合理。一些 VPS 服务允许您每月以至少 5 美元的价格设置实例,这可以低于在某些地区运行物理服务器所需的电费成本。
树莓派
树莓派单元正在迅速成为用户喜爱的服务器使用案例。它们价格低廉(某些型号甚至低于 40 美元),并且电力消耗非常少——你可以将它们 24/7 保持通电,几乎不会对电费产生显著影响。事实上,它们的功耗大约相当于充电一部高端手机所需的电力。另一个好处是,树莓派通常比入门级 VPS 更强大。最便宜的 VPS 实例通常只有 1 个 CPU 核心和 1GB RAM,但现代树莓派配备四核 CPU,并且具有 2GB、4GB 或 8GB 的 RAM,具体取决于购买的型号。这意味着树莓派可能比更便宜的 VPS 实例性能更好。树莓派的缺点是,由于它们使用 ARM CPU 而不是 x86,因此某些应用程序不可用。这意味着本书中的一些示例在树莓派上将无法运行(尽管大多数示例可以)。
一旦选择了要在其上安装 Ubuntu 服务器的设备,我们可以继续进行。如果选择使用 VPS,您可以跳转到下一章,第二章,管理用户和权限,因为您不需要详细介绍安装过程。对于树莓派,如果您选择了这个平台,您可以跳到本章末尾,查看专门设置的部分。对于其他所有设备,请继续阅读 Ubuntu 服务器 Live 安装程序的详细步骤。
获取安装媒体
是时候开始了!如果你决定使用物理服务器、桌面、笔记本电脑或虚拟机作为测试服务器,那么你需要完成安装过程来设置 Ubuntu。别担心——这非常简单,甚至比你想象的还要简单,因为与旧版本相比,整个过程的步骤要少得多。如果你选择使用 VPS 或树莓派,则无需经过这个过程,因为 VPS 提供商会为你完成这个步骤,而树莓派有一种完全不同的设置方法(我们将在本章后面的在树莓派上安装 Ubuntu部分介绍)。
假设你已经决定使用一个需要通过安装程序的设备,我们需要下载 Ubuntu Server,然后创建可启动的安装介质来安装它。如何操作很大程度上取决于你的硬件。你的设备有光驱吗?它能从 USB 启动吗?请查阅设备的文档以了解详细信息。
如果可以的话,建议使用闪存驱动器进行安装,最好是使用 USB 3.0 或更高版本,因为它比 USB 2.0 更快。推荐使用闪存驱动器的原因是它们通常比 DVD 更快。
然而,如果你的设备较旧,你将没有选择的余地,因为老旧设备根本无法从 USB 启动。一般来说,如果可能的话,使用闪存驱动器,如果没有选择,才选择 DVD。
过去,Ubuntu Server 的 ISO 镜像可以用来创建可启动的 CD 或 DVD。但现在,可写 CD 的空间不足以支持下载大小。因此,如果你选择将其刻录到可启动的光盘介质上,至少需要一个可写的 DVD。
不幸的是,典型数据中心中服务器的年龄差异会带来一些不可预测性,尤其是在如何启动安装介质方面。刚开始接触服务器时,所有标准的机架式服务器通常都配有 3.5 英寸软盘驱动器,甚至一些更高端的服务器还配有光驱。而如今,服务器通常既没有软盘驱动器,也没有光驱。如果服务器有光驱,它可能会长时间没有使用,直到下次有人尝试使用它时才发现它可能已经坏了。有些服务器可以从 USB 启动,有些则不行。继续之前,请查阅硬件的文档并做相应的计划。你的服务器功能决定了你需要创建哪种类型的介质。
无论我们计划创建可启动的 USB 还是 DVD,我们只需要下载一个文件。在浏览器中导航到以下网站开始:www.ubuntu.com/download/server。
在这个页面上,我们将通过点击选项 2 – 手动服务器安装按钮来下载 Ubuntu 22.04 LTS:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_01_01.png
图 1.1:Ubuntu Server 22.04 下载页面
接下来,您将看到一个或多个版本的 Ubuntu Server 可供下载:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_01_02.png
图 1.2:展示 Ubuntu Server 22.04 下载选项
截至本章撰写时,Ubuntu Server 22.04 是最新版本,并作为主要下载选项显示。根据您阅读本书的时间,页面上可能还列出了其他版本的 Ubuntu Server,例如 22.10 和 23.04。Ubuntu 每六个月发布一次新版本。然而,本书仅涵盖 长期支持(LTS)版本,因为它享有五年的支持。
相比之下,非 LTS 版本(或“过渡发布版”)仅支持九个月,因此不适合用作生产服务器。组织通常不会使用非 LTS 版本,除非是为了在正式发布之前测试即将推出的功能,所以为了我们的目的,我们将坚持使用 LTS 版本。下载完成后,我们将得到一个 ISO 镜像文件,可以用来创建可引导的安装介质。
如果您是在设置虚拟机,那么从 Ubuntu 下载页面下载的 ISO 文件就是您所需要的;您不需要创建可引导的 DVD 或闪存驱动器。在这种情况下,您只需要创建虚拟机,将 ISO 文件附加到虚拟光驱上并启动它。接下来,安装程序应该会自动启动,您可以按照本章稍后“安装 Ubuntu Server”部分中描述的安装步骤继续操作。由于在虚拟化解决方案之间,启动 ISO 镜像的过程有所不同,因此逐一详细说明每种方法会是一项非常困难的任务。幸运的是,这个过程通常很简单,您可以在虚拟化管理程序的文档中找到详细信息。在大多数情况下,过程就像是将下载的 ISO 镜像附加到虚拟机上并启动它一样简单。
如果您的设备不支持从 USB 启动,且您需要创建一个可引导的 DVD,通常只需要下载 ISO 文件,然后右键单击该文件。在操作系统的右键菜单中,您应该有一个类似“刻录到磁盘”的选项。这适用于 Windows 以及大多数安装了刻录应用程序的 Linux 图形桌面环境。
具体步骤因系统而异,主要是因为这里涉及大量的软件组合。例如,我见过许多 Windows 系统,其中右键点击菜单中的刻录 DVD 选项被已安装的 CD/DVD 刻录软件删除。在这种情况下,你必须首先打开 CD/DVD 刻录软件并找到从下载的 ISO 文件创建介质的选项。尽管我很想在这里列出完整的过程,但通常没有两台 Windows 电脑预装相同的 CD/DVD 刻录软件。最好的经验法则是尝试右键点击文件,看看是否有该选项,如果没有,就参考你所用应用程序的文档。请记住,数据光盘并不是我们需要的类型,所以一定要寻找从 ISO 镜像创建介质的选项,否则你的光盘将对我们的目的毫无用处。
到此时,你应该已经下载了 Ubuntu Server 的 ISO 镜像文件。如果你打算使用 DVD 来安装 Ubuntu,你也应该已经创建好它。在接下来的部分,我将概述如何创建一个可引导的闪存驱动器,用于安装 Ubuntu Server。
创建一个可引导的闪存驱动器
创建一个可引导的 USB 闪存驱动器来安装 Ubuntu 的过程,过去在不同平台间差异很大。具体步骤根据你的工作站或笔记本电脑当前使用的是 Linux、Windows 还是 macOS 而有所不同。幸运的是,现在有了一种更简单的方法。如今,我推荐使用Etcher来创建可引导的介质。Etcher 的优势在于它将方法抽象化,使得无论你使用哪种操作系统,过程都是相同的,而且它将过程简化到最简单的形式。
我喜欢的另一个功能是 Etcher 很安全;它能防止你在制作可引导介质的过程中破坏当前操作系统。过去,你可能会使用 Linux 上的 dd 命令将 ISO 文件写入闪存驱动器。然而,如果你设置 dd 命令不正确,可能会把 ISO 文件写入当前操作系统,从而擦除整个硬盘。Etcher 不会让你犯这样的错误。
在继续之前,你需要准备一只 USB 闪存驱动器,它必须是空的,或者是你不介意被清空的。这一过程将完全擦除其内容,所以确保该设备上没有你可能需要的信息。闪存驱动器的容量应至少为 2 GB 或更大。考虑到现在很难找到小于 4 GB 的闪存驱动器,这应该比较容易获取。
首先,前往www.balena.io/etcher/,从他们的网站下载最新版本的应用程序并打开它。启动后,窗口看起来会类似于以下截图:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_01_03.png
图 1.3:使用 Etcher 创建可引导的闪存驱动器
此时,点击 从文件闪存,这将打开一个新窗口,允许你选择之前下载的 ISO 文件。一旦选择了 ISO,点击 打开:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_01_04.png
图 1.4:使用 Etcher 选择 ISO 镜像
如果你的闪存驱动器已经插入到计算机中,Etcher 应该会自动检测到它。如果你连接了多个闪存驱动器,或者 Etcher 选择了错误的驱动器,你可以点击 更改 并选择你希望使用的闪存驱动器:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_01_05.png
图 1.5:使用 Etcher 选择不同的闪存驱动器
最后,点击 继续 启动该过程。此时,闪存驱动器将被转换为 Ubuntu Server 安装介质,可以用来启动安装过程:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_01_06.png
图 1.6:Etcher 正在写入闪存驱动器
几分钟后(时间长短取决于你的硬件),闪存 过程将完成,你将能够继续并开始一些安装操作。在继续之前,我们应该先快速讨论一下分区问题。
规划分区布局
分区 硬盘允许你将硬盘划分成多个部分,为不同的应用程序或用途分配专门的存储空间。例如,你可以为 Apache 网络服务器共享的文件分配一个分区,这样对其他分区的更改就不会影响它。你甚至可以为你的网络文件共享分配一个分区——可能性是无穷的。每个分区都会挂载(附加)到一个特定的目录,任何发送到该目录的文件都会被写入到该独立分区。你为分区挂载目录起的名字是任意的,实际上你叫什么名字并不重要。Linux 系统的存储灵活性使你在分区和目录命名上都可以发挥创意,因为 Linux 文件系统在将存储设备挂载到特定文件夹时提供了更大的灵活性。
诚然,我们有些急于求成了。毕竟,我们才刚刚开始,本章的重点是帮助你设置一个基础的 Ubuntu Server 安装,以便为接下来的内容奠定基础。在安装过程中,我们将接受默认设置。然而,本节的目的是给你提供一些选项供你以后参考。到某个时候,你可能会想要发挥创意,尝试不同的分区布局。
使用自定义分区,你可以做一些非常巧妙的事情。例如,经过正确配置后,你可以在不丢失用户数据、日志等的情况下清除并重新加载操作系统。这是因为 Ubuntu Server 允许你在安装过程中根据需要划分存储。如果你已有包含数据的分区,你可以选择保持不变,并将其带到新的安装中。你只需要将挂载目录路径设置为与之前相同,恢复配置文件,应用程序就会像什么都没发生一样继续工作。
现实世界中常见的自定义分区例子之一是将/home目录单独分割成一个分区。由于用户通常在这里存储文件,你可以配置服务器,以便重新加载操作系统时不会影响他们的文件。当他们在服务器刷新后重新登录时,所有的文件都会在原来的位置。你甚至可以将 Apache Web 服务器共享的文件放在它们自己的分区上,这样也能保持这些文件不被丢失。这里可以做很多创新的配置。
这可能不言而喻,但在重新安装 Ubuntu 时,你应该备份那些包含不希望被擦除数据的分区(即使你不打算格式化这些分区)。原因是,一旦出错(实际上只需勾选一个框),你就可能轻易擦除该分区上的所有数据。在刷新服务器时,始终备份你的数据。
使用独立分区的另一个理由可能是创建边界或限制。如果你在服务器上运行的某个应用程序容易占满大量存储空间,你可以将该应用程序指向一个独立的分区,且该分区的大小有限。例如,日志文件就是一个很好的应用场景。日志文件是任何系统管理员在存储方面的噩梦。
日志在帮助你找出为什么某个程序崩溃时非常有用,但如果不小心,它们会很快占满硬盘。在我的经验中,服务器因为日志文件占满了服务器上唯一分区的所有可用空间,导致服务器突然停顿。这个分区就是整个磁盘,应用程序没有其他的边界。
尽管有更好的方法来处理过度的日志记录(如日志轮转、磁盘配额等),但使用单独的分区无疑会有所帮助。如果应用程序的日志目录在一个单独的分区上,它只会填满那个分区,而不会影响整个硬盘,这虽然会导致一些问题,但不会影响整个服务器。作为管理员,你需要权衡这些策略的优缺点,避免服务器过载,并制定一个最适合你组织需求的分区方案。
维护服务器的成功在于高效管理资源、用户和安全性——一个好的分区方案无疑是其中的一部分。有时候,这只是为了让自己省事,万一需要重新加载操作系统时,能够减少工作量。为了跟上本书的内容,Ubuntu Server 的安装或分区方式并不重要。关键是要成功安装——你可以随时练习分区。毕竟,学习的一部分就是搭建平台,观察可能出现的问题,然后进行修复。
下面是一些关于分区的基本技巧:
-
至少需要为根文件系统(由正斜杠表示)创建一个分区。
-
/var目录包含大多数日志文件,因此它是一个很好的分区候选,原因如本节前面所述。 -
/home目录存储所有用户文件。将其分离成一个独立的分区是有益的,因为这样可以让你的用户文件在重新安装 Ubuntu 时得以保留。 -
如果你以前使用过 Linux,可能会熟悉 交换分区 的概念,它是一个特殊的分区,当内存满时可以作为虚拟内存来使用。不过在新的 Ubuntu 版本中,这已经不再是必需的——交换文件 将会自动创建。
在下一节的安装过程中,我们将选择默认的分区方案,让你快速入门。不过,我建议你在未来某个时候再次回到安装过程,尝试不同的分区方式。你可能会想出一些巧妙的方式来划分存储。但这并不是必须的——根据你的需求,所有内容放在一个分区也是可以的。
现在我们已经了解了分区的概念,我们应该已经涵盖了所有必要的主题,能够实际开始安装 Ubuntu Server。让我们现在开始吧。
安装 Ubuntu Server
到此为止,我们应该已经准备好开始安装 Ubuntu Server。在接下来的步骤中,我会带你一步步完成安装过程。
要开始,你只需要将安装介质插入服务器或设备,并按照屏幕上的说明打开启动菜单。启动过程开始时按的键因机器而异,但通常是F10、F11 或 F12。如果不确定,请参考你的文档,尽管大多数电脑和服务器都会在开始时提示你按哪个键。你可能在前几次会错过这个时机,这没关系——直到今天,我似乎仍然需要重启机器一两次才能及时按下正确的键。
一旦你成功启动设备并使用你的 Ubuntu Server 安装介质,安装程序的导航就相对简单了。你只需使用方向键上下移动,选择不同的选项,然后按Enter键确认选择。Esc键将允许你退出子菜单。一旦熟悉了操作,安装程序中的导航非常容易。
一旦安装程序启动,你将看到第一个选择屏幕。第一个选项,Ubuntu Server,允许你启动 Ubuntu Server 安装程序。第二个选项,测试内存,运行一个特殊程序,帮助你确定设备内存条是否有物理缺陷。我总是建议每年至少测试一次设备的内存,尤其是在首次安装操作系统之前。内存问题虽然很少见,但你会感到惊讶。为了保险起见,测试一下内存也许是个不错的主意。
如果你希望测试设备的内存,可以继续进行此操作。不过,为了继续下去,我们需要选择Ubuntu Server选项,以便启动安装程序:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_01_07.png
图 1.7:Ubuntu Server 安装介质的初始启动屏幕
接下来,你将看到一个允许你选择语言的屏幕,如下图所示:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_01_08.png
图 1.8:安装过程开始时的语言选择
如果你的语言是英语以外的其他语言,你可以在这里选择。一旦你对所选择的键盘布局满意,继续选择屏幕底部的完成。
选择语言后,你将进入一个屏幕,可以设置你的键盘配置。如果没有自动选择正确的键盘布局,你可以在这里进行更改。
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_01_09.png
图 1.9:设置你的键盘布局
接下来,我们将看到一个选项来安装Ubuntu Server,或者Ubuntu Server(最小化)。在这里,我们选择第一个选项。选择安装最小化版本的 Ubuntu Server 可能适合创建较小的安装,但对于本书而言,我们将专注于常规安装类型。
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_01_10.png
图 1.10:选择你的安装类型
接下来,Ubuntu Server 安装程序将尝试自动检测适合你的网络卡的参数。默认情况下,它应该通过动态主机配置协议(DHCP)自动检测合适的设置。我们将在后续章节中详细讲解 DHCP,特别是第十一章,设置网络服务。现在,默认设置应该是可以的。选择完成以继续。
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_01_11.png
图 1.11:Ubuntu Server 安装程序中的网络配置
接下来,屏幕将给我们一个机会来设置代理地址(如果需要的话)。大多数读者不需要这个功能,只有那些需要的用户可能已经从网络管理员那里获得了特定的代理设置。因此,我们选择完成继续:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_01_12.png
图 1.12:Ubuntu Server 安装程序中的代理设置
下一屏幕会显示设置镜像地址的选项。正如我们在第三章《管理软件包》中进一步讨论的那样,这个地址指的是可以下载可安装应用程序(软件包)的在线源。在某些情况下,一个组织可能会托管自己的软件仓库。
因此,在这个界面上,如果你有自己的服务器,可以选择不同的服务器来提供软件。对于我们的需求,我们将选择完成以接受默认设置并继续:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_01_13.png
图 1.13:Ubuntu Server 安装程序中的镜像设置
接下来,我们会看到存储设置。特别是,这里是我们可以配置硬盘布局以进行安装的地方。在本章早些时候,我提到过采用自定义分区方案是一种常见做法。如果你有首选的分区布局,这是你可以通过选择自定义存储布局来输入决策的屏幕。
然而,这样做有点跳过了书中的内容,因此我建议选择完成来接受默认设置,这将覆盖整个硬盘:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_01_14.png
图 1.14:安装 Ubuntu Server 时配置存储
在告诉安装程序如何设置服务器上的存储设备后,我们会看到一个屏幕,汇总了我们在配置存储时的选择。由于我们选择了默认布局,这个屏幕会展示一个基本布局。如果你决定设置一个自定义的分区方案,你需要确保这里显示的选择与您设想的相符。如果你对这些内容感到困惑,不必太担心。我们将在第九章《管理存储卷》中更详细地讲解存储相关内容。现在,选择完成接受默认的存储布局:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_01_15.png
图 1.15:安装 Ubuntu Server 时的存储配置总结屏幕
如果你还不知道,这个过程将会清除你设备硬盘上的所有数据,并用新的 Ubuntu Server 安装替代它。这意味着,如果你没有备份设备上可能保存的重要数据,你将永远丢失这些信息。接下来的屏幕将解释这是在擦除硬盘并安装 Ubuntu Server 之前的最后一步。如果你确定你的硬盘上没有重要数据,可以选择继续:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_01_16.png
图 1.16:确认安装并擦除硬盘的数据
当我们安装 Ubuntu Server 时,它将为我们创建一个初始用户账户作为安装过程的一部分。此用户将用于配置和维护服务器。在安装程序的这一部分,我们将有机会为此用户命名并设置密码。
在这个屏幕上填写您的信息,就像我在下面的截图中所做的那样。需要记住的一件重要事情是,您在这里创建的用户将具有管理员访问权限。稍后您可以创建其他用户,但在这里创建的用户将拥有特殊权限。完成后,箭头移到Done并按Enter键:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_01_17.png
图 1.17:Ubuntu Server 安装程序,配置用户详细信息
接下来,你将看到一个安装 OpenSSH 服务器的选项。我建议你启用它。在远程管理 Ubuntu 服务器时,OpenSSH 是我们最常用的工具,详细内容在第十章 连接到网络中有讲解。现在,让我们启用这个选项,这样以后我们就少一件事要做了。要这么做,你可以在光标位于选项上时按空格键,在其复选框中添加一个星号符号,表示选择。完成后,选择Done继续:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_01_18.png
图 1.18:在安装 Ubuntu Server 时选择是否设置 OpenSSH
接下来,我们将看到一些常用应用程序的选择,这些应用程序可以在 Ubuntu Server 上运行。例如,我们在这个屏幕上有 Nextcloud、Docker 等选择。现在,我们会忽略这些,因为在本书中我们将手动设置许多服务。因此,现在选择Done继续:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_01_19.png
图 1.19:特色应用程序选择
就这样了 —— 安装程序将继续进行,因为它已经从您那里获得了所有需要的信息。完成后,在屏幕底部您将看到一个重新启动选项;请继续选择它:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_01_20.png
图 1.20:安装完成,待重启
此时,您的服务器将重新启动,然后 Ubuntu Server 应该会立即启动。恭喜!您现在拥有自己的 Ubuntu Server 安装!
除了特定服务器硬件和虚拟机之外,Ubuntu Server 也可以安装在树莓派上,在下一节我们将详细了解这一点。
在树莓派上安装 Ubuntu
Raspberry Pi 平台已成为业界一个非常有价值的资产,并且是一个有用的服务器平台。这些微型计算机现在配备了四核处理器和最多 8GB 的 RAM,非常节能,且其性能足够强大,可以真正将它们转化为实际的服务器。在我的实验室里,我的网络上有几台 Raspberry Pi,每台都负责执行特定的任务或功能。在很多情况下,你甚至无法察觉它们是硬件性能较低的设备。也许更令人惊讶的是,Raspberry Pi 4 能够超越一些低端云实例,在不需要高端 CPU 的情况下,为你提供一个强大的服务器,且没有每月费用。所有这些,都是在如此小巧的外形中——这些设备比你的咖啡杯垫还要小!
Ubuntu Server 支持 Raspberry Pi 2、3 和 4 型号。要开始,只需访问 Raspberry Pi 版本的 Ubuntu 官方下载页面:ubuntu.com/download/raspberry-pi。这将带你到如下界面:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_01_21.png
图 1.21:官方 Ubuntu 网站上 Raspberry Pi 的下载区
一旦进入,你会看到多个可供下载的 Pi 版本列表。参考前面的截图查看可用选项,但请记住,Ubuntu 随时可能重新设计其网页。因此,作为经验法则,下载与您所拥有的 Raspberry Pi 类型匹配的版本,如果有 64 位版本,最好选择 64 位版本(Raspberry Pi 2 只提供 32 位版本)。
Pi 版本的下载文件将以压缩镜像的形式提供,可以直接写入 SD 卡。为了开始这个过程,打开之前下载的 Etcher。打开 Etcher 后,点击Flash from file:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_01_22.png
图 1.22:Etcher,准备开始操作
现在,选择之前下载的文件并点击Open:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_01_23.png
图 1.23:选择要写入 SD 卡的文件
接下来,将一张 SD 卡插入计算机,这张卡将专门用于 Ubuntu Server。Etcher 会完全擦除 SD 卡,因此请确保你不需要卡上的任何数据。如果你的电脑没有 SD 卡槽,可以使用 USB 卡读卡器。如果没有选择正确的设备,可以点击Select target来选择要使用的 SD 卡,如图 1.24所示。然后点击Continue:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_01_24.png
图 1.24:为 Raspberry Pi 选择使用的 SD 卡
一旦你选择了要使用的镜像文件和目标 SD 卡,你就可以开始了。点击**Flash!**开始写入镜像的过程:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_01_25.png
图 1.25:Etcher,准备开始刷写 SD 卡
现在,Etcher 将准备目标设备并写入源镜像文件。根据硬件速度,过程可能需要 5 到 15 分钟:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_01_26.png
图 1.26:Etcher 正在进行中
一旦 Etcher 完成向 SD 卡写入数据,你可以将其从电脑中弹出并插入 Pi 中,该设备可以通过 SSH 远程访问。当它第一次启动完成后,你可以登录并像使用其他任何 Ubuntu Server 安装一样开始使用它(用户名和密码默认为ubuntu)。从那里,你可以为自己创建一个新用户,安装应用程序并进行实验。
摘要
在本章中,我们详细介绍了几种不同的安装场景。与大多数 Linux 发行版一样,Ubuntu Server 是可扩展的,可以安装在各种服务器类型上。物理设备、虚拟机甚至 Raspberry Pi 都有可用的 Ubuntu 版本。安装过程已逐步讲解,现在你应该已经有了自己的 Ubuntu Server 实例,可以根据需要进行配置。本章还涉及了确定服务器角色、创建可启动媒体的过程,以及如何在你的服务器设备上(以及 Raspberry Pi 上)设置 Ubuntu Server 的详细步骤。现在,你已经开始掌握 Ubuntu Server 了!
在下一章中,我们将向你展示如何管理用户。你将能够创建用户、删除用户、更改用户、管理密码过期等。我们还将讨论权限,以便你可以确定用户在服务器上可以执行的操作。到时见!
相关教程
- 从 LearnLinuxTV 安装 Ubuntu Server(视频教程):
linux.video/install-ubuntu-server
加入我们的 Discord 社区
加入我们社区的 Discord 频道,与作者和其他读者讨论:
第二章:管理用户和权限
在上一章中,我们设置了自己的 Ubuntu 服务器安装,现在我们可以开始学习如何维护它,从管理谁能够使用我们的服务器开始。
作为 Ubuntu 服务器的管理员,用户既可以是你最大的资产,也可能是你最大的头痛。在你的职业生涯中,你将添加无数的新用户,管理他们的密码,在他们离开公司时删除他们的帐户,并授予或撤销他们对网络资源的访问权限。即使在你是唯一用户的服务器上,你也会发现自己在管理用户帐户,因为即使是系统进程也是以用户身份运行的。要成功地管理 Linux 服务器,你还需要知道如何管理权限、创建密码策略并限制谁可以在机器上执行管理命令。在本章中,我们将深入探讨这些概念,以便你清楚地了解如何管理用户及其资源。
具体来说,我们将涵盖:
-
理解用户和组的目的
-
理解何时使用
root -
创建和删除用户
-
理解
/etc/passwd和/etc/shadow文件 -
使用
/etc/skel分发默认配置文件 -
在用户之间切换
-
管理组
-
管理密码和密码策略
-
使用
sudo配置管理员访问权限 -
设置文件和目录的权限
在第一部分,我们将简要讨论管理用户的性质。
理解用户和组的目的
当谈到服务器时,用户非常重要——如果没有用户可供服务,那么根本就不需要服务器。在 IT 领域,用户管理这一主题本身是相当广泛的。关于认证的单个方法已经有整本书籍被写成,并且存在围绕它的技术(如轻量级目录访问协议,或LDAP)。在本章中,我们将重点介绍如何管理存在于我们服务器本地的用户以及帮助定义他们权限的组。
由于 Ubuntu Server 是一个 Linux 发行版,它采用了 Unix 风格的用户帐户、组和权限管理方式。尽管我们的重点是 Ubuntu,但本章中你将学习到的许多与用户管理相关的命令也适用于其他平台。有一些命令允许你添加、删除和更改用户,还有一些命令可以改变权限。
在服务器的上下文中,用户指的是谁(或什么)能够使用该服务器。例如,你可能有一个名叫 Susan 的会计,或一个名叫 Haneef 的 IT 管理员,他们都需要访问服务器。也许 Susan 只需要访问一个文件共享目录来存取与会计相关的文件,而 Haneef 可能作为系统管理员需要更多的访问权限。我们在服务器上创建的用户帐户将代表实际使用服务器的人。
组(Groups)允许我们将对特定文件和目录的访问进行隔离。正如我们稍后将学到的,文件和目录有用户和组的分配。当与权限结合使用时,我们就可以管理用户在服务器上可以执行的操作。
然而,用户并不总是指人类。我们的服务器上也有系统用户,这些用户可能会被应用程序和运行中的进程用于后台或自动化任务。一个例子可能是备份任务,可能有一个备份用户在后台运行任务,将重要文件复制到其他位置。你现在不需要担心与系统相关的用户,只需要知道它们的存在。随着我们阅读本书,你将会看到更多此类的例子。
更高级的组织可能会有一个中央登录服务器,例如Active Directory(AD)或标准的 LDAP。除此之外,还有其他类似的技术。本书中我们不会深入讨论这些技术,但请记住,中央认证服务器是你所在组织可能会采用的一种选择,若你决定进一步了解这方面的内容。
然而,最强大的用户是root。这个特殊的用户赋予我们最大权限,但正如你将在下一节看到的那样,这也伴随着一定的风险。
理解何时使用 root 用户
在上一章中,我们设置了自己独立的 Ubuntu 服务器安装。在安装过程中,我们被要求创建一个作为系统管理员的用户账户。所以,到目前为止,我们的服务器上应该至少有两个用户:前面提到的管理员用户,以及root用户。我们当然可以创建其他具有不同访问权限的用户账户(我们将在本章中进行此操作),但在我们开始之前,关于你创建的管理员账户以及为你创建的root用户的讨论是必要的。
root用户账户存在于所有 Linux 发行版中,是地球上最强大的用户账户。root用户账户可以用来在服务器内做任何事情,真的是任何事情。如果想在文件系统中的几乎任何地方创建文件和目录?想要安装软件?这些操作都可以通过root轻松完成。甚至,root账户可以通过一次打错字或错误命令摧毁整个安装:如果你指示root删除整个硬盘上的所有文件,它将毫不犹豫地执行这一操作。在 Linux 系统中,假定你正在使用root时,意味着你知道自己在做什么。因此,在以root身份执行任何命令时,通常不会有确认提示。它会按照指示执行,不论好坏。
正因为如此,我用过的每一个 Linux 发行版都表示,或者至少强烈建议,你在安装过程中创建一个标准用户。Linux 社区普遍建议,管理员应拥有自己的账户,并在需要root权限来完成任务时切换到root。这种做法不太可能因不小心的输入错误或错误命令而毁掉你的服务器。一些管理员会始终严格使用root,但同样,建议仅在必须时使用root。
大多数发行版要求你在安装过程中设置一个root密码,以保护该账户。即便是基于 Debian 的 Ubuntu,也要求你在安装过程中设置一个root密码。Ubuntu 只是决定做一些不同的事情。这样做的原因是,与许多其他发行版不同,Ubuntu 默认会完全锁定root账户。虽然默认情况下root账户不可用,但你仍然可以在登录后启用root,或者切换到root用户。默认禁用只是意味着root账户不像平时那样容易访问。如果你需要启用该账户,我会在本章稍后介绍如何操作。
这一规则的例外是一些 VPS 提供商,比如 Linode,即使是在它们的 Ubuntu 服务器上,也会启用root账户。有时,root密码会被随机生成并通过电子邮件发送给你。不过,你仍然应该创建一个具有管理员权限的用户账户。
Ubuntu(包括其服务器版本)推荐使用sudo,而不是直接使用root。具体来说,sudo使你能够以提升的权限运行单个命令,而不需要一直以root身份登录。
使用 sudo 运行特权命令
我会在本章稍后介绍如何管理sudo,但现在请记住,sudo的目的是让你可以使用用户账户执行通常只有root才能做的事情。例如,作为一个普通用户,你不能像下面这样发出安装软件包的命令(别担心现在的apt命令,我们将在第三章,软件包管理中介绍):
apt install tmux
反而,你会收到一个错误信息:
E: Could not open lock file /var/lib/dpkg/lock-frontend - open (13: Permission denied)
E: Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend), are you root?
但是,如果你在命令前加上sudo(假设你的用户账户有权限使用它),命令将正常工作:
sudo apt install tmux
当您使用sudo时,系统会要求您输入用户密码以确认,然后命令将被执行。后续带有sudo前缀的命令可能不会再提示您输入密码,因为系统会缓存您的密码一段时间,直到超时或终端关闭。理解这一点应该能够澄清在安装期间创建的用户帐户的实用性。我之前提到这个用户是一个管理帐户,但实际上它只是一个能够使用sudo的用户帐户。Ubuntu Server 在安装期间会自动为第一个创建的用户帐户授予sudo访问权限。
所期望的是,您将使用该帐户来管理系统,而不是root。当您创建额外的用户帐户时,默认情况下它们将无法访问sudo,除非您明确授予它们权限。
创建和删除用户
在 Ubuntu 中创建用户可以通过两个命令之一完成:adduser和useradd。这一开始可能会有些混淆,因为这两个命令执行的是相同的操作(方式不同),并且命名非常相似。我会首先介绍useradd命令,然后解释adduser的区别。您甚至可能更喜欢后者,但我们稍后会详细讨论。
使用useradd
首先,这里是useradd命令实际应用的一个例子:
sudo useradd -d /home/jdoe -m jdoe
使用此命令,我创建了一个名为jdoe的用户。通过-d选项,我澄清我希望为此用户创建一个主目录,并且在此之后,我指定/home/jdoe作为用户的主目录。-m标志告诉系统我希望在过程中创建主目录;否则,我将不得不自己创建目录。最后,我指定了我的新用户的用户名(在本例中为jdoe)。
随着我们在本书中的进展,会有需要root权限才能执行的命令。前面的命令就是一个例子。对于需要这种权限的命令,我会在命令前加上sudo。当您看到这些命令时,这意味着需要root权限才能运行。对于这些命令,您也可以登录为root(如果root已启用),或者切换到root以执行这些命令。但是,如我之前提到的,强烈建议使用sudo而不是使用root帐户。
现在,使用以下命令列出/home的存储:
ls -l /home
您应该会看到一个列出我们新用户的文件夹:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_02_01.png
图 2.1:在我们创建第一个用户后列出/home目录的内容
那么如何为我们的用户设置密码呢?由于使用了 sudo,可能会要求输入当前用户的密码,但并没有要求为新用户设置密码。要为用户创建密码,我们可以使用 passwd 命令。passwd 命令默认允许你更改当前登录用户的密码,但如果以 root 用户身份或通过 sudo 执行,它也允许你为任何其他用户设置密码。如果你单独输入 passwd,命令会首先要求你输入当前密码,然后是新密码,最后再确认一次新密码。如果在命令前加上 sudo 并指定其他用户帐户,你就可以为任何用户设置密码。以下是此过程的输出示例:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_02_02.png
图 2.2:更改用户的密码
正如你在上一个截图中看到的,当使用 passwd 命令输入密码时,你不会看到任何星号或其他类型的输出。这是正常的。虽然你不会看到输入的视觉指示,但你的输入已经被识别。
现在我们有了一个新用户,并且我们已经为该用户设置了密码。jdoe 用户现在可以使用我们选择的密码访问系统。默认情况下,该用户无法使用 sudo,但我们将在本章稍后讲解如何更改这一点。
使用 adduser
之前,我提到过 adduser 命令作为创建用户的另一种方式。这个命令的区别(和便捷性)一旦使用后就会立刻显现。去尝试一下吧;执行 adduser 并指定你想创建的用户的用户名。以下是该过程的示例:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_02_03.png
图 2.3:使用 adduser 命令创建用户
在前述过程中,我执行了 sudo adduser dscully(修改用户的命令需要 sudo 或 root 权限),然后我被问到一系列关于如何创建用户的问题。我被要求输入密码(两次)、全名、房间号、工作电话 和 家庭电话。在 其他 字段中,我输入了评论 Trust no one,这是管理用户时非常好的心态。最后的提示(在最终确认之前)都是可选的:我不必输入 全名、房间号 等等。如果我想跳过这些提示,我可以直接按 Enter 键。真正必须的只有用户名和密码。
从输出中,我们可以看到adduser命令为我们做了不少工作。该命令默认将/home/dscully作为用户的主目录,帐户被分配了下一个可用的用户 ID(UID)和组 ID(GID),其值为1002,并且它还将/etc/skel中的文件复制到了我们新用户的home目录中。实际上,adduser和useradd命令都会从/etc/skel复制文件,但adduser在执行操作时更加详细。
如果你还不明白UID、GID和/etc/skel是什么,不用担心,我们稍后会讲解这些概念。
总而言之,adduser命令在创建用户时更加方便,它会提示你输入各种选项,而无需记住命令行选项。它还会提供关于它所做操作的详细信息。此时,你可能会想,既然adduser看起来如此方便,为什么还要使用useradd呢?不幸的是,adduser并不是所有 Linux 发行版都提供的。最好还是熟悉一下useradd,以防你在一个非 Ubuntu 的 Linux 系统上遇到问题。
你可能会觉得看到adduser命令到底是什么很有趣。它甚至不是一个二进制程序——它是一个Shell 脚本。Shell 脚本其实就是一个可以作为程序执行的文本文件。现在你不需要太担心脚本的内容,因为我们会在第六章中讲解,提高你的命令行效率。就adduser而言,它是一个用Perl编写的脚本,Perl 是一种有时用于管理任务的编程语言。由于它不是二进制文件,你甚至可以在文本编辑器中打开它,查看它在后台执行的所有代码。然而,请确保不要在带有root权限的文本编辑器中打开该文件,以免不小心保存更改并破坏脚本。以下命令将在 Ubuntu Server 系统中打开adduser脚本:
nano /usr/sbin/adduser
使用上下箭头以及Page Up和Page Down键在文件中滚动。当完成后,按下Ctrl + x退出文本编辑器。如果编辑器提示你保存更改,请不要保存。无论如何,你们这些眼睛尖锐的人可能会注意到,adduser脚本调用了useradd来执行实际的工作。所以,不管怎样,你实际上是直接或间接地使用了useradd。
既然我们知道了如何创建用户,了解如何删除它们也是很有用的。
删除用户
当用户不再需要访问系统时,删除或禁用帐户非常重要,因为未管理的帐户往往会成为安全隐患。要删除用户帐户,我们将使用userdel命令。
然而,在删除账户之前,你应该问自己一个非常重要的问题:你(或其他人)是否需要访问该用户的文件?大多数公司都有文件保留政策,详细说明了当员工离职时应该如何处理用户的数据。有时,这些文件会被复制到存档中进行长期存储。通常,经理、同事或新员工可能需要访问前用户的文件,或许是为了继续完成某个项目。理解这一政策对管理用户非常重要。如果你没有明确规定离职用户文件的保留要求,最好与管理团队合作制定一项政策。
默认情况下,userdel命令不会删除用户的home目录的内容。在这里,我们使用以下命令将dscully从系统中删除:
sudo userdel dscully
我们可以通过输入以下命令来查看dscully用户的文件是否仍然存在:
ls -l /home
前面的命令将会产生以下输出:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_02_04.png
图 2.4:尽管我们已经删除了用户,但dscully的主目录仍然存在。
由于dscully的/home目录仍然存在,我们可以将该目录的内容移动到任何我们想要的地方。例如,如果我们有一个名为/store/file_archive的目录,我们可以轻松地将文件移动到那里:
sudo mv /home/dscully /store/file_archive
当然,最终存储的目录由你决定,但你明白我的意思。
如果你还不知道,你可以使用mkdir命令来创建一个新目录。你可以在任何你的登录用户有权限访问的目录中创建一个目录。以下命令将创建我在前面示例中提到的file_archive目录:
sudo mkdir -p /store/file_archive
-p标志只是会在父目录不存在时创建父目录。
如果你确实希望在删除账户时同时删除用户的主目录,只需添加-r选项。这样可以一并删除该用户及其数据:
sudo userdel -r dscully
如果在账户删除后仍需要删除/home目录(如果你第一次没有使用-r参数),可以使用rm -r命令像删除任何其他目录一样删除它:
sudo rm -r /home/dscully
可能不言而喻,但rm命令可能非常危险。如果你以root身份登录或在使用rm时使用了sudo,如果不小心,可能会轻易摧毁你整个已安装的系统。不要运行此命令,但作为一个假设性的示例,以下命令(乍一看似乎无害)很可能会完全摧毁你整个文件系统:
sudo rm -r / home/dscully
请注意错字:我不小心在第一个斜杠后面输入了一个空格。我实际上不小心告诉我的系统删除整个文件系统的内容。如果执行该命令,下次我们尝试启动服务器时,它可能甚至无法引导。所有用户和程序数据都将被清除。如果有一个单一的原因让我们保护 root 账户,那就是 rm 命令绝对是其中之一!
到目前为止,我们知道如何添加和删除用户。在下一节中,我们将更深入地了解密码。
理解 /etc/passwd 和 /etc/shadow 文件
现在我们知道如何在服务器上创建(和删除)用户账户,我们已经可以管理用户了。但是这些信息究竟存储在哪里?我们知道用户将其个人文件存储在 /home 中,但是是否有某种数据库可以追踪我们系统上的用户账户?实际上,用户账户信息存储在两个特殊的文本文件中:
-
/etc/passwd -
/etc/shadow
您可以使用以下命令显示这两个文件的内容。请注意,任何用户都可以查看 /etc/passwd 的内容,而只有 root 用户可以访问 /etc/shadow:
cat /etc/passwd
sudo cat /etc/shadow
随便看看这两个文件(只是不要做任何更改),我将帮助您理解它们。
理解 /etc/passwd 文件
首先,让我们来看一下 /etc/passwd 文件。接下来是我测试服务器上此文件的一些示例输出。为了简洁起见,我将输出限制为最后八行:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_02_05.png
图 2.5:示例 /etc/passwd 文件
此文件中的每一行对应系统上的一个用户账户。条目被分割成由冒号(:)分隔的列。用户名在第一列,因此您可以看到我创建了用户 jay 和 jdoe。每个条目的下一列只是一个 x。稍后我会解释这意味着什么。现在,让我们跳到第三和第四列,它们分别引用 UID 和 GID。
在 Linux 系统上,用户账户和用户组实际上是通过它们的 ID 引用的。虽然我们更容易通过名称管理用户,但用户名和组名只是放在 UID 和 GID 上的标签,以帮助我们更轻松地识别它们。
例如,尝试记住 jdoe 在我们服务器上的 UID 1001 可能会很烦人。通过引用账户名 jdoe 来管理它对人类来说更容易,因为我们不太能记住数字,而是名字。但是对于 Linux 系统来说,每次我们引用用户 jdoe,实际上我们只是引用 UID 1001。当创建用户时,默认情况下系统会自动为账户分配下一个可用的 UID。如果您管理多个 Ubuntu 服务器,请注意 UID 在不同系统之间不会匹配,因此请记住 UID 在安装之间不会同步。
在我的例子中(如图 2.5所示),每个用户的 UID 与其 GID 相同。这只是我系统中的一个巧合,实际使用中不一定是这样。虽然我稍后会在本章讨论创建组的内容,但需要理解的是,创建组的过程与创建用户相似,都是通过分配下一个可用的 GID 来进行的,类似于为新用户分配下一个可用的 UID。当你创建一个用户时,该用户的主组与其用户名相同(除非你要求其它方式)。例如,当我创建了jdoe时,系统也自动创建了一个名为jdoe的组。
这就是你实际看到的内容——用户的 UID,以及用户主组的 GID。我们稍后会详细讨论组。
你可能还注意到,你系统中的/etc/passwd文件包含了比我们自己创建的用户更多的条目。这是完全正常的,因为 Linux 使用用户帐户来处理后台运行的各种进程和服务。你可能永远不会与默认帐户交互,尽管你或许会在某一天为某个进程创建自己的系统用户。例如,也许你会为自动化数据处理脚本创建一个数据处理帐户来运行。
好的,回到我们的/etc/passwd文件。第五列用于存储用户信息,通常是用户的名字和姓氏。在我的例子中,jdoe的第五列是空的,因为我通过useradd命令创建了jdoe,该命令没有提示我输入名字和姓氏。这个字段也被昵称为GECOS字段,你在阅读文档时可能会看到它以这种方式被提及。
在第六列,显示了每个用户的主目录。对于jdoe来说,它被设置为/home/jdoe。最后,我们为用户指定了默认的 shell 为/bin/bash。这个字段指的是用户将使用的默认 shell,当使用adduser命令创建帐户时,默认的 shell 是/bin/bash,而使用useradd命令创建时,默认是/bin/sh。(如果你没有偏好,/bin/bash对大多数人来说是最好的选择。)如果我们希望用户使用不同的 shell,可以在这里指定(不过本书并未涉及/bin/bash以外的 shell)。如果我们愿意,也可以将用户的 shell 更改为一个无效的值,从而完全禁止他们登录。这在需要快速禁用帐户时非常有用。
理解/etc/shadow 文件
既然这些已经解释清楚了,让我们来看看/etc/shadow文件。我们可以像其他文本文件一样使用cat命令显示其内容,但与/etc/passwd不同,我们需要root权限才能查看它。所以,赶紧显示这个文件的内容,我会带你逐步分析:
sudo cat /etc/shadow
这将显示以下输出:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_02_06.png
图 2.6:示例/etc/shadow 文件
上面的截图,图 2.6,显示了我服务器上该文件的最后四行。首先,我们在第一列看到用户名——没有什么惊讶的。请注意,输出中没有显示每个用户的 UID。系统根据/etc/passwd文件知道哪个用户名对应哪个 UID,因此这里无需重复显示。第二列显示的似乎是一些乱码。实际上,这是整个文件中最重要的部分。那是用户密码的实际哈希值。
密码哈希是将实际密码转换为一个不同的字符串,代表原始密码。这是一个单向转换,因此你不能通过逆向工程哈希来找到实际密码。在/etc/passwd文件中,存储的是密码的哈希,而不是实际密码,这是出于安全考虑。
如果你还记得,在/etc/passwd文件中,每个用户条目在第二列都有一个x,我提到过稍后会解释这个。x表示的是用户的密码被加密,并且没有直接存储在/etc/passwd中,而是存储在/etc/shadow中。毕竟,/etc/passwd文件是所有人都可以查看的,因此如果任何人都能打开该文件并看到每个人的密码,那将极大地危及安全性。
在过去的日子里,你实际上可以将用户的密码存储在/etc/passwd中,但现在已经不再这么做了。每当你在现代 Linux 系统上创建用户账户时,用户的密码会被加密(在/etc/passwd的第二列会为该用户放置一个x),而实际的密码哈希会存储在/etc/shadow的第二列,以防止被窥视。希望现在你已经明白了这两个文件之间的关系。
记得我之前提到root用户账户默认是锁定的吗?好吧,让我们看看它是如何工作的。执行以下命令,查看/etc/shadow中的root用户账户条目:
sudo cat /etc/shadow | grep root
在我的系统上,我得到以下输出:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_02_07.png
图 2.7:示例 /etc/shadow 文件
你应该立即注意到,root用户账户根本没有密码哈希。相反,密码哈希的位置会显示一个星号。实际上,在这里放置一个星号或感叹号是一种锁定账户的方法。更简单的方法是,你可以使用passwd -l命令来锁定一个账户,而无需编辑文件。但无论哪种方式,我们仍然可以随时切换到root账户(稍后我会向你展示如何做到这一点)。在第二列输入一个星号或感叹号会创建一个限制,使得我们不能直接从 shell 或通过网络登录该用户。我们必须先以普通用户身份登录系统,然后如果需要,还可以切换到该用户。
在讨论完密码哈希后,/etc/shadow文件中还有一些字段我们应该理解。这里有一行构造的示例:
mulder:$6$TPxx8Z.:16809:0:99999:7:::
继续讨论第三列,我们可以看到自Unix 纪元以来密码最后一次更改的天数。对于不清楚的人来说,Unix 纪元是 1970 年 1 月 1 日。因此,我们可以将该列解读为密码是在 Unix 纪元后第 16,809 天更改的。
个人而言,我喜欢使用以下命令来更方便地查看密码最后一次更改的时间:
sudo passwd -S <username>
这将导致输出类似于以下内容:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_02_08.png
图 2.8:检查用户最后一次密码更改的日期
执行此命令后,你可以查看系统中任何账户的信息。第一列显然是用户名。第二列与密码的状态有关,在这种情况下是L,表示该用户的密码被锁定。如果密码已设置且可用,则显示P,如果用户没有密码,则显示NP。
该命令输出的第三列显示了用户最后一次密码更改的实际日期。第四列告诉我们用户在再次更改密码之前需要等待多少天。在这个例子中,jdoe可以随时更改密码,因为最小天数设置为0。我们稍后会在本章中讲解如何设置最小天数,但我会简要解释一下这个设置的含义。起初,要求用户等待一定天数才能更改密码似乎有些傻。然而,千万不要低估用户的反抗心理。当要求用户更改密码时,用户往往会为了满足历史要求而更改密码,但随后会迅速将其更改回原来的密码。通过设置最小天数,你强制要求用户在两次密码更改之间有一个等待期,这样就不那么方便用户直接更改回原来的密码。
第五列,顾名思义,是密码更改之间允许的最大天数。如果你要求用户在每隔一定天数后更改密码,你将在这一列看到相应的数字。默认情况下,这个值设置为99999天。这个天数远远超过人的寿命,所以实际上可以认为它是无限的。
继续讲解第六列,我们列出了在密码过期前,用户会被提醒需要更改密码的天数。在第七列中,我们设置了密码过期后可以过去多少天,在这种情况下,账户将会被禁用。对于我们的示例用户,暂时没有设置此项。最后,在第八列(该列不可见)中,我们可以看到自 Unix 纪元以来,账户将被禁用之前经过的天数(在我们的例子中,这里没有内容,因此没有设置禁用日期)。
我们稍后会讲解如何设置这些字段,但现在希望你能更好地理解/etc/shadow文件的内容。
如果在任何时候你需要进一步的说明,随时可以查看 Ubuntu 的手册页。手册页(man page 的缩写)可以提供关于命令和文件的更多信息。例如,以下命令会显示ls命令的手册页:
man ls
针对本节内容,你也可以检索/etc/shadow文件的手册页:
man passwd
man shadow
按下键盘上的q退出手册页。随时可以查看本书中任何命令的手册页,以便更深入了解。
现在我们已经完全理解了如何管理用户,我们还可以看看如何为他们的主目录提供默认文件。
使用 /etc/skel 分发默认配置文件
在典型的组织中,通常会有一些推荐的默认文件和配置供用户使用。
例如,在进行软件开发的公司中,通常会有推荐的文本编辑器和版本控制系统的设置。位于/etc/skel目录中的文件会在创建新用户时复制到他们的主目录中(假设你在设置用户时选择了创建主目录)。
事实上,你现在就可以亲自验证这一点。执行以下命令:
ls -la /etc/skel
现在,你应该能够查看/etc/skel目录的内容:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_02_09.png
图 2.9:默认的 /etc/skel 文件
你可能已经知道如何列出目录中的文件,但我添加了-a选项,因为我想查看隐藏文件。默认情况下,/etc/skel中包含的文件是隐藏的(它们的文件名以句点开头)。我还加了-l参数,因为它显示的是长格式列表,我觉得这种格式更易读。
每次创建新用户并要求同时创建主目录时,这三个文件(如图 2.9所示)会被复制到用户的主目录中,除此之外,任何你在此处创建的文件也会一同复制。你可以通过列出已创建用户的主目录存储内容来验证这一点。一个用户主目录中的.bashrc文件应该和其他任何用户的相同,除非他们对其进行了修改。
掌握了这些知识后,创建新用户的默认文件应该变得非常简单。例如,你可以使用自己喜欢的文本编辑器创建一个名为welcome的文件,并将其放置在/etc/skel目录中。也许你会创建一个包含公司新员工帮助电话和信息的文件。然后,在你创建账户时,这个文件会自动复制到新用户的主目录中。用户登录后,会在其主目录中看到该文件并查看相关信息。更实际一点,如果你的公司有特定的编辑器设置,适合写代码,你也可以将这些文件包含在/etc/skel中,以确保用户遵循这些设置。事实上,你可以为公司使用的任何应用程序包含默认配置文件。
赶紧试试吧。随便创建一些随机文本文件,然后创建一个新用户,接着你会看到这些文件会自动进入你系统中新账户的主目录中。
现在我们已经有了多个用户,并且了解了如何管理它们的默认文件,我们可以看看如何在用户之间切换。
切换用户
现在我们系统中已经有了多个用户,我们需要知道如何在它们之间切换。当然,你可以随时以某个用户身份登录到服务器,但实际上,你可以在任何时候切换到任何用户账户,只要你知道该用户的密码或拥有sudo权限。
切换用户时,你将使用su命令。如果你输入su而不带任何选项,它将默认假设你要切换到root用户,并会要求你输入root密码。正如我之前提到的,Ubuntu 默认锁定了root账户,所以此时你可能没有root密码。
即使 Ubuntu 默认不为root创建密码,某些虚拟专用服务器(VPS)提供商会解锁root密码,并让你以root用户身份登录。解锁root账户并不是 Ubuntu 的标准做法,而是某些云服务提供商的定制。
解锁root账户其实非常简单;你只需要创建一个root密码。为此,你可以以任何拥有sudo权限的用户身份执行以下命令:
sudo passwd
命令将要求你创建并确认root密码。从此以后,你将能够像使用其他账户一样使用root账户。你可以直接以root身份登录,或者切换到root——现在它完全可用了。然而,实际上你并不需要解锁root账户就可以使用它。你当然可以解锁它,但有办法在不解锁root的情况下切换到root,通常最好保持root账户锁定,除非你有非常特殊的原因需要解锁它。以下命令将允许你从具有sudo权限的用户账户切换到root:
sudo su -
现在你将以root身份登录,并且可以执行任何你想要的命令,不会有任何限制。要返回到之前登录的账户,只需输入exit。你可以通过bash提示符开头的值来判断自己当前以哪个用户身份登录。
如果你想切换到root以外的账户怎么办?当然,你可以直接注销并以该用户身份重新登录。但其实你不需要这么做。只要知道账户的密码,下面的命令就能帮你完成切换:
su - <username>
Shell 会要求输入该用户的密码,然后你将以该用户的身份登录。同样,当你使用完账户后,输入exit将返回到你之前使用的账户。
如果你知道用户的密码,这个命令是没问题的,但通常你并不会知道。通常,在企业环境中,你会创建一个账户,强制用户在首次登录时更改密码,然后你将无法知道该用户的密码。
由于你拥有root和sudo权限,你可以随时更改他们的密码,然后以他们的身份登录。但如果他们的密码突然失效,他们肯定会发现问题——你不是在窃听吧?有了sudo权限,你可以使用sudo切换到任何你想要的用户,即使你不知道他们的密码。只需要在之前的命令前加上sudo,你只需要输入你自己账户的密码,而不是他们的:
sudo su - <username>
切换到另一个用户账户对于支持工作(尤其是故障排除权限问题)通常非常有帮助。举个例子,假设某个用户找你抱怨无法访问特定目录的内容,或者无法运行某个命令。在这种情况下,你可以登录到服务器,切换到他们的用户账户,尝试重现他们的问题。这样,你不仅可以亲自看到他们的问题,还可以测试你的修复是否解决了问题,然后再回复他们。
现在我们已经完全理解了用户账户,甚至知道如何在它们之间切换。在接下来的部分,我们将探讨用户组,它允许我们对用户进行分类。
管理用户组
现在我们理解了如何创建、管理和切换用户账户,我们还需要了解如何管理用户组。Linux 中的用户组概念与其他平台并没有太大区别,基本上是为了实现相同的目的。有了用户组,你可以更高效地控制用户对服务器资源的访问。通过将用户组分配给某个资源(如文件、目录等),你可以通过简单地将用户添加或移除该组来允许或拒绝他们的访问。
在 Linux 中,工作方式是每个文件或目录都有一个用户和一个组来对其进行拥有。这与 Windows 等平台不同,Windows 允许一个资源被多个组分配。而 Linux 是一对一的拥有:每个文件或目录只分配一个用户和一个组。如果你列出 Linux 系统上某个目录的内容,你可以亲眼看到这一点:
ls -l
以下是我其中一台服务器上某个目录的输出示例:
-rw-r--r-- 1 root bind 490 2022-04-15 22:05 named.conf
在这种情况下,我们可以看到 root 拥有这个文件,并且组 bind 也被分配给了它。暂时忽略其他字段;当我们讲解关于权限的章节时,我会详细解释。现在,只需记住,每个文件或目录都分配了一个用户和一个组。
虽然每个文件或目录只能有一个组分配,但任何用户帐户都可以是多个组的成员。仅执行 groups 命令而不带任何选项,可以告诉你当前登录用户是哪些组的成员。如果你在 groups 命令后添加用户名,你将看到该用户是哪些组的成员。可以尝试一下带或不带用户名的 groups 命令,了解一下其作用。
在 Ubuntu Server 平台上,你很可能会发现每个用户帐户都是一个名为与用户名相同的组的成员。正如我之前提到的,当你创建一个用户帐户时,你也在创建一个与用户同名的组。然而,在某些 Linux 发行版中,用户的主要组会默认是名为 users 的组。如果你在 Ubuntu 桌面平台上执行 groups 命令,你可能会看到更多的组。这是因为,面向服务器平台的 Linux 发行版通常更加精简,而桌面平台上的用户需要访问更多的对象,如打印机、声卡等。一些可以安装的包也会为服务器添加额外的系统用户。
如果你想知道你的服务器上存在哪些组,你只需要执行 cat 命令来查看 /etc/group 文件的内容。与我们之前介绍的 /etc/passwd 文件类似,/etc/group 文件包含了系统中已创建的组的信息。快去查看你系统上的这个文件:
cat /etc/group
以下是我其中一台服务器上该文件的示例输出:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_02_10.png
图 2.10:/etc/group 文件的示例输出
和之前一样,文件中的列是用冒号分隔的,不过每行只有四列。在第一列,我们有组的名称,这一点并不意外。在第二列,我们可以存储组的密码,但这不常用,因为这样做实际上会带来安全风险。在第三列,我们有GID,它的概念与我们讨论用户时的UID类似。最后,在最后一列,我们(会)看到一个以逗号分隔的成员列表,列出每个组的成员。
有些条目根本没有显示任何组成员。每个用户确实是自己组的成员,所以虽然文件中没有明确写出这一点,但这是隐含的。如果你查看/etc/passwd文件中用户的条目,你会看到他们的主组(作为第三列显示,以GID的形式)引用了/etc/group文件中的一个组。
在系统中创建新组非常简单,也是分类用户及其权限的好方法。比如你可以为会计人员创建一个accounting组,为 IT 部门的员工创建admins组,为销售人员创建一个sales组。groupadd命令可以用来创建新组。
如果你愿意的话,也可以直接编辑/etc/group文件,手动添加一行新的组信息,不过我认为使用groupadd命令可以省去一些工作,还能确保组条目正确创建。直接编辑组和用户文件通常是不推荐的(而且一个拼写错误可能导致严重问题)。无论如何,接下来是使用groupadd命令创建新组的示例:
sudo groupadd admins
如果你在添加新组后再次查看/etc/group文件,你会看到文件中创建了一行新内容,并且为你选择了一个GID(第一个尚未使用的 GID)。删除组同样简单。只需要执行groupdel命令,后面跟上你想要删除的组名:
sudo groupdel admins
接下来,我们将了解usermod命令,它可以让你将用户与组关联起来。usermod命令可以说是瑞士军刀式的工具;它有很多功能(将用户添加到组只是其中之一)。如果我们想要把一个用户添加到admins组,可以执行以下命令:
sudo usermod -aG admins myuser
在这个例子中,我们提供了-a选项,意味着追加,然后紧接着使用-G,表示我们希望修改次要组成员资格。我把这两个选项合并为一个(-aG),但你也可以分别使用它们(-a -G)。我给出的示例只是将用户添加到附加的组,而不会替换他们的主组。
注意不要遗漏-a选项,因为这样做会将所有当前的组成员资格替换为新的组,这通常不是你想要的。-a选项意味着附加,即将该用户的现有组成员资格列表添加到新组中。
如果你想更改用户的主组,可以使用-g选项(使用小写的g,而不是我们之前使用的大写G):
sudo usermod -g <group-name> <username>
随时查看usermod命令的手册页,了解它允许你管理与用户相关的所有有用功能。你可以使用以下命令查看usermod命令的手册页:
man usermod
另一个例子是更改用户的/home目录。假设你的某个用户进行了改名,你希望更改他们的用户名,并将他们原来的home目录(以及文件)移动到新的位置。以下命令将完成这个操作:
sudo usermod -d /home/jsmith jdoe -m
sudo usermod -l jsmith jdoe
在这个例子中,我们将jdoe的主目录移动到/home/jsmith,在第二个例子中,我们将用户名从jdoe更改为jsmith。
如果你希望将用户从某个组中移除,可以使用gpasswd命令。gpasswd -d就可以完成这个操作:
sudo gpasswd -d <username> <grouptoremove>
实际上,gpasswd也可以代替usermod,将用户添加到组中:
sudo gpasswd -a <username> <group>
现在,你已经知道如何管理组了。通过有效地管理组,你将能够更好地管理服务器上的资源。当然,如果不解释如何管理权限,组将相对无用(否则,任何成员都无法访问资源)。在本章稍后的部分,我们将介绍权限管理,以便你能完整了解如何管理用户访问。
管理密码和密码策略
在本章中,我们已经讲解了一些密码管理的内容,因为我给了你一些passwd命令的例子。如果你还记得,passwd命令允许我们更改当前登录用户的密码。此外,使用passwd命令作为root(并提供用户名),我们可以更改系统上任何用户账户的密码。但这并不是这个命令唯一的功能。
锁定和解锁用户账户
我之前没有提到的关于passwd命令的一件事是,你可以用它来锁定和解锁用户账户。有许多原因可能需要这么做。例如,如果一个用户要去度假或休长假,你可能想要锁定他们的账户,以便他们不在外出期间使用它。毕竟,活跃账户越少,你的攻击面就越小。要锁定账户,使用-l选项:
sudo passwd -l <username>
要解锁账户,可以使用-u选项:
sudo passwd -u <username>
但是,锁定账户不会阻止用户登录,如果他们通过 SSH 使用公钥认证访问服务器。在这种情况下,你需要撤销他们使用 SSH 的权限。一种常见的做法是将 SSH 访问限制为某个特定组的成员。当你锁定账户时,只需将他们从该组中移除。如果你对 SSH 部分不太熟悉,不必过于担心。我们将在 第二十一章,保护你的服务器 中讨论如何保障 SSH 服务器的安全。目前只需要记住,你可以使用 passwd 来锁定或解锁账户,如果你使用 SSH,你将需要将用户锁定,以防止他们登录。
然而,密码管理不仅仅是 passwd 命令,我们还可以实施自己的策略,例如查看或调整密码过期的详细信息。
设置密码过期信息
之前我提到过,你可以为用户的密码设置过期日期(在我们讨论 /etc/shadow 文件时)。在这一节中,我们将介绍如何实际操作。具体来说,chage 命令为我们提供了这个能力。我们可以使用 chage 来修改用户密码的过期周期,但它也是比查看 /etc/shadow 文件更方便的方式来查看当前的过期信息。通过 chage 的 -l 选项,并提供用户名,我们可以看到相关信息:
sudo chage -l <username>
使用 sudo 或 root 并不是运行 chage 的必要条件。你可以在不提升权限的情况下查看自己用户名的过期信息。然而,如果你想查看除自己账户以外的任何用户账户的过期信息,你需要使用 sudo。
在接下来的示例中,我们可以看到来自一个示例用户账户的命令输出:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_02_11.png
图 2.11:chage 命令的输出
在输出中,我们可以看到有关密码过期日期、密码更改的最大天数等信息。基本上,它包含了存储在 /etc/shadow 中的相同信息,但更易于阅读。
如果你希望更改这些信息,chage 将再次是首选工具。下面提供的第一个示例是非常常见的。当创建用户账户时,你肯定希望用户在首次登录时更改密码。
不幸的是,并不是每个人都乐意这样做。chage 命令允许你强制用户在首次登录时更改密码。基本上,你可以将他们的密码过期天数设置为 0,如下所示:
sudo chage -d 0 <username>
如果你再次对刚修改过的用户账户运行chage -l,你将立即看到该命令的结果:
sudo chage -l <username>
输出将显示有关密码更改的信息:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_02_12.png
图 2.12:使用 chage 命令列出设置了密码过期周期的用户
要设置用户账户在一定天数后强制要求更改密码,以下操作可以实现:
sudo chage -M 90 <username>
在这个例子中,我将用户账户设置为在 90 天后过期并要求更改密码。当即将到达密码更改日期前 7 天时,用户登录时将看到一条警告信息。
如我之前提到的,用户通常会尽可能地绕过密码要求,可能在满足初始密码更改要求后,再把密码改回原来的密码。你可以使用 -m 参数设置最小天数,如下例所示,我们将其设置为 5 天:
sudo chage -m 5 dscully
设置最小密码年龄的诀窍是,将其设置为用户修改密码回原密码时感到不方便,但你仍然希望用户在需要时能够更改密码(因此也不要设置得太长)。如果用户想在最小天数还没到之前更改密码(例如,如果用户觉得他们的账户可能已经被泄露),他们可以随时让你为他们更改密码。然而,如果你让密码要求对用户来说过于不便,也可能会适得其反。
设置密码策略
接下来,我们应该讨论如何设置密码策略。毕竟,如果用户将密码更改为简单的密码(如 abc123),强制用户更改密码也没有多大意义。密码策略允许你强制用户遵守一些要求,例如密码长度、复杂性等。
为了方便,我们可以使用 Pluggable Authentication Module(PAM)。PAM 为我们提供了额外的认证功能,并且提供了我们可以使用的额外插件,扩展认证并添加更多功能。虽然本书没有详细讲解 PAM,但我建议你保持对它的记忆,以防你以后想添加更多的功能。
针对设置密码策略的主题,我们可以安装一个 PAM 模块来启用这个功能,这需要安装一个新的软件包:
sudo apt install libpam-cracklib
接下来,让我们看看以下文件,这是 Ubuntu 提供的。你可以使用文本编辑器(如 nano)打开它,我们需要对其进行编辑:
sudo nano /etc/pam.d/common-password
在修改与认证相关的配置文件(如密码要求、sudo 权限、SSH 等)时,一个非常重要的提示是,在进行更改时,始终保持一个 root shell 开放,并在另一个 shell 中测试这些更改。在你完全确认更改已经过充分测试之前,不要退出最初的 root 窗口。在测试策略时,确保不仅用户能够登录,管理员也能登录。否则,你可能会失去登录服务器并进行更改的能力。
要启用密码历史要求(即系统记住用户使用过的最后几个密码,防止他们重复使用),我们可以在文件中添加以下行:
password required pam_pwhistory.so remember=99 use_authok
在示例的 config 行中,我使用了 remember=99,这(你可能猜到)将使我们的系统记住每个用户的最后 99 个密码,并防止他们再次使用这些密码。如果你之前配置了密码的最小使用期限,例如 5 天,那么如果考虑到用户每 5 天更改一次密码 99 次,用户将需要 495 天才能返回到他们的原密码。这几乎不可能让用户重新使用他们的旧密码。
在 /etc/pam.d/common-password 文件中,另一个值得提及的部分是读取 difok=3 的配置项。此配置要求密码必须至少有三个字符与旧密码不同,才能被视为可接受。否则,密码会被认为与旧密码过于相似而被拒绝。你可以将此值更改为任何你喜欢的数字;默认值通常是 5,但在 Ubuntu 中,它将其默认设置为 3。此外,文件中还会看到 obscure 配置项,它防止使用简单密码(如常见的字典词汇等)。
设置密码策略是提高服务器安全性的一个好方法。然而,同样重要的是不要过度限制。为了在安全性和用户挫败感之间找到平衡,挑战在于制定足够的限制来提高安全性,同时尽量减少用户的挫败感。当然,单单提到“密码”这个词就足以让普通用户感到沮丧,所以你不可能让每个人都满意。但从整体系统安全的角度来看,我相信你的用户会感激你作为管理员已经采取了必要的预防措施,以确保他们(以及你们公司的)数据安全。最终,还是要用你最好的判断。
既然我们已经讨论了安全性问题,那么也应该看看如何配置 sudo 本身,这将在下一节中进行处理。
配置管理员访问权限使用 sudo
到目前为止,我们已经在本书中使用了很多次 sudo。此时,你应该已经意识到 sudo 允许你以其他用户的身份执行命令,默认情况下是 root 用户。然而,我们还没有正式讨论过它,也没有讨论如何修改哪些用户账户能够使用 sudo。
在所有 Linux 系统中,你应该用强密码保护你的 root 账户,并将其限制为尽可能少的人使用。在 Ubuntu 中,root 账户默认是锁定的,所以除非你通过设置密码解锁了它(或者你使用的是由 VPS 提供商提供的 Ubuntu 版本),否则无法用它登录系统。使用 sudo 是一种替代直接以 root 用户身份登录执行命令的方法,因此你可以通过 sudo 给管理员提供执行需要 root 权限的任务的权限,而不需要给他们 root 密码或解锁 root 账户。事实上,sudo 让你可以更加精细化管理。直接使用 root 基本上就是全有或全无——如果有人知道 root 密码并且 root 账户已启用,那么此人没有任何限制,可以随意操作。而使用 sudo 时,也可以出现类似情况,但你实际上可以限制某些用户只能使用特定的命令,从而限制他们在系统中能做的事情。例如,你可以给管理员提供安装软件更新的权限,但不允许他们重启服务器。
默认情况下,sudo 组的成员可以不受限制地使用 sudo。基本上,这个组的成员可以做任何 root 能做的事情(也就是一切)。在安装过程中,你创建的用户帐户已成为 sudo 组的成员。要为其他用户提供 sudo 权限,你只需要将他们添加到 sudo 组即可:
sudo usermod -aG sudo <username>
并非所有发行版默认使用 sudo 组,甚至有的不会自动安装 sudo。其他发行版需要你手动安装 sudo,并且可能使用另一个组(如 wheel)来管理对 sudo 的访问。
但再说一次,这样会给予那些用户一切权限,而这可能是你想要的,也可能不是。要实际配置 sudo,我们使用 visudo 命令。这个命令帮助你编辑 /etc/sudoers 文件,这是一个控制 sudo 访问的配置文件。虽然你可以用文本编辑器直接编辑 /etc/sudoers,但强烈不建议用这种方式配置 sudo。visudo 命令会检查你的修改是否遵循正确的语法,并帮助防止你不小心破坏文件。这是一个非常好的方法,因为如果你在 /etc/sudoers 文件中犯了错误,可能会导致没有人能够获得服务器的管理员控制权。虽然有办法从这样的错误中恢复,但显然,这并不是一个你想要面对的局面!所以,这里要记住的一点是,永远不要直接编辑 /etc/sudoers 文件;始终使用 visudo 来编辑它。
下面是 visudo 命令在你犯错误时显示的警告类型的示例:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_02_13.png
图 2.13:visudo 命令显示错误
如果你看到这个错误,按 e 返回编辑文件,然后纠正错误。
这个过程的工作方式是,当你在终端运行visudo时,它会将你带入一个文本编辑器,并打开/etc/sudoers文件。然后,你可以像编辑其他文本文件一样,修改并保存文件。默认情况下,Ubuntu 在使用visudo时会打开nano文本编辑器。在nano中,你可以使用Ctrl + w保存更改,使用Ctrl + x退出文本编辑器。
所以,visudo允许你更改谁能够访问sudo。但你究竟如何进行这些更改呢?你可以滚动浏览visudo打开的/etc/sudoers文件,你应该能看到类似以下的行:
%sudo ALL=(ALL:ALL) ALL
这是启用任何属于sudo组的成员访问sudo权限的配置行。你可以将组名更改为你喜欢的任何名称,例如,你可能希望创建一个名为admins的组。如果你做了这个更改,确保在编辑/etc/sudoers文件或注销之前,实际上已经创建了该组,并将你自己和你的团队添加为该组的成员;如果你发现自己被锁定,无法访问服务器的管理员权限,那可就尴尬了。
当然,你不必通过组来启用访问权限。你实际上也可以指定一个用户名。在/etc/sudoers文件中,组名前会有一个%符号,而用户名则没有。例如,文件中也有如下行:
root ALL=(ALL:ALL) ALL
这里,我们调用了一个用户名(在这个例子中是root),但这一行的其他部分和我之前提到的行是一样的。虽然你当然可以复制这一行并粘贴一遍或多遍(将root替换为其他用户名),以授予其他人访问权限,但使用组的方式实际上是最好的方法。将用户添加或移出一个组(如sudo组)要比每次使用visudo要容易得多。
到此为止,你可能在想,/etc/sudoers配置行上的各个选项到底是什么意思。目前为止,两个例子都使用了ALL=(ALL:ALL) All。为了完全理解sudo,理解其他字段非常重要,所以让我们通过它们(再次使用root这一行作为例子)来逐一了解。
第一个ALL表示root可以从任何终端使用sudo。第二个ALL表示root可以使用sudo冒充任何其他用户。第三个ALL表示root可以冒充任何其他组。最后一个ALL表示该用户能够使用的命令;在这种情况下,是他们想使用的任何命令。
为了帮助理解,我将提供一些额外的示例。这里有一个假设的例子:
charlie ALL=(ALL:ALL) /sbin/reboot,/sbin/shutdown
在这里,我们允许用户charlie执行reboot和shutdown命令。如果用户charlie尝试做其他事情(例如安装软件包),他们将收到错误信息:
Sorry, user charlie is not allowed to execute '/usr/bin/apt install tmux' as root on ubuntu.
然而,如果charlie想要在服务器上使用reboot或shutdown命令,他们将能够执行这些操作,因为我们在为该用户设置sudo权限时明确指定了这些命令。我们可以进一步限制,通过将第一个ALL改为机器名称,在本例中为ubuntu,来引用我在示例中使用的服务器主机名。我还修改了charlie被允许执行的命令:
charlie ubuntu=(ALL:ALL) /usr/bin/apt
在编辑sudo权限时,最好使用命令的完整路径,而不是简化版本。例如,我们在这里使用了/usr/bin/apt,而不是仅仅使用apt。这是非常重要的,因为用户可以创建一个名为apt的脚本,做一些我们通常不允许他们做的恶意行为。通过使用完整路径,我们限制了用户只能使用该路径下存储的二进制文件。
现在,charlie只能使用apt。他们可以使用apt update、apt dist-upgrade以及apt的任何其他子命令。但如果他们尝试重启服务器、删除受保护的文件、添加用户,或者做其他我们未明确设置的操作,他们将被阻止。
但是,我们遇到了另一个问题。我们正在允许charlie模拟其他用户。鉴于安装软件包的上下文,这可能并不完全糟糕(模拟另一个用户在没有权限安装软件包的情况下是没有意义的),但除非我们确实需要这样做,否则允许这种行为是不合适的。在这种情况下,我们可以完全删除这一行中的(ALL:ALL),从而防止charlie使用sudo的-u选项以其他用户身份运行命令:
charlie ubuntu= /usr/bin/apt
另一方面,如果我们确实希望charlie能够模拟其他用户(但仅限于特定用户),我们可以通过设置这些值来指定charlie被允许代表的用户名和组:
charlie ubuntu=(dscully:admins) ALL
在这个例子中,charlie能够代表用户dscully和组admins运行命令。
当然,sudo远远不止我在这一节中提到的内容。关于sudo可以写出整本书(事实上,已经有很多了),但你在日常管理这款工具时,99%的需求都涉及如何为用户添加访问权限,并明确规定每个用户能够做什么。作为最佳实践,尽可能使用组(例如,你可以有一个apt组、一个reboot组等等),并尽量具体地规定谁能做什么。通过这种方式,你不仅可以保持root账户的私密性(或者更好的是禁用它),还可以提高服务器的责任性。
现在我们已经探索了如何授予sudo访问权限,接下来我们将看看权限设置,它让我们对用户能够访问的内容有更高的控制权。
设置文件和目录的权限
在本节中,我们之前在本章所做的所有用户管理工作都将汇聚在一起。我们已经学会了如何添加帐户、管理帐户并保护它们,但我们实际上还没有处理有关谁能够访问这些资源的管理工作。在本节中,我将简要概述 Ubuntu Server 中权限的工作原理,然后提供一些自定义权限的示例。
查看权限
我相信到现在你已经明白如何使用ls命令列出目录的内容。谈到查看权限时,-l标志特别有用,因为长格式列出的输出可以让我们查看对象的权限:
ls -l
以下是一些示例性的假设文件列表:
-rw-rw-rw- 1 doctor 5 Jan 11 12:52 welcome
-rw-r--r-- 1 root root 665 Feb 19 profile
-rwxr-xr-x 1 dalek dalek 35125 Nov 7 exterminate
在每一行中,我们可以看到几个信息字段。第一列是对象的权限字符串(例如,-rw-r—r--),稍后我们会更详细地讲解。我们还可以看到对象的链接数(第二列)。链接超出了本章的范围,但将在第五章、管理文件和目录中讨论。接着,文件的拥有者显示在第三列,文件所属的组显示在第四列,大小(以字节为单位)显示在第五列,文件最后修改的日期显示在第六列,最后是文件的名称。
请记住,根据你的 shell 配置,输出可能会有所不同,字段可能位于不同的位置。为了讨论权限,我们真正关注的是权限字符串,以及拥有者用户和组。在本例中,我们可以看到第一个文件(名为welcome)由名为doctor的用户拥有。第二个文件名为profile,由root拥有。最后,我们有一个名为exterminate的文件,拥有者是名为dalek的用户。
对于这些文件,我们有-rw-rw-rw-、-rw-r--r--和-rwxr-xr-x的权限字符串。如果你以前没有接触过权限,它们可能看起来很陌生,但其实当你把它们拆解开来时,理解起来非常简单。每个权限字符串可以分解为四个部分,如下表所示:
| 对象类型 | 用户 | 组 | 世界 |
|---|---|---|---|
| - | rw- |
rw- |
rw- |
| - | rw- |
r-- |
r-- |
| - | rwx |
rwx |
r-x |
我将每个示例权限字符串分解成了四个组。基本上,我将它们拆分到第一个字符处,然后每三个字符拆分一次。权限字符串的第一部分只有一个字符。在这些示例中,它都是一个破折号。这表示对象的类型是什么。是目录吗?文件吗?链接吗?在我们的例子中,这些权限字符串都是文件,因为权限字符串的第一个位置都是破折号。如果对象是目录,第一个字符应该是d,而不是-。如果对象是链接,那么该字段应该是l(小写字母L)。
在下一部分,每个对象的第二列有三个字符,分别是rw-、rw-和rwx。这表示适用于拥有文件的用户的权限。例如,以下是第一个权限字符串:
-rw-rw-rw- 1 doctor doctor 5 Jan 11 12:52 welcome
前面的代码输出的第三部分显示,doctor是拥有该文件的用户。因此,回到表格,权限字符串的第二列(rw-)特别适用于用户doctor。接下来,权限字符串的第三列也有三个字符,在这种情况下是rw-。这一部分权限字符串指的是拥有该文件的组。在本例中,该组也叫doctor,正如你在前面的代码输出中的第四列看到的那样。最后,权限字符串的最后一部分,在表格中可视化(再次是rw-),指的是world,也称为其他。这基本上指的是除了拥有文件的用户和组以外的任何人。因此,实际上其他每个人对该对象都至少拥有rw-权限。
单独来看,r代表读取,w代表写入。因此,我们可以读取第二列(rw-),这表示用户(doctor)有权限读取和写入该文件。第三列(再次是rw-)告诉我们,doctor组也有读取和写入该文件的权限。权限字符串的第四列相同,因此其他任何人也会对该文件拥有读取和写入权限。
我给出的第三个权限字符串看起来有点不同。这里再次展示:
-rwxr-xr-x 1 dalek dalek 35125 Nov 7 exterminate
在这里,我们看到设置了x属性。x属性表示能够将文件作为脚本执行。因此,考虑到这一点,我们知道该文件可能是一个脚本,可以被用户、组和其他人执行。鉴于文件名为exterminate,这有点可疑,如果它是一个真实文件,我们可能需要进一步调查。
如果某个权限未设置,则它会简单地显示为单个破折号,而不是r、w或x。这与表示某个权限被禁用是一样的。以下是一些示例:
-
rwx:对象为该字段设置了读取、写入和执行权限。 -
r-x:对象具有启用读取、禁用写入并启用执行权限。 -
r--: 对象具有读取权限,写入禁用,执行禁用 -
---: 对象没有启用此字段的任何权限
将这个讨论推向结尾,以下是更多的权限字符串:
-rw-r--r-- 1 sue accounting 35125 Nov 7 budget.txt
drwxr-x--- 1 bob sales 35125 Nov 7 annual_projects
在这些示例中的第一个,我们看到 sue 是 budget.txt 的所有用户,并且该文件被分配给一个会计组。该对象对 sue 可读可写,对其他所有人(group 和 world)也可读。这可能不好,因为这是一个预算文件,可能是机密的。我们稍后会更改它。
annual_projects 对象是一个目录,我们可以从第一列的 d 看出这一点。该目录由 bob 用户和 sales 组拥有。然而,由于这是一个目录,每个权限位具有不同的含义。在以下两张表中,我将分别列出这些位在文件和目录中的含义:
- 文件:
| Bit | 含义 |
|---|---|
r |
文件可以被读取 |
w |
文件可以被写入 |
x |
文件可以作为程序执行 |
- 目录:
| Bit | 含义 |
|---|---|
r |
目录内容可以查看 |
w |
目录内容可以被更改 |
x |
用户或组可以使用 cd 进入目录 |
如你所见,权限的读取方式根据其上下文不同而有所不同:它们适用于文件还是目录。在 annual_projects 目录的例子中,bob 对该目录有 rwx 权限。这意味着用户 bob 可以执行所有操作(查看内容、添加或删除内容,以及使用 cd 将当前 shell 目录切换到该目录)。对于一个组,sales 组的成员能够查看该目录的内容并进入该目录。然而,sales 组中的任何人都无法向目录中添加或删除项目。在该对象上,其他 没有设置任何权限。这意味着没有其他人可以对该对象进行任何操作,甚至无法查看其内容。
更改权限
所以,现在我们理解了如何读取文件和目录的权限。很好,但我们如何更改它们呢?如前所述,budget.txt 文件对所有人(其他)都是可读的。这不好,因为该文件是机密的。要更改对象的权限,我们将使用 chmod 命令。该命令允许我们以几种不同的方式更改文件和目录的权限。
首先,我们可以通过从其他字段中移除读取权限来简单地去除 sue 用户对预算文件的读取权限。我们可以通过以下示例来实现:
chmod o-r budget.txt
如果我们当前不在文件所在的目录中,需要提供完整路径:
chmod o-r /home/sue/budget.txt
如果你对不是自己拥有的文件使用 chmod 命令,你需要使用 sudo。
不管怎样,你应该已经理解了。以这个示例为例,我们将从other(o-r)移除r权限位。如果我们想要添加这个权限位,我们只需要用+代替-。以下是一些chmod实际应用的额外示例:
-
chmod u+rw <filename>:该对象在user列中添加了rw权限 -
chmod g+r <filename>:拥有组被赋予读取权限 -
chmod o-rw <filename>:Other移除rw权限位
此外,你还可以使用八进制值来管理和修改权限。这实际上是更改权限的最常用方法。我喜欢将其看作一个评分系统。虽然它并非真正的评分系统,但将每种访问类型看作有自己价值的方式,更容易理解。基本上,每个权限位(r、w 和 x)都有其对应的八进制值,如下所示:
-
读取:
4 -
写入:
2 -
执行:
1
使用这种风格时,结合这些八进制值时,你能得到的数字组合不多(每个值只能使用一次)。因此,我们可以通过以不同的组合添加(或不添加)这些数字来得到0、1、2、3、4、5、6和7。其中一些你几乎永远不会看到,比如一个对象有写入权限但没有读取权限。大多数情况下,你会看到0、4、5、6和7最常用与chmod。例如,如果我们将读取和写入加起来,我们得到6。如果我们将读取和执行加起来,我们得到5。如果我们将三者都加起来,我们得到7。如果我们不加任何权限,我们得到0。我们为每一列(User、Group和Other)重复这个过程,得出一个三位数的字符串。以下是一些示例:
-
600:User拥有读取和写入权限(4+2)。没有其他权限被设置。这与
-rw-------是相同的。 -
740:User拥有读取、写入和执行权限。Group拥有读取权限。Other没有任何权限。这与
-rwxr-----是相同的。 -
770:User和Group都拥有完全的访问权限(读取、写入和执行)。Other没有任何权限。这与
-rwxrwx---是相同的。 -
777:每个人都有所有权限。这与
-rwxrwxrwx是相同的。
回到chmod,我们可以在实践中使用这种编号系统:
-
chmod 600 filename.txt -
chmod 740 filename.txt -
chmod 770 filename.txt
希望你能理解。如果你想更改一个目录的权限,-R选项可能会对你有帮助。它使更改具有递归性,这意味着你不仅会更改该目录的权限,还会一次性更改它下面所有文件和子目录的权限:
chmod 770 -R mydir
虽然使用-R选项配合chmod可以节省一些时间,但如果你在更改权限的目录下有文件和子目录混合的情况,它也可能引发问题。前面的例子将权限770授予mydir及其所有内容。如果目录内有文件,这些文件将被赋予可执行权限给用户和组,因为7包括了执行位(值为1)。这可能不是你想要的效果。我们可以使用find命令来区分这些情况。虽然find命令超出了本章内容的范围,但通过以下命令的使用,应该能相对简单地理解它们的功能,以及它们如何有用:
find /path/to/dir/ -type f -exec chmod 644 {} \;
find /path/to/dir/ -type d -exec chmod 755 {} \;
基本上,在第一个例子中,find命令定位到/path/to/dir/路径下的所有文件(-type f),并对其执行chmod 644操作。第二个例子是定位该路径下的所有目录,并将它们的权限更改为755。这里没有详细介绍find命令,因为它很容易成为一章内容,但我将其包含在此,因为希望这些示例能对你有所帮助,并成为你自己有用命令列表中的一部分。
更改对象的所有权
最后,我们需要知道如何更改文件和目录的所有权。通常情况下,某个特定的用户可能需要访问某个对象,或者我们可能需要更改所有组。我们可以使用chown命令来更改文件或目录的用户和组所有权。例如,如果我们希望将文件的所有者更改为sue,我们可以执行以下命令:
sudo chown sue myfile.txt
在处理目录时,我们还可以使用-R标志来更改目录本身的所有权,以及它可能包含的所有文件和子目录的所有权:
sudo chown -R sue mydir
如果我们希望更改对象的组分配,我们可以按照以下语法执行:
sudo chown sue:sales myfile.txt
注意冒号(:)用来分隔用户和组。在这个命令中,我们确定了希望sue用户和sales组拥有该资源。我们还可以使用-R选项,如果目标是目录并且想要递归更改。
另一个值得了解的命令是chgrp命令,它允许你直接更改文件的组所有权。使用该命令时,你可以执行chgrp命令,并跟上你希望拥有该文件的组名,再加上文件名。例如,之前的chown命令可以简化为以下命令,因为我们只是修改了文件的组分配:
sudo chgrp sales myfile.txt
就像chown命令一样,我们也可以使用-R选项与chgrp命令一起使用,以便在处理目录时递归地更改权限。
好了,你现在应该能管理服务器上的文件和目录权限了。如果你以前没有在 Linux 系统上处理过权限,可能需要几次尝试才能掌握。最好的方法就是多练习。创建一些文件和目录(以及用户)并管理它们的权限。尝试删除用户对某个资源的访问权限,然后作为该用户尝试访问该资源,看看会遇到什么错误。修复这些错误并尝试更多示例。通过练习,你应该能很快掌握这项技能。
总结
在 Linux 管理和相关领域,管理用户和权限是你会经常做的事情。新用户会加入你的组织,而其他用户则会离开,因此这将成为你思维工具集的一部分。即使你是唯一使用服务器的人,考虑到进程如果无法访问其所需资源就无法运行,你也会发现自己需要管理应用程序的权限。
在这一章中,我们深入探讨了用户、组和权限的管理。我们学习了创建和删除用户、分配权限,以及使用 sudo 管理管理员访问权限。请在你的服务器上实践这些概念。当你掌握了这些技能,我们将在下一章见面,届时我们将讨论与软件包管理相关的所有内容。这将是一次史诗级的学习之旅。
相关视频
-
Linux 崩溃课程 – 管理用户 (LearnLinuxTV):
linux.video/lcc-users -
Linux 崩溃课程 – 理解文件与目录权限 (LearnLinuxTV):
linux.video/lcc-perm -
Linux 崩溃课程 – usermod (LearnLinuxTV):
linux.video/lcc-usermod -
Linux 崩溃课程 – sudo (LearnLinuxTV):
linux.video/lcc-sudo -
Linux 崩溃课程 – 用户账户与密码过期 (LearnLinuxTV):
linux.video/lcc-userexp -
Linux 崩溃课程 – 管理组 (LearnLinuxTV):
linux.video/lcc-groups
进一步阅读
-
文件权限(Ubuntu 社区 Wiki):
learnlinux.link/ubuntu-perms -
用户管理(Ubuntu 文档):
learnlinux.link/sec-users
加入我们的 Discord 社区
加入我们社区的 Discord 讨论空间,与作者及其他读者互动:
第三章:管理软件包
现在你已经设置好了服务器安装,并且知道如何管理服务器上的用户,是时候来了解如何管理软件了。Ubuntu 平台提供了大量的软件,从服务器管理到游戏应有尽有。事实上,在我写这章内容的时候,Ubuntu 的仓库中已经有超过 60,000 个软件包。这是非常多的软件包,在这一章里,我们将看看如何管理它们。我们将介绍如何安装、卸载和更新软件包,以及如何使用相关的工具。
在我们讲解这些概念时,我们将涵盖:
-
理解 Linux 包管理
-
理解 Debian 包和 Snap 包的区别
-
安装和卸载软件
-
查找软件包
-
管理软件包仓库
-
备份和恢复 Debian 软件包
-
清理孤立的 APT 软件包
-
利用硬件启用更新
为了开始,让我们了解一下 Ubuntu 中软件包的分发方式,以及包管理概念的基本原理。
理解 Linux 包管理
如今,应用商店在大多数平台上都非常流行;通常,你会有一个集中位置来获取应用程序,从中安装到你的设备上。即便是手机和平板电脑也利用一个集中的软件仓库,在其中软件被策划并提供。Android 平台有 Google Play,Apple 有它的 App Store,等等。对于那些已经使用 Linux 一段时间的人来说,这个概念并不新鲜。软件仓库的概念与应用商店类似,并且早在移动电话还没有彩屏之前,Linux 社区就已经有了这个概念。
Linux 从 90 年代开始就有了包管理功能,最初由Debian推广,然后是Red Hat。软件仓库通常以镜像的形式提供,服务器会订阅这些镜像。镜像在多个地理区域都有提供,所以通常情况下,你的 Ubuntu Server 安装会订阅离你最近的镜像。这些镜像里包含了你可以安装的软件包。许多软件包依赖其他软件包,因此在 Linux 平台上有各种工具可以自动处理这些依赖关系。并不是所有 Linux 发行版都具有包管理和依赖关系解决功能,但 Ubuntu 当然具备,因为它继承了 Debian 已经打下的基础。
这些镜像中的软件包在不断变化。传统上,一个被称为软件包维护者的个人负责一个或多个软件包,并将新版本提交到软件库进行审批,最终分发到镜像中。对于 Ubuntu 的软件库来说,负责维护软件包的是一组开发人员,而不仅仅是一个维护者。大多数情况下,软件包的新版本是为了修复安全漏洞,但没有其他新功能。由于 Ubuntu 的大多数软件包都是开源的,任何人都可以查看源代码,发现问题并报告。发现漏洞后,负责的团队会审查报告并发布更新版本进行修复。这个过程非常迅速,我曾见过在漏洞报告当天就发布了修复版本。可以说,Ubuntu 的开发人员在处理安全问题方面非常专业。
软件包的新版本有时也是功能更新,这些更新发布是为了引入一些新功能,这些新功能不一定与安全漏洞有关。这可能是桌面应用程序的新版本,例如 Firefox,或者服务器软件包的新版本,例如 MySQL。然而,大多数时候,版本差异较大的新软件包会等到下一个 Ubuntu 版本发布时才会推出。原因在于,过多的变化可能导致你的服务器不够稳定,可能会出现应用程序甚至整个操作系统崩溃的情况。相比之下,已知的稳定软件包是首选;然而,由于 Ubuntu 每六个月发布一次,你不必等得太久。
具体来说,Ubuntu 版本中的功能更新必须经过审批流程,才能在默认的软件库中发布,这些功能更新被特别称为稳定发布更新(SRUs)。关于这些更新的审批流程有一个完整的过程,但总体的理解是,在一个稳定的长期支持 Ubuntu 版本中,进行大版本更新应该有充分的理由。
作为服务器管理员,你经常需要在安全性和功能更新之间做出选择。安全更新是最重要的,它允许你在面对安全漏洞时修补服务器。有时,功能更新会在你的组织中变得必要,因为决定新增的功能可能会对你有所帮助,或者可能成为当前目标所必需的。在这一章中,我们不会重点讨论安装安全更新(我们会在第二十一章,保护你的服务器中处理这部分内容),但理解为什么会有新的软件包发布给你是非常重要的。
在 Ubuntu 中,软件包管理通常非常方便,安全更新和漏洞修复定期发布。只需一条命令(我们稍后会介绍),你就可以安装一个软件包及其所有依赖项。亲自处理过手动依赖解决的我可以告诉你,自动处理依赖项是非常棒的事情。
在 Linux 服务器上维护软件包的主要好处是,通常你不需要在互联网上搜索下载软件包,因为 Ubuntu 的仓库包含了你所需的大多数软件包。随着本章的深入,你将了解管理这些软件所需的一切。
理解 Debian 和 Snap 软件包之间的区别
现在,在我们深入了解如何管理软件包之前,实际上有两种完全不同类型的软件包可供选择,你应该理解它们之间的区别。撰写本文时,Linux 中的软件管理方式正处于一个十字路口。
传统上,每个发行版都有自己的软件包格式和用于管理它们的工具。Ubuntu 使用 Debian 软件包(软件包名以 .deb 结尾)作为主要的软件包格式,这一格式是 Ubuntu 从 Debian 发行版继承而来的(Ubuntu 是从 Debian 分支出来的,这意味着它以 Debian 为基础)。Ubuntu 和 Debian 使用 apt 和 dpkg 命令来管理软件包。另一方面,CentOS 和 Red Hat 等发行版使用 RPM 软件包 及 dnf 命令来管理它们。还有其他的发行版和软件包格式,但在本书中,我们将主要讨论 Ubuntu 中的内容。首先,让我们讨论一下 Debian 软件包。
Debian 软件包
Debian 软件包一直是 Ubuntu 中的主要软件包类型,至今为止 Ubuntu 的整个版本都在使用这种类型。当你在线搜索如何在 Ubuntu 中安装某个软件时,通常你会安装一个 Debian 软件包。这些软件包之所以被称为 Debian 软件包,是因为 Ubuntu 是基于 Debian 源构建的,并且使用相同的命令来安装这些软件包。所以,尽管 Ubuntu 不是 Debian(Debian 是一个完全不同的发行版),它们主要使用相同的软件包格式。
对于新手来说,命名可能会让人感到困惑,因为如果 Ubuntu 被认为是一个与 Debian 不同的发行版,那为什么要把它的软件包称为“Debian”软件包呢?Debian 软件包的文件名以 .deb 结尾,这种软件包格式起源于 Debian。Ubuntu 并没有开发自己的软件包类型;它使用与 Debian 相同的软件包格式。因此,无论我们是在 Debian 还是 Ubuntu 中安装软件包,使用像 apt 这样的命令时,Debian 软件包都是两者使用的软件包类型。
如果你在阅读本书之前已经使用过 Ubuntu,那么很可能你已经使用过 apt 系列命令来进行包管理。Debian 包非常适合与 apt 命令配合使用,因为它们易于操作,并且能够帮助你处理依赖关系的解析。然而,它们也带来了一些挑战和重大缺点。
首先,发行版的大部分内容由 Debian 包组成。这意味着 Linux 内核、系统包、库和安全更新都是在你安装 Ubuntu Server 时安装的 Debian 包。当你安装安全更新时,实际上是安装了 Debian 包。这个问题的原因在于,你将要安装的其他软件(例如 Apache、MariaDB 等)也是 Debian 包,这可能与系统包发生冲突,尤其是当一个包需要一个与另一个包冲突的前置包时。
这可能会导致无法安装任何软件包的情况。软件包维护者通常能够避免这种情况,因此如今冲突并不常见。
然而,使用 Debian 包时,如果系统库遭到损坏,实际上所有依赖于它的软件都会出现故障。Ubuntu 开发者对此非常关注,因此你通常不会遇到问题。但事实上,这对于 Ubuntu 的维护者来说是一项巨大的工作。
另一个与 Debian 包相关的问题是软件的可用性。当一个包的新主版本发布时,通常不会在下一次发行版发布之前提供给你。这意味着,如果你需要比当前 Ubuntu 版本中提供的更新版本的 PHP、Apache 或其他软件,通常是无法获得的。你通常需要等待下一次整个发行版的更新发布。有些例外情况,例如桌面版本的 Ubuntu 中的 Firefox。正如之前所提到的,新的主要包版本是规则的例外,来自 SRU 审批过程。虽然可用经过广泛测试的成熟软件能够提供更好的稳定性,但有时你可能需要比现有版本更新的软件,这可能会促使你考虑其他来源。毕竟,你不需要为了安装更新的应用程序而重新安装新版的 Windows 或 macOS!
通用包是 Linux 的一个新概念,旨在提供一种多种发行版都能识别的单一包格式。其理念是开发者只需要编译一个包(而不是为每个发行版编译独立的包),用户则只需下载一个包,而无需考虑其选择的 Linux 发行版。下一节将讨论一种名为 Snaps 的通用包类型。
Snap 包
当前,开发者需要创建多种包类型来支持 Linux。也许他们会为 Debian 本身和 Ubuntu 创建 Debian 包,然后为 CentOS、Red Hat Enterprise Linux 和 SuSE 创建 RPM 包。虽然你可能认为需要创建两种包类型并不算太糟糕,但考虑到每个基于 RPM 的发行版需要其特定的 RPM 包,你就能理解开发者每次发布软件时,需要创建五个或更多不同包的情况会是多么繁琐。
因此,推动采用一种单一的包格式,每个发行版都可以安装,并且这种格式与系统包类型无关。这个概念被称为 通用包,其目的是拥有一个标准的包格式,可以在任何 Linux 发行版上安装。因此,开发者只需要创建一个包,就能让他们的应用程序在所有流行的发行版上运行。
Linux 社区通常使用 distro 这个词作为 distribution(发行版)的缩写。
通用包的另一个好处是,它们内置了所有依赖项,因此冲突发生的可能性较小;应用程序所需的一切都包含在一个单独的包中。这非常好,因为使用通用包时,发生包冲突的可能性几乎是不存在的。
就像 IT 行业中的一切一样,我们无法集体满足并决定哪种技术是最合适的。因此,社区中对于多种类型的通用包哪一种最合适存在争论。我在本书中不会深入政治性讨论,因为每种技术都有其优缺点。但对于我们来说,尤其是关于 Ubuntu Server,实际上只有一种适合服务器安装的技术。用于通用包的竞争技术包括 Flatpak、AppImage 和 Snap 包。
Ubuntu 的开发商 Canonical 理解开发人员和用户在使用过程中遇到的痛点,并且一直在努力改变包管理的方式。为了解决这些问题,他们开发的通用包类型被称为 Snap 包。像所有通用包一样,Snap 包(或更简洁地称为 Snaps)对底层的 Debian 包没有任何影响,且是完全独立的,从而避免了与系统包发生冲突的可能性。这使得你可以安装比原本可用版本更新的应用版本。由于 Snaps 是与底层 Debian 包独立安装的,因此没有理由不安装它们。Snap 包在各方面都表现得更好,是一个很棒的概念。唯一的缺点可能是它们是较大的包,因为它们不仅包括应用程序本身,还将所有必需的库包含在一个单独的包中。然而,它们其实并没有那么大,不会导致磁盘空间问题。这些包的大小与 macOS 或 Windows 上的典型应用程序差不多。
那么,应该选择哪一个呢?其实这取决于你的使用场景。每种通用包类型在某些方面都表现得很好,但也有其缺点。Flatpaks 和 AppImages 也是很好的技术,但对于我们的使用场景,它们的短板在于不太支持服务器(非图形用户界面,即非GUI)应用程序。这意味着,这些包类型最适合安装你通常会在桌面版 Ubuntu 上找到的应用程序,例如音乐播放器、浏览器、图形化文本编辑器等等。Snap 包则支持图形用户界面和非图形用户界面应用。由于服务器安装通常根本没有图形用户界面,这就决定了我们的选择。或许未来 Flatpaks 和 AppImages 会更好地支持非 GUI 应用,但目前,选择通用包格式的问题非常简单。
然而,现阶段,我们安装的大多数软件包将是 Debian 包,因为 Snap 包的普及有些缓慢。它们在稳步进展,但行业如何接受它们还需观察。目前,最好是在 Snap 包可用时进行评估,并根据可用性、安全性、版本和支持情况选择最合适的包类型。
在了解了 Snaps 和 Debian 包之间的区别后,让我们通过一些例子来实际管理我们服务器上的软件。我们将查看搜索可用软件包的命令,然后我们将安装和卸载它们。
安装和卸载软件
在我们开始之前,我们需要对想要安装的应用程序进行一些研究。在 Ubuntu 中,安装软件有多种方法,所以最好的方法是通过访问我们想要安装的应用程序的官方网站来查看文档。通常,Google 搜索就能找到(只要确保检查域名并访问正确的网站)。大多数软件会提供适用于各种平台的安装说明,包括 Ubuntu。通常,它会告诉你通过apt install命令下载 Debian 软件包格式。其他时候,软件可能会提供 Snap 格式,甚至是 PPA 仓库(我们将在本章后面讨论 PPA 仓库)。让我们通过查看用于安装 Debian 软件包的apt命令,来开始我们的包管理之旅。
使用 apt 管理 Debian 软件包
APT,即高级包管理工具,是一套允许我们安装、删除和更新 Debian 软件包的工具。这个工具套件由多个子命令组成,接下来我们将逐一介绍。apt命令中最常用的变体是apt install。如果你曾经阅读过在 Ubuntu 上执行某些操作的说明,可能已经运行过这个命令来安装软件包。这正是它的功能:通过命令行安装 Ubuntu 的软件包。例如,以下命令将安装openssh-server软件包:
sudo apt install openssh-server
你还可以通过用空格分隔每个软件包来一次性安装多个软件包,而不必一个个地安装。以下示例将安装三个不同的软件包:
sudo apt install <package1> <package2> <package3>
在一些书籍、博客和文章中,你可能会看到更长版本的apt命令,比如apt-get install,而不仅仅是apt install。能够将诸如apt-get install这样的命令简化为apt install是 Debian 和 Ubuntu 中apt的一个相对较新的特性。两种方法都是有效的,但未来推荐使用简化后的apt命令。
那么,当你使用apt安装软件包时,究竟发生了什么?如果你之前已经执行过这个过程,你可能已经习惯了。但通常情况下,这个过程从apt计算依赖开始。大多数软件包需要其他软件包才能正常工作,因此apt会检查确保你请求的软件包以及它的依赖项都可用。
首先,你会看到apt希望对你的服务器进行的更改的总结。以在未配置的 Ubuntu 服务器上安装apache2软件包为例,我输入以下命令:
sudo apt install apache2
当它开始安装时,我在系统上看到以下输出:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_03_01.png
图 3.1:在示例服务器上安装 Apache
即使我只要求安装apache2,apt仍然会通知我,它还需要安装apache2-bin、apache2-data、apache2-utils和libapr1(以及其他一些软件包),以满足apache2软件包的依赖。apt还建议我安装apache2-doc、apache2-suexec-pristine以及其他一些软件包,尽管它们是可选的,并不必要。你可以通过在apt install命令中添加--install-suggests选项来安装这些建议的软件包,但这并不总是一个好主意,因为它可能会安装许多你不需要的软件包。当然,你也可以通过使用apt命令单独选择性安装某些建议的软件包。
然而,大多数时候,你可能不想这样做;通常,最好将已安装的软件包保持在最小范围,只安装你需要的软件包。正如我们在第二十一章《保护你的服务器》中将讨论的那样,安装的软件包越少,服务器的攻击面就越小。
在通过apt安装或更新软件包时,你可能会看到一个消息,询问你是否愿意在过程中重启后台服务:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_03_02.png
图 3.2:软件包安装/升级过程中的服务重启提示
我们将在第七章《控制和管理进程》中讨论进程管理相关的概念,所以现在不必太关注这个问题。为了让你暂时了解一下,所有 Linux 服务器上都在后台运行服务,每个服务提供特定的功能。重启服务将确保它以最新的补丁和调整重新启动,但任何连接到你重启的服务的用户都会被断开。现在,你可以在看到这个消息时随时按回车接受默认设置。
另一个常见的通过apt安装软件包时的选项是-y选项,它假定你选择是,自动跳过确认提示,询问你是否继续。例如,我之前的输出中包括了Do you want to continue? [Y/n]这一行。如果使用了-y选项,命令将会在没有任何确认的情况下继续安装软件包。这对于急于操作的管理员来说可能很有用,尽管我个人认为除非你在脚本中进行软件包安装,否则没有必要使用这个选项。事实上,有时它可能是一个不好的主意,因为假定是可能意味着你确认了一些你之后会后悔的操作。
Ubuntu Server 的另一个巧妙的默认设置是,它会自动配置大多数软件包,使其守护进程启动并启用,以便在每次启动时自动启动。以之前提到的apache2为例,一旦你安装了该软件包,apache2服务将启动,应用程序也会自动运行。
为了方便起见,这可能看起来是个不错的主意,但并非每个人都偏好这种自动化。如我所提到的,服务器上安装的包越多,攻击面就越大,而正在运行的服务(也称为守护进程或单元)每个都可能成为恶意分子入侵的途径,前提是存在安全漏洞。因此,一些发行版在安装包时不会自动启用和启动守护进程。然而,我个人认为,你只应安装那些你打算实际使用的包,因此,如果你特意去安装像apache2这样的包,那你大概率是希望开始使用它的。
当你使用apt命令安装包时,它会在本地数据库中查找你指定的包。如果没有找到,它会抛出一个错误。有时,这个错误可能是因为该包不可用,或者apt希望安装的版本已经不存在。Ubuntu 的仓库更新速度非常快;新版本的包几乎每天都会被添加。当一个包的新版本被添加时,它的旧版本可能会被删除。因此,建议你定期更新包源。这样做很简单,只需要使用以下命令:
sudo apt update
这个命令实际上并不会更新任何包;它仅仅是与本地镜像进行对接,查看是否有新的包被添加或移除,并更新本地索引。这个命令很有用,因为如果源不更新,包的安装可能会失败。在大多数情况下,症状表现为当apt在查找某个包时无法找到时,进程会报错,而这个包通常是正常情况下可用的。
移除包也非常简单,语法与安装包非常相似;你只需要将install关键字替换为remove即可:
sudo apt remove <package>
就像使用install选项一样,你也可以同时移除多个包。以下示例将移除三个包:
sudo apt remove <package1> <package2> <package3>
如果你不仅想移除一个包,还希望删除它的配置文件,你可以使用--purge选项:
sudo apt remove --purge <package>
这不仅会移除包,还会删除它的配置目录(应用程序通常会将它们的配置文件存储在/etc的子目录中)。
所以,这就总结了使用apt管理 Debian 包的基础知识。现在,让我们继续学习如何管理 Snap 包。
使用 snap 管理 Snap 包
要管理 Snap 包,我们使用snap命令。snap命令有几个选项,允许我们搜索、安装和移除服务器或工作站上的 Snap 包。
首先,我们可以使用snap find命令配合关键字来显示与该关键字匹配的可用 Snap 包列表:
snap find <keyword>
基本上,你只需要简单地输入snap find命令并加上搜索词来查找。例如,nmap应用程序就是一个很有用的工具,尤其是当我们在管理网络时:
snap find nmap
对于nmap,该工具在 Ubuntu 的默认仓库中可用,因此你无需使用 Snap 包进行安装。然而,通常 Snap 版本会比 APT 仓库中提供的版本更新,并且具有更多功能。如果我们希望安装 Snap 版本,可以使用以下命令:
sudo snap install nmap
使用install选项时,我们需要使用sudo,因为安装包的操作会对服务器进行更改。而对于简单的find命令,则可以省略sudo。
现在我们已安装了nmap,可以使用which命令检查nmap二进制文件的位置。我们可以使用which命令查找命令的二进制文件位置——如果安装了相应的包,它将显示二进制文件的路径。如果命令不可用,which命令将没有输出。因此,如果我们运行以下命令,我们现在应该能看到该二进制文件的路径打印到屏幕上:
which nmap
这将返回以下输出,显示nmap的 Snap 版本是从一个特殊位置运行的:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_03_03.png
图 3.3:检查 nmap 二进制文件的位置
现在,当我们运行nmap时,实际上是从/snap/bin/nmap运行的。如果我们通过apt安装nmap,它将从/usr/bin/nmap运行。如果我们还从 Ubuntu 的 APT 仓库安装了nmap工具,那么我们可以随时通过指定要运行的二进制文件的完整路径来运行任意一个,因为 Snap 包与 APT 包是独立的。例如,如果我们通过snap和apt都安装了nmap,我们可以通过运行/usr/bin/nmap来运行 Ubuntu 的版本,通过运行/snap/bin/nmap来运行 Snap 版本。
移除已安装的 Snap 包很容易。我们只需使用remove选项:
sudo snap remove nmap
如果我们执行该命令,那么nmap(或我们指定的任何 Snap 包)将从系统中移除。
要更新一个包,我们使用refresh选项,并指定要更新的包名:
sudo snap refresh <package>
使用该命令,包将更新到最新版本。如果进一步操作,我们还可以尝试使用相同的命令更新服务器上的所有 Snap 包(无需指定包名):
sudo snap refresh
正如你所看到的,管理 Snap 包相当简单。使用snap命令套件,我们可以从服务器或工作站安装、更新或移除包。snap find命令允许我们查找新的 Snap 包以供安装。也许随着技术的发展,我们将会比安装 Debian 包更多地安装 Snap 包,但这仍有待观察。现在,有两个安装新软件的选择是一个不错的优势。
除了能够安装包之外,还有一些额外的技巧和注意事项,帮助我们搜索包。毕竟,如果你不知道有哪些包可用,你是无法安装的。我们将在下一节探讨如何搜索包。
搜索包
不幸的是,Ubuntu Server 中软件包的命名约定并不总是显而易见。更糟糕的是,即使是同一软件,不同的发行版中的软件包名称也往往大相径庭。尽管本书和其他在线教程会列出安装软件的确切步骤,但如果你独立操作,而不知道要安装的软件包的名称,那就没什么帮助了。在本节中,我将尽量揭开搜索软件包的神秘面纱。
在上一节中,我们已经讲解了如何搜索 Snap 软件包,所以这里就不再重复了。APT 工具套件也提供了搜索软件包的功能,使用的命令是apt search。我们可以使用以下命令,通过提供关键字来搜索软件包:
apt search <search term>
该命令的输出将显示与搜索条件匹配的软件包列表,包括它们的名称和描述。例如,如果你想安装 Apache 的 PHP 插件,但还不知道关联的包名,以下命令可以帮助你缩小范围:
apt search apache php
在输出中,我们会看到一个不止一项的软件包列表,但我们可以从输出中的软件包描述中推测出libapache2-mod-php很可能是我们需要的那个。然后,我们可以像平常一样使用apt安装它。
如果我们不确定这是否是我们想要的真正软件包,我们可以使用apt-cache show命令查看关于这个(或任何其他)软件包的更多信息:
apt-cache show libapache2-mod-php
该命令的输出在以下截图中进行了展示:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_03_04.png
图 3.4:展示 Debian 软件包的信息
使用这个命令,我们可以看到关于我们考虑安装的软件包的更多细节。在这个例子中,我们了解到libapache2-mod-php软件包还依赖于 PHP 本身,这意味着如果我们安装这个软件包,我们不仅会得到 PHP 插件,还会安装 PHP 本身。
另一种搜索软件包的方法(如果你有可用的网页浏览器)是访问Ubuntu 软件包搜索页面:packages.ubuntu.com/,你可以通过该页面在其数据库中浏览当前支持版本的 Ubuntu 所有的软件包。虽然在工作中你不总是能访问网页浏览器,但当你能够使用时,这是一个非常有用的方式来搜索软件包、查看它们的依赖关系、描述等信息。
使用 apt search 命令以及 snap find 命令,应该能帮助你在确定要安装的包名时走得更远。软件包管理技能需要随着时间积累,因此不要指望立即就能知道应该安装哪些包。如果有疑问,只需进行 Google 搜索,研究你要运行的软件的文档,学习如何在 Ubuntu 上安装它。通常,安装说明会引导你使用正确的命令。本书中我们将讲解的示例,将引导你完成 Ubuntu Server 最常见的使用案例。
在这一点上,我们应该已经对不同类型的软件包及其管理方式有了清晰的理解。然而,有时我们需要在服务器上运行一些软件,而这些软件在标准仓库中没有可用的包。因此,在下一部分,我们将学习如何添加额外的仓库,从中安装软件。
管理软件包仓库
通常,Ubuntu 自带的仓库已经足够满足大多数通过 APT 安装的 Debian 包。但偶尔,你可能需要安装一个额外的仓库,以便使用 Ubuntu 通常不提供的软件,或者是比你通常能获取到的软件包版本更新的版本。添加额外的仓库允许你订阅额外的软件源,并像从其他源一样安装软件包。
然而,添加额外的仓库应当被视为最后的手段。当你安装额外的仓库时,实际上是在将你组织的服务器交给该仓库的作者信任。尽管我亲眼未曾见过这种情况,但理论上,软件作者可能会在软件包中加入后门或恶意软件(无论是有意还是无意的),并通过软件仓库提供给其他人。因此,你应该仅添加那些你有理由信任的来源的仓库。
此外,有时会发生仓库的维护者干脆放弃维护该仓库并消失。我亲眼见过这种情况。在这种情况下,仓库可能会下线(这会在apt事务中显示错误,表示无法连接到仓库),更糟糕的是,仓库保持在线,但从未提供安全更新,导致你的服务器易受到攻击。有时,你可能别无选择。你需要一个特定的应用程序,而 Ubuntu 默认并未提供。你唯一的选择可能是从源代码编译一个应用程序或添加一个仓库。这个决定由你做,但尽可能时要考虑安全问题。如果有疑虑,除非这是获取你所需内容的唯一方法,否则避免添加仓库。如果你添加了一个额外的仓库,且长时间没有看到来自该仓库的包更新,考虑这是一个红旗,调查该仓库是否已被弃用。已弃用的仓库应被移除,替换为其他可用仓库。
添加额外的仓库
软件仓库本质上是一个存储在文本文件中的 URL,存储在两个地方之一。主 Ubuntu 仓库列表存储在/etc/apt/sources.list中。在该文件中,你会找到多个仓库,供 Ubuntu 的包管理器拉取包。此外,扩展名为.list的文件会从/etc/apt/sources.list.d/目录中读取,并且在你使用apt时也会被使用。我将演示这两种方法。
这两个文件中的典型仓库行会类似于以下内容:
deb http://us.archive.ubuntu.com/ubuntu/ jammy main restricted
每行的第一部分将是deb或deb-src,指示apt命令是否会在那里找到二进制包(deb)或源代码包(deb-src)。接下来是apt用来访问仓库的实际 URL。在第三部分,我们有发行版的代号;在这个例子中,它是jammy(指的是 Ubuntu 22.04 的代号,Jammy Jellyfish)。
如果你还不知道,每个 Ubuntu 发行版的代号都是基于一种动物。通常,所选的动物会比较稀有。例如,上一个 LTS 版本的代号是“fossa”,它是一种来自马达加斯加的动物,长得像猫,但耳朵是弯曲的。这次的代号是“jellyfish”,我相信大多数读者已经熟悉这种动物。
接下来,每个仓库行的第四部分是Component,它表示该仓库是否包含自由和开源的软件,并且是否得到 Canonical(负责 Ubuntu 开发的公司)的官方支持。该组件可以是main、restricted、universe或multiverse。带有main组件的仓库包含官方支持的软件,这通常意味着这些软件包有源代码可用,因此 Ubuntu 开发者能够修复 bug。标记为restricted的软件仍然得到支持,但可能存在有问题的许可。universe软件包由社区提供支持,而不是 Canonical 本身。最后,multiverse软件包包含既不自由也不受支持的软件,使用这些软件需要自行承担风险。
正如您从查看服务器上的/etc/apt/sources.list文件中看到的那样,一个仓库行可以包含来自多个组件的软件。每个仓库 URL 可能包含来自多个组件的软件包,而您区分它们的方法是只订阅该仓库所需的组件。在我们之前的示例中,仓库行同时包括main和restricted组件。这意味着,在这个特定示例中,apt工具将从该仓库索引自由(main)和非自由(restricted)软件包。
您可以将新的仓库添加到/etc/apt/sources.list文件中(它仍然可以正常工作),但这通常不是首选方法。正如我之前提到的,apt会扫描/etc/apt/sources.list.d/目录,查找以.list扩展名结尾的文本文件。这些文本文件的格式与/etc/apt/sources.list文件相同,即每行包含一个额外的仓库,但这种方法使您能够通过创建文件来轻松添加新仓库,也可以通过删除该文件来删除仓库。
这种方法比直接编辑/etc/apt/sources.list文件更安全,因为直接编辑时总有可能打错字,导致您无法从甚至官方仓库下载软件包。
此外,您可能需要为新的仓库安装GNU 隐私保护(GnuPG)密钥,但此过程因应用程序而异。通常,文档会概述整个过程。此密钥的作用是保护您,确保您正在安装签名的软件包。并非所有开发者都以这种方式保护他们的应用程序,但这绝对是一种值得做的好事。
一旦您在服务器上安装了仓库(以及可能的密钥),您需要运行以下命令来更新软件包索引:
sudo apt update
如本章前面所提到的,这个命令更新你本地的缓存,显示远程服务器上有哪些可用的软件包。APT 只知道它数据库中的软件包,所以你需要在使用这个命令之前同步它,这样才能实际安装仓库中的软件。
添加个人软件包存档
在 Ubuntu 平台上,还有另一种类型的仓库,称为个人软件包存档(PPA)。PPA 本质上是 APT 仓库的另一种形式,你仍然可以像平常一样使用apt命令与它们的包进行交互。PPA 通常是非常小的仓库,通常只包含一个应用程序,服务于一个特定的用途。可以把 PPA 看作是迷你仓库。当一个厂商没有提供自己的仓库,而只将应用程序以源代码的形式提供,用户需要手动下载、编译并安装时,PPA 非常常见。通过 PPA 平台,任何人都可以从源代码编译一个包,并轻松地将其提供给其他人下载。
PPAs 和常规仓库一样,也存在相同的安全问题(你需要信任供应商等),但考虑到软件通常根本没有经过审计,它们的安全性可能更差。此外,如果 PPA 服务器出现故障,你将停止收到从中安装的应用程序的安全更新。只有在确实需要时,才使用 PPA。
有一个可能非常有吸引力的 PPA 用例,特别适用于那些标准仓库无法很好处理的服务器平台,尤其是在软件版本管理方面。正如我之前提到的,像 PHP 或 MySQL 这样的主要服务器组件,可能会随着每次 Ubuntu Server 的发布而锁定在特定的主版本中。如果你需要使用 Ubuntu Server,但所需的应用程序版本在你组织要求的版本中不可用时,该怎么办?过去,你基本上只能在发行版和软件包之间做出选择,一些组织甚至会使用不同的 Linux 发行版,仅仅是为了满足在特定版本下运行特定应用程序的需求。你当然可以从源代码编译应用程序(假设源代码是可用的),但这样会带来额外的麻烦,因为你需要负责自己编译新的安全补丁,每当有新补丁发布时。PPAs 可以让你访问那些通常在默认仓库中不可用的应用程序,和/或访问比通常提供的版本更新的软件包。这使得你,作为服务器管理员,能够选择最适合自己目标的方式。
PPAs 通常通过apt-add-repository命令添加到你的服务器中。语法通常是使用apt-add-repository命令,后接冒号,再跟上用户名,最后是 PPA 名称。以下命令是一个假设的示例:
sudo apt-add-repository ppa:username/myawesomesoftware-1.0
要开始这个过程,你可以访问 Ubuntu 的 PPA 网站,网址是launchpad.net/ubuntu/+ppas。在那里,你可以在可用的 PPA 中进行搜索。
在将 PPA 添加到服务器之前,最好先研究一下它是否得到了良好的维护。例如,如果 PPA 很长时间没有更新软件包,那么这就值得关注——大多数软件包都会有安全修复。如果一个软件包没有定期更新,已经变得“过时”,那么最好避免使用它,因为它可能会带来更多的负面影响。
一旦你找到一个想要添加到服务器的 PPA,你可以通过找到 PPA 的名称,然后使用 apt-add-repository 命令将其添加到你的服务器中。
然而,你应该查看一下 PPA 的页面,以防有不同的说明。大部分情况下,apt-add-repository 命令应该能够正常工作。每个 PPA 通常都有一套附带的说明,因此这里不需要进行猜测。
那么,apt-add-repository 命令到底做了什么呢?说实话,它并不特别神奇。当你安装 PPA 时,它本质上是自动化了将一个仓库文件添加到 /etc/apt/sources.list.d 目录并安装其密钥的过程。因此,你可以通过简单地删除其文件来卸载 PPA。
如果谨慎使用,PPA 是一个非常有用的功能。PPA 为 Ubuntu 提供了一种灵活的方式来添加通常不会提供的额外软件,尽管你需要关注这些仓库,确保它们在出现漏洞时得到妥善修补,并且仅在绝对必要时使用。始终优先选择来自 Ubuntu 默认仓库以及 Snaps 的软件包,但 PPA 为你提供了另一种选择,以防你在其他地方找不到所需的软件。
在你维护服务器一段时间后,或者完成了为特定目标设置服务器的工作,你会安装大量的软件包以适应其目的。导出已安装的软件包列表可以让你在需要时更容易地重建服务器,下一部分我们将讨论一种实现方法。
备份和恢复 Debian 软件包
随着你维护服务器,已安装的软件包列表会不断增加。如果因为某些原因,你需要重建服务器,你需要精确复现之前安装的所有内容,这可能会非常麻烦。通常建议你通过变更控制流程记录所有对服务器的修改,但至少,跟踪已安装的软件包是绝对必须的。在某些情况下,服务器可能只包含一两个额外的软件包来实现目标,但在其他情况下,你可能需要一个特定的软件和库组合才能让服务器像之前一样工作。幸运的是,dpkg 命令允许我们导出和导入要安装的软件包列表。
要导出已安装包的列表,我们可以使用以下命令:
dpkg --get-selections > packages.list
此命令将把包选择列表导出到一个标准文本文件。如果你打开它,你将看到已安装包的列表,每行一个。导出的文件中的典型行如下所示:
tmux install
使用这个列表,我们可以将选择的包重新导入到服务器中,如果我们需要重新安装 Ubuntu Server,或者导入到一个新服务器中,使其执行类似的功能。首先,在管理任何包之前,我们应该更新索引:
sudo apt update
接下来,我们需要确保安装了dselect包。dselect包在管理 Debian 包时提供了额外的功能。它的细节超出了本章的范围,但对于我们当前的目标,我们可以使用它从导出的列表中恢复包。在你的命令行提示符下,键入which dselect,你应该会看到类似如下的输出:
/usr/bin/dselect
如果你没有看到输出,你需要使用apt安装dselect包:
sudo apt install dselect
完成后,你可以导入之前保存的包列表,并重新安装服务器上缺失的包。以下命令将完成此过程:
sudo dselect update
sudo dpkg --set-selections < packages.list
sudo apt-get dselect-upgrade
通常,我们现在使用apt而不是apt-get,但奇怪的是,dselect-upgrade命令仅在apt-get下有效。
在你执行了这些命令后,包列表中包含但尚未安装的包将在你确认更改后安装。这种方法可以让你轻松地恢复之前在服务器上安装的包,如果因为某些原因需要重建服务器时,也可以为新服务器的配置提供相似的设置。
现在我们已经了解了如何导出和导入已安装包的列表,我们还可以看看如何清理不需要的包,确保我们的服务器尽可能不含多余的臃肿。
清理孤立的 apt 包
当你在服务器上管理包时,最终会遇到这样一种情况:系统中有一些已安装但没有被任何东西需要的包。这种情况发生在移除具有依赖关系的包时,或者安装包的依赖关系发生变化时。你可能还记得,当你安装一个需要其他包的包时,这些依赖包也会一并安装。但是,如果你删除了那个需要它们的包,这些依赖包不会被自动移除。
为了说明这种情况,如果我从我的一台服务器上移除apache2包,当我尝试安装其他东西时,会看到以下额外信息:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_03_05.png
图 3.5:显示孤立包的输出
在这个例子中,我移除了apache2(这是在截图前完成的),然后我安装了tmux。我尝试安装的包是任意的;重要的是你在截图中看到的文字,那里写着The following packages were automatically installed and are no longer required。基本上,如果你的系统上有孤立的包,Ubuntu 会在你使用 APT 工具套件时定期提醒你。在这种情况下,我移除了apache2,因此所有为了支持apache2包而安装的依赖包都不再需要。
在截图中,我看到了一些 APT 认为我不再需要的包列表。它可能是对的,但我们需要进一步调查。按照输出中的指示,我们可以以root身份或使用sudo命令来移除这些包。这是保持已安装包清洁的好方法,但需要小心使用。如果你最近刚刚移除了某个包,手动清理可能是安全的。
虽然我们还没有讲解更新包的内容(我们将在第二十一章,保护你的服务器中进行讲解),但以后可能会遇到一种情况,你的内核版本过旧,可以通过autoremove选项进行清理。这些内核包会以与前面截图中显示的孤立包相同的方式显示,但名称中会包含linux-image。处理这些时要小心;在你验证新安装的内核工作正常并且服务器没有出现任何不必要或意外的行为之前,绝不要移除过时的内核。通常来说,当涉及到内核包时,你可能会想至少等一周才执行apt autoremove。
对于其他包,通常可以安全地通过apt autoremove命令移除,因为它们大多数是作为另一个已不在系统中的包的依赖而安装的。然而,在移除这些包之前,请务必仔细检查你是否真的想要移除它们。如果你不小心移除了某个包,可以随时重新安装它,并且作为附加好处,如果你重新安装了一个标记为自动移除的包,它以后不会再在输出中显示为孤立包。
如你所见,Ubuntu 在管理软件方面有许多选项,作为管理员,你可以选择最适合你的目标的方法。还有一种特殊类型的更新可以提高硬件支持,适用于硬件比你的 Ubuntu 版本更新的情况,或者为以前没有支持的硬件提供兼容性。
利用硬件启用更新
Linux 行业的一个问题是硬件支持。在各种 Linux 发行版中,这是一个问题,因为你可能会遇到这样的情况:你正在使用一台发布时配备了最新处理器和芯片组的服务器(甚至是台式机或笔记本),但你的 Linux 发行版还没有发布包含更新驱动程序的新版,无法支持它。与 Windows 等平台不同,硬件驱动通常直接集成在 Linux 内核中。所以,如果你使用的是旧版(该版本包含较旧的内核),你可能就无法获得硬件支持,直到下一个 Linux 发行版发布。
幸运的是,Ubuntu 想出了一个系统来解决这个问题,这也是它与其他发行版不同的许多优点之一。Ubuntu 提供了一组称为硬件启用(HWE)堆栈的更新,这是长期支持(LTS)版本的独有功能。我们在第一章、部署 Ubuntu 服务器中讨论过 LTS 版本和常规版本的区别。HWE 更新是可选的,但它们为当前 LTS 版本发布之后的较新硬件提供了额外的兼容性。新的 HWE 堆栈通常包括新的内核和驱动包。然而,由于驱动程序通常是直接集成到 Linux 内核中的,因此你还将获得对新视频卡以外的其他硬件(例如新发布的网卡)的支持。
HWE 更新通常从 LTS 版本的第二个点发布开始提供,然后每次随后的点发布中都会提供,直到下一个 LTS 版本发布。新的兼容性堆栈是从最新的非 LTS 版本回溯过来的,这意味着你可以在保持 LTS 版本的同时,享受最新非 LTS 版本的兼容性。例如,当 Ubuntu 20.04.2 在 2021 年 2 月 4 日发布时,它包含了从 Ubuntu 20.10 回溯过来的内核和驱动包。这意味着你可以在保持 20.04 LTS 的同时,利用 Ubuntu 20.10 的较新硬件支持,并享受 LTS 版本的更长支持周期。
截至撰写时,Ubuntu 22.04 是最新的 LTS 版本,因此尚未添加硬件启用。根据历史经验,硬件启用可能会像以往版本一样在 22.04 LTS 中展开。如果是这样,那么更新的包将在 Ubuntu 22.04.2 发布后提供。
一旦新的硬件启用堆栈(HWE)可用,你可以选择安装它,或者继续使用原来的 22.04 内核而不做任何更改。对于 Ubuntu 桌面版来说,喜欢玩电脑游戏的人会从这些更新中受益匪浅,因为新的驱动程序能在显卡方面提供更好的性能,并且支持更新的游戏硬件。就本书的范围而言,新的硬件启用对我们来说的好处比桌面用户少一些。原因是,如果你的服务器运行正常没有问题,那么实际上没有必要安装新的硬件启用堆栈,除非更新的内核包含你希望利用的新特性。
有时会遇到一个让人沮丧的情况,那就是 Ubuntu 报告说没有可用的网络卡,尽管你实际上有一张。通常在购买新服务器,特别是包含最新硬件的物理服务器时,我遇到这种情况最为频繁。当你启动一台崭新的服务器时,却发现根本无法建立网络连接,这种情况非常让人沮丧。这是需要更新兼容性堆栈的经典症状。也许你的网络卡是在当前 Ubuntu 版本发布之后才发布的。这种情况正好说明了硬件启用更新存在的原因,也解释了为什么你迟早可能需要使用它们。
如果你没有选择硬件启用更新,你的服务器将始终保持与首次发布你所安装的 LTS 版本时相同的硬件启用(内核、驱动程序等)。在这种情况下,只有在安装新的安全更新时,才会更新内核和相关软件包。稍后,你可以手动选择是否安装硬件启用更新。通常,只有当你向物理服务器添加了需要新内核的新硬件时,才会这样做。如果你的服务器运行正常,并且没有添加新硬件,那么可能没有必要安装新的硬件启用堆栈。
如果你决定使用这些更新,有两种方法可以实现。你可以在安装 Ubuntu Server 时选择更新的硬件启用堆栈,或者手动安装所需的软件包。在撰写本文时,Ubuntu 22.04 刚刚发布,因此是否会在 22.04.2 发布时提供更新的软件包尚未可知,但鉴于 Ubuntu 的历史,这种可能性很大。以下截图展示了 Ubuntu 20.04.4 安装程序的第一个界面。假设 Ubuntu 22.04 按照相同的计划进行,届时你很可能会看到类似下图所示的选项,一旦 22.04.2 发布:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_03_06.png
图 3.6:Ubuntu 20.04.4 安装程序的主菜单
请注意使用 HWE 内核安装 Ubuntu Server选项。如果你选择此选项,那么你的 Ubuntu Server 安装将立即包含新的 HWE 软件包。
如果你已经安装了 Ubuntu 服务器,并且希望之后安装 HWE 更新,可以通过终端进行安装。例如,在 Ubuntu 20.04 中,你可以使用以下命令切换到 HWE 内核:
sudo apt install --install-recommends linux-generic-hwe-20.04
当 Ubuntu 22.04 发布更新的 HWE 堆栈时,很可能会使用类似的命令来安装它。如果你需要更新的 HWE 内核,请在那个时候参考 Ubuntu 文档页面中的说明。
概述
在本章中,我们对包管理的世界进行了快速入门。正如你所看到的,Ubuntu 服务器提供了大量的软件包和各种工具,我们可以利用它们来管理这些包。我们从讨论 Ubuntu 的包管理如何工作开始,接着介绍了安装软件包、搜索软件包和管理仓库的过程。同时,我们还涉及了 Snap 包,这是一种较新的技术,旨在增强 Ubuntu 上的软件分发。
在第四章,导航与基础命令中,我们将探讨一些基础命令,用于导航 Linux Shell,了解文件系统布局等。
相关视频
- Linux 快速入门 - APT (LearnLinuxTV):
linux.video/lcc-apt
进一步阅读
-
LTSEnablementStack (Ubuntu wiki):
learnlinux.link/lts-es -
Ubuntu 服务器指南:
ubuntu.com/server/docs
加入我们的 Discord 社区
加入我们社区的 Discord 频道,与作者和其他读者讨论:
第四章:导航和基本命令
在我们旅程的这个阶段,我们已经覆盖了许多内容——我们学会了如何部署 Ubuntu 服务器,如何管理用户,最近还学会了如何管理软件包。在继续之前,我们应该花点时间学习一些重要的概念和命令,这些内容将帮助我们建立更多的基础知识,这些知识将对本书的后续部分乃至更远的未来有所帮助。这些基础概念包括用于浏览 shell、Linux 文件系统结构、查看文件内容甚至查看日志文件的核心 Linux 命令。具体来说,本讨论将包括:
-
学习基本的 Linux 命令
-
理解 Linux 文件系统结构
-
查看文件内容
-
查看应用程序日志文件
让我们花点时间学习一些基本的 Linux 命令,这些命令将帮助我们增强命令行技能。
学习基本的 Linux 命令
在命令行上建立坚实的能力至关重要,这将有效地赋予任何系统管理员或工程师超能力。我们的新能力虽然无法让我们一跃而过高楼,但绝对能让我们像命令行忍者一样执行终端命令。虽然我们在这一部分不能完全掌握使用命令行的艺术(那只能通过多年的经验积累),但我们一定会变得更加自信。
首先,让我们来谈谈如何在 Linux 文件系统中从一个位置移动到另一个位置。具体来说,所谓“Linux 文件系统”指的是你在 Ubuntu 安装中默认的各种文件夹(也称为“目录”)的结构。Linux 文件系统包含许多重要的目录,每个目录都有其指定的用途,我们将在本章后续部分详细讨论这些目录。
在我们进一步探索之前,我们需要先学习如何从一个目录切换到另一个目录。我们将在本节中介绍的第一个与浏览文件系统相关的命令将帮助你明确当前所在的目录。为此,我们有 pwd 命令。它代表 print working directory,用于显示你当前所在的文件系统位置。如果你运行它,你可能会看到如下输出:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_04_01.png
图 4.1:查看当前工作目录
在这个例子中,当我运行pwd时,输出告诉我当前工作目录是/home/jay。这个目录就是你的家目录,默认情况下,每个用户都有一个(正如我们在第二章,管理用户与权限中讨论的)。默认情况下,所有与你的用户账户相关的文件都会存储在这里。当然,你可以在任何你想要的位置创建文件,即使是在家目录之外,如果你有权限或者使用sudo。但是,仅仅因为你可以这样做,并不意味着你应该。正如你将在本章中学到的那样,Linux 文件系统几乎为所有内容都有一个指定的位置。但你的家目录,位于/home/<用户名>,是属于你的。你拥有它,你控制它——它是你在服务器上的家。在 2000 年代初期,带图形用户界面的 Linux 安装系统甚至通过一个房子图标来表示你的家目录。
通常,你在家目录中创建的文件,其权限字符串大致如下:
-rw-rw-r-- 1 jay jay 0 Jul 5 14:10 testfile.txt
我们已经讨论了权限,并且在第二章,管理用户与权限中讲解了如何读取权限字符串,但你可以看到,默认情况下,你在家目录中创建的文件由你自己、你的用户组拥有,并且可以被三类用户(用户、组、其他)读取。
要更改当前目录并导航到另一个目录,我们可以使用cd命令并指定目标路径:
cd /etc
现在,我还没有查看文件和目录布局,所以我随便选择了/etc目录。前面的斜杠表示文件系统的开始。稍后会详细讲解。现在,我们在/etc目录中,并且我们的命令提示符也发生了变化:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_04_02.png
图 4.2:切换目录后,命令提示符和 pwd 命令的输出
正如你可能猜到的,cd命令代表切换目录,它用于在导航时将当前工作目录从一个目录切换到另一个目录。例如,你可以使用以下命令返回家目录:
cd /home/<user>
实际上,有多种方法可以返回家目录,以下截图展示了其中几种方法:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_04_03.png
图 4.3:其他进入家目录的方法
第一个命令,cd -,其实并不专门与家目录有关。它是一个巧妙的技巧,可以让你返回到你最近所在的目录。对我来说,cd -命令把我带回到我之前所在的目录,而那个目录恰好是/home/jay。第二个命令,cd /home/jay,直接把我带到了家目录,因为我指定了完整路径。最后一个命令,cd ~,也把我带到了家目录。这是因为~是家目录路径的简写,因此你不需要每次都输入完整路径/home/<user>,只需使用~来代替。
另一个基本命令是ls。ls命令列出当前工作目录的内容。我们可能还没有在主目录中存放任何内容。但是,如果我们通过执行cd /etc(就像之前做的那样)导航到/etc,然后执行ls,我们会看到/etc目录中有许多文件。试试看吧:
cd /etc
ls
实际上,我们并不需要改变工作目录到/etc来列出内容。我们可以直接执行以下命令:
ls /etc
更好的是,我们可以运行:
ls -l /etc
这将以长列表的形式显示内容,我认为这样更容易理解。它会将每个目录或文件条目显示在单独的一行上,并附上权限字符串。但你可能已经记得ls和ls -l,这两者在第二章,用户与权限管理中提到过,所以我在这里不再详细说明。那例子中ls命令的-l部分被称为参数。我并不是指 Linux 社区中关于哪个命令行文本编辑器最好(无疑是 Vim)的永无休止的辩论,而是指在 Shell 命令中,参数可以让你覆盖默认设置,或者以某种方式为命令提供选项,就像在这个例子中,我们将ls的输出格式化为长列表。
rm命令是我们在第二章,用户与权限管理中提到的另一个命令,当时我们讨论了手动删除已从系统中移除的用户的主目录。因此,到现在为止,你可能已经很熟悉这个命令及其功能(它用于删除文件和目录)。这是一个潜在危险的命令,因为你可能会不小心删除不该删除的内容。在那一章中,我们使用了以下命令来删除用户dscully的主目录:
rm -r /home/dscully
如你所见,我们使用-r参数来改变rm命令的行为,默认情况下,rm不会删除目录,只会删除文件。-r参数指示rm递归地删除一切,甚至是目录。-r参数还会删除路径中的子目录,因此你在使用此命令时一定要小心。正如我在书中早些时候提到的,如果你与rm一起使用sudo,你甚至有可能删除整个 Ubuntu 系统!
rm提供的另一个选项是-f参数,代表force(强制),它告诉rm在删除前不要进行确认提示。这个参数不常用,它的使用案例超出了本章的范围。但请记住它的存在,万一需要的话。
另一个值得了解的基础命令是touch,它实际上有两个用途。首先,假设你在当前工作目录中有权限,touch命令将创建一个空文件(如果文件尚不存在的话)。其次,touch命令将更新文件或目录的修改时间(如果它已经存在的话):
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_04_04.png
图 4.4:使用touch命令进行实验
为了说明这一点,在相关的截图中,我运行了几个命令。首先,我运行了以下命令来创建一个空文件:
touch testfile.txt
之前那个文件并不存在,所以当我之后运行ls -l时,它显示了新创建的文件,大小为 0 字节。接下来,我在一分钟后再次运行了touch testfile.txt命令,你可以在截图中看到,修改时间从15:12变成了15:13。
关于查看文件内容,我们将在本章稍后讨论。我们肯定还需要学习更多的命令,以建立我们的基础。但现在,让我们暂时从基础概念中休息一下,来更好地理解 Linux 文件系统布局,这对我们稍后将要学习的一些命令来说是必不可少的。
理解 Linux 文件系统布局
如我之前提到的,Linux 安装中的每个目录都有一个指定的用途。这不是硬性规则,而是关于某些内容应该放置位置的强烈推荐。
你当然可以不遵循这些推荐;最终,你对你的安装拥有完全的控制权。但是,如果你习惯将文件放在奇怪的地方,可能会惹恼你的同事。在这一节中,我们将介绍最常见的目录并讨论它们的用途。
在 Linux 世界中,文件系统一词本身可能会让人感到困惑,因为它可以指代两个不同的事物——默认的目录结构,以及在格式化磁盘如硬盘或闪存驱动器时选择的实际文件系统(如 ext4、XFS 等)。在本节中,我们将快速了解 Linux 文件系统,重点关注默认的目录结构。
在 Linux 中(Ubuntu 使用 Linux 内核和相关工具,因此它是 Linux 的一个发行版),文件系统从一个单独的斜杠/开始。这被认为是文件系统的起点,目录和子目录从这里分支出来。例如,考虑/home目录。这个目录存在于文件系统的根级别,你可以通过它以斜杠开始来看到这一点。我的系统上的主目录是/home/jay,这意味着它是home目录中的jay目录,而这个目录位于文件系统的起始位置。
起初可能会感到困惑,但一旦习惯了,就会变得非常合乎逻辑。如果您熟悉 Microsoft Windows,那么您可以将 / 技术上视为 C: 驱动器。实际上比这复杂一些,但如果我们忽略一些怪癖,这个比较是成立的。为了更好地理解这一点,请在服务器上对几个目录执行 ls 命令。如果您执行 ls /,您将看到文件系统根目录下的所有目录。
在结果中您会看到 home 目录,以及许多其他目录。对于那些更喜欢视觉表现的人,以下截图展示了一个文件系统示例:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_04_05.png
图 4.5:典型 Linux 文件系统部分的图表
正如您所见,Linux 文件系统类似于一棵树,有一个主干向外延伸,目录之间相互分支。这个默认的目录结构是 文件系统层次结构标准(FHS)的一部分,它是一组指南,定义了目录结构的布局方式。该规范定义了目录的名称、位置以及用途。发行版有时会违反这里的一些定义,但大部分时间还是遵循得比较严格的。这就是为什么您可能会在 Ubuntu 以外的 Linux 发行版上看到非常相似(如果不是完全相同)的目录结构。
那么,这为何重要呢?正如我所提到的,每个目录通常都有其用途。关于默认布局有时会有一些争议,并且偶尔会有一些更改。但就 Linux 而言,文件系统布局的更改频率通常低于其他方面。
FHS 的完整详细解释将非常庞大,但在本章末尾我包含了该规范的链接,如果您决定进一步了解它,可以查阅。然而,有一些目录确实是您必须了解的。以下是一些比较重要的。
| 目录 | 用途 |
|---|---|
/ |
文件系统的开始;所有目录都位于其下 |
/etc |
系统范围的应用配置 |
/home |
用户主目录 |
/root |
root 用户的主目录(root 用户在 /home 下没有目录) |
/media |
可移动媒体,如闪存驱动器 |
/mnt |
长时间挂载的卷 |
/opt |
额外的软件包(某些程序安装在这里,不太常见) |
/bin |
用户必需的二进制文件(如 ls、cp 等) |
/proc |
用于操作系统级组件的虚拟文件系统 |
/usr/bin |
大多数用户命令 |
/usr/lib |
库文件 |
/var/log |
日志文件 |
/etc目录值得额外讨论,因为你肯定会频繁地使用它。正如前表所述,这个目录包含了应用程序的配置文件,这些配置文件是系统范围内需要被遵守的。例如,如果你在服务器上运行 OpenSSH 守护进程,默认情况下你会监听 22 号端口的连接。(别担心,我们会在后续章节中进一步讨论这些具体概念。)OpenSSH 服务器的配置文件位于/etc/ssh目录中。由于 OpenSSH 是一个作为后台进程在系统上运行的服务,它的配置文件存储在该目录中的sshd_config文件内。如果你删除了提供 OpenSSH 的包,配置文件仍然会保留(默认情况下,删除包并不会删除配置文件),所以如果你稍后重新安装 OpenSSH,下次会有相同的配置。如果我们希望在卸载软件包时同时删除配置文件,可以使用apt remove命令的--purge选项,正如我们在第三章《管理软件包》中所看到的那样。
本书中会随着主题的推进讨论其他重要的目录。如果现在某些内容让你感到困惑,不用担心;随着时间的推移,你会理解的。这里的关键点是,系统中有很多目录,每个目录都有其特定的用途。如果你想了解某个特定目录的用途,可以查阅 FHS。如果你想知道应该在服务器上放置某些文件的位置,同样也可以查阅 FHS。但再强调一次,不必过于担心去查阅本书以外的资料,因为我们会在后续章节中覆盖所有必要的内容。
现在我们对默认的文件系统布局和一些常见目录的用途有了更好的理解。在下一节中,我们将探索如何查看存储在这些目录中的文件内容。
查看文件内容
Linux 文件系统包含许多目录和文件。对于文件,我们需要学习如何读取和操作它们,以完善我们的知识。我们将在下一章中覆盖更多关于文件管理的话题。现在,我们可以通过查看如何查看现有文件的内容来获得一些帮助。
我们可以使用cat命令将文件内容打印到屏幕上,并提供文件名作为参数。例如,以下命令可以用来查看当前工作目录中testfile.txt的内容,这是我们在本章讨论touch命令时创建的文件。虽然这个练习有些无意义,因为该文件为空,但它提供了一个很好的初步示例:
cat testfile.txt
由于文件为空,因此没有输出。那么,让我们看一个更实际的例子。以下是一个我们可以用cat命令查看的文件,它实际上包含了内容:
cat /etc/os-release
该命令的输出如下所示:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_04_06.png
图 4.6:查看/etc/os-release 的内容
/etc/os-release文件是许多发行版中都存在的一个文件。它是一个特殊的文件,提供有关当前安装的 Linux 发行版的一些信息。如果你连接到一台 Linux 服务器并想知道它运行的是哪个发行版,查看该文件的内容是一种了解方法。你也可以通过以下命令查看以简化形式呈现的一些相同信息:
lsb_release -a
这个命令在各种发行版上都能工作,但我更喜欢使用/etc/os-release文件,因为它包含更多的信息。无论如何,这个练习的核心目的是演示cat命令允许你查看文件内容。差不多,还有其他命令也能实现同样的功能。我的意思是,你也可以尝试用more或less查看/etc/os-release的内容:
more /etc/os-release
less /etc/os-release
more命令使你更容易查看较大的文件,因此对于像/etc/os-release这样较短的文件,其优势不会立即显现。如果你使用more查看一个较长的文件,它将在填满屏幕后停止输出,并允许你按Enter键继续查看下一行。
less命令允许你做相同的事情,但它还允许你使用箭头键以及Enter键查看更多输出;它还允许你向前或向后滚动。因此,本质上,less命令比more命令提供了更多功能。
此外,我们还可以使用grep命令。它通常不用于仅仅查看文件内容,但它绝对是一个值得了解的好命令,能够帮助你查看你特别想要查看的部分,而不是整个文件。
如果你在首次安装 Ubuntu Server 时选择安装了 OpenSSH 服务器,你应该在安装中包含了它的配置文件,并且可以像平常一样使用cat命令查看该文件的内容:
cat /etc/ssh/sshd_config
当然,这将把该文件的内容打印到屏幕上,而文件的内容远远超过典型显示器一次性能够显示的内容。我们可能对某一特定行或单词感兴趣,因此需要能够将文件缩小到我们实际关心的部分。我们将在第十章《连接网络》中更详细地讨论 OpenSSH 服务器,所以目前不用担心这个配置文件的意义。假设我们只关心 OpenSSH 监听的端口,我们可以使用grep命令来打印出/etc/ssh/sshd_config文件中与此特定配置相关的行:
grep Port /etc/ssh/sshd_config
此命令将输出以下内容:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_04_07.png
图 4.7:使用 grep 查看/etc/ssh/sshd_config 文件的内容,以查找包含“Port”的行
本质上,我们所做的是指示grep仅打印出/etc/ssh/sshd_config文件中包含Port字符串的行。在截图中,只有一行包含了该字符串的匹配,因此显示出来。相比于在文件的 123 行文本中滚动查找,看到这个输出无疑更有效,尤其是当我们只关心与端口相关的行时。
默认情况下,grep是区分大小写的。这意味着,如果我们使用grep查找“port”(小写的 P)匹配的行,我们将完全得不到任何输出。我们可以简单地添加-i参数来使搜索不区分大小写。
将grep命令与其他命令(例如cat)搭配使用是非常常见的:
cat /etc/ssh/sshd_config | grep Port
这是一个完全有效的命令,并且会做相同的事情。然而,它有些冗余。我们将在下一章介绍输出重定向的概念,但本质上,这个命令将cat命令的输出重定向作为grep命令的输入。使用cat先打印出文件,然后让grep抓取该文件的内容并搜索字符串,这是一个两步过程,而实际上只需要一步。但话说回来,它仍然是一个有效的命令。
直到今天,我仍然习惯性地使用cat命令配合grep来做同样的事情,因为这就是我刚开始使用 Linux 时,所有新用户被教导的方法。你甚至会在我的 YouTube 视频中看到我这么做——老习惯很难改掉!
日志文件是了解服务器后台发生情况的宝贵信息来源,特别是在故障排除时非常有用。接下来我们将转入关于如何查看这些文件以及与日志相关的命令的讨论。
查看应用程序日志文件
在本章的最后一节,我们来稍微探讨一下日志文件,因为它们包含了我们已经讨论过的一些概念,形成了一个完整的循环。我们回顾了默认目录结构,练习了查看文件,并学习了如何搜索文件中的字符串。稍后我们会更详细地讨论日志文件,但现在我们可以利用这些概念初步了解如何查看日志文件。
如果你还记得,在本章前面讨论 Linux 文件系统布局时,我们展示了一张表格,列出了其中一些最常见的目录。在那张表格中的项目中,我提到了/var/log目录。尽管日志记录方式正在过渡到另一种风格(更多内容会在第二十二章,《Ubuntu 服务器故障排除》中讲到),但我们在/var/log目录中会有一系列日志文件。自己运行一下ls命令,你会看到那里面有相当多的文件。虽然我不会在本章中详细讲解它们,但让我们来看一下/var/log/syslog。
这个文件的内容将包含相当多的行。这是系统日志,用于查看关于 Ubuntu 在你的服务器上运行时的背景信息消息,并且还会显示警告和错误。如果你遇到某个功能不正常的情况,你可能会在系统日志中看到一些输出,提供某种错误信息,你可以通过搜索引擎查找并尝试找到解决方法。例如,如果你的连接出现问题,你可以使用grep查看包含搜索词Network的行:
grep Network /var/log/syslog
这只是一个假设的示例,但它可能显示相关的行。根据你的需求调整搜索词,以便找到你想要的信息。
现在也是介绍head和tail命令的好时机。这些命令分别显示文件的前十行或最后十行。这对/var/log/syslog文件很有用,因为该文件非常大,你可能只对某些行感兴趣。你还可以使用-n选项调整head和tail命令显示的行数,指定你想要的行数。例如,要查看文件的最后100行:
tail -n 100 /var/log/syslog
也许更有用的是-f选项:
tail -f /var/log/syslog
这使得你能够在(几乎)实时中跟踪(查看)文件。使用-f选项时,终端会继续显示文件中新添加的行,因此你可以监控日志文件,举个例子,当某人尝试重现问题时。你可以按下键盘上的Ctrl + c来退出跟踪模式并返回到命令提示符。
当然,还有更多我们可以讲解的基础命令和概念,但我认为现在这些已经足够了。在下一章中,我们将进一步扩展这些内容。但现在,我建议你先练习这一章中的所有概念,直到你熟悉它们为止,再继续前进。
总结
Linux 命令比你能记住的要多。我们大多数人只记住我们喜欢的命令和命令的变体,随着学习和知识的扩展,你将会形成自己的命令菜单。在这一章中,我们介绍了许多基础命令,大部分是必需的。我们探讨了如grep、cat、cd、ls等命令。下一章本质上是这一章的延续,但我想将基础概念分为两章,而不是一章巨大的篇幅。
在下一章中,我们将通过更深入的文件管理知识来扩展我们的基础知识,包括编辑文件、输入/输出流和符号链接,甚至会揭示生活的秘密。嗯,也许不是最后一个,但下一章仍然会很精彩。到时见!
相关视频
- Linux 速成课程 – 浏览 Linux 文件系统(LearnLinuxTV):
linux.video/lcc-navigating
进一步阅读
-
文件系统层次结构标准:
learnlinux.link/fhs-doc
加入我们的 Discord 社区
加入我们的社区 Discord 空间,与作者和其他读者进行讨论:
第五章:管理文件和目录
在 第四章,导航和基本命令 中,我们开始深入了解 Linux 命令。我们回顾了最基本的命令,讲解了文件系统的布局,以及查看文件内容的各种方法。在这一章(以及下一章)中,我们将继续扩展命令行知识,提高使用终端的效率。这一次,我们将进一步讨论文件管理,研究输入/输出流,并了解符号链接。在这个过程中,我们还将涉及:
-
复制、移动和重命名文件和目录
-
使用 Nano 和 Vim 文本编辑器编辑文件
-
输入和输出流
-
使用符号链接和硬链接
让我们从一些方法开始,看看我们如何在文件系统中修改文件和目录,比如复制和移动它们。
复制、移动和重命名文件和目录
此时,你应该知道如何在文件系统中移动(例如 cd 命令)、检查目录内容(ls),甚至如何创建空文件(touch 命令)。我们也知道如何删除文件,例如对文件或目录执行 rm 命令。但直到现在,我们还没有深入了解如何在你的 Ubuntu 文件系统中移动文件。
首先,要复制文件或目录,我们使用 cp 命令。复制文件相对简单,类似于以下的命令:
cp file1 file2
在这个例子中,file2 是 file1 的精确副本。复制文件在许多情况下都很有用,以下是其中一些最常见的情况:
-
将文件复制到备份介质,例如外部硬盘或网络共享
-
在进行更改之前创建文件的副本,比如在编辑一个非常重要的文本文件之前
-
复制日志文件以进行时间点分析
让我们看一下最后一个要点作为另一个很好的例子。我们可以通过执行以下命令捕获系统日志并将其保存在当前工作目录中:
sudo cp /var/log/syslog /home/<username>/syslog
cp 命令相当简单:我们提供一个文件的路径来复制,然后输入目标路径和所需的文件名。由于 syslog 默认情况下可能无法被普通用户读取,我们还需要使用 sudo。在这个命令中,原始的 syslog 文件副本将保存在当前工作目录中。
在这个特定的例子中,日志文件不断地被写入。如果文件一直在扩展,有时很难排查发生在某个特定时间的问题。 但这并不是唯一的原因。我们当然不希望意外更改日志文件,并冒着污染或丢失重要信息的风险。
上一个命令实际上可以稍微简化一下:
sudo cp /var/log/syslog .
在这个示例中,我们移除了目标路径和名称,并用一个句点替代。这之所以有效,是因为句点表示我们的当前工作目录。这不仅适用于cp命令。实际上,每个目录中都有一个名为句点的目录,它本质上是当前目录的指针。因此,如果你已经进入了希望复制文件的目录,就不需要输入路径。如果你希望文件名和源文件相同,那么也不需要输入名称。
复制文件(以及移动文件,我们接下来将讨论)可能是破坏性的。如果目标路径和名称已经存在,那么目标文件将被覆盖。默认情况下,在目标文件被覆盖之前,你不会看到任何确认提示。和所有命令一样,请小心你所指示命令行解释器执行的操作。
当涉及到复制目录时,单独使用cp命令是无法完成的:
sudo cp /var/log/apt .
/var/log/apt目录包含记录通过apt命令执行的事务的日志文件。保持对其他管理员所安装内容的监控是很有用的。然而,在这个示例中,之前的命令会因为以下错误而失败:
cp: -r not specified; omitting directory '/var/log/apt'
错误信息会明确告诉你如何处理,它基本上是在告诉你目录默认情况下是被忽略的。为了复制目录,你需要加上-r选项。-r代表递归,这是许多 Linux 命令可能会使用的选项。它告诉命令行解释器,不仅要抓取你指定路径的对象,还要递归地包含子对象。因此,以下命令将有效:
sudo cp -r /var/log/apt .
使用该命令时,/var/log/apt目录及其内容将会存储在当前工作目录中。
当涉及到将文件或目录从一个地方移动到另一个地方时,我们使用mv命令。其语法几乎与cp命令完全相同。不同之处在于,我们不是复制文件或目录,而是移动它。就这点而言,它的工作原理可能是不言自明的。考虑以下示例命令:
mv file1 /path/to/new/directory/file1
mv file1 file2
在第一个示例中,我们假设file1位于当前工作目录中。我们将该文件抓取并移动到/path/to/new/directory,并在新目录中使用相同的文件名file1。就像使用cp命令一样,我们可以省略目标文件名,因为它保持不变。如果目标目录中已经存在同名文件,它将被覆盖。因此,mv命令也是潜在的破坏性命令,但相比于cp命令,其破坏性更大,因为你是在移动文件,而不是复制。
第二个mv命令稍微有点不同,因为在这个例子中我们正在重命名一个文件。在 Linux 中,没有专门的重命名命令,因此mv命令被用来完成这个任务。事实上,mv可以算是一把瑞士军刀,因为它具有多种功能。通过它,你可以移动文件或目录、重命名文件,甚至将一个文件移动到另一个位置以覆盖另一个文件。具体操作取决于源路径和目标路径。如果目标文件存在,它将被覆盖;如果目标文件不存在,文件将被重命名和/或移动到该路径。
在管理文件时,你肯定会遇到需要管理多个文件或目录的情况。值得注意的是,cp命令和mv命令都可以一次处理多个对象;例如,如果你有三个目录,比如dir1、dir2和dir3,并且需要将它们移动到一个新的子目录中。你可以执行三条mv命令分别移动每个目录,但你也可以用一条mv命令一次性将三个目录全部移动:
mv dir1 dir2 dir3 /path/to/new/location
cp和文件的情况相同;cp和mv命令都可以让你通过一个命令来移动或复制多个目录或文件。
现在我们知道如何移动文件了,接下来我们也应该了解如何编辑文件。在 Ubuntu 平台上,我们有许多可用的文本编辑器,其中 Nano 和 Vim 是最常用的。接下来的部分,我们将介绍这两种编辑器的基本操作。
使用 Nano 和 Vim 文本编辑器编辑文件
现在我们知道如何复制和移动文件了,接下来了解如何编辑文件会非常有用。Ubuntu 提供了多种文本编辑器,其中一些在命令行中可用,另一些则是在图形环境下使用的,比如桌面版的文本编辑器。
有些人可能会觉得命令行文本编辑器比图形用户界面(GUI)编辑器更复杂(老实说,确实可能如此),但它的主要优点是,无论你是否有 GUI,你都可以使用相同的编辑器。从某种意义上来说,这意味着非图形编辑器更具便携性,且更加可靠。几乎所有的 Ubuntu 安装都包括nano文本编辑器,你可以更多地依赖它,而不必担心某个特定的 GUI 编辑器是否可用。此外,vim编辑器也是另一个流行的选择。它比nano更为高级,但在我看来,功能也更强大。在接下来的部分,我们将一起学习nano和vim的使用。
使用 Nano 编辑器
nano编辑器虽然在功能上较为基础,但依然有相当多的用户群体。事实上,如果你还没有注意到,选择编辑器其实在 Linux 社区中能引发一场小小的辩论。启动nano编辑器非常简单,只需运行nano命令。如果你不提供文件名,nano将会启动一个空白的窗口,如下图所示:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_05_01.png
图 5.1:nano文本编辑器,未选择文件
你可以马上开始输入,当你想保存文件时,只需按Ctrl + o即可。在nano屏幕的底部,你会看到快捷键的概述,包括我刚提到的保存文件的方法(它称之为写入文件)。如你所见,Ctrl + x是退出编辑器并返回命令行的方法。
我喜欢的一个技巧是(它也适用于vim),当你在使用nano时,按住Ctrl,然后按t再按z,这会让它消失。通常,你不需要按Ctrl和t来将进程放入后台,但在nano的情况下是个例外。
实际上,这就像是将其最小化。你可以通过执行fg来将nano窗口恢复回来,fg是foreground的缩写。能够在终端中将应用程序放入后台或恢复到前台是进程管理的一部分,实际上这是我们将在第七章,控制与管理进程中讨论的内容,但我们提前给你这个小技巧,帮助你顺利前进!在编辑文件时,有时将编辑器发送到后台然后稍后再回来是很有意义的。
如你所料,你也可以使用nano命令,并提供目标路径和文件名,使编辑器直接打开一个已打开的文件。例如:
sudo nano /var/log/syslog
这个命令会导致文件在nano中打开:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_05_02.png
图 5.2:nano文本编辑器,打开了 syslog 文件
公平地说,直接编辑日志文件在实践中可能不是个好主意,但这个例子是有效的。syslog是你可能想要打开并检查的文件,但最好先通过ls -lh /var/log/syslog命令检查syslog文件的大小,确保它不是过大,否则会拖慢服务器速度。
抛开这些不谈,重点是你可以通过直接提供文件路径来用nano打开文件。在编辑器窗口内,你可以像在图形化编辑器中一样使用箭头键进行移动。你还可以通过按Ctrl + w来搜索特定的文本字符串,这在底部的操作列表中有提到。
此外,注意截图中以红色高亮显示的文字。它只是告诉我们我们没有权限编辑该文件。在那个示例中,我没有使用sudo,因为我并不打算对文件进行任何更改。
有时,我会在一个没有写权限的编辑器中打开文件,这样可以防止我不小心进行更改(如果没有sudo,我将无法保存文件)。要进行真正的更改,我可以关闭文件,然后使用sudo重新打开它。
无论如何,nano 编辑器相当简洁。它除了这些还有更多功能吗?当然有,但最重要的是了解如何打开文件、编辑文件并保存文件,这些我们在本节中已经讲解过了。当然,你可以通过窗口底部提供的操作来练习,超越正常使用。
现在,让我们来看一下 Vim。
使用 Vim 编辑
Vim 是我最喜欢的编辑器,也是我使用最频繁的编辑器。它稍微有些进阶,但并不会让人感到沮丧。默认情况下,它并没有安装。就个人而言,我更喜欢安装 vim-nox 包,可以通过执行以下命令进行安装:
sudo apt install vim-nox
你安装哪个版本的 vim 其实并不重要。每个版本都会添加一些自己的功能。以 vim-nox 为例,它内置了对脚本语言的支持,但在其他方面与标准的 vim 并没有太大区别。你在这里学到的概念并不限于这个版本。就像 nano 一样,你可以通过输入 vim 命令来调用 vim 编辑器,不带任何选项,或者带上文件路径,比如 vim /home/myuser/myfile.txt。如果没有选择文件,vim 会显示默认的帮助文本。它会给出一些默认命令,比如 :q 用于退出编辑器:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_05_03.png
图 5.3:vim 文本编辑器,未打开文件
启动 vim 时,你会进入 命令模式,这是编辑器的多种模式之一。在命令模式下,你不能直接编辑文本。正如其名,命令模式允许你运行命令,这样可以以非常巧妙的方式操作文本。
如果你想像在 nano 中那样编辑文件,你需要切换到 插入模式。你可以通过按键盘上的 Insert 键,或 i 键来切换到插入模式。一旦进入插入模式,你可以像在任何其他编辑器中那样开始输入文本。你可以用方向键移动光标,并在任何地方插入文本。除了插入模式之外,你也可以使用 h、j、k 和 l 键代替方向键来进行导航(有些用户实际上更喜欢这种方式)。要退出插入模式,你可以按 Esc 键。那样就会回到命令模式。
一开始,vim 的不同模式可能会让新手有些困惑。对我来说,它有点像一种超能力。使用 vim,你有一个专门用于编辑文本的模式,还有一个专门用于操作文本的模式。谈到文本操作,这也是 vim 最强大的功能之一。比如,考虑以下这个假设文件:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_05_04.png
图 5.4:vim 文本编辑器,显示一个示例文件
我不知道为什么,但总觉得这个文件有些不对劲。我们需要做一个非常重要的修改来尝试修复它。首先,你可以从截图中看到编辑器停留在了插入模式。要进行文本操作,我们需要先按 Esc 键返回到命令模式。一旦进入命令模式,我们就可以准备输入一个命令。我们要输入的命令是:
:%s/Windows/Linux/g
我不知道你怎么想,但就我个人而言,我认为在执行了那个命令后,文件看起来更好了:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_05_05.png
图 5.5:运行示例命令后的 vim 文本编辑器
从技术上讲,Linux 是一个内核,而不是操作系统。Ubuntu 作为 Linux 的一个发行版,是我们最接近的操作系统。但暂且不提这一点。在我看来,这个版本的文件更准确!
这是一个更高级的 vim 使用示例,通常超出了本书的范围。我想给你展示这个强大编辑器的一个例子,查找和替换文本只是我们可以用它做的众多操作之一。有些人(包括我自己)甚至安装插件,把 vim 转变成 集成开发环境 (IDE)。在我们刚才使用的例子中,我们能够将所有出现的字符串替换成另一个字符串。这也是我们在命令模式下执行的任务之一,命令模式允许我们操控文本并输入更高级的命令。通过这个尽管有些牵强的例子,你可以立刻看到 vim 多模式的价值。
我已经使用 vim 大约十年了,因为我似乎永远也弄不明白如何退出它。好吧,公平地说,这个笑话现在有点过时了。如果你已经使用 Ubuntu 或其他 Linux 发行版一段时间了,可能会对这个笑话有些许反感。如果这是你第一次看到这个笑话,那我很高兴是我向你介绍了它——因为某种原因,vim 有个很难退出的声誉。但其实并不是真的,它其实非常简单。在命令模式下,你只需输入 :q 即可退出编辑器:
:q
如果你进行了更改,:q 命令将无法退出,但你可以通过添加感叹号强制退出,命令变成 :q!。如果你还想在退出时保存更改,可以加上 w,那么在 vim 中的命令就变成了:
:wq
本质上,我们是在同时退出编辑器(q)并写入文件(w)。在命令模式下,命令以冒号(:)开头,后跟实际命令。由于有太多命令可以使用,所以不可能在一章中全部讲完。那么我会提到一些我认为最重要的命令。
首先,实际上可以通过使用以下命令,在不退出 vim 的情况下运行一个 shell 命令:
:! <shell command>
感叹号允许你运行一个命令,然后输入实际的命令。例如:
:! ls -l /var/log
上一个示例会显示/var/log目录的内容,然后你可以按Enter键返回到vim。:sp命令是split的简写:
:sp /path/to/file
在这种情况下,vim能够在同一窗口中同时显示多个文件,通过有效地分割窗口来展示这两个文件。使用:split,或者简写为:sp(两者作用相同),它将把文件分成两个视图(每个视图中显示相同的文件),或者如果你提供了文件名,它会在另一个分割视图中显示一个独立的文件。这个命令会水平分割文件:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_05_06.png
图 5.6:vim 文本编辑器,两个文件在同一窗口中打开
前面的截图显示了两个文件正在打开,/var/log/apt/history.log和/var/log/syslog。你可能还注意到,每个文件底部的状态栏显示了RO。正如你所猜测的,这表示只读,它显示在屏幕上是因为我正在查看只有root用户才能更改的文件,并且我没有使用sudo。
要在两个文件之间切换,我们可以按住Ctrl键的同时,连续按两次w键。这样,我们的插入点就会从一个分割窗口移动到另一个分割窗口。要退出每个独立的缓冲区(或者如果我们只打开了一个文件,就是退出编辑器本身),我们可以按Esc键返回到命令模式,然后输入:q或:q!命令退出而不保存更改,或者输入:wq命令退出并保存更改,就像以前一样。
:split的替代命令是:vsplit,或者简写为:vs。它与:split的作用相同,但会垂直分割窗口。考虑到现在大多数计算机显示器都是宽屏(甚至是超宽屏),垂直分割通常在实际使用中更加方便:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_05_07.png
图 5.7:vim 文本编辑器,两个文件在垂直分割的窗口中打开
说实话,前面的截图效果看起来并不是特别好,原因在于书本中的一页宽度不足以真正展示这种分割的好处。你可以试试看,亲自体验一下。
到目前为止,我们已经介绍了vim的两种模式——命令模式和插入模式。但还有一种我们尚未讨论的常用模式——可视模式。可视模式允许你选择文本,然后执行如复制和粘贴等任务。
要做到这一点,确保你处于命令模式,然后将光标移动到你想要复制的文本的第一个字符。接着,按下键盘上的v键,并用箭头键移动选择区域。
你会发现,随着光标的移动,你会选中更多的文本。当你选中想要复制的所有文本后,按 y 键,选中的部分会消失。此时,你就相当于将选中的文本复制到了 vim 相当于剪贴板的地方,类似于桌面操作系统的剪贴板。然后,你可以(仍然在命令模式下)按 p 键,在光标所在位置粘贴文本。可能需要几次尝试才能掌握这个工作流程,但可以试试。如果你犯了错误,你可以在命令模式下按 u 键来 撤销,这样可以恢复任何更改。
再次强调,vim 是一个相对高级的编辑器。学习其基本功能相对简单,因此掌握如何打开、编辑、关闭和保存文件是你可以很快学会的。vim 的功能集非常庞大,尽管我已经使用它多年,我依然在不断学习新技巧。不过,为了确保你掌握基本操作,我们可以总结一下 vim 的基本工作流程,帮助你记忆。大致流程如下:
-
打开 Vim 可以通过单独输入
vim,或者指定文件名:vim <filename>。 -
你从 命令模式 开始。这个模式非常适合运行
vim命令。按 Insert 或 i 键可以切换到 插入模式。 -
在插入模式下,你可以通过键盘输入文本并用箭头键移动光标来编辑文本。
-
当你编辑完文件后,按 Esc 键返回命令模式。
-
如果想在不保存更改的情况下退出,可以输入
:q或:q!命令。如果你确实想保存更改,可以单独输入:w保存并保持在编辑器中,或者输入:wq同时保存并退出vim。
关于 vim 可以写整本书(实际上也有这样的书),所以本书不可能详细讲解所有内容。事实上,如果你有兴趣了解更多,我还专门制作了一系列关于 vim 的视频教程,地址是 www.learnlinux.tv。但现在,我会给你一些我认为你应该知道的有用技巧。
在命令模式下,你可以按 x 键删除光标所在位置的一个字符。你也可以连续按 d 键 两次 来删除整行。当你这么做时,这一行内容会被复制到粘贴缓冲区;你可以按 p 键将这一行粘贴出来。
此外,我曾多次提到,你可以通过按 i 或 Insert 键切换到插入模式。你也可以通过按 a 键(无论是否按住 Shift)来进入插入模式。如果不按 Shift,你将从光标右侧开始插入一个字符。对我来说,这个操作并不是很有用,但我发现自己经常输入大写的 A,它可以让你进入插入模式并将光标移至当前行的末尾。由于我常常需要在句子的末尾开始输入,这对我来说非常实用。
此外,在命令模式下,你可以按Shift + g立即跳转到文件的最后一行。或者,你也可以连续按两次g键跳转到文件的顶部。
另一个我喜欢的小技巧是启用行号。这在某些情况下非常有用,尤其是当日志文件中的错误消息提到与特定行相关的文件时。以下命令可以启用行号:
:set number
以下命令禁用行号:
:set nonumber
如果你希望默认情况下始终看到行号,可以编辑你主目录下的.vimrc文件。每次启动vim时,vim都会读取该文件。
请注意,.vimrc文件以点(.)开头,这意味着该文件是隐藏的。通常情况下,当你使用ls命令列出目录内容时,隐藏文件不会显示。使用ls命令的-a选项可以显示所有文件,包括那些通常隐藏的文件。
现在可以打开编辑器中的.vimrc文件:
vim ~/.vimrc
对你来说,这很可能是一个空文件,因为默认情况下.vimrc文件并不存在。我们可以在文件中添加许多命令来调整vim编辑器的行为,内容繁多,无法在一章中一一列举。不过,以下这一行非常有用,它确保了行号默认启用:
set number
在这一行前省略冒号是故意的;在.vimrc文件中并不需要冒号。从此以后,每次你打开新的vim会话时,行号将会默认启用。当然,你仍然可以像之前一样,通过vim中的:set nonumber命令来禁用行号。此外,你还可以通过.vimrc文件为vim添加许多其他自定义设置,但这里无法一一列举。目前,只需要知道,使用配置文件来定制vim是完全可行的。
现在我们知道了如何编辑文件,我们也应该更加深入地了解流,流使我们能够以多种方式操作输入和输出。
输入输出流
在我们对 Ubuntu Server 的探索过程中,我们已经在终端中做了不少工作。我们能够查看文件内容、向文件中插入文本等等。其实,在整个过程中,我们一直在使用流,只是没有意识到而已。在这一部分,我们将更详细地讨论这个话题。
如果你曾学习过计算机科学,你可能已经知道,输出指的是从计算机打印出来的内容(例如,文本打印到屏幕上,或从打印机打印到纸上),而输入则指的是输入到计算机中的数据,无论是在命令行、文件中还是其他地方。
Linux 将这个概念延伸得更远。在 Linux 中,流(streams)指的是一种处理输入和输出的特殊方式,除了输入流和输出流,我们还有第三种流,专门用于处理错误。
在 Linux 中,输出流被称为标准输出,而输入流被称为标准输入。这两个术语分别简写为stdout和stdin。将输入/输出这一简单概念扩展成一个独立概念的原因是,在 Linux 的 shell 中,我们可以以不同的方式处理这些流,并且可以对它们执行不同的任务。
到目前为止,我们在整本书中一直在处理标准输出。所有打印到终端的内容都是标准输出。例如,当你之前运行了sudo apt install vim-nox命令时,那条命令的结果(显示包安装状态的文字信息)就是标准输出。当你使用cat /var/log/syslog命令将/var/log/syslog的内容显示在屏幕上时,显示的内容就是标准输出。标准输出是你最常接触到的部分。
为了更好地理解标准输出的概念,让我们来看看重定向。以下命令就是一个例子:
cat /var/log/syslog > ~/logfile.txt
通过该命令,我们使用cat来显示/var/log/syslog的内容。但与其仅仅在屏幕上显示内容,我们使用>符号将标准输出重定向到一个文件~/logfile.txt。这意味着标准输出(显示文件内容)将完全不再显示,因为我们已经将其重定向到了文件中。类似地,我们也可以运行:
cat /var/log/syslog 1> ~/logfile.txt
请注意,我在大于符号前添加了一个1。标准输出通过文件描述符 1 来指定。因此,通过这个命令,我特别指定了我要将标准输出,仅标准输出,重定向到文件中。标准输出是默认的,因此我没有必要包括1。这就是为什么简单地使用大于符号就可以将标准输出重定向到文件的原因。
如果你想追加文件而不是完全覆盖它,可以使用两个大于符号(>>)来追加,而不是覆盖。例如,以下命令会将syslog文件的内容追加到logfile.txt文件的末尾,而不是覆盖整个文件:
cat /var/log/syslog >> ~/logfile.txt
标准输入也有一个文件描述符,即 0。标准输入是命令接收数据的方式。本质上,接受用户输入的命令通过接受stdin来获取数据。标准输入在例子中有点难以展示,但以下方式可以实现:
cat /var/log/syslog | grep -i <keyword>
使用这个命令,我正在获取 /var/log/syslog 文件的内容,并将其传递给 grep 命令,这样可以只显示包含特定术语的行。每个 syslog 文件都不会相同,因为每个服务器都可以有不同的配置。但如果你正在调查某个特定的应用或服务,你可以使用 grep 在日志中查找你认为合适的关键词。如果你加上 -i 选项,grep 将执行不区分大小写的搜索。在这个例子中,cat 命令的输出成为了 grep 命令的标准输入。这个命令可以用任何你选择的搜索词来执行。
我也可以运行:
cat < /var/log/syslog | grep Network
在这个例子中,我使用 小于号 符号将 /var/log/syslog 文件的内容重定向为 cat 命令的标准输入。cat 命令通常将传给它的文本打印到屏幕上作为标准输出,但在这里,我使用管道符号 | 来获取该输出,并将其作为标准输入传递给 grep 命令。
这个概念一开始可能有些令人困惑,但如果你持续练习,它一定会变得清晰。让我们再看一个例子,这样我们也能理解标准错误(stderr):
find / -name "syslog"
find 命令允许你查找符合特定条件的文件,例如在这个例子中查找名为 syslog 的文件。这里,我们正在搜索整个文件系统,因为我们从 / 开始了搜索。问题是我没有权限读取文件系统中的所有文件,并且没有使用 sudo。这将导致屏幕上出现许多错误,例如这些:
find: '/var/lib/netdata/health': Permission denied
find: '/var/lib/netdata/registry': Permission denied
find: '/var/lib/netdata/cloud.d': Permission denied
find: '/var/lib/udisks2': Permission denied
由于 find 命令被用来搜索整个文件系统,包括我没有权限查看的地方,我们的终端将被错误信息淹没。这些错误通过标准错误显示,标准错误的文件描述符是 2。如果我们想隐藏这些错误,可以这样做:
find / -name "syslog" 2> /dev/null
使用这个命令时,运行时不会显示任何错误。这是因为我们指示解释器捕获标准错误并将其重定向到 /dev/null。/dev/null 是一个特殊的设备,任何放到那里东西都会永远消失。如果你将某物移到或重定向到那里,它基本上就被删除了。由于标准错误的文件描述符是 2,我们将其与 大于号 符号结合形成 2>,这基本上指示 shell 执行重定向,但只重定向标准错误,保持标准输出不变。我们还可以选择在单个命令中将多个流重定向到不同的地方:
find / -name "syslog" 1> stdout.txt 2> stderr.txt
在这个变体中,我将成功的输出重定向到 stdout.txt,而错误信息则重定向到 stderr.txt。这样我们就可以完全控制成功和失败信息的输出位置。这在故障排除时非常有帮助,因为我们可能只想专注于错误信息,去掉成功的输出可以减少我们需要查看的行数。
我建议你尽量多练习这个概念;这绝对是你希望牢记的内容。你不必现在就完全掌握这个概念,但了解基本知识会为你提供一个很好的基础。
接下来,我们来讨论文件管理的另一个方面——链接。有时,你需要将一个东西链接到另一个东西,并且有几种方法可以实现这一点,同时也有一些最佳实践建议。
使用符号链接和硬链接
如果你已经使用图形操作系统超过一周,那么你可能对快捷方式这个概念非常熟悉。无论是在桌面上还是在菜单中,你都会看到指向文件和应用程序的快捷方式。这些快捷方式可能指向你的主页或个人目录、一个应用程序、单个文件等等。Linux 中也有相同的概念。
使用 Linux,我们可以将文件链接到其他文件,这使我们能够创建自己的快捷方式,这实际上类似于图形操作系统中的快捷方式,但不需要 GUI。这些快捷方式以 符号链接和硬链接 的形式存在,它们是两种不同的链接方式。符号链接和硬链接非常相似,但要解释它们,你首先需要理解 inode 的概念。
inode 是一个数据对象,包含有关文件系统中文件的元数据。尽管对 inode 概念的完整讲解会相当长,但可以将 inode 看作一种数据库对象,存储了你磁盘上实际存储项目的元数据。inode 中存储的信息包括文件的所有者、权限、最后修改日期和类型(是目录还是文件)等详细信息。inode 通过一个整数表示,你可以使用 ls 命令的 -i 选项查看。在我的系统中,我创建了两个文件:file1 和 file2。这两个文件分别是 inode 265416 和 266112。你可以在以下截图中看到运行 ls -i 命令的输出。这些信息很快就会派上用场:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_05_08.png
图 5.8:ls -i 的输出
正如我之前提到的,Linux 中有两种类型的链接:符号链接和硬链接。虽然这两种链接的实现方式不同,但它们的目的几乎相同。基本上,链接允许我们在文件系统的其他地方引用某个文件。
举个实际的例子,让我们创建一个硬链接。在我的例子中,我在一个 test 目录下有几个文件,因此我可以为它们中的任何一个创建链接。要创建链接,我们将使用 ln 命令:
ln file1 file3
这里,我正在创建一个指向 file1 的硬链接(file3)。为了实验,你可以尝试在系统上创建一个文件的链接。如果我们再次使用 ls 命令并加上 -i 选项,我们会看到一些有趣的事情:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_05_09.png
图 5.9:第二次 ls -I 命令的输出
如果仔细观察输出,你会发现file1和file3具有相同的 inode 编号。从本质上讲,硬链接是一个重复的目录项,两个目录项都指向相同的数据。在这种情况下,我们创建了一个指向另一个文件的硬链接。创建了这个硬链接后,我们可以将file3移动到文件系统中的另一个位置,它仍然会指向file1。然而,硬链接有几个限制。首先,你不能创建指向目录的硬链接,只能是文件。其次,硬链接不能被移动到不同的文件系统。这是有道理的,因为每个文件系统都有自己的 inode。在我的系统上,inode 265416当然不会指向另一个系统上的同一文件,假设该 inode 编号在另一个系统上存在的话。
为了克服这些限制,我们可以考虑使用软链接。软链接(也叫做符号链接或符号连接)是一个指向另一个目录或文件的条目。这与硬链接不同,因为硬链接是一个引用 inode 的重复条目,而符号链接引用的是特定的路径。符号链接不仅可以在不同的文件系统之间移动,我们还可以创建指向目录的符号链接。为了说明符号链接是如何工作的,我们来创建一个。在我的情况下,我将删除file3并将其重新创建为符号链接。我们将再次使用ln命令:
rm file3
ln -s file1 file3
使用ln的-s选项,我正在创建一个符号链接。首先,我通过rm命令删除了原始的硬链接(这不会影响原始文件file1),然后创建了一个名为file3的符号链接。如果我们再次使用ls -i,会发现file3的 inode 编号与file1不同:
https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/ms-ubt-svr/img/B18425_05_10.png
图 5.10:创建符号链接后使用ls -i命令的输出
请注意,每个文件的 inode 编号都是不同的。此时,与硬链接相比,主要的区别应该变得显而易见。符号链接并不是原始文件的克隆;它只是指向原始文件路径的一个指针。你对file3执行的任何命令,实际上都是针对符号链接指向的目标执行的。而硬链接则直接指向文件。
在实践中,符号链接在服务器管理中非常有用。然而,重要的是不要疯狂地在整个文件系统中创建大量的符号链接。如果你是服务器上唯一的管理员,这自然不是问题,但如果你辞职,别人接替你的职位,他们会为弄清楚你所有的符号链接并映射它们指向的位置而头疼。当然,你可以为你的符号链接创建文档,但那样你就得追踪它们并不断更新文档。我的建议是,只有在没有其他选项时,或者这样做对你的组织有利并简化文件布局时,才创建符号链接。
回到符号链接与硬链接的话题,你可能在想应该使用哪一种以及何时使用它们。硬链接的主要好处是你可以将任一文件(链接或原始文件)移动到同一文件系统的任何位置,链接都不会断开。然而,符号链接并非如此;如果你移动原始文件,符号链接将指向一个在该位置已不存在的文件。硬链接基本上是指向同一对象的重复条目,因此它们有相同的 inode 号码,因此两者将具有相同的文件大小和内容。符号链接是指向文件路径的指针——仅此而已。
然而,尽管我刚才谈到了硬链接的几个好处,我实际上推荐在大多数使用场景中使用符号链接。符号链接可以跨文件系统,可以链接到目录,并且从输出中更容易判断它们指向哪里。如果你移动硬链接,可能会忘记它们最初的位置或哪个文件实际上指向哪个。没错,使用几个命令你可以轻松找到并映射它们。但总的来说,从长远来看,符号链接更为方便。只要你在移动原始文件时留意重新创建符号链接(并且仅在需要时使用它们),你就不会遇到问题。
总结
在这一章中,我们将终端操作技巧提升到一个新水平,并探讨了移动和复制文件等概念。接着,我们讨论了两个流行的文本编辑器,Nano 和 Vim。然后,我们深入探讨了流的概念,并以理解符号链接和硬链接的区别以及如何创建它们作为本章的结束。
在第六章,提升你的命令行效率中,我们将深入探讨一些命令行技巧,包括讨论 Bash 历史、编写基础脚本等内容。
相关视频
-
Linux Crash Course – 数据流(LearnLinuxTV):
linux.video/se-data-streams -
Linux Crash Course – nano(LearnLinuxTV):
linux.video/le-nano -
Linux Crash Course – 符号链接(LearnLinuxTV):
linux.video/se-symlinks -
Vim 文本编辑器教程系列:
learnlinux.link/vim
加入我们的 Discord 社区
加入我们社区的 Discord 空间,与作者及其他读者进行讨论:
openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐


所有评论(0)