코어의 역할: Clash Meta와 mihomo의 설정 범위

mihomo는 Clash Meta의 계보를 잇는 프록시 코어입니다. 클라이언트는 설정 관리, 시스템 프록시, UI를 담당하고 코어는 연결 수신, 규칙 판정, 프록시 연결 구성을 담당합니다. 클라이언트 이름에 Clash가 들어간다고 해서 반드시 mihomo를 사용하는 것은 아닙니다. YAML을 가져올 수 있어도 YAML에 적힌 모든 프로토콜과 확장 필드를 지원한다는 뜻은 아닙니다.

이 글에서 말하는 ‘신규 기능’은 초기 Clash 오픈소스 코어와 비교해 확장된 기능을 뜻하며, 특정 버전에 특정 날짜 추가된 기능을 의미하지 않습니다. 규칙 제공자는 Clash Premium 등 다른 브랜치에도 구현되어 있으므로 rule-providers를 mihomo만의 필드로 단정할 수 없습니다. 마이그레이션할 때는 클라이언트 외형만 비교하지 말고 현재 사용하는 코어를 확인하세요.

기능주요 설정 항목사용 조건
외부 규칙 세트rule-providers、RULE-SET규칙 형식과 behavior가 일치하고 리소스에 접근할 수 있어야 함
도메인 스니핑sniffer연결이 코어에 전달되고 트래픽에 식별 가능한 도메인 정보가 있어야 함
VLESS 아웃바운드type: vless서버 프로토콜, 전송 계층, TLS 매개변수가 일치해야 함
Hysteria2 아웃바운드type: hysteria2서버가 Hysteria2를 지원하고 네트워크에서 해당 UDP 통신을 허용해야 함

먼저 실행 중인 코어 확인하기

독립 실행 환경에서는 다음 명령을 사용할 수 있습니다. GUI 클라이언트라면 먼저 코어 정보 화면과 시작 로그를 확인하세요. 시스템 터미널에서 실행한 동명 프로그램이 클라이언트에서 실제로 사용하는 바이너리와 다를 수 있습니다.

mihomo -v
mihomo -t -f config.yaml

-v는 코어 버전을 확인하고 -t는 지정한 설정을 테스트합니다. 설정 테스트로 여러 필드 및 참조 오류를 찾을 수 있지만, 원격 노드에 연결할 수 있다는 보장은 없습니다. 실제 DNS, TCP, UDP 테스트를 대신할 수도 없습니다. 필드를 인식하지 못한다는 오류가 나면 전체 버전 정보를 보관하고 해당 버전의 설정 문서와 대조하세요.

rule-providers: 규칙 내용과 트래픽 분리 정책 분리하기

도메인을 rules에 하나씩 직접 입력하면 유지 관리 부담이 커집니다. 규칙 제공자를 이용하면 ‘매칭할 항목’을 별도 리소스로 분리하고, 기본 설정에는 세트 이름과 업데이트 방식, 최종 동작만 남길 수 있습니다. 규칙 세트는 노드 구독과 다릅니다. 규칙 세트는 매칭 조건을 제공하고 노드 구독은 프록시 서버를 제공합니다. 서로 대신 가져올 수 없습니다.

HTTP 규칙 세트와 RULE-SET 참조

아래 예시는 공개 도메인 규칙 세트로 필드 간 관계를 설명합니다. 원격 리소스는 해당 프로젝트에서 관리하므로 적용하기 전에 내용과 용도를 검토하세요. 예시에서는 매칭된 연결을 REJECT로 처리하고 나머지는 직접 연결합니다. 이는 규칙 세트 로드를 확인하기 위한 예시이며, 국내외 트래픽을 완전히 분리하는 설정은 아닙니다.

mode: rule
log-level: info

rule-providers:
  reject-domains:
    type: http
    behavior: domain
    format: yaml
    url: https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/reject.txt
    path: ./ruleset/reject-domains.yaml
    interval: 86400

rules:
  - RULE-SET,reject-domains,REJECT
  - MATCH,DIRECT
  • type: http: HTTP 또는 HTTPS로 리소스를 가져옵니다. 처음 사용할 때는 네트워크에 연결할 수 있어야 합니다.
  • behavior: domain: 내용을 도메인 목록으로 해석하며, 완전한 규칙 구문으로 해석하지 않습니다.
  • format: yaml: 리소스의 인코딩 형식을 지정합니다. URL이 .txt로 끝나도 내용이 일반 텍스트 형식이라는 보장은 없습니다.
  • path: 로컬 캐시 위치입니다. 코어 작업 디렉터리에 쓰기 권한이 있는지 확인하고, 여러 규칙 세트가 같은 파일을 공유하지 않도록 하세요.
  • interval: 86400: 업데이트 간격은 86400초, 즉 24시간입니다. 밀리초가 아닙니다.

