구독 주소는 데이터를 가져오는 경로이고, Base64는 텍스트를 인코딩하는 방식이며, 공유 링크는 개별 노드를 설명하고 원본 JSON은 코어 실행 설정을 담습니다. 구독에 내용이 있는데도 가져올 수 없거나 JSON을 링크로 변환할 수 없는 경우, 먼저 입력 형식을 확인하고 오프라인으로 디코딩한 뒤 클라이언트에서 설정을 생성해 각 항목을 대조하세요. 변환 중 라우팅, DNS, 보안 설정이 누락되지 않도록 주의해야 합니다.
1. 구독 주소, 구독 본문, 노드 설정 구분하기
https://로 시작하는 구독 주소는 데이터를 가져오는 경로일 뿐, 응답 형식까지 정해 주지는 않습니다. 서버는 Base64 텍스트나 줄바꿈으로 구분된 공유 링크를 반환할 수도 있고, 특정 클라이언트 전용 설정을 반환할 수도 있습니다. 가져올 수 있는 형식인지 판단할 때는 주소의 확장자가 .txt나 .json인지가 아니라 실제로 내려받은 본문을 확인하세요.
흔히 쓰이는 Base64 구독은 여러 노드 공유 링크를 줄바꿈으로 연결한 다음 전체를 인코딩한 형식입니다. 여기에는 두 겹의 인코딩이 적용될 수 있습니다. 바깥쪽은 전체 목록이고, 안쪽은 각 vmess:// 뒤에 있는 노드 JSON일 수 있습니다. 바깥쪽을 디코딩해도 코어에서 바로 실행할 수 있는 완전한 설정이 되지는 않습니다. Base64는 되돌릴 수 있는 인코딩 방식이지, 데이터를 보호하는 암호화 방식이 아닙니다.
| 대상 | 일반적인 형태 | 포함 정보 | 처리 방법 |
|---|---|---|---|
| 구독 주소 | https://로 시작 | 원격 리소스 위치, 접근 토큰이 포함될 수 있음 | 구독 그룹 설정 |
| Base64 구독 본문 | 긴 인코딩 문자열 | 대개 인코딩된 공유 링크가 줄 단위로 나열됨 | 구독 업데이트 또는 오프라인 디코딩 |
| 공유 링크 목록 | vmess://、vless:// | 하나 이상의 노드 연결 정보 | 클립보드에서 가져오기 |
| 원본 JSON | inbounds, outbounds 등의 키 포함 | 인바운드, 아웃바운드, 선택 사항인 DNS 및 라우팅 설정 | 사용자 지정 설정 메뉴 |
판별 기준: 본문을 확인한 뒤 가져오기 방법 선택
본문이 이미 줄 단위 공유 링크라면 다시 디코딩하지 마세요. 인바운드와 아웃바운드 구조가 모두 포함된 본문이라면 구독 주소로 추가하면 안 됩니다. 로그인 페이지나 오류 페이지가 반환되면 변환을 계속하기 전에 구독 접근 문제부터 해결하세요.
2. VMess 및 VLESS 공유 링크의 매개변수 구성
일반적인 vmess:// 공유 형식은 노드 정보를 담은 JSON을 인코딩해 프로토콜 접두사 뒤에 붙입니다. 디코딩하면 add, port, id, net, host, path, tls 등의 필드를 확인할 수 있습니다. 이 JSON은 공유 링크용 형식이며, 코어에 그대로 전달해 실행할 수 있는 원본 JSON은 아닙니다.
아래는 구조를 확인하기 위한 VMess 노드 설명 예시입니다. 주소와 UUID는 문서용 예시이며 실제로 연결할 수 있는 서버 정보가 아닙니다. v: "2"는 이 공유 형식의 버전을 나타내며 클라이언트 버전이 아닙니다. 최신 VMess 노드는 일반적으로 aid: "0"을 사용하지만, 실제 값은 서버 설정을 기준으로 확인해야 합니다.
{
"v": "2",
"ps": "예시-VMess-WS",
"add": "example.com",
"port": "443",
"id": "123e4567-e89b-42d3-a456-426614174000",
"aid": "0",
"scy": "auto",
"net": "ws",
"type": "none",
"host": "example.com",
"path": "/proxy",
"tls": "tls",
"sni": "example.com"
}
VLESS 공유 링크는 보통 URI 형식을 그대로 사용합니다. 사용자 정보 위치에는 UUID가 들어가고, 호스트와 포트는 연결 대상을 나타내며, 쿼리 매개변수는 전송 방식과 보안 계층을 지정합니다. 해시 기호 뒤에는 노드 메모가 붙습니다. 아래 예시는 WebSocket과 TLS를 사용하며 별도의 흐름 제어 매개변수는 포함하지 않습니다.
vless://[email protected]:443?encryption=none&security=tls&type=ws&host=example.com&path=%2Fproxy&sni=example.com#예시-VLESS-WS
security=tls는 전송 보안 계층에 TLS를 사용한다는 뜻입니다.encryption=none은 VLESS 프로토콜 매개변수이므로 두 설정은 서로 모순되지 않습니다.host는 여기서 WebSocket 요청의 Host를 뜻하고,sni는 TLS 핸드셰이크에 사용됩니다. 용도가 다르므로 예시의 값이 같더라도 변환할 때 서로 대체할 수 없습니다.path=%2Fproxy를 디코딩하면/proxy가 됩니다. 경로에 물음표, 해시 기호 또는 공백이 포함되면 URI 매개변수 형식에 맞게 인코딩해야 하며, 값을 그대로 이어 붙이면 안 됩니다.#뒤의 메모는 연결 방식에 영향을 주지 않습니다. 중국어 메모는 UTF-8과 퍼센트 인코딩을 사용하면 가져오기 도구마다 다르게 처리될 가능성을 줄일 수 있습니다.
3. Base64 구독 오프라인 디코딩 및 재인코딩
실제 구독을 처리할 때는 구독 주소, UUID, 디코딩된 본문을 모두 민감한 정보로 취급하세요. 신뢰할 수 없는 온라인 변환 페이지에 입력하지 마세요. 로컬의 빈 페이지에서 브라우저 개발자 도구를 열고 검토한 코드를 실행할 수 있습니다. 실행 전에 다른 스크립트가 입력값을 읽지 않는지 확인하고, 개발자 도구에 기록이 남을 수 있다는 점도 유의하세요.
아래 함수는 네트워크 요청 없이 로컬에서 문자열만 변환합니다. 디코딩 함수는 일반 Base64와 URL 안전 문자를 모두 처리하고, 인코딩된 텍스트의 줄바꿈을 허용하며, 빠진 끝부분의 등호를 보완합니다. 입력값이 Base64가 아니라면 반복해서 인코딩하거나 디코딩하며 추측하지 말고 출처를 확인하세요.
function decodeBase64Utf8(input) {
const normalized = input.trim()
.replace(/\s+/g, "")
.replace(/-/g, "+")
.replace(/_/g, "/");
if (normalized.length % 4 === 1) {
throw new Error("Base64 길이가 올바르지 않습니다");
}
const padded = normalized.padEnd(
Math.ceil(normalized.length / 4) * 4, "="
);
const bytes = Uint8Array.from(atob(padded), c => c.charCodeAt(0));
return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
}
function encodeBase64Utf8(text) {
const bytes = new TextEncoder().encode(text);
let binary = "";
for (const byte of bytes) binary += String.fromCharCode(byte);
return btoa(binary);
}
원본 구독 본문을 문자열로 decodeBase64Utf8에 전달한 뒤, 결과에 프로토콜 접두사가 줄 단위로 나타나는지 확인하세요. 기존 Base64 구독을 만들려면 유효한 공유 링크를 먼저 정리한 다음 encodeBase64Utf8(links.join("\n"))을 호출하세요. 목록 전체에 URL 디코딩을 적용하면 노드 매개변수에 원래 인코딩되어 있던 구분 문자가 미리 복원될 수 있으므로 피해야 합니다.
- 텍스트 앞에 있을 수 있는 바이트 순서 표시를 제거하고
\r?\n을 기준으로 줄을 나눈 다음 빈 줄을 삭제합니다. - 각 줄의 프로토콜 접두사를 확인하세요. 오류 페이지, 트래픽 안내, 공지 문구가 노드 목록에 섞여서는 안 됩니다.
- VMess 노드 필드를 확인해야 하는 경우에만 개별 링크에서
vmess://뒤의 부분을 디코딩하세요. - 재인코딩한 뒤 다시 디코딩해 노드 줄 수와 중국어 메모가 그대로인지 확인한 다음 클라이언트에 가져오세요.
4. 클라이언트에서 가져오기·내보내기 및 설정 생성
일반적인 이전 작업에서는 먼저 클라이언트가 공유 링크를 파싱하도록 한 뒤, 클라이언트에서 해당 코어 설정을 생성하는 것이 좋습니다. 직접 필드를 작성하다 생기는 오류를 줄일 수 있지만 전송 매개변수는 여전히 확인해야 합니다. v2rayN 데스크톱 버전에 따라 메뉴 이름이 조금씩 다를 수 있으므로, 아래에서는 자주 쓰이는 메뉴 이름을 기준으로 설명합니다. 같은 이름의 항목을 찾을 수 없다면 관련 없는 사용자 지정 설정 메뉴를 쓰지 말고 동일한 기능을 찾아보세요.
-
그룹 백업
현재 활성 서버와 구독 그룹을 기록하고 원본 구독 주소를 저장하세요. 테스트 항목은 별도 그룹에 추가해 일괄 가져오기 후 기존 사용 구성이 덮어쓰이지 않게 하세요.
-
구독 추가
v2rayN에서 「구독 그룹」→「구독 그룹 설정」을 열고 그룹을 추가한 뒤 구독 주소를 입력합니다. 「구독 그룹」으로 돌아가 「모든 구독 업데이트(프록시 사용 안 함)」를 실행하세요. 해당 주소에 프록시가 필요하다면 프록시를 사용해 업데이트하는 항목을 선택합니다.
-
단일 링크 가져오기
공유 링크 전체를 복사한 뒤 「서버」→「클립보드에서 URL 일괄 가져오기」를 선택해 가져오세요. 여기에 붙여 넣는 것은 노드 링크뿐입니다. 로컬 JSON 파일은 사용자 지정 설정 기능으로 처리해야 합니다.
-
내보낸 뒤 대조하기
노드를 선택하고 마우스 오른쪽 버튼을 클릭한 뒤, 현재 버전에서 제공하는 공유 URL 내보내기 또는 복사 기능을 사용하세요. 내보낸 결과를 테스트 그룹에 다시 가져오고 편집 창을 열어 주소, 포트, UUID, 전송 유형, SNI, 경로를 대조합니다.
-
연결 확인
테스트 노드를 활성 서버로 설정하고 코어 시작 로그를 확인한 뒤 실제 요청을 테스트하세요. 클라이언트에 「전체 설정 내보내기」 또는 유사한 기능이 있을 때만 원본 JSON을 내보내세요. 공유 링크 복사는 실행 설정 내보내기와 다릅니다.
Android용 v2rayNG에서는 보통 메인 화면의 「+」→「클립보드에서 가져오기」를 사용합니다. 구독 주소는 「구독 그룹 설정」에서 추가한 다음 구독을 업데이트하세요. v2flyNG에서도 구독 관리와 단일 노드 가져오기를 구분해야 합니다. 두 Android 클라이언트는 서로 다른 코어 계열을 사용하므로 VLESS 링크를 파싱할 수 있다고 해서 링크에 필요한 모든 전송 기능을 지원하는 것은 아닙니다. 특히 REALITY 지원 여부를 확인하세요.
5. 공유 링크를 원본 JSON으로 매핑하기
원본 JSON의 구조는 파일 확장자가 아니라 대상 코어에 따라 달라집니다. 완전한 실행 설정에는 원격 노드뿐 아니라 로컬 인바운드와 필요한 아웃바운드 선택 설정도 포함되어야 합니다. 아래는 앞서 살펴본 URI의 필드 매핑을 보여 주는 Xray 형식의 VLESS, WebSocket, TLS 예시입니다. 예시 주소는 실제 서비스에 사용할 수 없습니다. 로컬에서 이미 10808 포트를 사용 중이라면 비어 있는 포트로 바꾸고 호출하는 쪽의 설정도 함께 수정하세요.
{
"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": "example.com",
"port": 443,
"users": [
{
"id": "123e4567-e89b-42d3-a456-426614174000",
"encryption": "none"
}
]
}
]
},
"streamSettings": {
"network": "ws",
"security": "tls",
"tlsSettings": {
"serverName": "example.com",
"allowInsecure": false
},
"wsSettings": {
"path": "/proxy",
"headers": {
"Host": "example.com"
}
}
}
}
]
}
- URI의 호스트와 포트는
settings.vnext의address,port에 매핑되고 UUID는users[].id에 매핑됩니다. type=ws는streamSettings.network에,security=tls는 같은 계층의security에 매핑됩니다.sni는tlsSettings.serverName에 매핑되고, WebSocket의 Host와 경로는wsSettings에 들어갑니다.- 로컬 리슨 주소, 인바운드 포트, 로그 수준은 실행 환경에서 설정하며 공유 링크에서 가져오지 않습니다. 서버의
443을 로컬 SOCKS 리슨 포트로 지정하지 마세요.
VMess는 VMess 구조에 맞춰 아웃바운드 프로토콜과 사용자 필드를 생성해야 합니다. 위의 protocol만 vmess로 바꾸는 것으로는 충분하지 않습니다. REALITY, 특정 지문 또는 흐름 제어가 포함된 VLESS 링크도 대상 코어가 지원하는 구조를 사용하고 공개 키, 짧은 ID 등 필요한 매개변수를 보존해야 합니다. JSON 문법 검사를 통과했다는 것은 형식이 유효하다는 뜻일 뿐, 코어가 지원하거나 서버 매개변수가 올바르다는 뜻은 아닙니다.
6. 변환할 때 유지되는 정보와 사라지는 정보
「JSON을 구독 형식으로 변환」하는 작업을 파일을 한 번 Base64로 인코딩하는 것으로 오해하기 쉽습니다. 실제로는 최소 두 단계가 필요합니다. 설정에서 공유 가능한 프록시 아웃바운드를 찾아 클라이언트가 인식하는 URI로 변환한 다음, 구독을 받는 쪽의 요구 형식에 맞춰 포장해야 합니다. 전체 JSON을 그대로 인코딩하면 디코딩 결과도 JSON일 뿐, 노드 목록으로 바뀌지 않습니다.
클라이언트에서 공유 링크 내보내기
권장클라이언트가 일반 노드로 인식한 항목을 내보내면 필드 매핑 실수를 줄일 수 있습니다. 그래도 내보낸 후 보안 계층, 전송 매개변수, 대상 클라이언트와의 호환성을 확인해야 합니다.
적합한 용도: 단일 노드 이전, 개인 노드 목록 정리
노드 필드를 오프라인으로 변환
명확히 지원되는 프로토콜과 매개변수만 처리하고, 알 수 없는 필드가 있으면 작업을 멈춰 기록하세요. 「가져오기 성공」을 위해 흐름 제어, SNI, 전송 설정을 조용히 버리면 안 됩니다.
적합한 용도: 소수 노드 대조, 인코딩 및 URI 이스케이프 문제 해결
원본 설정 전체 보존
인바운드, DNS, 라우팅, 여러 아웃바운드 간의 관계를 보존하고 호환되는 코어에서 사용자 지정 설정으로 실행합니다. 코어 간 이전 시에는 필드를 하나씩 확인해야 합니다.
적합한 용도: 복잡한 라우팅, 체인 아웃바운드, 전체 실행 환경에 의존하는 설정
원본 설정에는 직접 연결 아웃바운드, 차단 아웃바운드, 부하 분산 선택, 도메인별 라우팅 규칙이 포함될 수 있습니다. 이러한 정보는 단일 노드 URI로 표현할 수 없습니다. 모든 프록시 서버 정보를 추출하더라도 원래의 「요청별 아웃바운드 선택」 규칙은 공유 링크에 따라 이동하지 않습니다. 변환된 노드로 연결할 수 있다고 해서 기존 라우팅 정책까지 복원된 것은 아닙니다.
판단 기준: 노드 이전과 설정 이전을 따로 진행하기
같은 서버에 연결하는 것만 필요하다면 공유 링크를 내보내 각 필드를 확인하세요. DNS, 라우팅, 여러 아웃바운드 간의 관계를 유지해야 한다면 전체 설정을 백업한 뒤 대상 클라이언트에서 실행 정책을 별도로 복원하세요.
7. 구독 변환 관련 자주 묻는 질문
구독 업데이트는 성공했는데 노드 목록이 비어 있는 이유는 무엇인가요?
먼저 응답 본문에 실제로 노드 정보가 있는지 확인하세요. 디코딩 결과가 HTML 태그로 시작한다면 로그인 페이지나 접근 오류 페이지일 가능성이 큽니다. 원본 JSON이라면 형식에 맞는 설정 메뉴를 사용하세요. 노드를 가져온 뒤 현재 화면에서 숨겨지지 않았는지 그룹 필터도 확인합니다.
Base64 디코딩 후 중국어 메모가 깨지면 어떻게 해야 하나요?
UTF-8 바이트를 디코딩하세요. atob가 반환하는 바이트 문자열을 중국어 텍스트로 바로 처리하면 안 됩니다. 이 문서의 TextDecoder 방법을 사용할 수 있습니다. URI의 해시 뒤에 있는 메모만 퍼센트 인코딩 상태라면 메모 부분에만 URI 디코딩을 적용하세요.
JSON에서 변환한 링크를 가져올 수는 있지만 연결되지 않는 이유는 무엇인가요?
먼저 주소, 포트, UUID를 대조한 다음 TLS의 SNI와 WebSocket의 Host 및 경로를 확인하세요. 원본 설정에서 REALITY나 그 밖의 특정 기능을 사용했다면 대상 코어가 이를 지원하는지, 매개변수가 빠짐없이 들어갔는지도 확인해야 합니다. 변환 과정에서 빠진 항목을 숨기려고 인증서 검증을 끄지 마세요.
기존 중국 본토 직결 규칙이 사라진 이유는 무엇인가요?
공유 링크에는 보통 단일 노드 정보만 담기며 전체 라우팅 설정은 포함되지 않습니다. 대상 클라이언트의 라우팅 설정에서 분기 정책을 복원하거나 호환되는 원본 설정 전체를 사용하세요. 기본 아웃바운드도 확인해 직결 아웃바운드를 내보내야 할 프록시 노드로 착각하지 않도록 하세요.
구독 주소를 변환 사이트에 입력했다면 어떻게 해야 하나요?
상대방이 입력값을 어떻게 저장하는지 확인할 수 없다면 서비스 제공업체의 관리 화면에서 구독 토큰을 재설정한 뒤 클라이언트의 주소도 바꾸세요. 토큰을 재설정해도 이미 발급된 노드 인증 정보까지 바뀌지 않을 수 있습니다. 노드 링크도 유출되었다면 서비스에서 지원하는 방식으로 해당 인증 정보도 교체해야 합니다.
마지막으로 「입력 형식 확인 → 디코딩 결과 확인 → 노드 필드 완전성 확인 → 코어 기능 호환성 확인 → 실제 요청 성공 확인」 순서로 검증하세요. 한 번에 한 항목만 바꾸고 변환 전 텍스트를 백업해 두세요. 그러면 가져오기 실패, TLS 핸드셰이크 오류, 라우팅 변경이 발생했을 때 형식을 무작정 바꾸는 대신 어떤 필드가 빠졌는지 찾을 수 있습니다.