네트워크 설정 external-controller 태그: Clash Web 패널 YAML

Clash 외부 컨트롤러(External Controller)가 안 열릴 때:bind-address·secret·포트·방화벽을 순서대로 맞추기

Clash·Mihomo 코어는 HTTP로 제어하는 외부 컨트롤러(external-controller)를 통해 Web 대시보드·REST API에 접속합니다. 클라이언트는 켜 두었는데 브라우저가 시간 초과·연결 거절·401 Unauthorized만 돌려줄 때는, YAML의 bind-addresssecret, 실제로 열린 포트, 방화벽이 서로 엇갈린 경우가 많습니다. 아래는 Clash 문서 흐름에 맞춰 한 번에 정렬하는 순서이며, 설치는 다운로드 페이지의 패키지를 기준으로 합니다.

약 20분 읽기
Clash 편집부

1. 이런 증상이면 이 글을 먼저 보면 됩니다

트레이에 Clash는 떠 있는데 http://127.0.0.1:9090 같은 주소에 들어가면 영원히 로딩만 돌아가거나, 연결을 거절(connection refused)했다는 메시지가 나옵니다. 혹은 페이지는 뜨는 대신 401이나 Unauthorized로 API·대시보드가 막힐 수 있습니다. 이때 프록시 노드·구독은 정상이어도, external-controller수신 주소인증 문자열만 틀어져 있을 수 있으니, “인터넷이 안 된다”가 아니라 로컬 HTTP 서버에 손이 닿느냐를 분리해 생각하는 것이 핵심입니다.

2. external-controller가 열어 두는 것

Clash·Mihomo는 설정 파일(또는 GUI가 생성한 구성)에 적힌 external-controller 값(예: 127.0.0.1:9090 또는 0.0.0.0:9090)에서 REST API를 받습니다. 대부분의 데스크톱·모바일 GUI는 이 API를 사용해 트래픽·규칙·노드 목록을 띄웁니다. 즉, 여기가 막히면 “프로그램은 떠 있는데 패널만 안 뜨는” 현상이 그대로 재현됩니다. 반대로, 프록시 품질·TUN·DNS는 별도 축이므로 fake-ip·DNS 글이나 TUN·라우팅 글과 섞지 말고 먼저 API 포트부터 확정하는 편이 빠릅니다.

3. YAML에서 세 줄이 전부: 포트, bind, secret

핵심 키는 아래 셋입니다(일부 구버전·포크는 키 이름이 조금 다를 수 있으니 사용 중인 코어·클라이언트 문서와 병행하세요).

  • external-controllerIP:포트 형식으로 API를 어디에 바인딩할지 지정합니다. IP 부분이 곧 누가 연결해도 되는지의 첫 관문입니다.
  • bind-address — (지원하는 빌드에서) 컨트롤러·혼합 포트 등 수신 주소를 한 번 더 묶어 줄 수 있습니다. external-controller에 이미 IP가 있으면 그쪽이 우선되는 경우가 많으니, 중복 설정이 없는지 GUI가 만든 전체 구성을 펼쳐 보세요.
  • secret — API 요청에 Bearer 토큰 또는 Authorization 헤더로 넣을 공유 비밀입니다. 비어 있으면 로컬에서만 쓰는 용도로 두는 사용자도 있지만, 빈 값과 “실제로는 GUI가 다른 secret을 씀”이 섞이면 401이 납니다.

아래는 이해를 돕기 위한 예시뿐이며, 실제 포트·비밀번호는 본인 환경에 맞게 바꾸십시오.

# Example only — adjust host, port, and secret
external-controller: 127.0.0.1:9090
secret: "your-random-string"

# Some setups also use bind-address (check your client docs)
# bind-address: 127.0.0.1
보안: 0.0.0.0으로 열면 같은 LAN·공유기 뒤 기기에서도 API에 닿을 수 있습니다. 꼭 필요할 때만 쓰고, 반드시 secret을 길고 예측하기 어렵게 유지하며, 불필요한 인바운드는 방화벽에서 막으세요.

4. 본기 브라우저 vs 다른 PC·휴대폰

127.0.0.1(localhost)는 그 기기 안에서만 루프백으로 연결됩니다. 같은 PC의 브라우저로 http://127.0.0.1:9090에 붙는 것은 정상적인 사용입니다. 그런데 다른 랜선·Wi-Fi에 있는 휴대폰이나 노트북에서 접속하려면, Clash를 0.0.0.0:포트 또는 해당 PC의 LAN IP(예: 192.168.0.10:9090)로 듣게 해야 합니다. 이때도 클라이언트가 127.0.0.1만 쓰도록 고정돼 있으면 원격에서 아무리 URL을 쳐도 연결 거절이 납니다. “패널 주소”를 데스크톱 앱이 표시해 주는 경우가 많으니, 실제로 코어에 로드된 YAMLexternal-controller와 한 글자라도 다르면 안 됩니다. LAN에서 혼합 포트·다른 앱과 함께 쓰는 흐름은 Windows Mixed Port·LAN·방화벽 가이드와 맞춰 읽으면 수신 범위를 잡는 감이 잡힙니다.

팁: 휴대폰에서 PC 패널을 열 땐, PC 방화벽뿐 아니라 라우터 AP 격리·게스트 Wi-Fi로 인해 기기 간 통신이 막혀 있지 않은지도 함께 보세요.

