[Android 16][XRay/VLESS WS+TLS] IPv6 endpoint causes TLS handshake failure with no IPv4 fallback; config edits are discarded
Describe the bug
AmneziaVPN reports Connected for an imported VLESS WebSocket + TLS profile,
but no traffic passes.
The endpoint domain is proxied by Cloudflare and has both A and AAAA records. AmneziaVPN selects an IPv6 address. The bundled Xray core repeatedly reports:
transport/internet/websocket: failed to dial to [<CLOUDFLARE_IPV6>]:443
> remote error: tls: handshake failureThe connection does not reach the server-side VLESS/Xray service. The same original VLESS profile works in Hiddify and Happ on the same Android device and network. It also works from Hiddify on macOS.
Steps to reproduce
- Import a VLESS URI whose endpoint is a Cloudflare-proxied domain with A and AAAA records.
- Use
type=ws,security=tls, a validsni, WebSockethost, path, UUID and port 443. - Disable both application and site split tunneling.
- Connect on Android 16.
- Observe that the UI changes to
Connected, but Internet access is absent. - Export the AmneziaVPN log.
Actual behavior
- Android VPNService, TUN, tun2socks and Xray start.
- The UI reports
Connectedbefore the outbound TLS session succeeds. - The endpoint is resolved to IPv6.
- Xray repeatedly receives
remote error: tls: handshake failure. - No IPv4 fallback occurs.
- The server-side Xray journal receives no matching connection.
Confirmed workaround
A new VLESS URI was imported with a numeric Cloudflare IPv4 address in the endpoint position. The original domain was retained in TLS SNI/serverName and the WebSocket Host header. Traffic started working immediately.
Conceptual difference:
Failing: vless://<UUID>@<DOMAIN>:443?...&sni=<DOMAIN>&host=<DOMAIN>...
Working: vless://<UUID>@<CLOUDFLARE_IPV4>:443?...&sni=<DOMAIN>&host=<DOMAIN>...No server-side change was required.
Configuration persistence problem
As a diagnostic attempt, the following was added to streamSettings:
"sockopt": {
"domainStrategy": "UseIPv4"
}The editor initially displayed the modified JSON, but after the first connection attempt the settings returned to their defaults. The runtime log still showed the IPv6 endpoint. There is no warning that the field is not persisted or applied.
This appears related to, but is not identical to, #2958. That report concerns regeneration of a managed server configuration. This case concerns an imported client VLESS profile and its native Xray configuration on Android.
Expected behavior
- Use IPv4 fallback when the selected IPv6 endpoint cannot complete TLS.
- Do not report
Connectedsolely because the Android VPN interface started. - Preserve supported manual native-Xray edits, or clearly mark unsupported fields as transient/read-only.
- Provide a persistent IPv4/IPv6 endpoint strategy for imported VLESS profiles.
Environment
- AmneziaVPN: 5.0.1.5, commit
7d4f3e0 - Android: 16, SDK 36
- Device: Redmi 23129RN51X
- ABI: armeabi-v7a, armeabi
- Bundled Xray core: 26.6.27
- Transport: VLESS + WebSocket + TLS, port 443
- Endpoint: Cloudflare-proxied domain with A and AAAA records
- Split tunneling: disabled for applications and sites
- Android Always-on VPN: disabled
- Android block connections without VPN: disabled
Log files
Attach AmneziaVPN-public-sanitized.log from this draft package. It contains
only the minimal connection sequence and has no VPN UUID, domain, VPS address,
profile identifier, authentication keys or user public IP.
Related issues
- #2509: request for client-side domain strategy
- #2704: Android Xray/uTLS failure with a different transport/security case
- #2958: Xray configuration regeneration/state mismatch
Source: amnezia-vpn/amnezia-client