GUI 대신 external-controller API를 쓰는 이유
Clash에서 노드를 바꾸는 가장 쉬운 방법은 GUI의 프록시 그룹 화면을 열고 원하는 항목을 클릭하는 것입니다. 하지만 개발 PC에서 여러 작업을 반복하거나, 모니터와 키보드가 없는 홈 서버·CI 머신에서 프록시를 운영한다면 이 방식은 곧 한계에 부딪힙니다. 사람이 직접 화면을 확인하지 않아도 현재 응답이 빠른 노드를 찾고, 특정 정책 그룹의 선택 항목을 바꾸고, 장애가 발생했을 때 다시 시도하려면 external-controller API를 사용하는 편이 훨씬 일관적입니다.
Mihomo 계열 코어는 HTTP API 형태의 컨트롤러를 제공하며, 실행 중인 프로필의 상태 조회와 정책 그룹 변경을 요청으로 처리할 수 있습니다. Clash Verge Rev, Mihomo Party처럼 Mihomo 코어를 사용하는 클라이언트에서는 코어가 실행 중이고 컨트롤러가 활성화되어 있다면 같은 원리로 접근할 수 있습니다. 반면 클라이언트마다 메뉴 이름, 기본 포트, 인증 토큰 입력 위치가 다르므로 GUI의 브랜드보다 실제로 실행 중인 코어 설정과 API 응답을 기준으로 확인해야 합니다.
자동 전환의 핵심은 단순히 “핑이 가장 작은 노드”를 고르는 데 있지 않습니다. 테스트 대상 URL, DNS 응답, TCP 연결, TLS 협상, HTTP 상태 코드가 서로 다른 결과를 만들 수 있기 때문입니다. ICMP 핑이 빠른 노드가 실제 HTTPS API에서는 느릴 수 있고, 짧은 테스트는 통과했지만 장시간 스트리밍에서 끊기는 노드도 있습니다. 따라서 이 글에서는 컨트롤러 연결 확인 → 그룹과 노드 조회 → 실제 URL 테스트 → 그룹 전환 → 재시도와 복구라는 운영 순서로 구성합니다.
external-controller 활성화와 컨트롤러 보안
external-controller는 코어의 HTTP API를 외부에 노출하는 설정입니다. 설정하지 않았거나 코어가 완전히 시작되기 전에 요청하면 연결 거부가 발생합니다. 일반적으로 컨트롤러 주소는 로컬호스트와 특정 포트 조합으로 지정하며, API를 호출할 때는 설정한 secret을 인증 헤더에 넣습니다. 포트 번호는 클라이언트와 프로필에 따라 다를 수 있으므로 예시 값을 실제 설정에 그대로 복사하지 말고, 현재 코어가 사용하는 값을 확인해야 합니다.
external-controller: 127.0.0.1:9090
secret: change-this-to-a-long-random-token
개발 PC에서만 사용할 목적이라면 127.0.0.1 또는 localhost에 바인딩하는 것이 첫 번째 선택입니다. 0.0.0.0으로 열면 같은 LAN의 다른 장치가 접근할 가능성이 생기며, 방화벽 규칙이나 공유기 설정에 따라 인터넷에 노출될 위험도 있습니다. 컨트롤러는 단순한 상태 조회 API가 아니라 정책 그룹 변경, 프로필 제어, 연결 종료처럼 실질적인 제어 권한을 가질 수 있으므로 일반 웹 서버 포트처럼 가볍게 다루면 안 됩니다.
원격 서버에서 관리해야 한다면 직접 공인 주소로 포트를 열기보다 SSH 터널, 사설 네트워크, 접근 제어가 있는 리버스 프록시를 우선 고려하세요. secret은 저장소에 커밋하거나 셸 명령에 평문으로 반복해서 남기지 않는 것이 좋습니다. 자동화 서비스에서는 환경 변수나 권한이 제한된 비밀 저장소를 사용하고, 로그를 남길 때는 토큰 전체를 출력하지 마세요. 테스트가 끝난 뒤 컨트롤러가 정말 필요한지 다시 판단하고, 사용하지 않는 원격 바인딩은 닫는 것이 안전합니다.
연결 확인은 가장 작은 요청부터 시작합니다. 아래처럼 인증 헤더를 포함해 컨트롤러의 버전 또는 설정 일부를 읽어 보세요. 응답이 오지 않으면 먼저 노드 품질보다 주소, 포트, secret, 방화벽, 코어 실행 상태를 점검해야 합니다.
curl -sS \
-H "Authorization: Bearer YOUR_SECRET" \
http://127.0.0.1:9090/version
프록시 노드와 정책 그룹을 API로 읽기
자동 전환을 만들기 전에 API가 반환하는 데이터 구조를 직접 읽어야 합니다. /proxies 응답에는 개별 노드뿐 아니라 정책 그룹도 함께 포함됩니다. 그룹은 보통 type, 현재 선택된 now, 선택 가능한 자식 목록을 갖고 있으며, 자식 목록에는 노드 이름과 다른 중첩 그룹이 섞일 수 있습니다. 따라서 모든 이름을 무조건 노드로 취급하지 말고, 먼저 목표 그룹을 정확히 찾은 뒤 그 그룹의 all 배열을 순회하는 방식이 안전합니다.
curl -sS \
-H "Authorization: Bearer YOUR_SECRET" \
http://127.0.0.1:9090/proxies
실제 운영에서는 이름에 이모지, 지역명, 제공자 접두사, 공백이 포함될 수 있습니다. 예를 들어 화면에는 “자동 선택”처럼 보이더라도 API의 키는 다른 문자열일 수 있고, 노드 이름에 괄호나 슬래시가 들어가면 URL 경로에 직접 붙일 때 인코딩 문제가 생깁니다. 가능하면 응답을 JSON 파서로 읽고, 이름을 수동으로 이어 붙이는 대신 HTTP 클라이언트가 경로 인코딩을 처리하도록 하세요.
| 확인 대상 | 확인할 값 | 자동화에서의 용도 |
|---|---|---|
| 컨트롤러 | 주소, 포트, secret | API 연결과 인증 검증 |
| 정책 그룹 | 그룹 키, type, now | 전환 요청의 대상 지정 |
| 노드 목록 | 이름, 지연 시간, 상태 | 테스트 후보 필터링 |
| 실제 연결 | HTTP 상태와 소요 시간 | 최종 노드 선정 |
후보 필터링에서는 “이름에 숫자가 들어간 항목”처럼 불안정한 규칙보다 제공자 접두사, 지역 태그, 노드 타입처럼 자신이 관리하는 명명 규칙을 사용하는 편이 낫습니다. DIRECT, REJECT, GLOBAL, 자동 그룹 같은 특수 항목은 일반 노드와 구분해야 하며, 중첩된 정책 그룹을 후보에 넣을지 여부도 미리 결정해야 합니다. 후보가 한 개뿐이면 자동 전환을 실행하지 않고 현재 선택을 유지하는 것이 오히려 안전합니다.
핑 테스트보다 실제 URL 테스트가 중요한 이유
API에는 노드의 지연 시간을 측정하는 기능이 제공되는 경우가 있습니다. 특정 노드에 테스트 URL과 제한 시간을 지정하면 코어가 해당 노드를 통해 연결을 시도하고 결과 시간을 반환합니다. 이 방식은 GUI를 열지 않고도 후보를 비교할 수 있다는 장점이 있지만, 테스트 URL이 실제 업무 트래픽을 대표하지 않으면 판단이 왜곡됩니다. 일반적인 웹 페이지는 캐시되어 빠르게 응답할 수 있고, 반대로 인증이 필요한 API는 별도의 지역 제한이나 속도 제한을 적용할 수 있습니다.
curl -sS -G \
-H "Authorization: Bearer YOUR_SECRET" \
--data-urlencode "url=https://www.gstatic.com/generate_204" \
--data-urlencode "timeout=5000" \
"http://127.0.0.1:9090/proxies/Proxy%20Node%201/delay"
테스트 URL은 목적별로 나누어 생각하세요. 단순한 인터넷 연결 확인에는 작고 빠른 204 응답 주소가 적합하고, 개발 도구를 위한 전환이라면 실제로 사용하는 API의 안정적인 헬스 엔드포인트가 더 현실적입니다. 다만 모든 요청을 자동 테스트로 보내면 서비스 측 레이트 리밋을 건드릴 수 있으므로, 인증 요청이나 비용이 발생하는 엔드포인트는 피해야 합니다. 테스트 URL은 공개적으로 접근 가능하고 응답 형식이 일정하며, 개인정보나 비밀 키를 요구하지 않는 주소가 좋습니다.
단일 측정값으로 우승자를 정하면 순간적인 네트워크 변동에 쉽게 흔들립니다. 같은 노드를 두세 번 측정하고 중앙값을 사용하거나, 일정 시간 동안 성공률과 지연을 함께 기록하세요. 예를 들어 500ms 이내라도 다섯 번 중 두 번 타임아웃이면 안정적인 후보로 보기 어렵습니다. 반대로 평균이 약간 느려도 모든 요청이 성공하는 노드가 장시간 작업에는 더 적합할 수 있습니다.
또한 노드 테스트와 정책 그룹 테스트를 구분해야 합니다. 노드 API가 성공했다고 해서 애플리케이션 트래픽이 반드시 같은 경로를 타는 것은 아닙니다. 규칙이 다른 그룹을 선택하거나 특정 도메인이 DIRECT로 빠지면 실제 프로그램의 결과는 달라집니다. 전환 후에는 연결 로그에서 대상 도메인, 사용된策略 그룹, 최종 노드가 예상과 일치하는지 확인해야 합니다.
정책 그룹 전환, 재시도, 실패 복구
후보를 선정했다면 정책 그룹에 원하는 노드를 지정하는 요청을 보냅니다. 일반적으로 그룹 키를 URL 경로에 넣고, 요청 본문에 선택할 노드 이름을 JSON으로 전달합니다. 여기서 반드시 알아둘 점은 전환 API의 성공 응답이 “노드 자체의 인터넷 연결 성공”을 의미하지 않는다는 사실입니다. 성공은 코어가 설정 변경을 받아들였다는 뜻에 가깝기 때문에, 전환 직후 실제 대상 URL을 다시 호출해 검증해야 합니다.
curl -sS -X PUT \
-H "Authorization: Bearer YOUR_SECRET" \
-H "Content-Type: application/json" \
--data '{"name":"Proxy Node 1"}' \
"http://127.0.0.1:9090/proxies/PROXY_GROUP"
자동화 순서는 다음처럼 짜면 이해하기 쉽습니다. 먼저 현재 그룹과 후보 목록을 읽고, 제외 목록에 있는 노드와 최근 실패 노드를 제거합니다. 다음으로 각 후보의 테스트 결과를 수집하고, 성공률·지연·최근 사용 시점을 기준으로 점수를 계산합니다. 가장 높은 후보를 그룹에 적용한 뒤 실제 요청을 한 번 더 실행합니다. 검증이 실패하면 즉시 같은 노드를 반복하기보다 다음 후보로 넘어가고, 모든 후보가 실패했을 때만 현재 선택을 유지하거나 관리자에게 알림을 보내도록 합니다.
- 컨트롤러 확인: 인증과 코어 응답을 먼저 검증합니다.
- 그룹 조회: 전환할 정책 그룹의 정확한 키와 현재 선택을 읽습니다.
- 후보 측정: 노드별 URL 테스트를 실행하고 타임아웃과 HTTP 오류를 기록합니다.
- 그룹 변경: 선택된 노드 이름을 JSON 요청으로 전달합니다.
- 사후 검증: 실제 업무 URL과 Clash 연결 로그를 확인합니다.
- 복구 처리: 실패하면 백오프 후 다음 후보를 시도하고, 반복 횟수를 제한합니다.
재시도에는 지수 백오프를 적용하는 것이 좋습니다. 첫 실패 후 1초, 다음 실패 후 2초, 다시 4초처럼 간격을 늘리면 일시적인 DNS 지연이나 제공자 측 순간 오류가 연속 요청으로 증폭되는 것을 막을 수 있습니다. 다만 무인 서버에서 너무 긴 대기 시간을 두면 장애 감지가 늦어지므로 최대 대기 시간과 전체 실행 제한 시간을 별도로 둬야 합니다. 같은 실행에서 노드를 계속 순환하는 것도 피하세요. 짧은 시간 동안 정책을 여러 번 바꾸면 기존 TCP 세션이 끊기고, 어떤 노드가 실제로 성공했는지 로그가 복잡해집니다.
실행 중인 스트리밍 연결이나 다운로드를 노드 전환으로 강제로 살릴 수는 없습니다. 그룹 변경은 대체로 새 연결에 영향을 주며, 이미 열린 연결은 이전 경로를 유지하거나 오류가 난 뒤 재연결됩니다. 그러므로 애플리케이션 자체에도 요청 재개, 타임아웃, 중복 실행 방지 로직이 필요합니다. 자동 전환 스크립트는 모든 네트워크 문제를 해결하는 만능 장치가 아니라, 정해진 조건에서 출구를 바꾸는 운영 보조 계층으로 설계해야 합니다.
운영 스크립트 설계와 안전한 검증
간단한 개인용 스크립트라면 셸과 curl만으로도 시작할 수 있지만, 여러 노드와 장시간 실행을 다루면 Python이나 Node.js처럼 JSON과 예외 처리가 편한 언어가 유리합니다. 스크립트에는 컨트롤러 주소, 토큰, 그룹 이름, 테스트 URL, 후보 필터, 타임아웃, 최소 성공률, 최대 재시도 횟수를 설정값으로 분리하세요. 노드 이름을 코드에 하드코딩하기보다 API에서 읽고 정규화하면 구독 갱신으로 이름이 바뀌었을 때 수동 수정이 줄어듭니다.
로그에는 측정 시각, 그룹 이름, 후보 이름, 응답 시간, 성공 여부, 전환 결과를 남기면 좋습니다. 단, secret 헤더와 구독 URL, 인증 쿠키, 업무 요청 본문은 반드시 마스킹해야 합니다. 실패 원인도 하나의 문자열로 뭉개지 말고 컨트롤러 연결 실패, 노드 테스트 타임아웃, 그룹 변경 거부, 사후 검증 실패로 나누면 원인을 빠르게 분리할 수 있습니다. 특히 API가 401을 반환하면 노드 문제가 아니라 secret 또는 인증 헤더 형식부터 확인해야 합니다.
처음에는 실제 그룹을 바꾸지 않는 dry-run 모드로 후보 순위만 출력하세요. 예상한 그룹 키와 노드 이름이 맞는지, 테스트 URL이 너무 자주 호출되지 않는지, 실패 노드가 계속 1순위로 올라오지 않는지 확인한 뒤 쓰기 요청을 활성화합니다. 운영 서버에서는 설정 파일 권한을 제한하고, 자동화 프로세스가 필요한 API만 호출하도록 네트워크 범위를 줄이는 것도 중요합니다. 컨트롤러 API는 로컬 관리 인터페이스이므로 브라우저의 CORS 정책을 우회하는 용도로 노출해서는 안 됩니다.
실전 기준: “가장 빠른 노드”보다 “정해진 시간 안에 반복해서 성공하는 노드”를 우선하세요. 지연 시간이 50ms 낮아도 실패율이 높으면 개발 작업, 패키지 다운로드, 원격 셸 세션에서는 오히려 전체 처리 시간이 길어집니다.
Clash for Windows처럼 오래된 GUI는 external-controller 메뉴와 코어 호환성이 제한될 수 있고, 단순한 GUI 수동 전환은 무인 환경이나 반복 테스트를 처리하지 못합니다. 반대로 Clash Verge Rev와 Mihomo 기반 클라이언트는 코어 API를 활용하기 쉬우며, 스크립트로 그룹 조회·URL 테스트·재시도·로그 기록을 한 흐름으로 묶을 수 있습니다. 자동 전환과 API 운영을 안정적으로 시작하려면 컨트롤러 보안 설정과 Mihomo 코어 호환성을 함께 확인할 수 있는 Clash V.CORE를 사용해 보세요. 현재 환경에 맞는 패키지는 다운로드 페이지로 이동해 확인하면 됩니다.
// 에디터 추천
Clash V.CORE — API 자동 전환을 위한 안정적인 기반
external-controller와 정책 그룹을 활용해 GUI에 의존하지 않는 노드 점검·전환 환경을 구성하세요.
- external-controller 연동에 적합한 코어 환경
- 정책 그룹과 노드 상태를 한눈에 확인
- URL 테스트와 재시도 흐름을 쉽게 구성
- 개발 PC와 무인 서버 운영을 함께 지원
- 로컬 바인딩 중심의 컨트롤러 보안 설정