vless-core-cli
OpenWrt package for notfence/vless-core-cli — a standalone C client that connects to a VLESS, Trojan, VMess, Shadowsocks or SOCKS5 server and exposes a local SOCKS5 proxy.
Compared to Go-based cores it is very small and depends only on libopenssl,
which makes it suitable for devices with small flash and RAM.
Supported upstreams:
- VLESS (with
xtls-rprx-visionand VLESS Encryption), Trojan, VMess AEAD (alterId=0), Shadowsocks (AEAD and 2022) over TCP / WebSocket / gRPC / XHTTP / HTTPUpgrade with no security, TLS or Reality (Reality is not available for WebSocket and HTTPUpgrade). - Plain SOCKS5, optionally with username/password.
Files
| Path | Purpose |
|---|---|
/usr/bin/vless-core |
client binary |
/etc/init.d/vless-core |
procd init script |
/etc/config/vless-core |
UCI config |
Quick start
uci set vless-core.main.uri='vless://UUID@example.com:443?type=tcp&security=reality&sni=www.example.org&fp=chrome&pbk=PUBLIC_KEY&sid=SHORT_ID&flow=xtls-rprx-vision#server'
uci set vless-core.main.listen_port='1080'
uci set vless-core.main.enabled='1'
uci commit vless-core
/etc/init.d/vless-core enable
/etc/init.d/vless-core start
Check:
curl -x socks5h://127.0.0.1:1080 https://2ip.io
The SOCKS5 listener binds to 127.0.0.1 only. Use it with tun2socks, redsocks or anything
else that can talk to a SOCKS5 proxy. Logs go to logread.
UCI options
Section config vless-core 'main':
| Option | Default | Description |
|---|---|---|
enabled |
0 |
Start the service (1/0) |
uri |
– | vless://, vmess://, trojan://, ss:// or socks5:// upstream URI (required) |
listen_port |
1080 |
Local SOCKS5 port on 127.0.0.1 |
routing |
– | Optional routing rules, see below |
tls_mode |
strict |
Certificate verification: strict, insecure or tofu |
Always quote the URI in uci set: it contains &, # and ?.
The client serves exactly one upstream URI, so the init script runs a single instance.
URI examples
Reality + Vision:
vless://UUID@example.com:443?type=tcp&security=reality&sni=www.example.org&fp=chrome&pbk=PUBLIC_KEY&sid=SHORT_ID&flow=xtls-rprx-vision#reality
XHTTP + TLS:
vless://UUID@example.com:443?type=xhttp&security=tls&sni=example.com&path=%2Fxh&mode=auto#xhttp
WebSocket + TLS:
vless://UUID@example.com:443?type=ws&security=tls&sni=example.com&host=example.com&path=%2Fws#ws
gRPC + Reality:
vless://UUID@example.com:443?type=grpc&security=reality&serviceName=svc&sni=www.example.org&fp=chrome&pbk=PUBLIC_KEY&sid=SHORT_ID#grpc
HTTPUpgrade + TLS:
vless://UUID@example.com:443?type=httpupgrade&security=tls&sni=example.com&host=example.com&path=%2Fup#httpupgrade
Trojan (TLS by default, the whole userinfo is the password):
trojan://PASSWORD@example.com:443?sni=example.com#trojan
VMess (encryption is the body mode, scy is an alias; the base64 JSON form is accepted too):
vmess://UUID@example.com:443?type=ws&security=tls&sni=example.com&host=example.com&path=%2Fws&encryption=auto#vmess
Shadowsocks (SIP002, userinfo is base64url of method:password):
ss://BASE64URL_METHOD_PASSWORD@example.com:8388#ss
Upstream SOCKS5:
socks5://192.0.2.1:1080
Supported fp values: chrome, firefox, edge, random, randomized, qq
(there are no safari or ios fingerprints).
Routing
routing is a single string, fields separated by ;:
ENABLED;DEFAULT;LAN;action,type,value;action,type,value;...
| Field | Values |
|---|---|
ENABLED |
1 / 0 |
DEFAULT |
proxy / direct / block — used when no rule matches |
LAN |
1 / 0 — private IP ranges always go direct (checked before the rules) |
action |
proxy / direct / block |
type |
domain (exact), suffix (domain and subdomains), cidr, port (single or a-b) |
Rules are checked in order, first match wins. Up to 48 rules, 8191 characters total.
Domains are lowercase a-z0-9-_. without leading or trailing dot (ru, not .ru).
Example: everything through the proxy, .ru and .lan direct, SMTP and one subnet blocked:
uci set vless-core.main.routing='1;proxy;1;direct,suffix,ru;direct,suffix,lan;block,port,25;block,cidr,203.0.113.0/24'
uci commit vless-core
/etc/init.d/vless-core restart
Notes:
- Domain rules match when the client sends a hostname (
socks5h). For a bare IP the client tries to sniff the domain from the first packet, but only if domain/suffix rules exist. 8.8.8.8:53always goes through the proxy if no rule matched earlier, even withDEFAULT=direct.- A
directconnection is opened byvless-coreitself via the normal routing table. If your default route points into a tun device (tun2socks), direct traffic will loop back into it. The client has--route-control-port/--route-control-socketfor an external controller, they are not exposed in UCI.
TLS verification
tls_mode is passed to the client as VLESS_TLS_MODE:
strict— only verified TLS, no fallback (default). Forsecurity=tlsinstallca-bundle.insecure— never verify certificates.tofu— pin the certificate on first connection, later connections must match.
Reality client version
For Reality the client writes an Xray version (x.y.z, default 26.3.27) into the ClientHello
session ID. Override it with the XRAY_VER environment variable or --xray-version x.y.z,
for example if the server limits client versions with minClientVer / maxClientVer.
This is not exposed in UCI.
Build notes
Upstream's Makefile runs its test suite (clang sanitizers, a separate OpenSSL 3.5, Xray) and
an x86-64-only binary check, and hardcodes the output name vless-core-linux-amd64.
The package therefore does not use it: it compiles src/*.c directly with the SDK toolchain
and installs the result as /usr/bin/vless-core.
ML-KEM based features (VLESS Encryption, the X25519MLKEM768 key share) need OpenSSL 3.5 or newer.
Tested: OpenWrt SDK, musl x86-64, OpenSSL 3.5.9.
ToDo
luci-app-vless-core— LuCI web interface (someday).