0%

sing-box:让 OpenWrt 路由器实现智能代理的终极方案

OpenWrt 路由器配置网络代理

网络环境日益复杂,优秀的工具往往意味着不低的配置门槛。即使是像 sing-box 这样功能强大、设计优雅的通用代理平台,其 JSON 格式的灵活配置也可能让人望而却步,且不同协议、路由规则的组合极易遗忘。为避免重复“踩坑”,特此记录下 sing-box 的配置过程与关键细节,以作备忘。

什么是 sing-box?

sing-box 是一个用 Rust 编写的通用代理平台,由 SagerNet 团队开发。它支持多种代理协议,包括 V2Ray、Trojan、Hysteria2、Shadowsocks 等,可以说是目前功能最全面的代理工具之一。

为什么选择 sing-box?

  • 🚀 性能卓越:Rust 编写,内存占用小,并发能力强
  • 🔄 协议丰富:支持市面上几乎所有主流代理协议
  • 🎯 智能路由:内置强大的规则引擎,支持域名、IP、地理位置等多种匹配方式
  • 🔧 配置灵活:JSON 格式配置,结构清晰,易于维护
  • 🛡️ 透明代理:支持 TProxy 模式,无需客户端配置

准备工作

硬件要求

  • OpenWrt 路由器:建议 21.02 版本以上
  • 存储空间:至少 16MB 可用空间
  • 内存:建议 128MB 以上(内存越大,并发连接数越多)
  • 网络:稳定的互联网连接

技术概念简介

TProxy(透明代理) 是 Linux 内核提供的一种流量重定向机制。简单来说,它可以在用户毫无察觉的情况下,将网络流量自动转发到代理服务器。这意味着:

  • 📱 零配置:手机、电脑、平板等设备无需任何设置
  • 🏠 全屋覆盖:连接路由器的所有设备都能享受代理服务
  • 🔄 智能分流:国内网站直连,国外网站走代理

安装 sing-box

下载安装包

首先连接到你的 OpenWrt 路由器,通过 SSH 登录:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 进入临时目录
cd /tmp

# 下载最新版本的 sing-box(以 x86_64 架构为例)
# 如果你的路由器是其他架构,请到 GitHub Releases 页面找到对应的版本
wget https://github.com/SagerNet/sing-box/releases/download/v1.8.3/sing-box-1.8.3-linux-amd64.tar.gz

# 解压文件
tar -xzf sing-box-*.tar.gz
cd sing-box-*/

# 将可执行文件复制到系统路径
cp sing-box /usr/bin/
chmod +x /usr/bin/sing-box

# 创建配置文件目录
mkdir -p /etc/sing-box/rule-sets

# 验证安装是否成功
sing-box version

创建服务管理脚本

为了确保 IP 路由规则持久化,我们创建一个服务管理脚本,负责在启动时添加 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
# 创建服务脚本
cat > /etc/init.d/singbox << 'EOF'
#!/bin/sh /etc/rc.common

START=99
STOP=10

TPROXY_TABLE=100
FWMARK=1

load_ip_rules() {
echo "正在加载 Sing-box IP 规则..."
ip rule add fwmark $FWMARK lookup $TPROXY_TABLE 2>/dev/null
ip route add local 0.0.0.0/0 dev lo table $TPROXY_TABLE 2>/dev/null
echo "Sing-box IP 规则已加载。"
}

unload_ip_rules() {
echo "正在卸载 Sing-box IP 规则..."
ip rule del fwmark $FWMARK lookup $TPROXY_TABLE 2>/dev/null
ip route del local 0.0.0.0/0 dev lo table $TPROXY_TABLE 2>/dev/null
}

start() {
echo "正在启动 sing-box..."
# 启动 sing-box
ENABLE_DEPRECATED_SPECIAL_OUTBOUNDS=true /usr/bin/sing-box run -c /etc/sing-box/config.json > /var/log/singbox.log 2>&1 &
echo $! > /var/run/singbox.pid

# 确保 sing-box 启动后再加载 IP 规则
sleep 5
load_ip_rules
}

stop() {
echo "正在停止 sing-box..."
[ -f /var/run/singbox.pid ] && {
kill $(cat /var/run/singbox.pid)
rm -f /var/run/singbox.pid
}
# 停止时清理 IP 规则
unload_ip_rules
}

restart() {
stop
sleep 2
start
}
EOF

# 设置执行权限并启用开机自启动
chmod +x /etc/init.d/singbox
/etc/init.d/singbox enable

配置 sing-box

