1. YAML 구조와 설정 파일의 범위
매핑, 목록, 스칼라
config.yaml은 커널의 동작 방식을 정의하는 텍스트 파일입니다. 최상위에는 보통 필드명과 값을 묶은 매핑이 있습니다. dns 아래에는 매핑이 중첩되고, rules 아래에는 순서가 있는 목록이 들어갑니다. 문자열, 숫자, 불리언 값은 스칼라입니다. 먼저 이 세 가지 구조를 구분한 뒤 내용을 수정하면 목록을 문자열로 잘못 쓰거나 최상위에 있어야 할 필드를 다른 객체 안에 들여쓰는 실수를 줄일 수 있습니다.
YAML은 들여쓰기로 상하위 관계를 표현합니다. 공백 두 칸으로 통일하고 탭은 사용하지 않는 것이 좋습니다. 같은 단계의 필드는 왼쪽에 맞춰 정렬하고, 목록 항목의 하이픈 뒤에는 공백을 넣으세요. 필드명 뒤의 콜론 다음에도 보통 공백이 필요합니다. 아래 예제에서 mode와 dns는 같은 단계이고, enable은 DNS 객체에 속합니다. nameserver의 두 값은 하나의 목록입니다. 빈 줄은 가독성을 높일 뿐 계층에는 영향을 주지 않습니다.
mixed-port: 7890
mode: rule
dns:
enable: true
nameserver:
- https://dns.alidns.com/dns-query
- https://doh.pub/dns-query
rules:
- MATCH,DIRECT
불리언 스위치에는 true 또는 false를 사용하고, 포트는 정수로 씁니다. 식별자로 사용되는 값은 문자열로 처리하세요. 비밀번호, 샵(#)이 들어간 주소, 콜론이 포함된 복합 문자열은 주석이나 매핑 경계로 잘못 해석되지 않도록 따옴표로 묶는 편이 좋습니다. 작은따옴표 안의 백슬래시는 일반적으로 문자 그대로 유지되지만, 큰따옴표에서는 이스케이프 문자를 사용할 수 있습니다. 웹 페이지에서 Windows 경로를 복사할 때는 백슬래시의 의미에 특히 주의하세요. 주석은 따옴표 밖에서 문법상 허용되는 위치에 샵(#)을 써서 시작합니다.
최상위 필드의 순서와 실행 순서는 다릅니다
rules를 파일 끝에 두는 것은 읽기 편하게 하기 위한 관례일 뿐, 커널이 앞의 모든 필드를 처리한 다음 규칙을 실행한다는 뜻은 아닙니다. 실제 순서가 중요한 곳은 규칙 목록과 일부 프록시 그룹의 후보 순서입니다. 최상위 키의 순서는 대체로 결과에 영향을 주지 않습니다. 하나의 매핑에서 같은 키를 중복 정의하지 마세요. 파서에 따라 중복 키를 거부하거나 나중 값을 남길 수 있으므로 이런 차이를 이용해 안정적으로 오버라이드할 수는 없습니다. DNS를 수정할 때는 기존 DNS 객체 안에서 변경하고, 파일 끝에 두 번째 객체를 추가하지 마세요.
원본 구독, 클라이언트에 저장된 설정, 커널에 전달되는 런타임 파일을 구분해야 합니다. 구독에는 노드만 들어 있을 수도 있고, 프록시 그룹과 규칙이 모두 포함될 수도 있습니다. 클라이언트는 가져온 내용을 재구성한 뒤 포트, 제어 인터페이스, TUN 설정을 추가하기도 합니다. 따라서 구독 캐시를 편집해도 실행 결과가 바뀌지 않을 수 있고, 클라이언트를 다시 시작하면 수정 내용이 덮어써질 수도 있습니다. 문제를 찾을 때는 먼저 클라이언트에서 현재 설정, 런타임 설정 또는 커널 설정 미리보기를 찾아 원본과 달라진 부분을 기록하세요.
문법 검사를 통과해도 참조 관계를 확인하세요
YAML 파싱에 성공했다는 것은 들여쓰기와 데이터 형식이 대체로 올바르다는 뜻일 뿐, 현재 커널이 모든 필드를 지원한다는 보장은 아닙니다. 존재하지 않는 프록시 그룹을 규칙에서 참조하거나, 그룹에서 잘못 입력한 노드 이름을 참조하는 것은 설정 의미상의 오류입니다. 이름은 대소문자를 구분하는 경우가 많고, 한글 공백이나 끝 공백, 전각 문장 부호도 이름을 다르게 만들 수 있습니다. 먼저 프록시 그룹과 노드 이름을 목록으로 정리한 뒤 규칙의 마지막 항목을 대조하세요. 잘못된 위치의 들여쓰기를 반복해서 고치는 일을 줄일 수 있습니다.
이 페이지의 나머지 장에 나오는 코드는 일부 설정만 보여 주는 예제입니다. 기존 설정에 추가할 때는 같은 단계에 있는 기존 필드를 유지하고 목록을 항목별로 병합해야 합니다. 클라이언트가 반드시 config.yaml이라는 파일을 사용하는 것은 아닙니다. 시작 인수에서 다른 이름을 지정할 수도 있으므로 커널이 실제로 읽는 경로를 확인하세요. 클래식 Clash와 mihomo의 필드 차이는 커널 발전 과정과 호환성 비교에서 확인할 수 있습니다. 같은 설정이 서로 다른 커널에서 똑같이 작동한다고 가정하지 마세요.
2. 공통 필드: 포트, 모드, 접근 범위
인바운드 포트와 시스템 프록시는 서로 다른 설정입니다
인바운드 포트는 커널이 앱의 연결을 받아들이는 진입점입니다. port는 HTTP 프록시 포트를, socks-port는 SOCKS 포트를 제공합니다. mixed-port는 하나의 포트에서 HTTP와 SOCKS를 모두 지원합니다. 일반적인 데스크톱 환경에서는 혼합 포트 하나만 사용하면 여러 진입점을 관리하는 부담을 줄일 수 있습니다. 포트 번호는 로컬에서 정하는 값이므로 모든 클라이언트가 따라야 하는 고정 번호는 없습니다. 앱에 입력한 프록시 주소는 실제로 리슨 중인 주소와 일치해야 합니다.
mixed-port: 7890
allow-lan: false
bind-address: "127.0.0.1"
mode: rule
log-level: info
ipv6: false
커널이 정상적으로 리슨한다고 해서 시스템 프록시까지 켜진 것은 아닙니다. 시스템 프록시는 해당 기능을 지원하는 앱이 특정 프록시 주소에 연결하도록 운영체제에 알리는 설정이고, 설정 파일의 인바운드 포트는 연결을 받는 역할만 합니다. 시스템 프록시를 꺼도 프록시 주소를 직접 입력한 앱은 계속 커널을 사용할 수 있습니다. 반대로 커널을 종료했는데 시스템 프록시를 해제하지 않으면 브라우저가 아무도 리슨하지 않는 포트에 연결할 수 있습니다. 문제를 점검할 때는 클라이언트의 통합 스위치만 보지 말고 프로세스, 리슨 포트, 시스템 프록시 상태를 각각 확인하세요.
| 필드 | 의미 | 확인할 사항 |
|---|---|---|
mixed-port | HTTP와 SOCKS를 함께 지원하는 진입점 | 로컬 포트가 이미 사용 중인지 확인 |
allow-lan | LAN 기기의 접속 허용 | 리슨 범위와 방화벽 설정이 일치하는지 확인 |
mode | 트래픽 처리 방식 선택 | rules에 따른 분기가 계속 적용되는지 확인 |
log-level | 로그 상세 수준 | 문제 해결 후 적절한 로그 수준으로 복원 |
rule, global, direct 모드
rule은 규칙 순서에 따라 연결에 적용할 정책을 선택합니다. global은 커널에 들어온 연결을 전역 정책으로 전달합니다. direct는 대상에 직접 연결합니다. 모드는 커널에 들어온 뒤의 처리 방식을 정할 뿐, 모든 앱의 트래픽을 커널로 보내지는 않습니다. 따라서 전역 모드는 TUN을 대체하지 않으며, 시스템 프록시를 무시하는 앱을 강제로 프록시로 연결할 수도 없습니다. 먼저 트래픽을 커널로 가져오는 범위를 해결한 다음, 들어온 연결에 어떤 출구를 적용할지 정하세요.
일상적인 사용에는 직접 연결과 프록시 연결 조건을 각각 설정할 수 있는 규칙 모드가 적합한 경우가 많습니다. 전역 모드는 규칙의 영향을 잠시 배제하고 특정 출구가 작동하는지 확인할 때 유용합니다. 직접 연결 모드는 비교 테스트에 쓸 수 있지만 인바운드나 DNS 등 다른 구성 요소의 영향은 남을 수 있습니다. 테스트가 끝나면 원래 모드로 돌리고 실제 연결 기록을 확인하세요. 상황별 비교는 세 가지 프록시 모드 선택 방법을 참고하세요. 웹페이지 하나가 열린다는 이유만으로 모든 트래픽 분기가 올바르다고 판단하지 마세요.
리슨 범위와 관리 인터페이스
allow-lan과 bind-address는 다른 기기에서 인바운드로 연결할 수 있는지 함께 결정합니다. 현재 컴퓨터에서만 사용할 때는 루프백 주소로 범위를 제한하면 문제를 쉽게 추적할 수 있습니다. 휴대폰과 공유하려면 LAN 접속을 허용하는 것 외에도 리슨 주소가 LAN 어댑터를 포함하는지, 두 기기가 서로 통신할 수 있는지, 방화벽이 해당 인바운드 연결을 허용하는지 확인해야 합니다. 리슨 포트를 열었다고 해서 인터넷에 안전하게 공개해도 되는 것은 아닙니다. 라우터에서 포트 포워딩을 설정하면 접근 범위가 크게 달라집니다.
external-controller는 관리 인터페이스이며 브라우저 프록시 포트가 아닙니다. 제어 패널과 클라이언트가 커널을 관리하는 데 사용하므로 앱의 HTTP 프록시 설정에 입력하면 안 됩니다. 클라이언트가 관리 주소와 인증 설정을 자동으로 만들 수 있으며, 이를 직접 덮어쓰면 화면이 커널과 연결되지 않을 수 있습니다. 별도 관리가 필요하지 않다면 클라이언트 설정을 그대로 사용하세요. 변경이 꼭 필요하다면 먼저 로컬에 바인딩하고 인증을 설정하세요. 관리 자격 증명이 들어 있는 런타임 파일을 공개 게시판에 올리지 마세요.
포트 충돌이 나면 먼저 다른 프록시 프로그램을 종료하고 이전 커널 프로세스가 계속 실행 중인지 확인하세요. 포트를 변경한 뒤에는 설정을 다시 로드하고 앱에 직접 입력한 프록시 주소도 함께 수정해야 합니다. log-level은 문제 해결 중에만 debug로 높일 수 있지만, 상세 로그에는 대상 도메인과 연결 정보가 포함될 수 있습니다. 공유 전에 민감한 정보를 삭제하세요. 클라이언트를 다시 선택하려면 설치 파일 페이지에서 플랫폼별 항목을 확인하세요. 일반적인 그래픽 인터페이스를 원한다면 Clash Plus를 먼저 살펴볼 수 있습니다.
3. DNS: 해석 진입점, 업스트림, 도메인 연결
누가 누구에게 DNS 조회를 요청하는지 먼저 구분하세요
DNS 설정에는 최소 세 가지 역할이 있습니다. 앱이나 시스템은 조회를 요청하고, 커널의 DNS 모듈은 요청을 받아 전달하며, 업스트림 리졸버는 결과를 반환합니다. dns.enable은 커널 모듈을 켜고, listen은 모듈이 리슨할 주소를 지정하며, nameserver는 업스트림을 지정합니다. 모듈만 켠다고 시스템이 자동으로 이 모듈을 사용하지는 않습니다. 시스템 DNS 설정, 클라이언트의 트래픽 처리 기능 또는 TUN 하이재킹 규칙을 통해 해당 조회를 이 진입점으로 보내야 합니다.
dns:
enable: true
listen: 127.0.0.1:1053
ipv6: false
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
fake-ip-filter:
- "*.lan"
- "*.local"
default-nameserver:
- 223.5.5.5
- 119.29.29.29
nameserver:
- https://dns.alidns.com/dns-query
- https://doh.pub/dns-query
이 예제는 기존 시스템 서비스와 함께 사용할 수 있도록 DNS 서비스를 로컬의 비표준 포트에 바인딩합니다. DNS 모듈의 구조를 보여 줄 뿐, 시스템 리졸버를 자동으로 변경하지는 않습니다. default-nameserver는 주로 업스트림 DNS 서버 자체의 도메인을 해석해 암호화 DNS에 필요한 초기 연결 경로를 만드는 데 사용합니다. 모든 서비스 도메인의 기본 업스트림은 아닙니다. 업스트림이 도메인으로 지정되어 있는데 초기 조회가 되지 않으면 DNS 모듈 전체가 안정적으로 조회하지 못할 수 있습니다.
fake-ip와 redir-host의 차이
fake-ip는 조회 결과로 매핑용 가상 주소를 할당합니다. 커널은 이후 연결에서 이 주소를 이용해 원래 도메인을 찾아 도메인 규칙과 출구를 적용합니다. 이 주소는 대상 서버의 실제 공인 IP가 아니므로 앱에서 가상 주소가 조회되더라도 DNS 오류라는 뜻은 아닙니다. redir-host는 일반적으로 실제 조회 결과를 반환하며 도메인 연결 방식이 다릅니다. 어느 방식을 쓸지는 앱 호환성과 트래픽 처리 경로를 고려해 결정하세요. 속도나 보안 등급의 차이로 이해해서는 안 됩니다.
일부 LAN 서비스, 기기 검색, 실제 주소에 의존하는 앱은 가상 주소와 호환되지 않을 수 있습니다. fake-ip-filter로 지정한 도메인에 가상 주소 할당을 적용하지 않을 수 있지만, 필터는 DNS 응답 방식만 바꾸며 직접 연결 규칙을 추가하지는 않습니다. 실제 내부 주소로 접속해야 하는 도메인이라면 업스트림이 내부 이름을 해석할 수 있는지, 이후 라우팅이 해당 네트워크에 도달할 수 있는지도 확인하세요. 문제를 해결할 때는 우선 정확히 알고 있는 도메인 하나만 필터에 추가하세요. 지나치게 넓은 와일드카드 패턴을 바로 넣지 않는 편이 좋습니다.
최상위의 ipv6와 DNS 객체 안의 같은 이름을 가진 필드는 적용 범위가 다릅니다. 전자는 커널 전체의 IPv6 사용 여부에 영향을 주고, 후자는 DNS 모듈의 IPv6 조회 동작에 영향을 줍니다. DNS의 IPv6 응답을 차단해도 앱의 기존 캐시, 내장 리졸버, 미리 저장된 주소까지 모두 없어지는 것은 아닙니다. 네트워크가 IPv6를 지원한다면 라우팅과 출구가 준비됐는지 확인한 뒤 각각 설정하세요. 잘못 구성된 IPv6 경로를 숨기기 위해 AAAA 응답만 감추지 마세요.
분기용 DNS 조회와 프록시 서버 주소 조회
nameserver-policy는 특정 도메인에 사용할 리졸버를 지정하며, 사내 도메인이나 명확한 조회 조건이 있는 도메인에 적합합니다. 어느 DNS 업스트림에 조회할지 정할 뿐, 서비스 연결의 프록시 정책을 직접 결정하지는 않습니다. proxy-server-nameserver는 프록시 서버 도메인 조회에 별도의 리졸버를 사용해 출구 연결이 아직 준비되지 않았는데 그 출구에 의존해 서버 주소를 조회해야 하는 순환 문제를 줄일 수 있습니다. 실제 순환 조회나 결과 차이가 확인된 경우에만 이런 설정을 추가해 여러 변수를 동시에 바꾸지 마세요.
dns:
nameserver-policy:
"+.internal.example.com":
- 192.168.1.1
proxy-server-nameserver:
- https://dns.alidns.com/dns-query
위 예제의 내부 도메인과 라우터 주소는 구조를 보여 주기 위한 값입니다. 실제로 관리하는 내부 도메인과 DNS 서비스를 제공하는 주소로 바꾸세요. 문제를 찾을 때는 먼저 커널에 조회가 도착하는지 확인하고, 업스트림 접속을 테스트한 다음, 반환 결과와 이후 연결의 도메인 연결 상태를 살펴보세요. 앱에 자체 암호화 DNS 기능이 있으면 시스템 설정을 우회할 수 있습니다. 브라우저에서 이미 연결된 세션도 DNS를 바꾼 즉시 새로 연결되지는 않습니다. 필요하면 기존 연결을 닫고 관련 캐시를 지운 뒤 같은 대상으로 다시 테스트해 이전 결과를 새 설정의 동작으로 착각하지 않도록 하세요.
4. 프록시 노드: 프로토콜 필드와 제공자
공통 필드와 프로토콜별 필드
proxies는 고정 프록시 노드 목록이며 각 항목은 하나의 출구를 나타냅니다. 공통 필드에는 이름 name, 프로토콜 type, 서버 server, 포트 port가 있습니다. 그 외의 매개변수는 프로토콜에 따라 다르므로 다른 프로토콜의 인증 필드를 그대로 가져오면 안 됩니다. 노드 이름은 프록시 그룹과 규칙에서 참조하는 데 사용하며 인증 역할은 하지 않습니다. 서버 값에는 도메인이나 주소를 입력할 수 있지만 웹사이트 홈 주소나 경로가 포함된 구독 링크로 서버 필드를 대신할 수는 없습니다.
proxies:
- name: SS-Example
type: ss
server: proxy.example.com
port: 443
cipher: aes-128-gcm
password: "your-password"
udp: true
이 코드는 Shadowsocks 노드의 구조를 보여 줍니다. 서버 도메인과 비밀번호는 설명용 값이므로 그대로는 연결할 수 없습니다. 암호화 방식, 포트, 인증 정보가 서버 설정과 각각 일치해야 합니다. udp: true는 해당 노드의 UDP 사용을 허용하는 설정이며, UDP를 지원하지 않는 서버에 전송 기능을 추가해 주지는 않습니다. 앱에서 실제로 UDP를 사용할 수 있는지는 인바운드 방식, 프록시 그룹, 서버, 중간 네트워크가 모두 이를 지원하는지에 따라 달라집니다.
TLS 연결에서는 접속 대상과 인증서 검증에 사용하는 서버 이름을 구분해야 합니다. 연결 주소는 클라이언트가 접속할 위치를 지정하고, 서버 이름은 TLS 핸드셰이크와 인증서 검증에 사용됩니다. 특정 구성에서는 두 값이 다를 수 있지만 서버 측에서 제공한 정확한 정보에 따라 설정해야 합니다. 인증서 오류가 나면 검증을 끄기보다 시스템 시간, 서버 이름, 인증서 체인, 주소를 확인하세요. 검증을 건너뛰면 보안 범위가 달라지고 잘못된 서버에 연결한 문제를 잠시 가릴 수도 있습니다.
노드 목록과 전체 구독은 서로 다른 구조입니다
proxy-providers는 노드 목록을 별도 출처에 두고, 기본 설정에서 제공자 이름으로 참조합니다. 이 방식은 노드 업데이트와 로컬 규칙을 분리해 관리할 수 있습니다. 제공자는 일반적으로 proxies 구조의 콘텐츠를 받으므로 아무 구독 텍스트나 그대로 읽을 수 있는 것은 아닙니다. Base64 텍스트, 단일 URI, 전체 Clash YAML은 구조가 서로 다릅니다. 형식이 맞지 않으면 먼저 변환하거나 클라이언트로 가져오세요. 자세한 내용은 구독 링크 형식과 변환 방법을 참고하세요.
proxy-providers:
local-nodes:
type: file
path: ./providers/local-nodes.yaml
health-check:
enable: true
url: https://www.gstatic.com/generate_204
interval: 600
이 제공자 예제는 구독 주소 대신 로컬 파일을 사용합니다. 상대 경로는 보통 커널의 작업 디렉터리나 클라이언트가 지정한 설정 디렉터리를 기준으로 하며, 편집 중인 파일이 있는 폴더를 기준으로 하지 않을 수 있습니다. 파일을 찾지 못하면 시작 매개변수와 로그에 표시된 최종 경로를 확인한 뒤 파일을 읽을 수 있는지 살펴보세요. 파일 안에는 여전히 노드 목록이 있어야 합니다. 기본 설정 전체를 그대로 복사해 넣으면 커널이 어느 계층에서든 노드만 추출할 것이라고 기대해서는 안 됩니다. 클라이언트가 관리하는 폴더는 앱 샌드박스 권한의 제한을 받을 수도 있습니다.
원격 제공자는 보통 type: http를 사용하며 출처 주소, 캐시 경로, 업데이트 간격을 설정합니다. 주소에 접근 자격 증명이 포함될 수 있으므로 민감한 설정으로 취급하고 스크린샷이나 공개 저장소에 올리지 마세요. 업데이트 실패 시에는 네트워크 요청 실패, 인증 실패, YAML이 아닌 콘텐츠, 지원되지 않는 프로토콜 필드 문제를 구분해 확인하세요. 캐시가 있으면 커널이 이전 노드를 계속 사용할 수도 있습니다. 따라서 화면에 노드가 보인다는 것만으로 최신 업데이트가 성공했다고 볼 수는 없습니다.
상태 확인에 성공해도 실제 서비스 사용이 보장되지는 않습니다
상태 확인은 지정한 URL로 노드 연결을 테스트하며, 결과는 테스트 대상과 DNS 경로, 서버 응답에 따라 달라집니다. 테스트 성공은 해당 확인 경로가 작동한다는 뜻일 뿐 모든 웹사이트, UDP 앱, 지역 서비스에 접속할 수 있다는 보장은 아닙니다. 제공자 상태 확인과 프록시 그룹 상태 확인도 완전히 같은 단계가 아닙니다. 지나치게 짧은 간격으로 검사를 반복하면 요청이 늘어납니다. 명확한 테스트 대상과 적절한 간격을 설정하고 노드 하나부터 확인한 뒤 자동 선택을 사용하세요.
노드 설정이 완전해 보이는데도 사용할 수 없다면 핸드셰이크 단계의 구체적인 오류를 확인하세요. 도메인 조회 실패는 사전 네트워크 문제이고, 연결 시간 초과는 주소나 포트, 방화벽과 관련됐을 수 있습니다. 인증 오류는 자격 증명을, 프로토콜 파싱 오류는 노드 유형과 커널 호환성을 확인해야 합니다. 한 번에 모든 필드를 바꾸지 마세요. 기존 값을 보존하고 서비스 제공자가 안내한 프로토콜 매개변수와 하나씩 대조해 수정한 뒤, 수동 선택 그룹으로 출구를 고정해 테스트하면 자동 전환으로 문제가 가려지는 일을 줄일 수 있습니다.
5. 프록시 그룹: 참조 관계와 선택 방식
프록시 그룹은 출구를 선택하는 계층입니다
proxy-groups는 노드, 다른 프록시 그룹, 내장 정책을 묶어 규칙에서 사용할 대상으로 만듭니다. 규칙은 보통 이름이 안정적인 그룹을 지정하고, 그룹에서 실제 출구를 선택합니다. 이렇게 하면 노드 목록이 바뀌어도 각 트래픽 규칙을 다시 작성할 필요가 없습니다. 그룹 이름은 설정 인터페이스의 일부이므로 이름을 바꾸면 모든 참조도 함께 수정해야 합니다. 이름이 중복되거나 참조가 순환하면 설정을 이해하기 어려워지고 로드되지 않을 수도 있습니다. 규칙에서 그룹으로, 그룹에서 노드로 이어지는 단방향 참조도를 그려 설계해 보세요.
proxy-groups:
- name: Proxy
type: select
proxies:
- Auto
- DIRECT
use:
- local-nodes
- name: Auto
type: url-test
use:
- local-nodes
url: https://www.gstatic.com/generate_204
interval: 600
tolerance: 50
이 예제는 앞 장에서 정의한 local-nodes 제공자를 사용합니다. proxies는 후보 이름을 직접 나열하고 use는 제공자의 노드를 가져옵니다. 두 항목의 이름 유형을 서로 바꿔 쓸 수 없습니다. Proxy는 사용자가 직접 선택하는 그룹으로 자동 그룹, 직접 연결 또는 제공자 노드를 선택할 수 있습니다. Auto에서 Proxy를 다시 참조하면 순환이 발생하므로 피하세요. 예제를 합칠 때 제공자 정의를 유지해야 합니다. 프록시 그룹만 복사하면 정의되지 않은 참조가 생깁니다.
수동 선택, 자동 테스트, 장애 조치
select는 사용자가 후보를 직접 지정하므로 출구 하나를 검증하거나 트래픽 정책을 고정할 때 적합합니다. url-test는 테스트 결과에 따라 후보를 선택하므로 사용 가능한 출구를 자동으로 유지하고 싶을 때 유용합니다. fallback은 후보 순서에 따라 사용 가능한 항목을 선택하는 방식에 가깝고 주 출구와 예비 출구가 명확할 때 적합합니다. 세 방식은 단계적으로 고급화되는 기능이 아닙니다. 출구 변경을 허용하는지, 고정된 출구가 필요한지, 테스트 연결이 추가되는 것을 감수할 수 있는지에 따라 선택하세요.
| 유형 | 선택 기준 | 사용 방식 |
|---|---|---|
select | 사용자가 직접 선택 | 출구 고정 및 항목별 문제 해결 |
url-test | 테스트 결과와 전환 허용 범위 | 후보 출구를 자동으로 관리 |
fallback | 순서와 사용 가능 여부 | 주 출구를 우선 사용하고 실패하면 예비 출구로 전환 |
load-balance | 지정된 분배 정책 | 여러 출구에 연결 분배 |
자동 그룹의 interval은 검사 간격이고, tolerance는 미세한 테스트 차이로 전환이 반복되는 것을 줄이는 값입니다. 네트워크 지연 목표나 속도 향상 스위치를 뜻하지 않습니다. 테스트 주소에서 노드가 더 빠르더라도 파일 다운로드나 동영상 서비스에서 더 빠르다는 보장은 없습니다. load-balance는 연결을 분배할 뿐, 일반 다운로드 연결 하나를 여러 노드의 대역폭으로 자동 합치지 않습니다. 연결마다 다른 출구를 사용하면 서비스 측 세션이 달라질 수도 있습니다.
후보 필터와 선택 상태
노드가 많은 제공자는 필터를 이용해 후보 범위를 좁힐 수 있지만, 필터 적용 후에도 결과가 남아 있는지 확인해야 합니다. 정규식의 특수 문자와 YAML 따옴표 규칙이 함께 적용되므로 노드 이름을 정규식으로 복사하면 괄호, 더하기 기호, 대괄호를 추가로 처리해야 할 수 있습니다. 트래픽을 보내고 나서 빈 그룹의 원인을 찾기보다 먼저 클라이언트에서 후보 목록을 미리 확인하세요. 구독의 이름 규칙이 계속 같다고 가정해서도 안 됩니다. 노드 이름이 바뀌면 기존 필터가 작동하지 않을 수 있습니다.
클라이언트나 profile.store-selected 같은 기능이 수동 그룹의 선택 상태를 저장할 수 있습니다. 파일을 다시 로드한 뒤에도 이전 선택이 유지된다고 해서 설정이 적용되지 않은 것은 아닙니다. 이전 런타임 상태를 복원했을 수 있습니다. 후보를 추가했는데 화면에서 자동으로 선택되지 않으면 현재 그룹에서 실제로 선택된 항목을 확인하세요. 반대로 현재 노드를 삭제하면 커널이나 클라이언트가 다른 사용 가능한 후보를 고를 수 있으므로 목록의 첫 번째 항목만 보고 최종 출구를 판단하지 마세요.
프록시 그룹을 점검할 때는 먼저 규칙이 어느 그룹에 적용됐는지 확인한 다음, 최종 노드나 내장 정책이 나올 때까지 그룹이 참조하는 다음 단계를 펼쳐 보세요. 로그에 그룹 이름만 보이고 이후 참조 관계를 확인하지 않으면 노드 문제를 규칙 문제로 오해하기 쉽습니다. 여러 자동 그룹을 겹겹이 중첩하지 말고 명확한 수동 테스트 경로를 하나 유지하세요. 운영체제별 클라이언트를 다시 비교하려면 선택 가이드를 확인하세요. 화면에 그룹을 표시하는 방식이 달라도 내부 참조 관계는 바뀌지 않습니다.
6. 규칙 문법: 매칭 유형, 순서, 규칙 제공자
위에서부터 확인하며 처음 일치하는 규칙을 적용합니다
rules는 순서가 있는 목록입니다. 커널은 연결을 차례로 확인하고 적용 가능한 규칙과 일치하면 해당 규칙의 정책으로 연결을 넘기며, 더 구체적으로 보이는 다음 규칙을 계속 찾지 않습니다. 따라서 특정 서비스의 예외 규칙은 일반 규칙보다 앞에 두고, 최종 대체 규칙은 마지막에 배치합니다. 규칙 순서는 문서 서식이 아니라 실제 실행 로직입니다. 광범위한 규칙을 맨 위로 옮기면 뒤에 있는 많은 항목이 적용되지 않을 수 있습니다.
rules:
- DOMAIN,api.example.com,DIRECT
- DOMAIN-SUFFIX,github.com,Proxy
- DOMAIN-KEYWORD,example,DIRECT
- IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
- GEOIP,CN,DIRECT
- MATCH,Proxy
일반적으로 규칙은 유형, 매칭 값, 정책으로 구성되며 영문 쉼표로 구분합니다. MATCH는 매칭 값 없이 최종 정책을 지정합니다. 정책은 DIRECT, REJECT 같은 내장 값이나 이미 정의된 프록시 그룹 또는 노드 이름을 사용할 수 있습니다. 영문 쉼표를 한국어 쉼표로 바꾸거나 정책 이름 뒤에 설명을 덧붙이지 마세요. 예제의 Proxy는 프록시 그룹 이름과 정확히 일치해야 합니다. 그렇지 않으면 규칙 구조가 맞아 보여도 참조가 제대로 작동하지 않습니다.
도메인 규칙과 IP 주소 규칙의 범위
DOMAIN은 전체 도메인과 일치하고, DOMAIN-SUFFIX는 해당 도메인과 하위 도메인을 매칭하며, DOMAIN-KEYWORD는 도메인에 포함된 키워드를 기준으로 매칭합니다. 범위를 제어하기 어려운 키워드 규칙을 무작정 쓰기보다 접미사 규칙을 사용하는 편이 안전합니다. 규칙에는 호스트명을 입력해야 하며 프로토콜, 경로, 쿼리 매개변수를 포함한 전체 URL을 넣으면 안 됩니다. 같은 사이트의 특정 페이지 경로만 구분하려 해도 일반 도메인 규칙으로는 처리할 수 없습니다. 프록시 라우팅은 암호화된 연결 내부의 요청 경로를 볼 수 없는 경우가 많기 때문입니다.
IP-CIDR은 대상 IPv4 네트워크를 기준으로 매칭하고, IPv6 네트워크에는 해당하는 IP-CIDR6 규칙을 사용할 수 있습니다. 선택 사항인 no-resolve는 이 주소 규칙을 확인하기 위해 도메인 조회를 새로 시작하지 말라는 뜻이지, 연결에서 도메인을 영구히 해석하지 말라는 뜻은 아닙니다. 연결에 사용할 수 있는 대상 주소가 이미 있으면 주소 규칙을 계속 확인할 수 있습니다. 불필요한 조회를 피하는 데 유용하지만 도메인 정보만 있는 연결이 네트워크 규칙을 건너뛸 수도 있으므로 실제 트래픽에 맞춰 이해해야 합니다.
GEOIP는 IP 주소 데이터베이스를, GEOSITE는 도메인 분류 데이터를 사용합니다. 이 분류는 데이터베이스가 관리하는 범주이지 서비스의 영구적인 속성이 아닙니다. 여러 지역의 CDN을 사용하는 도메인은 IP 위치와 서비스 지역이 일치하지 않을 수 있습니다. 예상과 다르게 트래픽이 분기되면 먼저 도메인 규칙과 주소 규칙 중 무엇이 적용됐는지 확인한 뒤 데이터 파일이 있는지, 업데이트가 성공했는지 살펴보세요. 처음부터 모든 노드를 바꾸거나 DNS를 끄는 것은 피하는 편이 좋습니다.
규칙 제공자와 behavior
rule-providers는 규칙 내용을 외부 파일로 분리하고, RULE-SET은 해당 규칙을 기본 규칙 체인에 연결합니다. 제공자의 behavior는 콘텐츠 형식을 정합니다. domain은 도메인 매칭 항목, ipcidr은 IP 네트워크, classical은 규칙 유형이 포함된 항목을 저장합니다. 필드 하나만 바꿔 서로 다른 형식을 전환할 수는 없으며 파일 내부 내용도 해당 형식에 맞아야 합니다. 원본이 일반 텍스트인지 YAML인지도 형식 설정과 일치해야 합니다.
rule-providers:
local-direct:
type: file
behavior: classical
format: yaml
path: ./rules/local-direct.yaml
rules:
- RULE-SET,local-direct,DIRECT
- MATCH,Proxy
# ./rules/local-direct.yaml
payload:
- DOMAIN-SUFFIX,example.com
- IP-CIDR,192.168.0.0/16,no-resolve
규칙 세트 안에는 보통 최종 정책을 쓰지 않고 기본 설정의 RULE-SET에서 정책을 지정합니다. 위 예제는 규칙 세트 전체에 DIRECT를 적용해 기본 규칙 체인에서 출구를 제어합니다. 원격 규칙 업데이트가 실패해도 캐시가 계속 적용될 수 있으므로 규칙이 여전히 매칭된다고 해서 최신 상태라는 뜻은 아닙니다. 규칙을 검증하려면 대상을 하나 명확히 정하고 기존 연결을 닫은 뒤 다시 접속해 적용된 항목, 프록시 그룹, 최종 출구를 확인하세요. 기존 장기 연결은 규칙을 변경해도 새 순서에 따라 자동으로 다시 연결되지 않습니다.
7. TUN: 가상 네트워크 인터페이스, 라우팅, DNS 처리
TUN은 트래픽 진입 경로를 마련하며 규칙을 대신하지 않습니다
TUN은 가상 네트워크 인터페이스와 라우팅을 이용해 시스템 프록시를 사용하지 않는 트래픽도 커널로 보냅니다. mode와는 서로 다른 계층입니다. TUN은 트래픽을 어떻게 가져올지 정하고 규칙은 들어온 뒤 어떻게 처리할지 결정합니다. TUN을 켜도 규칙 모드를 계속 사용할 수 있으며, 라우팅 제외, 인터페이스 선택, 권한 문제로 일부 트래픽이 누락될 수 있습니다. 스위치 상태만 보고 트래픽 처리 성공을 판단하지 말고 대상 프로그램에서 발생한 연결이 커널 로그에 기록되는지 확인하세요.
tun:
enable: true
stack: mixed
auto-route: true
auto-detect-interface: true
dns-hijack:
- any:53
enable은 가상 인터페이스를 켜고, stack은 네트워크 스택 처리 방식을 지정합니다. auto-route는 관련 라우팅을 자동 설정하도록 요청하고, auto-detect-interface는 출구 인터페이스를 자동으로 찾습니다. mixed는 mihomo가 지원하는 스택 옵션 중 하나일 뿐 모든 운영체제에 가장 적합하다는 뜻은 아닙니다. 다른 스택의 지원 여부와 동작은 사용 중인 커널과 플랫폼을 기준으로 확인하세요. 문제를 해결할 때는 한 번에 스택 옵션 하나만 바꾸고 로그를 비교해 라우팅 변경과 스택 변경이 섞이지 않도록 하세요.
DNS 하이재킹과 암호화 DNS의 적용 범위
dns-hijack의 any:53은 해당 경로로 들어온 일반 DNS 포트 대상 조회를 가로채 커널 DNS에 전달합니다. 모든 암호화 DNS를 가로채는 범용 기능은 아닙니다. 앱이 HTTPS로 DNS 조회를 보내면 일반 암호화 연결처럼 보이므로 대상 포트가 다르다는 이유만으로 이 규칙이 자동 변환하지는 않습니다. 브라우저에서 별도 DNS 기능을 켰다면 커널 업스트림을 반복해서 수정하기보다 실제 조회 경로부터 확인하세요.
TUN과 DNS 모듈은 함께 사용하는 경우가 많지만 두 설정은 서로 다른 스위치입니다. DNS 모듈이 꺼져 있거나 리슨 충돌이 나거나 업스트림에 연결할 수 없으면 트래픽을 가져왔어도 도메인을 해석하지 못할 수 있습니다. 반대로 DNS 조회 성공만으로 서비스 라우팅이 정상이라고 볼 수는 없습니다. 주소 하나와 도메인 하나를 각각 테스트해 주소 연결 실패와 이름 해석 실패를 구분한 다음 정책, 출구, 라우팅을 확인하세요.
플랫폼별 권한과 라우팅 충돌
데스크톱 운영체제에서 인터페이스를 만들고 라우팅을 수정하려면 관리자 권한, 특권 서비스 또는 별도의 시스템 승인이 필요한 경우가 많습니다. 클라이언트가 이런 권한을 대신 관리할 수 있지만 YAML을 직접 수정해 시스템 승인 절차를 대체할 수는 없습니다. Android 클라이언트는 일반적으로 VpnService로 트래픽 처리 권한을 얻으며, 시스템에 표시되는 VPN 승인 방식은 데스크톱 가상 인터페이스와 완전히 같지 않습니다. iOS 클라이언트는 자체 지원하는 네트워크 확장 기능으로 동작하므로 데스크톱 필드를 모바일 화면에 그대로 옮기지 마세요.
| 증상 | 우선 확인할 항목 | 다음 단계 |
|---|---|---|
| 가상 인터페이스 생성 실패 | 시스템 권한, 서비스 상태 | 커널 시작 오류 확인 |
| 도메인 접속 실패, IP 주소는 접속 가능 | DNS 모듈과 조회 경로 | DNS 조회 로그 비교 |
| 사내 네트워크 접속 불가 | 사내 라우팅과 다른 VPN | 네트워크 대역 제외 설정 확인 |
| 절전 모드 해제 후 연결 이상 | 인터페이스 변경과 기존 연결 | 출구 인터페이스를 다시 확인하고 재테스트 |
회사 VPN, 가상 머신 네트워크, 컨테이너 브리지, 다른 프록시 도구가 동시에 라우팅을 변경할 수 있습니다. 자동 감지가 잘못된 인터페이스를 선택하면 우회나 루프가 발생할 수 있습니다. 먼저 다른 네트워크 트래픽 처리 도구를 종료하고 현재 라우팅 정보를 저장한 뒤 클라이언트 하나만 켜서 테스트하세요. 여러 도구를 함께 사용해야 한다면 회사 VPN에 맡길 네트워크 대역과 프록시 커널에 맡길 트래픽을 명확히 정하세요. 반복해서 재시작하며 해결되기를 기대하면 다음에 네트워크 어댑터 순서가 바뀌었을 때 문제가 다시 생길 수 있습니다.
라우팅 제한을 강화하면 LAN 접속, 핫스팟 공유, 다른 VPN의 동작이 달라질 수 있으므로 관련 스위치를 만능 해결책처럼 사용하지 마세요. 먼저 최소한의 TUN 설정을 구성한 뒤 확인된 문제에 따라 제외 항목이나 플랫폼 옵션을 추가하세요. 절전 모드에서 복귀하거나 네트워크를 전환한 뒤에는 시스템 프록시와 가상 인터페이스가 예상한 상태로 복구됐는지 확인해야 합니다. 구체적인 설정 절차는 TUN 원리와 트래픽 처리 방법을 참고하세요. Android에서 백그라운드 앱이 시스템에 의해 종료된다면 VpnService와 배터리 최적화 제외 안내를 확인하세요. 이런 문제의 원인이 반드시 YAML인 것은 아닙니다.
8. 오버라이드, 병합, 런타임 검증
먼저 설정 출처를 확인하고 병합 방식을 정하세요
오버라이드는 클라이언트가 구독 또는 로컬 설정을 불러올 때 일부 필드를 바꾸거나 보완하고 재구성하는 과정입니다. YAML에 공통으로 포함된 기능이 아니며 모든 Clash 클라이언트가 같은 병합 순서를 사용하는 것도 아닙니다. 같은 이름의 화면 항목이라도 클라이언트에 따라 얕은 교체, 재귀 병합, 스크립트 처리로 동작할 수 있습니다. 수정하기 전에 해당 클라이언트의 오버라이드 안내를 확인하고 현재 설정에만 적용되는지 전체 설정에 적용되는지, 구독 업데이트 후에도 다시 실행되는지 살펴보세요.
매핑과 목록은 특히 따로 확인해야 합니다. DNS 객체를 재귀 병합하면 수정하지 않은 업스트림 필드가 유지될 수 있지만, 객체 전체를 교체하면 기존 설정이 사라집니다. 규칙 목록을 교체하면 구독의 기존 트래픽 분기가 없어질 수 있습니다. 반대로 규칙을 뒤에 추가하면 기존 MATCH가 먼저 모든 연결을 처리해 새 규칙이 적용되지 않을 수 있습니다. 노드와 프록시 그룹 목록은 이름 참조도 포함하므로 파일 두 개를 단순히 이어 붙인 결과가 유효하다고 볼 수 없습니다.
# 원본 설정의 DNS 객체
dns:
enable: true
enhanced-mode: fake-ip
nameserver:
- https://dns.alidns.com/dns-query
# 클라이언트 오버라이드로 적용할 필드 조각
# 별도의 입력입니다. 두 번째 dns 키로 그대로 추가하면 안 됩니다.
# dns:
# ipv6: false
위 예제에서 의도한 결과는 원래 DNS 객체의 활성화 상태, 조회 모드, 업스트림을 삭제하지 않고 ipv6: false를 추가하는 것입니다. 실제로 이렇게 병합할 수 있는지는 클라이언트 구현에 따라 다릅니다. 저장한 뒤 런타임 미리보기를 열어 네 필드가 모두 있는지 확인하세요. 클라이언트가 전체 객체 교체만 지원한다면 오버라이드에 유지할 필드를 모두 명시해 네트워크 사용에 필요한 동작을 암묵적인 처리에 맡기지 마세요.
구독 업데이트와 로컬 수정 내용의 저장 위치
구독에서 내려받은 캐시 파일을 직접 편집하면 다음 업데이트 때 원격 콘텐츠로 덮어써지는 경우가 많습니다. 더 안정적인 방법은 개인 규칙, DNS 설정, 포트 구성을 클라이언트가 지원하는 영구 오버라이드에 넣거나, 별도의 로컬 설정을 관리한 뒤 제공자로 원격 노드를 참조하는 것입니다. 두 방법 모두 비용이 따릅니다. 전자는 클라이언트의 병합 방식에 의존하고, 후자는 프록시 그룹과 규칙을 직접 관리해야 합니다. 어느 쪽을 선택하든 구독에서 관리할 필드와 로컬에서 관리할 필드를 먼저 정하세요.
노드나 프록시 그룹 이름을 바꿀 때는 이름을 여러 설정 영역에서 참조하는 인터페이스로 취급해야 합니다. 최종 노드와 그룹을 먼저 구성한 뒤 규칙의 대상이 올바른지 확인하세요. 객체를 삭제하기 전에는 다른 그룹에서 참조하는지도 검색해야 합니다. 구독 변환 서비스는 이름, 규칙, 그룹을 다시 만들 수 있으므로 변환 전후의 텍스트는 같은 구조가 아닙니다. 민감한 구독 주소를 다룰 때는 신뢰할 수 있는 로컬 처리 방식을 우선 사용하고 설정을 공유하기 전에 주소의 인증 정보를 삭제하세요.
문법 테스트, 로드 확인, 연결 재테스트
명령줄 커널을 사용할 수 있다면 테스트 옵션으로 현재 바이너리가 설정을 읽을 수 있는지 확인할 수 있습니다. 테스트에는 클라이언트에서 실제 사용하는 것과 같은 커널 및 관련 데이터 디렉터리를 사용해야 합니다. 다른 실행 파일에서 테스트를 통과했다고 해서 그래픽 클라이언트의 커널도 해당 필드를 지원한다는 뜻은 아닙니다. 제공자 파일과 지리 데이터가 필요하면 테스트 환경에서 해당 항목을 읽을 수 있는지도 확인하세요. 테스트는 설정 문제를 찾는 데 도움을 줄 뿐 실제 네트워크 연결 검증을 대신하지 않습니다.
mihomo -t -f ./config.yaml
검증은 네 단계로 진행할 수 있습니다. 먼저 백업하고 문법을 테스트한 다음 클라이언트에서 설정을 다시 로드합니다. 이어서 로그에서 새 설정을 정상적으로 적용했는지 확인하고 마지막으로 기존 연결을 닫은 뒤 대상을 테스트합니다. 런타임 파일을 보면 필드가 유지됐는지 확인할 수 있고 연결 기록을 보면 규칙과 출구가 예상대로 적용됐는지 알 수 있습니다. 저장 버튼만 누르고 다시 로드하지 않았거나 현재 설정이 편집 중인 파일이 아니라면 네트워크 동작은 바뀌지 않습니다.
수정 기록을 남겨 두면 유용합니다. 이번에 바꾼 필드, 기대한 결과, 실제 결과, 복구 방법을 적어 두세요. 한 번에 한 계층만 수정하고 검증을 마친 뒤 다음 단계로 넘어가세요. 상세 로그는 문제 해결 중에만 켜고 공유 전에 구독 자격 증명, 서버 인증 정보, 불필요한 접속 기록을 삭제하세요. 클라이언트 상태 자체에 문제가 있다면 사용 가이드로 돌아가 가져오기, 모드, 연결 절차를 다시 확인하세요. 클라이언트를 바꿔야 한다면 그다음에 설치 파일 페이지에서 플랫폼에 맞는 항목을 선택하세요. 모든 문제를 설정 파일 손상 탓으로 돌리지 마세요.