使用 Docker/WSL 编译 ImmortalWrt/OpenWrt

在本文开始前,务必确保你的网络已经附魔,研究好了再回来这里。
其次,务必确保 OpenWrt 支持你的机型,在这里查:https://firmware-selector.openwrt.org/ ,比如我的是华硕小旋风 pro,英文代号是 ASUS TUF-AX4200
最后,务必了解清楚如何刷入你的机型,以及如何恢复到原厂固件,以及如何救砖。
刷机有风险,玩机需谨慎!!!
〇、前言
本教程不使用 VMWare 等虚拟机软件,而是在 Docker 容器上编译 ImmortalWrt,全程使用终端进行操作,可能需要少许的 Linux 的基础,比如掌握 ls cd 等基础命令以及对 Docker 有基本的认识。
不使用 Docker 而直接使用 WSL(Windows Subsystem for Linux) 的操作是差不多的。
温馨提示:从这里开始,请使用魔法上网。
一、部署 Docker Desktop 或 WSL
方式一:Docker 部署
官网下载:https://www.docker.com/products/docker-desktop/,看不懂英文的,直接点 这里下载
然后按照教程来(懒得写了 ( ̄o ̄) . z Z ):https://blog.csdn.net/Natsuago/article/details/145588600
Docker 容器可使用 HTTP_PROXY 和 HTTPS_PROXY 环境变量设置代理
方式二:WSL 部署
# 列出可用的发行版
wsl --list --online
# 安装 Ubuntu 24.04
wsl --install Ubuntu-24.04 --name Ubutnu_immortalwrt
# 进入 Ubuntu 子系统,按照提示添加账户,设置密码即可进入。
wsl -d Ubutnu_immortalwrt
# 将以下语句加入 /etc/wsl.conf,以禁止合并 Windows 路径,否则编译时会提示 PATH 错误
[interop]
appendWindowsPath = false
# 重启 WSL
# 退出到 Windows 终端
exit
# 关闭 WSL
wsl --shutdown
# 重新启动
wsl -d Ubutnu_immortalwrtClash 中可开启 TUN 模式为 WSL 提供代理服务,或配置 HTTP_PROXY 和 HTTPS_PROXY 环境变量
二、部署 Linux 容器
到这里,你应该已经安装并启动 Docker 程序界面了。直接使用 WSL 的可跳转到第二步更换软件源。
1、安装 Linux 容器
打开 Windows 终端:(右键开始菜单,选择终端管理员),拉取 Ubuntu 24.04版本的镜像
docker pull ubuntu:24.04部署容器并进入其终端(直接在镜像界面上点击运行容器是运行不起来的)
docker run -it --name ubuntu_for_openwrt ubuntu:24.04 /bin/bash
# -it 创建一个交互式终端会话,让你能够在 Windows 终端上操控容器内终端
# --name 容器名字
# /bin/bash 启动一个 bash 终端
2、更换软件源
虽然已经给网络附魔了,但是准备编译环境时还需要下载大量的软件包。
安装文件编辑软件 nano (比 vi 好用,因为可以复制粘贴)与验证 SSL 证书合法性的软件包 ca-certificates(必须安装,不然换源后无法使用)
sudo apt update # 更新软件列表
sudo apt install nano ca-certificates # 安装软件这里使用 清华镜像站,里面有详细说明
Ubuntu 24.04 以上版本的使用 DEB822 格式而不是传统格式,勾选强制安全更新使用镜像(因为不是生产环境,所以勾选没问题,能加快软件包安装速度)

1、打开软件源列表
sudo nano /etc/apt/sources.list.d/ubuntu.sources2、注释原来的两段,并将清华镜像站的两段复制进去

