이 글의 핵심

구독 URL은 콘텐츠를 가져오는 주소이고, Base64는 텍스트 인코딩 방식이며, 공유 링크는 단일 노드를, 네이티브 JSON은 코어 실행 설정을 나타냅니다. ‘가져오기 실패’, ‘변환 후 규칙이 사라짐’, ‘클라이언트마다 같은 구독의 결과가 다름’ 같은 문제를 겪는다면 데이터의 유형부터 구분하세요. 이어서 알맞은 메뉴로 가져오고, 변환 과정에서 전송 방식·TLS·DNS·라우팅 설정이 유지되는지 확인하면 됩니다.

1. 구독 주소, 인코딩, 노드 설정은 서로 다른 계층

‘V2Ray 구독’은 하나의 표준 파일 형식을 가리키는 말이 아닙니다. 클라이언트는 먼저 구독 URL에 접속한 뒤 서버가 반환한 본문을 해석합니다. 흔히 여러 줄의 공유 링크가 반환되거나, 각 줄을 합친 텍스트 전체가 Base64로 인코딩되어 있습니다. JSON을 직접 반환하는 서비스도 있습니다. 주소가 HTTPS로 시작한다는 사실은 가져오는 방식만 알려 줄 뿐, 특정 가져오기 도구가 본문을 인식할 수 있다는 뜻은 아닙니다.

대상주요 특징포함 범위가져오기 메뉴
구독 URLHTTPS 주소이며 액세스 토큰이 포함될 수 있음원격 콘텐츠를 가져오는 위치구독 그룹 설정
Base64로 인코딩된 구독 본문디코딩하면 보통 한 줄에 링크 하나씩 표시됨노드 목록이며 로컬 정책은 포함하지 않을 수 있음구독 업데이트 및 파서
공유 링크vmess:// 또는 vless://단일 노드와 연결 매개변수클립보드에서 가져오기
네이티브 JSONinbounds, outbounds 등의 키인바운드, 아웃바운드, 선택적 DNS 및 라우팅사용자 지정 설정 메뉴

JSON은 문법 형식일 뿐, 설정 유형을 뜻하지 않습니다. add, id, net 키가 포함된 VMess 공유 객체도 JSON 문법 검사를 통과할 수 있지만, 완전한 Xray 설정으로 바로 실행할 수는 없습니다. 반대로 완전한 설정을 Base64로 인코딩해도 클라이언트가 지원하는 노드 구독으로 바뀌지는 않습니다.

2. Base64 구독: 먼저 디코딩한 뒤 줄마다 파싱

일반적인 노드 구독은 여러 공유 링크를 줄바꿈으로 연결한 다음, 전체 UTF-8 텍스트를 인코딩합니다. 클라이언트는 본문을 받은 뒤 텍스트를 복원하고 각 줄의 프로토콜을 인식합니다. VMess는 단일 링크 안에 Base64 인코딩이 한 겹 더 들어갈 수 있습니다. 따라서 ‘구독 본문의 디코딩 성공’이 ‘노드 내부 필드의 유효성’을 보장하지는 않습니다.

  1. 본문 확인: 로그인 페이지, 액세스 제한 안내, 서버 오류 페이지가 아니라 실제 구독 콘텐츠를 받았는지 확인합니다.
  2. 인코딩 여부 확인: 본문이 이미 공유 링크로 시작한다면 일반 텍스트로 처리하고, 무작정 다시 디코딩하지 마세요.
  3. 디코딩: 바깥쪽 Base64를 풀어 한 줄에 링크 하나씩 있는 텍스트가 나오는지 확인합니다.
  4. 노드 파싱: 각 줄의 프로토콜을 확인한 다음 서버 주소, 포트, 사용자 ID, 전송 매개변수를 점검합니다.

표준 Base64에는 +, /가 흔히 사용되며 끝에 =가 붙을 수 있습니다. 일부 제공처는 URL 안전 변형의 -, _를 사용하거나 끝의 패딩을 생략합니다. 가져오기 도구마다 허용하는 형식이 다르므로, ‘등호가 없다’는 이유만으로 구독이 손상됐다고 단정할 수 없습니다. Base64 전체를 URL 퍼센트 인코딩으로 처리해서도 안 됩니다.

