跳转到正文
Mind in Motion

Ubuntu/RDK 开发环境代理配置:自动开关与局域网代理

整理 Ubuntu 与 RDK 开发环境中的局域网代理配置,包含自动检测、手动开关、sudo 环境继承以及 apt、Git、curl 和 ROS 的排障方法。

开发实践,ROS1分钟阅读

在 Ubuntu 和 RDK 开发环境中,代理通常同时服务于 apt、Git、curl、ROS 软件包和 Python 依赖。局域网代理设备可能随网络环境变化,固定写入 Shell 的代理变量会让离线开发、局域网通信和设备调试互相干扰。

这篇文章把 Ubuntu Shell 自动代理脚本与 RDK 局域网代理变量合并为一套配置:启动终端时检测代理端口,端口可用时自动启用;局域网设备地址加入 NO_PROXY,让 SSH、ROS 节点和 WebSocket 通信保持直连。示例中的主机、端口和 RDK 地址全部使用占位符,部署时按实际网络填写。

  • Ubuntu 桌面或 RDK 板端的 Bash Shell。
  • 代理服务运行在同一局域网的另一台电脑或网关上。
  • 需要让 apt、Git、curl 或 ROS 工具读取代理环境变量。
  • 需要在代理网络与普通网络之间切换。

先确认当前 Shell:

Terminal window
echo "$SHELL"
ps -p "$$" -o comm=

本文配置写入 ~/.bashrc。RDK 镜像使用其他 Shell 时,将同一段函数放入对应的启动文件,并按 Shell 语法检查。

变量 作用
HTTP_PROXY、HTTPS_PROXY 为 HTTP/HTTPS 客户端提供代理
ALL_PROXY 为支持该变量的程序提供 SOCKS5 代理
NO_PROXY 指定本地地址、局域网地址和 RDK 地址直连
PROXY_HOST 局域网代理设备地址
HTTP_PORT、SOCKS5_PORT 代理服务的 HTTP 与 SOCKS5 端口

同时设置大小写变量可以兼容不同程序。apt、Git、curl 和 ROS 相关进程会继承当前 Shell 导出的环境。

自动检测依赖 netcat-openbsd 提供的 nc:

Terminal window
sudo apt update
sudo apt install netcat-openbsd
nc -h

初次安装没有代理时,可以临时使用可访问的软件源,或者先在系统网络设置中配置代理。

默认情况下,sudo 会清理一部分环境变量。创建 /etc/sudoers.d/proxy:

Terminal window
sudoedit /etc/sudoers.d/proxy

写入:

Defaults env_keep += "http_proxy https_proxy HTTP_PROXY HTTPS_PROXY all_proxy ALL_PROXY no_proxy NO_PROXY"

设置文件属主和权限,再检查 sudoers 语法:

Terminal window
sudo chown root:root /etc/sudoers.d/proxy
sudo chmod 0440 /etc/sudoers.d/proxy
sudo visudo -c

正常结果应包含:

/etc/sudoers: parsed OK
/etc/sudoers.d/proxy: parsed OK

/etc/sudoers.d/ 下的配置文件需要保持 root:root 和 0440,否则 sudo 可能拒绝读取。

编辑 ~/.bashrc:

Terminal window
nano ~/.bashrc

追加以下代码。先替换 PROXY_HOST、HTTP_PORT、SOCKS5_PORT 和 RDK_HOST;这些值也可以先保留占位符,用于检查脚本结构。