3、保存: Ctrl + O,回车
4、回到终端:Ctrl + X
三、配置编译环境
根据 ImmortalWrt Github 中的指导进行配置,中途要选择地区和语言就选 5(Asia)和 69(Shanghai)
# 更新软件源
sudo apt update -y
# 更新所有软件包
sudo apt full-upgrade -y
# 安装必要环境
sudo apt install -y ack antlr3 asciidoc autoconf automake autopoint binutils bison build-essential \
bzip2 ccache clang cmake cpio curl device-tree-compiler ecj fastjar flex gawk gettext gcc-multilib \
g++-multilib git gnutls-dev gperf haveged help2man intltool lib32gcc-s1 libc6-dev-i386 libelf-dev \
libglib2.0-dev libgmp3-dev libltdl-dev libmpc-dev libmpfr-dev libncurses-dev libpython3-dev \
libreadline-dev libssl-dev libtool libyaml-dev libz-dev lld llvm lrzsz mkisofs msmtp nano \
ninja-build p7zip p7zip-full patch pkgconf python3 python3-pip python3-ply python3-docutils \
python3-pyelftools qemu-utils re2c rsync scons squashfs-tools subversion swig texinfo uglifyjs \
upx-ucl unzip vim wget xmlto xxd zlib1g-dev zstd
# 执行官方安装脚本
sudo bash -c 'bash <(curl -s https://build-scripts.immortalwrt.org/init_build_environment.sh)'A few moments later...
官方安装脚本执行成功后,你应该能看到结尾显示 [SUCCESS] All dependencies have been installed. 如果没有,那就重新执行脚本,出问题的基本上是网络问题。
强制使用 root 权限编译,GitHub 上的 Note 提到不建议使用 root 进行编译,但硬要使用 root 编译则需要添加一个环境变量(必须加,不然编译检查阶段就不通过)(为什么官方不建议你去用 root 编译呢,是因为怕把你系统搞崩了)
export FORCE_UNSAFE_CONFIGURE=1(可选)到这里,我们的编译环境就准备好了,再打开一个 Windows 终端(不要在当前 Docker 容器的终端执行),执行下面的命令将当前容器保存为一个镜像,下面如果搞崩了就不用重新配置环境了,运行保存好的镜像就行。
# 查看正在运行的容器ID(确认目标容器)
docker ps
# 创建镜像快照(保留文件系统层)
docker commit <容器ID> ubuntu-backup:v1
# 如果需要运行此镜像
# docker run -it -name <自定义容器名> ubuntu-backup:v1 /bin/bash四、拉取官方源码
注意:与 Immortalwrt 不同,Openwrt 严格禁止使用 root 编译,即使配置时执行了 export FORCE_UNSAFE_CONFIGURE=1 命令也会在编译时报错!所有对 openwrt 项目的操作都应回到普通用户中再进行操作。(对于 Immortalwrt 的操作也建议同样如此。)
# 对于 WSL,从root退出到普通用户即可
exit
# 若使用了root创建了openwrt目录,则需要更改所有者,并将这个目录移动到普通用户可访问的地方
chown -R user:user openwrt拉取官方源码
# Openwrt
git clone -b <branch> --single-branch --filter=blob:none https://github.com/openwrt/openwrt
# Immortalwrt
git clone -b <branch> --single-branch --filter=blob:none https://github.com/immortalwrt/immortalwrt上面的 -b 参数指的是分支,目前最新的分支是 openwrt-24.10 ,在GitHub 界面的 Code 中查看。(不建议选择 master 或 main)

