Clash config.yaml 구조 분석: port부터 rules까지 설정 순서
일반 설정, dns, proxies, proxy-groups, rules를 파일 순서대로 살펴보고 들여쓰기 규칙과 각 섹션의 참조 관계를 설명합니다.
먼저 구조부터: 다섯 설정 섹션은 어떻게 연결될까
설정을 읽을 때는 먼저 진입점을 확인한 다음 DNS, 노드, 정책 그룹, 규칙을 점검하세요.config.yaml은 위에서 아래로 실행되는 스크립트가 아닙니다. 최상위 필드는 보통 순서를 바꿔도 되지만, 목록 안의 순서는 동작에 직접 영향을 줄 수 있으며 특히 rules가 그렇습니다. 파일을 다섯 섹션으로 나누는 것은 읽기와 문제 해결을 쉽게 하기 위한 것이지, 코어가 다섯 단계를 차례로 실행한다는 뜻은 아닙니다.
이 문서에서는 Clash 설정 형식을 사용하는 mihomo 코어를 기준으로 설명합니다. Clash 클라이언트는 그래픽 인터페이스를 제공하고, 코어는 설정을 파싱해 연결을 처리합니다. 클라이언트에 따라 port, DNS, TUN 등의 설정을 병합하거나 덮어쓸 수 있습니다. 따라서 편집하기 전에 현재 사용하는 코어와 수정 대상이 구독 원본 파일인지, 오버라이드 파일인지, 아니면 클라이언트가 코어에 최종 전달하는 실행 설정인지 확인해야 합니다.
| 설정 섹션 | 주요 역할 | 연관 항목 |
|---|---|---|
| 일반 설정 | 수신 포트, 실행 모드, 로그 수준 설정 | 프록시 설정 적용 및 클라이언트 옵션 |
dns | 코어 DNS의 조회 방식과 업스트림 설정 | 도메인 조회, Fake-IP, DNS 가로채기 |
proxies | 프록시 노드의 연결 매개변수 정의 | 정책 그룹에서 참조하는 구성원 이름 |
proxy-groups | 노드와 다른 정책을 묶어 선택 가능한 출구 제공 | 규칙에서 대상으로 지정하는 이름 |
rules | 연결을 순서대로 매칭해 처리 대상을 지정 | 정책 그룹, 노드 또는 내장 정책 |
가장 흔한 참조 구조는 rules가 정책 그룹을 가리키고, 정책 그룹이 노드 이름을 참조하며, 노드가 최종적으로 서버 주소와 포트, 인증 정보를 제공하는 방식입니다. DIRECT와 REJECT는 내장 정책이므로 proxies에 따로 정의할 필요가 없습니다.
일반 설정: port, 모드, 수신 범위
프록시 포트 세 개가 노드 세 개를 뜻하지는 않습니다
port는 HTTP 프록시가 요청을 받는 포트이며 일반적인 HTTPS CONNECT 터널도 지원합니다. socks-port는 SOCKS 프록시 수신 포트이고, mixed-port는 하나의 포트에서 HTTP와 SOCKS 프록시 요청을 모두 받습니다. 모두 로컬 진입점이며 원격 노드의 port와는 다릅니다.
port: 7890
socks-port: 7891
mixed-port: 7892
allow-lan: false
bind-address: "127.0.0.1"
mode: rule
log-level: info
ipv6: false
이 설정은 필드 간 관계를 보여주기 위해 포트 세 개를 각각 사용하지만, 실제로 모두 켤 필요는 없습니다. 혼합 진입점만 필요하다면 mixed-port: 7892만 남기면 됩니다. 브라우저나 시스템 HTTP 프록시에는 127.0.0.1:7892를 입력하면 되고, SOCKS를 지원하는 앱도 같은 혼합 포트에 연결할 수 있습니다. 코어 포트를 바꾼 뒤에는 앱 설정도 함께 변경해야 합니다. 앱이 이전 포트인 7890에 계속 연결하지 않도록 확인하세요.
mode와 allow-lan의 역할
mode: rule: 규칙 목록에 따라 트래픽을 분기합니다. 도메인이나 IP별로 출구를 나누는 일반적인 사용에 적합합니다.mode: global: 주로 글로벌 정책을 통해 출구를 선택하며, 일반 규칙 목록을 하나씩 적용해 분기하지 않습니다.mode: direct: 직접 연결 모드를 사용합니다. 클라이언트를 끄거나 시스템 프록시를 해제하는 것과는 다릅니다.allow-lan: false: 로컬 네트워크 기기에서 프록시 진입점에 연결할 수 없게 합니다. 공유가 필요할 때만 수신 주소, 인증, 방화벽을 추가로 설정하세요.
dns: 업스트림 조회와 트래픽 가로채기
dns 섹션은 코어의 도메인 조회 설정을 담당합니다. 하지만 ‘코어 DNS 활성화’와 ‘시스템의 모든 DNS 요청을 코어로 전달’은 서로 다른 작업입니다. 다음 예시는 로컬 1053 포트에서 DNS 요청을 받고, Fake-IP 모드와 일반 DNS 업스트림을 사용합니다.
dns:
enable: true
listen: "127.0.0.1:1053"
ipv6: false
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
nameserver:
- 223.5.5.5
fake-ip-filter:
- "*.lan"
- "localhost"
구분해야 할 네 가지 필드
listen은 코어가 DNS 요청을 받는 주소와 포트이며, 업스트림 서버 주소가 아닙니다. 일반적인 시스템 DNS 설정에는1053같은 사용자 지정 포트를 직접 입력할 수 없는 경우가 많습니다.nameserver는 DNS 조회에 사용할 업스트림입니다. 예시에서는 일반 DNS를 사용합니다. 실제 연결 가능 여부와 조회 결과가 현재 네트워크에 적합한지는 환경에 따라 확인해야 합니다.enhanced-mode: fake-ip를 사용하면 코어가 해당되는 경우 가상 주소를 반환하고 도메인과 주소 간 매핑을 저장합니다. 이 주소는 웹사이트의 실제 공인 IP가 아닙니다.fake-ip-filter에는 Fake-IP로 응답하지 않을 도메인 범위를 지정합니다. 로컬 네트워크 이름이나 특정 호환성 문제를 처리할 때 사용합니다.
TUN을 사용할 때는 클라이언트나 설정에서 DNS 가로채기, 라우팅 처리 등의 옵션을 구성해 요청을 코어로 전달해야 합니다. dns.enable: true만 설정한다고 시스템 라우팅이 자동으로 바뀌지는 않습니다. 시스템 프록시만 켜도 모든 앱의 DNS 조회가 코어를 거친다고 보장할 수 없습니다. 앱에 내장된 암호화 DNS는 별도의 조회 경로를 사용할 수도 있습니다.
업스트림을 https://dns.alidns.com/dns-query처럼 도메인 이름을 사용하는 DoH 주소로 바꾼다면 업스트림 도메인을 어떻게 조회할지도 고려해야 합니다. mihomo의 default-nameserver는 이런 초기 조회에 사용할 수 있고, proxy-server-nameserver는 프록시 노드 도메인을 조회하는 데 사용합니다. 두 필드를 같은 의미로 취급하지 말고, 연결 경로를 파악하지 않은 상태에서 여러 단계의 DNS 전달을 겹쳐 설정하지 마세요.
proxies: 노드 정의와 구독 파일 관리
proxies는 노드 객체의 목록입니다. 노드마다 보통 name, type, server, port가 포함되며, 나머지 인증 및 전송 필드는 프로토콜에 따라 다릅니다. 원격 노드의 포트는 443이나 서버에서 지정한 다른 값일 수 있습니다. 로컬 프록시 수신 포트가 7890이라고 해서 노드 포트까지 7890으로 바꾸면 안 됩니다.
노드를 편집할 때는 필드별 출처를 확인하세요
- 먼저
type이 서버에서 사용하는 프로토콜과 일치하는지 확인하세요. 지원 프로토콜은 코어 버전에 따라 달라지며, 파일을 가져올 수 있다고 해서 모든 프로토콜로 연결할 수 있는 것은 아닙니다. - 서버 주소, 비밀번호, UUID, 암호화 방식 등 연결 정보는 서비스 제공자가 안내한 설정을 기준으로 입력해야 합니다. 필드 이름만 보고 값을 추측하지 마세요.
- 전송 계층, TLS, 인증서 이름은 서버 설정과 일치해야 합니다. 인증서 오류가 발생하면 인증 검증을 바로 끄기보다 도메인 이름과 시스템 시간을 먼저 확인하세요.
name은 고유한 값으로 지정하는 것이 좋습니다. 정책 그룹은 이 이름으로 노드를 참조하므로 노드 이름을 바꾸면 관련 참조도 함께 수정해야 합니다.
노드가 없어도 유효한 설정을 작성할 수 있습니다. proxies: []는 빈 목록을 뜻합니다. 파일 구조를 검증할 때는 유용하지만, 프록시 출구가 저절로 생기지는 않습니다. 이후의 전체 예시는 빈 목록과 DIRECT를 사용하므로 설정 로드와 규칙 연결을 확인하는 용도로만 사용할 수 있습니다.
proxy-groups: 이름 참조와 정책 선택
정책 그룹은 노드, 내장 정책 또는 다른 정책 그룹을 묶어 참조 가능한 출구로 만듭니다. 아래 예시는 수동 선택 그룹을 정의하며, 내장 정책인 직접 연결과 거부만 구성원으로 사용하므로 노드 인증 정보가 필요하지 않습니다.
proxy-groups:
- name: "출구 선택"
type: select
proxies:
- DIRECT
- REJECT
type: select는 구성원을 수동으로 선택한다는 뜻입니다. 클라이언트의 프록시 화면에서 DIRECT를 선택하면 ‘출구 선택’을 참조하는 규칙이 직접 연결을 사용하고, REJECT를 선택하면 해당 연결을 거부합니다. 규칙이 사라지는 것이 아니라 그룹에서 선택한 항목에 따라 같은 규칙 대상의 실제 동작이 달라지는 것입니다.
자주 사용하는 정책 그룹 유형 세 가지
| 유형 | 용도 | 설정 시 확인할 항목 |
|---|---|---|
select | 구성원을 수동으로 선택 | 구성원이 존재하고 현재 선택이 의도한 값인지 확인 |
url-test | 연결 테스트 결과를 기준으로 자동 선택 | 테스트 URL과 간격, 후보 노드의 사용 가능 여부 확인 |
fallback | 후보 순서에 따라 사용 가능한 구성원 선택 | 구성원 순서와 상태 확인 설정 |
자동 테스트 결과는 지정한 테스트 주소까지의 측정값이며, 모든 웹사이트에서의 실제 다운로드 속도를 뜻하지는 않습니다. 구조를 파악하는 것이 목적이라면 먼저 select로 참조 관계를 확인하는 편이 간단합니다. 정책 그룹을 중첩할 때는 A가 B를 참조하고 B가 다시 A를 참조하는 순환 의존성도 피해야 합니다.
설정에서 proxy-providers를 사용한다면 정책 그룹은 보통 use로 제공자 이름을 참조합니다. 제공자 이름을 proxies 목록에 넣는 방식이 아닙니다. 두 필드는 서로 다른 객체를 가리킵니다. ‘프록시를 찾을 수 없음’ 오류가 발생하면 노드, 정책 그룹, 노드 제공자 중 무엇을 참조하고 있는지 먼저 확인하세요.
rules: 구체적인 규칙부터 적용하고 마지막에 기본 규칙 배치
규칙 모드에서는 연결을 목록 순서대로 비교하고, 먼저 일치하는 규칙의 대상을 사용합니다. 설정에서 사용하는 정책 이름은 대소문자, 공백, 한글까지 앞에서 정의한 이름과 정확히 일치해야 합니다. 아래 네 규칙은 로컬 네트워크 도메인, 예시 도메인, 사설 주소, 나머지 연결을 각각 처리합니다.
rules:
- DOMAIN-SUFFIX,lan,DIRECT
- DOMAIN-SUFFIX,example.org,출구 선택
- IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
- MATCH,출구 선택
DOMAIN-SUFFIX,lan,DIRECT는lan과 그 하위 도메인을 매칭합니다. 문자열에 ‘lan’이 포함되어 있기만 한 경우에는 매칭되지 않습니다.DOMAIN-SUFFIX,example.org,출구 선택은 예시 도메인과 그 하위 도메인을 ‘출구 선택’으로 보냅니다.example.org는 규칙 문법을 설명하기 위한 예시입니다.IP-CIDR,192.168.0.0/16,DIRECT,no-resolve는 이 사설 IPv4 대역을 매칭합니다.no-resolve는 해당 규칙을 매칭하기 위해 도메인을 별도로 조회하지 않는다는 뜻입니다.MATCH,출구 선택은 앞선 규칙에 매칭되지 않은 연결을 처리하므로 목록의 마지막에 배치해야 합니다.
no-resolve는 설정 전체의 DNS를 끄거나 연결에서 DNS 조회가 절대 발생하지 않도록 하는 옵션이 아닙니다. 관련 IP 규칙이 조회를 새로 수행할지에만 영향을 줍니다. 대상 IP가 이미 있는 연결은 계속 IP 규칙과 비교할 수 있습니다.
MATCH,DIRECT를 첫 줄에 배치하면 이후 규칙은 이미 처리된 연결에 적용되지 않습니다. 도메인 예외를 더 세밀하게 지정하려면 범위가 넓은 접미사 규칙보다 앞에 배치하세요. GEOIP, GEOSITE, RULE-SET을 사용할 때는 해당 지리 데이터베이스나 규칙 제공자를 사용할 수 있는지도 확인해야 합니다. 데이터 출처를 무시한 채 규칙만 복사해서는 안 됩니다.
전체 구조: 두 칸 들여쓰기와 최소 설정
아래 설정에는 외부 노드가 없으며, 매칭된 트래픽은 DIRECT만 구성원으로 둔 정책 그룹으로 전달됩니다. YAML 구조와 수신 포트, 그룹 이름 참조를 먼저 검증하기 위한 예시입니다. 원격 프록시 연결 기능을 바로 제공하는 구독 설정은 아니며 TUN도 활성화하지 않습니다. 코어 DNS는 127.0.0.1:1053에서 요청을 받지만, 시스템 DNS 요청을 전달하려면 시스템이나 클라이언트 설정이 추가로 필요합니다.
mixed-port: 7890
allow-lan: false
bind-address: "127.0.0.1"
mode: rule
log-level: info
ipv6: false
dns:
enable: true
listen: "127.0.0.1:1053"
ipv6: false
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
nameserver:
- 223.5.5.5
fake-ip-filter:
- "*.lan"
- "localhost"
proxies: []
proxy-groups:
- name: "출구 선택"
type: select
proxies:
- DIRECT
rules:
- DOMAIN-SUFFIX,lan,DIRECT
- IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
- MATCH,출구 선택
YAML에서 자주 발생하는 실수 네 가지
- Tab으로 들여쓰기. 공백만 사용하고, 위 예시처럼 각 단계마다 공백 두 칸을 추가하세요. 같은 수준의 필드는 열을 맞춰야 합니다.
- 최상위 필드를 앞 섹션 안으로 들여쓰기.
proxies,proxy-groups,rules는 모두 줄 맨 앞에서 시작해야 하며dns아래에 들여쓰면 안 됩니다. - 목록 항목의 하이픈을 빠뜨리기.
nameserver, 정책 그룹 구성원, 규칙은 모두 목록 형식입니다. 각 항목은-로 시작해야 합니다. - 같은 최상위 키를 여러 번 정의하기. 파일 끝에 두 번째
dns나rules섹션을 추가하지 마세요. 기존 위치에 합쳐야 중복 키를 파서마다 다르게 처리하는 문제를 피할 수 있습니다.
이름에 #이나 콜론 뒤 공백처럼 특수한 내용이 있으면 주석이나 매핑 문법으로 잘못 해석되지 않도록 따옴표로 감싸세요. 일반적인 규칙 문자열은 한글 이름이 포함되어도 따옴표가 필요하지 않지만, 문자열 전체를 표준 따옴표로 감싸도 됩니다. 웹페이지에서 사용하는 전각 콜론 ‘:’을 YAML의 반각 콜론 :과 혼동하지 마세요.
로드 검증: 문법 확인부터 실제 연결까지
설정을 저장했다는 것은 편집기가 파일을 기록했다는 뜻일 뿐입니다. 코어가 설정을 로드해도 구조와 필수 필드를 통과했다는 의미에 그칩니다. 노드 연결 여부, DNS 요청의 경로, 앱의 프록시 사용 여부는 각각 따로 확인해야 합니다.
네 단계로 확인하세요
- 현재 정상 작동하는 파일을 백업한 뒤 별도의
config.yaml로 복사해 편집하세요. 한 번에 설정 섹션 하나만 변경하면 문제가 생겼을 때 쉽게 되돌릴 수 있습니다. - 현재 실제로 실행 중인 mihomo 바이너리로 설정을 테스트하세요. Linux나 macOS에서 바이너리가 현재 디렉터리에 있다면 아래 명령을 실행할 수 있습니다.
- 클라이언트에서 설정을 다시 불러오거나 활성화한 뒤 로그에 포트 충돌, 존재하지 않는 이름 참조, 누락된 규칙 데이터 등의 오류가 있는지 확인하세요.
- 프록시를 명시한 요청으로 진입점을 테스트하고, 클라이언트의 연결 기록에서 적용된 규칙과 정책 경로를 확인하세요. 마지막으로 시스템 프록시나 TUN의 전체 트래픽 처리 여부를 검증합니다.
./mihomo -t -f ./config.yaml
curl --proxy http://127.0.0.1:7890 --head https://example.org/
설정에서 상대 경로의 규칙 파일, 노드 제공자, 데이터베이스를 사용한다면 테스트에도 실제 실행 환경과 같은 작업 디렉터리를 지정해야 합니다. 코어의 -d 매개변수로 설정 작업 디렉터리를 지정할 수 있습니다. 명령을 찾을 수 없다면 YAML 필드를 변경하기 전에 바이너리 경로부터 확인하세요. 위의 curl 요청은 지정한 HTTP 프록시 진입점과 대상 주소 접속만 확인합니다. UDP, 시스템 DNS, TUN이 정상 작동한다는 증거로는 충분하지 않습니다.