一、需求背景
在一台运行 Ubuntu Server 的树莓派上,已经存在稳定可用的有线网络连接。与此同时,还希望接入无线网络,以满足以下需求:
- 有线网络作为长期稳定的保底入口,确保始终可以远程 SSH 管理
- 无线网络在需要时手动启用,以获得更高的带宽或更灵活的接入方式
- 当有线和无线同时在线时,希望无线优先、有线备用
- 不希望将无线网络永久写入系统主网络配置,避免在外部环境中产生不必要的自动连接与报错
- 希望通过命令行完成 Wi-Fi 扫描、选择和连接,适合后续用手机 SSH 工具远程操作
这一需求本质上不是“桌面式自动联网”,而是“服务器式可控联网”。
二、系统现状判断
首先需要确认系统中可用的网络工具,以及当前的网络管理方式。检查结果显示:
- 系统存在
netplan - 系统存在
wpa_supplicant - 系统存在
ip - 系统使用的是
systemd-networkd - 不存在
nmcli与nmtui - 无线接口已被系统识别,但默认未启用
这说明该环境属于典型的 Ubuntu Server 风格:
- 没有桌面端常见的交互式 Wi-Fi 管理工具
- 无法像桌面系统一样直接弹出菜单选择无线网络
- 更适合通过底层命令和脚本完成无线连接管理
因此,后续方案不采用 NetworkManager,不依赖图形界面,而是基于以下工具链完成:
iw/iwlist:扫描无线网络wpa_supplicant:建立 Wi-Fi 连接dhclient:获取 DHCP 地址ip route:控制路由优先级
三、总体策略
本次实践最终形成了如下结构:
1. 有线网络长期保留
有线接口始终保持可用,作为系统的远程管理保底入口。
这样做的意义很大:
- 即使无线连接失败,也不会失去 SSH 控制权
- 即使在外部环境中搜不到目标 Wi-Fi,系统仍然可管理
- 不会因为无线配置问题把自己“锁”在系统外
2. 无线网络按需启用
无线不作为系统的开机自动连接项,而是在需要时手动触发:
- 在家庭环境中,可手动连接家庭 Wi-Fi
- 在咖啡馆、临时网络环境中,也可手动连接公共 Wi-Fi
- 不修改系统的长期网络主配置,不污染系统默认行为
3. 当双接口同时在线时,设为 Wi-Fi 优先
这是通过调整默认路由 metric 实现的:
- 无线默认路由 metric 更低
- 有线默认路由 metric 更高
- 从而使系统实际出站优先走无线
- 有线继续保留,作为备份链路
最终实现的逻辑是:
有线常驻保底,Wi-Fi 按需启用;启用后 Wi-Fi 优先,有线备用。
四、工具安装与基础验证
为了支持命令行下的无线操作,需要安装以下工具:
iwwireless-toolswpasupplicantisc-dhcp-client
安装完成后,需要验证几个关键点:
- 无线扫描工具是否存在
- 连接工具是否存在
- DHCP 客户端是否存在
- 无线接口是否已被内核识别
实际验证结果表明:
- 所需工具全部可用
- 无线接口已存在
- 只是初始状态为未启用
这说明系统层面已经具备无线接入能力。
五、扫描附近 Wi-Fi
在命令行环境下,第一步是先拉起无线接口,然后扫描附近无线网络。
扫描结果中能够看到多个 SSID,说明:
- 无线硬件工作正常
- 驱动正常
- 扫描链路正常
- 后续已经具备连接条件
值得注意的是,扫描结果中个别中文 SSID 可能以转义形式显示。这并不意味着扫描失败,只是终端编码显示方式不同。
六、为什么不直接修改系统主配置
在服务器环境中,最常见的做法之一,是直接将 Wi-Fi 写进 netplan 或其它系统主网络配置中,实现开机自动连接。
但在本场景下,这种做法并不是最优解。原因有三点。
1. 远程操作场景更需要可控性
后续可能经常通过手机 SSH 工具远程进入系统。如果每次修改都依赖主配置文件,会增加操作复杂度,也提高误配置风险。
2. 外部环境不固定
无线网络并不总是同一个:
- 家庭网络
- 咖啡馆公共网络
- 临时热点
如果长期绑定某个无线配置,系统在找不到目标网络时会出现额外的失败尝试或日志噪音。
3. 有线已经足够承担“始终在线”的职责
既然已有有线作为保底入口,就没有必要把无线也做成强绑定的自动基础设施。无线更适合作为可插拔能力,而不是系统底盘的一部分。
因此,最终放弃“永久写入系统主配置”的思路,转而采用脚本化、按需启用的方案。
七、从手动命令到脚本化管理
最初的无线接入过程包括以下步骤:
- 手动启用无线接口
- 扫描 SSID
- 手动输入目标 SSID
- 输入密码
- 生成临时连接配置
- 启动
wpa_supplicant - 通过 DHCP 获取地址
- 调整默认路由优先级
这套流程本身没有问题,但重复执行会比较繁琐。因此,后续将其整理为脚本。
八、wifi-connect 脚本的设计思路
为了满足日常使用需求,连接脚本被设计为具备以下特性。
1. 自动扫描附近 Wi-Fi
脚本启动后先扫描并列出附近所有可见 SSID,避免每次手动敲扫描命令。
2. 支持数字编号选择
为提升交互体验,脚本不再要求手动输入完整 SSID,而是将扫描结果编号后列出,用户只需输入数字即可选择目标网络。
这比直接输入无线名称更适合在手机 SSH 环境中操作。
3. 密码隐藏输入
密码通过隐藏模式读取,不会直接显示在终端中,避免明文暴露在 shell 输入记录中。
4. 使用临时配置文件
Wi-Fi 连接配置生成在临时位置,脚本退出后删除,从而避免长期在系统中残留明文连接信息。
5. 连接成功后自动设置优先级
脚本会在获取无线地址后,将无线默认路由调整为更低的 metric,从而让无线成为主线路。
6. 保留有线网络不动
脚本不会破坏现有有线连接,因此整个过程始终保有一个稳定入口。
九、wifi-disconnect 的作用
除了连接脚本,还增加了一个断开脚本。
它的作用很简单:
- 停掉无线连接进程
- 释放无线 DHCP 地址
- 关闭无线接口
这样做之后,系统就会自然回到仅有线运行的状态。
这个脚本虽然不复杂,但很实用。因为它把“回到纯有线状态”这件事也做成了标准化操作。
十、路由优先级确认过程
在双接口都连通之后,最关键的问题不是“两个网都在线”,而是:
系统实际出站到底走哪一个?
检查方式包括:
- 查看
ip route - 查看
ip route get 外部地址
通过这些结果可以明确确认:
- 默认路由存在两条时,metric 更小的那条优先
- 无线被设为较低 metric 后,系统实际对外访问走无线
- 有线继续保留默认路由,但作为备用
在调试过程中,曾出现过无线默认路由重复的问题,即同一接口存在两条默认路由,其中一条没有 metric,另一条显式指定了 metric。这种状态虽然不一定立即导致故障,但不够干净。
后续通过修正脚本中的路由处理逻辑,最终将路由表整理为清晰状态:
- 无线默认路由:metric 较低
- 有线默认路由:metric 较高
这样网络行为就完全明确了。
十一、为什么最终放弃“家庭 Wi-Fi 自动连接”
在后续讨论中,曾考虑将家庭 Wi-Fi 设为自动连接,而外部公共网络继续使用脚本临时连接。
这个思路看似合理,但最终还是放弃了自动连接,原因很明确:
1. 自动连接并非必要
因为系统已经有有线网络作为常驻保底入口,所以即使不自动连接 Wi-Fi,也不会影响远程管理能力。
2. 自动连接会引入环境判断问题
在外部环境中,如果系统持续尝试连接家里的 Wi-Fi,就可能带来不必要的失败日志或无意义扫描。
3. 手动连接更符合服务器管理思路
本机本质上不是一个“拿起来随时漫游”的消费型终端,而是一台可以远程管理的服务器。对于这类设备:
- 稳定入口比自动化更重要
- 可控性比便利性更重要
- 明确操作比隐式行为更可靠
因此最终确定:
- 不启用家庭 Wi-Fi 自动连接
- 保留纯手动脚本式无线接入
- 有线网络作为长期底盘
这让整套方案更加简洁。
十二、脚本实现
下面给出本次实践最终形成的两个脚本版本。内容做了适度脱敏,但保留了完整逻辑。
1. 连接脚本:wifi-connect
这个脚本完成的工作包括:
- 启用无线接口
- 扫描附近 Wi-Fi
- 去重并编号显示 SSID
- 通过数字选择目标网络
- 隐藏输入密码
- 生成临时
wpa_supplicant配置 - 启动 Wi-Fi 连接
- 获取 DHCP 地址
- 设置无线优先于有线
- 输出最终结果
#!/bin/bash
set -euo pipefailIFACE="wlan0"
CONF="/tmp/${IFACE}-wpa.conf"cleanup() {
rm -f "$CONF"
}
trap cleanup EXITecho "== Bringing up ${IFACE} =="
ip link set "$IFACE" upecho
echo "== Scanning nearby Wi-Fi =="mapfile -t SSIDS < <(
iw dev "$IFACE" scan 2>/dev/null \
| sed -n 's/^[[:space:]]*SSID: //p' \
| awk 'NF && !seen[$0]++'
)if [ "${#SSIDS[@]}" -eq 0 ]; then
echo "No Wi-Fi SSIDs found."
exit 1
fiecho
echo "== Nearby Wi-Fi =="
for i in "${!SSIDS[@]}"; do
printf "%2d) %s\n" "$((i+1))" "${SSIDS[$i]}"
doneecho
read -r -p "Select Wi-Fi number: " NUMif ! [[ "$NUM" =~ ^[0-9]+$ ]]; then
echo "Invalid number."
exit 1
fiif [ "$NUM" -lt 1 ] || [ "$NUM" -gt "${#SSIDS[@]}" ]; then
echo "Number out of range."
exit 1
fiSSID="${SSIDS[$((NUM-1))]}"echo "Selected: $SSID"
read -r -s -p "Enter password: " PASS
echoumask 077
wpa_passphrase "$SSID" "$PASS" > "$CONF"
unset PASSpkill wpa_supplicant 2>/dev/null || true
dhclient -r "$IFACE" 2>/dev/null || trueecho
echo "== Connecting to ${SSID} =="
wpa_supplicant -B -i "$IFACE" -c "$CONF"
dhclient "$IFACE"GW="$(ip route | awk '$1=="default" && $5=="wlan0" {print $3; exit}')"
if [ -n "${GW:-}" ]; then
ip route del default via "$GW" dev "$IFACE" 2>/dev/null || true
ip route add default via "$GW" dev "$IFACE" metric 50
fiecho
echo "== Result =="
ip addr show "$IFACE"
echo
ip route
2. 断开脚本:wifi-disconnect
这个脚本用于将系统从“有线+无线双接入”状态恢复为“仅有线”状态。
#!/bin/bash
set -euo pipefailIFACE="wlan0"echo "== Disconnecting ${IFACE} =="pkill wpa_supplicant 2>/dev/null || true
dhclient -r "$IFACE" 2>/dev/null || true
ip link set "$IFACE" down || trueecho
ip addr show "$IFACE" || true
echo
ip route
十三、脚本设计上的几个关键点
1. 配置文件写入临时目录
连接脚本并没有将无线配置写入长期位置,而是放在临时目录中,并在脚本退出时清理。这意味着:
- 不会在系统里长期残留连接信息
- 不会形成“默认自动连接”
- 更适合临时网络场景
2. 密码不直接出现在命令行参数中
脚本采用隐藏输入,而不是把密码直接写在 shell 命令中。这样可以减少以下问题:
- 终端屏幕直接暴露明文
- 复制粘贴时泄露
- shell 历史中留下完整命令
虽然从绝对安全角度讲,任何连接过程都不可能做到“完全无痕”,但在日常远程管理场景中,这已经是一个比较平衡的做法。
3. 路由 metric 明确控制优先级
连接脚本在拿到无线默认路由后,会主动删除旧的无线默认路由,再添加带 metric 的新路由,避免出现重复默认路由的问题。
最终效果是:
- 无线默认路由 metric 较小
- 有线默认路由 metric 较大
- 实际对外访问优先走无线
4. 有线网络完全不参与脚本销毁流程
脚本只操作无线接口,不触碰有线接口。这是整套方案最重要的稳定性保证之一。
十四、实际验证结果
在脚本调通之后,系统最终呈现出以下状态:
- 有线接口在线
- 无线接口在线
- 无线获取到独立地址
- 默认路由中同时存在有线和无线
- 无线 metric 更低
ip route get验证实际出站走无线
也就是说,设计目标已经完整实现:
- 有线是保底链路
- 无线是主用链路
- 两者同时在线时行为明确
- 断开无线后系统自然回落到纯有线状态
十五、为什么这套方案适合服务器而不是桌面机
很多桌面环境会倾向于:
- 自动记忆 Wi-Fi
- 自动重连
- 自动切换最优网络
但在服务器场景中,尤其是远程管理场景中,这种“方便优先”的策略未必最优。
本方案更接近服务器思维:
- 永远保留一个稳定入口
- 额外能力通过显式操作启用
- 不让系统产生过多隐式行为
- 不让无线配置污染长期主配置
- 在出现异常时,仍然可以通过有线入口救援
对于小型 ARM 服务器、树莓派边缘节点、家用实验机、远程开发盒子等场景,这种方式往往更可靠。
十六、最终方案总结
本次实践最终形成的结构可以概括为:
1. 有线网络长期在线
作为远程 SSH 管理入口和系统底层保障。
2. 无线网络按需手动启用
通过脚本扫描、选择、隐藏输入密码、连接。
3. 双接口同时在线时,无线优先
通过 metric 控制路由优先级,实现无线主用、有线备用。
4. 不改系统主网络配置
避免引入自动连接、副作用和环境依赖问题。
5. 外部网络环境仍然适配
在家庭网络、公共网络、临时热点之间切换时,都可以继续复用同一套脚本逻辑。
十七、这套方案的价值
这次实践的真正价值,不只是“连上了 Wi-Fi”,而是建立了一种适合服务器场景的网络管理思路:
- 不追求桌面式傻瓜自动化
- 不把所有东西都永久写死在配置文件里
- 有稳定保底入口
- 需要时再启用附加能力
- 对网络路径和系统行为保持明确控制
对于长期运行的树莓派或小型服务器来说,这种方式往往比“全自动、全写死”的方案更稳妥。
它不是最花哨的方案,但非常适合强调可控性、可维护性和远程管理可靠性的场景。