更新软件包列表
# 进入源码目录
## Immortalwrt
cd immortalwrt
## Openwrt
cd openwrt
# 更新软件列表
./scripts/feeds update -a
# 建立软件包链接(快捷方式),编译时需要这个软件包就会自动下载
./scripts/feeds install -a受限于国内的访问国际互联网的环境中,feeds update这一步特别容易失败。最稳妥的方式是配置代理,也可以通过以下几条方式来提高成功率:
git config --global http.postBuffer 524288000、git config --global http.lowSpeedLimit 1000、git config --global http.lowSpeedTime 600以上配置的含义为:配置git缓冲区为500M,配置git访问超时的条件为:速率小于1KB/s,且持续600秒
五、添加第三方软件
虽然 ImmortalWrt 中的源提供的软件包足够用了,但是还是有不少需要我们去手动添加才有的,下面我就以 OpenClash、MosDNS、Partexp(用于硬路由上的 U盘扩容)为例,说明如何添加第三方软件。
基本上就是把第三方包添加到源码中的 package 目录下即可,该操作应该在执行完上面的 ./scripts/feeds install -a 之后。
OpenClash(仓库已包含,无需手动添加)
GitHub 网站:https://github.com/vernesong/OpenClash/tree/master
## 下载OpenClash,不推荐用 git clone,会把整个仓库拉下来,非常大
wget https://github.com/vernesong/OpenClash/archive/master.zip
## 解压
unzip master.zip
## 复制OpenClash软件包到OpenWrt
cp -r OpenClash-master/luci-app-openclash ./package
## 删除下载文件
rm -rf master.zip
rm -rf OpenClash-masterMosDNS —— DNS 分流软件
GitHub 网站:https://github.com/sbwml/luci-app-mosdns
rm -rf feeds/packages/lang/golang
git clone https://github.com/sbwml/packages_lang_golang -b 25.x feeds/packages/lang/golang # 注意 -b 参数分支的选择
git clone https://github.com/sbwml/luci-app-mosdns -b v5 package/mosdns
git clone https://github.com/sbwml/v2ray-geodata package/v2ray-geodataPartexp —— 一键分区扩容挂载工具
GitHub 网站:https://github.com/sirpdboy/luci-app-partexp
git clone https://github.com/sirpdboy/luci-app-partexp.git package/luci-app-partexpDDNS-go —— 动态域名
git clone https://github.com/sirpdboy/luci-app-ddns-go.git package/ddns-goArgon 主题
git clone https://github.com/jerrykuku/luci-theme-argon.git package/luci-theme-argon
git clone https://github.com/jerrykuku/luci-app-argon-config.git package/luci-app-argon-configqosmate —— 一款新的 QoS 软件
git clone https://github.com/hudra0/qosmate.git package/qosmate
git clone https://github.com/hudra0/luci-app-qosmate.git package/luci-app-qosmate需手动添加额外依赖:Utilities -> jq 、Network -> Routing and Redirection -> ip-full (取消勾选 ip-tiny)
DDNS-go —— 动态域名解析
git clone https://github.com/sirpdboy/luci-app-ddns-go package/luci-app-ddns-go六、配置编译选项
进入编译配置菜单,自定义编译
make menuconfig
1、选择目标机型(以小旋风 pro 为例)
目标平台 Target System:MediaTek ARM
平台子选项 Subtarget:Filogic 8x0 (MT798x)
目标机型 Target Profile:ASUS TUF-AX4200
2、选择软件包(按需选择,某些软件包 ImmortalWrt 含有,而 OpenWrt 没有)
注意:选择时应将对应软件包前面的符号选择为 '*',而不是 'M',前者会编译并打包进固件,而后者仅编译。
进入 Luci -> Applications
Base system
如果启用了OpenClash,则会自动勾选 dnsmasq-full,此时应当检查 dnsmasq 是否取消勾选,避免冲突。
ca-certificates(建议安装,避免 opkg 使用 https 源时证书验证失败)
zram-swap(内存压缩)
Kernel modules
Filesystems -> kmod-fs-exfat, kmod-fs-ext4, kmod-fs-msdos, kmod-fs-ntfs3(文件系统支持,若使用 USB 文件管理则应安装这些模块)
Network Devices -> kmod-macvlan(单线多拨需要该模块)
Network Support -> kmod-tcp-bbr(使用 BBR 拥塞控制)
Other modules -> kmod-zram(内存压缩模块)
USB Support -> kmod-usb-core, kmod-usb-storage, kmod-usb-storage-extras, kmod-usb-storage-uas(USB 支持)
LuCI
Applications
luci-app-acme(自动证书申请)
luci-app-argon-config(argon 主题设置,Openwrt 未提供)
luci-app-autoreboot (自动重启设置)
luci-app-cpufreq(设置路由器的 CPU 性能模式)
luci-app-ddns(动态域名解析,在 Network -> IP Addresses and Names 中选择额外的 DDNS 提供商支持)
luci-app-ddns-go(动态域名解析(Openwrt 中并未提供),与 luci-app-ddns 两者选其一)
luci-app-mosdns(第三方软件)
luci-app-mwan3(多拨,若无需要请勿安装,需要手动配置才能上网)
luci-app-openclash(小猫咪)
luci-app-partexp(第三方软件)
luci-app-ramfree(内存释放)
luci-app-sqm(QoS)
luci-app-statistics(统计数据,谨慎安装,可能导致无法硬件 NAT,在 Utilities -> collectd 中添加其他监控项,推荐 cpufreq(处理器主频), sqm(QoS), thermal(温度))
luci-app-ttyd(Web 终端)
luci-app-uhttpd(Web 服务器设置界面)
luci-app-upnp(UPNP)
luci-app-usb3disable(关闭 USB3,避免干扰 2.4GHz WiFi)
luci-app-wifischedule(WiFi 定时)
luci-app-wol(网络唤醒)
luci-app-zerotier(内网穿透,Openwrt 并未提供 luci 界面)
Collections
luci ( Web 界面,ImmortalWrt 默认添加,OpenWrt 默认没有)
luci-nginx(若想用 nginx 代替原本的 uhttpd 服务)
Modules -> Translations
Chinese Simplified (zh_Hans)(中文包,ImmortalWrt 默认添加,OpenWrt 默认没有)
Themes
luci-theme-argon(argon 主题,Openwrt 未包含,需要下载源码到 Openwrt 的 package 目录)
Network
adguardhome(adg 广告拦截)
File Transfer > curl (curl 支持)
VPN > zerotier(Openwrt 未提供 luci,仅有软件包)
3、保存配置
按左右方向键到 <save>,点击保存配置

