먼저 구독 주소, 노드 목록, 전체 설정을 구분하세요
Clash 클라이언트에서 말하는 ‘구독’은 하나의 고정된 파일 형식을 뜻하지 않습니다. 사용자가 받는 것은 대개 HTTPS 주소이며, 클라이언트가 해당 주소에 접속하면 서버는 전체 Clash YAML, 노드만 담긴 프록시 제공자 파일 또는 Base64로 인코딩된 일반 노드 목록을 반환할 수 있습니다. 링크의 겉모양은 비슷해도 응답 내용은 완전히 다를 수 있습니다.
전체 Clash 설정에는 노드뿐 아니라 수신 포트, 작동 모드, 프록시 그룹, 규칙 집합, DNS, TUN 및 트래픽 스니핑 설정이 포함될 수 있습니다. 일반 Base64 구독은 보통 ss://, trojan://, vmess:// 또는 vless:// 같은 여러 노드 URI를 전달하는 역할만 합니다. 노드 목록만으로는 ‘중국 본토 외 사이트를 어느 그룹으로 보낼지’, ‘로컬 네트워크 주소를 직접 연결할지’, ‘어떤 규칙에도 일치하지 않는 트래픽을 어떻게 처리할지’를 알 수 없습니다.
세 번째로 흔한 유형은 Mihomo 또는 Clash용 프록시 제공자 파일입니다. 이 파일도 YAML이지만 최상위에는 보통 proxies:만 있으며, 주 설정의 proxy-providers에서 참조하도록 사용합니다. 따라서 전체 설정으로 바로 실행되지 않을 수 있습니다. 세 유형을 구분해야 직접 가져올지, provider로 사용할지, 먼저 형식을 변환할지 판단할 수 있습니다.
| 콘텐츠 유형 | 일반적인 시작 부분 또는 필드 | 규칙 및 프록시 그룹 포함 여부 | 대표적인 용도 |
|---|---|---|---|
| 전체 Clash YAML | mixed-port:、proxies:、proxy-groups: |
대개 포함 | 클라이언트 주 설정으로 가져오기 |
| 프록시 제공자 YAML | 최상위에 주로 proxies:가 있음 |
대개 미포함 | proxy-providers에서 주기적으로 로드 |
| Base64 노드 구독 | 문자, 숫자, 더하기 기호, 슬래시 또는 URL 안전 문자로 이루어진 긴 문자열 | 미포함 | 호환 클라이언트에서 읽거나 Clash 설정으로 변환 |
| 단일 노드 URI | ss://、trojan://、vmess:// |
미포함 | 노드 하나를 수동으로 가져오기 |
Clash YAML 설정에는 무엇이 들어 있나요?
YAML은 읽기 쉬운 구조화 텍스트입니다. 들여쓰기로 계층을 나타내며 목록 항목은 보통 하이픈으로 시작합니다. Clash와 Mihomo는 설정을 읽을 때 필드 이름, 데이터 유형, 들여쓰기 관계를 해석하므로 공백 두 개, 불리언 값, 따옴표와 콜론이 결과에 영향을 줄 수 있습니다. 노드 이름에 콜론, 샵 또는 대괄호가 들어간 경우에는 따옴표를 사용하는 편이 안전합니다.
아래는 축약한 구조 예시입니다. 포트 7890과 컨트롤 포트 9090은 흔히 사용하는 예시값일 뿐, 모든 클라이언트의 고정 기본값은 아닙니다. 실제 수신 포트는 클라이언트의 ‘설정’ 또는 실행 로그를 확인해야 합니다.
mixed-port: 7890
allow-lan: false
mode: rule
external-controller: 127.0.0.1:9090
proxies:
- name: "Tokyo-01"
type: ss
server: edge.example.net
port: 443
cipher: aes-128-gcm
password: demo-password
proxy-groups:
- name: "노드 선택"
type: select
proxies:
- "Tokyo-01"
- DIRECT
rules:
- DOMAIN-SUFFIX,example.org,노드 선택
- GEOIP,LAN,DIRECT
- MATCH,노드 선택
proxies는 사용 가능한 노드를 정의하고, proxy-groups는 노드를 수동 선택, 지연 시간 테스트 또는 장애 조치 그룹으로 구성하며, rules는 연결 경로를 순서대로 결정합니다. 규칙은 위에서 아래로 매칭되며, 앞에서 일치하지 않은 연결은 보통 MATCH가 처리합니다. 노드만 있고 프록시 그룹과 규칙이 없는 경우 클라이언트가 추가 템플릿으로 보완할 수 있지만, 이는 클라이언트 또는 변환기가 수행하는 별도 처리입니다.
전체 설정과 provider 파일의 경계
프록시 제공자 파일의 역할은 더 제한적입니다. 주 설정은 다운로드 주소, 갱신 주기와 상태 확인을 선언하고, 원격 파일은 노드만 제공합니다. 아래의 interval: 86400은 86400초, 즉 24시간마다 갱신한다는 뜻이며, 상태 확인은 600초마다 테스트 주소에 접속합니다.
proxy-providers:
airport-main:
type: http
url: "https://sub.example.net/clash-provider.yaml"
path: ./providers/airport-main.yaml
interval: 86400
health-check:
enable: true
interval: 600
url: "https://www.gstatic.com/generate_204"
proxies:만 있는 provider 파일을 주 설정으로 바로 사용하면 클라이언트에서 프록시 그룹이 없다는 오류가 표시될 수 있고, 가져온 뒤 원하는 분기 진입점이 보이지 않을 수도 있습니다. 반대로 DNS, TUN과 규칙이 포함된 전체 설정을 provider 경로에 넣는 것도 provider 데이터 구조에 맞지 않습니다.
Base64 구독에는 실제로 무엇이 인코딩되어 있나요?
Base64는 텍스트 인코딩 방식이지 암호화가 아닙니다. 원본 노드 URI를 제한된 문자로 이루어진 텍스트로 바꾸어 인터페이스를 통해 전송하기 쉽게 합니다. 디코딩하면 보통 한 줄에 노드 하나가 나오며, 각 줄은 클라이언트가 해당 프로토콜에 맞게 다시 해석해야 합니다. Base64 콘텐츠는 표준 문자 집합을 사용할 수도 있고, 더하기 기호와 슬래시를 하이픈과 밑줄로 바꾼 URL 안전 변형을 사용할 수도 있습니다.
ss://[email protected]:443#Tokyo-01
trojan://[email protected]:443?security=tls#Singapore-02
vless://[email protected]:443?security=tls&type=ws#Los-Angeles-03
이 URI에는 서버, 포트, 인증 정보, 전송 방식과 메모가 담기지만 Clash 프록시 그룹과 규칙을 통일된 방식으로 포함할 수는 없습니다. 변환기가 실행 가능한 설정을 만들려면 별도의 템플릿을 적용해야 합니다. 예를 들어 모든 노드를 ‘노드 선택’이라는 select 그룹에 넣고 DIRECT 및 최종 MATCH 규칙을 추가하는 방식입니다.
디코딩했는데도 이해하기 어려운 이유
- 외부 Base64를 디코딩한 결과가 여러 줄의 URI일 수 있으며, 그중 한
vmess://URI 뒤에 독립적인 Base64 JSON이 다시 포함되어 있을 수 있습니다. - 서버가 먼저 gzip으로 응답을 압축했을 수도 있습니다. 브라우저와
curl --compressed는 보통 이를 자동으로 처리하지만, 원시 바이트를 그대로 복사하면 문자가 깨져 보일 수 있습니다. - 반환된 내용이 오류 페이지일 수도 있습니다. 로그인이 만료되었거나 요청 빈도 제한에 걸렸거나 토큰이 만료되면 서버가 구독 대신 HTML을 반환할 수 있습니다.
- 구독이 URL 안전 Base64를 사용하면서 끝의 패딩 문자
=를 생략했을 수 있습니다. 일부 엄격한 디코딩 도구는 이 때문에 오류를 보고합니다. - 노드 프로토콜이나 확장 매개변수가 구버전 Clash 코어의 지원 범위를 벗어날 수 있습니다. 형식은 정상적으로 디코딩되어도 클라이언트가 로드를 거부할 수 있습니다.
구독 형식을 확인하는 네 단계
1단계: 먼저 클라이언트가 표시한 오류 위치를 확인하세요
‘다운로드 실패’와 ‘파싱 실패’는 같은 문제가 아닙니다. 전자는 대개 DNS, TLS, 네트워크 연결, HTTP 상태 코드 또는 구독 토큰 단계에서 발생합니다. 후자는 클라이언트가 이미 응답을 받았지만 목표 형식으로 읽지 못했다는 뜻입니다. 로그에 HTTP 401 또는 403이 표시되면 먼저 구독 주소를 갱신해야 합니다. yaml: line 18, mapping values are not allowed 또는 proxy 2: unsupported type이 표시될 때에만 콘텐츠와 코어 호환성을 계속 확인하세요.
2단계: 링크 문자열만 보지 말고 응답을 저장하세요
터미널에서 테스트 구독을 파일로 저장할 수 있습니다. 실제 구독 URL에는 액세스 토큰이 포함되는 경우가 많으므로 공개 스크린샷, 온라인 포럼 또는 공용 명령 기록에 붙여 넣지 마세요. 아래 예시는 테스트용 도메인과 데모 토큰을 사용합니다.
curl -L --compressed \
'https://sub.example.net/api/v1/client/subscribe?token=demo-token' \
-o subscription.txt
wc -c subscription.txt
head -c 160 subscription.txt
-L은 리디렉션을 따라가며, --compressed는 서버가 압축된 콘텐츠를 반환할 수 있도록 합니다. 파일 크기가 수십 바이트에 불과하고 <html, {"error" 또는 로그인 안내로 시작한다면 문제는 대개 Clash 형식이 아니라 API 응답에 있습니다. 정상적인 구독은 수 KB에서 수백 KB까지 다양하며, 통일된 길이 기준은 없습니다.
3단계: 확인 가능한 필드를 점검하세요
proxies:,proxy-groups:와rules:가 함께 나타나면 일반적으로 전체 Clash YAML입니다.- 최상위에
proxies:와 노드 배열만 있다면 대개 provider YAML입니다. ss://,trojan://또는vless://가 여러 줄로 바로 나타나면 평문 노드 목록입니다.- 본문 전체가 Base64 문자열이라면 먼저 디코딩한 뒤 앞의 세 가지 기준으로 판단하세요.
- 웹 페이지 제목, 인증 코드 입력, 로그인 폼 또는 JSON 오류 객체가 나타난다면 서버가 구독 데이터를 반환하지 않은 것입니다.
4단계: 대상 코어를 확인하세요
Clash Premium, Clash Meta와 이후의 Mihomo는 완전히 동일한 설정 대상이 아닙니다. Mihomo는 더 많은 프로토콜 필드, 규칙 기능, DNS 옵션과 TUN 매개변수를 지원합니다. 변환할 때 대상을 단순히 ‘Clash’로만 선택하면 구형 코어용 보수적인 형식이 생성되거나, 구형 클라이언트가 인식하지 못하는 필드가 포함될 수 있습니다. Mihomo 코어를 사용하는 클라이언트라면 Mihomo 또는 Clash Meta로 명확히 표시된 출력 대상을 우선 선택하세요.
Base64와 YAML을 서로 변환하는 방법
방법 1: 클라이언트의 호환 가져오기 기능 사용
일부 데스크톱 클라이언트는 구독을 가져오는 과정에서 일반 URI 목록을 인식하고 로컬 설정을 자동으로 생성합니다. Mihomo 코어를 사용하는 클라이언트의 경우 보통 ‘구독’ 또는 ‘설정’ 페이지에서 원격 URL을 추가한 뒤 클라이언트가 응답을 파싱하도록 합니다. 메뉴는 「구독」→「새 구독 만들기」 또는 「설정」→「URL 가져오기」처럼 표시될 수 있습니다. 가져온 후에는 ‘업데이트 성공’ 안내만 보지 말고 설정 상세 정보에서 프록시 그룹과 최종 규칙이 생성되었는지 확인해야 합니다.
자동 호환 기능은 빠르게 사용할 때 편리하지만 생성 방식은 클라이언트가 결정합니다. 어떤 클라이언트는 모든 노드를 수동 선택 그룹에 넣고, 다른 클라이언트는 자동 지연 시간 테스트 그룹을 추가할 수 있습니다. 다른 클라이언트로 옮기면 그룹 이름, 규칙과 DNS 설정이 달라질 수 있습니다.
방법 2: 구독 변환 서비스 사용
변환 서비스는 보통 원본 구독, 대상 형식과 템플릿 매개변수를 받은 뒤 원본 콘텐츠를 다운로드하고 노드를 파싱하여 Clash 또는 Mihomo YAML을 출력합니다. 일반적인 과정은 대상을 Mihomo로 선택하고 구독 URL을 입력한 다음 원격 설정 템플릿을 지정해 새 구독 주소를 생성하는 것입니다. 이후 클라이언트는 원본 Base64가 아니라 변환된 주소에 접속합니다.
템플릿이 최종 설정의 품질을 결정합니다. 최소한 다음 항목을 확인하세요:
- 프록시 그룹에 필요한 모든 노드가 포함되어 있는지, 참조되었지만 정의되지 않은 그룹 이름은 없는지 확인합니다.
- 규칙 마지막에
MATCH,노드 선택처럼 합리적인 기본 처리 항목이 있는지 확인합니다. - 로컬 네트워크, 일반적인 사설 주소와 로컬 호스트 주소가 예상대로 직접 연결되는지 확인합니다.
- DNS 설정이 현재 네트워크 환경에 맞는지, 접근할 수 없는 업스트림을 잘못 사용하고 있지 않은지 확인합니다.
- TUN, 스니핑과 IPv6 설정이 현재 운영 체제에 맞는지 확인합니다. 템플릿에서 기계적으로 가져오면 안 됩니다.
- 출력 대상이 클라이언트에서 실제로 사용하는 Mihomo 또는 해당 Clash 코어인지 확인합니다.
방법 3: 로컬에서 디코딩한 뒤 설정 템플릿 적용
Base64 콘텐츠만 확인하려는 경우에는 구독을 제3자 웹사이트에 넘기지 않고 로컬에서 디코딩할 수 있습니다. 아래 Python 3 명령은 파일을 읽고 누락된 Base64 패딩을 보완한 뒤 decoded.txt로 출력합니다. URI를 Clash 노드 객체로 변환하는 기능은 제공하지 않고 디코딩만 수행합니다.
python3 -c "import base64,pathlib; p=pathlib.Path('subscription.txt').read_text().strip(); p += '=' * (-len(p) % 4); pathlib.Path('decoded.txt').write_bytes(base64.urlsafe_b64decode(p))"
head -n 5 decoded.txt
완전한 변환을 위해서는 프로토콜 URI를 하나씩 파싱하고 TLS, WebSocket, gRPC, Reality, UDP 및 인증서 검증 등의 매개변수를 올바르게 매핑해야 합니다. 몇 개의 필드만 수동으로 복사하면 전송 계층 설정을 빠뜨리기 쉬우므로 소수 노드 디버깅에는 적합하지만 장기적인 관리 방식으로는 권장되지 않습니다. 노드가 많다면 대상 코어를 명확히 지원하고 지속적으로 관리되는 로컬 변환 도구를 사용하세요.
변환 후 Clash 또는 Mihomo로 가져오기
YAML을 얻었다고 해서 현재 작동하는 설정을 바로 덮어쓰지 마세요. 먼저 새 설정으로 별도 저장한 뒤 문법 검사와 소규모 연결 테스트를 진행합니다. 데스크톱 클라이언트의 일반적인 흐름은 「설정」→「새로 만들기」 또는 「URL에서 가져오기」→「업데이트」→「현재 설정으로 지정」입니다. 클라이언트마다 명칭은 조금씩 다르지만 새 설정의 검증이 끝날 때까지 기존 설정을 보존해야 합니다.
먼저 YAML 구조를 확인하세요
최소한 proxies, proxy-groups와 rules의 이름이 서로 일치하는지 확인해야 합니다. 프록시 그룹이 존재하지 않는 노드를 참조하거나 규칙이 존재하지 않는 그룹을 가리키면 시작에 실패하거나 트래픽 분기가 비정상적으로 작동할 수 있습니다. YAML에서는 Tab으로 공백 들여쓰기를 대신할 수 없으며, 같은 계층에는 공백 두 개를 일관되게 사용하는 것이 좋습니다.
그다음 수신 포트를 확인하세요
설정에 mixed-port: 7890이 지정되어 있다면 시스템 프록시도 로컬 호스트 127.0.0.1:7890을 가리켜야 합니다. 클라이언트가 실제로 HTTP 포트 7890과 SOCKS 포트 7891을 사용한다면 터미널 환경 변수에서 해당 프로토콜에 맞는 포트를 선택해야 합니다. 포트가 다른 프로세스에서 이미 사용 중이면 로그에 address already in use가 자주 표시됩니다. 이 경우 형식을 바꿔도 해결되지 않습니다.
HTTP_PROXY=http://127.0.0.1:7890
HTTPS_PROXY=http://127.0.0.1:7890
ALL_PROXY=socks5://127.0.0.1:7891
마지막으로 규칙, DNS와 TUN을 확인하세요
- 프록시 페이지에서 사용 가능한 노드를 하나 수동으로 선택해 자동 정책 그룹 선택 오류를 배제합니다.
- 연결 페이지를 열고 테스트 요청이 예상한 프록시 그룹에 매칭되는지 확인하세요.
DIRECT또는REJECT로 처리되어서는 안 됩니다. - 로그에서 도메인 해석 결과를 확인하고 DNS 시간 초과가 계속 발생하지 않는지 점검합니다.
- 일반 시스템 프록시가 정상적으로 검증된 뒤에만 TUN을 활성화하여 동시에 확인해야 할 변수를 줄이세요.
- TUN을 활성화한 후 클라이언트에 필요한 시스템 권한이 있는지 확인하고 기본 경로와 로컬 네트워크 접근이 정상인지 점검합니다.
TUN 모드는 시스템 프록시를 읽지 않는 애플리케이션의 트래픽을 가로채는 문제를 해결할 뿐, 유효하지 않은 노드, 잘못된 인증 정보 또는 손상된 YAML을 고쳐 주지는 않습니다. 변환 후 일반 프록시도 모두 연결되지 않는다면 TUN을 반복해서 전환하기보다 노드 매개변수, 코어 지원 여부와 구독 유효 기간을 먼저 확인해야 합니다.
자주 발생하는 가져오기 실패와 해결 방법
| 증상 | 우선 확인할 사항 | 해결 방법 |
|---|---|---|
| 구독을 업데이트하자마자 YAML 파싱 오류가 표시됨 | Base64, HTML 또는 잘못된 들여쓰기가 반환됨 | 응답을 저장하고 파일 시작 부분을 확인한 뒤, 대상 형식을 확인해 다시 변환합니다. |
| 가져오기는 성공했지만 프록시 페이지가 비어 있음 | provider 파일을 가져왔거나 프록시 그룹이 노드를 참조하지 않음 | 최상위 필드와 proxy-groups 참조를 확인합니다. |
| 노드는 있지만 모두 시간 초과됨 | 노드 만료, 호환되지 않는 프로토콜 필드, DNS 또는 네트워크 제한 | 개별 노드의 오류 로그를 확인하고 대상 코어와 전송 매개변수를 점검합니다. |
| 변환 후 모든 규칙이 직접 연결됨 | 템플릿 그룹 이름과 규칙 대상이 일치하지 않음 | 규칙의 세 번째 항목과 프록시 그룹 이름이 완전히 같은지 확인합니다. |
| 구독 업데이트에서 401 또는 403이 반환됨 | 토큰 만료, 권한 제한 또는 요청 방식 불일치 | 구독 주소를 다시 발급받고 계정 상태와 필요한 요청 헤더를 확인합니다. |
| 구형 클라이언트에서 unsupported proxy type이 표시됨 | 현재 코어가 지원하지 않는 프로토콜 또는 필드가 출력에 포함됨 | 호환되는 Mihomo 클라이언트로 업그레이드하거나 해당 구형 코어를 대상으로 선택합니다. |
| 변환 주소가 한 번은 작동하지만 이후 업데이트되지 않음 | 임시 링크 만료, 변환 서버 캐시 또는 원본 토큰 변경 | 변환 서비스의 유효 기간을 확인하고 새로 생성한 뒤 원본 주소를 대조합니다. |
중복 변환을 피하세요
원본 구독을 변환 서비스 A에서 Clash YAML로 만든 뒤 그 결과를 다시 서비스 B에 넘기면 노드 메모 변경, 정책 그룹 재생성, 규칙 템플릿 덮어쓰기와 매개변수 손실이 발생하기 쉽습니다. 가능한 한 단일 변환 경로를 유지하세요. 원본 구독을 대상 변환기에 직접 전달하고 클라이언트는 최종 주소를 읽도록 구성하는 방식입니다.
구독 업데이트를 설정 덮어쓰기와 혼동하지 마세요
일부 클라이언트는 원격 설정을 기반으로 포트, DNS 또는 규칙을 로컬에서 덮어쓸 수 있도록 합니다. 원격 업데이트 후 로컬 덮어쓰기가 유지되는지는 클라이언트 구현에 따라 다릅니다. 수정하기 전에는 ‘다운로드된 캐시 파일 편집’, ‘원격 설정 사본 편집’, ‘영구 덮어쓰기 추가’라는 세 가지 작업을 구분해야 합니다. 그렇지 않으면 다음 업데이트에서 원래 내용으로 되돌아갈 수 있습니다.
형식 선택에 대한 실용적인 결론
구독 제공자가 Mihomo 또는 Clash YAML을 직접 출력할 수 있다면 현재 코어에 맞는 기본 형식을 우선 사용하세요. 이 형식은 노드 매개변수를 온전히 표현하고 프록시 그룹과 규칙도 포함할 수 있습니다. 일반 Base64만 제공되는 경우에만 클라이언트 호환 계층이나 신뢰할 수 있는 변환 도구로 YAML을 생성하세요.
규칙을 직접 관리해야 한다면 노드를 provider 파일에 넣고, 로컬 주 설정에서 프록시 그룹, 규칙, DNS와 TUN을 관리하는 구조가 안정적입니다. 이렇게 하면 노드 업데이트가 규칙 로직을 직접 덮어쓰지 않으며, 구독이 갱신될 때마다 주 설정을 다시 생성할 필요도 없습니다. provider 갱신 주기는 86400초로 설정하고, 상태 확인 주기는 노드 수와 네트워크 환경에 따라 300~600초로 설정할 수 있습니다.
문제를 해결할 때는 항상 네 계층으로 나누어 확인하세요. 구독 주소에 접속할 수 있는지, 응답이 어떤 형식인지, 대상 코어가 파싱할 수 있는지, 실행 후 규칙과 네트워크가 올바른지 순서대로 점검합니다. 형식 변환은 두 번째 계층과 세 번째 계층의 일부만 처리할 뿐, 노드 유효성, 포트 수신, DNS 및 시스템 프록시 점검을 대신할 수 없습니다.