OpenWrt 透明代理部署文档
概述
在 OpenWrt 25.12.2 上基于 sing-box TUN 模式部署透明代理,实现:
大陆 IP 和大陆域名直连,不走代理
海外流量通过 Shadowsocks 加密转发
DNS 分流:国内域名用国内 DNS 解析,海外域名通过代理用 Google DNS 解析
其他主机将网关和 DNS 指向本机即可透明上网
已部署验证的机型:
MIPS ramips/mt7621 小米路由器 3G(旁路由模式,br-wan)
架构原理
1 2 3 4 5 6 7 8 9 10 11 12 13 客户端 (网关/DNS → 本机) │ ├─ DNS 查询 (UDP 53) │ └─ dnsmasq → 10.10.10.2 (sing-box DNS 模块) │ ├─ geosite-cn 命中 → 223.5.5.5 直连解析 │ └─ 其他域名 → tcp://8.8.8.8 通过 SS 解析 │ └─ TCP/UDP 数据 └─ 路由 → tun0 (sing-box TUN) ├─ geoip-cn 命中 → direct 直连 ├─ geosite-cn 命中 → direct 直连 ├─ 私有 IP → direct 直连 └─ 其余 → Shadowsocks 出站
sing-box TUN 模式通过 auto_route 自动创建策略路由,将非本地流量导入 tun0 虚拟网卡。strict_route 确保 sing-box 自身的出站连接不会被 TUN 再次拦截,避免路由回路。
环境要求
OpenWrt 25.12.2(理论支持 25.x 全系列)
内核模块:kmod-tun、kmod-nf-tproxy、kmod-nft-tproxy
已开启 IP 转发
至少 40MB 可用磁盘空间
mipsel_24kc 架构(其他架构需替换 sing-box 二进制和 kmod 源)
文件传输
OpenWrt 25 没有 SFTP/SCP,使用 SSH PIPE 传输:
1 2 3 4 5 # 传输单个文件 ssh root@<router-ip> 'cat /root/deploy.sh' > deploy.sh # 多文件打包传输 ssh root@<router-ip> 'tar czf - -C /root deploy.sh troubleshoot.sh' > backup.tar.gz
部署步骤
第一步:确认系统信息
1 2 3 4 5 cat /etc/openwrt_release # DISTRIB_ARCH 决定架构 uname -r # 内核版本 ip addr show # 网络接口名和 IP ip route show # 默认网关 df -h / # 可用空间
第二步:安装内核模块
1 2 apk add kmod-tun kmod-nf-tproxy kmod-nft-tproxy modprobe tun nf_tproxy nft_tproxy
MIPS 平台通常能直连 OpenWrt 仓库,直接 apk add 即可。
第三步:获取 sing-box 二进制
从 GitHub 下载 MIPS 版本:
1 2 # MIPS (mipsel_24kc / 1004Kc 软浮点) https://github.com/SagerNet/sing-box/releases/download/v1.11.9/sing-box-1.11.9-linux-mipsle-softfloat.tar.gz
注意:MIPS 必须用 softfloat 版本。linux-mipsle(硬浮点)在 1004Kc 核心上会报 Illegal instruction。
1 2 chmod 755 /usr/local/bin/sing-box /usr/local/bin/sing-box version # 确认可执行
第四步:下载 geo 规则集文件
1 2 3 4 5 6 7 mkdir -p /etc/sing-box wget -O /etc/sing-box/geoip-cn.srs \ https://raw.githubusercontent.com/SagerNet/sing-geoip/rule-set/geoip-cn.srs wget -O /etc/sing-box/geosite-cn.srs \ https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-cn.srs
两个文件合计不到 100KB。不要用 v2ray 格式的 geoip.dat(22MB),sing-box 1.11.x 已不支持。
第五步:写入 sing-box 配置
文件位置:/etc/sing-box/config.json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 { "log" : {"level" : "info" , "timestamp" : true }, "dns" : { "servers" : [ {"tag" : "dns-direct" , "address" : "223.5.5.5" , "detour" : "direct" }, {"tag" : "dns-remote" , "address" : "tcp://8.8.8.8" , "detour" : "ss-out" } ], "rules" : [ {"rule_set" : "geosite-cn" , "server" : "dns-direct" } ], "final" : "dns-remote" , "strategy" : "ipv4_only" }, "inbounds" : [ { "type" : "tun" , "tag" : "tun-in" , "interface_name" : "tun0" , "mtu" : 1500 , "address" : ["10.10.10.1/30" ], "auto_route" : true , "strict_route" : true , "sniff" : true , "sniff_override_destination" : false } ], "outbounds" : [ {"type" : "dns" , "tag" : "dns-out" }, { "type" : "shadowsocks" , "tag" : "ss-out" , "server" : "<SS-SERVER-IP>" , "server_port" : <SS-PORT>, "password" : "<SS-PASSWORD>" , "method" : "aes-256-gcm" }, {"type" : "direct" , "tag" : "direct" } ], "route" : { "rule_set" : [ {"tag" : "geoip-cn" , "type" : "local" , "format" : "binary" , "path" : "/etc/sing-box/geoip-cn.srs" }, {"tag" : "geosite-cn" , "type" : "local" , "format" : "binary" , "path" : "/etc/sing-box/geosite-cn.srs" } ], "rules" : [ {"protocol" : "dns" , "outbound" : "dns-out" }, {"ip_is_private" : true , "outbound" : "direct" }, {"rule_set" : "geoip-cn" , "outbound" : "direct" }, {"rule_set" : "geosite-cn" , "outbound" : "direct" } ], "final" : "ss-out" , "auto_detect_interface" : true }, "experimental" : { "cache_file" : {"enabled" : false } } }
关键配置说明:
dns.servers[1].address 使用 tcp://8.8.8.8 而非 UDP(UDP DNS 通过 TUN 代理回程有问题)
dns.strategy 设为 ipv4_only,过滤 AAAA 记录避免 IPv6
inbounds[0].mtu 设为 1500(默认 9000 会导致分片问题)
inbounds[0].auto_route 和 strict_route 组合是核心,sing-box 自动管理策略路由
experimental.cache_file.enabled 设为 false(/var/cache 重启后会被清空,启用会导致启动失败)
第六步:配置 DNS(dnsmasq)
dnsmasq 配置由 init 脚本在每次启动时动态生成,自动检测当前网口 IP。参考配置:
1 2 3 4 5 6 7 8 listen-address=127.0.0.1 listen-address=<LAN-IP> bind-interfaces server=10.10.10.2 server=/yview.cn/172.20.2.113 cache-size=2048 no-resolv filter-AAAA
说明:
server=10.10.10.2 — 所有 DNS 查询转发到 sing-box DNS 模块
server=/yview.cn/172.20.2.113 — 内网域名后缀转发(如公司内部系统)
bind-interfaces — 必须启用,否则 dnsmasq 只在 lo 上监听
filter-AAAA — 过滤 IPv6 DNS 记录
no-resolv — 不从 /etc/resolv.conf 读取上游 DNS
第七步:写入 init 启动脚本
文件位置:/etc/init.d/sing-box
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 START=95 USE_PROCD=1 PROG=/usr/local /bin/sing-box CONFIG=/etc/sing-box/config.json DNSMASQ_CONF=/etc/dnsmasq-proxy.conf SS_SERVER="<your-ss-domain-or-ip>" SS_PORT="<port>" SS_PASSWORD="<password>" SS_METHOD="aes-256-gcm" boot () { start; }start_service () { SS_IP="$SS_SERVER " case "$SS_SERVER " in [0-9]*.[0-9]*.[0-9]*.[0-9]*) ;; *) SS_IP=$(nslookup "$SS_SERVER " 223.5.5.5 2>/dev/null | grep "Address: [0-9]" | awk "{print \$NF}" | head -1) ;; esac case "$SS_IP " in [0-9]*.[0-9]*.[0-9]*.[0-9]*) ;; *) echo "$(date) start aborted: nslookup $SS_SERVER failed" >> /tmp/sing-box.log; return 1 ;; esac mkdir -p /var/cache/sing-box ip link del tun0 2>/dev/null sleep 1 WAN_IP=$(ip addr show br-wan | grep "inet " | awk "{print \$2}" | cut -d/ -f1) DNS_IPS=$(grep "server=/" $DNSMASQ_CONF | awk -F/ "{print \$NF}" | sort -u) sed -i "/\"server\":/{ /dns/! s|\"server\": *\"[^\"]*\"|\"server\": \"$SS_IP \"| }" $CONFIG sed -i "s|\"server_port\": [0-9]*|\"server_port\": $SS_PORT |" $CONFIG sed -i "s|\"password\": *\"[^\"]*\"|\"password\": \"$SS_PASSWORD \"|" $CONFIG sed -i "s|\"method\": *\"[^\"]*\"|\"method\": \"$SS_METHOD \"|" $CONFIG sed -i "/^listen-address=/d" $DNSMASQ_CONF sed -i "1i listen-address=127.0.0.1\nlisten-address=${WAN_IP} " $DNSMASQ_CONF sed -i "s/^server=[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}$/server=10.10.10.2/" $DNSMASQ_CONF while ip rule del priority 8999 2>/dev/null; do :; done for ip in 223.5.5.5 ${SS_IP} ${DNS_IPS} ; do [ -n "$ip " ] && ip rule add to ${ip} /32 table main priority 8999 done killall dnsmasq 2>/dev/null sleep 1 dnsmasq -C $DNSMASQ_CONF rm -f /etc/resolv.conf echo "nameserver 127.0.0.1" > /etc/resolv.conf procd_open_instance procd_set_param command /bin/sh -c "$PROG run -c $CONFIG > /tmp/sing-box.log 2>&1" procd_set_param respawn procd_close_instance }stop_service () { ip link del tun0 2>/dev/null while ip rule del priority 8999 2>/dev/null; do :; done sed -i "s/^server=10\.10\.10\.2$/server=223.5.5.5/" $DNSMASQ_CONF killall dnsmasq 2>/dev/null sleep 1 dnsmasq -C $DNSMASQ_CONF rm -f /etc/resolv.conf echo "nameserver 127.0.0.1" > /etc/resolv.conf }
赋予执行权限并启用:
1 2 3 4 chmod 755 /etc/init.d/sing-box /etc/init.d/sing-box enable /etc/init.d/dnsmasq disable rm -f /etc/rc.d/S*dnsmasq*
第八步:开启 IP 转发
1 2 echo 1 > /proc/sys/net/ipv4/ip_forward echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
第九步:配置 geo 规则集自动更新
/usr/local/bin/update-geo.sh:
1 2 3 4 5 6 7 8 9 10 11 12 #!/bin/sh GEOIP_URL="https://raw.githubusercontent.com/SagerNet/sing-geoip/rule-set/geoip-cn.srs" GEOSITE_URL="https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-cn.srs" DST="/etc/sing-box" wget -q --timeout=15 -O "$DST /geoip-cn.srs.new" "$GEOIP_URL " 2>/dev/null && \ [ -s "$DST /geoip-cn.srs.new" ] && mv "$DST /geoip-cn.srs.new" "$DST /geoip-cn.srs" wget -q --timeout=15 -O "$DST /geosite-cn.srs.new" "$GEOSITE_URL " 2>/dev/null && \ [ -s "$DST /geosite-cn.srs.new" ] && mv "$DST /geosite-cn.srs.new" "$DST /geosite-cn.srs" /etc/init.d/sing-box restart 2>/dev/null
1 2 chmod 755 /usr/local/bin/update-geo.sh echo "17 03 * * * /usr/local/bin/update-geo.sh" >> /etc/crontabs/root
第十步:启动服务
1 /etc/init.d/sing-box start
验证
检查进程:
1 ps | grep -E "sing-box|dnsmasq"
应该看到两个进程都在运行。
检查 TUN 接口:
应该显示 inet 10.10.10.1/30。
检查 bypass 路由:
1 ip rule show | grep 8999
应该显示 SS 服务器和 DNS 服务器的 bypass 规则。
检查 DNS:
1 2 nslookup www.baidu.com 127.0.0.1 # 应返回大陆 IP,如 180.101.x.x nslookup www.google.com 127.0.0.1 # 应返回海外真实 IP,如 142.251.x.x
客户端设置
将需要使用透明代理的机器配置为:
默认网关:指向本机 IP
DNS 服务器:指向本机 IP
Windows 在网络适配器属性中设置。注意 Chrome/Edge 默认开启 Secure DNS (DoH),需关掉:chrome://settings/security → 使用安全 DNS → 关闭。
日常维护
1 2 3 4 /etc/init.d/sing-box start /etc/init.d/sing-box stop /etc/init.d/sing-box restart cat /tmp/sing-box.log # 查看日志
更换 SS 节点:编辑 /etc/init.d/sing-box 顶部的 SS_SERVER/SS_PORT/SS_PASSWORD/SS_METHOD,然后 restart。init 脚本会自动解析域名并注入 config.json、更新 bypass 路由。
更换本机 IP 后:直接 restart 即可,init 脚本自动检测新 IP。
部署脚本(一键)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 #!/bin/sh SS_SERVER="<your-ss-server>" SS_PORT="<port>" SS_PASSWORD="<password>" SS_METHOD="aes-256-gcm" SING_BOX_VER="1.11.9" SING_ARCH="linux-mipsle-softfloat" TUN_ADDR="10.10.10.1/30" WAN_IF="br-wan" set -eecho "========================================" echo " MIPS 透明代理部署" echo " sing-box ${SING_BOX_VER} ${SING_ARCH} " echo "========================================" echo "[1/8] 内核模块..." apk add kmod-tun kmod-nf-tproxy kmod-nft-tproxy 2>&1 | tail -1 modprobe tun nf_tproxy nft_tproxy 2>/dev/nullecho "[2/8] sing-box..." mkdir -p /usr/local /bin /var/cache/sing-box /etc/sing-boxif [ -x /usr/local /bin/sing-box ]; then echo " 已安装" else URL="https://github.com/SagerNet/sing-box/releases/download/v${SING_BOX_VER} /sing-box-${SING_BOX_VER} -${SING_ARCH} .tar.gz" wget -q --timeout=30 -O /tmp/sb.tar.gz "$URL " || { echo "下载失败! 手动下载 $URL " exit 1 } cd /tmp && tar xzf sb.tar.gz && cp sing-box-*/sing-box /usr/local /bin/ chmod 755 /usr/local /bin/sing-box rm -rf /tmp/sb.tar.gz /tmp/sing-box-*fi echo "[3/8] geo 规则..." for f in geoip-cn.srs geosite-cn.srs; do repo="sing-geoip" ; [ "$f " = "geosite-cn.srs" ] && repo="sing-geosite" wget -q --timeout=15 -O /etc/sing-box/$f \ "https://raw.githubusercontent.com/SagerNet/${repo} /rule-set/${f} " 2>/dev/nulldone echo "[4/8] 配置..." WAN_IP=$(ip addr show $WAN_IF | grep "inet " | awk '{print $2}' | cut -d/ -f1) cat > /etc/sing-box/config.json << EOF {"log" :{"level" :"info" ,"timestamp" :true },"dns" :{"servers" :[{"tag" :"dns-direct" ,"address" :"223.5.5.5" ,"detour" :"direct" },{"tag" :"dns-remote" ,"address" :"tcp://8.8.8.8" ,"detour" :"ss-out" }],"rules" :[{"rule_set" :"geosite-cn" ,"server" :"dns-direct" }],"final" :"dns-remote" ,"strategy" :"ipv4_only" },"inbounds" :[{"type" :"tun" ,"tag" :"tun-in" ,"interface_name" :"tun0" ,"mtu" :1500,"address" :["${TUN_ADDR} " ],"auto_route" :true ,"strict_route" :true ,"sniff" :true ,"sniff_override_destination" :false }],"outbounds" :[{"type" :"dns" ,"tag" :"dns-out" },{"type" :"shadowsocks" ,"tag" :"ss-out" ,"server" :"${SS_SERVER} " ,"server_port" :${SS_PORT} ,"password" :"${SS_PASSWORD} " ,"method" :"${SS_METHOD} " },{"type" :"direct" ,"tag" :"direct" }],"route" :{"rule_set" :[{"tag" :"geoip-cn" ,"type" :"local" ,"format" :"binary" ,"path" :"/etc/sing-box/geoip-cn.srs" },{"tag" :"geosite-cn" ,"type" :"local" ,"format" :"binary" ,"path" :"/etc/sing-box/geosite-cn.srs" }],"rules" :[{"protocol" :"dns" ,"outbound" :"dns-out" },{"ip_is_private" :true ,"outbound" :"direct" },{"rule_set" :"geoip-cn" ,"outbound" :"direct" },{"rule_set" :"geosite-cn" ,"outbound" :"direct" }],"final" :"ss-out" ,"auto_detect_interface" :true },"experimental" :{"cache_file" :{"enabled" :false }}} EOFecho "[5/8] init 脚本..." echo "[6/8] geo 更新..." cat > /usr/local /bin/update-geo.sh << 'SCRIPT' #!/bin/sh for f in geoip-cn.srs geosite-cn.srs; do repo="sing-geoip" ; [ "$f " = "geosite-cn.srs" ] && repo="sing-geosite" wget -q --timeout=15 -O "/etc/sing-box/$f .new" \ "https://raw.githubusercontent.com/SagerNet/${repo} /rule-set/${f} " && \ [ -s "/etc/sing-box/$f .new" ] && mv "/etc/sing-box/$f .new" "/etc/sing-box/$f " done /etc/init.d/sing-box restart 2>/dev/null SCRIPT chmod 755 /usr/local /bin/update-geo.sh grep -q update-geo /etc/crontabs/root 2>/dev/null || \ echo "17 03 * * * /usr/local/bin/update-geo.sh" >> /etc/crontabs/rootecho "[7/8] IP 转发..." echo 1 > /proc/sys/net/ipv4/ip_forward grep -q ip_forward /etc/sysctl.conf 2>/dev/null || echo "net.ipv4.ip_forward=1" >> /etc/sysctl.confecho "[8/8] 启动..." /etc/init.d/dnsmasq disable 2>/dev/null; rm -f /etc/rc.d/S*dnsmasq* /etc/init.d/sing-box enable 2>/dev/null killall sing-box dnsmasq 2>/dev/null; ip link del tun0 2>/dev/null; sleep 1 /etc/init.d/sing-box start 2>&1; sleep 3echo "" echo "========================================" echo " 部署完成" echo " sing-box: $(pgrep sing-box|xargs) dnsmasq: $(pgrep dnsmasq|xargs) " echo " TUN: $(ip addr show tun0 2>/dev/null|grep 'inet '|awk '{print $2}') " echo " 客户端: 网关+DNS = $(ip addr show br-wan|grep 'inet '|awk '{print $2}'|cut -d/ -f1) " echo "========================================"
故障诊断脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 #!/bin/sh echo "========================================" echo " 透明代理诊断报告" echo " 时间: $(date) " echo "========================================" ERRORS=0check () { local desc="$1 " local cmd="$2 " printf "%-50s" " $desc ..." if eval "$cmd " > /dev/null 2>&1; then echo "✓" else echo "✗ 故障" ERRORS=$((ERRORS + 1)) fi }info () { local desc="$1 " local cmd="$2 " echo "" echo "--- $desc ---" eval "$cmd " 2>&1 }echo "" echo "【1】基础连通性" check "本机默认路由" "ip route show | grep -q default" info "路由表" "ip route show | grep -E 'default|br-wan|tun0'" echo "" echo "【2】进程状态" check "sing-box 运行中" "pgrep sing-box > /dev/null 2>&1" check "dnsmasq 运行中" "pgrep dnsmasq > /dev/null 2>&1" info "进程详情" "ps | grep -E 'sing-box|dnsmasq' | grep -v grep" echo "" echo "【3】端口监听" check "DNS 53 端口" "netstat -tlnp 2>/dev/null | grep -q ':53 '" echo "" echo "【4】TUN 接口" check "tun0 存在" "ip link show tun0 > /dev/null 2>&1" info "TUN 详情" "ip addr show tun0 2>&1" echo "" echo "【5】路由规则" check "bypass 规则存在" "ip rule show 2>&1 | grep -q '8999'" info "策略路由" "ip rule show 2>&1 | grep -E '8999|2022|2023|2024'" echo "" echo "【6】DNS 解析" info "百度 (应返回国内IP)" "nslookup www.baidu.com 127.0.0.1 2>&1 | grep -E 'Address: [0-9]+\.'" info "Google (应返回海外IP)" "nslookup www.google.com 127.0.0.1 2>&1 | grep -E 'Address: [0-9]+\.'" echo "" echo "【7】sing-box 日志 (最近 20 行)" if which logread > /dev/null 2>&1; then logread -e sing-box | tail -20elif [ -f /tmp/sing-box.log ]; then tail -20 /tmp/sing-box.logfi echo "" echo "【8】IP 转发" info "转发状态" "cat /proc/sys/net/ipv4/ip_forward" echo "" echo "【9】磁盘空间" info "空间" "df -h /" echo "" echo "========================================" if [ $ERRORS -eq 0 ]; then echo " 诊断结果: 全部通过 ✓" else echo " 诊断结果: $ERRORS 项异常, 请检查上方 ✗ 项" fi echo "" echo " 快速修复: /etc/init.d/sing-box restart" echo "========================================"
遇到的坑
sing-box 二进制兼容性
MIPS 必须用 softfloat 版本。linux-mipsle(硬浮点)在 1004Kc 核心上会 Illegal instruction。
TUN MTU
TUN 接口默认 MTU 9000,底层物理网卡只有 MTU 1500,大包分片失败。config.json 中显式设为 1500。
cache_file 路径
sing-box 默认启用 cache_file。OpenWrt 的 /var/cache 重启后被清空,目录不存在会导致启动 FATAL。设为 false 或在 init 中 mkdir -p。
TUN 接口残留
sing-box 异常退出后 tun0 可能残留,下次启动报 device or resource busy。start_service 开头执行 ip link del tun0 2>/dev/null。
auto_route 与 strict_route
两者必须同时启用,否则 SS 服务器连接会形成路由回路。
bypass 路由
即使有 strict_route,手动添加 bypass 路由(priority 8999)最稳妥。
DNS 的 UDP 问题
UDP DNS 通过 TUN/SS 代理后回程响应无法正确送达。用 tcp://8.8.8.8。
内网域名解析
内网域名(如公司 OA)在 dnsmasq 中配置 server=/<domain>/<internal-dns-ip>。
dnsmasq 的 rebind 保护
OpenWrt dnsmasq 默认 stop-dns-rebind,会丢弃私有 IP。内网 DNS 返回私有 IP 时需关闭:option rebind_protection '0'。
dnsmasq 不自启
系统 dnsmasq 需 UCI 配置才启动。我们的方案是接管 dnsmasq,需禁用系统 init 避免冲突。
sing-box v2ray 格式不支持
1.11.x 必须用 .srs 格式规则集,不要用 v2fly 的 22MB geoip.dat。
MIPS 内存
sing-box 在 MIPS 上占用约 55MB。小米路由器 3G(256MB)完全够用。128MB 以下设备需留意。
旁路由网口配置
MIPS 旁路由网口名是 br-wan(x86 物理机 eth0)。ip addr show 查看。
Windows Chrome/Edge 无法上网
Chrome/Edge 默认 Secure DNS (DoH) 绕过系统 DNS。sing-box stop 后 DoH 直连被墙 → 浏览器废掉。关闭:chrome://settings/security → 使用安全 DNS → 关闭。
init 脚本中不要用 killall sing-box
procd 管理的 shell 进程名也是 sing-box,killall 会误杀导致 stop_service 被中断。procd 负责进程管理,stop_service 只做清理。
init 脚本设计要点
stop_service 原则:保留 DNS
旧版直接 killall sing-box dnsmasq,所有客户端 DNS 全断。新版:procd 杀 sing-box,dnsmasq 保留并切上游到 223.5.5.5。
stop 后效果:
国内 DNS:dnsmasq → 223.5.5.5 直连 ✓
海外 DNS:被 GFW 污染(无 SS 隧道,预期行为)
内网 DNS:server=/<domain>/<ip> 不受影响 ✓
start_service DNS 恢复
start 时 sed 把裸 IP 上游(无论之前被 stop 改成什么)恢复为 server=10.10.10.2。用 ^server=[0-9.]\+$ 匹配裸 IP,不会误碰 server=/<domain>/<ip>。
SS 域名解析前置
SS_SERVER 填域名时,nslookup 在任何 setup 之前完成。失败则 return 1 干净退出,不搞半拉子状态。日志写入 /tmp/sing-box.log。
路由器自身 DNS
/etc/resolv.conf 设为 nameserver 127.0.0.1,路由器自身也走 dnsmasq。WAN 是静态 IP(option proto ‘static’),netifd 不会中途 DHCP 覆写。无环路风险:sing-box 出站只用 IP。
速查手册
程序与配置
1 2 3 4 5 6 7 8 sing-box /usr/local/bin/sing-box (MIPS softfloat) → 配置文件 /etc/sing-box/config.json → geo规则 /etc/sing-box/geoip-cn.srs / geosite-cn.srs dnsmasq 由 init 脚本启动 → 配置文件 /etc/dnsmasq-proxy.conf (每次启动自动生成) nftables sing-box TUN auto_route 自动管理
dnsmasq 参考配置
1 2 3 4 5 6 7 8 listen-address=127.0.0.1 listen-address=<LAN-IP> bind-interfaces server=10.10.10.2 server=/yview.cn/172.20.2.113 cache-size=2048 no-resolv filter-AAAA
服务控制
1 2 /etc/init.d/sing-box {start|stop|restart|status} 换IP后: /etc/init.d/sing-box restart (自动检测新IP)
查看配置
1 2 3 4 cat /etc/sing-box/config.json cat /etc/dnsmasq-proxy.conf cat /etc/init.d/sing-box cat /tmp/sing-box.log
更换 SS 节点
vi /etc/init.d/sing-box — 改顶部 SS_SERVER/SS_PORT/SS_PASSWORD/SS_METHOD
/etc/init.d/sing-box restart — init 脚本自动解析域名、注入 config.json、更新 bypass 路由
一次完整请求的数据流(以 Google 为例)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 1. DNS 解析 客户端 → dnsmasq (LAN_IP:53) → 转发到 10.10.10.2 (sing-box DNS模块) → geosite-cn 不命中 "google.com" → 走 dns-remote: tcp://8.8.8.8 通过 SS 隧道查询 → 返回真实海外 IP 2. TCP 连接 客户端 → br-wan → 路由决策: geoip-cn 不命中, 非私有IP → 路由到 tun0 → sing-box 处理: sniff域名, 查规则, final=ss-out → 加密后发往 SS 服务器 3. SS 出站 sing-box 自身到 SS 的连接通过 bypass 路由(priority 8999) 直连 4. 回程 Google → SS服务器 → 加密隧道 → br-wan → tun0 → 客户端
访问百度:DNS geosite-cn 命中 → 223.5.5.5 直连;TCP geoip-cn 命中 → direct 直连。
geosite-cn 的局限性
漏网:新上线大陆网站未被收录 → 走代理绕路变慢
误判:国外域名被标为 cn → 走直连被污染
CDN 混淆:同一域名国内外都有节点 → 收录在 cn 中走直连,正确
实际影响:主流网站 100% 正常,冷门网站小概率异常。
server=/域名/DNS 配置指南
写在 /etc/init.d/sing-box 的 dnsmasq 配置段。
场景 1:内网域名(只有内网 DNS 认识)
公网 DNS 不认识内网域名,必须问内网 DNS:
1 2 server=/yview.cn/172.20.2.113 server=/oa.internal/172.20.2.113
场景 2:国内新网站变慢(geosite-cn 漏了,默认走了代理)
sing-box DNS 用 8.8.8.8 解析,拿到海外 CDN IP,绕路。指定走国内 DNS 直连:
1 server=/xinwangzhan.cn/223.5.5.5
场景 3:国外新网站打不开(geosite-cn 误判为 cn,被污染)
sing-box DNS 用 223.5.5.5 直连解析,被 GFW 污染。指定走 10.10.10.2 重新判断(不命中 geosite-cn,fallback 到 8.8.8.8 via SS):
1 server=/newsite.io/10.10.10.2
如果 10.10.10.2 仍返回错误(geosite-cn 继续误判),直接指定 8.8.8.8(其不在 bypass 列表,走 SS 隧道):
1 server=/newsite.io/8.8.8.8
文件清单(路由器 /root/)
文件清单(项目目录)
1 2 3 4 5 6 7 config.json sing-box 配置 sing-box init 启动脚本 dnsmasq-proxy.conf DNS 配置 deploy.sh 部署脚本 troubleshoot.sh 诊断脚本 update-geo.sh geo 更新脚本 transparent-proxy-deploy.md 详细文档