创建主配置文件

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
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
{
"log": {
"level": "info",
"timestamp": true
},
"dns": {
"servers": [
{
"tag": "local",
"address": "223.5.5.5",
"detour": "direct"
},
{
"tag": "proxy-dns",
"address": "tls://8.8.8.8",
"detour": "proxy"
},
{
"tag": "block",
"address": "rcode://success"
}
],
"rules": [
{
"rule_set": ["geosite-cn"],
"server": "local"
},
{
"rule_set": ["geosite-gfw"],
"server": "proxy-dns"
},
{
"rule_set": "geosite-category-ads-all",
"server": "block"
}
],
"final": "local",
"disable_cache": false,
"strategy": "prefer_ipv4"
},
"inbounds": [
{
"type": "tproxy",
"tag": "tproxy-in",
"listen": "0.0.0.0",
"listen_port": 12345,
"sniff": true,
"sniff_override_destination": true,
"network": "tcp,udp"
}
],
"outbounds": [
{
"type": "direct",
"tag": "direct"
},
{
"type": "hysteria2",
"tag": "proxy",
"server": "your-server.com",
"server_port": 443,
"password": "your-password",
"tls": {
"enabled": true,
"server_name": "your-server.com",
"insecure": false
}
},
{
"type": "block",
"tag": "block"
},
{
"type": "dns",
"tag": "dns-out"
}
],
"route": {
"rules": [
{
"protocol": "dns",
"outbound": "dns-out"
},
{
"rule_set": ["geoip-cn"],
"outbound": "direct"
},
{
"rule_set": ["geosite-cn"],
"outbound": "direct"
},
{
"rule_set": ["geosite-gfw"],
"outbound": "proxy"
},
{
"rule_set": "geosite-category-ads-all",
"outbound": "block"
}
],
"rule_set": [
{
"tag": "geoip-cn",
"type": "remote",
"format": "binary",
"url": "https://raw.githubusercontent.com/SagerNet/sing-geoip/rule-set/geoip-cn.srs"
},
{
"tag": "geosite-cn",
"type": "remote",
"format": "binary",
"url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-cn.srs"
},
{
"tag": "geosite-gfw",
"type": "remote",
"format": "binary",
"url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-gfw.srs"
}
],
"final": "proxy",
"auto_detect_interface": true
}
}

配置文件说明:

  • DNS 设置:国内域名使用 223.5.5.5 解析,国外域名使用 8.8.8.8 解析
  • 入站设置:监听 12345 端口,接收 TProxy 转发的流量
  • 出站设置:定义了直连、代理、阻止等不同的出口
  • 路由规则:根据地理位置和域名列表智能分流

配置防火墙规则

为了确保防火墙规则在网络或防火墙服务重启后不会丢失,我们采用 nftables 钩子方案。这是 OpenWrt 中持久化防火墙规则的最佳实践。

创建一个 .nft 文件,OpenWrt 的 firewall4 服务在每次启动或重载时都会自动读取并加载它。

创建文件: /etc/nftables.d/99-singbox.nft

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
cat << "EOF" > /etc/nftables.d/99-singbox.nft
# TProxy 端口和标记定义
define TPROXY_PORT = 12345
define FWMARK = 1

# 在 inet (ipv4 和 ipv6) 的 fw4 表中添加规则
# 我们将这些规则插入到 mangle_prerouting 链中

chain mangle_prerouting {
# 1. 排除局域网和保留地址 (确保这些地址的流量不被重定向)
ip daddr { 127.0.0.0/8, 192.168.123.0/24, 10.0.0.0/8, 100.64.0.0/10, 169.254.0.0/16, 172.16.0.0/12, 192.0.0.0/24, 192.168.0.0/16, 198.18.0.0/15, 224.0.0.0/4, 240.0.0.0/4 } counter return comment "Sing-box Bypass LAN/Reserved"

# 2. TProxy 重定向规则:TCP 流量
ip protocol tcp tproxy ip to :$TPROXY_PORT meta mark set $FWMARK comment "Sing-box TProxy TCP"

# 3. TProxy 重定向规则:UDP 流量
ip protocol udp tproxy ip to :$TPROXY_PORT meta mark set $FWMARK comment "Sing-box TProxy UDP"
}
EOF

验证路由规则

启动服务后,检查路由规则是否正确加载:

1
2
3
4
5
6
7
8
# 检查 IP 规则
ip rule show | grep "fwmark 1"

# 检查路由表
ip route show table 100

# 检查 nftables 规则
nft list ruleset | grep -A 10 "mangle_prerouting"

启动和验证

启动服务

1
2
3
4
5
6
7
8
# 应用 nftables 规则
/etc/init.d/firewall reload

# 重启 sing-box 服务
/etc/init.d/singbox restart

# 检查服务状态
/etc/init.d/singbox status

验证配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 检查 sing-box 进程是否运行
ps | grep sing-box

# 检查端口是否监听
netstat -tlnp | grep 12345

# 查看 nftables 规则
nft list ruleset | grep -A 10 "mangle_prerouting"

# 检查路由规则
ip rule show | grep "fwmark 1"

# 测试代理功能(应该显示代理服务器的 IP)
curl -s https://ipinfo.io/ip

监控日志

1
2
3
4
5
# 实时查看 sing-box 日志
tail -f /var/log/singbox.log

