这个系列是什么
「Linux 实战」按线上真正会撞上的事情排:认清系统和装软件(本篇)、端口不通、服务起不来、磁盘满了、网络和 SSH、日志与性能......
每一篇都做两件事 :①所有命令在真机上跑过、贴原始输出;②同一件事在三个系统上各跑一遍 ------ CentOS 7 还大量在线上跑着,新机器多半是 Rocky 9 或 Ubuntu,而这三个系统在装软件、换源这件事上几乎处处不一样,照着一个系统的教程去弄另一个,常常是命令敲对了却不生效。
实测环境
| 机器 | 版本 | 内核 | 说明 |
|---|---|---|---|
| CentOS 7 | CentOS Linux release 7.9.2009 (Core) |
3.10.0-1160.71.1.el7 | VMware 虚拟机,firewalld 开、SELinux Enforcing |
| Rocky 9 | Rocky Linux release 9.8 (Blue Onyx) |
5.14.0-687.49.1.el9_8 | KVM 虚拟机,最小化镜像后补装了 firewalld、SELinux 切到 Enforcing |
| Ubuntu 24.04 | Ubuntu 24.04.5 LTS |
6.8.0-139-generic | KVM 虚拟机,最小化镜像后补装了 ufw(未启用)、AppArmor |
⚠️ 后两台是最小化镜像,下文凡是写「这台机器上没有 X」,只代表这台机器,你那台标准安装的服务器可能装了。
1. 先认清是什么系统 ✅
装软件、改源、开端口的命令都跟系统走,所以第一步永远是确认自己在哪台什么系统上。
1.1 /etc/os-release:三个系统都有,最该先看
ini
# cat /etc/os-release (CentOS 7,截取前 6 行)
NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="7"
PRETTY_NAME="CentOS Linux 7 (Core)"
ini
# cat /etc/os-release (Rocky 9,截取)
NAME="Rocky Linux"
VERSION="9.8 (Blue Onyx)"
ID="rocky"
ID_LIKE="rhel centos fedora"
VERSION_ID="9.8"
PLATFORM_ID="platform:el9"
PRETTY_NAME="Rocky Linux 9.8 (Blue Onyx)"
SUPPORT_END="2032-05-31"
ini
# cat /etc/os-release (Ubuntu 24.04,截取)
PRETTY_NAME="Ubuntu 24.04.5 LTS"
NAME="Ubuntu"
VERSION_ID="24.04"
VERSION="24.04.5 LTS (Noble Numbat)"
VERSION_CODENAME=noble
ID=ubuntu
ID_LIKE=debian
🔑 最有用的是 ID_LIKE :它说的是「这个系统像谁」。含 rhel → 按 yum/dnf 那一套走;含 debian → 按 apt 那一套走。
写脚本时只取一个值:
shell
# . /etc/os-release && echo "$ID"
rocky
# grep '^ID=' /etc/os-release | cut -d= -f2 | tr -d '"'
rocky
⚠️ . /etc/os-release 会把文件里的变量灌进当前 shell。实测(三台结果一致,这里贴 CentOS 7):
shell
# VERSION=mine; . /etc/os-release; echo "VERSION 被覆盖成: $VERSION"
VERSION 被覆盖成: 7 (Core)
# VERSION=mine; ( . /etc/os-release; echo "子shell里: $ID" ); echo "外面 VERSION 仍是: $VERSION"
子shell里: centos
外面 VERSION 仍是: mine
脚本里自己有 VERSION、NAME 这类变量的,要么放进 ( ) 子 shell,要么用 grep 那种写法。
1.2 其他几个文件,各有各的坑
| 命令 | CentOS 7 | Rocky 9 | Ubuntu 24.04 |
|---|---|---|---|
cat /etc/redhat-release |
CentOS Linux release 7.9.2009 (Core) |
Rocky Linux release 9.8 (Blue Onyx) |
No such file or directory |
cat /etc/debian_version |
No such file or directory |
No such file or directory |
trixie/sid |
cat /etc/issue |
\S / Kernel \r on an \m |
\S / Kernel \r on \m |
Ubuntu 24.04.5 LTS \n \l |
command -v lsb_release |
没有 | 没有 | /usr/bin/lsb_release |
三个要注意的地方:
- Ubuntu 的
/etc/debian_version给的是trixie/sid,不是 24.04。判 Ubuntu 版本别看它。 - RHEL 系的
/etc/issue里是\S、\r这样的转义符 ,登录提示时才被替换,cat出来看不到版本号。 lsb_release两台 RHEL 系机器上都没有,Ubuntu 上有:
yaml
# lsb_release -a (Ubuntu 24.04)
Distributor ID: Ubuntu
Description: Ubuntu 24.04.5 LTS
Release: 24.04
Codename: noble
# lsb_release -a (Rocky 9)
bash: line 1: lsb_release: command not found
所以脚本里判系统用 /etc/os-release,别依赖 lsb_release。
另外,不知道有哪些 release 文件时 ls /etc/*release /etc/*version 能列全,但在 RHEL 系上它的退出码是 2 (/etc/*version 一个都匹配不到),写进脚本别拿退出码判断成败:
bash
# ls /etc/*release /etc/*version 2>/dev/null (Rocky 9,退出码 2)
/etc/os-release
/etc/redhat-release
/etc/rocky-release
/etc/system-release
1.3 内核、架构、是不是虚拟机
shell
# uname -r; uname -m
3.10.0-1160.71.1.el7.x86_64 ← CentOS 7
5.14.0-687.49.1.el9_8.x86_64 ← Rocky 9
6.8.0-139-generic ← Ubuntu 24.04
x86_64
内核里的 el7 / el9 能反推 RHEL 大版本,但只能当线索:最终以 /etc/os-release 为准。
shell
# systemd-detect-virt
vmware ← CentOS 7(VMware 虚拟机)
kvm ← Rocky 9 / Ubuntu 24.04(KVM 虚拟机)
# systemd-detect-virt -c; echo "退出码=$?"
none
退出码=1
⚠️ -c 只判容器:不是容器时输出 none、退出码是 1 。脚本里 if systemd-detect-virt -c 这样写,在物理机和虚拟机上都会走 else 分支,这是对的,但别把退出码 1 当成「命令出错」。
dmidecode 能看到虚拟化厂商:CentOS 7 是 VMware, Inc. / VMware Virtual Platform,Rocky 9 是 QEMU / Standard PC (Q35 + ICH9, 2009)。这台 Ubuntu 最小化镜像上没有 dmidecode 命令 (command not found)。
1.4 一段脚本拿全景(三台都实跑过)
bash
echo "===== 系统 ====="
( . /etc/os-release 2>/dev/null && echo "$PRETTY_NAME (ID=$ID LIKE=$ID_LIKE)" ) \
|| cat /etc/redhat-release 2>/dev/null \
|| cat /etc/issue
echo "===== 内核/架构 ====="
uname -srm
echo "===== 虚拟化 ====="
systemd-detect-virt 2>/dev/null || echo "(无 systemd-detect-virt)"
echo "===== 包管理器 ====="
for p in dnf yum apt zypper apk pacman; do
command -v $p >/dev/null 2>&1 && echo "有:$p"
done
echo "===== 防火墙 ====="
for p in firewall-cmd ufw nft iptables; do
command -v $p >/dev/null 2>&1 && echo "有:$p"
done
echo "===== init ====="
ps -p 1 -o comm=
三台的输出:
ini
===== 系统 =====
CentOS Linux 7 (Core) (ID=centos LIKE=rhel fedora)
===== 内核/架构 =====
Linux 3.10.0-1160.71.1.el7.x86_64 x86_64
===== 虚拟化 =====
vmware
===== 包管理器 =====
有:yum
===== 防火墙 =====
有:firewall-cmd
有:iptables
===== init =====
systemd
ini
===== 系统 =====
Rocky Linux 9.8 (Blue Onyx) (ID=rocky LIKE=rhel centos fedora)
===== 内核/架构 =====
Linux 5.14.0-687.49.1.el9_8.x86_64 x86_64
===== 虚拟化 =====
kvm
===== 包管理器 =====
有:dnf
有:yum
===== 防火墙 =====
有:firewall-cmd
有:nft
有:iptables
===== init =====
systemd
ini
===== 系统 =====
Ubuntu 24.04.5 LTS (ID=ubuntu LIKE=debian)
===== 内核/架构 =====
Linux 6.8.0-139-generic x86_64
===== 虚拟化 =====
kvm
===== 包管理器 =====
有:apt
===== 防火墙 =====
有:ufw
有:nft
有:iptables
===== init =====
systemd
2. 装软件:yum、dnf、apt 的差别 ✅
2.1 Rocky 9 上的 yum 其实就是 dnf
shell
# ls -l $(command -v yum); yum --version | head -1 (Rocky 9)
lrwxrwxrwx. 1 root root 5 May 19 22:37 /usr/bin/yum -> dnf-3
4.14.0
# ls -l $(command -v yum); yum --version | head -1 (CentOS 7)
-rwxr-xr-x. 1 root root 801 Oct 2 2020 /usr/bin/yum
3.4.3
所以 Rocky 9 上敲 yum 和 dnf 结果一样;CentOS 7 上只有 yum,没有 dnf,也没有模块流:
bash
# yum module list (CentOS 7)
No such command: module. Please use /usr/bin/yum --help
2.2 装、卸、撤销(Rocky 9 实测)
arduino
# dnf install -y nginx (截取末尾)
nginx-2:1.20.1-28.el9_8.6.rocky.0.1.x86_64
nginx-core-2:1.20.1-28.el9_8.6.rocky.0.1.x86_64
nginx-filesystem-2:1.20.1-28.el9_8.6.rocky.0.1.noarch
rocky-logos-httpd-90.17-1.el9.noarch
Complete!
🔑 dnf history undo 是后悔药:每次装卸都有一条带编号的记录,可以按编号撤销。
markdown
# dnf history | head -5
ID | Command line | Date and time | Action(s) | Altered
-------------------------------------------------------------------------------
7 | remove -y nginx | 2026-09-21 14:49 | Removed | 4
6 | install -y nginx | 2026-09-21 14:49 | Install | 4
5 | -y -q install firewalld | 2026-09-21 14:29 | Install | 21 EE
# dnf history undo -y 7 (撤销第 7 次的卸载 = 装回来)
...
Complete!
# rpm -q nginx
nginx-1.20.1-28.el9_8.6.rocky.0.1.x86_64
CentOS 7 的 yum history undo 同样可用(下文 §3 测完后就是用它把装的包逐次撤掉的)。升级前记一下 history 的当前编号,出事时有救。
2.3 rpm -ivh / dpkg -i 不解依赖
手上只有一个包文件时,别直接 rpm -ivh:
vbnet
# rpm -ivh nginx-1*.rpm nginx-core-*.rpm; echo "rpm 退出码=$?" (Rocky 9)
error: Failed dependencies:
nginx-filesystem = 2:1.20.1-28.el9_8.6.rocky.0.1 is needed by nginx-2:1.20.1-28.el9_8.6.rocky.0.1.x86_64
system-logos-httpd is needed by nginx-2:1.20.1-28.el9_8.6.rocky.0.1.x86_64
nginx-filesystem is needed by nginx-core-2:1.20.1-28.el9_8.6.rocky.0.1.x86_64
rpm 退出码=2
换成 dnf install ./文件名,缺的依赖会从仓库自动补:
shell
# dnf install -y ./nginx-1*.rpm ./nginx-core-*.rpm (截取)
Installing:
Installing dependencies:
nginx-filesystem noarch 2:1.20.1-28.el9_8.6.rocky.0.1 appstream 11 k
CentOS 7 同理,rpm -ivh httpd 报缺 httpd-tools、libapr-1.so.0 等 4 项(退出码 1),yum install -y ./httpd-*.rpm 自动补上 apr、apr-util、httpd-tools、mailcap。
Ubuntu 上的对应情况:
vbnet
# dpkg -i nginx_*.deb; echo "dpkg 退出码=$?" (Ubuntu 24.04)
Selecting previously unselected package nginx.
...
dpkg: dependency problems prevent configuration of nginx:
nginx depends on nginx-common (= 1.24.0-2ubuntu7.18); however:
Package nginx-common is not installed.
dpkg: error processing package nginx (--install):
dependency problems - leaving unconfigured
Errors were encountered while processing:
nginx
dpkg 退出码=1
# dpkg -l | grep -E '^.. +nginx '
iU nginx 1.24.0-2ubuntu7.18 amd64 small, powerful, scalable web/proxy server
⚠️ iU = 已解包、未配置 ------ 包「装了一半」挂在那里。补救:
bash
# apt --fix-broken install -y (截取)
Correcting dependencies... Done
The following additional packages will be installed:
nginx-common
...
# dpkg -l | grep -E '^.. +nginx'
ii nginx 1.24.0-2ubuntu7.18 amd64 small, powerful, scalable web/proxy server
ii nginx-common 1.24.0-2ubuntu7.18 all small, powerful, scalable web/proxy server - common files
2.4 🔴 apt remove nginx 之后,/etc/nginx 还在
shell
# apt remove -y nginx
...
Removing nginx (1.24.0-2ubuntu7.18) ...
# dpkg -l | grep -E '^.. +nginx'
ii nginx-common 1.24.0-2ubuntu7.18 all small, powerful, scalable web/proxy server - common files
# ls /etc/nginx | head -5
conf.d
fastcgi.conf
fastcgi_params
koi-utf
koi-win
配置文件属于 nginx-common,不属于 nginx。想把配置改坏了「彻底重来」,要连它一起 purge:
bash
# apt purge -y nginx nginx-common
...
# ls /etc/nginx
ls: cannot access '/etc/nginx': No such file or directory
很多教程写「apt purge nginx 连配置一起删」------ 只 purge nginx 这一个包是删不掉 /etc/nginx 的。
2.5 「命令找不到,该装哪个包」
以 semanage(SELinux 常用命令)为例:
yaml
# dnf provides '*/semanage' (Rocky 9,截取)
policycoreutils-python-utils-3.6-5.el9.noarch : SELinux policy core python utilities
Repo : appstream
Matched from:
Filename : /usr/sbin/semanage
# yum provides '*/semanage' (CentOS 7,截取)
policycoreutils-python-2.5-34.el7.x86_64 : SELinux policy core python utilities
Repo : @base
Matched from:
Filename : /usr/sbin/semanage
注意两个版本的包名不一样 :CentOS 7 是 policycoreutils-python,Rocky 9 是 policycoreutils-python-utils。照抄 7 的教程在 9 上装会找不到包。
Ubuntu 上「命令找不到时提示你装哪个包」这个功能依赖 command-not-found 包 。这台最小化镜像一开始没有,敲 semanage 只有一句 command not found;装上之后:
csharp
# apt install -y command-not-found && apt update
# semanage
Command 'semanage' not found, but can be installed with:
apt install policycoreutils-python-utils
没这个提示时用 apt-file(要先装、先 apt-file update):
bash
# apt-file search /usr/sbin/semanage
policycoreutils-python-utils: /usr/sbin/semanage
2.6 两个写脚本时会咬人的细节
① check-update 有更新时退出码是 100,不是 1:
sql
# yum check-update >/dev/null 2>&1; echo "yum check-update 退出码=$?" (CentOS 7)
yum check-update 退出码=100
# dnf check-update >/dev/null 2>&1; echo "dnf check-update 退出码=$?" (Rocky 9,当时无更新)
dnf check-update 退出码=0
脚本里 set -e 或 if yum check-update 会把「有可用更新」当成失败。
② 脚本里用 apt-get,别用 apt :apt 的输出一被管道接走,就会先打一行警告:
csharp
# apt show nginx 2>&1 | head -3
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
2.7 锁住某个包不让升级(Ubuntu)
csharp
# apt-mark hold nginx; apt-mark showhold
nginx set on hold.
nginx
# apt-mark unhold nginx
Canceled hold on nginx.
排查「这个包为什么一直没升级」时,先看一眼 apt-mark showhold。
3. 🔴 CentOS 7 源失效:照教程切 vault,实测 403 ✅
这是本篇的重点。 下面的测试把 CentOS 7 的仓库配置换回了 centos-release 包里自带的原版(从 rpm 包里解出来的,不是手写的),复现一台「从没改过源」的 CentOS 7 现在会遇到什么。
3.1 症状:Cannot find a valid baseurl
原版配置用的是 mirrorlist:
ini
[base]
name=CentOS-$releasever - Base
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os&infra=$infra
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
csharp
# yum makecache (截取末尾)
5. Configure the failing repository to be skipped, if it is unavailable.
Note that yum will try to contact the repo. when it runs most commands,
so will have to try and fail each time (and thus. yum will be be much
slower). If it is a very temporary problem though, this is often a nice
compromise:
yum-config-manager --save --setopt=<repoid>.skip_if_unavailable=true
Cannot find a valid baseurl for repo: base/7/x86_64
yum install 任何包都是同一句。原因不是网络,是源下线了:
shell
# getent hosts mirrorlist.centos.org || echo "mirrorlist.centos.org 解析不到"
mirrorlist.centos.org 解析不到
# curl -sS -m 10 -o /dev/null -w '%{http_code}\n' http://mirror.centos.org/centos/7/os/x86_64/repodata/repomd.xml
404
3.2 教程里的第一选择 vault.centos.org:实测 403
大多数教程让你把 baseurl 指向官方归档 vault.centos.org。在我这条国内宽带上直连,它返回 403:
shell
# curl -sS -m 15 -I https://vault.centos.org/7.9.2009/os/x86_64/repodata/repomd.xml (截取)
HTTP/1.1 403 Forbidden
Server: CloudFront
X-Cache: Error from cloudfront
加浏览器 User-Agent 也还是 403。yum 里的表现:
vbnet
failure: repodata/repomd.xml from base: [Errno 256] No more mirrors to try.
https://vault.centos.org/7.9.2009/os/x86_64/repodata/repomd.xml: [Errno 14] HTTPS Error 403 - Forbidden
⚠️ 这是 2026-09-21 在一条国内宽带上的读数;同一时刻从一个走代理出口的网络访问是 200 。所以它跟你的网络出口有关,不代表 vault 关了。切 vault 之前先 curl -I 看一眼能不能拿到 200,拿不到就直接用下面的镜像。
3.3 实测能用的:阿里云 centos-vault
先确认路径能拿到 200(这一步别省,路径写错的表现和源失效一模一样):
bash
200 0.377s https://mirrors.aliyun.com/centos-vault/7.9.2009/os/x86_64/repodata/repomd.xml
然后:
bash
mkdir -p /etc/yum.repos.d/bak
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/bak/
新建 /etc/yum.repos.d/CentOS-Vault.repo:
ini
[base]
name=CentOS-7 - Base
baseurl=https://mirrors.aliyun.com/centos-vault/7.9.2009/os/$basearch/
gpgcheck=1
enabled=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
[updates]
name=CentOS-7 - Updates
baseurl=https://mirrors.aliyun.com/centos-vault/7.9.2009/updates/$basearch/
gpgcheck=1
enabled=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
[extras]
name=CentOS-7 - Extras
baseurl=https://mirrors.aliyun.com/centos-vault/7.9.2009/extras/$basearch/
gpgcheck=1
enabled=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
php
# yum clean all; time yum makecache (截取末尾)
Loaded plugins: fastestmirror
Determining fastest mirrors
Metadata Cache Created
real 3m7.691s
🔑 两个要点:
baseurl写死7.9.2009,别用$releasever:它展开成7,而归档站只有按小版本分的目录(7.0.1406/...7.9.2009/),没有7/(下面两行是在另一台机器上用 curl 查的):
bash
404 https://mirrors.aliyun.com/centos-vault/7/os/x86_64/repodata/repomd.xml
200 https://mirrors.aliyun.com/centos-vault/7.9.2009/os/x86_64/repodata/repomd.xml
- 换完先
yum clean all再yum makecache,让 yum 丢掉旧的元数据。
⚠️ 切到归档只是让 yum 重新能用,归档里不会再有新的安全更新。长期看还是要迁到仍在维护的系统。
3.4 如果 mirrorlist 那一行没删掉,会怎样
很多教程说「mirrorlist= 不删,yum 还会去问已经下线的 mirrorlist,所以一定要删」。实测:在 baseurl 已经指向阿里云的前提下,把 mirrorlist 行加回去:
bash
# yum --disablerepo='*' --enablerepo=base makecache (截取末尾)
Loaded plugins: fastestmirror
Determining fastest mirrors
Could not retrieve mirrorlist http://mirrorlist.centos.org/?release=7&arch=x86_64&repo=os&infra=stock error was
14: curl#6 - "Could not resolve host: mirrorlist.centos.org; Unknown error"
Metadata Cache Created
退出码是 0 ------ yum 先问 mirrorlist、报一行错,然后回落到 baseurl,最后是成功的 。所以留着它不会让换源失败,但每次都会多一行报错、多一次解析等待。还是删掉,只是别把「换源没成功」归咎到它身上。
3.5 EPEL 7 也下线了:metalink 卡满 3 分钟
CentOS 7 上很多常用软件(比如 nginx)不在 base 源里,要先装 EPEL。epel-release 本身能从 extras 装上,但它写进去的是 metalink:
shell
# grep -E '^(metalink|#baseurl)' /etc/yum.repos.d/epel.repo | head -2
#baseurl=http://download.fedoraproject.org/pub/epel/7/$basearch
metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-7&arch=$basearch
之后任何 yum 命令都会卡住。我给它设了 180 秒上限:
yaml
# timeout 180 yum makecache
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
* epel: d2lzkl7pfhq30w.cloudfront.net
退出码=124 用时=180s
退出码 124 = 被 timeout 杀掉,除了开头三行,180 秒里没有任何输出。EPEL 7 的正式地址已经 404,归档还在:
bash
200 https://archives.fedoraproject.org/pub/archive/epel/7/x86_64/repodata/repomd.xml
200 https://mirrors.aliyun.com/epel-archive/7/x86_64/repodata/repomd.xml
404 https://dl.fedoraproject.org/pub/epel/7/x86_64/repodata/repomd.xml
把 /etc/yum.repos.d/epel.repo 的 [epel] 段改成:
ini
[epel]
name=Extra Packages for Enterprise Linux 7 - $basearch
baseurl=https://mirrors.aliyun.com/epel-archive/7/$basearch
#metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-7&arch=$basearch
failovermethod=priority
enabled=1
gpgcheck=1
arduino
# yum clean all; yum makecache
...
Metadata Cache Created
退出码=0 用时=100s
# yum install -y nginx (截取末尾)
nginx-filesystem.noarch 1:1.20.1-10.el7 openssl11-libs.x86_64 1:1.1.1k-7.el7
Complete!
# rpm -q nginx
nginx-1.20.1-10.el7.x86_64
4. Rocky 9:powertools 改名 crb、模块流要先 reset ✅
4.1 powertools 在 9 上叫 crb
照着 Rocky 8 的教程开 powertools 仓库:
shell
# dnf config-manager --set-enabled powertools; echo "退出码=$?"
Error: No matching repo to modify: powertools.
退出码=1
# dnf config-manager --set-enabled crb; echo "退出码=$?"
退出码=0
⚠️ 在这台最小化的 Rocky 9 上,dnf config-manager 一开始根本不存在,报的是另一句:
bash
No such command: config-manager. Please use /usr/bin/dnf --help
It could be a DNF plugin command, try: "dnf install 'dnf-command(config-manager)'"
要先 dnf install -y dnf-plugins-core。所以同一条命令可能撞上两种报错,先看清是哪一句。
装 EPEL 在 9 上是正常的:
rust
# dnf install -y epel-release; dnf repolist | grep -i epel
epel Extra Packages for Enterprise Linux 9 - x86_64
epel-cisco-openh264 Extra Packages for Enterprise Linux 9 openh264 (From Cisco) - x86_64
4.2 模块流:换版本前要 reset
装特定大版本的 Node.js / PHP 这类软件,Rocky 9 用模块流:
ini
# dnf module list nodejs (截取)
Name Stream Profiles Summary
nodejs 18 common [d], development, minimal, s2i Javascript runtime
nodejs 20 common [d], development, minimal, s2i Javascript runtime
nodejs 22 common [d], development, minimal, s2i Javascript runtime
nodejs 24 common [d], development, minimal, s2i Javascript runtime
先启用了 20,再想换成 22:
vbnet
# dnf module enable -y nodejs:22
...
The operation would result in switching of module 'nodejs' stream '20' to stream '22'
Error: It is not possible to switch enabled streams of a module unless explicitly enabled via configuration option module_stream_switch.
It is recommended to rather remove all installed content from the module, and reset the module using 'dnf module reset <module_name>' command. After you reset the module, you can install the other stream.
先 reset 再启用就行:
ini
# dnf module reset -y nodejs; dnf module enable -y nodejs:22
# dnf module list nodejs | grep -E '^nodejs'
nodejs 18 common [d], development, minimal, s2i Javascript runtime
nodejs 20 common [d], development, minimal, s2i Javascript runtime
nodejs 22 [e] common [d], development, minimal, s2i Javascript runtime
nodejs 24 common [d], development, minimal, s2i Javascript runtime
4.3 Rocky 9 换国内源
Rocky 默认用 mirrorlist(dnf repoinfo 里能看到它挑中的镜像)。改成阿里云:
bash
cp -a /etc/yum.repos.d /root/yum.repos.d.bak
sed -e 's|^mirrorlist=|#mirrorlist=|g' \
-e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.aliyun.com/rockylinux|g' \
-i.bak /etc/yum.repos.d/rocky*.repo
bash
# grep -E '^(baseurl|#mirrorlist)' /etc/yum.repos.d/rocky.repo | head -2
#mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=BaseOS-$releasever$rltype
baseurl=https://mirrors.aliyun.com/rockylinux/$releasever/BaseOS/$basearch/os/
# dnf clean all; time dnf makecache (截取末尾)
Metadata cache created.
real 0m23.952s
# dnf repoinfo baseos | grep Repo-baseurl
Repo-baseurl : https://mirrors.aliyun.com/rockylinux/9/BaseOS/x86_64/os/
5. Ubuntu 24.04:改 sources.list 不生效 ✅
5.1 源已经不在 sources.list 里了
shell
# cat /etc/apt/sources.list
# Ubuntu sources have moved to the /etc/apt/sources.list.d/ubuntu.sources
# file, which uses the deb822 format. Use deb822-formatted .sources files
# to manage package sources in the /etc/apt/sources.list.d/ directory.
# See the sources.list(5) manual page for details.
真正的源在 /etc/apt/sources.list.d/ubuntu.sources,而且是多行格式:
makefile
Types: deb
URIs: http://archive.ubuntu.com/ubuntu
Suites: noble noble-updates noble-backports
Components: main universe restricted multiverse
Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg
Types: deb
URIs: http://security.ubuntu.com/ubuntu
Suites: noble-security
Components: main universe restricted multiverse
Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg
5.2 老教程的 sed,一个字节都没改到
shell
# sed -i 's|//archive.ubuntu.com|//mirrors.aliyun.com|g' /etc/apt/sources.list
# sed -i 's|//security.ubuntu.com|//mirrors.aliyun.com|g' /etc/apt/sources.list
# cmp /tmp/sources.list.before /etc/apt/sources.list && echo "sources.list 一个字节都没变"
sources.list 一个字节都没变
# apt-get update 2>&1 | grep -oE 'http://[a-z.]+' | sort | uniq -c
3 http://archive.ubuntu.com
1 http://security.ubuntu.com
命令不报错,apt update 也正常,只是还在走官方源 ------ 这是最难发现的那种「没生效」。
5.3 改 ubuntu.sources,而且两个地址都要改
只改 archive 的话:
arduino
# sed -i 's|//archive.ubuntu.com|//mirrors.aliyun.com|g' /etc/apt/sources.list.d/ubuntu.sources
# grep ^URIs /etc/apt/sources.list.d/ubuntu.sources
URIs: http://mirrors.aliyun.com/ubuntu
URIs: http://security.ubuntu.com/ubuntu
# apt-get update 2>&1 | grep -oE 'http://[a-z.]+' | sort | uniq -c
36 http://mirrors.aliyun.com
1 http://security.ubuntu.com
security 那一段还在走官方。完整写法:
bash
cp /etc/apt/sources.list.d/ubuntu.sources /etc/apt/sources.list.d/ubuntu.sources.bak
sed -i 's|//archive.ubuntu.com|//mirrors.aliyun.com|g' /etc/apt/sources.list.d/ubuntu.sources
sed -i 's|//security.ubuntu.com|//mirrors.aliyun.com|g' /etc/apt/sources.list.d/ubuntu.sources
apt update
arduino
# grep ^URIs /etc/apt/sources.list.d/ubuntu.sources
URIs: http://mirrors.aliyun.com/ubuntu
URIs: http://mirrors.aliyun.com/ubuntu
# apt-get update 2>&1 | grep -oE 'http://[a-z.]+' | sort | uniq -c
16 http://mirrors.aliyun.com
备份放在 sources.list.d/ 里、叫 ubuntu.sources.bak 的话,实测不会 被当成源读进去:上面只改了 archive 那一次,.bak 里还是 archive.ubuntu.com,而 apt update 里一次都没出现它。
5.4 加第三方源:apt-key 还能用,但换成 signed-by
以 nginx 官方源为例。老写法 apt-key add 在 24.04 上还能执行成功,但会打弃用警告:
vbnet
# apt-key add /tmp/nginx_signing.key; echo "apt-key 退出码=$?"
OK
apt-key 退出码=0
Warning: apt-key is deprecated. Manage keyring files in trusted.gpg.d instead (see apt-key(8)).
现在的写法:把 key 转成二进制放进 /etc/apt/keyrings/,在源里用 signed-by 指定它:
bash
install -d -m 0755 /etc/apt/keyrings
curl -fsSL https://nginx.org/keys/nginx_signing.key -o /tmp/nginx_signing.key
gpg --dearmor -o /etc/apt/keyrings/nginx.gpg < /tmp/nginx_signing.key
echo "deb [signed-by=/etc/apt/keyrings/nginx.gpg] http://nginx.org/packages/ubuntu noble nginx" \
| tee /etc/apt/sources.list.d/nginx.list
apt update
ruby
# apt-get update 2>&1 | grep -iE 'nginx.org|W:|E:'
Get:5 http://nginx.org/packages/ubuntu noble InRelease [3278 B]
Get:6 http://nginx.org/packages/ubuntu noble/nginx amd64 Packages [45.3 kB]
# apt policy nginx | head -6
nginx:
Installed: 1.24.0-2ubuntu7.18
Candidate: 1.30.5-1~noble
Version table:
1.30.5-1~noble 500
500 http://nginx.org/packages/ubuntu noble/nginx amd64 Packages
🔑 apt policy <包名> 能看到候选版本来自哪个源 ------ 排查「怎么装到的不是我想要的版本」就看它。
5.5 「Could not get lock」
另一个进程拿着 dpkg 的锁时(下面是我用一个脚本故意占住锁来复现的):
csharp
# apt-get install -y tree; echo "退出码=$?"
E: Could not get lock /var/lib/dpkg/lock-frontend. It is held by process 2879 (python3)
E: Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend), is another process using it?
退出码=100
apt-get不会等,直接退出(退出码 100);- 报错里直接写了是哪个进程占着 (
process 2879 (python3))------ 先看它是谁,等它结束。真实环境里最常见的是后台自动更新,这台机器上unattended-upgrades默认是enabled的。
别一上来就删锁文件,先看报错里写的是哪个进程、等它结束。锁释放后同一条命令直接成功:
java
# apt-get install -y tree (截取末尾)
Setting up tree (2.1.1-2ubuntu3.24.04.2) ...
6. 本篇速查(三台实测过的写法)
| 想做的事 | CentOS 7 | Rocky 9 | Ubuntu 24.04 |
|---|---|---|---|
| 判系统 | cat /etc/os-release |
同左 | 同左 |
| 更新索引 | yum makecache |
dnf makecache |
apt update |
| 装本地包(自动解依赖) | yum install ./x.rpm |
dnf install ./x.rpm |
apt install ./x.deb |
| 文件属于哪个包(未安装) | yum provides '*/名字' |
dnf provides '*/名字' |
apt-file search 路径 |
| 撤销上一次装卸 | yum history undo <ID> |
dnf history undo <ID> |
--- |
| 连配置一起删 | --- | --- | apt purge 包 及其 -common 包 |
| 源配置在哪 | /etc/yum.repos.d/*.repo |
同左 | /etc/apt/sources.list.d/ubuntu.sources |
| 换源后必做 | yum clean all && yum makecache |
dnf clean all && dnf makecache |
apt update |
| 实测能用的国内源 | mirrors.aliyun.com/centos-vault/7.9.2009 + epel-archive/7 |
mirrors.aliyun.com/rockylinux |
mirrors.aliyun.com/ubuntu |
这一篇最容易踩的坑:
- 🔴 CentOS 7 源失效,切
vault.centos.org前先curl -I------ 国内直连实测 403。 - 🔴 EPEL 7 的 metalink 会让 yum 卡死,改成
epel-archive的 baseurl。 - 🔴 Ubuntu 24.04 改
sources.list不生效;改ubuntu.sources要连 security 一起改。 - 🔴
apt remove nginx删不掉/etc/nginx,要 purgenginx-common。 - 🔴 Rocky 9 上
powertools叫crb;config-manager可能要先装dnf-plugins-core。 - 🔴 同一个命令,CentOS 7 和 Rocky 9 的包名可能不同(
policycoreutils-pythonvspolicycoreutils-python-utils)。 - ⚠️
check-update有更新时退出码是 100;apt-get撞锁退出码也是 100。
下一篇
(二)端口不通:firewalld / ufw / iptables / nftables / SELinux,同样三台机器实测。