// 로컬 JavaScript 예제: 여러 줄로 된 공유 링크 텍스트를 입력합니다.
// TextEncoder / TextDecoder를 사용하면 한글 노드 이름을 보존할 수 있습니다.
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(encoded) {
  let normalized = encoded.replace(/\s/g, "")
    .replace(/-/g, "+")
    .replace(/_/g, "/");
  normalized += "=".repeat((4 - normalized.length % 4) % 4);
  const binary = atob(normalized);
  const bytes = Uint8Array.from(binary, char => char.charCodeAt(0));
  return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
}

이 코드는 텍스트 형식만 변환하며, 구독을 온라인으로 가져오거나 노드 연결을 확인하지는 않습니다. 디코딩에 실패하면 내용이 잘렸는지, 안내 문구까지 함께 복사했는지 먼저 확인하세요. 디코딩에 성공해도 해당 프로토콜을 지원하는 클라이언트에서 파싱해야 합니다. 브라우저에서 한글을 바로 btoa()에 전달하면 오류가 날 수 있으므로, 예제에서는 먼저 UTF-8 바이트로 변환합니다.

3. VMess·VLESS 공유 링크: 필드별 대응 관계

일반적인 vmess:// 공유 링크는 프로토콜 접두사 뒤에 Base64로 인코딩된 JSON 객체를 붙입니다. 아래는 인코딩 전 객체로, 흔히 쓰이는 공유 규칙의 한 예이며 완전한 코어 설정은 아닙니다. 도메인과 UUID는 구조를 설명하기 위한 값으로, 실제 노드에 사용할 수 없습니다.

{
  "v": "2",
  "ps": "VMess WebSocket 예시",
  "add": "node.example.org",
  "port": "443",
  "id": "2d1e7e18-49f4-4ab7-8b63-c929d11c5e29",
  "aid": "0",
  "scy": "auto",
  "net": "ws",
  "type": "none",
  "host": "node.example.org",
  "path": "/proxy",
  "tls": "tls",
  "sni": "node.example.org"
}

v는 공유 객체의 형식 표시이며 클라이언트 버전이 아닙니다. ps는 설명이고, add와 port는 연결 대상입니다. net, host, path는 전송 계층을 나타냅니다. 여기서 aid는 0이며, 이를 근거로 VLESS에도 같은 이름의 매개변수가 있다고 추정해서는 안 됩니다. 공유 형식에 따라 일부 필드는 생략될 수 있으므로 가져온 뒤 노드 편집 화면에서 확인하세요.

VLESS 공유 링크는 보통 URI 구조를 따릅니다. 사용자 ID는 @ 앞에, 서버 주소와 포트는 뒤에 놓이고, 쿼리 매개변수에는 전송 방식과 보안 설정이 담깁니다. # 뒤에는 설명이 붙습니다. 아래 예시는 뒤의 JSON과 같은 매개변수를 사용합니다.

vless://[email protected]:443?encryption=none&security=tls&type=ws&host=node.example.org&path=%2Fproxy&sni=node.example.org#Example-WS

정리: 프로토콜 이름을 바꾸지 말고 필드에 맞춰 변환

vmess://를 vless://로 바꾸는 것만으로는 프로토콜을 변환할 수 없습니다. 서버가 해당 프로토콜에 필요한 매개변수를 제공해야 다른 형식의 링크를 만들 수 있습니다. 같은 노드를 다른 형식으로 옮길 때도 전송 방식, 보안 계층, 인증 필드를 유지해야 합니다.

4. 네이티브 JSON: 노드 매개변수 외에 실행 환경도 설정

네이티브 Xray 설정은 프로세스 전체의 동작 방식을 정의합니다. 인바운드는 로컬 앱이 연결되는 지점을, 아웃바운드는 요청을 서버로 보내는 방식을 결정하며, 라우팅과 DNS는 트래픽 분기 및 이름 해석 방식을 정합니다. 아래는 필드 비교용 최소 설정으로, VLESS·WebSocket·TLS를 사용합니다. 예시 주소는 실제 서비스를 제공하지 않습니다.