behavior와 파일 내용의 형식을 맞추세요

domain은 도메인 목록, ipcidr은 IP 대역 목록, classical은 DOMAIN-SUFFIX, IP-CIDR 등의 규칙 구문에 사용합니다. 이름만 바꾸고 같은 파일을 재사용할 수는 없습니다. 다음은 로컬 classical YAML 파일의 구조입니다. 일반 도메인 목록과의 차이를 확인할 수 있습니다.

payload:
  - DOMAIN-SUFFIX,example.com
  - IP-CIDR,192.168.50.0/24,no-resolve

여기서 example.com은 예약된 예시 도메인이고 192.168.50.0/24는 사설 IP 대역 예시입니다. 이 파일에는 매칭 조건만 나열합니다. 직접 연결, 프록시 연결, 거부 중 어떤 동작을 할지는 기본 설정의 RULE-SET,세트 이름,정책 이름이 결정합니다. 출구를 다르게 사용하려면 조건을 별도 세트로 나누세요. 세트 항목 뒤에 정책 그룹을 임의로 덧붙이면 안 됩니다.

도메인 스니핑: 연결에서 도메인 정보 보완하기

목표 IP로 코어에 들어오는 연결은 도메인 규칙에 필요한 매칭 정보가 부족할 수 있습니다. 스니핑은 HTTP의 Host, TLS ClientHello에서 확인할 수 있는 SNI, 또는 지원되는 QUIC 핸드셰이크 정보를 읽어 대상 도메인을 보완합니다. HTTPS를 복호화하는 기능이 아니므로 암호화된 웹 페이지 내용을 확인할 수 없으며 모든 연결에서 도메인을 식별할 수 있는 것도 아닙니다.

HTTP, TLS, QUIC 설정 예시

sniffer:
  enable: true
  force-dns-mapping: true
  parse-pure-ip: true
  override-destination: false
  sniff:
    HTTP:
      ports: [80, 8080]
    TLS:
      ports: [443, 8443]
    QUIC:
      ports: [443]

ports는 해당 프로토콜을 식별하기 위해 시도할 대상 포트 범위입니다. 443만 지정하면 다른 포트에서 실행되는 모든 TLS 서비스를 자동으로 포함하는 것은 아닙니다. parse-pure-ip는 순수 IP 주소를 대상으로 스니핑을 시도하고, force-dns-mapping은 관련 DNS 매핑 상황에서 스니핑을 계속 시도합니다. 두 옵션 모두 도메인을 반드시 추출한다는 뜻은 아닙니다.

예시에서는 override-destination을 false로 설정해 스니핑한 도메인이 원래 대상을 덮어쓰지 않도록 했습니다. 먼저 매칭 결과의 변화를 확인하기에 적합합니다. true로 바꾸면 연결 대상 처리 방식이 달라지므로 별도로 테스트하세요. 식별된 도메인은 규칙 선택에 영향을 줄 수 있지만, 규칙은 현재 모드와 순서의 제약을 받습니다. 전역 모드에서는 도메인별 트래픽 분리가 완벽하게 이루어진다고 기대할 수 없습니다.

Fake-IP 및 TUN과의 관계

  • Fake-IP: 코어가 관리하는 DNS 매핑으로 도메인과 가상 IP를 연결합니다. 앱의 DNS 요청이 이미 코어에 전달됐다면 보통 도메인 정보를 확보할 수 있으므로 스니핑은 보완 수단으로 사용됩니다.
  • TUN: 네트워크 트래픽을 가상 네트워크 인터페이스로 전달합니다. 가로채는 트래픽 범위가 넓어지지만 모든 연결에 도메인 정보가 자동으로 포함되지는 않습니다.
  • 스니핑: 코어에 이미 전달된 연결을 처리합니다. 시스템 프록시를 우회하고 TUN도 통과하지 않은 트래픽은 가져오지 않습니다.
  • 식별 한계: ECH 같은 암호화 기술, 비표준 핸드셰이크, SNI 누락, 미지원 프로토콜 때문에 원하는 도메인을 추출하지 못할 수 있습니다.

