Experience from V2Ray to Xray


Recently, I stumbled upon a new development from Xray through a recommended YouTube video. It’s called REALITY.

To be honest, I’ve been sticking with the architecture I adopted back in 2020, using Docker + Watchtower for automatic updates. It has been stable for two years, with the only modification being the addition of WARP support in April for accessing ChatGPT.

The last time I paid attention to Xray was during the V2Ray, Trojan, XRay saga in 2021. Curious about the latest developments, I visited the Xray project to find some clues among the various issues since the official website provided limited information.

After assessing the migration cost, I transitioned from V2Ray to Xray, maintaining the same overall architecture with Nginx as the proxy. The network tools changed, and I added new protocols such as VLESS, Vision, and gRPC.

What is Xray, and how is it related to V2Ray?

Xray and V2Ray share the same origin but diverged through successive iterations. For more details, refer to this article 🍉.

Why REALITY and Vision were created?

Tools like Trojan, representing TLS communication, have a problem known as TLS in TLS, creating a “nesting” of encryption layers that might exhibit certain statistical features. For a detailed analysis, check this discussion under the “Life and Death of 5 packets” section.

To address this, RPRX initiated the Trojan-killer project, aiming to validate the “nesting” of encryption layers.

What are XTLS, Vision, and REALITY? How do they work?

XTLS was an early solution to the TLS in TLS issue, requiring modifications to the TLS/uTLS official library. Although its maintainability is questioned, the approach is conceptually sound.

Vision can be considered a stable version of XTLS, also designed to address the TLS in TLS problem. It is now referred to as flow control and uses the label xtls-rprx-vision.

The workings of XTLS and Vision were previously discussed 👉 V2Ray, Trojan, XRay.

REALITY aims to further eliminate server TLS fingerprint features and address SNI blocking issues. Its operational principles are scattered across various issues, and by analyzing the project code, I provided a simplified explanation of how REALITY works.

In essence, REALITY relies on disguising itself to deceive inspectors. It obtains a normal Server Hello packet during TLS handshake from reputable websites like Apple or Bing. It then interacts with the client using this normal handshake packet, containing additional verification content. The process involves:

  1. The server requests a normal TLS handshake Server Hello packet from legitimate websites like Apple or Bing.
  2. Using this normal handshake packet, the server interacts with the client, incorporating its own constructed authentication content.
  3. As the packet content is modified, the client cannot directly process this Hello packet. It requires additional validation to proceed with communication.

From a feature perspective, this entire process appears like interacting with major websites. The design cleverly utilizes the handshake characteristics of well-known websites while adding its authentication elements. The TLS handshake process was previously explained 👉 Trojan Shared 443 Port Scheme.

In summary, REALITY’s design approach is indeed quite innovative!

Relevant GitHub Issues:

Obtaining Disguised Packets

Communication Verification

Client MITM

What might be the downsides of REALITY?

Firstly, the lack of support from compatible tools could be a drawback. User-friendliness is crucial for widespread adoption, and currently, there is limited support for various tools.

Secondly, protocol refinement is essential. While the approach seems reasonable, the disguised behavior itself may introduce new features. This remains unverifiable and needs validation over time.

Additionally, there’s a performance consideration. The additional step of the server fetching a handshake packet from Apple or other websites incurs network overhead. However, this aspect is subject to optimization, as recent messages suggest caching implementation.

Lastly, a reported issue mentioned DNS concerns. Although the interaction is disguised as traffic from major websites, the IP address is still visible. The sudden increase in traffic to certain domains like Apple or Bing from a specific IP could potentially be a new feature. This, too, remains unverifiable and needs further validation over time.

As it’s a fresh development, I believe continued observation is necessary. Innovation is always required for new possibilities 👏.

My Choice

The selection criteria remain consistent: Security > Stability > Speed.

The final tool choices are:

  1. V2Ray => Xray
  2. ClashX => Clash.Meta (Client configuration compatible)

Protocol choices are:

  1. VLESS+Vision+TLS (default, newly added)
  2. Trojan+TCP+TLS (previously retained)
  3. VLESS+gRPC+TLS (newly added)
  4. VMess+WebSocket+TLS+CDN (emergency, previously retained)

To be honest, I’ve had no issues with Trojan in the absence of using a network. However, this transition is an opportunity to experience new tools and address potential risks:

  1. TLS in TLS feature: Using Vision, i.e., xtls-rprx-vision
  2. Client TLS fingerprint: ClashX does not support Vision (VLESS), so I migrated to Clash.Meta, which comes with client-fingerprint
  3. Server TLS feature: REALITY is not currently in use; if needed later, the migration cost in my current architecture is low.

Compared to the 2020 scheme, the new plan has not changed significantly. It still relies on Nginx’s SNI routing architecture, with inter-container communication now using Unix Socket. Fallback is extensively utilized for multi-protocol coexistence.

graph LR
A["Client"] -->|HTTPS Request| B("Nginx")
A["Client"] -->|HTTPS Request| B0("CDN")
B0-->|Only White List \n and No TLS|B
B -->C{"dispatch"}
C -->|SNI Socket|D["VLESS+Vision+TLS"]
C -->|SNI Socket|E["Trojan+TCP+TLS"]
C -->|SNI Socket|F["Nginx Web No TLS"]
C -->|SNI Socket|J["Other Services"]
D -->|Fallback|F
E -->|Fallback|F
F -->|Path Socket|G["VLESS+gRPC"]
F -->|Path Socket|H["VMess+WebSocket"]
F -->|Fallback|I["Default Page"]
J -->|Socket|J0["PHP"]
J -->|Socket|J1["GO"]
J -->|Socket|J2["..."]

Various combinations can be referenced in the lxhao61/integrated-examples project, which aligns well with my current setup. Performance optimization varies, adjust as needed.

Let’s run some tests 🏃!

The speed test results were unexpected. VLESS+gRPC+TLS being the slowest surprised me; the speed was similar in Multi and Single modes, possibly due to link reuse issues 🤔️. VLESS+Vision+TLS and Trojan+TCP+TLS showed minimal differences, as expected. VMess+WebSocket+TLS+CDN performed adequately, considering it’s for emergency use 🚑.


My personal conclusion remains unchanged: Currently, protocols based on TLS are the future direction, and “network neighbors” continue to be the biggest risk.

While TLS-based solutions face issues like TLS in TLS, client fingerprints, and server features, it’s encouraging to see many people contributing to this field and actively working to address these problems.

During this process, new protocols and tools emerge, but it’s essential not to invest too much effort in protocol experimentation. If your current protocol is not disrupted, there’s no need to pursue others. Stay informed and attentive.

Our goal is to freely access internet resources, obtain the content we want, not to focus on the transport tool itself. Choosing a protocol should be akin to choosing a means of travel, aiming to experience the journey rather than fixating on the vehicle.