{
  "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": "vless",
      "settings": {
        "vnext": [
          {
            "address": "node.example.org",
            "port": 443,
            "users": [
              {
                "id": "2d1e7e18-49f4-4ab7-8b63-c929d11c5e29",
                "encryption": "none"
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "ws",
        "security": "tls",
        "tlsSettings": {
          "serverName": "node.example.org"
        },
        "wsSettings": {
          "path": "/proxy",
          "headers": {
            "Host": "node.example.org"
          }
        }
      }
    }
  ]
}
10808
예시 로컬 SOCKS 인바운드 포트
443
예시 원격 TLS 서버 포트

두 포트의 역할은 서로 다릅니다. 10808은 로컬 루프백 주소에 바인딩되며 예시용 값일 뿐, 모든 기기의 실제 설정을 뜻하지는 않습니다. 443은 원격 서버가 수신하는 포트이므로 서버 설정과 일치해야 합니다. 로컬에서 같은 주소와 포트를 이미 사용 중인 프로세스가 있으면 설정을 추가로 실행하지 못할 수 있습니다.

5. v2rayN·v2rayNG: 올바른 가져오기 메뉴 선택

클라이언트 메뉴 이름은 버전과 인터페이스 언어에 따라 달라질 수 있습니다. 아래는 일반적인 중국어 간체 메뉴를 기준으로 설명합니다. 작업 전에 클립보드 내용이 구독 URL인지, 단일 노드 링크인지, 완전한 JSON인지 확인하세요. 특히 HTTPS 구독 주소를 일반 노드 링크로 가져오지 마세요.

v2rayN: 구독 그룹과 단일 노드는 각각 가져오기

  1. 구독 그룹 추가

    메인 화면에서 ‘구독 그룹’ → ‘구독 그룹 설정’으로 이동한 뒤 목록에서 ‘추가’를 선택합니다. 설명과 구독 주소를 입력하고 저장하세요. 주소에 포함된 쿼리 매개변수는 모두 유지해야 합니다.

  2. 구독 업데이트

    ‘구독 그룹’ 메뉴로 돌아가 현재 구독 또는 전체 구독을 업데이트합니다. 프록시 사용 여부를 선택하는 메뉴가 있다면 현재 네트워크에서 실제로 접속 가능한 방식을 고른 뒤 업데이트 로그를 확인하세요.

  3. 단일 노드 가져오기

    vmess:// 또는 vless:// 전체 링크를 복사한 다음, 메인 창에서 ‘서버’ → ‘클립보드에서 일괄 URL 가져오기’를 선택합니다. 일반적인 단축키는 Ctrl+V입니다.

  4. 연결 설정 확인

    노드 편집 창을 열어 주소, 포트, UUID, 전송 유형, 경로, TLS 서버 이름을 확인합니다. 가져오기에 성공했다는 것은 파싱이 끝났다는 뜻일 뿐, 서버에 연결할 수 있다는 의미는 아닙니다.

v2rayNG: 구독 그룹 및 클립보드에서 가져오기

6. 형식 변환: 유지해야 할 항목에 따라 선택

‘변환 성공’은 최소한 세 가지 기준으로 나눠 봐야 합니다. 텍스트 디코딩, 클라이언트 가져오기, 예상한 연결 동작입니다. 앞의 두 단계가 성공해도 라우팅, DNS, 지문, 전송 확장 매개변수가 누락될 수 있습니다. 먼저 무엇을 옮길지 정하면 변환 버튼부터 찾는 것보다 문제를 빠르게 해결할 수 있습니다.

공유 링크로 노드 이전

권장

클라이언트의 공유 또는 링크 복사 기능으로 내보낸 뒤 대상 클라이언트에서 가져오세요. 완료 후 전송 및 TLS 매개변수를 하나씩 확인하고, 로컬 라우팅과 DNS는 별도로 옮깁니다.

적합한 경우: 기기 간 단일 노드 이전, 소수 연결 정리

구독 주소로 노드 목록 관리

대상 클라이언트에 구독 주소를 다시 추가해 파싱 및 업데이트를 맡기세요. 본문을 고정된 링크 목록으로 변환하면 특정 시점의 사본만 남고, 원격 업데이트 기능은 유지되지 않습니다.

적합한 경우: 노드가 자주 바뀌거나 지속적인 업데이트가 필요한 그룹

네이티브 JSON으로 정책 유지

호환되는 코어 사이에서 설정을 옮기고 파일 참조, 포트, 시스템 권한, 필드 지원 여부를 하나씩 확인하세요. 사용자 지정 설정을 가져온 뒤에는 클라이언트 인터페이스의 일부 옵션이 해당 설정에 적용되지 않을 수 있습니다.

적합한 경우: 아웃바운드가 여러 개이거나 사용자 지정 DNS 또는 복잡한 라우팅이 포함된 설정

이전 후 먼저 로그에서 설정 파싱 오류나 수신 오류가 있는지 확인한 다음 노드 하나를 선택해 연결을 테스트하세요. 데스크톱에서는 시스템 프록시나 앱 내 프록시가 실제 인바운드를 가리키는지 확인합니다. Android에서는 연결 서비스가 시작됐는지 확인하고, 시스템 안내에 따라 VPN 인터페이스 권한을 허용하세요. 속도 측정 결과가 나오는 것과 브라우저 트래픽이 프록시를 통과하는 것은 서로 다른 테스트입니다.

7. 가져오기 및 변환 관련 자주 묻는 질문

구독 주소는 열리는데 업데이트 후 노드가 0개인 이유는 무엇인가요?

응답 본문이 HTML 페이지, 오류 메시지, 또는 클라이언트가 지원하지 않는 형식인지 먼저 확인하세요. 브라우저에서 URL을 열 수 있다고 해서 노드 목록이 반환되는 것은 아닙니다. 토큰이 만료되지 않았는지 확인한 뒤 클라이언트 업데이트 로그에서 파싱 오류를 살펴보세요.

Base64를 디코딩했는데도 vmess로 시작합니다. 다시 디코딩해야 하나요?

바깥쪽 구독은 이미 디코딩된 상태입니다. 일반적인 형식에서는 한 줄의 vmess:// 뒤에 인코딩된 내용이 한 겹 더 들어 있지만, 프로토콜 접두사 뒤의 페이로드만 파싱해야 합니다. 여러 줄로 된 목록 전체를 다시 디코딩하지 마세요. 정상적으로 가져오면 이 과정은 클라이언트가 처리합니다.

JSON 검사는 통과했는데 코어가 시작되지 않는 이유는 무엇인가요?

문법이 올바르다고 해서 필드까지 유효한 것은 아닙니다. 먼저 VMess 공유 객체와 전체 설정을 구분하고, 코어가 해당 프로토콜과 필드를 지원하는지 확인하세요. 로그에 수신 실패가 표시된다면 구독 인코딩을 계속 바꾸기보다 로컬 포트가 사용 중인지 확인해야 합니다.

링크로 변환한 뒤 기존 라우팅 규칙이 사라진 이유는 무엇인가요?

단일 노드 링크에는 보통 연결 매개변수만 포함됩니다. 트래픽 분기를 복원하려면 대상 클라이언트에서 라우팅과 DNS를 다시 설정하거나 호환되는 전체 설정 이전 방법을 사용하세요. 로컬 정책이 빠진 것을 노드 인증 매개변수 손실로 오해하지 마세요.

가져오기는 성공했지만 TLS 또는 핸드셰이크 오류가 표시되면 어떻게 하나요?

노드 편집 화면을 열어 서버 정보와 포트, 전송 유형, SNI, WebSocket Host, 경로를 대조하고 기기 시간이 올바른지 확인하세요. 필드 수정 대신 인증서 검증을 끄지 마세요. 원본 링크도 연결에 실패한다면 서버 상태와 네트워크 연결을 계속 확인해야 합니다.