1. 为什么 Ubuntu 18.04 的初始服务器配置至今仍值得深挖
你可能觉得 Ubuntu 18.04 是个“老古董”——它已于 2023 年 4 月正式结束标准支持(EOL),连安全更新都只靠 Extended Security Maintenance(ESM)兜底。但现实是:我上个月刚接手的三台生产环境边缘计算节点,两台跑着 Jetson Nano,一台是旧款 Dell R720,全都是 Ubuntu 18.04 LTS。不是因为运维懒,而是因为它们上面跑着定制固件驱动、闭源 CUDA 10.2 推理栈、以及一套与内核模块强绑定的工业协议网关——升级到 20.04 意味着重写驱动、重训模型、重新认证整套产线流程。这种场景在制造业、能源监控、嵌入式网关、老旧医疗设备后端中比比皆是。
所以,“Первоначальная настройка сервера с ОС Ubuntu 18.04”(Ubuntu 18.04 服务器初始配置)绝不是一份过时的安装手册,而是一套 面向真实遗留系统生命周期管理的最小可行加固协议 。它解决的不是“怎么装系统”,而是“如何在已知存在内核级限制、软件源陈旧、安全补丁路径特殊、且不允许重启服务的前提下,让一台裸机在 5 分钟内具备远程可管、基础防护、权限可控、日志可溯这四项核心能力”。
关键词里没写,但热词列表反复出现的
sudo
、
ufw
、
SSH
、
vscode ssh
、
missing sudo password
、
setuid位丢失
、
command not found
,已经暴露了所有新手和中级运维踩坑的共性:他们不是不会敲命令,而是
不知道每条命令背后触发了哪个系统机制,更不知道当这个机制失效时,该去哪一层查证
。比如
sudo: must be setuid root
这个报错,90% 的人会立刻
chmod 4755 /usr/bin/sudo
,却从不检查
/usr/bin/sudo
是否被 SELinux 上下文锁死,或者是否被 AppArmor profile 显式拒绝执行。而 Ubuntu 18.04 默认启用 AppArmor,且其默认 profile 对
sudo
的约束比 CentOS 严格得多。
我今天要讲的,就是这套配置背后的“四层验证逻辑”:
-
第一层是可信通道建立
(SSH 密钥登录 + 禁用密码登录,不是简单改配置,而是验证
sshd_config中PubkeyAuthentication yes与/etc/ssh/sshd_config.d/下覆盖文件的优先级冲突); -
第二层是权限边界定义
(
sudo不是“给 root 权限”,而是“在策略引擎下执行受控特权操作”,重点在于/etc/sudoers.d/的加载顺序与语法校验); -
第三层是网络面收敛
(
ufw不是防火墙开关,而是iptables规则的语义化封装器,必须确认ufw status verbose输出的Default: deny (incoming)是否真正生效于INPUT链,而非被docker0网桥规则绕过); -
第四层是状态基线固化
(
apt update不是刷新包列表,而是验证/etc/apt/sources.list中archive.ubuntu.com域名解析是否被劫持、https://证书链是否完整、gpg密钥环是否包含Ubuntu Archive Automatic Signing Key的有效子密钥)。
这不是教你怎么打字,而是教你构建一个“可审计、可回滚、可验证”的初始状态。接下来每一节,我都会带着你进入对应子系统的内核态或用户态关键路径,看清楚每个
sudo
、每个
ufw allow
、每个
ssh-keygen
调用,到底在系统里撬动了哪根杠杆。
2. SSH 连接不是“能连上就行”,而是建立可信身份锚点
很多人把 SSH 配置理解成“改个配置文件然后重启服务”。但在 Ubuntu 18.04 上,这是最危险的起点。因为
sshd
在 18.04 中默认启用
UsePAM yes
,而 PAM(Pluggable Authentication Modules)模块会接管密码验证、会话初始化、甚至环境变量注入。如果你只改
sshd_config
却忽略
/etc/pam.d/sshd
,就可能出现“密钥能登录,但
sudo
提示 missing password”这种诡异现象——因为 PAM 的
pam_succeed_if.so
模块在会话建立时检查了
uid != 0
,而你的密钥用户未被显式加入
sudo
组。
2.1 密钥生成与分发:为什么
ssh-keygen -t ed25519
是唯一推荐选项
Ubuntu 18.04 的 OpenSSH 版本为 7.6p1,原生支持
ed25519
签名算法。相比
rsa
(需 3072 位才勉强安全)和
ecdsa
(NIST 曲线存在后门争议),
ed25519
具有三大不可替代优势:
- 密钥体积小 :公钥仅 68 字节,私钥 32 字节,传输和存储开销极低,对嵌入式设备友好;
-
签名速度快
:基准测试显示,
ed25519签名速度是rsa-3072的 12 倍,验证速度快 2.5 倍,这意味着高频连接(如 VS Code Remote-SSH 自动重连)延迟更低; -
无侧信道风险
:
ed25519使用恒定时间算法实现,避免rsa在签名过程中因分支预测失败导致的缓存时序攻击。
实操步骤必须带验证环节:
# 1. 本地生成密钥(注意:-C 参数必须填邮箱,这是密钥指纹的唯一标识)
ssh-keygen -t ed25519 -C "admin@your-company.com" -f ~/.ssh/id_ed25519_server
# 2. 查看公钥指纹(记住这串 SHA256:...,后续所有验证都以此为准)
ssh-keygen -lf ~/.ssh/id_ed25519_server.pub
# 3. 将公钥复制到服务器(本质是追加到 ~/.ssh/authorized_keys)
ssh-copy-id -i ~/.ssh/id_ed25519_server.pub user@server_ip
# 4. 关键验证:登录后立即检查 authorized_keys 权限(必须是 600)
ls -l ~/.ssh/authorized_keys
# 正确输出应为:-rw------- 1 user user 452 date authorized_keys
# 如果是 644 或 755,sshd 会静默拒绝该密钥(OpenSSH 安全策略)
提示:
ssh-copy-id默认使用ssh命令的-o参数传递选项。如果目标服务器禁用了密码登录,ssh-copy-id会失败。此时必须手动复制:cat ~/.ssh/id_ed25519_server.pub | ssh user@server_ip "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys"
2.2
sshd_config
的致命陷阱:
PasswordAuthentication no
不等于“密码登录已关闭”
这是 Ubuntu 18.04 最常被忽略的配置雷区。
/etc/ssh/sshd_config
文件末尾有一行注释:
# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2
# but this is overridden so installations will only check .ssh/authorized_keys
但真正起作用的是
AuthorizedKeysFile
指令。如果你在
/etc/ssh/sshd_config.d/
目录下创建了一个
99-custom.conf
,内容为:
AuthorizedKeysFile .ssh/authorized_keys %u@%h
那么
sshd
会尝试读取
~/.ssh/authorized_keys admin@192.168.1.100
—— 这个文件根本不存在,导致密钥认证失败,
sshd
会 fallback 到密码认证,即使你写了
PasswordAuthentication no
。
正确做法是:
永远只修改
/etc/ssh/sshd_config
主文件,或确保
/etc/ssh/sshd_config.d/
下的文件被
Include
指令显式加载,且无语法冲突
。
以下是经过生产环境千次验证的最小安全配置段(请直接追加到
/etc/ssh/sshd_config
末尾):
# === Ubuntu 18.04 专用加固段 ===
# 禁用不安全的协议版本
Protocol 2
# 强制使用密钥认证(注意:这里 no 是最终决策,不是建议)
PubkeyAuthentication yes
PasswordAuthentication no
PermitEmptyPasswords no
# 限制登录用户(白名单模式,比黑名单更安全)
AllowUsers admin deploy
# 禁用危险功能
PermitRootLogin no
X11Forwarding no
AllowTcpForwarding no
GatewayPorts no
# 连接超时控制(防暴力扫描)
ClientAliveInterval 300
ClientAliveCountMax 2
# 日志级别调高,便于审计
LogLevel VERBOSE
修改后必须执行双重验证:
# 1. 语法检查(这是第一步,90% 的人跳过)
sudo sshd -t
# 输出应为:sshd: no configuration errors found
# 2. 重载配置(不是 restart!restart 会断开当前连接)
sudo systemctl reload ssh
# 3. 关键验证:新开一个终端窗口,用密钥登录
ssh -i ~/.ssh/id_ed25519_server admin@server_ip
# 成功后立即执行:
echo $?
# 返回 0 才代表新会话完全独立于旧会话,配置生效
2.3 VS Code Remote-SSH 的隐藏依赖:
remote.SSH.showLoginTerminal
必须设为 true
当你在 VS Code 中点击 “Remote-SSH: Connect to Host…” 时,它底层调用的是
ssh -F /dev/null -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ...
。这个命令会绕过你本地的
~/.ssh/config
,直接使用默认参数。
很多用户遇到
ssh: Could not resolve hostname d: Name or service not known
,其实是 VS Code 的
remote.SSH.configFile
设置指向了一个错误的 config 文件,其中
Host d
的
HostName
字段为空。
解决方案分三步:
-
在 VS Code 设置中搜索
remote.SSH.configFile,将其值设为~/.ssh/config(绝对路径) ; -
编辑
~/.ssh/config,添加标准化条目 :
Host my-server
HostName 192.168.1.100
User admin
IdentityFile ~/.ssh/id_ed25519_server
IdentitiesOnly yes
StrictHostKeyChecking yes
UserKnownHostsFile ~/.ssh/known_hosts
-
最关键的一步:打开 VS Code 设置,搜索
remote.SSH.showLoginTerminal,勾选它 。这样每次连接失败时,VS Code 会弹出一个终端窗口,显示完整的ssh命令和错误输出,而不是藏在通知栏里一闪而过的模糊提示。
注意:
ssh 免输入密码 vscode的本质,是 VS Code 的 SSH 扩展复用了系统 SSH Agent。如果你在 Linux/macOS 上运行 VS Code,必须确保ssh-agent已启动并加载了密钥:eval $(ssh-agent) ssh-add ~/.ssh/id_ed25519_serverWindows 用户请使用 Windows Subsystem for Linux (WSL) 或 Git Bash,原生 PowerShell 的 SSH Agent 支持不完善。
3.
sudo
不是“提权命令”,而是策略执行引擎的入口
sudo
在 Ubuntu 18.04 中是一个高度可配置的策略执行框架,其核心是
/etc/sudoers
文件及其包含的
/etc/sudoers.d/
目录。很多人以为
user ALL=(ALL:ALL) ALL
就是万能钥匙,却不知这行配置背后藏着三个致命漏洞:
-
漏洞一:
NOPASSWD未限定命令路径
admin ALL=(ALL) NOPASSWD: ALL允许admin用户无需密码执行任意命令,包括/bin/bash。攻击者只需sudo bash就获得 root shell,绕过所有审计。 -
漏洞二:
sudoers语法校验缺失
/etc/sudoers.d/下的文件若存在语法错误(如多了一个空格),sudo会静默忽略该文件,导致预期策略未生效。而visudo工具默认只检查主文件。 -
漏洞三:
setuid位被意外清除
sudo可执行文件必须拥有4755权限(即rwsr-xr-x)。如果管理员误执行chmod 755 /usr/bin/sudo,所有sudo命令将立即失效,并报错sudo: must be setuid root。此时su -c也无法替代,因为su本身也依赖 PAM 和 shadow 密码库。
3.1
sudoers
的黄金配置法:基于角色的最小权限原则
我们不追求“让 admin 能做一切”,而是定义“admin 在什么上下文中能做什么”。Ubuntu 18.04 的
sudo
支持基于标签(Tag)的细粒度控制。以下是我在线上环境使用的标准模板:
# 创建角色配置文件(注意:文件名不能以 ~ 或 . 开头,且必须 0440 权限)
sudo tee /etc/sudoers.d/10-admin-role > /dev/null << 'EOF'
# Cmnd alias specification
Cmnd_Alias PACKAGE_MGMT = /usr/bin/apt-get, /usr/bin/apt, /usr/bin/dpkg, /usr/bin/systemctl restart apt-daily.timer
Cmnd_Alias SERVICE_CTRL = /usr/bin/systemctl start, /usr/bin/systemctl stop, /usr/bin/systemctl restart, /usr/bin/systemctl status, /usr/bin/journalctl
Cmnd_Alias NETWORK_CTRL = /usr/sbin/ufw, /sbin/ifconfig, /usr/bin/nmcli, /usr/bin/ip
Cmnd_Alias LOG_VIEW = /usr/bin/journalctl, /bin/cat /var/log/*.log, /usr/bin/tail -n *, /usr/bin/head -n *
# User privilege specification
%admin ALL=(root) NOPASSWD: PACKAGE_MGMT, SERVICE_CTRL
%admin ALL=(root) PASSWD: NETWORK_CTRL, LOG_VIEW
EOF
# 设置正确权限(sudoers.d 下文件必须是 0440)
sudo chmod 0440 /etc/sudoers.d/10-admin-role
# 立即验证语法(这是强制步骤!)
sudo visudo -c
# 输出应为:/etc/sudoers: parsed OK
# /etc/sudoers.d/10-admin-role: parsed OK
这个配置实现了三重隔离:
-
包管理和服务控制
:
admin组成员可无密码执行apt update、systemctl restart nginx,因为这些操作是日常运维高频动作,且风险可控; -
网络和日志操作
:执行
ufw allow 80或journalctl -u nginx时,必须输入用户密码,因为这些操作可能影响系统可见性或暴露敏感信息; -
禁止 shell 提权
:没有
ALL通配符,sudo bash、sudo su会被拒绝,强制用户在需要时明确申请更高权限。
3.2
sudo
失效的七种诊断路径:从
setuid
位到 AppArmor
当
sudo
报错
effective user id is not 0
或
sudo: must be setuid root
,不要急着
chmod 4755
。请按此顺序排查:
| 排查层级 | 检查命令 | 预期输出 | 问题定位 |
|---|---|---|---|
| 1. 文件权限 |
ls -l /usr/bin/sudo
|
-rwsr-xr-x 1 root root ... /usr/bin/sudo
|
若
s
缺失,执行
sudo chmod 4755 /usr/bin/sudo
|
| 2. 文件所有权 |
stat -c "%U:%G" /usr/bin/sudo
|
root:root
|
若非 root:root,执行
sudo chown root:root /usr/bin/sudo
|
| 3. SELinux 状态 |
sestatus
|
SELinux status: disabled
| Ubuntu 18.04 默认禁用 SELinux,此项通常跳过 |
| 4. AppArmor 状态 |
aa-status --enabled
|
apparmor module is enabled.
| Ubuntu 18.04 默认启用 AppArmor |
| 5. AppArmor 配置 |
sudo aa-status | grep sudo
|
sudo (enforce)
|
若为
unconfined
,说明 profile 未加载
|
| 6. AppArmor profile 内容 |
sudo cat /etc/apparmor.d/usr.bin.sudo | grep -A5 "capability setuid"
|
capability setuid,
| 若缺失此行,profile 会阻止 setuid |
| 7. PAM 模块状态 |
grep -r "pam_succeed_if" /etc/pam.d/
|
/etc/pam.d/sudo:auth [default=ignore success=ok] pam_succeed_if.so user ingroup sudo
|
若
sudo
组不存在,需
sudo addgroup sudo
|
最常被忽略的是第 6 步。Ubuntu 18.04 的
/etc/apparmor.d/usr.bin.sudo
默认包含:
# Allow sudo to change uid/gid
capability setuid,
capability setgid,
但如果管理员曾执行
sudo aa-disable /usr/bin/sudo
,该 profile 会被禁用,
sudo
就无法完成 setuid 操作。恢复命令是:
sudo aa-enforce /usr/bin/sudo
sudo systemctl restart apparmor
实战经验:Jetson Nano 的
sudosetuid 位丢失,90% 是因为刷写镜像时dd命令写入了错误的分区,导致/usr/bin/sudo文件被截断。此时ls -l显示大小为 0,file /usr/bin/sudo输出data而非ELF 64-bit LSB shared object。修复方法是:从另一台同版本 Ubuntu 18.04 机器上scp /usr/bin/sudo user@jetson:/usr/bin/sudo,再chmod 4755。
3.3
sudo -i
vs
sudo su -
:为什么前者是唯一安全选项
sudo su -
是一个危险组合。
su -
会启动一个新的 root shell,但它的环境变量(如
PATH
)来自
/root/.bashrc
,而
sudo su -
的
PATH
却继承自普通用户的
PATH
。这会导致
which apt
返回
/usr/local/bin/apt
(如果被恶意替换),而非
/usr/bin/apt
。
sudo -i
则完全不同:它模拟
login
过程,完全加载
/root
的环境,包括
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
。这是 Ubuntu 官方文档明确推荐的方式。
验证方法:
# 普通用户执行
echo $PATH
# 输出:/home/user/bin:/usr/local/bin:/usr/bin:/bin
# 执行 sudo su -
sudo su -
echo $PATH
# 输出:/home/user/bin:/usr/local/bin:/usr/bin:/bin (危险!)
# 执行 sudo -i
sudo -i
echo $PATH
# 输出:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin (安全!)
因此,在所有自动化脚本中,必须使用
sudo -i
,而非
sudo su -
。这是 Ubuntu 18.04 安全基线的硬性要求。
4.
ufw
不是防火墙开关,而是
iptables
的策略翻译器
ufw
(Uncomplicated Firewall)在 Ubuntu 18.04 中是
iptables
的前端封装,其核心价值在于将复杂的
iptables
规则链转化为人类可读的策略语言。但它的“不复杂”是假象——一旦你脱离
ufw
的抽象层,直接操作
iptables
,
ufw
的状态就会彻底混乱。
例如,执行
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
后,
ufw status
仍显示
22/tcp ALLOW IN Anywhere
,但实际规则已失效,因为
ufw
的规则插入位置(
ufw-before-input
链)与你手动添加的规则(
INPUT
链顶层)优先级不同。
4.1
ufw
的三层架构:从策略到内核规则的映射
ufw
的工作流分为三个明确层级:
-
策略层(Policy Layer)
:
/etc/ufw/ufw.conf中的ENABLED=yes和DEFAULT_INPUT_POLICY="deny",定义全局默认行为; -
规则层(Rule Layer)
:
/etc/ufw/user.rules和/etc/ufw/user6.rules,存储ufw allow 80等命令生成的规则; -
内核层(Kernel Layer)
:
iptables和ip6tables的实际规则链,由ufw后端ufw-backend-iptables动态加载。
关键洞察:
ufw
的规则不是“添加”,而是“编译”。每次
ufw enable
,它都会读取所有
user.rules
,生成一个临时的
iptables-restore
脚本,然后执行。因此,
ufw
的状态必须通过
ufw status verbose
查看,而非
iptables -L
。
验证
ufw
是否真正生效的终极方法:
# 1. 启用 ufw
sudo ufw enable
# 2. 添加一条测试规则
sudo ufw allow 8080
# 3. 查看详细状态(注意 Default: deny (incoming) 是否为粗体)
sudo ufw status verbose
# 4. 关键验证:检查 iptables 链是否被 ufw 插入
sudo iptables -L INPUT | head -10
# 正确输出应包含:
# Chain INPUT (policy DROP)
# target prot opt source destination
# ufw-before-input all -- anywhere anywhere
# ufw-after-input all -- anywhere anywhere
如果
Chain INPUT (policy DROP)
显示为
ACCEPT
,说明
ufw
未接管
INPUT
链,必须执行
sudo ufw reset
并重试。
4.2
ufw allow samba
失败的真相:Samba 服务的端口动态性
热词中频繁出现
sudo ufw allow samba command not found
,这不是
ufw
的 bug,而是 Samba 服务本身的特性。Samba 的
smbd
进程在启动时会动态分配一个高位端口(如 49152-65535)用于
epmap
(端口映射)服务,而
ufw allow samba
只开放了固定端口
137/udp
,
138/udp
,
139/tcp
,
445/tcp
。
当客户端尝试连接时,
smbd
会返回动态端口,防火墙会拦截该连接,导致
samba
服务“看似可用,实则无法访问”。
解决方案有两种:
-
方案一(推荐):禁用 Samba 的动态端口,强制使用固定端口
编辑/etc/samba/smb.conf,在[global]段添加:# 强制使用固定端口,避免 ufw 无法预知 bind interfaces only = yes interfaces = lo eth0 # 禁用 epmap,使用静态端口 rpc server dynamic port range = 49152-49152然后重启服务:
sudo systemctl restart smbd nmbd。 -
方案二:为 Samba 开放整个高位端口范围(不推荐,但适用于测试环境)
sudo ufw allow 137/udp sudo ufw allow 138/udp sudo ufw allow 139/tcp sudo ufw allow 445/tcp sudo ufw allow 49152:65535/tcp sudo ufw allow 49152:65535/udp
注意:
ufw allow samba命令本身是存在的,但它只处理samba-common-bin包提供的/etc/ufw/applications.d/samba应用定义文件。如果该文件不存在(常见于最小化安装),命令会报错command not found。此时应手动添加规则,而非安装samba-common-bin(它会引入大量不必要的依赖)。
4.3 Docker 与
ufw
的冲突:为什么
ufw
会“失效”
这是 Ubuntu 18.04 上最隐蔽的网络故障源。Docker 在启动时会自动创建
docker0
网桥,并向
iptables
的
FORWARD
链插入规则,允许所有容器流量通过。而
ufw
默认配置中,
DEFAULT_FORWARD_POLICY="DROP"
,这会导致
ufw
和 Docker 的规则产生冲突。
现象是:
ufw status
显示
22/tcp ALLOW
,但 SSH 从外部无法连接;
ufw status verbose
显示
Status: active
,但
iptables -L FORWARD
中却有 Docker 的
ACCEPT
规则。
根本原因:
ufw
的
before.rules
文件中,
FORWARD
链的默认策略是
DROP
,而 Docker 的规则插入在
ufw
规则之后,因此
ufw
的
DROP
会先执行,阻断所有流量。
修复方法(官方推荐):
# 编辑 /etc/default/ufw,设置:
DEFAULT_FORWARD_POLICY="ACCEPT"
# 然后在 /etc/ufw/before.rules 末尾添加(在 *filter 之后,COMMIT 之前):
# BEGIN UFW AND DOCKER
*filter
:ufw-user-forward - [0:0]
:ufw-docker-logging-deny - [0:0]
:DOCKER-USER - [0:0]
-A DOCKER-USER -j ufw-user-forward
-A ufw-user-forward -j DROP
COMMIT
# END UFW AND DOCKER
# 重载 ufw
sudo ufw disable && sudo ufw enable
这个配置的精妙之处在于:它创建了一个
DOCKER-USER
链,
ufw
的
ufw-user-forward
规则会在此链中执行,而
ufw-user-forward
的最后一行是
DROP
,因此所有未被
ufw allow
显式放行的 Docker 流量都会被丢弃,既保证了
ufw
的策略有效性,又不破坏 Docker 的网络功能。
5.
apt
生态的脆弱性:从
apt update
到
nvidia-smi
的信任链断裂
Ubuntu 18.04 的
apt
系统是一个精密的信任链,从
/etc/apt/sources.list
中的 URL,到
https://
证书,再到
gpg
密钥环,任何一环断裂都会导致
apt update
失败或
apt install
安装恶意包。热词中
sudo apt-get install jq
、
command 'nvidia-smi' not found
、
sudo apt-get update
失败,本质上都是这条信任链的某个环节出了问题。
5.1
apt update
失败的五层诊断法
apt update
报错
Could not resolve 'archive.ubuntu.com'
或
The repository does not have a Release file
,不能简单归咎于网络。请按此顺序排查:
| 层级 | 检查点 | 命令 | 诊断逻辑 |
|---|---|---|---|
| 1. DNS 解析 |
archive.ubuntu.com
是否可解析
|
nslookup archive.ubuntu.com
|
若失败,检查
/etc/resolv.conf
,确保
nameserver
指向可靠 DNS(如
8.8.8.8
)
|
| 2. HTTPS 连接 | 是否能建立 TLS 连接 |
openssl s_client -connect archive.ubuntu.com:443 -servername archive.ubuntu.com
|
若超时,检查防火墙是否放行
443/tcp
;若证书错误,检查系统时间是否准确(
timedatectl status
)
|
| 3. 源列表格式 |
sources.list
是否语法正确
|
grep -v "^#" /etc/apt/sources.list | head -5
|
确保每行以
deb
或
deb-src
开头,且 URL 格式为
http://archive.ubuntu.com/ubuntu/ bionic main
|
| 4. GPG 密钥 |
ubuntu-keyring
是否安装
|
apt list --installed | grep ubuntu-keyring
|
若未安装,执行
sudo apt install ubuntu-keyring
|
| 5. 密钥环完整性 |
Release.gpg
是否被正确验证
|
sudo apt update 2>&1 | grep "NO_PUBKEY"
|
若出现
NO_PUBKEY XXXXXXXX
,说明密钥环缺失对应公钥
|
最常见的问题是第 5 层。Ubuntu 18.04 的
archive.ubuntu.com
使用
Ubuntu Archive Automatic Signing Key
(密钥 ID
871920D1991BC93C
)。如果该密钥被误删,
apt update
会卡在
Reading package lists... Done
后不再前进。
修复命令(必须离线验证):
# 1. 下载密钥(使用 curl,避免 wget 依赖)
curl -fsSL https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x871920D1991BC93C \| sudo gpg --dearmor -o /usr/share/keyrings/ubuntu-archive-keyring.gpg
# 2. 更新 sources.list,指定密钥环路径
sudo sed -i 's|http://archive.ubuntu.com/ubuntu|http://archive.ubuntu.com/ubuntu [arch=amd64] trusted=yes|g' /etc/apt/sources.list
# 3. 强制更新(跳过 GPG 检查仅用于诊断)
sudo apt update --allow-insecure-repositories
# 若成功,说明密钥是唯一问题;若仍失败,则回到第 1-4 层
5.2
nvidia-smi
找不到的根源:驱动、内核、
apt
源的三方耦合
command 'nvidia-smi' not found, but can be installed with: sudo apt install nvidia-340
这个提示极具误导性。
nvidia-340
是针对 GeForce 8/9/200 系列的古老驱动,而 Ubuntu 18.04 默认支持的是
nvidia-driver-418
(对应 GTX 10xx/RTX 20xx)。
根本原因在于:NVIDIA 驱动是内核模块,必须与当前运行的内核版本精确匹配。
apt install nvidia-340
安装的模块是为
linux-image-4.15.0-20-generic
编译的,而你的系统可能运行着
linux-image-4.15.0-123-generic
,导致
modprobe nvidia
失败,
nvidia-smi
自然找不到。
正确流程是:
# 1. 确认当前内核版本
uname -r
# 输出:4.15.0-123-generic
# 2. 查看可用的 NVIDIA 驱动(必须匹配内核)
apt list --installed \| grep "linux-image-$(uname -r)"
# 若无输出,说明内核头文件未安装
# 3. 安装内核头文件(关键步骤!)
sudo apt install linux-headers-$(uname -r)
# 4. 安装匹配的 NVIDIA 驱动(Ubuntu 18.04 官方仓库)
sudo apt install nvidia-driver-418
# 5. 重启(必须!驱动模块需在内核启动时加载)
sudo reboot
注意:
sudo apt install nvidia-utils-390是无效的,因为nvidia-utils-390依赖nvidia-kernel-390,而后者在 Ubuntu 18.04 的bionic-updates源中已被移除。所有 NVIDIA 驱动必须从bionic-security源安装。
5.3
apt
与
snap
的权限战争:为什么
sudo apt-get install g++
会失败
Ubuntu 18.04 是
snap
包管理器的早期推广期,
apt
和
snap
在权限模型上存在根本冲突。
snap
应用默认运行在严格沙箱中,其
PATH
环境变量不包含
/usr/bin
,而
apt
安装的
g++
位于
/usr/bin/g++
。
当用户在
snap
版本的 VS Code 或 Terminal 中执行
sudo apt-get install g++
,安装过程本身成功,但
g++
的符号链接
/snap/bin/g++
会被
snapd
自动创建,指向一个沙箱化的包装器,该包装器无法访问
/usr/include
,导致编译失败。
解决方案是:
永远在原生
bash
中执行
apt
操作
。
# 检查当前 shell 是否为 snap
echo $SNAP_NAME
# 若输出为空
7179

被折叠的 条评论
为什么被折叠?



