前言

作为一个通用代理平台,sing-box 协议覆盖更广,DNS 和分流结合得更紧密,TUN 和系统级代理能力也更完整,拿来给自己搭一个私人小通道再合适不过啦(´▽`)

这篇教程就带大家从零开始,在自己的海外服务器上把 sing-box 部署起来。全程只用官方的手动安装方式,不装 s-ui 之类的配置面板,清清爽爽,每行配置都能看懂~

官方文档放在这里,遇到不认识的字段随时可以去翻:

Sing-box 官方文档

版本小约定:下面的服务端配置在 sing-box 1.11 及以上版本都能跑;客户端配置用到了 1.14 才有的顶层 http_clients 和新版 DNS 写法,所以客户端内核请用 1.14 及以上(老内核需要改动几处,文末有说明)。

一、安装 sing-box

本文不使用 s-ui 或其他配置面板,直接按官方文档手动安装 sing-box。运行安装命令:

1
curl -fsSL https://sing-box.app/install.sh | sh

跑完之后敲一下版本命令:

1
sing-box version

能打印出版本号,就说明这个小家伙已经安安静静住进你的服务器啦。官方安装脚本会顺手把 systemd 服务也注册好,之后直接用 systemctl 管理就行。

默认配置文件在 /etc/sing-box/config.json,记住这个路径哦,下一步就要改它。

二、生成节点 UUID 以及 Reality 密钥对

Reality 需要准备三样小东西:密钥对、UUID,还有 short_id。

1. 生成 Reality 密钥对

打开终端运行:

1
sing-box generate reality-keypair

你会得到类似这样的输出:

1
2
PrivateKey: kPf5rxxxxxxBE1w
PublicKey: D3HY1oN9xxxxgUOlg

这是 Reality 要用到的密钥对,先把它复制到剪贴板备用。两个值的用途可别记混啦:

  • PrivateKey(私钥):填在服务端配置里,自己收好,不要外传
  • PublicKey(公钥):填在客户端配置里

小提醒:客户端填的是 PublicKey 公钥,不是私钥哦,这一点好多教程都容易写错。

2. 生成 UUID

1
sing-box generate uuid

或者用系统自带的小工具也一样:

1
cat /proc/sys/kernel/random/uuid

会得到一串类似 xxxxx3b69-9xax-41be-axf3-5dxxxx0efbf8 的字符串,这是 uuid,同样复制到剪贴板备用。

3. 生成 short_id

1
sing-box generate rand --hex 8

short_id 是一串十六进制字符,最长 8 字节(也就是 16 个十六进制字符),它会参与 Reality 握手时的身份校验。留空(写 "")也能用,但填上更稳妥,服务端和客户端必须填得一模一样。

三、修改服务端默认配置文件

sing-box 的默认配置文件是 /etc/sing-box/config.json,我们用 vim 打开它:

1
vim /etc/sing-box/config.json

把里面的内容清空。今天我们要搭建的是 VLESS + Reality,可以直接使用下面这个模板,并把其中的占位符替换成你刚生成的内容:

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
{
"log": {
"level": "info",
"timestamp": true
},
"inbounds": [
{
"type": "vless",
"tag": "vless-in",
"listen": "::",
"listen_port": 443, //端口号建议443,如果被占用可用8443等代替
"users": [
{
"name": "me", //用户名,随便取,只是个备注
"uuid": "", //粘贴你刚才生成的uuid
"flow": "xtls-rprx-vision"
}
],
"tls": {
"enabled": true,
"server_name": "www.learn.microsoft.com", //伪装域名,必须和下面 handshake.server 一致
"alpn": [
"h2",
"http/1.1"
],
"reality": {
"enabled": true,
"handshake": {
"server": "www.learn.microsoft.com",
"server_port": 443
},
"private_key": "", //粘贴你之前生成的reality密钥对的PrivateKey内容
"short_id": [
"" //填你刚才生成的short_id
]
}
}
}
],
"outbounds": [
{
"type": "direct",
"tag": "direct"
}
]
}

sing-box 自带的 JSON 解析器支持 // 注释和尾随逗号,所以上面这些注释不会让它报错(不过就别再拿其他 JSON 校验工具去检查啦,标准 JSON 是不认注释的)。

关于伪装域名(也就是 handshake.server),挑选时记住这几点:

  • 必须是支持 TLS 1.3 + HTTP/2 的网站
  • 挑大厂的大流量站点,和你的服务器之间延迟低一些更好
  • 别用你自己的域名,也别用已经被标记过、或你所在网络根本打不开的域名

顺手可以验证一下它合不合格:

1
openssl s_client -connect www.learn.microsoft.com:443 -tls1_3 -alpn h2 </dev/null 2>/dev/null | grep -E "Protocol|ALPN"

看到 Protocol : TLSv1.3 和 ALPN protocol: h2 就可以放心啦。

顺便说说 alpn 为什么写 h2、http/1.1:Reality 的握手走的是 TCP,而 h3 是给 QUIC/UDP 用的,把它塞进这个列表属于常见的小坑,容易让握手对不上。

四、启动 sing-box

先做一次配置语法检查:

1
sing-box check -c /etc/sing-box/config.json

如果没有任何输出,就代表语法检查通过,可以进入下一步。

启动服务:

1
systemctl start sing-box

如果需要开机自启,运行:

1
systemctl enable sing-box

看看运行状态:

1
systemctl status sing-box

输出里存在 Active: active (running) 即为运行成功。以后每次改完配置,都记得先检查再重启:

1
sing-box check -c /etc/sing-box/config.json && systemctl restart sing-box

万一起不来,就到日志里找原因:

1
journalctl -u sing-box -o cat -e

五、客户端连接

打开 sing-box 客户端,添加配置文件(需要 1.14 及以上内核),粘贴下面的模板,并修改其中所有占位符:

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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
{
"$schema": "https://sing-box.sagernet.org/schema.json",
"log": {},
"dns": {
"servers": [
{
"type": "https",
"tag": "remote",
"server": "8.8.8.8",
"detour": "select"
},
{
"type": "https",
"tag": "local",
"server": "223.5.5.5"
},
{
"type": "fakeip",
"tag": "fakeip",
"inet4_range": "198.18.0.0/15",
"inet6_range": "2001:470:f9da:fdfa::1/64"
}
],
"rules": [
{
"rule_set": [
"AdGuardSDNSFilter",
"chrome-doh"
],
"action": "predefined"
},
{
"query_type": "HTTPS",
"action": "predefined"
},
{
"query_type": [
"A",
"AAAA"
],
"action": "route",
"server": "fakeip",
"rewrite_ttl": 1
},
{
"clash_mode": "global",
"action": "route",
"server": "remote"
},
{
"clash_mode": "direct",
"action": "route",
"server": "local"
},
{
"rule_set": "geosite-cn",
"action": "route",
"server": "local"
},
{
"rule_set": "ext-cn-domain",
"action": "route",
"server": "local"
}
],
"strategy": "prefer_ipv4",
"optimistic": true
},
"http_clients": [
{
"tag": "select",
"version": 2,
"detour": "select",
"stream_receive_window": 0,
"connection_receive_window": 0
}
],
"inbounds": [
{
"type": "tun",
"mtu": 9000,
"address": [
"172.19.0.1/30",
"fdfe:dcba:9876::1/126"
],
"auto_route": true,
"strict_route": true
},
{
"type": "socks",
"tag": "socks-in",
"listen": "127.0.0.1",
"listen_port": 2333
},
{
"type": "mixed",
"tag": "mixed-in",
"listen": "127.0.0.1",
"listen_port": 2334
}
],
"outbounds": [
{
"type": "selector",
"tag": "select",
"default": "VLESS",
"outbounds": [
"VLESS"
]
},
{
"type": "vless",
"tag": "VLESS",
"server": "", //你的服务器ip
"server_port": 443, //服务端sing-box的监听端口
"uuid": "", //你的uuid
"flow": "xtls-rprx-vision",
"tls": {
"enabled": true,
"server_name": "www.learn.microsoft.com", //必须和服务端一致
"utls": {
"enabled": true,
"fingerprint": "chrome"
},
"reality": {
"enabled": true,
"public_key": "", //你的Reality公钥(PublicKey)
"short_id": "" //你的short_id
}
}
},
{
"type": "direct",
"tag": "direct"
}
],
"route": {
"rules": [
{
"action": "sniff"
},
{
"protocol": "dns",
"action": "hijack-dns"
},
{
"action": "resolve",
"strategy": "prefer_ipv4"
},
{
"clash_mode": "direct",
"outbound": "direct"
},
{
"clash_mode": "global",
"outbound": "select"
},
{
"ip_is_private": true,
"outbound": "direct"
},
{
"rule_set": "geoip-cn",
"outbound": "direct"
}
],
"rule_set": [
{
"type": "remote",
"tag": "geoip-cn",
"url": "https://raw.githubusercontent.com/SagerNet/sing-geoip/rule-set/geoip-cn.srs"
},
{
"type": "remote",
"tag": "geosite-cn",
"url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-geolocation-cn.srs"
},
{
"type": "remote",
"tag": "AdGuardSDNSFilter",
"url": "https://raw.githubusercontent.com/xmdhs/sing-box-ruleset/rule-set/AdGuardSDNSFilterSingBox.srs"
},
{
"type": "remote",
"tag": "chrome-doh",
"url": "https://gist.githubusercontent.com/xmdhs/71fc5ff6ef29f5ecaf2c52b8de5c3172/raw/chrome-doh.json"
},
{
"type": "remote",
"tag": "ext-cn-domain",
"url": "https://raw.githubusercontent.com/xmdhs/cn-domain-list/rule-set/ext-cn-list.srs"
}
],
"final": "select",
"auto_detect_interface": true,
"default_domain_resolver": "local"
},
"experimental": {
"cache_file": {
"enabled": true
}
}
}

需要替换的地方一共这几处,别漏掉:

  • server:你的服务器 IP
  • server_port:服务端 sing-box 监听的端口
  • uuid:服务端填的那个 UUID
  • public_key:Reality 的 PublicKey 公钥
  • short_id:和服务端一致的 short_id
  • server_name:和服务端保持一致(模板里已经填好了)

替换完保存启用,就可以用它出去看看世界啦~(๑•̀ㅂ•́)و✧

这份客户端配置里还有几个小细节,知道了会更安心:

  • dns 里的 remote 服务器走 select 出站,也就是借用你的节点来解析;local 则直连阿里 DNS,国内域名用国内 DNS 解析会更快。
  • http_clients 里定义的那个客户端,默认会被用作远程 rule_set 的下载通道(第一个即默认,不需要额外指定),所以规则集也能顺顺利利拉下来。
  • 分流部分:geoip-cn 命中走直连,geosite-cn、ext-cn-domain 命中用国内 DNS 解析,广告域名和 Chrome 的 DoH 域名则由 AdGuardSDNSFilter、chrome-doh 这两个规则集拦掉。
  • 那两条 clash_mode 规则要在客户端里切换模式(global / direct)才会生效;如果想手动切换模式,可以在 experimental 里补一个 clash_api。

六、几个小贴士

  • 端口要放行:云服务商的安全组和服务器自身的防火墙都得放行对应的 TCP 端口,比如:
    1
    ufw allow 443/tcp
  • 443 被占用:先用 ss -tlnp | grep :443 看看是谁占了(比如 nginx),不想动它就把 sing-box 换成 8443 之类的端口,客户端记得同步改。
  • 关于 listen: "::":它表示同时监听 IPv4 和 IPv6;如果你的服务器彻底关掉了 IPv6,可以改成 0.0.0.0。
  • 老内核要改哪里:客户端内核低于 1.14 时,需要删掉顶层的 http_clients 整段(远程规则集会退回用默认出站去下载),DNS 规则里的 "action": "predefined" 也要改回旧写法。
  • 速度慢的话:可以在服务端顺手开一下 BBR:
    1
    echo -e "net.core.default_qdisc=fq\nnet.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf && sysctl -p

到这里,一个属于自己的 VLESS + Reality 小节点就搭好啦!全程不用证书、不用域名、不用面板,干干净净的(≧▽≦)

配置里最容易踩坑的还是 PublicKey 和 short_id 两边要一致,其他字段照抄就行。祝你用得开心~