七、编译
先多线程下载好所需的软件包(这一点很重要),免得编译的时候报错。然后再编译,首次编译不建议使用 -j$(nproc) 多线程参数。(编译过程可能持续 3~6 个小时,稍安勿躁)
# 下载所需文件,V=s 输出日志,-j 启用多线程
make download V=s -j$(nproc)
# 启动编译(首次编译最好使用单线程 -j1 以便更好地排查错误)
make V=s -j$(nproc)如果编译顺利没有出错,那么恭喜!!!你已经学会了如何使用 Docker 编译 Openwrt。
编译完成后的固件在 ImmortalWrt 下的 /bin/targets 目录下,利用 ls 和 cd 命令找到生成的固件,比如我的小旋风 pro ,其路径为 /bin/targets/mediatek/filogic ,固件文件名为 immortalwrt-mediatek-filogic-asus_tuf-ax4200-squashfs-sysupgrade.bin
八、导出固件文件
编译完成后,需要从 Docker 容器中导出固件到 Windows 中。
# 查看编译 Openwrt 的容器,获取容器ID (如abcd1234)
docker ps
# 复制固件到 C 盘
docker cp abcd1234:/immortalwrt/bin/targets/mediatek/filogic/immortalwrt-mediatek-filogic-asus_tuf-ax4200-squashfs-sysupgrade.bin C:\WSL 可使用文件资源管理器输入 \\wsl$ 查看 WSL 文件(如果遇到权限问题请查看下方解决方案),或在 WSL 终端中使用 cp 命令将固件导出到 /mnt/c 中(WSL 自动挂载 Windows 目录,/mnt/c 代表 C 盘)
至此,结束。
我遇到的问题
国行 小旋风pro 的适配问题
国行版本的小旋风代号为 AX4200q,并不是国际版的 AX4200,对比国际版增加了一个 2.5G 的 Lan 口。需要在编译之前手动修改 dts 文件才能使用这个额外的 2.5G 口。
论坛中提到的修改方案:https://forum.openwrt.org/t/asus-tuf-ax4200-support/155738/415
对应的 dts 文件存放在 ImmortalWrt 项目下的:/target/linux/mediatek/dts/mt7986a-asus-tuf-ax4200.dts
添加论坛上提到的代码即可:
添加到
&mdio节点的代码:
phy5: phy@5 {
compatible = "ethernet-phy-ieee802.3-c45";
reg = <5>;
mxl,led-drive-vdd;
mxl,led-config = <0x03f0 0x0 0x0 0x0>;
};添加到
&switch节点的代码:
port@5 {
reg = <5>;
label = "lan5";
phy-mode = "2500base-x";
phy-handle = <&phy5>;
};如何进入已经在运行的容器终端
# 查询容器id
docker ps
# 进入容器终端
docker exec -it <容器id> /bin/bash编译 U-boot 报错,缺失 config.h 文件
错误提示:
make[4]: Entering directory '/usr/local/openwrt/build_dir/target-aarch64_cortex-a53_musl/u-boot-2025.01'
ENVP include/generated/env.in
<command-line>: fatal error: include/config.h: No such file or directory
compilation terminated.
排查:
进入 uboot 目录单独编译发现错误
# 单独编译 uboot
make package/boot/uboot-tools/compile V=s -j1scripts/dtc/pylibfdt/libfdt_wrap.c:177:11: fatal error: Python.h: No such file or directory
177 | # include <Python.h>
| ^~~~~~~~~~
compilation terminated.
这个问题发生在我用 Debian 容器而不是 Ubuntu,这是因为缺失了 Python.h 头文件导致的(感谢 DeepSeek),重新安装 Python 软件包即可。
# 安装 Python 环境
apt install python3-dev
# 检查 Python.h 头文件是否存在
find /usr -name "Python.h" 2>/dev/null
# 重新编译
make V=s -j4资源管理器访问 /root 没有权限
访问 WSL 子系统的 /root 文件夹时提示没有权限访问。

