この記事の概要

まず、受け取ったものがサブスクリプションURL、エンコードされたリンク一覧、完全なコア設定のどれなのかを確認し、適切な方法で読み込みましょう。「サブスクリプションを読み込んでも空」「JSONを認識できない」「変換後に設定が消えた」といった場合に向けて、VMess・VLESSの各項目から、ローカルでのBase64変換、クライアントへの読み込み、Xray設定へのマッピングまで解説します。共有リンクに引き継げない情報についても説明します。

1. サブスクリプションURL・Base64・JSONの違い

「V2Rayのサブスクリプション」は、特定のひとつのファイル形式を指す言葉ではありません。普段受け取るHTTPSのURLは、データを取得するための入口です。クライアントがアクセスすると、実際のレスポンスが返されます。レスポンスは、1行に1つの共有リンクが並ぶ形式の場合もあれば、リンク一覧全体をBase64でエンコードしたテキストの場合もあります。サービスによってはリクエストヘッダーに応じて返す内容が変わるため、URLの拡張子だけで形式を判断することはできません。

対象見分け方適した処理方法
サブスクリプションURL通常はhttps://で始まり、アクセストークンを含む場合がありますサブスクリプショングループに登録して、必要に応じて更新
プレーンテキストのリンク一覧各行がvmess://やvless://などのプロトコルスキームで始まりますクリップボードからまとめて読み込む
Base64形式のサブスクリプション本文長いエンコード文字列で、デコードすると共有リンクが現れますサブスクリプションパーサーで処理するか、ローカルでデコード
VMessリンク内のJSONよく使われる項目はv、add、id、netですVMess共有リンク1件の生成・解析に使用
Xrayネイティブ設定トップレベルにはinbounds、outbounds、routingなどがあります対応するコアに読み込ませるか、カスタム設定から読み込む

どちらもJSONだからといって、相互に置き換えられるわけではありません。VMess共有オブジェクトはサーバーとその通信パラメーターを表します。一方、Xray設定は、コアがローカルポートを待ち受け、アウトバウンド接続を確立し、ルーティングを実行する方法を定義します。前者をconfig.jsonとして保存しても、後者に自動変換されるわけではありません。後者を丸ごとBase64にしても、クライアントが対応するサブスクリプションにはなりません。

2. VMess・VLESS共有リンクの項目構成

一般的なVMess共有形式は、vmess://の後にBase64文字列が続き、デコードするとJSONになります。以下はJSONの内容のみを示しています。ドメインとUUIDは説明用の架空データで、接続には使用できません。v: "2"は共有オブジェクトの形式を示す値であり、クライアントやコアのバージョンではありません。

{
  "v": "2",
  "ps": "VMess WSの例",
  "add": "edge.example.com",
  "port": "443",
  "id": "00000000-0000-4000-8000-000000000001",
  "aid": "0",
  "scy": "auto",
  "net": "ws",
  "type": "none",
  "host": "edge.example.com",
  "path": "/ws",
  "tls": "tls",
  "sni": "edge.example.com"
}

addは接続先アドレス、portはリモートポート、idはユーザー識別子です。net、host、pathは、通信方式やWebSocketリクエストの設定に使われます。aid: "0"は、現在一般的なVMess AEAD設定に対応します。エラーを消すために、根拠なく別の数値へ変更しないでください。また、例のtype: "none"はTLSを無効にするスイッチではありません。

VLESS共有リンクは通常URI形式で、@より前に識別情報、その後にサーバーとポート、クエリ文字列に通信パラメーターを記述します。以下も接続できないサンプルです。リンクは1行のまま扱ってください。

vless://[email protected]:443?encryption=none&security=tls&type=tcp&sni=edge.example.com#demo-vless

VMessのサンプル項目

アドレスとポート
addとport
識別情報
id
通信方式
net: "ws"
リクエストパス
path: "/ws"
TLS名
sni

これらは一般的な共有オブジェクトの項目です。コア設定にマッピングすると、キー名や階層が変わります。

VLESSのサンプルパラメーター

