V2Ray 구독 형식 가이드: Base64, 네이티브 JSON 및 공유 링크 변환

Base64 구독, 네이티브 JSON 구성, 단일 공유 링크의 구조적 차이를 구분하고 변환 시 유지해야 할 핵심 필드와 사용 범위를 설명합니다.

인코딩, 컨테이너, 프로토콜부터 구분하기

V2Ray 구독을 다룰 때 가장 혼동하기 쉬운 부분은 ‘인코딩 형식’, ‘구성 컨테이너’, ‘프록시 프로토콜’이라는 세 가지 계층입니다. Base64는 원시 바이트를 전송하기 쉬운 문자로 바꾸는 텍스트 인코딩 방식입니다. JSON은 구조화된 데이터 형식으로, 전체 코어 구성을 저장할 수도 있고 특정 노드의 필드만 담을 수도 있습니다. VMess와 VLESS는 프록시 프로토콜로, 클라이언트와 서버가 필요한 정보를 주고받는 방식을 결정합니다. 서로 다른 계층에 속하므로 단순히 서로를 대체하는 관계로 볼 수 없습니다.

일반적인 구독 응답은 구분 기호가 거의 보이지 않는 긴 문자열처럼 보이며, 디코딩하면 여러 줄의 공유 링크가 나오는 경우가 많습니다. 이때 Base64는 외부 포장일 뿐이고 실제로 가져올 수 있는 내용은 디코딩 결과에 있습니다. 구독 주소가 JSON을 직접 반환하는 경우도 있는데, 노드 배열이 들어 있거나 인바운드, 아웃바운드, 라우팅, DNS 설정을 포함한 코어 구성 전체일 수 있습니다. 또 어떤 주소는 외부 인코딩 없이 vmess:// 또는 vless:// 링크를 한 줄씩 바로 반환합니다.

따라서 형식을 식별할 때는 바깥쪽부터 안쪽으로 확인해야 합니다. 먼저 HTTP 응답이 일반 텍스트인지 JSON인지 보고, 일반 텍스트라면 Base64 디코딩이 필요한지 판단한 다음, 디코딩 결과가 공유 링크 목록인지 단일 노드 객체인지 전체 구성인지 확인합니다. 파일 확장자, 문자열 길이, 구독 주소의 끝부분만으로는 콘텐츠 형식을 확실히 알 수 없습니다.

Base64 구독 식별 및 디코딩

기존 Base64 구독은 여러 공유 링크를 줄바꿈으로 이어 붙인 뒤 전체 텍스트를 인코딩하는 방식이 일반적입니다. 클라이언트는 구독을 갱신하면서 응답 본문을 가져오고, 디코딩한 다음 줄바꿈으로 항목을 나누고 각 URI를 개별적으로 해석합니다. 줄바꿈은 LF 또는 CRLF일 수 있으므로 두 형식을 모두 처리해야 하며, 앞뒤 공백과 빈 줄은 무시하는 것이 바람직합니다.

표준 Base64 문자표에는 대소문자 알파벳, 숫자, 더하기 기호, 슬래시가 포함되며 끝에 패딩으로 등호가 하나 또는 두 개 붙을 수 있습니다. URL 안전 변형은 더하기 기호와 슬래시를 각각 하이픈과 밑줄로 바꾸고, 끝의 패딩을 생략하기도 합니다. 일부 구독 생성기는 본문 앞에 보이지 않는 표시를 넣거나 여분의 공백이 포함된 내용을 반환하기도 합니다. 변환 도구가 한 가지 문자표만 지원하면 구독 자체는 정상이어도 ‘디코딩 실패’를 표시할 수 있습니다.

디코딩 결과는 대체로 다음과 같은 줄 단위 구조입니다. 아래 예시는 구조만 보여 주며, 도메인은 예약된 접미사를 사용하므로 실제로 연결되는 서비스가 아닙니다:

