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 jsonimport yamlimport 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 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: 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 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 jsonimport yamlimport 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.