ユーザー識別子
URIの@より前にあるUUID
プロトコルの暗号化
encryption=none
接続のセキュリティ
security=tls
通信方式
type=tcp
TLS名
sni=edge.example.com

encryption=noneはTLSを無効にするという意味ではありません。両者は異なる階層の設定です。

URIのパラメーター値はURLのルールに従ってエンコードします。たとえば、パス/ws?ed=2048をひとつの値として渡す場合は、path=%2Fws%3Fed%3D2048と記述します。こうすれば、含まれる疑問符が別のクエリ文字列として誤認されません。備考に日本語、空白、特殊記号を含める場合も、適切にエンコードしてください。URI全体を一括でパーセントエンコードすると、スキームや区切り文字まで壊れるため避けてください。

3. Base64形式のサブスクリプションをローカルでデコード・再エンコード

一般的な変換手順は「複数の共有リンクを改行でつなぐ → テキスト全体をBase64でエンコード」です。VMessが含まれる場合は、二重のエンコードになります。外側はリンク一覧全体、内側はVMessリンク1件分のJSONです。外側をデコードしてvmess://が現れたら、まず行ごとに分割してください。スキーム付きの文字列全体を、さらにBase64として扱う必要はありません。

3 → 4
Base64では区切りの改行を除き、3バイトが4文字に対応
443
この記事の例で使うリモートTLSポートです。すべてのノードで共通ではありません。
10808
後述の設定で使うローカルSOCKSポートです。未使用であることを確認してください。

以下のプレーンなJavaScriptは、ローカルの空白ページで開発者ツールのコンソールから実行できます。コードを確認してから、自分のデータだけをローカル変数に入れてください。ネットワークリクエストは発生しません。エンコード関数はUTF-8を使用するため、日本語の備考をそのままbtoa()に渡してもエラーになりません。デコード関数は標準Base64と、よく使われるURLセーフ文字の変種の両方に対応します。

function encodeSubscription(text) {
  const bytes = new TextEncoder().encode(text);
  let binary = "";
  for (const byte of bytes) {
    binary += String.fromCharCode(byte);
  }
  return btoa(binary);
}

function decodeSubscription(text) {
  let encoded = text.trim()
    .replace(/\s+/g, "")
    .replace(/-/g, "+")
    .replace(/_/g, "/");

  if (!/^[A-Za-z0-9+/]*={0,2}$/.test(encoded)) {
    throw new Error("有効なBase64文字列ではありません");
  }

  encoded = encoded.replace(/=+$/, "");
  if (encoded.length % 4 === 1) {
    throw new Error("Base64の長さが不正です。全文をコピーしたか確認してください");
  }

  encoded += "=".repeat((4 - encoded.length % 4) % 4);
  const bytes = Uint8Array.from(atob(encoded), char => char.charCodeAt(0));
  return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
}

const demoLink =
  "vless://[email protected]:443"
  + "?encryption=none&security=tls&type=tcp&sni=edge.example.com#demo-vless";

const encodedDemo = encodeSubscription(demoLink);
console.log(encodedDemo);
console.log(decodeSubscription(encodedDemo));

4. v2rayN・v2rayNGの読み込み方法

手元にあるデータの種類に応じて読み込み方法を選びます。サブスクリプションURLはサブスクリプショングループに登録し、共有リンクはクリップボードから読み込み、コア設定全体のJSONはカスタム設定から読み込みます。デスクトップ版とAndroid版では、バージョンによってメニューの位置が変わることがあります。以下は一般的な日本語メニュー名です。表示が多少異なる場合は、該当する読み込み機能を使ってください。サブスクリプションURLをサーバーアドレス欄に入力しないよう注意してください。

