Recommended sing-box Configurations

Introduction

This article only presents a working stable sing-box configuration.

From JSON to YAML

The default configuration file for sing-box is in JSON format, making it unfriendly to manual modifications. It is much easier to write configuration file in YAML. If you already have a config.json file, you may use a python script to convert the file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import json
import yaml
import os

os.chdir(
os.path.dirname(
os.path.abspath(
__file__
)
)
)

with open('config.json', 'r') as input:
json_object: dict = json.loads(input.read())
with open('config.json.yaml', 'w') as output:
output.write(yaml.dump(json_object, allow_unicode=True, indent=4))

Log, DNS and Experimental

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
log:
disabled: false
level: info
timestamp: true

ntp:
enabled: true
interval: 60m
server: ntp.aliyun.com
server_port: 123
# Dial Fields
detour: DIRECT

experimental:
cache_file:
enabled: true
path: cache.db
store_fakeip: false
clash_api:
external_controller: 127.0.0.1:9090
external_ui: clash_api
external_ui_download_detour: PROXY
secret: alpine

These parts are easy to comprehend, so not many comments provided. The only thing to be noticed is that it is recommended to specify the detour as DIRECT in ntp because a direct connection to a nearest NTP server is safe and quick.

Inbounds

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
inbounds:
- tag: mixed-in
type: mixed
set_system_proxy: false
# Listen Fields
listen: 127.0.0.1
listen_port: 56116
sniff: true
sniff_override_destination: true

- tag: tun-in
type: tun
inet4_address: 100.100.0.1/30
inet6_address: 2001:0470:f9da::1/64
stack: system
auto_route: true
strict_route: true
mtu: 9000
# Listen Fields
sniff: true
sniff_override_destination: true

Unlike JSON, YAML uses hyphens to distinguish items of a list. So please remember to add a hyphen at the beginning of the inbounds list item.

There are two working inbounds that most users should implement. The first one is mixed, a proxy server, which is well known. The second one is tun, a TUN tunnel, which routes all the TCP and UDP connections of the system.

Without root on Android devices and jailbreak on iOS devices, it is not possible to set up global proxy settings on mobile platforms. So far, the developers have been using VPN interfaces to build up TUN tunnels. Under this circumstance, all kinds of network data should be considered for routing. Classical rules working on desktop platforms (with only global proxy settings) are deprecated.

Outbounds

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
outbounds:
- tag: DIRECT
type: direct

- tag: REJECT
type: block

- tag: dns-out
type: dns

- tag: Remote 1
type: shadowsocks
method: chacha20-ietf-poly1305
password: your-favoraite-passphrase
server: your.socks.provider.com
server_port: 30001

- tag: Remote 2
type: shadowsocks
method: chacha20-ietf-poly1305
password: your-favoraite-passphrase
server: your.socks.provider.com
server_port: 30002

- tag: Auto Selection
type: urltest
outbounds:
- Remote 1
- Remote 2
url: http://cp.cloudflare.com/
interval: 5m
tolerance: 200

- tag: Manual Selection
type: selector
outbounds:
- Remote 1
- Remote 2
default: Remote 1
interrupt_exist_connections: true

- tag: PROXY
type: selector
outbounds:
- Auto Selection
- Manual Selection
default: Auto Selection
interrupt_exist_connections: true

- tag: BLOCK
type: selector
interrupt_exist_connections: true
outbounds:
- REJECT
- DIRECT

- tag: GLOBAL
type: selector
interrupt_exist_connections: true
outbounds:
- PROXY
- DIRECT

- tag: FINAL
type: selector
outbounds:
- PROXY
- DIRECT
- Manual Selection

In outbounds, we must have three default kinds of items beforehand: direct, block and dns. Otherwise, the sing-box will not properly run. Then put all the entries form the provider. Use type urltest to build an automatic selector by URL test, type selector to build a manual selector by hand, and another selector to bundle the two together.

DNS

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
dns:
fakeip:
enabled: false
inet4_range: 198.18.0.0/15
inet6_range: fc00::/18
independent_cache: true
reverse_mapping: false

rules:
- disable_cache: true
domain:
- uspider.yuanshen.com
- log-upload.mihoyo.com
- public-data-api.mihoyo.com
- log-upload-os.hoyoverse.com
- sg-public-data-api.hoyoverse.com
- overseauspider.yuanshen.com
- dump.gamesafe.qq.com
server: dns-block

- domain:
- your.socks.provider.com
- ntp.aliyun.com
server: dns-init

- clash_mode: Global
server: dns-proxy

- clash_mode: Direct
server: dns-system

- domain:
- ip.istatmenus.app
domain_keyword:
- icloud
- zxinc
- mhystatic
- yuhengcup
domain_suffix:
- .me.com
rule_set:
- private
- category-games@cn
- apple-cn
server: dns-direct