# 过滤显示代理相关的日志
tail -f /var/log/singbox.log | grep -E "(tproxy|PROXY|DIRECT)"

常见问题解决

TProxy 不工作

1
2
3
4
5
6
7
8
9
10
# 检查内核是否支持 IP 转发
cat /proc/sys/net/ipv4/ip_forward
# 应该返回 1,如果不是,执行:
echo 1 > /proc/sys/net/ipv4/ip_forward

# 检查 nftables 规则是否正确加载
nft list ruleset | grep -A 10 "mangle_prerouting"

# 检查防火墙状态
/etc/init.d/firewall status

DNS 解析失败

1
2
3
4
5
6
7
8
9
10
# 测试 DNS 解析
nslookup google.com
nslookup baidu.com

# 检查 DNS 配置
cat /tmp/resolv.conf.auto

# 手动测试 DNS 服务器
dig @8.8.8.8 google.com
dig @223.5.5.5 baidu.com

性能优化

1
2
3
4
5
6
7
8
9
10
11
12
13
# 调整内核参数以提高性能
cat >> /etc/sysctl.conf << 'EOF'
# 网络连接优化
net.netfilter.nf_conntrack_tcp_timeout_established = 1200
net.netfilter.nf_conntrack_udp_timeout = 60
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
EOF

# 应用新的内核参数
sysctl -p

日常维护

服务管理

1
2
3
4
5
6
7
8
9
10
11
# 重启 sing-box 服务
/etc/init.d/singbox restart

# 停止服务
/etc/init.d/singbox stop

# 查看详细状态
/etc/init.d/singbox status

# 重载防火墙规则
/etc/init.d/firewall reload

更新规则集

1
2
3
4
5
6
7
8
# 下载最新的地理位置规则集
cd /etc/sing-box/rule-sets
wget -O geoip-cn.srs "https://raw.githubusercontent.com/SagerNet/sing-geoip/rule-set/geoip-cn.srs"
wget -O geosite-cn.srs "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-cn.srs"
wget -O geosite-gfw.srs "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-gfw.srs"

# 重启服务以应用新规则
/etc/init.d/singbox restart

备份配置

1
2
# 备份整个配置目录
tar -czf sing-box-backup-$(date +%Y%m%d).tar.gz /etc/sing-box/ /etc/nftables.d/99-singbox.nft /etc/init.d/singbox

进阶配置

多服务器负载均衡

如果你有多个代理服务器,可以配置负载均衡:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
"outbounds": [
{
"type": "selector",
"tag": "proxy",
"outbounds": ["server1", "server2", "server3"],
"default": "server1"
},
{
"type": "hysteria2",
"tag": "server1",
"server": "server1.com",
"server_port": 443,
"password": "password1"
},
{
"type": "hysteria2",
"tag": "server2",
"server": "server2.com",
"server_port": 443,
"password": "password2"
}
]
}

自定义规则

你可以添加自定义的路由规则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"route": {
"rules": [
{
"domain": ["example.com", "test.com"],
"outbound": "proxy"
},
{
"ip_is_private": true,
"outbound": "direct"
}
]
}
}

为什么选择 nftables 钩子方案?

nftables 钩子方案具有以下显著优势:

  • 持久性:规则存储在 /etc/nftables.d/ 目录中,防火墙重启时自动加载
  • 稳定性:避免网络重启时规则丢失导致的断网问题
  • 简洁性:规则集中管理,配置更加清晰
  • 兼容性:与 OpenWrt 的 firewall4 服务完美集成
  • 可维护性:便于调试和修改规则

服务脚本特点

  • 🔄 自动管理 IP 规则:启动时加载,停止时清理,避免规则残留
  • 优化的启动顺序:确保 sing-box 启动后再加载路由规则
  • 🛡️ 错误处理:使用 2>/dev/null 避免重复添加规则时的报错
  • 📊 状态反馈:明确的加载和卸载提示信息

总结

sing-box 的 TProxy 配置方案提供了一个功能强大且相对简单的透明代理解决方案。相比传统的 TUN 模式,它具有以下优势:

  • 兼容性更好:不会与 VPN、Docker 等网络服务冲突
  • 性能更优:内核层面转发,性能损失更小
  • 配置更简单:无需复杂的客户端配置
  • 维护更容易:集中管理,便于调试和监控

通过这个配置,你可以为整个家庭网络提供智能代理服务,让所有设备都能畅游全球互联网。同时,国内网站仍然保持直连,确保访问速度。

重要提醒:你的防火墙规则已经持久化,即使运行 /etc/init.d/firewall reload,TProxy 的重定向规则也会被自动重新加载,确保网络连接稳定可靠!


📝 记录时间:2025-11-01 20:41 | 配置环境:OpenWrt 23.05 + sing-box v1.8.3

温馨提示:在使用代理服务时,请确保遵守当地法律法规,合理使用网络资源。本文仅用于技术学习和交流目的。