本記事では REALITY と XTLS Vision を「ハンドシェイク」と「転送」の2段に分けて解説します。REALITY がターゲットサイトから証明書チェーンを取得してハンドシェイクを完了する仕組み、認証されなかったアクセスがどこへ転送されるのか。XTLS Vision が TLS レコードを識別してそのまま転送する仕組み、どの層の暗号化を省いているのか。読み終えると、自分のノードにどの組み合わせが適しているか、CDN 経由・WebSocket 転送・v2fly コアといった構成でなぜ使えないのかが判断でき、v2rayN と v2rayNG で REALITY の各フィールドと flow パラメータを正しく入力できるようになります。
結論:片方はハンドシェイク、片方は転送層を変える
REALITY は VLESS における転送セキュリティ層の実装方式のひとつで、作用するのはハンドシェイク段階です。サーバーは自前のドメイン証明書を保持せず、ターゲットサイト(dest)から証明書チェーンを取得してハンドシェイクに使います。クライアントは公開 CA によるサーバー検証を行わず、設定にあらかじめ埋め込んだ公開鍵で本人確認を行います。検証を通過しなかったアクセスはそのまま dest へ転送され、ターゲットサイトの実際のページと実際の証明書チェーンが見えます。
XTLS Vision が作用するのはハンドシェイクの後です。HTTPS トラフィックをプロキシする場合、クライアントと目的のサイトの間にはもともと TLS が1層あります。XTLS は、クライアントが外側のハンドシェイクを終えたあと、内側の TLS レコードを外側のレコード層に詰め込んで二重に暗号化するのをやめ、すでに暗号化済みのレコードをそのまま転送します。サーバー側もそれを識別して同じくターゲットサイトへそのまま転送します。省いているのは重複した1層であって、唯一の1層ではありません。
どちらも Xray コアで実装されており、単独でも併用も可能です。VLESS + TCP + REALITY + flow=xtls-rprx-vision は現在サーバー側でよく使われる構成です。REALITY だけを有効にして flow を設定しない場合、ハンドシェイク段階の偽装効果は変わりませんが、大流量時には暗号化・復号の CPU コストを1回分余計に払うことになります。
TLS ハンドシェイク段階:遅延とフィンガープリントはどこで生じるか
TLS 1.3 のフルハンドシェイクには1往復が必要で、セッション再開なら 0-RTT も可能です。ハンドシェイクのメッセージに含まれる SNI、暗号スイートの一覧、拡張の順序、鍵共有グループが組み合わさってクライアントのフィンガープリントを形成します。サーバーが返す証明書チェーン、署名アルゴリズム、セッションチケットはサーバー側のフィンガープリントになります。どれかひとつでも「一般的な HTTPS サイト」と食い違えば、区別の手がかりになりえます。
従来の自前ノードでは、独自ドメインで証明書を取得するか、自己署名証明書を使うのが一般的でした。前者はドメインと証明書更新のコストがかかり、後者は証明書チェーンが不完全になりやすく、SNI と証明書が一致しないことも多く、適切なフォールバック設定がないと簡単に見破られます。
| 観察ポイント | 自己署名証明書 + フォールバック | REALITY |
|---|---|---|
| サーバーが提示する証明書 | 自己署名証明書のため、ブラウザーに信頼されない旨の警告が出る | ターゲットサイトの実際の証明書チェーン |
| SNI と証明書の一致 | 不一致が多い | 一致 |
| 未認証で 443 番ポートにアクセスした場合 | フォールバック設定次第で、プロキシであることが露呈しうる | dest へ転送され、実際のページが返る |
| クライアントの本人確認方式 | 証明書チェーンによる検証、または検証のスキップ | 事前共有した公開鍵 + X25519 鍵交換 |
| ドメインと証明書のコスト | ドメインが必要で、証明書の更新も要る | 独自ドメインと証明書は不要 |
表の違いはハンドシェイクの最初の数メッセージに集中しています。REALITY の狙いは、これらのメッセージを「そのターゲットサイトへ直接アクセスした場合」と区別できないようにすることであり、トラフィックを隠すことではありません。トラフィック自体は標準の TLS のままで、レコード形式・バージョン番号・拡張は通常の HTTPS と一致し、証明書の取得元と検証方法だけが別の仕組みに置き換わっています。
REALITY:実在サイトの証明書チェーンを借りる
サーバー側で REALITY を設定するには4つの重要な値が必要です。dest(ターゲットサイト。例: www.python.org:443)、serverNames(dest と一致するドメインの一覧)、privateKey(サーバー秘密鍵。xray x25519 コマンドで生成)、shortIds(クライアントを区別するための短い ID の一覧)です。クライアント側は対応する publicKey、serverName、shortId を保持し、この3つがサーバー側と1対1で対応します。
接続を受け取ると、サーバーは秘密鍵と ClientHello 内の一時公開鍵で X25519 演算を行い、期待どおりの結果が出ればプロキシとして処理します。結果が出なければ接続全体を dest へ転送し、ターゲットサイトが通常どおり応答します。これがターゲットサイト選びの基準でもあります。実在していること、TLS 1.3 と X25519 に対応していること、通常の Web ページがあること、できれば HTTP/2 にも対応していること。そうして初めてフォールバック時の挙動が自然になります。
REALITY + VLESS TCP
推奨独自ドメインと証明書が不要で、443 番ポート1つがハンドシェイクの偽装とプロキシを同時に担います。未認証のアクセスにはターゲットサイトの実際のページが見えます。
向いている環境:直接接続、単体での自前構築、能動的探査への耐性が必要な場合
ドメイン証明書 + TLS + WebSocket
設定が分かりやすく、証明書は定期的な更新が必要です。転送層に WebSocket を重ねられるため、後から CDN 経由に組み込みやすい構成です。
向いている環境:ドメインを保有済みで、標準的な 443 番の TLS を使いたい場合
自己署名証明書 + WebSocket + CDN
オリジン IP は CDN で隠せますが、証明書チェーンが不完全になりやすく、フォールバックを丁寧に設定しないとハンドシェイクの特徴が目立ったままになります。
向いている環境:オリジン IP を隠したい、設定手順が増えても許容できる場合
結論:CDN を使うかどうかを先に決め、それからハンドシェイク方式を選ぶ
REALITY と XTLS Vision はいずれも RAW(TCP)の直接接続に依存しているため、CDN 経由にするとどちらも併用できません。その場合は「ドメイン証明書 + WebSocket」の組み合わせに戻すことになります。直接接続と決めたなら、REALITY はドメインを買わなくても実際の証明書チェーンを手に入れられる方式です。
制約もはっきり書いておきます。dest と serverNames は必ず一致させる必要があり、間違えるとハンドシェイクは完了してもページが証明書エラーになります。shortId と publicKey は必ずペアで配布する必要があり、クライアント側で誤ると接続できません。WebSocket、gRPC、HTTP/2 などの転送方式は併用できないため CDN は使えません。v2fly コア(V2flyNG)は VLESS の対応は充実していますが、REALITY 関連のフィールドを解釈しないため、REALITY ノードは Xray コア上で動かす必要があります。v2rayNG に内蔵されているのは Xray コアです。
XTLS Vision:ハンドシェイク後に1層分の暗号化を省く
HTTPS をプロキシするときのデータ経路はこうです。クライアントと目的のサイトの間に TLS が1層、クライアントとプロキシサーバーの間にもう1層の TLS があります。外側の TLS はクライアントからプロキシサーバーまでの区間を保護するためのものです。内側の TLS レコードはクライアントが送り出す時点ですでに一度暗号化されており、通常の実装はそれを普通のバイト列として扱い、外側のレコード層でもう一度暗号化してしまいます。
XTLS のやり方は、外側のハンドシェイクが完了したあとに最初のアプリケーションデータを識別するというものです。それが TLS ClientHello であれば、この接続上のデータはそれ自体が暗号化されていると判断し、外側での再暗号化を行わずそのまま転送します。TLS ではないトラフィック、たとえば平文 HTTP の場合は、従来どおり暗号化して転送します。判断材料は最初のパケットの中身で、特別なスイッチは必要ありません。
Vision は XTLS の改良実装で、初期の xtls-rprx-direct が一部の環境で抱えていた互換性の問題を解消し、UUID 検証と初回パケットの識別を追加しています。設定上は flow フィールドとして現れます。サーバー側の clients に "flow": "xtls-rprx-vision" と書き、クライアント側の outbound にも同じ値を設定します。両端で値が一致しないと接続に失敗するか、通常の VLESS にフォールバックします。
- メリット:回線をフルに使うダウンロード時に共通鍵暗号の暗号化と復号を1回分省けるため、CPU 使用率が下がります。ソフトウェアルーターや低消費電力機器で最も効果が出ます。
- メリット:大流量の場面でスループットが素の TCP に近づき、初回パケットが直通するため遅延の揺らぎも小さくなります。
- デメリット:TLS トラフィックにのみ有効で、平文 HTTP は通常の暗号化経路のままです。
- デメリット:両端とも flow を設定する必要があり、クライアント側のコアが Vision に対応している必要があります。
- デメリット:REALITY と同様に RAW 転送しか使えず、WebSocket や gRPC は併用できません。
設定の要点:鍵、flow、フォールバックの確認
鍵ペアを生成する
サーバー側で xray x25519 を実行し、秘密鍵と公開鍵を取得します。秘密鍵はサーバー側の設定にのみ残し、公開鍵はノード情報と一緒にクライアントへ配布します。
inbound を記述する
inbound では VLESS + TCP で 443 番をリッスンし、streamSettings.security を reality に設定して、dest、serverNames、shortIds、privateKey を記入します。
クライアントに公開鍵を設定する
v2rayN のノード編集でアドレス、ポート 443、UUID を入力し、flow で xtls-rprx-vision を選び、publicKey、serverName、shortId を記入します。
フォールバックの挙動を確認する
ブラウザーでそのドメインとポートに直接アクセスし、dest サイトのページが表示されれば正常です。証明書エラーが出る場合は dest と serverNames が一致していません。
コアのログを確認する
接続に失敗するときはログの REALITY、invalid user、flow といったキーワードを確認し、まず公開鍵と shortId がペアで配布されているかを確かめます。
{
"port": 443,
"protocol": "vless",
"settings": {
"clients": [
{ "id": "8f7a2c1e-5b3d-4a9f-9c21-7d6e4b0a1f33", "flow": "xtls-rprx-vision" }
],
"decryption": "none"
},
"streamSettings": {
"network": "tcp",
"security": "reality",
"realitySettings": {
"dest": "www.python.org:443",
"serverNames": ["www.python.org"],
"privateKey": "aP3nQ8vK2sL7dF9xR4tY6uW1zC5bN0mJ2hG8kD3sQ1E",
"shortIds": ["6ba85179e30d4fc2"]
}
}
}
この抜粋では dest と serverNames が同じドメインを指しており、これが REALITY で正常にハンドシェイクできる前提になります。shortIds は複数並べられ、クライアントごとに1つ使うため、クライアントを替えるたびにサーバー鍵を生成し直す必要はありません。クライアント側の publicKey は上記の秘密鍵と対になる公開鍵であり、別のランダム値ではありません。間違えると接続できません。
よくある質問:探査、互換性、コアによる違い
第三者が 443 番ポートに直接アクセスすると何が見えるのか
正しい公開鍵を伴わない接続は dest サイトへ転送され、そのサイトの実際のページと証明書チェーンが見えます。前提として serverNames と dest が一致し、フォールバックの経路が壊れていない必要があります。
REALITY ノードに CDN を挟めるのか
挟めません。REALITY と XTLS Vision はいずれも RAW(TCP)の直接接続に依存しており、CDN が扱える WebSocket、gRPC、HTTP/2 といった転送方式は併用できません。「ドメイン証明書 + WebSocket」の組み合わせに戻す必要があります。
クライアントに flow を設定したのに接続できない
まずサーバー側の clients にも同じ flow が書かれているかを確認し、次にクライアントが Xray コアを使っているかを確認します。v2fly コアは REALITY のフィールドを解釈しないため、ノードのパラメータに入力しても反映されません。
REALITY だけを有効にして Vision を使わない構成は可能か
可能です。REALITY はハンドシェイクの偽装を、Vision は転送層の二重暗号化を解決するもので、両者は独立しています。flow を設定しなくてもハンドシェイクの効果は変わりませんが、大流量時には CPU 使用率がやや高くなります。
dest は必ず大手サイトを選ぶ必要があるのか
TLS 1.3 と X25519 に対応し、通常の Web ページがあり、自分のノードとは別のドメインのサイトであれば問題ありません。dest と serverNames は必ず一致させ、自分のドメインは使わないでください。API のデータしか返さないドメインも避けます。
構成パターン:直接接続、CDN、コアの選択
単体で自前構築し、独立した IP があり、オリジンサイトを隠す必要がない場合:VLESS + TCP + REALITY + xtls-rprx-vision。443 番ポート1つがハンドシェイクの偽装と転送の最適化を同時に担い、ドメインも証明書も不要で、設定項目も最小限です。クライアントは v2rayN でも v2rayNG でも構いません。
すでにドメインと証明書があり、CDN を使いたい場合:VLESS + WebSocket + TLS。この場合は REALITY も Vision も使えず、最適化の方向はハンドシェイクや転送層ではなく、CDN 側と転送方式の選択になります。2つの路線の分かれ目は「オリジン IP を公開するかどうか」です。まずこの問いに答えてからでないと、後続のパラメータは意味を持ちません。
結論:転送方式を先に決め、ハンドシェイク方式は後から決める
CDN が必要な場合、REALITY と Vision は選択肢に入りません。直接接続と決めたうえで、「独自ドメインを維持するかどうか」で二択になります。維持したくないなら REALITY、すでにドメインがあり標準的な TLS に慣れているならドメイン証明書です。どちらの方式もハンドシェイクの往復は 1-RTT で、差は遅延ではなく証明書の取得元と探査時の特徴にあります。