vless://[email protected]:443?encryption=none&security=tls&type=ws&host=edge.invalid&path=%2Fconnect#Office
vmess://eyJ2IjoiMiIsInBzIjoiVGVzdCIsImFkZCI6Im5vZGUuaW52YWxpZCJ9

첫 번째 줄은 URI에 매개변수가 포함된 VLESS 공유 링크입니다. 두 번째 줄은 vmess:// 뒤에도 인코딩된 문자열이 남아 있어, 단일 노드 JSON을 확인하려면 한 번 더 디코딩해야 합니다. 즉 외부 구독과 단일 VMess 공유 링크가 각각 한 번씩 Base64를 사용할 수 있습니다. 구독 외부 포장만 풀었다고 해서 노드 필드까지 해석된 것은 아닙니다. 여러 단계로 디코딩할 때도 일반 UUID, 경로, 메모를 새로운 인코딩 계층으로 잘못 판단하지 않도록 주의해야 합니다.

브라우저나 명령줄 도구로 디코딩할 때는 텍스트 문자 집합도 확인해야 합니다. 노드 메모는 일반적으로 UTF-8을 사용하므로 도구가 다른 문자 집합으로 결과를 처리하면 한국어 메모가 깨질 수 있지만, 서버 주소·포트·UUID에는 반드시 영향이 생기는 것은 아닙니다. 문자가 깨졌다고 노드 필드를 삭제해서는 안 됩니다. UTF-8을 유지하고 다시 인코딩하기 전에 줄바꿈과 URI 퍼센트 인코딩이 변경되지 않았는지 확인하세요.

네이티브 JSON 구성의 계층과 범위

네이티브 V2Ray 또는 Xray JSON 구성은 일반적으로 코어에 바로 전달해 실행할 수 있는 구조를 정의합니다. 원격 노드뿐 아니라 로컬 수신 포트, DNS, 로그, 라우팅 규칙, 정책, 여러 아웃바운드까지 포함할 수 있습니다. 다음은 축약한 구조 예시입니다:

