mihomo 설정 파일 가이드
YAML 구조, 포트, DNS, 노드와 트래픽 분기 규칙을 살펴봅니다. 먼저 필드가 속한 계층을 확인한 다음 참조 관계와 실행 결과를 점검하세요.
이 페이지는 클라이언트를 실행할 수 있고 설정의 동작 방식을 이해하려는 사용자를 위한 안내서입니다. 처음 설치하거나 구독을 가져오고 연결을 확인하려면 먼저 입문 가이드를 읽어 보세요. 특정 필드나 설정 적용 순서, 서비스 실행 방식의 차이를 확인할 때는 이 페이지에서 해당 장을 찾아보면 됩니다. 예제는 Linux에서 mihomo를 직접 실행하는 경우를 기준으로 합니다. 그래픽 클라이언트는 포트, 권한, 설정 병합 항목을 추가로 생성할 수 있습니다.
YAML 구조와 설정 디렉터리
매핑, 목록, 들여쓰기
config.yaml은 계층 구조를 가진 설정 파일이지, 한 줄씩 실행하는 스크립트가 아닙니다. 최상위의 dns와 tun은 매핑이며, 그 아래에 필드를 작성합니다. proxies, proxy-groups, rules는 보통 목록이며 하이픈으로 항목을 표시합니다. 들여쓰기에 따라 항목의 소속이 정해지므로 공백 두 칸으로 통일하고 탭은 사용하지 않는 것이 좋습니다. 필드 이름의 철자가 맞아도 잘못된 상위 항목 아래 들여쓰면 파싱에 실패하거나 설정이 적용되지 않을 수 있습니다.
콜론 뒤에는 공백을 하나 둡니다. 불리언은 true 또는 false로, 포트와 간격은 숫자로 작성합니다. 비밀번호, 특수 문자가 포함된 이름, 날짜처럼 보이는 문자열에는 따옴표를 붙이는 편이 좋습니다. 일반 문자열에서 샵 기호는 주석 시작으로 처리될 수 있으므로 샵이 들어간 비밀번호는 문자열로 지정해야 합니다. 큰따옴표 문자열에서는 백슬래시 이스케이프가 처리되고, 백슬래시를 그대로 보존해야 한다면 작은따옴표가 적합합니다. 모든 항목에 무조건 큰따옴표를 붙여 경로의 백슬래시가 뜻하지 않게 이스케이프 문자로 해석되지 않도록 하세요.
같은 매핑에서 동일한 키를 두 번 선언하지 마세요. 파일 위쪽에 dns를 작성하고 아래쪽에 다시 작성해도 두 설정이 자동으로 병합되지는 않습니다. 파서에 따라 중복 키를 거부하거나 한쪽 값만 유지할 수 있으므로 이런 동작에 의존해서는 안 됩니다. 규칙을 추가할 때는 기존 rules 목록에 이어서 작성하고, 같은 이름의 목록을 새로 만들지 마세요. YAML 앵커를 사용하면 반복되는 텍스트를 줄일 수 있지만 클라이언트의 설정 병합 기능과는 다르며, 최종 설정을 확인하는 절차를 대신할 수도 없습니다.
먼저 검증 가능한 최소 설정 만들기
아래는 직접 연결만 수행하는 최소 설정입니다. 구독이나 프록시 서버 없이 파일 경로, 파서, 수신 포트를 확인할 수 있습니다. TUN은 끄고, 제어 인터페이스와 혼합 포트는 루프백 주소에 바인딩합니다. 테스트 성공은 로컬 접속 지점이 작동한다는 뜻일 뿐, 프록시 경로가 구성되었다는 의미는 아닙니다. 이후 노드를 추가하더라도 문제 해결의 기준으로 이 최소 설정을 보관하세요. 복잡한 설정으로 시작되지 않을 때 이 파일로 바이너리, 시스템 환경, 설정 내용 중 어디에 문제가 있는지 구분할 수 있습니다.
mixed-port: 7890
bind-address: 127.0.0.1
allow-lan: false
mode: rule
log-level: info
external-controller: 127.0.0.1:9090
tun:
enable: false
rules:
- MATCH,DIRECT
커널을 직접 실행할 때는 작업 디렉터리와 설정 파일을 명시하는 것이 좋습니다. 터미널마다 다른 파일을 사용하게 되는 상황을 방지할 수 있습니다. 아래 명령에서 -d는 데이터 디렉터리, -f는 설정 파일 경로를 지정하고 -t는 설정을 테스트합니다. 디렉터리에는 캐시, Provider 다운로드 파일, 지리 데이터도 있을 수 있으므로 이 모든 파일을 설정 본문으로 간주해서는 안 됩니다. 상대 경로는 보통 터미널의 현재 디렉터리가 아니라 커널 작업 디렉터리를 기준으로 해석됩니다. 서비스를 이전할 때 이 점을 다시 확인하세요.
mkdir -p "$HOME/.config/mihomo"
mihomo -t -d "$HOME/.config/mihomo" \
-f "$HOME/.config/mihomo/config.yaml"
mihomo -d "$HOME/.config/mihomo" \
-f "$HOME/.config/mihomo/config.yaml"
원본 파일과 실행 파일 구분하기
그래픽 클라이언트는 구독 원본, 사용자 설정 덮어쓰기, 생성된 실행 파일을 각각 관리할 수 있습니다. 캐시 디렉터리의 생성 파일을 수정하면 다음에 설정을 바꾸거나 구독을 업데이트할 때 다시 생성되는 경우가 많습니다. 클라이언트 로그에서 커널이 실제로 불러온 경로를 확인한 뒤 수정할 원본을 정하세요. 그래픽 클라이언트의 내장 커널과 독립 서비스를 동시에 실행해 같은 포트를 사용하지 마세요. 두 프로그램이 같은 이름의 파일을 읽더라도 디렉터리, 작업 디렉터리, 실행 사용자, 환경 변수는 서로 다를 수 있습니다.
설정 오류가 나면 첫 번째 오류 메시지와 주변 행 번호부터 확인하세요. 마지막 줄부터 추측하지 마세요. 앞선 목록 항목의 들여쓰기가 잘못되어 파서가 뒤에 있는 정상적인 필드에서야 오류를 보고할 수도 있습니다. 웹 예제를 복사했다면 전각 콜론, 스마트 따옴표, 보이지 않는 공백이 들어갔는지 확인하세요. 한 번에 모듈 하나씩 추가하고 매번 테스트한 뒤, 되돌릴 수 있도록 이전 파일을 보관하는 것이 좋습니다. 파일의 자연스러운 순서대로 익히려면 config.yaml 단계별 해설을 함께 참고하되, 최종 기준은 로컬 커널의 파싱 결과입니다.
수신 포트, 접근 범위, 모드
포트는 애플리케이션이 커널에 접속하는 입구입니다
port는 HTTP 프록시 입구를, socks-port는 SOCKS 입구를 제공합니다. mixed-port는 하나의 포트에서 두 프로토콜을 모두 받습니다. 일반적인 데스크톱 환경에서는 혼합 포트 하나면 충분하며, 모든 필드를 채우려고 세 가지 입구를 전부 열 필요는 없습니다. 프록시에 연결하는 프로그램에는 올바른 프로토콜과 주소를 지정해야 합니다. HTTP 프록시 설정에 제어 인터페이스 포트를 입력하거나, 꺼져 있는 SOCKS 포트를 사용해도 커널이 정상 실행 중이라는 이유만으로 연결 문제가 해결되지는 않습니다.
allow-lan은 LAN 접속 허용 여부를, bind-address는 수신 주소를 지정합니다. 이 컴퓨터에서만 사용할 때는 루프백 바인딩을 유지하세요. 다른 기기에서 접속해야 할 때만 실제 네트워크 인터페이스 주소와 방화벽, 접근 제어를 함께 검토해 포트를 여세요. 바인딩 주소 하나가 모든 포트에 동일한 보안 정책을 적용하는 것은 아닙니다. 특히 제어 인터페이스와 DNS 수신 주소도 함께 바뀐다고 가정하면 안 됩니다. 변경 후에는 설정 화면의 스위치만 보는 것보다 시스템 도구로 실제 수신 상태를 확인하는 편이 정확합니다.
| 필드 | 용도 | 로컬 예시 |
|---|---|---|
mixed-port | HTTP와 SOCKS 공용 입구 | 7890 |
allow-lan | LAN 연결 허용 여부 | false |
bind-address | 프록시 입구 바인딩 주소 | 127.0.0.1 |
external-controller | 관리 인터페이스 수신 주소 | 127.0.0.1:9090 |
log-level | 로그 상세 수준 | info |
규칙, 전역, 직접 연결 모드의 차이
mode: rule은 규칙에 따라 연결 경로를 선택하므로 장기간 사용 시 동작을 이해하기 쉽습니다. global은 일반 트래픽을 전역 정책으로 보내고, direct는 주로 직접 연결을 확인할 때 사용합니다. 모드는 커널에 들어온 트래픽을 처리하는 방식만 제어하며, 브라우저나 명령줄 도구, 백그라운드 프로세스를 자동으로 연결해 주지는 않습니다. 따라서 전역 모드로 바꿔도 시스템 프록시를 사용하지 않는 프로그램은 직접 연결될 수 있습니다. 이럴 때는 규칙을 계속 바꾸기보다 먼저 트래픽이 커널로 들어오는 경로를 확인하세요.
그래픽 클라이언트의 모드 전환은 관리 인터페이스를 통해 실행 중 상태를 즉시 바꿀 수 있지만, 구독 원본 파일까지 변경하지는 않을 수 있습니다. 재시작 후 이전 모드로 돌아간다면 여러 파일에 mode를 중복해서 추가하기보다 클라이언트의 저장 설정과 설정 생성 과정을 확인하세요. 마찬가지로 프록시 그룹의 현재 선택은 캐시에서 복원될 수 있으며 목록의 첫 번째 항목과 다를 수 있습니다. 문제를 찾을 때 파일 값, 화면에 표시된 값, 실제 연결 기록을 각각 확인해 서로 다른 상태를 혼동하지 마세요.
mixed-port: 7890
allow-lan: false
bind-address: 127.0.0.1
mode: rule
log-level: info
external-controller: 127.0.0.1:9090
secret: "your-controller-secret"
관리 인터페이스는 상태 조회, 프록시 선택, 설정 불러오기에 사용하며 브라우저용 프록시는 아닙니다. 관리 기능을 사용하려면 별도의 접근 키를 설정하고 실제 키는 로컬에만 보관하세요. 관리 인터페이스를 인터넷에 직접 노출하거나 키를 스크린샷, 공개 설정, 문제 보고서에 포함하지 마세요. 원격 관리가 꼭 필요하다면 먼저 통제된 접속 경로를 마련하고 인터페이스 바인딩, 인증, 방화벽을 각각 점검하세요. 흔하지 않은 포트 번호로 바꾸는 것만으로는 접근 제어를 대신할 수 없습니다.
명확한 테스트로 환경 차이 확인하기
먼저 수신 상태를 확인한 뒤, 단일 명령에서 프록시를 명시해 테스트하세요. HTTP와 SOCKS 입구를 각각 확인해야 합니다. SOCKS 테스트에서 socks5h를 사용하면 대상 도메인 처리를 프록시 측에 맡길 수 있어 로컬 DNS 경로와 구분하기 쉽습니다. 테스트 대상과 네트워크, 출구에 따라 결과가 달라질 수 있으므로 연결 거부, 핸드셰이크 실패, 도메인 확인 실패처럼 오류 원문을 기록하세요. 단순히 “접속이 안 됨”이라고만 적으면 문제가 연결 입구 전인지 출구 이후인지 판단하기 어렵습니다.
ss -lntp | grep -E ':(7890|9090)\b'
curl --proxy http://127.0.0.1:7890 \
--connect-timeout 10 --head https://example.com
curl --proxy socks5h://127.0.0.1:7890 \
--connect-timeout 10 --head https://example.com
env | grep -iE '^(http|https|all|no)_proxy='
환경 변수는 해당 변수를 상속받은 프로세스에만 적용됩니다. 데스크톱 설정도 모든 명령줄 도구에 적용된다고 보장할 수 없습니다. 대문자·소문자 변수와 NO_PROXY가 함께 결과에 영향을 줄 수 있습니다. 테스트를 분리하려면 시스템 전체를 영구 수정하기보다 해당 명령의 변수를 지우거나 명시적인 옵션을 사용하세요. 상세 로그를 임시로 켰다면 대상 정보가 지나치게 출력되지 않도록 테스트 후 원래대로 돌려놓으세요. 포트가 수신 중인데도 연결되지 않으면 문제 해결에서 프록시 입구, DNS, 규칙, 노드 순서로 확인하세요.
DNS 업스트림, fake-ip, 이름 확인 경로
먼저 DNS 질의가 커널에 도달하는지 확인하세요
dns.enable은 내장 DNS 리졸버를 켜지만 시스템이 사용할 DNS 주소를 바꾸지는 않습니다. 데스크톱 DNS 서비스, 라우터에서 받은 주소, 브라우저의 암호화 DNS가 계속 질의를 처리할 수 있습니다. 시스템이 커널의 수신 주소를 명시적으로 사용하거나 TUN 같은 트래픽 가로채기 기능이 질의를 커널로 보내야 DNS 설정이 적용될 수 있습니다. 문제를 찾을 때는 업스트림이 적절한지 따지기 전에 애플리케이션, 시스템 리졸버, 커널, 업스트림 간의 경로부터 그려 보세요. 이 과정을 건너뛰면 실제로 사용되지 않는 필드만 계속 수정하게 됩니다.
listen은 DNS 서비스의 수신 주소이며 혼합 프록시 입구와는 다릅니다. 예제에서는 일반 사용자가 별도로 테스트할 수 있도록 루프백 주소의 높은 포트 번호를 사용하며, 시스템의 표준 DNS 포트를 직접 가로챌 필요는 없습니다. 시스템 네트워크 설정은 보통 서버 주소만 입력할 수 있고 임의의 포트는 지정할 수 없으므로, 이 예제를 데스크톱 DNS 주소 입력란에 그대로 넣어서는 안 됩니다. 실제로 DNS를 가로채려면 로컬 전달, TUN 가로채기 등 명확한 방식을 사용하고 시스템 DNS 서비스가 대상 포트를 이미 사용 중인지 확인하세요.
dns:
enable: true
listen: 127.0.0.1:1053
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
fake-ip-filter:
- "*.lan"
- "*.local"
default-nameserver:
- 223.5.5.5
nameserver:
- https://dns.alidns.com/dns-query
proxy-server-nameserver:
- 223.5.5.5
세 가지 DNS 조회 작업 구분하기
nameserver는 일반 대상 도메인을 조회합니다. default-nameserver는 주로 DNS 업스트림의 도메인을 확인해 암호화 DNS 서비스의 주소를 찾는 데 사용합니다. proxy-server-nameserver는 프록시 서버 도메인 조회에 사용합니다. 각각의 용도를 분리하면 프록시 연결이 DNS에 의존하고 DNS가 아직 연결되지 않은 프록시에 의존하는 순환 구조를 피할 수 있습니다. 예제의 공용 DNS 서비스는 테스트용 설정일 뿐이므로 실제 배포에서는 사용 중인 네트워크에서 접속 가능한지, 어떤 DNS 정책이 필요한지 고려하세요.
fake-ip는 도메인과 매핑되는 합성 주소를 반환하며, 연결이 커널에 들어오면 원래 도메인으로 복원해 트래픽을 분기합니다. 이 주소는 대상 웹사이트의 실제 서버 주소가 아니므로 합성 주소가 보인다는 것만으로 DNS가 오염된 것은 아닙니다. 매핑에 사용하는 대역이 로컬 네트워크 주소 계획과 충돌하지 않는지도 확인하세요. 애플리케이션이 합성 주소를 받은 뒤 커널을 우회해 연결하면 대상에 도달하지 못할 수 있습니다. 따라서 fake-ip가 제대로 작동하려면 DNS 경로와 연결 경로가 일치해야 하며, 한 번의 질의만 확인해서 전체 연결이 정상이라고 판단해서는 안 됩니다.
fake-ip-filter는 지정한 도메인에 실제 DNS 응답을 반환하며, LAN 기기 검색이나 주소 동작에 민감한 앱에 주로 사용합니다. 이 설정은 트래픽을 직접 연결로 보내지 않으며 규칙 목록을 대신하지도 않습니다. 필터에 포함된 도메인으로 연결하더라도 트래픽은 분기 규칙에 따라 경로가 정해집니다. LAN 기기 문제를 해결할 때는 이름 확인, 실제 주소, LAN 라우팅, 규칙을 함께 확인하세요. 접속 실패 도메인을 모두 필터에 넣으면 안 됩니다. 예외 범위가 지나치게 넓어지면 설정 동작을 파악하기 어려워집니다.
DNS 정책과 캐시의 범위
일부 도메인이 지정한 업스트림을 사용하게 하려면 nameserver-policy를 검토하고, 업스트림 연결에도 분기 규칙을 적용하려면 respect-rules를 살펴보세요. 후자는 DNS 연결의 라우팅 의존 관계를 바꾸므로 프록시 서버 도메인을 어떻게 조회할지도 명확히 정해야 합니다. 그렇지 않으면 자기 자신을 필요로 하는 순환이 생길 수 있습니다. fallback을 기본 서버가 실패한 뒤에만 사용하는 예비 주소로 단순화해 이해해서는 안 됩니다. 필터 조건과 함께 결과를 결정합니다. 처음 설정할 때는 경로가 명확하고 검증 가능한 단일 구성부터 시작한 뒤 복잡한 정책을 하나씩 추가하세요.
dig @127.0.0.1 -p 1053 example.com A
dig @127.0.0.1 -p 1053 example.com AAAA
resolvectl status
resolvectl query example.com
커널에 직접 보내는 질의와 시스템 리졸버를 이용하는 질의는 서로 다른 테스트입니다. 전자는 정상이고 후자는 실패한다면 먼저 시스템 DNS 주소와 전달 경로를 확인하세요. 둘 다 정상인데 브라우저만 실패한다면 브라우저 자체의 암호화 DNS, 캐시, 프록시 설정도 확인해야 합니다. 설정을 변경한 뒤에도 앱 캐시, 시스템 캐시, 커널 매핑에 이전 결과가 남아 있을 수 있으므로 어느 계층의 캐시를 지우는지 명확히 하세요. 기존 연결은 이전 주소를 계속 사용할 수도 있어 페이지를 다시 여는 것만으로 새 연결이 만들어진다고 볼 수 없습니다.
dns.ipv6와 최상위 ipv6는 적용 범위가 다릅니다. 한 항목만 바꿔 모든 앱에서 IPv6를 사용하지 않도록 보장할 수는 없습니다. IPv4와 IPv6가 함께 사용되는 환경에서만 문제가 생기면 A 및 AAAA 응답과 실제 연결 주소를 각각 테스트해 출구가 해당 연결을 지원하는지 확인하세요. 단계별 검증 방법은 연결은 됐지만 웹페이지가 열리지 않을 때 확인할 사항을 참고하세요. DNS를 변경할 때는 목표를 명확히 하고, 업스트림과 강화 모드, 라우팅을 한꺼번에 바꾼 뒤 페이지가 열리는지만으로 원인을 판단하지 마세요.
프록시 노드 필드와 구독 Provider
노드 설정은 출구 연결 매개변수를 정의합니다
proxies에는 개별 노드 정의를 저장합니다. 각 항목에는 참조 가능한 name과 프로토콜 유형인 type이 필요하고, 나머지 필드는 프로토콜에 맞게 지정합니다. 이름은 화면에 표시될 뿐 아니라 프록시 그룹과 규칙에서도 참조하므로 안정적이고 고유하며 알아보기 쉬워야 합니다. 이름이 비슷하다고 같은 노드인 것은 아닙니다. 실제 연결은 서버 주소, 포트, 인증 정보로 결정됩니다. 이름을 바꿨다면 노드 항목이 파싱되는지만 확인하지 말고 해당 이름을 사용하는 모든 목록도 함께 점검하세요.
가장 기본적인 필드 관계를 설명하기 위해 Shadowsocks를 사용합니다. 서버에는 예시용 예약 도메인을 사용하고 비밀번호도 설명용 텍스트이므로 실제로 연결하려면 서비스 제공자가 안내한 값으로 바꿔야 합니다. cipher는 서버 설정과 일치해야 합니다. 알고리즘이 최신처럼 보인다는 이유만으로 임의로 바꾸지 마세요. udp는 관련 기능을 켜는 항목일 뿐, UDP를 지원하지 않는 서버나 네트워크에 해당 기능을 추가해 주지는 않습니다. 애플리케이션 프로토콜, 커널 구현, 서버, 중간 네트워크가 모두 해당 기능을 지원해야 합니다.
proxies:
- name: SS-Example
type: ss
server: proxy.example.com
port: 443
cipher: aes-128-gcm
password: "your-password"
udp: true
프로토콜에 따라 비밀번호, UUID, TLS 이름, 전송 경로, 공개 키 등의 필드가 필요할 수 있습니다. 한 프로토콜의 매개변수를 다른 프로토콜에 그대로 적용할 수는 없습니다. 연결 주소와 TLS 인증서 검증 이름도 다를 수 있으므로 IP 주소를 입력했다고 인증서 이름을 생략할 수 있는 것은 아닙니다. 인증서 오류가 발생하면 검증을 건너뛰는 것을 일반적인 해결책으로 삼지 말고 시스템 시간, 서버 인증서, 이름 일치 여부부터 확인하세요. 공개적으로 도움을 요청할 때는 인증 정보와 구독 주소의 민감한 매개변수를 삭제하고 필요한 프로토콜 구조와 오류 정보만 남기세요.
Provider로 노드 업데이트를 주 설정에서 분리하기
proxy-providers를 사용하면 주 설정에는 정책과 규칙을 두고, 자주 바뀌는 노드 목록은 외부 파일이나 구독 업데이트로 관리할 수 있습니다. Provider 이름과 노드 이름은 서로 다른 계층입니다. 프록시 그룹은 use로 Provider를 참조하고, proxies로 개별 노드나 다른 프록시 그룹을 참조합니다. Provider만 선언한다고 모든 규칙이 자동으로 해당 Provider를 사용하는 것은 아닙니다. 프록시 그룹을 만들고 트래픽을 그 그룹으로 보내야 합니다. 이렇게 나누면 업데이트는 편리해지지만 참조 관계도 반드시 확인해야 합니다.
proxy-providers:
local-nodes:
type: file
path: ./providers/local-nodes.yaml
health-check:
enable: true
url: https://www.gstatic.com/generate_204
interval: 600
proxy-groups:
- name: PROXY
type: select
use:
- local-nodes
로컬 Provider 파일은 최상위에 proxies 목록을 두는 등 노드 모음에 맞는 형식이어야 합니다. 주 설정의 상대 경로는 작업 디렉터리를 기준으로 해석되므로 해당 디렉터리가 존재하고 서비스 실행 사용자에게 읽기 권한이 있어야 합니다. 포트, DNS, 규칙이 모두 포함된 클라이언트 설정 파일을 노드 파일로 임의 사용하지 마세요. 일부 입력 형식을 호환하더라도 확인되지 않은 변환 방식에 의존해서는 안 됩니다. 목록이 비어 있다면 먼저 실제 파일을 열어 보고 로그에서 읽기 경로, 형식 오류, 노드 필터 조건을 확인하세요.
원격 업데이트, 상태 검사, 오류 분류
HTTP Provider에는 url, 캐시 path, 업데이트 interval도 필요합니다. 업데이트 간격과 상태 검사 간격은 서로 다른 작업입니다. 전자는 노드 정의를 다시 가져오고, 후자는 기존 노드가 테스트 주소에 접속할 수 있는지 확인합니다. 한쪽 간격을 줄여도 다른 작업이 더 빨라지지는 않습니다. 테스트 주소에 접속할 수 없으면 상태 검사가 연이어 실패할 수 있지만, 모든 노드의 인증 정보가 잘못되었다는 뜻은 아닙니다. 노드를 일괄 삭제하기 전에 실제 서비스 대상에 접속해 확인하세요.
구독 업데이트 시간 초과, 비정상 HTTP 상태 코드, YAML이 아닌 응답 내용, 파일 쓰기 권한 부족은 서로 다른 문제입니다. 먼저 요청에 응답이 왔는지 확인한 다음 응답 내용과 저장된 파일을 점검하세요. 구독 주소는 계정에 접근할 수 있는 정보일 수 있으므로 백업과 로그의 접근 권한을 제한하고 공개 저장소에 올리지 마세요. 업데이트를 위해 기존 프록시가 필요하다면 시작 경로를 미리 마련해야 합니다. 노드가 하나도 없어 첫 설치 시 노드를 가져오지 못하는 상황이 생길 수 있습니다. 로컬 캐시는 복구에 도움이 되지만 안정적인 가져오기 경로를 대신하지는 않습니다.
업데이트에 성공해도 노드 이름, 지역 태그, 지원 프로토콜이 바뀌면서 프록시 그룹 필터나 수동 선택에 영향을 줄 수 있습니다. 유지보수할 때는 노드 목록이 어떻게 바뀌었는지 비교하세요. 파일 다운로드 성공이 프록시 정책 연결까지 정상이라는 뜻은 아닙니다. 구독 제공업체와 이 사이트의 클라이언트 문서는 서로 다른 역할을 하며, 클라이언트가 사용할 수 있는 프록시 서비스를 만들어 주지는 않습니다. 앱을 설치하려면 클라이언트 다운로드 페이지에서 플랫폼에 맞는 항목을 선택하세요. Windows, macOS, Android, iOS에서는 Clash Plus를, Linux 그래픽 환경에서는 Clash Verge Rev를 확인할 수 있습니다. 업데이트 오류의 자세한 해결 방법은 구독 업데이트 실패와 자동 새로고침 설정을 참고하세요.
프록시 그룹 유형, 참조 관계, 선택 상태
프록시 그룹이 규칙과 실제 출구를 연결합니다
proxy-groups는 출구 선택 방식을 정의합니다. 규칙은 그룹을 가리키고, 그룹은 노드나 다른 그룹 또는 내장 출구를 선택합니다. 이렇게 하면 구독 노드 이름이 바뀌어도 규칙에서는 안정적인 용도별 이름만 참조하면 됩니다. 프록시 그룹은 단순한 노드 폴더가 아닙니다. 유형에 따라 선택 방식이 달라지며, 모든 노드를 하나의 그룹에 넣는다고 커널이 노드를 동시에 사용하는 것도 아닙니다. 먼저 직접 선택, 테스트 결과에 따른 선택, 순서에 따른 장애 대응, 연결 분배 중 어떤 동작이 필요한지 정한 뒤 유형을 선택하세요.
select는 목록에서 사용자나 관리 인터페이스가 항목을 지정해 출구를 명확히 제어하는 데 적합합니다. url-test는 테스트 결과에 따라 후보를 선택하고, fallback은 주로 후보 순서에 따라 사용 가능한 출구를 찾으며, load-balance는 정책에 따라 연결을 분배합니다. 자동 선택은 지정한 테스트 주소를 기준으로 하며 모든 서비스 품질을 종합적으로 평가하지 않습니다. 검사 속도가 빠른 노드라도 특정 서비스에는 접속하지 못할 수 있습니다. 자동 검사 결과를 해석할 때는 테스트 대상과 방식, 실제 서비스 이용 결과를 구분하세요.
proxy-groups:
- name: AUTO
type: url-test
use:
- local-nodes
url: https://www.gstatic.com/generate_204
interval: 600
tolerance: 50
- name: PROXY
type: select
proxies:
- AUTO
- DIRECT
use:
- local-nodes
위 설정은 앞 장의 local-nodes Provider를 사용합니다. AUTO는 Provider에서 후보를 가져옵니다. PROXY에서는 자동 선택 그룹뿐 아니라 노드나 직접 연결도 수동으로 선택할 수 있습니다. 그룹에 DIRECT를 넣는 것은 사용자가 직접 선택할 수 있다는 뜻이지, 프록시 노드에 문제가 생기면 반드시 직접 연결로 전환된다는 뜻은 아닙니다. 문제가 생겼을 때 출구를 바꾸지 않고 연결을 중단해야 한다면 요구 사항에 맞지 않는 후보를 제거하고 장애 대응 그룹의 전체 경로를 확인하세요. 이름에 “안전”이나 “고정”이 들어간다고 동작을 추측해서는 안 됩니다.
이름 참조는 방향성 관계를 만듭니다
proxies에 나열한 이름은 실제로 존재해야 하며 대소문자와 공백까지 일치해야 합니다. 그룹이 다른 그룹을 참조할 수는 있지만 입구 그룹이 자동 그룹을 참조하고 자동 그룹이 다시 입구 그룹을 참조하는 식의 순환은 만들면 안 됩니다. 순환 참조가 있으면 실제 노드까지 선택할 수 없어 테스트 단계에서 거부되거나 실행 중 문제가 생길 수 있습니다. 규칙에서 그룹, 그룹에서 노드로 이어지는 경로를 화살표로 그려 보세요. 각 경로는 실제 노드나 명시적인 내장 출구에서 끝나야 합니다.
그룹 이름과 노드 이름은 다르게 지정하고, 용도별 그룹 이름을 내장 정책 이름과 같게 짓지 마세요. 복잡한 이름에는 문자열 범위를 명확히 하도록 따옴표를 붙일 수 있지만, 따옴표가 이름 불일치를 해결해 주지는 않습니다. Provider 업데이트로 노드가 사라지면 수동 선택이 작동하지 않거나 다른 후보로 돌아갈 수 있으므로 클라이언트에서 현재 선택된 항목을 확인하세요. 선택 상태를 저장하는 캐시는 재시작 후 복원에 도움이 되지만, 목록 순서를 바꿨는데 출구가 바뀌지 않는 상황을 만들기도 합니다. 목록의 첫 항목과 실행 중 선택된 항목은 같은 개념이 아닙니다.
| 유형 | 선택 기준 | 주의 사항 |
|---|---|---|
select | 사용자 또는 관리 인터페이스에서 지정 | 현재 저장된 선택 항목 확인 |
url-test | 테스트 주소에 대한 후보 노드의 검사 결과 | 테스트 결과가 모든 서비스의 품질을 보장하지 않습니다 |
fallback | 후보 순서와 사용 가능 여부 | 순서에 따라 출구 우선순위가 달라집니다 |
load-balance | 설정된 연결 분배 정책 | 단일 연결의 대역폭이 합산되지는 않습니다 |
자동 전환이 영향을 미치는 범위 제어하기
interval은 주기적인 검사를 제어하고, tolerance는 작은 차이로 선택이 자주 바뀌는 현상을 줄여 줍니다. 하지만 연결 품질을 보장하지는 않습니다. 검사를 너무 자주 실행하면 네트워크 요청이 늘어나며 노드가 많을수록 영향이 커집니다. 그룹 선택이 바뀌더라도 기존 장시간 연결이 다른 출구로 끊김 없이 이동하는 경우는 보통 없습니다. 전환 결과를 테스트하려면 새 연결을 만들고 앱이 이전 세션을 재사용하지 않는지 확인하세요. 로그인 상태, 지역 판정, 장시간 작업과 관련된 서비스라면 출구 변경을 허용할 수 있는지 먼저 확인해야 합니다.
로드 밸런싱은 보통 연결이나 대상에 따라 트래픽을 분배하며 다운로드 하나의 연결을 여러 노드로 나눠 대역폭을 합산하지 않습니다. 연결마다 출구가 달라지면 서비스의 세션 제한이 작동할 수 있습니다. 모든 트래픽을 하나의 무작위 출구 그룹에 넣기보다 서비스별로 그룹을 나누세요. 고정 출구가 필요한 서비스는 별도의 선택 그룹을 규칙에서 먼저 지정하고, 일반 웹 트래픽은 자동 그룹을 사용할 수 있습니다. 그룹이 적으면 관리가 쉽지만 너무 많이 합치면 한 번의 전환이 관계없는 서비스에도 영향을 줍니다.
그룹이 비어 있으면 Provider가 로드되었는지, 필터 표현식이 모든 노드를 제외했는지, 올바른 Provider를 참조하는지, 프로토콜 지원 제한으로 노드가 제외되었는지 순서대로 확인하세요. 후보가 있는데 서비스가 작동하지 않는다면 먼저 노드 하나를 직접 선택하고 새 연결을 만들어 규칙이 최종적으로 어느 그룹을 가리키는지와 출구 오류를 확인하세요. 그룹 유형, 테스트 주소, 노드 필터 조건을 한꺼번에 바꾸면 어떤 변경이 결과를 만들었는지 알기 어렵습니다. 안정적인 프록시 그룹에는 명확한 용도, 이해할 수 있는 선택 기준, 분명한 장애 처리 방식이 필요합니다.
규칙 순서, 매칭 문법, 규칙 세트
위에서 아래로 확인하고, 먼저 일치한 규칙을 적용합니다
rules는 순서가 있는 목록으로, 보통 위에서 아래로 검사하고 일치한 규칙의 정책을 적용합니다. 규칙을 파일의 어느 위치에 두는지가 결과에 직접 영향을 줍니다. 키워드를 많이 나열한다고 가장 정확한 규칙을 자동으로 선택하는 것은 아닙니다. 보통 범위가 명확한 예외를 앞에 두고, 서비스 도메인과 규칙 세트를 중간에 배치하며, 넓은 주소 범위 규칙을 뒤쪽에 둔 뒤 마지막에 MATCH로 나머지를 처리합니다. 기본 규칙을 앞에 두면 뒤의 규칙은 대부분 검사되지 않습니다.
DOMAIN은 도메인 하나를 정확히 매칭하고, DOMAIN-SUFFIX는 도메인 자체와 하위 도메인을 매칭하며, DOMAIN-KEYWORD는 문자열 키워드로 매칭합니다. 키워드 규칙은 예상보다 넓은 범위를 포함할 수 있으므로 신중하게 사용하고, 짧은 단어를 서비스 범위의 기준으로 삼지 마세요. 일반 도메인 규칙에는 웹페이지 경로가 포함되지 않습니다. 같은 도메인의 서로 다른 경로를 도메인 규칙만으로 구분할 수는 없습니다. 암호화 연결에서 사용할 수 있는 대상 정보는 앱 동작, DNS 경로, 스니핑 설정에 따라 달라지므로 모든 연결에 전체 URL이 포함된다고 가정하면 안 됩니다.
rules:
- DOMAIN,example.com,DIRECT
- DOMAIN-SUFFIX,example.org,PROXY
- IP-CIDR,127.0.0.0/8,DIRECT,no-resolve
- IP-CIDR,10.0.0.0/8,DIRECT,no-resolve
- IP-CIDR,172.16.0.0/12,DIRECT,no-resolve
- IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
- IP-CIDR6,::1/128,DIRECT,no-resolve
- IP-CIDR6,fc00::/7,DIRECT,no-resolve
- MATCH,PROXY
이 예제는 이미 정의된 PROXY 그룹을 사용하며 대상 도메인은 매칭 범위를 보여 주기 위한 것입니다. 사설 주소를 직접 연결하는 규칙은 일반적인 로컬 네트워크에 적합하지만, 터널이나 컨테이너 네트워크, 기업망까지 포함되는지는 실제 라우팅에 따라 판단해야 합니다. no-resolve는 이 주소 규칙을 위해 대상 도메인을 능동적으로 조회하지 않는다는 뜻이며 DNS 모듈 전체를 끄는 설정이 아닙니다. 연결에 대상 IP가 이미 있다면 주소 규칙으로 계속 매칭할 수 있습니다. 이 옵션을 제거하면 DNS에 대한 의존성이 늘어날 수 있으므로 필요한 동작을 파악한 뒤 조정하세요.
규칙 세트의 형식은 실제 내용과 일치해야 합니다
rule-providers는 길이가 긴 규칙 모음을 별도 파일로 분리하고, 주 규칙에서는 RULE-SET으로 참조합니다. Provider의 behavior는 항목이 도메인, 주소, 기존 규칙 문법 중 무엇인지 나타내고, format은 파일 인코딩 형식을 지정합니다. 두 필드는 서로 다른 역할을 합니다. 도메인 목록으로 선언하고 완성된 규칙 행을 넣거나, 텍스트 형식으로 선언하고 최상위 매핑이 있는 YAML을 제공하면 파일을 읽지 못하거나 예상대로 매칭되지 않을 수 있습니다. 선언과 실제 다운로드된 내용을 모두 확인하세요.
rule-providers:
business-domains:
type: file
behavior: classical
format: yaml
path: ./rules/business.yaml
rules:
- RULE-SET,business-domains,PROXY
- MATCH,DIRECT
해당 business.yaml 파일은 다음과 같습니다. 규칙 세트의 항목은 매칭 조건만 설명하며 어떤 출구를 사용할지는 주 파일의 RULE-SET 행에서 결정됩니다. 이렇게 하면 같은 매칭 목록을 배포 환경마다 다른 정책에 연결할 수 있어 규칙 파일 자체를 수정할 필요가 없습니다. 유지보수 시에는 로컬 파일과 원격 파일의 경로를 다르게 설정해 업데이트 작업이 직접 작성한 내용을 덮어쓰지 않도록 하세요. 파일이 있는데도 매칭되지 않으면 주 규칙에서의 위치를 확인하세요. 앞선 넓은 범위의 규칙이 먼저 일치해 해당 규칙까지 도달하지 못했을 수 있습니다.
payload:
- DOMAIN-SUFFIX,example.org
- DOMAIN,api.example.net
규칙이 매칭되는지 확인한 뒤 목록을 조정하세요
원격 규칙 세트의 업데이트에 실패해도 커널이 기존 캐시를 사용하고 있다면 현재 동작이 바로 달라지지 않을 수 있습니다. 반대로 첫 실행에서 캐시가 없으면 규칙 세트 로드 실패가 설정 로드나 매칭 결과에 영향을 줄 수 있습니다. 따라서 로컬 파일 수정 시간만 확인하지 말고 Provider 상태와 오류 로그를 확인하세요. 지리 데이터 기반 규칙을 사용할 때는 관련 데이터 파일이 준비되어 있는지, 형식이 지원되는지, 업데이트 방법이 정해져 있는지도 확인해야 합니다. 규칙 문법이 올바르다고 외부 데이터까지 준비되었다는 보장은 없습니다.
Linux의 프로세스 규칙은 프로세스 검색 기능과 적절한 권한이 필요할 수 있습니다. 컨테이너, 전달된 트래픽, 다른 사용자 권한으로 실행되는 프로그램에서는 같은 프로세스 정보를 얻지 못할 수도 있습니다. 프로세스 규칙이 매칭되지 않으면 프로세스 이름을 계속 바꾸기 전에 커널이 프로세스를 확인할 수 있는지부터 점검하세요. 원본 주소 규칙에서는 로컬 앱과 LAN에서 전달된 트래픽을 구분해야 합니다. 규칙 매칭은 실제로 확인 가능한 정보에 의존하므로 라우팅이나 NAT가 출발지를 바꿨다면 기존 규칙의 전제가 더는 성립하지 않을 수 있습니다.
트래픽이 잘못 분기되는 문제를 조사할 때는 대상 도메인, 대상 주소, 일치한 규칙, 최종 프록시 그룹, 실제 출구를 기록하세요. 목록 맨 앞에 범위가 명확한 임시 규칙을 추가해 확인한 뒤 올바른 위치로 옮기세요. 네트워크를 “복구”하려고 많은 규칙을 한꺼번에 삭제하지 마세요. 규칙 업데이트 후에는 새 연결로 다시 테스트하고 필요하면 관련 캐시를 비우세요. 한 사이트에서 여러 도메인을 사용하는 경우 연결 기록을 하나씩 확인해야 합니다. 첫 페이지 도메인만 처리하고 API, 정적 파일, 인증 도메인을 놓치지 않도록 하세요.
TUN 트래픽 가로채기, Linux 권한, 상시 실행 서비스
투명 프록시에는 커널 외부의 조건도 필요합니다
tun.enable은 가상 네트워크 장치를 통한 트래픽 가로채기를 켜고, auto-route는 관련 라우팅 설정을 요청하며, auto-detect-interface는 출구 네트워크 인터페이스를 찾습니다. 이 항목들은 트래픽을 커널로 보내는 방법을 정할 뿐, 노드와 DNS, 규칙 설정을 대신하지는 않습니다. TUN을 켜기 전에 명시적 프록시 테스트가 정상인지 확인하세요. 그렇지 않으면 연결 입구, 라우팅, 출구가 동시에 바뀌어 문제 범위가 넓어집니다. 데스크톱에서 다른 VPN이나 투명 프록시를 사용 중이라면 기본 라우팅과 DNS를 어느 프로그램이 담당하는지 먼저 정하세요.
tun:
enable: true
stack: mixed
auto-route: true
auto-detect-interface: true
dns-hijack:
- any:53
stack은 TUN의 프로토콜 스택 방식을 결정하며 지원 여부는 플랫폼, 빌드, 커널 구현에 따라 달라집니다. 예제에서는 mixed를 사용하지만 모든 환경에서 최선이라고 볼 수는 없습니다. dns-hijack의 일반적인 설정은 보통 DNS 질의를 대상으로 하며 브라우저나 앱의 HTTPS DNS를 자동으로 복호화하지 않습니다. 설정을 켠 뒤에도 DNS 질의 경로를 확인하세요. 특히 시스템 로컬 리졸버, 컨테이너, 앱에서 직접 지정한 업스트림은 TUN 스위치가 켜져 있는지만 봐서는 확인할 수 없습니다.
권한이 부족하면 장치를 만들거나 라우팅을 추가하지 못할 수 있습니다. 먼저 시스템에 /dev/net/tun이 있는지 확인한 다음 실행 사용자와 capability 설정을 점검하세요. 컨테이너는 장치 매핑, 네트워크 네임스페이스, 호스트의 권한 부여에도 제약을 받습니다. 컨테이너 안에서 관리자 권한을 사용한다고 호스트가 필요한 네트워크 권한을 부여한 것은 아닙니다. 원격 서버에서 라우팅을 바꾸면 관리 연결이 끊길 수 있으므로 콘솔이나 복구 경로를 준비하고, 관리 네트워크 대역과 기존 VPN 라우팅이 잘못 가로채지지 않는지 먼저 확인하세요.
실제 실행할 바이너리에 권한 부여하기
직접 설치한 커널에는 권한 범위를 검토한 뒤 필요한 네트워크 권한을 부여할 수 있습니다. 아래 예제는 사용자 디렉터리의 고정된 바이너리를 사용하므로 실행할 파일의 경로가 맞는지 먼저 확인하세요. 권한은 해당 파일에 부여되므로 바이너리를 교체하거나 다시 설치한 뒤에는 재설정해야 할 수 있습니다. 출처를 모르는 프로그램에 권한을 부여하지 마세요. 네트워크 권한을 부여한다고 모든 격리가 끝나는 것도 아닙니다. 다른 프로세스가 허가된 프로그램을 교체할 수 없도록 디렉터리 쓰기 권한도 확인해야 합니다.
test -c /dev/net/tun
install -d "$HOME/.local/bin"
sudo setcap cap_net_admin,cap_net_bind_service=+ep \
"$HOME/.local/bin/mihomo"
getcap "$HOME/.local/bin/mihomo"
cap_net_admin은 네트워크 관리에 필요하고 cap_net_bind_service는 낮은 번호의 포트를 바인딩할 때 사용합니다. 후자가 필요한지는 실제 수신 포트에 따라 다릅니다. 일부 파일 시스템이나 서비스 보안 제한으로 파일 capability가 예상대로 적용되지 않을 수 있으므로 capability 출력 확인은 첫 단계일 뿐입니다. 시작 로그도 확인하세요. 그래픽 클라이언트는 자체 서비스 구성 요소로 권한을 처리할 수 있으므로 별도의 권한 설정을 동시에 적용하지 마세요. 명시적 HTTP 프록시만 필요하다면 TUN을 끄고 권한 및 라우팅 변경을 줄일 수 있습니다.
경로와 로그를 확인할 수 있는 사용자 서비스
아래 사용자 서비스는 고정된 작업 디렉터리와 절대 설정 경로를 사용하고 시작 전에 설정 테스트를 실행합니다. 앞서 설명한 대로 커널을 사용자 디렉터리에 설치한 경우에 적합합니다. systemd는 ExecStart를 대화형 셸로 실행하지 않으므로 터미널 별칭, 임시 변수, 물결표 확장에 의존할 수 없습니다. 예제의 %h는 systemd가 사용자의 홈 디렉터리로 확장합니다. 시스템 서비스로 배포하려면 실행 사용자, 디렉터리 권한, capability 범위를 별도로 설계해야 합니다. 파일만 시스템 디렉터리로 옮기면 되는 것은 아닙니다.
# ~/.config/systemd/user/mihomo.service 로 저장
[Unit]
Description=mihomo user proxy service
[Service]
Type=simple
WorkingDirectory=%h/.config/mihomo
ExecStartPre=%h/.local/bin/mihomo -t -d %h/.config/mihomo -f %h/.config/mihomo/config.yaml
ExecStart=%h/.local/bin/mihomo -d %h/.config/mihomo -f %h/.config/mihomo/config.yaml
Restart=on-failure
RestartSec=5
[Install]
WantedBy=default.target
먼저 서비스 디렉터리를 만들고 파일을 저장한 다음 유닛을 다시 불러오세요. 서비스가 시작된 뒤 로그에서 실제 경로, 권한 오류, 라우팅 오류를 확인하세요. 프로세스가 존재하는지만 확인해서는 안 됩니다. 사용자 서비스는 보통 사용자 관리자의 수명 주기를 따릅니다. 로그아웃 후에도 계속 실행해야 한다면 사용자 상주 기능을 활성화할지 검토하세요. 상주 기능은 백그라운드 작업의 수명 주기를 바꾸므로 모든 데스크톱 설치에서 기본으로 켜기보다 컴퓨터의 용도에 맞게 결정해야 합니다.
mkdir -p "$HOME/.config/systemd/user"
systemctl --user daemon-reload
systemctl --user enable --now mihomo.service
systemctl --user status mihomo.service
journalctl --user -u mihomo.service -n 80 --no-pager
ip route
ip rule
TUN을 켠 뒤 LAN이나 다른 VPN 연결이 끊기면 먼저 서비스를 중지해 라우팅이 복구되는지 확인한 다음 활성화 전후의 라우팅 테이블과 정책 라우팅을 비교하세요. 출처를 모르는 라우팅을 한꺼번에 삭제하지 마세요. 시스템 네트워크 관리자의 상태가 손상될 수 있습니다. 서비스를 종료한 뒤에도 문제가 계속되면 다른 커널 인스턴스, 남아 있는 DNS 설정, 클라이언트 백그라운드 서비스가 있는지 확인하세요. 라우터 배포에는 포워딩, 방화벽, 게이트웨이 구성도 필요합니다. OpenWrt 바이패스 라우터 배포 가이드를 참고하세요. 이 컴퓨터의 TUN 예제를 바이패스 라우터의 완성된 설정으로 그대로 사용해서는 안 됩니다.
설정 병합, 변경 테스트, 롤백
YAML 문법과 클라이언트 설정 생성 로직 구분하기
설정 덮어쓰기는 클라이언트나 외부 도구가 설정을 가공하는 과정이지, 모든 YAML 파일에 원래부터 있는 기능은 아닙니다. 구독 원본, 로컬 덮어쓰기, 화면 설정은 서로 다른 순서로 결합되어 실행 파일을 만들 수 있으며 클라이언트마다 병합 규칙이 다릅니다. 따라서 “나중에 작성한 필드가 항상 앞의 값을 덮어쓴다”고 가정하지 마세요. 특정 클라이언트의 확장 키를 독립 커널에 그대로 전달해서도 안 됩니다. 먼저 어떤 도구가 설정을 처리하는지, 입력 파일은 무엇인지, 최종 출력 파일이 어디 있는지 확인한 다음 어떤 설정이 덮였는지 살펴보세요.
스칼라, 매핑, 목록은 각각 따로 확인해야 합니다. 포트 번호 하나는 대체하기 쉽지만 DNS 매핑은 재귀 병합될 수도 있고 전체가 교체될 수도 있습니다. 규칙과 프록시 그룹 목록은 뒤에 추가되거나 앞에 삽입되거나 완전히 다시 생성될 수 있습니다. 도구가 덮어쓰기 설정의 rules 전체를 주 설정으로 교체한다면 LAN 규칙 하나만 있는 덮어쓰기 때문에 기존 프록시 규칙이 모두 사라질 수 있습니다. 반대로 기본 규칙 뒤에 단순히 추가하면 새 규칙이 전혀 매칭되지 않을 수도 있습니다. 병합이 성공했다고 해서 순서가 목적에 맞는 것은 아닙니다.
구독 설정을 관리할 때는 노드는 구독이 담당하고, 안정적인 포트와 보안 범위, 서비스별 정책은 로컬 설정이 담당하도록 나누는 것이 좋습니다. Provider로 분리할 수 있다면 노드 업데이트를 독립적으로 수행해 파일 전체를 매번 갱신하면서 생기는 충돌을 줄이세요. 다만 모든 클라이언트가 동일한 절차를 지원하는 것은 아닙니다. 그래픽 인터페이스에서 관련 항목을 다시 생성할 수 있으므로 제공되는 덮어쓰기 또는 확장 기능을 사용하고 최종 실행 파일을 확인하세요. 편집기에서 저장 성공 메시지만 확인해서는 안 됩니다.
한 번에 하나의 동작만 바꿔 테스트하기
변경 전에 롤백할 수 있는 복사본을 보관하고 현재 모드, 프록시 그룹 선택, 트래픽 가로채기 방식을 기록하세요. YAML만 백업해서는 실행 상태를 복구하지 못할 수 있습니다. 클라이언트 캐시, Provider 파일, 시스템 프록시 설정도 영향을 줄 수 있기 때문입니다. DNS나 TUN을 변경한다면 기존 DNS 경로와 라우팅 정보도 기록하세요. 백업에 구독 주소나 인증 정보가 포함된 경우 권한이 제한된 디렉터리에 보관하고 웹사이트, 공유 동기화 디렉터리, 공개 질문 첨부 파일에는 올리지 마세요. 외부에 차이점을 공유하기 전 민감한 정보를 제거하세요.
cd "$HOME/.config/mihomo"
cp -p config.yaml config.yaml.before-change
cp -p config.yaml config.candidate.yaml
# 후보 파일을 수정한 뒤 먼저 후보 파일 자체를 검사합니다.
mihomo -t -d "$HOME/.config/mihomo" \
-f "$HOME/.config/mihomo/config.candidate.yaml"
diff -u config.yaml.before-change config.candidate.yaml
상대 경로가 예상대로 작동하도록 후보 파일은 같은 작업 디렉터리에 두고 테스트하세요. 다만 설정 테스트 중에도 Provider를 읽거나 캐시를 만들 수 있으므로 완전히 격리된 샌드박스는 아닙니다. 설정 테스트는 주로 문법, 필드, 참조 오류를 찾으며 원격 노드가 사용 가능한지, DNS에 순환이 없는지, 라우팅이 충돌하지 않는지까지 증명하지는 않습니다. 테스트를 통과한 뒤 차이를 확인해 프록시 그룹이 실수로 삭제되거나 수신 범위가 넓어지거나 관리 인터페이스가 외부 주소로 바뀌지 않았는지 살펴본 다음 실제로 전환하세요.
후보 파일을 확인한 뒤 정식 파일로 교체하고 현재 배포 방식에 따라 다시 불러오세요. 이 안내서의 사용자 서비스에서는 서비스를 재시작하면 시작 전 테스트를 다시 실행할 수 있습니다. 클라이언트에서 핫 리로드를 사용하는 경우에는 다른 구독이 아니라 대상 설정을 불러왔는지 확인하세요. 다시 불러오기에 성공한 뒤 새 연결을 만들어 검증해야 합니다. 기존 연결에는 이전 출구와 DNS 결과가 남아 있을 수 있습니다. 연결을 강제로 끊어야 한다면 다운로드, 원격 세션, 다른 사용자의 작업이 진행 중인지 먼저 확인해 불필요한 중단을 피하세요.
cd "$HOME/.config/mihomo"
cp -p config.candidate.yaml config.yaml
systemctl --user restart mihomo.service
journalctl --user -u mihomo.service -n 80 --no-pager
curl --proxy http://127.0.0.1:7890 \
--connect-timeout 10 --head https://example.com
# 롤백이 필요할 때 실행:
cp -p config.yaml.before-change config.yaml
systemctl --user restart mihomo.service
원인을 구분할 수 있도록 단계별로 검증하기
첫 번째 단계에서는 설정 파싱과 프로세스 실행을 확인하고, 두 번째 단계에서는 프록시, DNS, 제어 인터페이스가 실제로 수신 중인지 확인합니다. 세 번째 단계에서는 노드 핸드셰이크와 대상 접속을 점검하고, 네 번째 단계에서는 규칙 매칭과 투명 트래픽 가로채기를 확인합니다. 앞 단계의 결과가 분명해야 다음 테스트도 정확히 해석할 수 있습니다. 명시적 프록시는 작동하지만 TUN이 작동하지 않으면 트래픽 가로채기와 권한을 우선 확인하세요. 노드 도메인을 확인할 수 없다면 먼저 초기 DNS 조회를 점검하세요. 접속은 되지만 출구가 잘못되었다면 클라이언트를 반복해서 재설치하지 말고 규칙 순서와 그룹 선택을 확인하세요.
롤백 후에도 결과를 확인해야 합니다. 파일을 복원한 뒤 서비스가 실제로 다시 불러왔는지, Provider가 업데이트된 상태로 남아 있는지, 클라이언트가 포트와 DNS를 다시 덮어쓰지 않았는지 확인하세요. 구독 업데이트 이후에만 문제가 발생했다면 민감한 정보를 제거한 구조 차이를 저장하고 노드 이름, 프로토콜 필드, 그룹 필터 조건을 확인하세요. 업데이트 작업을 영구적으로 꺼서는 안 됩니다. 변경 원인을 찾았다면 유지보수 기록에는 변경 목적, 관련 필드, 테스트 결과, 복구 방법만 적으면 됩니다. 계정 정보가 포함된 전체 로그를 저장할 필요는 없습니다.
장기적으로 관리하려면 실제 요구 사항에 맞춰 불필요한 설정을 줄이세요. 사용하지 않는 입구는 닫아 두고, 서비스별 예외 범위는 명확히 하며, 원격 규칙 세트의 출처를 추적할 수 있게 하고, 시작 서비스를 담당하는 주체를 하나로 정하세요. 새 필드를 추가하기 전에 현재 커널에서 지원하는지, 클라이언트가 설정을 생성하는 과정에서 제거하지 않는지 확인해야 합니다. 동작을 확신할 수 없다면 입문 가이드의 가장 짧은 검증 경로를 다시 따라가거나 문제 해결 절차에 따라 오류 정보를 정리하세요. 이 설정 가이드는 필드와 의존 관계를 설명하며, 최종 판단은 로컬에서 불러온 파일과 로그, 새 연결의 실제 결과를 기준으로 해야 합니다.