V2Rayのサブスクリプション形式を解説:Base64・ネイティブJSON・共有リンクの変換
Base64サブスクリプション、ネイティブJSON設定、単一の共有リンクの構造の違いを整理し、変換時に保持すべき主要フィールドと適用範囲を解説します。
エンコード・コンテナ・プロトコルを区別する
V2Rayのサブスクリプションを扱う際、混同しやすいのが「エンコード形式」「設定コンテナ」「プロキシプロトコル」の3つの階層です。Base64はテキストエンコード方式の一つで、元のバイト列を転送しやすい文字列に変換します。JSONは構造化データ形式で、カーネルの完全な設定も、特定ノードのフィールドだけも保存できます。VMessやVLESSはプロキシプロトコルで、クライアントとサーバーが必要な情報を交換する方法を定めます。3者は同じ階層に属するものではなく、単純に置き換えられる関係でもありません。
一般的なサブスクリプションのレスポンスは、区切りの見えない長い文字列に見えますが、デコードすると複数行の共有リンクになることがあります。この場合、Base64は外側のラッパーにすぎず、実際にインポートされる内容はデコード結果に含まれています。別のタイプでは、ノード配列を含むJSONや、inbound・outbound・ルーティング・DNS設定を備えたカーネル設定全体が直接返されます。また、vmess://やvless://のリンクを1行ずつ返し、外側のエンコードを追加しない形式もあります。
形式を判別するときは、外側から内側へ確認します。まずHTTPレスポンスが通常のテキストかJSONかを見極め、通常のテキストならBase64デコードが必要かを判断し、最後にデコード後の内容が共有リンク一覧、単一ノードのオブジェクト、完全な設定のどれに当たるかを確認します。ファイル拡張子、文字列の長さ、サブスクリプションURLの末尾だけでは、内容の種類を確実に判断できません。
Base64サブスクリプションの見分け方とデコード
従来型のBase64サブスクリプションでは、複数の共有リンクを改行で連結し、その全体をエンコードします。クライアントがサブスクリプションを更新すると、レスポンス本文を取得してデコードし、改行で項目を分割したうえで各URIを解析します。改行にはLFとCRLFの両方が使われるため、適切な解析では両方に対応し、先頭・末尾の空白と空行を無視する必要があります。
標準Base64の文字セットは英字の大文字・小文字、数字、プラス、スラッシュで構成され、末尾にパディングとして1個または2個のイコールが付くことがあります。URLセーフ版ではプラスとスラッシュがハイフンとアンダースコアに置き換わり、末尾のパディングが省略される場合もあります。生成側によっては本文の先頭に不可視マーカーを付けたり、余分な空白を含めたりします。変換ツールが一方の文字セットしか受け付けないと、サブスクリプション自体は有効でも「デコードに失敗しました」と表示されることがあります。
デコード後の結果は、通常、次のような行単位の構造になります。ここでは構造の例を示しており、ドメインには予約済みのサフィックスを使っているため、接続可能なサービスを示すものではありません。
vless://[email protected]:443?encryption=none&security=tls&type=ws&host=edge.invalid&path=%2Fconnect#Office
vmess://eyJ2IjoiMiIsInBzIjoiVGVzdCIsImFkZCI6Im5vZGUuaW52YWxpZCJ9
1行目はパラメータをURI内に含むVLESS共有リンクです。2行目はvmess://の後にもエンコードされた文字列が続いており、単一ノードのJSONを確認するにはさらにデコードが必要です。つまり、外側のサブスクリプションと単一のVMess共有リンクが、それぞれ1回ずつBase64を使うことがあります。サブスクリプションの外側だけをデコードしても、ノードのフィールドまで解析できたことにはなりません。また、連続してデコードする際に、通常のUUID・パス・備考を新たなエンコード層と誤認しないよう注意が必要です。
ブラウザーやコマンドラインツールでデコードする場合は、テキストの文字コードにも注意します。ノードの備考は通常UTF-8を使用します。ツールが別の文字コードとして処理すると、日本語の備考が文字化けすることがありますが、サーバーアドレス、ポート、UUIDには影響しない場合があります。文字化けをノードフィールドの削除で解決してはいけません。UTF-8を維持し、再エンコードする前に改行とURIのパーセントエンコードが変更されていないことを確認してください。
ネイティブJSON設定の階層と範囲
ネイティブのV2RayまたはXray JSON設定は、通常、カーネルにそのまま渡して実行できる構造を記述します。リモートノードだけでなく、ローカルの待受ポート、DNS、ログ、ルーティングルール、ポリシー、複数のoutboundを含むこともあります。以下は簡略化した構造例です。
{
"inbounds": [
{
"listen": "127.0.0.1",
"port": 10808,
"protocol": "socks",
"settings": {
"udp": true
}
}
],
"outbounds": [
{
"tag": "proxy",
"protocol": "vless",
"settings": {
"vnext": [
{
"address": "node.invalid",
"port": 443,
"users": [
{
"id": "11111111-2222-3333-4444-555555555555",
"encryption": "none"
}
]
}
]
},
"streamSettings": {
"network": "ws",
"security": "tls",
"wsSettings": {
"path": "/connect",
"headers": {
"Host": "edge.invalid"
}
}
}
}
]
}
この種の設定では、inboundsがローカルアプリからプロキシへ接続する方法を定め、outboundsがクライアントから出ていくトラフィックの処理方法を記述します。routingはトラフィックをどのoutboundへ送るかを決め、dnsはドメイン名の解決を制御します。共有リンクは通常、特定のリモートoutboundに必要な情報しか含まず、ローカルの待受、複雑な振り分け、複数outboundの関係、DNSルールまで完全に表現することはできません。
「サブスクリプションJSON」を独自オブジェクトとして設計し、トップレベルにノード配列、更新日時、グループ名などを含めるサービスもあります。このJSONはカーネルのネイティブ設定ではなく、フィールド名と階層は生成側とクライアントの取り決めで決まります。中括弧が見えたからといって、そのままカーネルへ渡してはいけません。inboundsやoutboundsなどの主要構造が存在するか、またはクライアントがそのサブスクリプション構造に明確に対応しているかを先に確認してください。
v2rayNはノード、サブスクリプション、ルーティングを管理し、画面上の設定に基づいてカーネル実行用の設定を生成できます。Androidではv2rayNGがXrayカーネル、v2flyNGがv2flyカーネルを使用します。3つとも一般的な共有リンクを認識できる場合でも、対応するトランスポートパラメータはカーネルのバージョンによって異なることがあります。完全なJSONをあるクライアントから別のクライアントへコピーする場合、ローカルの待受、ログの保存先、プラットフォーム固有の設定は通常、改めて確認が必要です。
形式変換で保持すべき主要フィールド
サブスクリプション一覧から共有リンクを作成する場合、共有リンクからoutbound JSONを生成する場合、または完全なJSONを単一ノード情報へ分解する場合に最も重要なのは、フィールドの対応関係を定義することです。サーバーへの接続には、アドレスとポートだけでなく、認証情報、トランスポート層、セキュリティ層、および関連パラメータも必要です。
- サーバーアドレスとポート:設定で固定アドレスが明示されていない限り、ドメイン名はそのまま保持します。名前解決で得られた一時的なアドレスに先回りして置き換えると、後のDNS更新を回避してしまう可能性があります。
- ユーザー認証フィールド:VMessとVLESSではUUIDを使うことが一般的です。コピー、デコード、再エンコードの過程では文字列を完全に保持し、数値として扱ったり、ハイフンを削除して独自の形式に変えたりしてはいけません。
- トランスポート:TCP、WebSocket、gRPCなどの方式はサーバー側と一致している必要があります。サーバーとポートだけを残してトランスポート種別を失うと、クライアントは通常の既定方式で接続し、元の設定と一致しない結果になります。
- トランスポートの追加パラメータ:WebSocketのパスとHost、gRPCのサービス名などは接続の一部です。空文字列、ルートパス、フィールドの欠落が異なる意味を持つ場合があるため、変換時に一括して同じ扱いにしないでください。
- セキュリティ層のパラメータ:TLSの有効・無効、サーバー名、関連オプションは正確に対応付けます。サーバーアドレスとセキュアハンドシェイクに使う名前は異なることがあるため、似て見えるからといって一方で他方を上書きしてはいけません。
- ノードの備考:備考は接続を決めるものではありませんが、ノードの識別やグループ分けに影響します。UTF-8で保存し、URIフラグメント内では正しくパーセントエンコードしてください。
完全なJSONを共有リンクへ変換すると、ルーティングとDNSの情報が特に失われやすくなります。設定にproxy、direct、blockの3つのoutboundがあり、ルールによってドメインごとに送信先を振り分けているとします。このときproxyに対応する単一リンクをエクスポートしても、保持できるのはそのリモート接続だけです。リンクを再インポートしても、残り2つのoutboundやルールの関係が自動的に再構築されることはありません。
逆方向の変換にも限界があります。共有リンクから1つのリモートoutboundは生成できますが、ローカルの受信ポート、ログレベル、DNSサーバー、ルーティングモードはクライアント側で補う必要があります。v2rayN、v2rayNG、v2flyNGは通常、それぞれの既定設定とノード情報を組み合わせるため、同じリンクを異なる端末で正常にインポートできても、最終的に生成される完全な実行設定が項目ごとに一致するとは限りません。
サブスクリプションのインポート失敗を段階的に切り分ける
「サブスクリプションを解析できない」「インポート後にノードがない」といった場合は、取得、デコード、分割、プロトコル解析、接続確認の順に原因を切り分けます。すべてのフィールドを一度に変更すると本当の原因が隠れ、利用できる設定まで壊すおそれがあります。
第1段階:取得したものがサブスクリプション本文か確認する
サブスクリプションURLは、認証の失効、ネットワークのリダイレクト、サーバーエラーによって通常の案内ページを返すことがあります。案内ページもテキストですが、Base64でもJSONでもありません。レスポンスの先頭にHTMLタグ、エラー説明、ログイン案内がないかを確認し、クライアントからのリクエストで得られる内容が、ブラウザー環境で必要な認証方式と一致しているかも確認してください。
第2段階:外側のデコードが必要か判断する
本文がBase64文字で構成されている場合は、標準形式とURLセーフ形式の両方を試してデコードします。デコード後には、認識可能なリンクのプレフィックスかJSON構造が現れるはずです。結果がなお規則性のないバイナリデータなら、繰り返しデコードしてはいけません。まずレスポンスが圧縮されていないか、文字コードが正しいか、コピー時に文字が欠落していないかを確認します。
第3段階:行区切りと不可視文字を確認する
デコード結果に複数のリンクがあるのに1ノードしかインポートされない場合、改行が正しく認識されていないことがよくあります。リンク間がLF、CRLFのどちらで区切られているか、またはリテラル文字としてエスケープされていないかを確認します。ファイル先頭の不可視マーカーによって、最初のリンクのプレフィックスを認識できないこともあります。除去するのは明確な空白とマーカーだけにし、URI内部のパーセントエンコードは削除しないでください。
第4段階:プロトコルフィールドとクライアントの対応状況を確認する
リンクは認識されるものの、パラメータがサポートされていないと表示される場合、共有形式に現在のクライアントまたはカーネルのバージョンが未対応のフィールドが含まれている可能性があります。まず使用環境に適したv2rayN、v2rayNG、v2flyNGへ更新し、元の設定と照らし合わせてトランスポート、セキュリティ層、追加パラメータを確認します。「インポート成功」を優先して未知のパラメータを無作為に削除してはいけません。削除したフィールドが、サーバー接続に必要な条件である可能性があるためです。
第5段階:解析成功と接続成功を分けて考える
ノードが一覧に表示されたことから分かるのは、テキストの解析が完了したという点だけです。実際の接続には、サーバーの状態、ドメイン名の解決、ローカルネットワーク、時刻設定、トランスポートパラメータ、セキュアハンドシェイクも関係します。まずノードのフィールドが元データと一致していることを確認し、その後に実際の接続テストを行います。複数の形式に変換したノードがすべて接続できない場合は、変換を重ねるのではなく、元のリンクまたは元のJSONに戻って照合してください。
用途に合わせて形式を選ぶ
複数のノードを定期的に取得したいなら、サブスクリプション一覧でまとめて更新する方法が適しています。端末間で1つのノードだけを渡したいなら、共有リンクが手軽です。複雑な振り分け、複数のoutbound、ローカルのinbound、DNSポリシーまで保存する必要があるなら、十分な情報を表現できる完全なJSONを使います。形式は文字列の短さではなく、必要な設定範囲に合わせて選ぶべきです。
日常の管理では、サブスクリプションをノードの取得元として使い、更新とグループ分けはクライアントに任せ、ルーティングとDNSはローカルで管理できます。複雑な設定を移行する場合は、ノードの取得元とローカルルールを分けてバックアップし、単一の共有リンクを完全なバックアップと見なさないようにします。変換前に元データを保存し、変換後にアドレス、ポート、UUID、トランスポート、セキュリティ設定、パス、サーバー名を1項目ずつ確認すると、「インポートは成功したのに接続できない」状況を大幅に減らせます。