문제를 확인할 때는 먼저 클라이언트 연결 목록에 해당 연결이 표시되는지 확인하고, 이어서 대상 IP, 식별된 도메인, 매칭 규칙, 최종 정책을 살펴보세요. 연결이 코어에 들어온 뒤에야 sniffer 설정을 조정할 의미가 있습니다. 앱의 트래픽이 가로채지지 않는다면 스니핑 포트 범위를 계속 넓히기보다 시스템 프록시나 TUN 라우팅부터 점검하세요.

VLESS: 프로토콜, 전송 계층, TLS 설정을 각각 확인하세요

VLESS는 프록시 프로토콜이고 WebSocket은 선택 가능한 전송 방식이며 TLS는 연결 보안 계층입니다. 세 가지는 서로 다른 설정입니다. 서버에서 VLESS over WebSocket over TLS를 사용한다면 클라이언트에서도 UUID, 포트, WebSocket 경로, Host, TLS 서버 이름을 모두 일치시켜야 합니다.

아래 예시는 예약된 도메인과 데모 UUID로 필드 구성을 보여 주며 실제로 사용할 수 있는 서비스 정보가 아닙니다. 실제 배포 시에는 서버에서 제공한 전체 매개변수를 사용하세요. 연결 오류를 없애려고 경로를 추측하거나 인증서 검증을 끄지 마세요.

proxies:
  - name: VLESS-WS-TLS
    type: vless
    server: vless.example.com
    port: 443
    uuid: 550e8400-e29b-41d4-a716-446655440000
    network: ws
    tls: true
    servername: vless.example.com
    udp: true
    ws-opts:
      path: /proxy
      headers:
        Host: vless.example.com

자주 발생하는 설정 불일치

  1. 전송 방식 불일치: 서버는 TCP를 사용하는데 클라이언트에 network: ws를 설정했다면 포트를 바꾸는 것만으로는 해결되지 않습니다.
  2. 도메인 필드 혼동: server는 연결 주소, servername은 TLS에 사용하며 WebSocket의 Host는 HTTP 요청에 사용합니다. 배포 환경에 따라 세 값이 달라질 수 있지만 임의로 서로 바꿔 쓰면 안 됩니다.
  3. 경로 불일치: /proxy와 다른 경로가 리버스 프록시를 통해 서로 다른 서비스로 전달될 수 있습니다. 서버에서 지정한 경로와 대소문자를 그대로 사용하세요.
  4. 다른 방식의 필드 혼용: REALITY, 공개 키, 핑거프린트, flow에는 각각 적용 조건이 있습니다. 일반적인 WebSocket TLS 예시에 그대로 추가하지 마세요.

프록시 항목을 추가한 뒤에는 기존 정책 그룹에 해당 이름을 넣고 규칙에서도 그 그룹을 참조해야 합니다. proxies에 항목이 있다는 것만으로 실제 요청이 해당 프록시를 선택하는 것은 아닙니다. 클라이언트가 구독 설정을 주기적으로 덮어쓴다면, 다음 업데이트 때 사용자 설정이 사라지지 않도록 클라이언트에서 지원하는 덮어쓰기 또는 병합 기능을 사용하세요.

Hysteria2: 전송 매개변수보다 UDP 연결부터 확인하기

Hysteria2는 QUIC 기반이며 UDP 통신이 필요합니다. 1세대 Hysteria와 설정 구문이 다르므로 노드에 Hysteria2라고 표시되어 있다면 type: hysteria2를 사용하세요. TCP로 서버의 443 포트에 연결할 수 있다고 해서 같은 포트의 UDP 서비스도 연결된다는 뜻은 아닙니다.

proxies:
  - name: HY2-TLS
    type: hysteria2
    server: hy2.example.com
    port: 443
    password: demo-password-for-documentation
    sni: hy2.example.com
    skip-cert-verify: false

여기에서도 예약된 예시 도메인과 데모 인증 정보를 사용합니다. password는 서버의 인증 설정과 일치해야 하고 sni는 실제 인증서와 서버 배포 설정에 맞아야 합니다. 서버에서 특정 난독화 방식을 사용하는 경우 해당 필드도 설정해야 합니다. 프로토콜 이름이 같다는 이유로 이 매개변수를 생략하면 안 됩니다.

