Clash 사용자 지정 규칙 문법과 우선순위: DOMAIN-SUFFIX, IP-CIDR, MATCH 매칭 순서
rules 섹션 작성법과 매칭 순서를 하나씩 분석합니다. DOMAIN, DOMAIN-SUFFIX, IP-CIDR부터 GEOIP, MATCH 폴백까지 위에서 아래로 이어지는 단락 매칭 원리와 흔한 실수를 정리했습니다.
rules 섹션의 3단 구조와 위에서 아래로 이어지는 단락 매칭
Clash와 mihomo의 규칙은 모두 설정 최상위의 rules: 배열에 작성합니다. 각 규칙은 YAML 목록 항목 하나이며, 구조는 규칙 유형,매칭 값,정책 이름 세 부분으로 고정됩니다. 첫 번째 부분은 어떤 방식으로 매칭할지 결정하고, 두 번째는 매칭 대상, 세 번째는 매칭되었을 때 나갈 출구입니다. 출구에는 DIRECT(직접 연결), REJECT(차단)를 쓸 수 있고, proxy-groups에 정의해 둔 임의의 정책 그룹 이름도 사용할 수 있습니다. 일부 유형은 네 번째 인자를 받으며, 현재 가장 많이 쓰이는 것은 no-resolve입니다.
rules:
- DOMAIN,api.github.com,Proxy
- DOMAIN-SUFFIX,github.com,Proxy
- IP-CIDR,10.0.0.0/8,DIRECT,no-resolve
- GEOIP,CN,DIRECT
- MATCH,Proxy
매칭 과정은 위에서 아래로 진행되는 단락 매칭입니다. 커널은 첫 번째 규칙부터 차례로 비교하고, 한 번 매칭되면 즉시 끝나 뒤의 규칙은 더 이상 참여하지 않습니다. 즉, 규칙 순서 자체가 우선순위이며, 커널이 특정 규칙을 더 구체적이라는 이유로 자동으로 앞당겨 주지는 않습니다. DOMAIN-SUFFIX,github.com,Proxy를 DOMAIN,api.github.com,DIRECT보다 앞에 두면 후자는 절대 적용되지 않습니다.
MATCH는 매칭 값이 없어 모든 트래픽이 여기에 걸립니다. 규칙 목록 중간에 들어가면 그 뒤의 모든 규칙이 실행되지 않는 죽은 코드가 됩니다. 규칙을 수정한 뒤에는 이 항목부터 확인하세요.
정책 이름은 proxy-groups에 정의된 이름과 대소문자까지 정확히 일치해야 합니다. 그대로 쓸 수 있는 것은 DIRECT와 REJECT뿐이고, 나머지는 모두 사용자 정의 그룹 이름입니다.
도메인 규칙: DOMAIN, DOMAIN-SUFFIX, DOMAIN-KEYWORD의 경계
도메인 규칙은 세 단계로 나뉘고 매칭 범위가 차례로 넓어집니다. 작성 전에 단일 호스트를 덮을지, 사이트 전체를 덮을지 먼저 확인하세요:
| 작성법 | 매칭 예 | 비매칭 예 |
|---|---|---|
DOMAIN,api.github.com |
api.github.com | github.com、cdn.api.github.com |
DOMAIN-SUFFIX,github.com |
github.com、api.github.com | raw.githubusercontent.com、github.com.cn |
DOMAIN-KEYWORD,github |
github.com、githubassets.com、mygithub.io | gitlab.com |
DOMAIN은 정확히 같은 도메인만 인식하는 완전 일치입니다. DOMAIN-SUFFIX는 도메인 계층 경계를 기준으로 매칭합니다. github.com 자체와 .github.com으로 끝나는 호스트 이름은 매칭되지만 github.com.cn은 매칭되지 않습니다. 완전히 같지도 않고 .github.com으로 끝나지도 않기 때문입니다. 많은 사용자가 이를 문자열 접미사로 이해해 github.com.cn이나 notgithub.com이 이 규칙에 걸린다고 오해하지만, 실제로는 둘 다 걸리지 않습니다.
DOMAIN-KEYWORD는 순수 부분 문자열 매칭이라 github는 githubusercontent.com과 mygithub.io를 동시에 매칭합니다. 도메인 변형이 많고 접미사가 제각각인 서비스에 어울리지만, 키워드가 짧을수록 오탐이 커지므로 app, api, cloud 같은 단어는 키워드로 쓰지 않는 편이 좋습니다.
mihomo는 DOMAIN-REGEX도 지원해 정규식으로 복잡한 패턴을 표현할 수 있습니다. 연결마다 정규식을 한 번씩 실행하므로 규칙 수가 많으면 부담이 커지고, 보통 꼭 필요한 소수 상황에서만 사용합니다.
IP 규칙: IP-CIDR, GEOIP, no-resolve의 해석 비용
IP 규칙에는 IP-CIDR, IP-CIDR6, SRC-IP-CIDR, GEOIP가 있고 매칭 대상은 IP 주소입니다. 그런데 브라우저와 클라이언트가 시작하는 연결은 보통 도메인만 가지고 있으므로, 커널은 도메인 요청을 만나면 먼저 DNS 해석으로 IP를 얻은 뒤 이를 비교합니다.
이 해석에는 두 가지 부작용이 따릅니다. 연결마다 조회가 한 번씩 늘어나고, 해석 결과가 dns 섹션 설정에 좌우되어 규칙을 작성할 때의 예상과 어긋날 수 있습니다.
no-resolve는 이 동작을 꺼 줍니다. 이를 붙이면 현재 요청이 도메인을 가지고 있을 때 커널은 이 규칙과 매칭하려고 해석하지 않고 곧바로 불일치로 판정한 뒤 다음 규칙으로 넘어갑니다.
rules:
- IP-CIDR,127.0.0.0/8,DIRECT,no-resolve
- IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
- IP-CIDR,100.64.0.0/10,DIRECT,no-resolve
- IP-CIDR6,fc00::/7,DIRECT,no-resolve
- GEOIP,CN,DIRECT
- MATCH,Proxy
내부망 대역, 루프백 주소, 통신사 예약 대역은 대부분 IP 규칙으로 처리하며 no-resolve를 붙이면 추가 해석이 생기지 않습니다. GEOIP,CN,DIRECT 같은 규칙은 실제 IP를 얻어야 국가를 판별할 수 있으므로 보통 no-resolve를 붙이지 않고 정상적으로 해석을 유도합니다.
dns.enhanced-mode: fake-ip에서는 특히 주의해야 합니다. 애플리케이션이 받는 주소는 커널이 위조한 주소(기본값 198.18.0.1/16)로 실제 위치를 나타내지 않으므로 IP 규칙으로 매칭하면 안 됩니다. 도메인 규칙을 IP 규칙보다 앞에 두면 해석 한 단계를 줄일 수 있습니다.
GeoIP 데이터 파일이 없거나 로드에 실패하면 모든 GEOIP 규칙이 매칭되지 않고 트래픽이 MATCH까지 흘러내려, 중국 본토 사이트도 프록시를 타는 증상이 나타납니다. 규칙을 살펴보기 전에 데이터 파일이 제자리에 있는지 먼저 확인하세요.
포트, 프로세스, 출발지 대역: 세밀한 규칙 배치법
DST-PORT, SRC-PORT는 포트로 매칭하고, PROCESS-NAME, PROCESS-PATH는 연결을 시작한 프로세스로 매칭하며, SRC-IP-CIDR는 연결을 시작한 로컬 주소를 매칭합니다. 이런 규칙은 보통 도메인 규칙 뒤, MATCH 앞에 둡니다.
rules:
- PROCESS-NAME,Telegram.exe,Proxy
- PROCESS-PATH,/usr/bin/curl,Proxy
- SRC-IP-CIDR,192.168.1.0/24,DIRECT,no-resolve
- DST-PORT,22,DIRECT
- MATCH,Proxy
프로세스 규칙은 연결이 어느 프로세스에 속하는지 먼저 판별해야 하므로 단일 매칭 비용이 순수 도메인 비교보다 큽니다. 그래서 규칙 목록 앞쪽에 두는 편이 유리합니다. PROCESS-NAME은 Windows와 macOS에서 바로 쓸 수 있고, Linux에서는 프로세스 정보가 권한 제약을 받으므로 대부분 PROCESS-PATH가 더 안정적입니다.
SRC-IP-CIDR는 가상 머신 네트워크 어댑터나 Docker 브리지 같은 출발지 트래픽을 따로 직접 연결로 보낼 때 자주 쓰이며, no-resolve와 함께 사용합니다. 포트 규칙은 적용 범위가 매우 넓어 DST-PORT,22,DIRECT는 대상 포트가 22인 모든 연결에 영향을 줍니다. 작성 전에 뒤에서 프록시를 타야 할 트래픽을 잘라내지 않는지 확인하세요.
RULE-SET과 rule-providers: 규칙을 메인 설정 밖으로
규칙이 수백 개를 넘으면 메인 설정에 모두 쌓아 두는 것은 읽기도, 갱신하기도 어렵습니다. rule-providers로 규칙을 별도 파일로 분리하고 rules에서 RULE-SET으로 참조합니다:
rule-providers:
ad-block:
type: file
behavior: domain
path: ./ruleset/ad-block.yaml
rules:
- RULE-SET,ad-block,REJECT
- MATCH,Proxy
behavior는 파일 내용의 형식을 결정합니다. domain은 순수 도메인 목록, ipcidr은 대역 목록, classical은 완전한 규칙 문법입니다. RULE-SET 뒤의 이름은 rule-providers 아래 키와 정확히 일치해야 하며, 틀리면 설정 로드가 곧바로 오류를 냅니다.
규칙 집합을 원격에서 주기적으로 갱신해야 한다면 type을 http로 바꾸고 url과 interval 두 필드를 추가합니다. interval: 86400은 24시간마다 한 번 가져온다는 뜻입니다. 규칙 집합 파일이 손상되거나 형식이 맞지 않으면 해당 RULE-SET 전체가 무효가 되므로, MATCH 폴백을 제대로 작성해 두면 장애가 나도 동작이 최소한 예측 가능합니다.
자주 나오는 여섯 가지 실수와 로그 확인 경로
발생 빈도가 높은 순서대로 정리했으니 규칙이 적용되지 않을 때 차례로 대조해 보세요:
MATCH를 중간에 배치: 뒤의 모든 규칙이 무효가 되며, 문제를 찾을 때 가장 놓치기 쉬운 부분입니다.DOMAIN-SUFFIX를 문자열 접미사로 착각:github.com.cn,notgithub.com모두 매칭되지 않으므로 변형까지 덮으려면DOMAIN-KEYWORD나DOMAIN-REGEX로 바꿔야 합니다.DOMAIN-KEYWORD를 너무 넓게 사용: 짧은 키워드는 무관한 도메인까지 함께 매칭해 전체 연결을 프록시로 끌고 갑니다.- IP 규칙에
no-resolve누락: 도메인 연결마다 해석이 한 번씩 늘어 지연과 DNS 부하가 함께 커집니다. - 정책 이름 대소문자 불일치:
proxy-groups에서는Proxy인데 규칙에는proxy로 적으면 설정 검증이 실패합니다. - GeoIP 데이터 파일 누락:
GEOIP규칙이 모두 빗나가 트래픽이MATCH까지 흘러내립니다.
확인 경로: 설정에서 external-controller: 127.0.0.1:9090을 열고 대시보드에서 각 연결이 실제로 어떤 규칙에 매칭되는지 확인합니다. 커널 로그에는 match DomainSuffix(github.com) using Proxy 같은 기록이 출력되어 어느 규칙이 적용됐는지 바로 알려 줍니다. 규칙을 수정한 뒤 설정을 다시 로드하고 같은 연결을 한 번 더 재현하면 확인할 수 있습니다.
규칙 목록은 본질적으로 순서대로 실행되는 판정 목록입니다. 작성한 뒤 위에서 아래로 한 번 읽으면서 각 규칙이 앞의 넓은 규칙에 가로막히지 않는지 확인하고, MATCH를 마지막에 두면 규칙 부분은 거의 문제가 생기지 않습니다.