v2rayN:グループを作成してからサブスクリプションを更新

  1. グループを作成

    メインウィンドウで「サブスクリプショングループ」→「サブスクリプショングループの設定」を開き、「追加」を選択します。備考とサブスクリプションURLを入力して保存し、サーバー一覧に戻ります。

  2. データを取得

    「サブスクリプショングループ」メニューから「現在のサブスクリプションを更新(プロキシを使用しない)」、またはプロキシ経由の更新項目を選びます。現在のネットワークからサブスクリプションサービスへ直接接続できる場合は、まず前者を使います。後者には、利用可能なプロキシと正しい接続経路が必要です。

  3. リンクを読み込む

    共有リンクのテキストしかない場合は、リンク全体をコピーし、「サーバー」→「クリップボードからURLを一括インポート」を実行します。一般的なデスクトップ画面ではCtrl+Vでも読み込めます。この方法で追加されるのはノードのスナップショットで、リモートのサブスクリプション更新とは連携しません。

  4. パラメーターを確認

    読み込んだ項目の編集画面を開き、サーバーアドレス、ポート、通信プロトコル、TLS、SNIを確認します。一覧に表示されるだけでは十分ではありません。対象の項目を起動し、画面下部のコアログに設定解析エラーがないか確認してください。

v2rayNG:サブスクリプションとクリップボードを使い分ける

サブスクリプションをデコードして手動で読み込んだ場合、サーバー側でアドレス、ポート、識別情報が変更されても、ローカルのスナップショットは自動更新されません。継続的な更新が必要なら、元のサブスクリプショングループを残してください。移行時は共有リンク一覧だけを保存するのではなく、サブスクリプションURLとローカルのカスタム設定をそれぞれバックアップします。

5. 共有リンクをXrayネイティブJSONにマッピング

クライアントがコア設定を生成するときは、単に項目名を置き換えるだけでなく、ローカルのインバウンド、アウトバウンドのタグ、ログ、ルーティングなど、実行に必要な情報も追加します。以下では、前述のVLESS TCP + TLSの例を、最小限のSOCKS設定にマッピングします。ローカル側は127.0.0.1:10808のみで待ち受けます。リモート側は説明用ドメインのままなので、構造を理解するための例であり、そのまま接続には使えません。

