Trojan over WebSocket: tunnel establishes but upload stalls at 0 — same profile works on upstream sing-box
Summary
With hiddify-core v4.1.0, a Trojan + TLS + WebSocket outbound connects successfully but carries almost no data: download trickles, upload sits at 0, and any speed test fails. The identical profile against the identical server works normally on upstream sing-box (tested 1.10.7 and 1.13.14) and on Xray-based clients.
Reproduced on two unrelated client networks (Starlink and a mobile carrier), on iOS, in two different apps that both embed hiddify-core — including the stock Hiddify app. That rules out our own integration and the client's link.
Environment
- hiddify-core v4.1.0 (latest release), built as HiddifyCore.xcframework, iOS Network Extension
- Also reproduced with the stock Hiddify iOS app (same core family), so this is not specific to our build
- Server: Hiddify Manager 12.3.3, Xray 26.3.27 behind HAProxy
- Outbound: trojan, transport.type = ws, TLS with alpn: ["http/1.1"], uTLS chrome
What happens
The tunnel reports connected. sing-box logs no error at all for the outbound at log.level: warn — nothing is refused. Server-side accounting shows only ~13 KB transferred for the whole session, and the app's speed test errors out immediately. The stock Hiddify app shows download 56 / upload 0 on the same profile.
Comparison on one profile and one server
| client / core |
result |
| upstream sing-box 1.10.7 (SOCKS inbound) |
works — 1.33 MB/s up, 1.39 MB/s down |
| upstream sing-box 1.13.14 (SOCKS inbound) |
works — 810 KB/s up |
| Streisand (upstream sing-box) |
works |
| Happ, INCI (Xray) |
work |
| stock Hiddify app (hiddify-core) |
upload 0 |
| our app (hiddify-core v4.1.0) |
upload 0 |
Upload was measured with a 3–5 MB POST to https://speed.cloudflare.com/__up through the proxy.
Outbound (redacted)
{
"type": "trojan",
"server": "",
"server_port": 443,
"password": "",
"tls": {
"enabled": true,
"server_name": "",
"utls": { "enabled": true, "fingerprint": "chrome" },
"insecure": true,
"alpn": ["http/1.1"]
},
"transport": {
"type": "ws",
"path": "/",
"early_data_header_name": "Sec-WebSocket-Protocol",
"headers": { "Host": "" }
}
}
The same JSON, unmodified, is what upstream sing-box accepts and runs successfully.
Ruled out
- Server — three transport variants (raw IP, sslip.io, domain) all return 204 and full throughput from an independent host; the subscription's path, password and SNI match the Xray inbound exactly; MSS clamp (1200) is in place.
- Account — active, 30-day package, enable: 1.
- Client network — reproduced on Starlink and on a mobile carrier, with the same split between cores.
- Our config pipeline — the outbound taken verbatim from the config our app generates works when handed to upstream sing-box.
- Core version — v4.1.0 is the newest release.
Known caveat in our measurements
Our upstream comparisons run with a SOCKS inbound on a Linux host, while the failing cases run with a TUN inbound on iOS. We did not isolate TUN-vs-core, since doing so would have meant reconfiguring the network stack on a production machine. We report this openly: the split is consistently "hiddify-core fails / upstream works", but TUN remains an uncontrolled variable, and if you can reproduce with a TUN inbound on both cores that would settle it.
Other transports on the same server
For context, on the same Hiddify Manager and the same client: gRPC, xHTTP, WebSocket-on-VLESS, ShadowTLS, TUIC and Hysteria2 all work. Trojan (every transport) and HTTPUpgrade-over-TLS do not. Trojan over WebSocket is the cleanest case to reproduce, which is why it is the subject of this report.
Trojan over WebSocket: tunnel establishes but upload stalls at 0 — same profile works on upstream sing-box
Summary
With hiddify-core v4.1.0, a Trojan + TLS + WebSocket outbound connects successfully but carries almost no data: download trickles, upload sits at 0, and any speed test fails. The identical profile against the identical server works normally on upstream sing-box (tested 1.10.7 and 1.13.14) and on Xray-based clients.
Reproduced on two unrelated client networks (Starlink and a mobile carrier), on iOS, in two different apps that both embed hiddify-core — including the stock Hiddify app. That rules out our own integration and the client's link.
Environment
What happens
The tunnel reports connected. sing-box logs no error at all for the outbound at log.level: warn — nothing is refused. Server-side accounting shows only ~13 KB transferred for the whole session, and the app's speed test errors out immediately. The stock Hiddify app shows download 56 / upload 0 on the same profile.
Comparison on one profile and one server
Upload was measured with a 3–5 MB POST to https://speed.cloudflare.com/__up through the proxy.
Outbound (redacted)
{
"type": "trojan",
"server": "",
"server_port": 443,
"password": "",
"tls": {
"enabled": true,
"server_name": "",
"utls": { "enabled": true, "fingerprint": "chrome" },
"insecure": true,
"alpn": ["http/1.1"]
},
"transport": {
"type": "ws",
"path": "/",
"early_data_header_name": "Sec-WebSocket-Protocol",
"headers": { "Host": "" }
}
}
The same JSON, unmodified, is what upstream sing-box accepts and runs successfully.
Ruled out
Known caveat in our measurements
Our upstream comparisons run with a SOCKS inbound on a Linux host, while the failing cases run with a TUN inbound on iOS. We did not isolate TUN-vs-core, since doing so would have meant reconfiguring the network stack on a production machine. We report this openly: the split is consistently "hiddify-core fails / upstream works", but TUN remains an uncontrolled variable, and if you can reproduce with a TUN inbound on both cores that would settle it.
Other transports on the same server
For context, on the same Hiddify Manager and the same client: gRPC, xHTTP, WebSocket-on-VLESS, ShadowTLS, TUIC and Hysteria2 all work. Trojan (every transport) and HTTPUpgrade-over-TLS do not. Trojan over WebSocket is the cleanest case to reproduce, which is why it is the subject of this report.