Terminal window
# =========================
# Ubuntu/RDK 网络代理
# =========================
PROXY_SCHEME="http"
PROXY_HOST="<PROXY_HOST>"
HTTP_PORT="<HTTP_PORT>"
SOCKS5_PORT="<SOCKS5_PORT>"
RDK_HOST="<RDK_IP>"
# auto: 检测代理端口、系统代理或 TUN;port: 只检测代理端口
# system: 检测系统代理后使用上面的代理;tun: 检测 TUN 后使用上面的代理
# off: 不在读取 ~/.bashrc 时自动修改代理变量
PROXY_AUTO_MODE="auto"
proxy_configured() {
[ -n "$PROXY_HOST" ] &&
[ "$PROXY_HOST" != "<PROXY_HOST>" ] &&
[ -n "$HTTP_PORT" ] &&
[ "$HTTP_PORT" != "<HTTP_PORT>" ]
}
proxy_port_available() {
proxy_configured || return 1
command -v nc >/dev/null 2>&1 || return 1
nc -z -w1 "$PROXY_HOST" "$HTTP_PORT" >/dev/null 2>&1
}
proxy_system_enabled() {
command -v gsettings >/dev/null 2>&1 || return 1
local mode
mode=$(gsettings get org.gnome.system.proxy mode 2>/dev/null)
case "$mode" in
""|*none*) return 1 ;;
*) return 0 ;;
esac
}
proxy_tun_enabled() {
command -v ip >/dev/null 2>&1 || return 1
ip -o link show 2>/dev/null |
awk -F': ' '{print $2}' |
cut -d@ -f1 |
grep -Eq '^(tun|tap|wg|tailscale|zt)'
}
proxy_network_enabled() {
proxy_port_available || proxy_system_enabled || proxy_tun_enabled
}
proxy_on() {
if ! proxy_configured; then
[ "${1:-}" = "--quiet" ] || echo "Please configure PROXY_HOST and HTTP_PORT first."
return 1
fi
export http_proxy="$PROXY_SCHEME://$PROXY_HOST:$HTTP_PORT"
export https_proxy="$PROXY_SCHEME://$PROXY_HOST:$HTTP_PORT"
export HTTP_PROXY="$PROXY_SCHEME://$PROXY_HOST:$HTTP_PORT"
export HTTPS_PROXY="$PROXY_SCHEME://$PROXY_HOST:$HTTP_PORT"
if [ -n "$SOCKS5_PORT" ] && [ "$SOCKS5_PORT" != "<SOCKS5_PORT>" ]; then
export all_proxy="socks5h://$PROXY_HOST:$SOCKS5_PORT"
export ALL_PROXY="socks5h://$PROXY_HOST:$SOCKS5_PORT"
else
unset all_proxy ALL_PROXY
fi
# NO_PROXY 的通配符支持取决于客户端;RDK_HOST 用于确保设备地址明确直连。
export no_proxy="localhost,127.0.0.1,::1,$RDK_HOST,10.*,192.168.*,172.*"
export NO_PROXY="$no_proxy"
if [ "${1:-}" != "--quiet" ]; then
echo "Proxy enabled"
echo "HTTP proxy: $http_proxy"
if [ -n "$all_proxy" ]; then
echo "SOCKS5 proxy: $all_proxy"
else
echo "SOCKS5 proxy: disabled"
fi
fi
}
proxy_off() {
unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY
unset all_proxy ALL_PROXY no_proxy NO_PROXY
if [ "${1:-}" != "--quiet" ]; then
echo "Proxy disabled"
fi
}
proxy_status() {
if proxy_system_enabled; then
echo "System proxy: ON"
else
echo "System proxy: OFF"
fi
if proxy_tun_enabled; then
echo "TUN route : ON"
else
echo "TUN route : OFF"
fi
if proxy_port_available; then
echo "Proxy port : ON ($PROXY_HOST:$HTTP_PORT)"
else
echo "Proxy port : OFF ($PROXY_HOST:$HTTP_PORT)"
fi
if [ -n "$http_proxy" ]; then
echo "Shell proxy : ON"
echo "HTTP proxy : $http_proxy"
echo "HTTPS proxy : $https_proxy"
if [ -n "$all_proxy" ]; then
echo "SOCKS5 proxy: $all_proxy"
else
echo "SOCKS5 proxy: disabled"
fi
else
echo "Shell proxy : OFF"
fi
}
case "$PROXY_AUTO_MODE" in
auto)
if proxy_network_enabled && proxy_port_available; then
proxy_on --quiet
else
proxy_off --quiet
fi
;;
port)
if proxy_port_available; then
proxy_on --quiet
else
proxy_off --quiet
fi
;;
system)
if proxy_system_enabled && proxy_port_available; then
proxy_on --quiet
else
proxy_off --quiet
fi
;;
tun)
if proxy_tun_enabled && proxy_port_available; then
proxy_on --quiet
else
proxy_off --quiet
fi
;;
off)
;;
*)
echo "Unknown PROXY_AUTO_MODE: $PROXY_AUTO_MODE"
;;
esac

重新加载:

Terminal window
source ~/.bashrc
proxy_status

手动控制:

Terminal window
proxy_on
proxy_off
proxy_status

proxy_on 和 proxy_off 只影响当前 Shell 及其子进程。重新打开终端后,自动逻辑会再次运行。

Terminal window
env | grep -i proxy

Terminal window
curl -I --max-time 10 https://example.com

使用 -v 可以观察 CONNECT 或 SOCKS5 连接过程:

Terminal window
curl -vI --max-time 10 https://example.com

Terminal window
sudo env | grep -i proxy
sudo apt update

Terminal window
curl --noproxy '*' -I --max-time 5 http://$RDK_HOST:8000
ssh <RDK_USER>@$RDK_HOST

ROS、SSH、相机网页和 rosbridge WebSocket 使用的设备地址应放入 NO_PROXY。局域网服务的连通性可以用 curl –noproxy ‘*’ 单独验证,排除代理规则的影响。

代理主要服务于公网依赖下载:

  • apt update 和 apt install 获取 Ubuntu、ROS 或 RDK 软件包。
  • Git 克隆和拉取远程仓库。
  • curl、wget 和 Python 包管理器访问外部地址。

RDK 的 SSH、相机网页、rosbridge WebSocket 和局域网 ROS 通信需要直连。RDK_HOST 与局域网网段写入 NO_PROXY 后,代理变量可以继续保留给公网请求。

nc 只能证明 TCP 端口可以连接,代理服务还需要确认协议类型。HTTP 代理使用 http://,SOCKS5 代理使用 socks5h://。检查代理软件的监听地址、端口和访问控制。

依次检查:

Terminal window
proxy_status
sudo env | grep -i proxy
sudo visudo -c
sudo apt -o Debug::Acquire::http=true update

不同版本 apt 还可以通过 /etc/apt/apt.conf.d/ 单独设置代理;当前配置先使用环境变量,便于 proxy_on 和 proxy_off 统一控制。

检查 NO_PROXY 是否包含 RDK 的实际 IP、主机名和本地网段。不同客户端对通配符和 CIDR 的支持存在差异,最稳定的做法是把 RDK 的实际 IP 单独写入 RDK_HOST。

© yznn007. 保留所有权利。