{
  "log": {
    "loglevel": "warning"
  },
  "inbounds": [
    {
      "tag": "socks-in",
      "listen": "127.0.0.1",
      "port": 10808,
      "protocol": "socks",
      "settings": {
        "auth": "noauth",
        "udp": true
      }
    }
  ],
  "outbounds": [
    {
      "tag": "proxy",
      "protocol": "vless",
      "settings": {
        "vnext": [
          {
            "address": "edge.example.com",
            "port": 443,
            "users": [
              {
                "id": "00000000-0000-4000-8000-000000000001",
                "encryption": "none"
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "tcp",
        "security": "tls",
        "tlsSettings": {
          "serverName": "edge.example.com"
        }
      }
    }
  ]
}
共有リンクの内容JSONでの対応箇所変換時の注意点
サーバーと:443settings.vnext[0].addressとportJSONではポートを数値で指定
UUIDsettings.vnext[0].users[0].id内容をすべて保持し、備考で代用しない
encryption=noneusers[0].encryptionVLESSのユーザー設定にあり、TLS設定ではありません
type=tcpstreamSettings.network使用中のコアが該当する通信方式名と構文に対応している必要があります
security=tlsとsnistreamSettings.securityとtlsSettings.serverNameサーバーのIPアドレスからSNIを推測しないでください
#demo-vless通常はクライアントの備考として保存備考が実行設定に含まれるとは限りません

ローカルポート10808は、この例で明示的に設定した値です。すべてのクライアントが現在このポートを使っているという意味ではありません。実行前に、ほかのプログラムが使用していないことを確認してください。ループバックアドレスだけで待ち受ければ、認証なしのSOCKSインバウンドがLANに公開されるのを防げます。リモート接続の問題を直すために、すべてのネットワークインターフェースで待ち受ける設定へ変更しないでください。

JSON全体を共有リンクにエクスポートする場合、通常取り出せるのは互換性のあるプロキシアウトバウンドひとつだけです。routing.rules、DNS、複数のインバウンドやアウトバウンドの組み合わせは、単一ノードの共有リンクでは完全に表現できません。元の設定がこれらに依存している場合は、JSONをそのまま保管してください。QRコードをひとつ出力しただけで、完全な移行が済んだと考えないようにしましょう。

6. 読み込み結果が空・デコードエラー・変換で項目が消える場合

「取得 → デコード → 解析 → 実行」の段階ごとに結果を記録して確認します。サブスクリプションの更新成功は、クライアントが何らかの処理を完了したことを示すだけです。項目が生成されたか、各項目が揃っているか、コアが起動したか、リモートに到達できるかは、それぞれ別に確認する必要があります。最初に失敗した段階から修正し、TLS、ポート、サブスクリプションURLを同時に変更して比較できなくなるのを避けてください。

サブスクリプションを開けるのに、読み込むと一覧が空なのはなぜ?

リクエストが成功したかだけでなく、実際のレスポンス内容を確認してください。Webページやアクセス権限の案内、現在のクライアントが対応していない形式が返っている場合は、サブスクリプションの提供元に対応形式を確認します。デコード結果が共有リンクなら、リンクを1件まるごとコピーしてクリップボードから読み込み、レスポンス形式の問題か、個別リンクの問題かを切り分けてください。

Base64のデコードで文字や長さが正しくないと表示されたら?

まず、サブスクリプションURLそのものをデコードしていないか、引用符・コードフェンス・省略記号が混ざっていないか確認します。本文に含まれる区切りの空白を取り除き、URLセーフ文字と末尾のパディングを確認してください。データが途中で切れている場合、イコール記号を追加しても欠落したデータは復元できません。本文全体を改めて取得してください。

JSONの構文チェックに通るのに、コアがエラーを出すのはなぜ?

構文が正しいというのは、カンマ、引用符、括弧の使い方に問題がないという意味にすぎません。項目構造がコアに対応しているとは限りません。まず、VMess共有オブジェクトではなくXrayの実行設定であることを確認します。次に、コアログに示された項目、通信方式、不足ファイルを確認し、読み込んだ設定と実際に使用するコアが合っているか調べてください。

エクスポートして再読み込みしたら、ノード名は同じなのに接続できないのはなぜ?

ノード名は接続パラメーターではありません。アドレス、ポート、UUID、通信方式、パス、Host、SNIに加え、設定されている場合はFlowやRealityのパラメーターも項目ごとに比較してください。証明書検証を無効にして確認の代わりにしないでください。エクスポーターが必須項目を落としている場合は、完全な設定のバックアップまたは元のサブスクリプションから復元します。

ローカルで編集したノードが、サブスクリプション更新後に元に戻るのはなぜ?

サブスクリプションを更新すると、通常はリモートの内容に合わせて対象の項目が更新されるため、ローカルでの変更が保持されるとは限りません。個別に管理したい項目は、サブスクリプションに属さないグループへコピーし、変更内容を記録してください。サーバー側で管理されているノードは、毎回手作業で変更せず、サブスクリプションの配信元で修正するのがおすすめです。

7. 変換後の確認とバックアップの順序

安全に移行するには、長い文字列ひとつではなく、用途の異なる3種類のデータを明確に分けて扱います。サブスクリプションURLは今後の更新に、共有リンクはノードの受け渡しに、完全な設定またはクライアントのバックアップはローカル環境の復元に使います。3種類を同時に保存してもかまいませんが、互いに代用はできません。識別情報を含むバックアップは、アクセス制限のあるローカル環境に保管してください。

  1. 元データを保存:変換前に元のレスポンスまたはファイルを保存し、何度も処理した結果しか残らない状態を避けます。
  2. 個別項目を確認:まず項目をひとつ選び、プロトコル、アドレス、ポート、通信パラメーターを比較します。UUID、Host、SNIを混同していないかも確認してください。
  3. 起動を確認:項目を有効にしてコアログを確認します。まず設定の解析エラーとポートの競合を解消し、その後に証明書、ハンドシェイク、リモート接続を確認してください。
  4. アプリの設定を確認:デスクトップアプリでは、システムプロキシまたは指定したローカルプロキシポートを正しく設定します。Androidでは、接続を開始し、システムから要求されるVPN権限を許可してください。
  5. 更新を確認:移行先でサブスクリプションを使う場合は、一度手動で更新し、新しい内容が想定したグループに追加されることを確認します。静的なノード一覧があるだけでは不十分です。