> /technology/
为 Raspberry Pi Zero 2 W 配置 USB SSH 与 Linux 主机代理
记录 Raspberry Pi Zero 2 W 通过 USB gadget 建立稳定 SSH 管理链路,并使用 Linux 主机上的 Clash/Mihomo 访问外网的配置流程。
本文记录一次 Raspberry Pi Zero 2 W 实验环境中的最终配置。Zero 2 W 的 wlan0 用于 IBSS 自组网,USB 数据线同时提供一条独立的以太网管理链路。树莓派通过这条链路使用 SSH 登录,并将需要访问公网的 HTTP、HTTPS、Git 和 APT 请求交给 Linux 主机上的 Clash/Mihomo 代理。
1. 环境与目标
实验环境
| 设备 | 系统与内核 | 作用 |
|---|---|---|
| Linux 主机 | Ubuntu 24.04.4 LTS,Linux 7.0.0-28-generic,x86_64 | USB 网络对端、SSH 客户端、Clash/Mihomo 代理 |
| Raspberry Pi Zero 2 W | Debian GNU/Linux 13.5,Linux 6.18.34+rpt-rpi-v8,aarch64 | FANET/IBSS 节点、USB 网络客户端 |
最终地址规划如下:
Linux 主机 USB 网卡 192.168.7.3/24
Raspberry Pi usb0 192.168.7.2/24
IBSS wlan0 10.10.0.3/32
Clash/Mihomo mixed 192.168.7.3:7897
Clash/Mihomo DNS 192.168.7.3:7854
USB 网卡名称由 Linux 根据设备 MAC 地址生成,不应写死为某个名称。本文实测时主机名称为 enx9a1511acea67;重新插拔或更换 USB 设备后,应先通过 ip -br link 确认实际名称。
方案边界
这套方案是“静态 USB 管理网段 + 显式应用代理”:
- USB 链路只负责 SSH、管理和访问主机代理端口。
- usb0 不设置默认网关,Zero 2 W 原有 IBSS 路由不受影响。
- 普通公网 HTTP/HTTPS 请求通过主机的 192.168.7.3:7897 代理。
- 10.0.0.0/8、192.168.0.0/16、172.16.0.0/12 和 USB 管理网段直连,不进入代理。
这不是完整的三层透明网关。若需要让树莓派的所有未匹配流量都经主机转发,还需要额外配置 Linux 转发、NAT、DNS 和防火墙规则;本实验没有采用这种方式。
2. 先确认 USB 网络设备
将 Zero 2 W 通过支持数据传输的 USB 线连接到 Linux 主机后,在主机执行:
ip -br link
ip -br addr
找到新出现的 enx… 接口。树莓派一侧应出现 usb0:
ssh pi_2w 'ip -br addr show usb0'
如果主机没有新接口,优先检查 USB 线是否支持数据传输、Zero 2 W 是否启用了 USB gadget 网络,以及内核日志:
dmesg | tail -50
3. 配置主机 USB 静态地址
使用 NetworkManager 创建持久化连接。将下面的 USB_IF 替换为实际的 enx… 名称:
USB_IF=enx9a1511acea67
sudo nmcli connection add type ethernet \
ifname "$USB_IF" \
con-name rpi-zero2w-usb \
ipv4.method manual \
ipv4.addresses 192.168.7.3/24 \
ipv4.never-default yes \
ipv6.method disabled
sudo nmcli connection up rpi-zero2w-usb
如果连接配置已经存在,使用修改命令而不是重复创建:
sudo nmcli connection modify rpi-zero2w-usb \
connection.interface-name "$USB_IF" \
ipv4.method manual \
ipv4.addresses 192.168.7.3/24 \
ipv4.never-default yes \
ipv6.method disabled
sudo nmcli connection up rpi-zero2w-usb
ipv4.never-default yes 很重要。它确保 USB 管理链路不会抢走 Linux 主机访问校园网或互联网的默认路由。
检查结果:
ip addr show "$USB_IF"
ip route show dev "$USB_IF"
预期至少包含:
192.168.7.3/24
192.168.7.0/24 dev enx... scope link
4. 配置 Zero 2 W 的 usb0
在树莓派上创建持久化 NetworkManager 连接:
sudo nmcli connection add type ethernet \
ifname usb0 \
con-name usb0-static \
ipv4.method manual \
ipv4.addresses 192.168.7.2/24 \
ipv4.never-default yes \
ipv6.method disabled
sudo nmcli connection up usb0-static
已有连接时使用:
sudo nmcli connection modify usb0-static \
connection.interface-name usb0 \
ipv4.method manual \
ipv4.addresses 192.168.7.2/24 \
ipv4.never-default yes \
ipv6.method disabled
sudo nmcli connection up usb0-static
这里不设置网关。USB 网段只需要一条二层直连路由,树莓派访问主机代理时直接使用 192.168.7.3。
验证链路:
ping -c 3 192.168.7.2 # Linux 主机执行
ping -c 3 192.168.7.3 # Zero 2 W 执行
5. 配置 SSH 密钥登录
在 Linux 主机确认已有密钥;没有时生成一对 Ed25519 密钥:
test -f ~/.ssh/id_ed25519.pub || ssh-keygen -t ed25519
将公钥安装到树莓派。首次安装可以使用树莓派账户密码:
ssh-copy-id -i ~/.ssh/id_ed25519.pub lixueyang@192.168.7.2
树莓派端的权限应为:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
主机端为 Zero 2 W 增加 SSH 别名:
Host pi_2w
HostName 192.168.7.2
User lixueyang
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
使用 IdentitiesOnly yes 可以避免 SSH 依次尝试大量无关密钥。测试必须使用批处理模式,确保不会回退到密码:
ssh -o BatchMode=yes pi_2w 'hostname; ip -br addr show usb0'
6. 验证 Linux 主机上的代理
主机上的 Clash/Mihomo 应监听可被 USB 网段访问的地址。实测使用 mixed 端口 7897,而不是仅供控制面使用的管理端口 9097:
ss -ltnp | rg ':(7897|7854|9097)\b'
预期代理端口类似:
*:7897 mixed HTTP/SOCKS proxy
*:7854 DNS service
10.112.50.238:9097 management API
代理监听端口和管理端口的含义不同,树莓派应使用 7897。端口还必须允许来自 192.168.7.0/24 的连接,不能只监听 127.0.0.1。
7. 在树莓派上持久化显式代理
创建 /etc/profile.d/linux-host-proxy.sh:
sudo install -m 0644 /dev/stdin /etc/profile.d/linux-host-proxy.sh <<'EOF'
export http_proxy="http://192.168.7.3:7897"
export https_proxy="http://192.168.7.3:7897"
export all_proxy="socks5h://192.168.7.3:7897"
export HTTP_PROXY="$http_proxy"
export HTTPS_PROXY="$https_proxy"
export ALL_PROXY="$all_proxy"
export no_proxy="localhost,127.0.0.1,::1,192.168.7.2,192.168.7.3,192.168.7.0/24,10.10.0.1,10.10.0.2,10.10.0.3,10.10.0.4,10.0.0.0/8,192.168.0.0/16,172.16.0.0/12,.local"
export NO_PROXY="$no_proxy"
EOF
重新登录,或在当前 shell 中加载配置:
. /etc/profile.d/linux-host-proxy.sh
env | rg -i '^(http|https|all|no)_proxy='
no_proxy 同时列出具体的 IBSS 节点地址和私有网段。部分旧程序对 CIDR 的支持不完整,因此保留具体地址可以提高兼容性。
8. 为 APT 和 Git 配置代理
APT 不一定读取交互式 shell 的代理变量。使用自动判断脚本,让私有地址直连、其他地址使用主机代理:
sudo install -m 0755 /dev/stdin /usr/local/bin/linux-host-apt-proxy <<'EOF'
#!/bin/sh
url="$1"
host="$(printf '%s\n' "$url" | sed -e 's#^[^:]*://##' -e 's#/.*$##' -e 's/:[0-9][0-9]*$//')"
case "$host" in
localhost|127.*|::1|192.168.7.2|192.168.7.3|10.*|192.168.*|172.16.*|172.17.*|172.18.*|172.19.*|172.20.*|172.21.*|172.22.*|172.23.*|172.24.*|172.25.*|172.26.*|172.27.*|172.28.*|172.29.*|172.30.*|172.31.*)
echo DIRECT
;;
*)
echo http://192.168.7.3:7897
;;
esac
EOF
sudo install -m 0644 /dev/stdin /etc/apt/apt.conf.d/95linux-host-proxy <<'EOF'
Acquire::http::Proxy-Auto-Detect "/usr/local/bin/linux-host-apt-proxy";
Acquire::https::Proxy-Auto-Detect "/usr/local/bin/linux-host-apt-proxy";
EOF
sudo apt-get update
Git 使用 HTTPS 访问 GitHub 时可以只为 GitHub 设置代理,避免把校园网或实验网中的其他 Git 服务全部送入代理:
git config --global http.https://github.com.proxy http://192.168.7.3:7897
git config --global http.noProxy 'localhost,127.0.0.1,192.168.7.2,192.168.7.3,10.0.0.0/8,192.168.0.0/16,172.16.0.0/12'
如果使用 GitHub SSH 协议,则代理环境变量不会自动作用于 git@github.com。本实验使用已配置的 GitHub SSH 密钥,网络可用的树莓派可以直接执行:
git -C ~/code/fanet fetch origin --dry-run
不要把密码、访问令牌、私钥或包含明文凭据的 .git-credentials 提交到公开仓库。
9. 持久化检查与重启验证
NetworkManager 连接配置会在重启后自动恢复:
nmcli connection show rpi-zero2w-usb # Linux 主机
ssh pi_2w 'nmcli connection show usb0-static'
树莓派重启后检查:
ssh pi_2w 'ip -br addr show usb0; ip route; systemctl is-system-running'
重点确认:
- usb0 仍为 192.168.7.2/24。
- USB 路由只有 192.168.7.0/24,没有通过 USB 生成默认路由。
- ssh -o BatchMode=yes pi_2w 可以直接登录。
- 新开的登录 shell 能读取 /etc/profile.d/linux-host-proxy.sh。
- sudo apt-get update 和 git ls-remote https://github.com/ForRMByishi/fanet.git HEAD 成功。
- 10.0.0.0/8、192.168.0.0/16 等私有地址按设计直连。
10. 实验中的坑点
USB 网卡名称不是固定的
Linux 的 USB gadget 网卡通常命名为 enx 加 MAC 地址。不能假设每次都是同一个名称;应使用 ip -br link 检查,并让 NetworkManager 连接绑定实际接口。
USB 链路不应随意设置默认网关
USB 网络的目标是管理和访问主机代理。设置 192.168.7.3 为树莓派默认网关会改变路由行为,可能干扰 IBSS 的 OLSRv2 路由,也可能导致校园网地址绕行。最终配置使用 ipv4.never-default yes,只保留 USB 直连路由。
SSH 密钥存在不等于 SSH 会使用它
当本机有多把密钥时,SSH 可能尝试错误的密钥或超过服务端尝试次数。树莓派端要检查 authorized_keys 权限,主机端要在 ~/.ssh/config 指定正确的 IdentityFile 和 IdentitiesOnly yes,再用 BatchMode=yes 验证无密码登录。
Clash 的管理端口不是代理端口
9097 是控制面 API 端口,不能当作普通 HTTP/SOCKS 代理使用。树莓派应连接主机的 mixed 代理端口 7897;端口必须监听在 USB 网段可达的地址上,不能只监听 127.0.0.1。
no_proxy 需要覆盖整个私有地址范围
只排除 192.168.7.2 不够。校园网、IBSS 和 Docker 等本地服务还可能使用其他私有地址,因此最终配置排除了 10/8、192.168/16 和 172.16/12,并额外列出本实验的具体节点地址。
APT 与交互式 Shell 的代理配置相互独立
/etc/profile.d 只影响登录 shell,APT 可能不会读取这些变量。必须单独配置 Proxy-Auto-Detect,并在脚本中区分 DIRECT 和代理地址。
树莓派时间错误会导致 APT 签名校验失败
实验中 Zero 2 W 的系统时间落后,APT 出现仓库签名“尚未生效”的错误。这不是代理故障。遇到类似问题应先检查:
date -R
timedatectl status
修正系统时间后再重复 apt-get update,不要为了绕过时间错误而关闭 APT 签名校验。
显式代理不等于透明代理
本方案只影响遵守 HTTP、HTTPS、SOCKS 或 Git/Apt 代理配置的程序。原始 TCP/UDP、DNS、容器流量和不读取代理环境变量的程序不会自动经过 Clash。若需求变为“所有流量经主机出网”,应单独设计转发、NAT、DNS 和防火墙策略,并重新评估 IBSS 路由冲突。