연결 시간 초과 시 점검 순서

  • 서버 주소가 예상한 IP로 해석되는지 확인하세요. 특히 IPv4와 IPv6 경로가 모두 사용 가능한지 살펴보세요.
  • 서버가 UDP 443을 수신하는지, 호스트 방화벽과 클라우드 보안 그룹, 중간 게이트웨이에서 해당 트래픽을 허용하는지 확인하세요.
  • 인증 정보, SNI, 인증서 유효 기간, 클라이언트 기기의 시간을 점검하세요.
  • 다른 네트워크에서도 비교 테스트해 현재 네트워크에 UDP 제한이 있는지 확인하세요.
  • 기본 연결이 성립된 다음 서버 설정에 따라 대역폭이나 난독화 매개변수를 조정하세요. 한 번에 한 종류의 설정만 변경하세요.

Hysteria2의 실제 성능은 패킷 손실, 혼잡, 통신사 정책, 서버 자원의 영향을 받습니다. 프로토콜 이름만으로 처리량이 정해지는 것은 아닙니다. 비교할 때는 같은 기기와 네트워크, 대상을 사용하고 연결 성공률과 전송 성능을 따로 기록하세요. 한 번의 속도 측정 결과를 모든 환경에 일반화하지 마세요.

설정 검증: 구문, 리소스, 연결, 규칙 순으로 확인하기

규칙 세트와 스니핑, 신규 프로토콜을 함께 사용할 수 있지만 처음 마이그레이션할 때 모든 기능을 한꺼번에 켜는 것은 바람직하지 않습니다. 먼저 원본 설정을 백업하고 이미 동작이 검증된 출구를 하나 남겨 둔 다음 항목별로 변경하세요. 아래 순서대로 진행하면 ‘설정 로드 실패’와 ‘노드 연결 실패’를 구분할 수 있습니다.

  1. 구문 단계: mihomo -t -f config.yaml을 실행하고 들여쓰기, 중복된 최상위 키, 알 수 없는 프록시 유형, 존재하지 않는 정책 그룹 참조를 확인하세요.
  2. 리소스 단계: 코어를 시작하고 규칙 세트가 정상적으로 다운로드되는지 확인하세요. HTTP 오류, 쓰기 권한, 내용 형식 불일치는 각각 나누어 점검해야 합니다.
  3. 연결 단계: 프록시 노드 하나를 선택해 먼저 핸드셰이크를 테스트하세요. VLESS는 전송 방식과 TLS를, Hysteria2는 UDP와 인증을 중점적으로 확인하세요.
  4. 규칙 단계: 규칙 모드로 전환하고 대상 연결이 예상한 RULE-SET에 매칭되는지, 최종 출구가 정책 그룹에서 현재 선택한 항목과 일치하는지 확인하세요.

포트를 지정해 로컬 프록시 확인하기

테스트 설정에 mixed-port: 7890을 지정했다면 다음 요청으로 로컬 HTTP 프록시 포트를 확인할 수 있습니다. mixed-port는 HTTP와 SOCKS 프록시 연결을 모두 받습니다. 노드의 서버 포트나 외부 컨트롤러 포트가 아닙니다.

curl -I --proxy http://127.0.0.1:7890 https://example.com

이 명령으로 확인할 수 있는 것은 이번 요청의 처리 결과뿐입니다. 연결 기록도 함께 확인해 프록시 노드를 통과했는지 DIRECT로 연결됐는지 살펴보세요. 웹 페이지 응답이 왔다는 사실만으로 트래픽 분리 설정이 올바르다고 단정할 수 없습니다. 테스트 중에는 log-level을 일시적으로 debug로 설정하고, 종료 후 info로 되돌리세요. 로그를 공유하기 전에는 구독 주소, 인증 정보, 개인 접속 기록을 삭제하세요.

YAML 병합 시 최상위 키는 하나만 유지하세요

이 글의 코드 블록은 기능별 예시이므로 정리 없이 파일 끝에 차례로 붙이면 안 됩니다. 이미 proxies가 있다면 새 노드를 기존 목록에 추가하고, rules가 있다면 우선순위에 맞춰 규칙을 삽입하세요. 같은 이름의 최상위 키를 중복 정의하면 오류가 나거나 파서가 기존 값을 덮어쓸 수 있습니다. 이런 동작에 의존해 설정을 병합하지 마세요.

마이그레이션 완료 여부는 코어 버전 확인, 설정 테스트 통과, 규칙 리소스 사용 가능, 대상 프로토콜 핸드셰이크 성공, 연결 기록의 예상 규칙 및 출구 확인을 기준으로 판단하세요. 시스템 트래픽을 가로채야 한다면 TUN을 별도로 활성화한 뒤 로컬 네트워크 접속, DNS, 앱 연결을 다시 테스트하세요. 기본 사용법은 이 사이트의 설정 가이드를, 용어는 용어 빠른 설명을 참고하세요.