{
  "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은 트래픽이 어느 아웃바운드로 갈지 결정하며, dns는 도메인 조회를 제어합니다. 공유 링크는 일반적으로 특정 원격 아웃바운드에 필요한 정보만 담으므로 로컬 수신, 복잡한 분기, 여러 아웃바운드 간 관계, DNS 규칙을 완전히 표현할 수 없습니다.

일부 서비스는 최상위에 노드 배열, 업데이트 시간, 그룹 이름 등을 담는 맞춤형 객체 형태로 ‘JSON 구독’을 설계하기도 합니다. 이런 JSON은 코어의 네이티브 구성이 아니며, 필드명과 계층은 생성기와 클라이언트 간 약속으로 정해집니다. 중괄호가 보인다고 바로 코어에 전달해서는 안 됩니다. 먼저 inbounds, outbounds 같은 핵심 구조가 있는지 확인하거나, 클라이언트가 해당 구독 구조를 명시적으로 지원하는지 살펴보세요.

v2rayN은 노드, 구독, 라우팅을 관리한 뒤 인터페이스 설정에 따라 코어 실행 구성을 생성할 수 있습니다. Android의 v2rayNG는 Xray 코어를 사용하고, v2flyNG는 v2fly 코어를 사용합니다. 세 클라이언트 모두 일반적인 공유 링크를 인식하더라도, 지원되는 전송 매개변수는 코어 버전에 따라 다를 수 있습니다. 전체 JSON을 한 클라이언트에서 다른 클라이언트로 복사할 때는 로컬 수신, 로그 경로, 플랫폼 관련 설정을 다시 확인해야 합니다.

형식 변환에서 반드시 보존할 핵심 필드

구독 목록을 공유 링크로 변환하거나, 공유 링크로 아웃바운드 JSON을 만들거나, 전체 JSON을 단일 노드 정보로 분리할 때 가장 중요한 것은 필드 간 대응 관계를 설정하는 것입니다. 서버에 연결하려면 주소와 포트뿐 아니라 인증 정보, 전송 계층, 보안 계층과 관련 매개변수도 필요합니다.

  1. 서버 주소와 포트: 구성이 고정 주소를 명시적으로 요구하지 않는 한 도메인은 원래 값 그대로 유지해야 합니다. 특정 시점에 조회된 주소로 도메인을 미리 바꾸면 이후 DNS 갱신을 우회할 수 있습니다.
  2. 사용자 인증 필드: VMess와 VLESS는 UUID를 사용하는 경우가 많습니다. 복사, 디코딩, 재인코딩 과정에서 문자를 온전히 유지해야 하며, 숫자로 처리하거나 하이픈을 제거한 뒤 형식을 임의로 바꿔서는 안 됩니다.
  3. 전송 네트워크: TCP, WebSocket, gRPC 등의 전송 방식은 서버 설정과 일치해야 합니다. 서버와 포트만 남기고 네트워크 유형을 누락하면 클라이언트가 보통 기본 방식으로 연결을 시도하므로 원래 구성과 맞지 않게 됩니다.
  4. 전송 추가 매개변수: WebSocket 경로와 Host, gRPC 서비스 이름 등은 연결의 일부입니다. 빈 문자열, 루트 경로, 필드 누락은 때때로 서로 다른 의미를 가지므로 변환할 때 한데 묶어 처리하지 않는 것이 좋습니다.
  5. 보안 계층 매개변수: TLS 사용 여부, 서버 이름 및 관련 옵션을 정확히 매핑해야 합니다. 서버 주소와 보안 핸드셰이크에 사용하는 이름은 다를 수 있으므로, 비슷해 보인다는 이유로 한쪽을 다른 쪽으로 덮어써서는 안 됩니다.
  6. 노드 메모: 메모는 연결 자체를 결정하지 않지만 노드 식별과 그룹화에 영향을 줍니다. UTF-8로 저장하고 URI 조각 안에서 퍼센트 인코딩을 올바르게 적용해야 합니다.

전체 JSON을 공유 링크로 변환할 때 가장 크게 손실되는 정보는 라우팅과 DNS입니다. 구성에 proxy, direct, block이라는 세 아웃바운드가 있고 규칙에 따라 도메인별로 연결할 아웃바운드가 정해진다고 가정해 보겠습니다. 이때 proxy에 해당하는 단일 링크만 내보내면 원격 연결 정보만 남습니다. 링크를 다시 가져와도 나머지 두 아웃바운드와 규칙 관계가 자동으로 복원되지는 않습니다.

역방향 변환에도 한계가 있습니다. 공유 링크로 원격 아웃바운드는 만들 수 있지만 로컬 수신 포트, 로그 수준, DNS 서버, 라우팅 모드는 클라이언트가 별도로 채워야 합니다. v2rayN, v2rayNG, v2flyNG는 보통 각자의 기본 설정과 노드 정보를 조합하므로, 같은 링크를 다른 기기에 성공적으로 가져왔더라도 최종 실행 구성의 모든 항목이 같다는 보장은 없습니다.

구독 가져오기 실패 단계별 점검

‘구독을 해석할 수 없음’ 또는 ‘가져온 후 노드가 없음’ 문제가 발생하면 가져오기, 디코딩, 분리, 프로토콜 파싱, 연결 확인 순서로 원인을 좁혀야 합니다. 모든 필드를 한꺼번에 수정하면 진짜 원인을 가릴 뿐 아니라 정상 구성을 망가뜨릴 수 있습니다.

1단계: 구독 본문을 제대로 가져왔는지 확인

구독 주소는 인증 만료, 네트워크 리디렉션, 서버 오류 때문에 일반 안내 페이지를 반환할 수 있습니다. 안내 페이지도 텍스트이지만 Base64나 JSON은 아닙니다. 응답 시작 부분에 페이지 태그, 오류 설명, 로그인 안내가 있는지 확인하고, 클라이언트 요청 결과가 브라우저 환경에서 필요한 인증 방식과 일치하는지도 점검하세요.

2단계: 외부 디코딩이 필요한지 판단

본문이 Base64 문자로 구성되어 있다면 표준 형식과 URL 안전 형식으로 각각 디코딩을 시도할 수 있습니다. 디코딩 결과에는 식별 가능한 링크 접두사나 JSON 구조가 나타나야 합니다. 결과가 여전히 규칙 없는 바이너리 데이터라면 반복해서 디코딩하지 마세요. 먼저 응답이 압축되었는지, 문자 집합이 올바른지, 복사 과정에서 문자가 누락되지 않았는지 확인해야 합니다.

3단계: 줄 구분과 보이지 않는 문자 확인

디코딩 결과에 링크가 여러 개 있는데 노드 하나만 가져와진다면 줄바꿈을 제대로 인식하지 못한 것이 흔한 원인입니다. 링크 사이가 LF인지 CRLF인지, 아니면 리터럴 문자로 이스케이프되어 있는지 확인하세요. 파일 시작 부분의 보이지 않는 표시 때문에 첫 번째 링크의 접두사를 인식하지 못할 수도 있습니다. 정리할 때는 명확한 공백과 표시만 삭제하고 URI 내부의 퍼센트 인코딩은 제거하지 마세요.

4단계: 프로토콜 필드와 클라이언트 지원 범위 확인

링크는 인식되지만 매개변수가 지원되지 않는다는 메시지가 나오면 현재 클라이언트나 코어 버전이 공유 형식의 일부 필드를 처리하지 못하는 경우가 많습니다. 먼저 플랫폼에 맞는 v2rayN, v2rayNG 또는 v2flyNG를 적절한 버전으로 업데이트한 뒤, 원본 구성과 대조하여 전송 네트워크, 보안 계층, 추가 매개변수를 확인하세요. ‘가져오기 성공’을 위해 알 수 없는 매개변수를 무작정 삭제하지 마세요. 삭제한 필드가 서버에서 요구하는 연결 조건일 수 있습니다.

5단계: 파싱 성공과 연결 성공을 구분

목록에 노드가 나타났다는 것은 텍스트 파싱이 완료되었다는 뜻일 뿐입니다. 실제 연결에는 서버 상태, 도메인 조회, 로컬 네트워크, 시간 설정, 전송 매개변수, 보안 핸드셰이크가 모두 영향을 줍니다. 점검할 때는 먼저 노드 필드가 원본과 일치하는지 확인한 다음 실제 연결 테스트를 진행하세요. 여러 형식으로 변환한 노드가 모두 연결되지 않는다면 변환을 계속 덧붙이지 말고 원본 링크나 원본 JSON으로 돌아가 대조해야 합니다.

사용 목적에 맞는 형식 선택

여러 노드를 정기적으로 가져오는 것이 목적이라면 구독 목록이 중앙 관리에 적합합니다. 기기 간에 단일 노드만 전달하면 공유 링크가 더 간단합니다. 복잡한 트래픽 분기, 여러 아웃바운드, 로컬 인바운드, DNS 정책을 보존해야 한다면 전체 정보를 담을 수 있는 JSON이 필요합니다. 어떤 문자열이 더 짧아 보이는지가 아니라 구성 범위에 따라 형식을 선택해야 합니다.

일상적인 관리에서는 구독을 노드 소스로 사용해 클라이언트가 업데이트와 그룹화를 담당하게 하고, 라우팅과 DNS는 로컬에서 관리할 수 있습니다. 복잡한 구성을 옮길 때는 노드 소스와 로컬 규칙을 따로 백업하여 단일 공유 링크를 전체 백업으로 착각하지 않도록 하세요. 변환 전 원본 데이터를 보관하고 변환 후 주소, 포트, UUID, 전송 네트워크, 보안 설정, 경로, 서버 이름을 항목별로 대조하면 ‘가져오기는 성공했지만 연결되지 않는’ 문제를 크게 줄일 수 있습니다.

v2rayN 다운로드 4개 플랫폼 설치 패키지 보기