Base64はエンコード方式、サブスクリプションはノード一覧の取得方法、ネイティブJSONはコアの実行設定です。それぞれ役割が異なります。「サブスクリプションを開けるのに読み込めない」「デコードしても文字列のまま」「共有リンクを設定ファイルとして使えない」といった場合に役立ちます。外側のサブスクリプション、個々のリンク、コア設定の順に確認すれば、デコード・インポート・設定補完のどれが必要か判断できます。
まず形式を区別:サブスクリプションURLはノード設定ではない
結論:受け取った内容を確認してから、適切なインポート方法を選びます。https://で始まるサブスクリプションURLは取得先にすぎません。クライアントが受け取るBase64形式のノード一覧、平文の共有リンク、その他のデータ形式は、レスポンス本文で決まります。URLそのものをBase64デコードしても、サーバー設定は得られません。
サブスクリプションURLとノード一覧
おすすめよくある形式では、複数の共有リンクを改行区切りで並べ、全体をBase64エンコードします。クライアントにサブスクリプションURLを登録しておけば、更新時にノードを再取得できます。ノード一覧を継続的に管理するのに便利ですが、すべてのサービスがこの形式を採用しているわけではありません。
用途:有効なサブスクリプションURLが提供され、ノードを継続的に更新したい場合。
vmess://共有リンク
この記事では、一般的なv2共有形式を扱います。接頭辞の後ろには、Base64エンコードされたノードJSONが続きます。VMessのアウトバウンドに必要な情報を主に記述する形式で、ローカルの待ち受け、DNS、ルーティングポリシーなどは含まれません。
用途:単一ノードの移行、クリップボードからのインポート、QRコードでの共有。
コアのネイティブJSON設定
通常はinboundsとoutboundsを含み、dnsやroutingも設定できます。構造や対応フィールドはコアとバージョンによって異なるため、ファイル拡張子だけで互換性を判断することはできません。
用途:カスタムの受け入れ設定やルールを指定する場合、または使用するコアを明確にした設定管理。
Base64は情報を秘匿する仕組みではありません。サブスクリプションURLのアクセストークン、ノードのUUID、共有用QRコードから接続権限が得られる場合があります。問題の調査にはローカルのエディターを使い、実際のデータをオンラインデコードサイトに貼り付けないでください。ログを他人に渡す前に、これらの識別情報も削除しましょう。
Base64サブスクリプションのデコード:外側の一覧と個々のノードを分けて処理
よくある二層構造では、外側をBase64デコードすると複数のvmess://リンクが得られます。そのうち1つを選び、接頭辞を取り除いてからもう一度デコードすると、ノードJSONを確認できます。どの入力にも一律に2回デコードを適用してはいけません。サブスクリプション本文が共有リンクで始まっているなら、外側のデコードは不要です。
-
レスポンス本文を取得する
ローカルのツールでサブスクリプションの返却内容を確認します。ログイン画面、CAPTCHA、エラーページが表示されたら、まずアクセスの問題を解決してください。HTMLページはノード一覧ではないため、リクエストが成功していてもサブスクリプションが使えるとは限りません。
-
外側の形式を見分ける
本文に
vmess://やvless://が直接含まれている場合は、行ごとに読み取ります。連続したエンコード文字列なら、Base64デコードを試します。{または[で始まる内容は、まずJSONとして確認してください。 -
ノードごとに行を分ける
デコード結果を改行で分割し、各行の前後の空白を取り除いて、空行を除外します。複数のリンクを連結したり、リンク内の文字を書き換えたりしないでください。
-
個々のリンクを解析する
この記事で扱うVMess v2形式では、
vmess://を取り除いてからデコードし、JSONとして解析します。異なる形式の場合はフィールドを無理に当てはめず、共有リンクの形式と提供元を確認してください。
以下の関数は、ローカルのブラウザーコンソールで使う例です。標準のBase64と一般的なURLセーフ文字に対応し、省略された末尾のパディングを補って、UTF-8として日本語の注釈を復元します。実行前にコードを確認してください。ネットワークリクエストの送信やクリップボードの自動読み取りは行いません。
function decodeBase64Utf8(input) {
let value = input.trim().replace(/\s+/g, "");
value = value.replace(/-/g, "+").replace(/_/g, "/");
if (!/^[A-Za-z0-9+/]*={0,2}$/.test(value)) {
throw new Error("Base64以外の文字が含まれています");
}
value = value.replace(/=+$/, "");
if (value.length % 4 === 1) {
throw new Error("Base64の長さが不正です");
}
value += "=".repeat((4 - value.length % 4) % 4);
const binary = atob(value);
const bytes = Uint8Array.from(binary, char => char.charCodeAt(0));
return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
}
function readSubscription(body) {
const text = body.trim();
const decoded = /^(vmess|vless):\/\//i.test(text)
? text
: decodeBase64Utf8(text);
return decoded.split(/\r?\n/)
.map(line => line.trim())
.filter(Boolean);
}
function readVmess(link) {
const value = link.trim();
if (!value.startsWith("vmess://")) {
throw new Error("vmess://リンクが必要です");
}
return JSON.parse(decodeBase64Utf8(value.slice(8)));
}
readSubscriptionは、「平文のリンク一覧またはそのBase64エンコード」という1種類のサブスクリプション形式を示す例で、汎用パーサーではありません。異なる形式の場合は処理を止め、提供元の形式説明を確認してください。Base64のデコードに成功しても、内容を読めるというだけで、ノードが有効であることやアカウントにアクセス権があることを意味しません。
vmess://リンクを解析:共有フィールドをネイティブ設定に対応づける
以下は構造を説明するためのVMess v2ノードオブジェクトです。example.comはドキュメント用の例示ドメインで、UUIDも例示専用です。この情報でプロキシサーバーに接続することはできません。フィールドvの値"2"は共有形式のバージョンを示し、クライアントやコアのバージョンではありません。
{
"v": "2",
"ps": "ドキュメント用の例",
"add": "example.com",
"port": "443",
"id": "00000000-0000-4000-8000-000000000001",
"aid": "0",
"scy": "auto",
"net": "ws",
"type": "none",
"host": "example.com",
"path": "/ws",
"tls": "tls",
"sni": "example.com"
}
| 共有フィールド | ネイティブ設定の出力先 | 変換時の注意点 |
|---|---|---|
add、port | settings.vnext[].address、port | アドレスは文字列、ネイティブ設定のポートは数値です。 |
id、aid | settings.vnext[].users[].id、alterId | この例のaidは0で、現在のVMess AEADの使い方に対応しています。 |
scy | settings.vnext[].users[].security | VMessのユーザー暗号化設定であり、TLSのオン・オフを指定する項目ではありません。 |
net | streamSettings.network | この例ではwsを使用しています。トランスポートが異なる場合、フィールドを1つ変更するだけでは不十分です。 |
host、path | wsSettings.headers.Host、wsSettings.path | ここではWebSocketとして扱います。パスに含まれるクエリパラメーターも保持してください。 |
tls、sni | streamSettings.security、tlsSettings.serverName | TLSのサーバー名とWebSocketのHostは、それぞれ別のレイヤーに属します。 |
ps、v | 注釈と共有形式の情報 | コアの接続に必要なフィールドではないため、そのままアウトバウンド設定に入れてはいけません。 |
変換時の確認:トランスポートの意味を保ち、フィールドの型を調整する
アドレス、ポート、UUID、トランスポート、TLS、SNI、Host、パスを1つずつ確認します。共有フィールドのtype: "none"をTLS無効化の根拠にしたり、アドレスの値で提供元が指定したSNIを上書きしたりしないでください。
VMessとVLESSは異なるプロトコルです。vless://は一般に、ユーザー情報、ホスト、ポート、クエリパラメーターを含むURI形式で、接頭辞を除いてBase64デコードしJSONを得る手順は使えません。リンクの接頭辞をVMessからVLESSに変えても、プロトコル変換にはなりません。サーバー側が対応するプロトコルと認証設定をサポートしている必要があります。
ネイティブJSONに変換:ノード以外にインバウンド設定も必要
ネイティブ設定は、デコードしたノードJSONのファイル名を変えるだけでは作れません。以下は、よく使われるXrayのVMess、WebSocket、TLS構成をまとめた例です。ローカルにSOCKSインバウンドを設定し、アウトバウンドには前述のサンプルノードを使用します。実際のフィールドはインストール済みのコアのバージョンに合わせてください。すべてのV2Flyバージョンで使える共通設定ではありません。
{
"log": {
"loglevel": "warning"
},
"inbounds": [
{
"tag": "local-socks",
"listen": "127.0.0.1",
"port": 10808,
"protocol": "socks",
"settings": {
"auth": "noauth",
"udp": true
}
}
],
"outbounds": [
{
"tag": "proxy",
"protocol": "vmess",
"settings": {
"vnext": [
{
"address": "example.com",
"port": 443,
"users": [
{
"id": "00000000-0000-4000-8000-000000000001",
"alterId": 0,
"security": "auto"
}
]
}
]
},
"streamSettings": {
"network": "ws",
"security": "tls",
"tlsSettings": {
"serverName": "example.com",
"allowInsecure": false
},
"wsSettings": {
"path": "/ws",
"headers": {
"Host": "example.com"
}
}
}
}
]
}
この例にはルーティングルールがなく、すべての通信はデフォルトで最初のアウトバウンドに送られます。システムプロキシも自動設定されません。アプリで127.0.0.1:10808のSOCKSサービスを明示的に使用してください。127.0.0.1は待ち受けをローカルマシンに限定するアドレスです。問題の切り分けのために、すべてのネットワークインターフェースで待ち受けるアドレスへ安易に変更しないでください。
- まずポートを確認。既存のクライアントが10808を使用中の場合、2つ目のコアが起動に失敗することがあります。重複するプロセスを停止するか、ローカルのインバウンドとアプリ側のプロキシポートを両方変更してください。
- 証明書の検証を維持。この例では
allowInsecure: falseのままにしています。証明書エラーが発生した場合は、システム時刻、サーバー名、証明書チェーンを確認し、検証を無効にしないでください。 - 設定の適用範囲を区別。クライアントにカスタム設定をインポートした後、システムプロキシ、TUN、組み込みルーティングが引き続き有効かどうかはインポート方式によって異なります。通常のノードモードと同じ動作だと決めつけないでください。
逆変換:共有リンクに含められるのは設定の一部だけ
単一のVMessアウトバウンドから共有リンクを作るには、ネイティブ設定からサーバー、ユーザー、トランスポートの各フィールドを取り出し、前述のv2共有オブジェクトに組み立てます。UTF-8でエンコードしてBase64に変換し、最後にvmess://を付けます。ネイティブ設定全体をそのままエンコードして接頭辞を付けても、一般的なノードインポート形式にはなりません。
function encodeBase64Utf8(text) {
const bytes = new TextEncoder().encode(text);
let binary = "";
for (const byte of bytes) {
binary += String.fromCharCode(byte);
}
return btoa(binary);
}
function createVmessLink(share) {
return "vmess://" + encodeBase64Utf8(JSON.stringify(share));
}
function createBase64Subscription(links) {
return encodeBase64Utf8(links.join("\n"));
}
createVmessLinkが受け取るのは、フィールド表に沿って整理済みの共有オブジェクトです。複雑な設定からの自動抽出やノードパラメーターの検証は行いません。createBase64Subscriptionは共有リンクの配列を受け取り、一般的な形式のサブスクリプション本文を生成します。更新可能なサブスクリプションURLを作成する機能ではありません。URLには、管理されたサービスからのレスポンス提供が別途必要です。
- ネイティブ設定に複数のサーバーやユーザーが含まれる場合は、どの組み合わせを使うか明確に選んでください。配列内のすべての項目が単一のリンクに属すると決めつけないでください。
- ローカルのインバウンド、DNS、ルーティング、ログレベル、複数アウトバウンドのポリシーは、通常1つのVMess共有リンクでは完全に引き継げません。
- 高度なトランスポート設定は、対応する共有形式の規約がなければ、インポート時に失われる可能性があります。設定全体を移行する場合はバックアップを使い、移行先のコアとの互換性を確認してください。
移行方法の選び方:ノードにはリンク、ポリシーにはバックアップ
サーバーへの接続情報だけを移行するなら共有リンクを使い、ルーティング、DNS、ローカルの待ち受け設定も保持するなら、内容を確認した設定バックアップを使います。変換後は重要なフィールドを1つずつ照合してください。「インポート成功」だけでは、設定が完全に引き継がれた証明にはなりません。
クライアントへのインポート:サブスクリプション、クリップボード、カスタム設定を使い分ける
クライアントが外側の形式を認識できても、その中のすべてのプロトコルやトランスポートをコアがサポートしているとは限りません。v2rayNはデスクトップクライアント、v2rayNGはXrayコア、v2flyNGはV2Flyコアを使用します。接続パラメーターとコアの対応状況を確認してから、インポート方法を選んでください。以下のメニュー名は一般的な日本語UIを参考にしたものです。リリースによって名称や場所が異なる場合があります。
| 入力形式 | v2rayN | Androidクライアント |
|---|---|---|
| サブスクリプションURL | 「サブスクリプショングループ」→「サブスクリプショングループ設定」を開き、URLを追加してグループを更新します。 | v2rayNGではサイドメニューの「サブスクリプショングループ設定」から追加し、メイン画面のメニューで「サブスクリプションを更新」を選びます。v2flyNGでは、現在のバージョンにあるサブスクリプションの追加機能を使ってください。 |
| 単一の共有リンク | リンク全体をコピーし、「サーバー」→「クリップボードからURLを一括インポート」を選びます。 | v2rayNGでは、メイン画面右上の「+」→「クリップボードからインポート」を選びます。v2flyNGでは、共有リンクのインポート機能を使ってください。 |
| ネイティブJSONファイル | 「サーバー」メニューの「カスタム設定サーバーを追加」を選び、使用するコアを確認してください。 | 現在のバージョンにあるカスタム設定のインポート機能を使ってください。サブスクリプションURL欄には貼り付けず、コアをまたいで移行する場合はフィールドを確認してください。 |
v2rayNでは、一般的に「サブスクリプショングループ」→「現在のサブスクリプションを更新(プロキシを経由しない)」からサブスクリプションを更新できます。この設定はサブスクリプション取得時にプロキシを経由するかどうかを切り替えるもので、ノードの接続方式を直接接続に変更するものではありません。サブスクリプションサイトへのアクセスにプロキシが必要な場合は、「プロキシ経由で更新」を選び、既存のプロキシ経路が使えることを先に確認してください。
- 更新に失敗したら、まずレスポンスを確認。URLの期限切れ、アクセストークンの無効化、Webページの返却がある場合は、ノード形式の変換を続けないでください。更新ログとサブスクリプションの利用権限を確認しましょう。
- インポートに失敗したら、まず形式を確認。余分な引用符をコピーしていないか、接頭辞が欠けていないか、JSON全体を共有リンクとして扱っていないかを確認してください。日本語の注釈が文字化けする場合は、UTF-8のエンコードとデコードを確認します。
- 接続できない場合は、パラメーターを確認。ノードが一覧に表示されるのに接続できない場合は、UUID、ポート、WebSocketのパス、Host、TLS、SNIを確認してください。Base64変換を何度もやり直しても解決しません。
- 手動変更は別に保存。サブスクリプションの更新でノード項目が再作成されることがあります。一時的に変更したノードは別のグループにコピーし、サブスクリプションの元の値との差分を記録しておきましょう。
よくある質問:デコードできたのに使えないのはなぜ?
デコード結果がまだvmess://で始まります。デコードに失敗していますか?
いいえ。外側のサブスクリプションに共有リンク一覧が含まれている場合、vmess://が表示されるのは、ノードの行を取得できたことを示すのが一般的です。ノードJSONを確認するには、個々のリンクから接頭辞を除いた部分をデコードしてください。クライアントにインポートするだけなら、通常は共有リンク全体をそのまま使えます。
どのJSONでもV2Rayのネイティブ設定として使えますか?
いいえ。VMess共有オブジェクト、クライアント設定のバックアップ、コア設定はいずれもJSONの場合がありますが、フィールドの意味は異なります。まず、そのコアが要求するインバウンドとアウトバウンドの構造になっているかを確認し、次にプロトコルとトランスポートのフィールドを確認してください。JSONの構文が正しいというだけでは、テキストを解析できることしか分かりません。
ローカルのノード一覧をエンコードすれば、自動更新できるサブスクリプションになりますか?
できるのはサブスクリプション本文の作成だけで、配信サービスは別途必要です。自動更新には、安定していてアクセス制御された取得先が必要です。本文をローカルに保存しても、他のデバイスに変更が自動配信されるわけではありません。ノードを一度だけ共有するなら、共有リンクのほうが手軽です。
クライアントへのインポートに成功すれば、接続パラメーターがすべてそろっていますか?
必ずしもそうとは限りません。パーサーが基本フィールドを読み込んでも、未対応の拡張パラメーターを無視する場合があります。インポート後にノードの編集画面を開き、トランスポート、パス、Host、TLSのサーバー名を照合してから、実際に接続を試してください。QRコードもテキストを渡す手段にすぎず、欠けたパラメーターを補うものではありません。