- domain_keyword:
- github
- bing
- 3shain
- hakush
- fygod
- gstatic
- googleapis
rule_set:
- geolocation-!cn
- tld-!cn
- gfw
server: dns-proxy

- rule_set:
- tld-cn
- cn
server: dns-direct

- disable_cache: true
rule_set: category-ads-all
server: dns-block

servers:
- tag: dns-proxy
address: https://1.1.1.1/dns-query
detour: PROXY
strategy: ipv4_only
- tag: dns-direct
address: https://223.5.5.5/dns-query
detour: DIRECT
strategy: prefer_ipv4
- tag: dns-init
address: https://223.5.5.5/dns-query
detour: DIRECT
strategy: ipv4_only
- tag: dns-system
address: local
- tag: dns-block
address: rcode://success

The most important thing in this part of configuration is that you must specify a trusted resolver before proxy connections. In this case, dns-init is specified to resolve all the necessary domains in the rules section: your.socks.provider.com and ntp.aliyun.com. Otherwise, when resolving these two domains at the very beginning of the bootstrap of sing-box, it will mismatch all the rules and use the final domain server. If not specified, final will be the first one of the servers list. But unfortunately the first entry of the servers list specifies detour as PROXY, which uses your.socks.provider.com, but it is not resolved! This causes a loopback and the error can be seen in the log.

Route

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
route:
rule_set:
- tag: category-ads-all
type: remote
format: binary
url: https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/category-ads-all.srs
download_detour: PROXY
update_interval: 1d
- tag: apple-cn
type: remote
format: binary
url: https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/apple-cn.srs
download_detour: PROXY
update_interval: 1d
- tag: category-games@cn
type: remote
format: binary
url: https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/category-games@cn.srs
download_detour: PROXY
update_interval: 1d
- tag: cn
type: remote
format: binary
url: https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/cn.srs
download_detour: PROXY
update_interval: 1d
- tag: private
type: remote
format: binary
url: https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/private.srs
download_detour: PROXY
update_interval: 1d
- tag: tld-cn
type: remote
format: binary
url: https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/tld-cn.srs
download_detour: PROXY
update_interval: 1d
- tag: geolocation-!cn
type: remote
format: binary
url: https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/geolocation-!cn.srs
download_detour: PROXY
update_interval: 1d
- tag: tld-!cn
type: remote
format: binary
url: https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/tld-!cn.srs
download_detour: PROXY
update_interval: 1d
- tag: gfw
type: remote
format: binary
url: https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/gfw.srs
download_detour: PROXY
update_interval: 1d
- tag: openai
type: remote
format: binary
url: https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/openai.srs
download_detour: PROXY
update_interval: 1d
- tag: cn-ip
type: remote
format: binary
url: https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geoip/cn.srs
download_detour: PROXY
update_interval: 1d
- tag: private-ip
type: remote
format: binary
url: https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geoip/private.srs
download_detour: PROXY
update_interval: 1d
- tag: telegram
type: remote
format: binary
url: https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geoip/telegram.srs
download_detour: PROXY
update_interval: 1d

rules:
- clash_mode: Global
outbound: GLOBAL

- clash_mode: Direct
outbound: DIRECT

- protocol: dns
outbound: dns-out

- ip_is_private: true
outbound: DIRECT

- domain:
- uspider.yuanshen.com
- log-upload.mihoyo.com
- public-data-api.mihoyo.com
- log-upload-os.hoyoverse.com
- sg-public-data-api.hoyoverse.com
- overseauspider.yuanshen.com
- dump.gamesafe.qq.com
outbound: BLOCK

- domain:
- ip.istatmenus.app
domain_keyword:
- icloud
- zxinc
- mhystatic
- yuhengcup
domain_suffix:
- .me.com
rule_set:
- private
- category-games@cn
- apple-cn
- cn-ip
- private-ip
outbound: DIRECT

- domain_keyword:
- bing
- github
- xn--ngstr-lra8j
- 3shain
- hakush
- fygod
- gstatic
- googleapis
rule_set:
- openai
- geolocation-!cn
- tld-!cn
- gfw
- telegram
outbound: PROXY

- rule_set:
- tld-cn
- cn
outbound: DIRECT

- rule_set: category-ads-all
outbound: BLOCK

final: FINAL
auto_detect_interface: true

From YAML to JSON

After all, we need to convert the YAML file back to JSON and use the JSON file in sing-box (and its GUI variants).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import json
import yaml
import os

os.chdir(
os.path.dirname(
os.path.abspath(
__file__
)
)
)

with open('config.json.yaml', 'r') as input:
yaml_object: dict = yaml.load(input.read(), yaml.Loader)
with open('config.yaml.json', 'w') as output:
output.write(json.dumps(yaml_object, ensure_ascii=False))

The config.yaml.json is the final output.


Recommended sing-box Configurations
https://lucisurbe.pages.dev/2024/03/23/Recommended-sing-box-Configurations/
Author
Lucis Urbe
Posted on
March 23, 2024
Licensed under