# 进入 WSL 子系统
wsl -d Ubuntu
# 提权
sudo -i
# 赋予其他用户只读权限(包括文件夹下的其他文件)
chmod 755 /root -R更改访问权限后,即可在 Windows 的文件资源管理器访问 WSL 子系统的 /root 文件。
使用 Automake 工具链编译时无法找到 Perl 依赖模块 Automake::Config.pm
错误提示:
Can't locate Automake/Config.pm in @INC (you may need to install the Automake::Config module) (@INC entries checked: /root/openwrt/build_dir/host/automake-1.16.5/lib/ /root/openwrt/build_dir/host/automake-1.16.5/lib/ /etc/perl /usr/local/lib/x86_64-linux-gnu/perl/5.38.2 /usr/local/share/perl/5.38.2 /usr/lib/x86_64-linux-gnu/perl5/5.38 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl-base /usr/lib/x86_64-linux-gnu/perl/5.38 /usr/share/perl/5.38 /usr/local/lib/site_perl) at /usr/bin/aclocal-1.16 line 35.
问题:使用root用户编译,导致权限配置异常
解决:使用普通用户编译
提示 PATH 错误
错误提示:
find: The relative path 'Files/dotnet/' is included in the PATH environment variable, which is insecure in combination with the -execdir action of find. Please remove that entry from $PATH
分析:PATH中包含相对路径Files/dotnet/(实际应该是Windows路径Program Files/dotnet/的截断形式),这与find命令的-execdir操作冲突
原因:
WSL会自动将Windows系统的PATH继承到Linux环境。Windows下的程序路径(如C:\Program Files\dotnet)会被转换为Linux格式,但可能包含空格和不兼容的路径格式。
find命令的-execdir要求在命令执行时使用绝对路径。相对路径在PATH中存在会被视为安全隐患。
解决:
(临时)清理 PATH 环境变量
# 清理PATH中所有Windows相关路径
export PATH=$(echo "$PATH" | tr ':' '\n' | grep -vE '/mnt/[a-z]/' | tr '\n' ':' | sed 's/:$//')
# 可选:完全重置为Linux基础PATH
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"(永久)WSL 启动时禁止合并 Windows 路径(参考:https://devblogs.microsoft.com/commandline/automatically-configuring-wsl/)
# 将以下语句加入 /etc/wsl.conf
[interop]
appendWindowsPath = false编译 Mosdns 时 go 版本过低
错误提示:go: ../../go.mod requires go >= 1.24 (running go 1.23.11; GOTOOLCHAIN=local)
原因:mosdns 包需要 Go 1.24 或更高版本,但编译环境使用的是 Go 1.23.11。出现这种情况是在下载 mosdns 源码时没有替换官方源的 golang 包导致的。
解决:
rm -rf feeds/packages/lang/golang
git clone https://github.com/sbwml/packages_lang_golang -b 25.x feeds/packages/lang/golang # 注意 -b 参数分支的选择