Ubuntu 18.04服务器初始配置:遗留系统安全加固四层验证法

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 具有三大不可替代优势:

  1. 密钥体积小 :公钥仅 68 字节,私钥 32 字节,传输和存储开销极低,对嵌入式设备友好;
  2. 签名速度快 :基准测试显示, ed25519 签名速度是 rsa-3072 的 12 倍,验证速度快 2.5 倍,这意味着高频连接(如 VS Code Remote-SSH 自动重连)延迟更低;
  3. 无侧信道风险 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 字段为空。

解决方案分三步:

  1. 在 VS Code 设置中搜索 remote.SSH.configFile ,将其值设为 ~/.ssh/config (绝对路径)
  2. 编辑 ~/.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
  1. 最关键的一步:打开 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_server

Windows 用户请使用 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 的 sudo setuid 位丢失,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 的工作流分为三个明确层级:

  1. 策略层(Policy Layer) /etc/ufw/ufw.conf 中的 ENABLED=yes DEFAULT_INPUT_POLICY="deny" ,定义全局默认行为;
  2. 规则层(Rule Layer) /etc/ufw/user.rules /etc/ufw/user6.rules ,存储 ufw allow 80 等命令生成的规则;
  3. 内核层(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
# 若输出为空
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值