mini-sing
Lightweight sing-box compatible proxy. ~6,500 lines of Go, config-compatible with sing-box.
Architecture
┌──────────────────────────────────────────────────────────┐
│ main.go — Entry point, config loading │
│ box.go — Box lifecycle (create inbounds/outbounds/DNS) │
│ api.go — HTTP API server (/connections, /proxies, etc.) │
├──────────────────────────────────────────────────────────┤
│ Inbound │ Outbound │
│ ├─ mixed (SOCKS5+HTTP) │ ├─ direct │
│ ├─ tun (system VPN) │ ├─ shadowsocks │
│ ├─ shadowsocks │ ├─ trojan │
│ └─ trojan │ ├─ vmess │
│ │ ├─ vless │
│ │ ├─ tailscale (via tailnet) │
│ │ ├─ block │
│ │ └─ group (selector/urltest) │
├───────────────────────────┴───────────────────────────────┤
│ route/ — Router + rules (domain, IP, protocol, process) │
├──────────────────────────────────────────────────────────┤
│ dns/ — Split DNS resolver (remote DoT/DoH + local) │
├──────────────────────────────────────────────────────────┤
│ common/ │
│ ├─ dialer — Protected dialer (Android VPN bypass) │
│ ├─ listener — TCP/UDP listener with context │
│ ├─ sniff — Protocol sniffing (TLS SNI, HTTP Host) │
│ └─ tlsutil — TLS fingerprint (uTLS) │
└──────────────────────────────────────────────────────────┘
Directory Structure
mini-sing/
├── main.go Entry point, config loading
├── box.go Box lifecycle (386 lines)
├── api.go HTTP API (Clash-compatible)
├── ffi_android.go Android JNI bridge + socket protection
│
├── adapter/ Interfaces
│ ├── inbound.go Inbound interface
│ ├── outbound.go Outbound interface
│ ├── router.go Router interface
│ ├── handler.go Connection handler
│ ├── upstream.go Upstream proxy chain
│ ├── conn.go Connection wrappers
│ └── lifecycle.go Start/Close stages
│
├── protocol/ Protocol implementations
│ ├── mixed/inbound.go SOCKS5 + HTTP proxy (250 lines)
│ ├── tun/inbound.go System TUN/VPN (490 lines)
│ ├── shadowsocks/ SS inbound + outbound
│ ├── trojan/ Trojan inbound + outbound
│ ├── vmess/outbound.go VMess client
│ ├── vless/outbound.go VLESS client
│ ├── tailscale/outbound.go Tailscale via tailnet (253 lines)
│ ├── direct/outbound.go Direct connection
│ ├── block/outbound.go Block/reject
│ └── group/ Selector + URL test
│
├── route/ Routing engine
│ ├── router.go Route matching + dispatch
│ ├── rule.go Rule evaluation
│ ├── rule_item.go Rule matchers (domain, IP, etc.)
│ └── conn.go Connection tracking
│
├── dns/ DNS subsystem
│ ├── resolver.go Split DNS (remote + local)
│ ├── server.go DNS server (UDP/TCP)
│ └── cache.go DNS cache
│
├── option/ Config types (JSON)
│ ├── options.go Top-level config
│ ├── inbound.go Inbound options
│ ├── outbound.go Outbound options
│ ├── rule.go Route rule options
│ └── *.go Per-protocol options
│
├── manager/ Component managers
│ ├── inbound.go Inbound registry + lifecycle
│ └── outbound.go Outbound registry + lifecycle
│
├── registry/ Type registration
│ ├── inbound.go Inbound type registry
│ └── outbound.go Outbound type registry
│
├── common/ Shared utilities
│ ├── dialer/dialer.go Protected dialer (Android fd protection)
│ ├── listener/listener.go TCP/UDP listener
│ ├── sniff/sniff.go Protocol sniffing (TLS SNI, HTTP Host)
│ └── tlsutil/tls.go uTLS fingerprinting
│
├── transport/trojan/ Trojan wire protocol
│ ├── protocol.go Trojan framing
│ └── service.go Trojan server handler
│
├── log/log.go Structured logger
└── include/registry.go Protocol registration entry point
Protocols
| Protocol | Inbound | Outbound | Notes |
|---|---|---|---|
| Mixed (SOCKS5+HTTP) | ✅ | — | Primary proxy inbound |
| TUN | ✅ | — | System VPN, Android VpnService |
| Shadowsocks | ✅ | ✅ | AEAD 2022 + stream ciphers |
| Trojan | ✅ | ✅ | TLS + WebSocket transport |
| VMess | — | ✅ | AEAD + legacy |
| VLESS | — | ✅ | Vision (uTLS) support |
| Tailscale | — | ✅ | Via tailnet library |
| Direct | — | ✅ | Bypass proxy |
| Block | — | ✅ | Reject connections |
| Selector | — | ✅ | Manual proxy selection |
| URL Test | — | ✅ | Auto-select by latency |
Routing
Rules evaluated in order, first match wins:
{
"route": {
"rules": [
{"domain_suffix": ["cn"], "outbound": "direct"},
{"ip_cidr": ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"], "outbound": "direct"},
{"protocol": "dns", "outbound": "dns-out"},
{"domain_keyword": ["google"], "outbound": "proxy"}
],
"final": "proxy"
}
}
Rule matchers: domain, domain_suffix, domain_keyword, domain_regex, ip_cidr, source_ip_cidr, protocol, network, port, source_port, process_name, inbound.
DNS
Split DNS with caching:
{
"dns": {
"servers": [
{"tag": "remote", "address": "tls://8.8.8.8:853", "detour": "proxy"},
{"tag": "local", "address": "223.5.5.5:53"}
],
"rules": [
{"domain_suffix": ["cn"], "server": "local"}
],
"final": "remote"
}
}
Tailscale Integration
{
"outbounds": [
{
"type": "tailscale",
"tag": "tailnet",
"auth_key": "tskey-auth-...",
"hostname": "my-node",
"state_dir": "tailscale"
}
]
}
Features: DERP relay + direct UDP, NAT traversal, MagicDNS short names, network change detection, path health monitoring.
Build
# Standard
go build -o mini-sing .
# With gVisor netstack (for tailscale netstack mode)
go build -tags with_gvisor -o mini-sing .
# With uTLS (for VLESS Vision)
go build -tags with_utls -o mini-sing .
# Android shared library
CGO_ENABLED=1 GOOS=android GOARCH=arm64 \
go build -tags with_gvisor,with_utls -buildmode=c-shared \
-o libminising.so .
# Cross-compile
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -tags with_gvisor -o mini-sing .
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -tags with_gvisor -o mini-sing.exe .
Run
mini-sing run -c config.json
Dependencies
Core:
github.com/sagernet/sing— sing-box base librarygithub.com/sagernet/sing-shadowsocks— Shadowsocks protocolgithub.com/sagernet/sing-vmess— VMess protocolgithub.com/sagernet/sing-tun— TUN interfacegithub.com/netkits-dev/tailnet— Tailscale protocol (local)github.com/netkits-dev/mini-dns— DNS resolver (local)github.com/miekg/dns— DNS library
Optional:
github.com/metacubex/utls— uTLS fingerprinting (build tag:with_utls)- gVisor netstack (build tag:
with_gvisor)
Description
Languages
Go
100%