5. 401 Unauthorized — secret·헤더·쿼리

API가 secret을 요구하도록 되어 있으면, 단순히 주소만 치는 것으로는 쿠키·토큰 없이 거절됩니다. 브라우저 주소창 GET만으로는 Authorization: Bearer ...를 붙이기 어렵기 때문에, 대시보드 URL에 ?token= 형태를 붙이게 해 주는 GUI도 있고, 별도 “외부 제어” 설정 화면에서 토큰을 복사하라는 안내만 뜨는 경우도 있습니다. 여기서 자주 생기는 실수는 (1) YAML의 secret과 (2) GUI에 입력한 API 키가 다르다는 점, (3) 구성을 바꾼 뒤 코어를 재시작하지 않아 이전 secret이 남는 점입니다. 401이면 “방화벽” 이전에 문자열 일치부터 맞추는 것이 비용 대비가 가장 좋습니다.

6. 포트가 겹치면 listen 자체가 실패

이미 다른 프로그램이 9090을 쓰고 있으면, Clash는 그 포트에 바인딩하지 못하고 실패하거나 이전 프로세스만 응답할 수 있습니다. OS별로 누가 점유 중인지 확인한 뒤, YAML의 포트를 바꾸고 대시보드·북마크·방화벽 규칙을 같은 숫자로 맞추세요. “기본 예시는 9090”이라서 여러 문서에 같은 숫자가 나올 뿐, 실제로는 9091·19090처럼 바꾸는 경우가 흔합니다. Linux·systemd로 띄운다면 journalctl에 bind 실패나 address already in use 흔적이 남는지 같이 보면 원인이 빨리 좁혀집니다.

7. OS 방화벽과 보안 제품

0.0.0.0이나 LAN IP로 API를 열었는데도 원격에서만 안 되면, Clash·코어 프로세스에 대한 인바운드 허용이 OS 방화벽이나 서드파티 백신·엔드포인트에서 막혔을 수 있습니다. Windows는 “개인/공용 프로필”에 따라 규칙이 갈리고, macOS는 첫 연결 시 팝업을 놓쳤을 때 잠깁니다. 반대로 로컬 127.0.0.1만 쓰는 구성이면 방화벽 이슈보다는 앞의 bind-address·external-controller 설정이 틀렸을 가능성이 큽니다. “원격만 안 됨” vs “로컬도 안 됨”을 나누어 보면 다음 단계가 달라집니다. Docker·WSL에서 호스트 API를 쓰는 흐름은 Docker Desktop·ClashWSL2·localhost 글의 주소·프록시 정렬과 겹칩니다.

8. GUI가 쓰는 API 주소와 코어가 읽는 YAML

Clash for Windows, Verge, 안드로이드/아이폰용 앱 등은 자체 “외부 제어” 포트를 UI에 띄우지만, 실제로는 한 개의 구성이 코어에 로드돼 있어야 합니다. (1) UI에서 “외부 API” 켬/끔을 바꾸고, (2) 스킨·대시보드가 가리키는 URL이 9090이 아닌 9091인데 YAML만 9090을 고치는 식이면, 브라우저와 코어가 서로 엇갈립니다. 설정 동기화 후 재시작·구독/프로필 다시 읽기를 한 뒤, 하나의 글external-controller를 검색해 충돌이 없는지 보는 것이 안전합니다. 안드로이드에서 API·로그는 Clash Meta Android 흐름과 함께 점검하는 편이 수월합니다.

9. 체크리스트 — 위에서 아래로

  1. Clash(코어) 프로세스가 실제로 떠 있는지, 트레이만 남고 코어는 죽지 않았는지
  2. 로드된 구성에 있는 external-controllerIP:포트가 브라우저/북마크와 완전히 동일한지(오타·http/https)
  3. 원격 접속이면 127.0.0.1이 아닌 0.0.0.0·LAN IP로 바인딩했는지
  4. secret이 있으면 대시보드·툴에 같은 값이 들어갔는지(변경 후 재시작)
  5. 포트 충돌·bind 실패 로그가 없는지
  6. 윈·맥·리눅스 방화벽·백신이 인바운드를 막지 않는지(원격일 때)

11. 맺음말

외부 컨트롤러는 프록시 품질과 별도로, 로컬 HTTP 서버가 어디에·어떤 인증으로 떠 있느냐의 문제입니다. bind-addresssecret, 포트, 방화벽을 한 줄로 맞추면 “클라이언트는 켰는데 패널만 죽는” 상황의 대부분을 건너뛸 수 있습니다. 설정을 자주 옮기는 환경이라면, 문서에 맞는 최소 구성을 유지한 채, 앱이 고른 포트에만 집중하는 편이 가장 덜 꼬입니다.

바이너리는 배포·업데이트 경로를 통일해 두는 것이 좋고, 공식 다운로드에서 설치·재설치 흐름을 맞춰 두면 UI와 코어 버전이 어긋나며 생기는 “보이는 포트” 혼란도 줄어듭니다. 다른 툴 대비 Clash·Mihomo 계열은 동일한 YAML·REST 모델로 데스크톱·서버·모바일을 아우를 수 있어, 한 번 API 주소를 제대로 잡아 두면 이후 룰·노드 튜닝에 쓸 시간이 아낍니다.

Clash를 무료로 내려받아 external-controller·Web 패널을 다시 맞춰 보세요