구독 주소는 업데이트에 사용하는 경로이고, Base64는 인코딩 방식이며, 공유 링크는 개별 노드를 설명합니다. 반면 코어 JSON에는 전체 실행 설정을 담을 수 있습니다. 브라우저에서는 열리지만 클라이언트에 가져올 수 없는 경우, 먼저 응답 내용을 확인한 뒤 v2rayN 또는 v2rayNG에서 알맞은 가져오기 메뉴를 선택하세요. 마지막으로 변환 과정에서 라우팅, DNS, 전송 설정이 누락되는지 확인합니다.
1. 구독 주소, Base64, JSON은 서로 다른 개념
‘V2Ray 구독’은 파일 확장자로 정해지는 하나의 통일된 형식이 아닙니다. 일반적으로 클라이언트가 HTTPS 주소에 접속해 텍스트를 가져오고, 그 안의 노드를 분석해 자체 설정 목록에 추가합니다. 주소는 데이터를 가져오고 업데이트하는 경로이며, 어떤 형식으로 해석할지는 응답 본문이 결정합니다. 따라서 주소 끝에 확장자가 없거나 .txt가 붙어 있다는 사실만으로 가져올 수 있는지 판단할 수는 없습니다.
구독 주소와 노드 목록
권장일반적인 응답은 줄마다 공유 링크가 하나씩 있거나, 링크 전체를 한 번 Base64로 인코딩한 형태입니다. 노드 변경 사항을 계속 받으려면 구독 주소를 유지해야 합니다.
적합한 경우: 여러 기기에서 서버 목록을 계속 업데이트하려는 사용자
단일 공유 링크
vmess://, vless:// 같은 접두어로 프로토콜을 구분하며, 보통 노드 하나의 연결 정보를 담습니다. 가져오면 대개 일회성 복사본으로 추가되며 구독 업데이트 기능은 제공되지 않습니다.
적합한 경우: 노드 하나를 임시로 옮기거나 연결 설정을 항목별로 확인할 때
코어 기본 JSON
인바운드, 아웃바운드, DNS, 라우팅, 로그 설정 등을 포함할 수 있습니다. 특정 코어의 설정 파일이므로 GUI 클라이언트의 노드 목록이나 클라이언트 데이터 백업과는 다릅니다.
적합한 경우: 여러 아웃바운드, 사용자 지정 라우팅 또는 전체 코어 설정을 유지해야 할 때
Base64는 암호화가 아닙니다. 구독 토큰과 노드 식별 정보는 긴 문자열로 변환되어도 다시 복원할 수 있습니다. 전체 구독 내용을 공개 변환 사이트에 입력하지 말고, 도움을 요청할 때도 주소의 쿼리 매개변수가 보이지 않도록 주의하세요.
2. vmess://와 vless://의 구조 차이
일반적인 VMess 공유 형식은 vmess:// 뒤에 Base64로 인코딩한 JSON 객체가 이어집니다. 이 객체에는 add, port, id, net, tls 등의 필드가 자주 포함됩니다. 하지만 이는 공유 형식에서 노드 하나를 설명하는 데이터일 뿐, Xray를 실행할 때 바로 사용할 수 있는 전체 설정은 아닙니다.
| 확인 항목 | 일반적인 VMess 공유 형식 | 일반적인 VLESS 공유 형식 |
|---|---|---|
| 기본 구조 | 프로토콜 접두어 뒤에 Base64 JSON이 이어짐 | URI 사용자 정보, 호스트, 포트, 쿼리 매개변수 |
| 노드 식별 정보 | JSON의 id | URI에서 @ 앞에 오는 사용자 정보 |
| 전송 방식 | 자주 쓰이는 필드 net | 자주 쓰이는 쿼리 매개변수 type |
| TLS와 서비스 이름 | 자주 쓰이는 필드 tls, sni | 자주 쓰이는 매개변수 security, sni |
| 메모 | 자주 쓰이는 필드 ps | # 뒤의 문자열. 보통 퍼센트 인코딩됨 |
VLESS 링크는 보통 ‘링크 전체를 다시 Base64로 디코딩’하는 형식이 아닙니다. 매개변수에 flow, fp, pbk, sid가 포함될 수 있으며, 각각 흐름 제어, 핑거프린트, REALITY 설정과 관련이 있습니다. 매개변수 이름과 지원 범위는 클라이언트 버전에 따라 다르므로, 프로토콜 접두어만 보고 모든 매개변수가 지원된다고 판단해서는 안 됩니다.
- 포트: 원격 포트가
443이라고 해서 반드시 TLS가 활성화된 것은 아닙니다. 보안 계층 설정도 함께 확인하세요. - 경로: WebSocket 경로의
/가%2F로 표기될 수 있습니다. URI 규칙에 따라 디코딩해야 하며, 퍼센트 기호를 단순히 지우면 안 됩니다. - 도메인: 서버 주소, TLS의 SNI, WebSocket의 Host는 서로 다른 필드입니다. 서버가 같은 값을 요구하는 경우에만 동일하게 설정하세요.
- 줄바꿈: 노드 목록은 보통 한 줄에 링크 하나씩 배치됩니다. 메신저가 임의로 줄을 바꾸면 쿼리 매개변수가 잘릴 수 있습니다.
3. Base64 구독 디코딩과 두 단계로 파싱해야 하는 경우
응답 본문이 ‘여러 VMess 링크를 줄마다 나열한 뒤 전체를 Base64로 인코딩한 텍스트’라고 가정해 보겠습니다. 첫 번째 디코딩으로 줄 단위 링크를 얻고, 각 vmess:// 뒤의 데이터도 별도로 디코딩해야 노드 필드를 확인할 수 있습니다. 이는 서로 다른 두 포장 단계가 겹친 경우이며, 모든 구독을 반드시 두 번 디코딩해야 한다는 뜻은 아닙니다.
- 먼저 원문을 확인하세요. 줄마다
vmess://또는vless://로 시작한다면 전체를 디코딩할 필요가 없습니다. - Base64 문자열처럼 보이면 한 번 디코딩한 뒤 결과가 링크 목록인지 확인하세요.
- 디코딩 결과가 웹 페이지 태그, 로그인 안내 또는 오류 메시지라면 형식 변환을 중단하고 가져오기 단계부터 확인하세요.
- 결과가 JSON이라면 필드 구조를 확인하세요. JSON 배열, 코어 설정, 서비스 API 응답은 문법적으로 유효하다는 이유만으로 서로 바꿔 사용할 수 없습니다.
아래는 텍스트를 오프라인에서 처리하는 순수 JavaScript 함수입니다. 인코딩과 디코딩만 수행하며 네트워크 요청은 보내지 않습니다. 흔히 쓰이는 Base64URL 문자를 지원하고, 한글 메모는 UTF-8로 처리합니다. 신뢰할 수 있는 로컬 환경에서 사용하고, 실제 구독 내용을 잘 모르는 페이지의 콘솔에 붙여 넣지 마세요.
function decodeBase64Text(source) {
const normalized = source.trim()
.replace(/\s+/g, "")
.replace(/-/g, "+")
.replace(/_/g, "/");
const padded = normalized.padEnd(
Math.ceil(normalized.length / 4) * 4, "="
);
const bytes = Uint8Array.from(
atob(padded), char => char.charCodeAt(0)
);
return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
}
function encodeBase64Text(text) {
const bytes = new TextEncoder().encode(text);
let binary = "";
for (const byte of bytes) {
binary += String.fromCharCode(byte);
}
return btoa(binary);
}
판별 방법: 디코딩 결과를 확인한 다음 가져오기 메뉴 선택
결과가 줄 단위 공유 링크라면 노드 목록으로 처리하세요. inbounds, outbounds 등의 실행 설정 필드가 포함되어 있다면 코어 설정 구조를 추가로 확인해야 합니다. 반복해서 인코딩해도 잘못된 응답이 수정되거나 빠진 프로토콜 매개변수가 채워지지는 않습니다.
4. v2rayN과 v2rayNG에서 가져오는 위치
GUI 클라이언트는 일반적으로 ‘서버 노드’, ‘구독 그룹’, ‘사용자 지정 전체 설정’을 나누어 관리합니다. 노드 가져오기는 공유 링크를 인식하고, 구독 설정은 업데이트 주소를 저장하며, 사용자 지정 설정 메뉴는 전체 JSON을 처리합니다. 세 가지 형식의 내용을 모두 구독 주소 입력란에 붙여 넣지 마세요.
가져오기 방법: 콘텐츠에 맞는 데스크톱·Android 메뉴 선택
데스크톱: v2rayN
- 단일 또는 여러 공유 링크: 복사한 다음 ‘서버’ → ‘클립보드에서 URL 일괄 가져오기’를 선택합니다.
- 구독 주소: ‘구독 그룹’ → ‘구독 그룹 설정’에서 URL을 추가한 뒤 구독을 업데이트합니다.
- 전체 JSON: ‘서버’ 메뉴에서 사용자 지정 구성 서버 항목을 찾아 설정에 맞는 코어를 선택합니다.
Android: v2rayNG
- 공유 링크: 오른쪽 위의 ‘+’ → ‘클립보드에서 가져오기’를 누릅니다.
- 구독 주소: 사이드 메뉴에서 ‘구독 그룹 설정’으로 이동해 그룹과 URL을 추가합니다. 목록으로 돌아와 ‘구독 업데이트’를 실행하세요.
- 전체 JSON: ‘+’ 메뉴에서 사용자 지정 구성 가져오기 항목을 사용합니다. 일반 노드 링크로 가져오지 마세요.
위 메뉴 이름은 일반적인 예시이며 버전에 따라 조금씩 다를 수 있습니다. 현재 메뉴에서 클립보드, 구독 그룹, 사용자 지정 구성 기능을 확인하세요.
v2rayNG는 Xray 코어를, v2flyNG는 V2Fly 코어를 사용합니다. 어떤 JSON이 v2rayNG에서 실행된다고 해서 v2flyNG에서도 그대로 실행되는 것은 아닙니다. 특히 REALITY, 특정 전송 설정 또는 코어 전용 필드를 사용하는 경우 대상 코어의 지원 범위를 먼저 확인하세요.
5. 세 가지 형식의 변환 방법과 유지할 수 없는 정보
공유 링크와 Base64 구독 간 변환은 대개 겉으로 감싼 형식만 바꿉니다. 완전한 링크 여러 개를 줄바꿈으로 연결한 다음 UTF-8로 인코딩해 Base64로 변환하면 일반적인 정적 구독 본문을 만들 수 있습니다. 다만 본문만으로는 업데이트 가능한 구독 서비스가 되지 않습니다. 클라이언트가 해당 본문을 가져올 주소와 이후 내용을 관리할 방법도 필요합니다.
| 변환 방향 | 변환 방법 | 주요 제한 사항 |
|---|---|---|
| Base64 구독 → 공유 링크 | 전체를 한 번 디코딩하고 링크와 줄바꿈을 그대로 유지 | 본문만으로는 원래 구독 토큰, 업데이트 주기, API 응답 헤더를 복원할 수 없음 |
| 공유 링크 → Base64 본문 | 한 줄에 완전한 링크 하나씩 배치하고 UTF-8로 인코딩한 뒤 전체를 Base64로 변환 | 정적 콘텐츠는 원래 구독의 업데이트를 자동으로 반영하지 않음 |
| 공유 링크 → 코어 JSON | 프로토콜, 보안 계층, 전송 매개변수를 파싱해 해당 아웃바운드를 생성 | 인바운드, 라우팅, DNS 등 실행 환경도 별도로 설정해야 함 |
| 전체 JSON → 공유 링크 | 표현 가능한 원격 아웃바운드 하나를 선택하고 매개변수를 항목별로 변환 | 여러 아웃바운드 간 연동, 라우팅 규칙, 전체 DNS 정책은 대개 유지할 수 없음 |
JSON을 변환할 때 서버, 포트, 식별 정보만 추출해서는 안 됩니다. WebSocket과 TLS를 사용하는 경우 전송 유형, 경로, Host, TLS 활성화 여부, SNI를 최소한 확인해야 합니다. VLESS와 REALITY 조합이라면 공개 키, 짧은 ID, 관련 흐름 제어 매개변수도 점검해야 합니다. 항목 하나라도 빠지면 클라이언트에 ‘가져오기 성공’으로 표시되더라도 연결이 실패할 수 있습니다.
- 먼저 입력 구조를 확인하세요: 공유 형식의 VMess JSON과 코어의
outbounds에 들어가는 객체는 필드 구성이 서로 다릅니다. - 다음으로 내보낼 대상을 선택하세요: 전체 설정에 원격 아웃바운드가 여러 개 있다면 어떤 항목을 내보낼지 정하세요. 직접 연결이나 차단용 아웃바운드를 노드로 선택하지 마세요.
- 항목별로 대조하세요: 대상 클라이언트로 가져온 다음 편집 화면을 열어 보안 계층, 전송 경로, 프로토콜별 필드를 확인하세요.
- 마지막으로 검증하세요: 먼저 코어가 정상적으로 시작되는지 확인한 뒤 요청을 테스트하세요. 노드 연결에 성공했다고 원래 설정의 라우팅 동작까지 복원된 것은 아닙니다.
마이그레이션 팁: 라우팅을 유지하려면 전체 설정을 우선 보존하세요
서버 목록만 옮기려면 공유 링크를 사용할 수 있습니다. 기존 DNS 및 라우팅 동작까지 재현하려면 전체 JSON을 보존하고 대상 코어와의 호환성을 확인하세요. 공유 링크를 전체 설정의 백업으로 사용하지 마세요.
6. 구독 및 변환 관련 자주 묻는 질문
브라우저에서는 구독이 열리는데 클라이언트에는 노드가 0개로 표시되는 이유는 무엇인가요?
응답이 실제 링크 목록인지, 링크 목록을 Base64로 감싼 것인지 먼저 확인하세요. 브라우저는 로그인 상태를 이용하지만 클라이언트에는 로그인 페이지가 전달될 수 있습니다. 서버가 요청 정보에 따라 다른 내용을 반환하는 경우도 있습니다. 구독 그룹에 입력한 URL이 완전한지 확인한 뒤 서비스 제공자가 안내한 형식이 대상 클라이언트에 적합한지 점검하세요.
디코딩 후 한글 메모가 깨졌는데 계속 가져와도 되나요?
먼저 UTF-8로 디코딩하세요. atob()의 결과를 한글 문자열로 바로 취급하면 안 됩니다. 메모만 깨진 경우 연결 필드에는 문제가 없을 수도 있지만 원문을 다시 확인해야 합니다. 경로나 쿼리 매개변수도 함께 손상되었다면 잘못된 설정으로 테스트하지 않도록 가져오기를 중단하세요.
전체 JSON의 문법은 올바른데도 시작에 실패하는 이유는 무엇인가요?
JSON 문법 검사는 따옴표와 쉼표 등의 구조만 확인합니다. 다음으로 코어 로그에서 구체적인 필드 경로를 확인하고, 대상 코어가 지원하지 않는 필드가 있는지, 실행에 필요한 설정이 빠졌는지, 로컬 수신 포트가 충돌하는지 살펴보세요. 시작 오류를 해결하려고 Base64 인코딩을 반복하지 마세요.
구독을 공유 링크로 변환한 뒤 노드가 자동 업데이트되지 않는 이유는 무엇인가요?
클립보드에서 가져오면 보통 현재 노드의 복사본만 생성되고, 해당 노드를 가져온 구독 주소는 유지되지 않습니다. 계속 업데이트하려면 ‘구독 그룹 설정’에 원래 구독 URL을 저장하고 해당 그룹에서 업데이트하세요. 그룹의 노드를 수동으로 수정할 때는 다음 업데이트에서 변경 사항이 덮어써질 수 있다는 점도 고려해야 합니다.
형식을 변환하면 오래된 코어가 새 매개변수를 지원하게 할 수 있나요?
아니요. 변환은 표현 방식만 바꿀 뿐 코어의 기능을 늘려 주지 않습니다. 클라이언트와 코어의 실제 버전을 확인한 뒤 대상 프로토콜, 보안 계층, 전송 방식의 지원 여부를 살펴보세요. 알 수 없는 필드가 있다면 중요한 매개변수를 임의로 삭제하지 말고 호환되는 버전으로 업데이트하거나 서버에서 제공하는 호환 설정을 받으세요.
실제 작업 순서는 다음과 같이 정리할 수 있습니다. 어떤 콘텐츠를 가져왔는지 확인하고, 그에 맞는 가져오기 메뉴를 선택한 다음, 프로토콜 매개변수와 코어 로그를 점검하세요. ‘가져오기 실패’, ‘형식 불일치’, ‘연결 설정 오류’를 나눠서 확인하면 인코딩 방식을 계속 바꾸는 것보다 문제를 쉽게 찾을 수 있습니다.