ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Ubuntu 20.04离线安装Realtek无线网卡驱动完整指南

Ubuntu 20.04离线安装Realtek无线网卡驱动完整指南 装完 Ubuntu 20.04 之后发现右上角根本没有 WiFi 图标设置里也没有“无线网络”选项那一刻的心情我太懂了。更绝望的是这台机器正好是个无线路由器环境身边连个网线口都找不到手上只有一个U盘和一台能上网的Windows电脑。这时候要解决的就是在完全离线的情况下给这块 Realtek b852 无线网卡把驱动装上——而真正的难点从来不在“编译”本身在于你怎么把一整套依赖工具链也一起搬过去。这篇文章就是把我实际操作中走过的完整流程、踩过的坑以及最终稳定可复现的离线安装方案整理出来。无论你是刚装完双系统发现没网的新手还是公司内网环境里必须离线部署 Linux 的运维只要你手上是一块 Realtek 无线网卡且系统是 Ubuntu 20.04这套思路都适用。1. 先搞清楚你手里这块网卡到底是谁家的方案1.1 “Realtek b852”并不等于芯片型号很多人看到网卡包装盒上写着“Realtek b852”就跑去搜“b852 driver”结果搜出来的东西七零八落根本对不上号。这里必须先澄清一个关键概念b852 是厂商的销售型号不是 Realtek 的芯片方案型号。瑞昱Realtek的无线网卡芯片一般是以 RTL 开头比如 RTL8812AU、RTL8821CU、RTL8188EU 这些。包装盒上印的 b852 可能只是某个 OEM 厂商给这个网卡起的商业代号同一个代号在不同批次上可能还对应不同的芯片。所以在安装驱动之前第一步是确认芯片真实方案而不是急着找“b852 驱动”。确认方法很简单把网卡插到电脑上然后执行lsusb如果它是一块 USB 接口的无线网卡输出里会有一行以Realtek Semiconductor Corp.开头的内容后面跟着的就是 USB 厂商 ID 和设备 ID比如Bus 001 Device 002: ID 0bda:b812 Realtek Semiconductor Corp. RTL8812AU 802.11a/b/g/n/ac 2T2R DB WLAN Adapter如果是 PCIe 接口的网卡比如笔记本内置的则用lspci -nnk | grep -i net0bda是 Realtek 的固定厂商 ID后面的b812才是真正的设备 ID。不同设备 ID 对应不同芯片方案。举个例子常见的几种对应关系大致是USB ID芯片方案接口类型备注0bda:8812 / 0bda:b812RTL8812AUUSB 2.0/3.0老经典社区驱动支持最完善0bda:c811RTL8811CUUSB单天线 AC 600M 常见0bda:c82bRTL8822CUUSB带蓝牙方案驱动麻烦一些0bda:8179RTL8188EUUSB老款 150M驱动相对简单按照我经手的案例印着 b852 的网卡大多数情况下是 RTL8812AU 方案。但你在自己的机器上一定要以lsusb的实际输出为准这一步千万不要跳否则后面的驱动选型大概率是白折腾。1.2 从芯片方案到驱动源码包的对应关系确认了芯片方案之后驱动选择就清晰多了。常见的选择有这么几类Realtek 官方中文网/英文网驱动包瑞昱官网有各型号的 Linux 驱动源码下载但老型号的官方驱动停留在一个很老的内核适配版本上在 Ubuntu 20.04 的 5.4 / 5.8 / 5.13 内核上经常会编译报错。我不太推荐它作为首选。社区维护驱动aircrack-ng/rtl8812au这个仓库专门维护 RTL8812AU/8814AU 系列内核 API 变化后更新得很快Ubuntu 20.04 上编译通过率非常高。GitHub 上直接搜 rtl8812au选 star 数最多的 aircrack-ng 分支就行。厂商定制驱动部分网卡厂商如 EDUP、Comfast会提供自己的驱动压缩包本质上还是改过的 Realtek 官方驱动。能用但优先级排在社区驱动之后。如果你是 RTL8821CU / RTL8822CU我建议找morrownr/8821cu-20210916或者对应的rtw88主线驱动思路如果是 RTL8188EUaircrack-ng/rtl8188eus这个仓库也维护得不错。这里有一个很实在的经验优先选社区维护的驱动仓库而不是 Realtek 官方原版。原因很简单Linux 内核的 API 变动非常频繁官方驱动往往在新内核上会出现类似于implicit declaration of function这种编译错误而社区维护的项目通常会在几周内修复。既然你已经处于离线场景必然希望一次编译就成功没有太多试错的余地所以选社区活跃仓库更稳。2. 离线安装最难啃的骨头依赖不是驱动2.1 全新 Ubuntu 20.04 默认缺了哪些东西驱动源码拿到手之后编译还缺一整套工具链。很多第一次尝试离线安装的人会犯一个错误只把驱动源码拷到离线机器上然后发现make命令都不存在。在 Ubuntu 20.04 上编译一个内核模块无线网卡驱动本质就是内核模块需要的最小依赖大致包括build-essential里面包含了gcc、g、make、dpkg-dev等基础编译工具是整个工具链的入口。dkmsDynamic Kernel Module Support也就是“动态内核模块支持”。它可以把驱动登记到系统里将来你的内核升级时自动重新编译驱动不至于换个内核版本网卡就挂了。linux-headers-$(uname -r)这可能是最重要的东西。编译内核模块需要当前运行内核的头文件否则编译器不知道内核导出了哪些函数、数据结构长什么样。linux-firmware部分 Realtek 驱动在运行时还需要从/lib/firmware/rtlwifi/目录加载固件.bin文件缺了它驱动能装上但 dmesg 里会报固件下载失败。其中build-essential和dkms在全新系统上默认基本都没装linux-headers默认只带了一个 generic 包的空壳真正对应内核版本的那一个也没有。如果你是桌面版安装的话linux-firmware一般默认会有但不保证版本匹配。2.2 理清依赖关系比记命令更重要我建议你不要死记硬背这些包名而是理解它们之间的关系这样换内核版本、换 Ubuntu 小版本你都知道该带什么。依赖链路大致是这样的dkms ├── build-essential提供 gcc / make / dpkg-dev ├── linux-headers-generic元包指向当前内核版本的头文件 └── linux-headers-$(uname -r)实际编译时的头文件dkms依赖build-essentialbuild-essential里包含编译器linux-headers-generic是一个元包它不直接提供文件而是指向当前内核版本对应的linux-headers-5.x.x-xx-generic。在离线机器上我们用uname -r看到的输出才是真正要匹配的版本。举个例子如果uname -r输出是5.4.0-150-generic那么你需要的头文件包就是linux-headers-5.4.0-150-generic。这个版本必须精确一致差一个小版本都没法用。我见过一个很典型的坑有人只拷贝了linux-headers-generic和linux-headers-5.4.0-26-generic但离线机器实际运行的却是5.4.0-42-generic结果 dkms 编译时一直报找不到/usr/src/linux-headers-5.4.0-42-generic。所以无论如何离线机器上先执行一把uname -r把这个输出记下来后面所有打包物料都以它为准。2.3 容易被忽略的版本匹配细节除了内核头文件版本要和uname -r严格一致之外还有几个小坑值得提前提醒第一gcc版本不能太老。Ubuntu 20.04 默认的 gcc 是 9.x社区驱动在适配新内核时基本都是按较新的 gcc 测试的如果你从什么奇奇怪怪的地方拷了一个 gcc-4.8 的 deb 包来离线装大概率是在给自己找麻烦。直接用 20.04 软件源里的默认版本最靠谱。第二dkms版本在 Ubuntu 20.04 中是 2.8.x它和较新内核配合时偶尔会有兼容问题但总体问题不大。如果遇到dkms: failed to build的报错可以先不用 dkms 方式直接用最原始的make make install把模块装上先把网卡跑起来再说。第三如果你是从一台 Ubuntu 20.04 机器上拷贝 deb 包到另一台 Ubuntu 20.04 机器注意架构必须一致。绝大多数情况下都是 amd64但也有人拿 32 位系统或者 arm64 系统当“辅机”那装上去是完全不行的。3. 离线物料的筹备一台联网机器就够了3.1 方案一精确下载依赖包适合网络不太好的人最稳妥的物料筹备方式是在一台同样装有 Ubuntu 20.04 且能联网的机器上用apt download把需要的软件包及它们的依赖一个个下载下来。比如先确认需要的包列表sudo apt update apt depends build-essential dkms然后根据输出把依赖包都用apt download拉下来cd ~/offline-packages apt download build-essential dkms linux-headers-generic linux-headers-$(uname -r)这个方案的问题在于apt download只下载你指定的包不会自动下载这些包的依赖。你需要先分析依赖关系再手动把每个依赖也下载一遍。对于build-essential这种依赖链比较长的包来说用手动方式收集很容易漏。如果你一定要用这个方案可以借助apt-cache depends去递归查询但说实话效率不高比较容易漏包。3.2 方案二直接打包 apt 缓存目录我强烈推荐我实际测试过很多次之后更推荐的做法是在联网机器上先模拟安装一遍然后直接打包/var/cache/apt/archives/目录。操作方式是这样的。联网机器上执行sudo apt update sudo apt install build-essential dkms linux-firmware安装完成后apt 会把所有下载下来的 deb 包保留在/var/cache/apt/archives/目录。我们直接把这个目录下的所有*.deb拷走cd /var/cache/apt/archives/ tar -czf ~/offline-driver-deps.tgz *.deb然后把offline-driver-deps.tgz通过 U 盘拷贝到离线机器上解压。假设解压到了/home/user/deps/目录接下来这一步非常关键cd /home/user/deps/ sudo apt install ./*.deb注意这里不要用sudo dpkg -i *.deb。虽然dpkg -i也能装但它不会自动处理依赖顺序很可能遇到“先装了 A但 A 依赖的 B 还没装”导致的报错。而apt install ./*.deb会把本地 deb 包作为一个整体交给 apt 处理apt 会智能排序自动解决包之间的依赖顺序问题就算报错也会明确告诉你缺什么。为什么这个方案更稳因为apt install已经把整棵依赖树的所有包都放进了缓存目录你打包带走的就是一套完整闭环不需要手动收集依赖。唯一要注意的是不要在联网机器上执行apt clean或者apt autoclean否则缓存目录会被清空。3.3 不要漏掉驱动源码包和固件文件依赖包解决了驱动源码包也别忘。去 GitHub 下载驱动源码的 zip 包或者用台式机上已经克隆好的仓库重新打成压缩包。我这里还是建议用 zip 或者 tar.gz 格式避免 Windows 和 Linux 之间来回传文件时出现换行符问题。驱动源码传到离线机器之后先做一次完整性校验md5sum rtl8812au-master.zip和你在联网机器上记录下来的校验值比一下。这一步看着没用但当你面对一个 200MB 的源码包在传输过程中损坏时就知道校验能省多少时间了。另外linux-firmware的 deb 包最好也带上因为它包含/lib/firmware/rtlwifi/下的固件文件。很多网卡驱动加载时只缺一两个.bin文件系统会在 dmesg 里告诉你缺什么名字。与其等那一刻再去单文件拷贝不如一开始就装上完整固件包。4. 驱动编译安装与 dkms 的正确集成方式4.1 常规编译安装流程先说最简单直接的方案。假设你已经拿到了rtl8812au-master源码并解压到目录里cd rtl8812au-master sudo make -j$(nproc) sudo make install这里-j$(nproc)表示用 CPU 所有核心并行编译能明显缩短时间。编译过程中如果看到像Kernel preparation unnecessary for this kernel. Skipping...这样的信息这不是报错是正常提示。真正需要警惕的是Error 1或者Error 2结尾的输出。编译完成后把模块手动加载起来看看sudo modprobe 8812au然后立刻用dmesg | tail -20查看内核日志。如果驱动正常加载一般会看到类似Realtek Wireless的识别信息再配合iwconfig就能看到wlan0接口了。但直接用make install有个问题下次内核一升级模块文件还在但它和新内核版本对不上系统会把旧模块单独放到一个目录里新内核根本不会加载它。也就是说你升级一次内核网卡基本又要重新编译一次。4.2 用 dkms 接管让内核升级后依然稳定为了避免“升级内核就掉网卡”我强烈建议一开始就把驱动登记进 dkms。很多社区驱动源码根目录下自带dkms.conf比如 aircrack-ng 的 rtl8812au 仓库就有。这种情况下操作起来很简单sudo dkms add . sudo dkms build -m rtl8812au -v 版本号 sudo dkms install -m rtl8812au -v 版本号版本号可以看dkms.conf文件里的PACKAGE_VERSION字段。比如它写的是5.6.4.2那命令就是sudo dkms build -m rtl8812au -v 5.6.4.2 sudo dkms install -m rtl8812au -v 5.6.4.2装完之后模块会自动复制到/lib/modules/$(uname -r)/updates/dkms/并且自动运行depmod注册。你可以用这个命令验证dkms status输出类似rtl8812au/5.6.4.2, 5.4.0-150-generic, x86_64: installed就说明已经装好了。如果源码根目录下没有dkms.conf也可以手动写一个。我通常会在源码目录下创建dkms.conf内容大致是PACKAGE_NAMErtl8812au PACKAGE_VERSION5.6.4.2 BUILT_MODULE_NAME[0]8812au DEST_MODULE_LOCATION[0]/kernel/drivers/net/wireless/ AUTOINSTALLyes MAKE[0]make CLEANmake clean写完后再执行dkms add .就可以了。这里有个细节要注意BUILT_MODULE_NAME必须和你编译出来的.ko文件名一致比如模块名就是8812au.ko。4.3 Secure Boot 签名一个容易被忽略的拦路虎如果你安装 Ubuntu 20.04 的时候没有关闭 BIOS 里的 Secure Boot安全启动那么后续会碰到一个很诡异的现象dkms 状态显示 installedmodprobe也不报错但网卡就是不出现在系统里dmesg里还有一行类似module verification failed: signature and/or required key missing的提示。原因很简单启用了 Secure Boot 的机器只允许加载能通过签名校验的内核模块。Realtek 社区驱动没有经过系统内置的 Microsoft 签名所以即使模块文件放在正确的位置内核也不会真正加载它。解决方式有两种。第一种是进入 BIOS把 Secure Boot 关闭然后保存退出。这最省事但如果你需要同时兼容其他系统的安全要求可以用第二种方式就是自己生成一个签名密钥并导入到系统里。签名导入的完整体操作如下# 生成一对签名密钥 openssl req -new -x509 -newkey rsa:2048 -keyout MOK.priv -outform DER -out MOK.der -nodes -days 36500 -subj /CNMy Key/ # 对 .ko 模块签名 sudo /usr/src/linux-headers-$(uname -r)/scripts/sign-file sha256 ./MOK.priv ./MOK.der $(modinfo -n 8812au) # 把公钥导入到 MOKMachine Owner Key数据库 sudo mokutil --import MOK.der执行最后一步时系统会要求设置一个一次性密码重启后会在蓝色 MokManager 界面让你确认导入密钥输入刚才设置的密码即可。整个过程不复杂但在离线环境下第一次遇确实会卡很久提前知道这个机制能省下大量排查时间。5. 驱动装完还是连不上别急按这条链路排查5.1 先用这几条命令确认模块和接口状态驱动装完不代表就万事大吉了。接下来最可靠的排查方式是依次执行下面几条命令逐层确认问题出在哪一层。# 1. 查看驱动模块是否加载 lsmod | grep 88 # 比如 8812au、8821au、88x2bu 这类输出 # 2. 查看无线接口是否建立 iwconfig # 3. 查看 NetworkManager 能否看到无线设备 nmcli dev status # 4. 检查是否被 rfkill 软/硬件开关锁住 rfkill list # 5. 看内核日志里有没有固件或驱动报错 dmesg | tail -50iwconfig里如果能到wlan0 IEEE 802.11AC ESSID:off/any说明接口已经建起来了nmcli dev status里能看到wifi类型且状态是unmanaged或disconnected说明 NetworkManager 已经识别到设备剩下来只是连接配置的问题。5.2 常见故障对照表我把实际中遇到最多的故障点整理成了一张表你可以直接对照处理现象可能原因处理方式lsmod没有模块输出模块未加载可能 Secure Boot 拦截sudo modprobe 8812au若报错看 dmesg检查 Secure Boot 状态rfkill list显示Soft blocked: yes无线被软件开关锁定sudo rfkill unblock allrfkill list显示Hard blocked: yes笔记本物理开关/快捷键关闭按键盘上的飞行模式键或笔记本侧边物理开关能找到wlan0但搜不到任何 WiFi国家码不对或天线接触问题执行sudo iw reg set CN按你所在地区设置再nmcli radio wifi ondmesg 报 firmware failed to load缺少固件.bin文件安装linux-firmware或手动把.bin放到/lib/firmware/rtlwifi/能连上但频繁掉线USB 供电不足或电源管理换一个 USB 口关闭电源管理sudo iw dev wlan0 set power_save off升级内核后失效dkms 未生效或未重建执行sudo dkms autoinstall或重新dkms build/install5.3 一个真实的排查案例固件文件缺失我记得有一次帮朋友装驱动模块加载正常iwconfig也能看到wlan0但一执行扫描就卡住没有任何结果。查看内核日志时发现一行很关键的报错rtl8812au: Firmware rtlwifi/rtl8812aefw.bin not available问题一下就清楚了驱动本身编译成功但它依赖的固件文件没有进到系统里。有两种解决办法一是安装linux-firmware包二是在联网机器上直接下载对应固件文件拷贝到离线机器的/lib/firmware/rtlwifi/目录然后重新加载模块。我当时没有现成的 linux-firmware 包就直接在联网机器上找到rtl8812aefw.bin这个文件单独拷过去放在/lib/firmware/rtlwifi/目录下再执行sudo modprobe -r 8812au sudo modprobe 8812au再扫描一次WiFi 列表就出来了。这个案例说明驱动装完搜不到网络时不要第一时间怀疑驱动编译有问题先看 dmesg 的固件日志很多时候问题只差一个几十 KB 的固件文件。6. 给后来者的一点实话这套离线安装的流程我完整走过不止一遍从第一次折腾一下午到后来只需要十分钟最大的体会是离线安装的核心不在于你会不会编译而在于准备工作做得够不够完整。依赖包、固件、驱动源码、校验值这些物料缺一不可。建议你在联网机器上就把所有东西放到同一个目录、打成压缩包做好一套“离线驱动安装包”以后重装系统直接拿出来用就行。另外还有一个隐藏救急方案如果手边有 Android 手机用 USB 线连上电脑开启手机的“USB 网络共享”Ubuntu 20.04 一般能直接识别为一个有线网卡接口利用这个临时网络你可以在线安装依赖等于把离线问题转化成了有线网络问题。这个技巧在不少极端场景下比钻离线依赖方便得多。最后再分享一个小习惯升级内核之前先跑一下dkms status确认所有第三方驱动都是 installed 状态。升级完重启后如果发现网卡又不见了第一件事就是回来跑sudo dkms autoinstall大多数情况下模块会自动重建。这套组合拳打下来Realtek 网卡在 Ubuntu 20.04 上基本就不会再闹脾气了。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进