외부 제어 포트가 왜 «한 번 털리면 끝장»인가

Clash·mihomo(Clash Meta) 계열 코어는 설정 파일뿐 아니라, 런타임에 REST API로 상태를 조회하고 /configs 등 엔드포인트를 통해 실행 중 구성을 갱신할 수 있습니다. 이 말은 곧 «해당 포트에 쓰기 권한이 있는 주체는 프록시 정책을 바꾸거나, 구독 URL·노드 메타데이터를 읽어 갈 수 있다»는 뜻입니다. 집·기숙사·카페처럼 같은 L2 브로드캐스트 도메인에 낯선 기기가 붙어 있거나, 공유기에서 포트 포워딩을 잘못 열어 둔 경우, 의도치 않게 «작은 관리 포트 하나»가 공격 면이 됩니다.

Yacd·Yacd-meta·각종 «웹 대시보드」는 정적 파일을 브라우저가 열 뿐이고, 실제 제어는 사용자가 입력한 IP:포트로 향합니다. 그래서 «패널만 열었는데 왜 위험하지?»라고 느끼기 쉽지만, 코어가 듣는 주소인증 유무가 곧 보안 경계입니다. Windows에서 LAN으로 프록시를 공유할 때는 mixed 포트와 별개로, 관리 포트가 LAN에 노출됐는지까지 같이 봐야 합니다.

전제 여기서는 «합법적인 자기 장비를 남이 못 건드리게 한다»는 관점입니다. 타인의 네트워크·시스템에 무단 접속하는 행위는 법적 문제가 될 수 있으며, 본문은 방어·설정 목적의 기술 설명에 한합니다.

1단계: external-controller를 127.0.0.1에 고정하기

가장 효과가 크고 되돌리기 쉬운 조치는 루프백 바인딩입니다. 127.0.0.1:9090처럼 쓰면 같은 기기 안의 브라우저·CLI·패널(로컬로 연 경우)만 접속할 수 있고, 다른 PC·휴대폰은 직접 IP로는 붙지 않습니다. 반대로 0.0.0.0:9090 또는 LAN IP를 명시하면, 방화벽이 허용하는 한 동일 네트워크 세그먼트에서 스캔에 걸리기 쉽습니다.

IPv6만 켜진 환경에서는 [::1]·듀얼 스택 동작을 함께 확인하세요. 클라이언트 GUI가 생성한 YAML이 매 업데이트마다 0.0.0.0으로 되돌아간다면, GUI 쪽 «외부 제어 주소» 옵션을 루프백으로 맞춘 뒤 재생성·동기화되는지 확인하는 것이 좋습니다. 헤드리스 Linux에 올린 경우는 systemd 유닛과 설정 경로가 단일 진실 원천인지부터 정리하세요.

# Example: loopback only (adjust port to your client)
external-controller: 127.0.0.1:9090

원격에서 꼭 제어해야 한다면 코어 포트를 직접 인터넷에 내지 말고, SSH 로컬 포트 포워딩(ssh -L 9090:127.0.0.1:9090)·와이어가드·집 VPN 등으로 먼저 신원·채널을 확보한 뒤 로컬호스트로만 붙는 패턴이 일반적으로 안전합니다. 공유기 OpenWrt·게이트웨이에서 Clash를 돌릴 때도, 관리 포트를 WAN 쪽 규칙과 분리했는지 점검表에 넣어 두면 실수를 줄일 수 있습니다.

2단계: secret(API Secret)를 비우지 않기

secret 필드는 외부 제어·일부 관련 엔드포인트에 대한 공유 비밀 역할을 합니다. 비어 있으면 «같은 포트에 도달만 하면 누구나»에 가깝고, 짧고 추측하기 쉬운 문자열이면 사전·무차별 시도에 취약합니다. 랜덤 32바이트 이상을 Base64나 안전한 비밀번호 생성기로 만들고, 패널·스크립트·모바일 앱에 동일하게 넣으세요.

# Use a long random secret; never commit real secrets to git
secret: "replace-with-long-random-string"

구독 URL·노드 비밀번호와 같은 문자열을 재사용하지 마세요. 한쪽이 유출됐을 때 연쇄로 관리 API가 털리는 일을 막을 수 있습니다. 팀 PC라면 1Password·Bitwarden 등에만 보관하고, 채팅·스크린샷으로 공유하지 않는 습관이 필요합니다.

3단계: 요청 헤더와 쓰기 메서드 인증

대부분의 최신 Clash 계열은 HTTP API에 Authorization: Bearer <secret> 또는 동등한 헤더를 요구합니다. curl로 점검할 때도 헤더 없이 GET /version만 보지 말고, PUT /configs 같은 쓰기 가능한 경로가 401·403으로 막히는지 확인하세요. 반대로 헤더 없이 200이 나오면 아직 잠기지 않은 것입니다.

자동화 스크립트는 환경 변수에 시크릿을 두고 런타임에만 주입하는 편이 좋습니다. CI 로그에 URL이 찍히지 않게 하고, 실패 시 응답 본문에 시크릿이 에코되지 않는지도 확인합니다. 프록시 체인 뒤에서 관리 API를 호출할 때는 루프백 트래픽이 실수로 업링크 프록시를 탄다 같은 설정 실수가 없는지, 클라이언트별 «로컬 주소 제외」 목록을 함께 봅니다.

Yacd·웹 패널과의 연결 실무

브라우저에서 Yacd를 열고 API 주소에 http://127.0.0.1:9090을 넣었다면, 패널 JavaScript는 사용자 PC에서 해당 주소로 XHR을 보냅니다. 이 구성은 코어가 같은 PC에서 돌고 외부 제어가 루프백일 때 가장 단순합니다. 휴대폰 브라우저에서 http://데스크톱-LAN-IP:9090을 넣고 싶다는 욕구가 생기는데, 그 순간이 바로 0.0.0.0 바인딩·방화벽 개방으로 가는 분기점입니다.

모바일에서 상태만 보고 싶다면 (1) SSH 터널로 9090을 전달하거나, (2) 코어는 루프백 유지 + 중간에 인증 있는 리버스 프록시만 노출하는 방식을 검토하세요. 리버스 프록시를 쓸 때는 TLS 종료·rate limit·소스 IP 제한을 함께 두는 것이 좋습니다. «패널은 편하니까»라고 인증 없이 nginx만 얹는 경우가 있는데, 그때는 Clash 시크릿과 별개로 또 다른 공격 면이 생깁니다.

Allow LAN·mixed-port와 헷갈리지 않기

많은 GUI에서 Allow LAN은 «프록시 포트를 LAN에 공개할지»에 가깝고, external-controller는 별도 항목입니다. 그러나 제품·버전에 따라 한 스위치가 여러 포트에 영향을 주기도 하므로, 실제로는 ss·netstat·OS 방화벽 로그로 어느 프로세스가 어느 인터페이스에서 LISTEN 중인지를 한 번씩 확인하는 것이 확실합니다. Windows에서는 Defender 방화벽 인바운드 규칙과 함께 읽으면 맥락이 이어집니다.

프록시는 LAN에 열어 두되 관리 API는 루프백만—같은 장비에서 역할을 나누면, 가족·동료에게 «인터넷만 공유»하고 «정책 편집 권한»은 나에게만 남기기 쉽습니다.

Docker·VPS·클라우드 이미지에서의 추가 주의

컨테이너는 기본 브리지에서 0.0.0.0 매핑이 습관화되어 있어, 호스트 방화벽 없이 -p 9090:9090만 하면 외부에서 바로 보일 수 있습니다. 가능하면 포트 퍼블리시를 하지 않고 같은 Docker 네트워크의 사이드카·로컬 소켓만 쓰거나, 호스트 루프백에만 바인딩하세요. 클라우드 보안 그룹에서 9090을 전 세계 0.0.0.0/0에 연 경우, 스캐너가 먼저 찾아옵니다.

VPS에 헤드리스로 올렸다면 SSH·VPN 없이 관리 API를 열어두지 마세요. 최소한 시크릿·방화벽·관리자 IP 제한을 세트로 적용하고, 불필요하면 관리 포트 퍼블리시 자체를 제거합니다.

점검 체크리스트(복사해 두고 주기적으로 확인)

  • 리슨 주소: external-controller127.0.0.1(또는 필요한 최소 범위)인가.
  • secret: 비어 있지 않고, 추측 불가능한가. 유출 시 즉시 교체할 수 있는가.
  • 쓰기 API: 인증 없이 설정 변경이 되지 않는가.
  • 패널: 브라우저에 저장된 API URL이 실수로 LAN/공인을 가리키지 않는가.
  • 방화벽: OS·공유기·클라우드 SG에서 9090 등 관리 포트가 불필요하게 개방돼 있지 않은가.
  • 포트 포워딩: 게임·원격데스크톱용 규칙과 섞여 관리 포트가 밖으로 나가지 않았는가.
  • 구독·백업: 프로필에 구독 링크·API 키가 들어 있다면, 제어 API가 열려 있을 때 함께 노출될 수 있음을 인지하는가.

구독 자동 갱신·403 문제는 구독 URL·UA·시간 동기화 글과 연결되지만, «URL이 새는 경로」 관점에서는 관리 API 노출도 같은 대화 안에 두는 것이 좋습니다.

자주 묻는 질문

external-controller를 0.0.0.0으로 두면 왜 위험한가요?

모든 인터페이스에서 REST API 포트가 열려 같은 Wi‑Fi의 기기, 혹은 포트 포워딩·DMZ가 있을 때 공인망 스캔에도 노출될 수 있습니다. secret이 비어 있거나 기본값이면 규칙·프록시·구독 URL을 읽고 바꾸는 요청이 무인증으로 통과할 위험이 큽니다. 가능하면 127.0.0.1(또는 ::1)만 리슨하고, 원격에서는 SSH 터널·VPN·리버스 프록시 뒤 TLS와 별도 인증으로만 노출하세요.

Yacd·메타광 패널은 어떤 주소로 붙여야 하나요?

패널 HTML은 브라우저에서 열리지만, API는 사용자가 입력한 external-controller 주소로 연결됩니다. 코어가 127.0.0.1:9090만 듣는다면 같은 PC의 브라우저에서만 패널이 동작합니다. 휴대폰에서 패널을 쓰려고 0.0.0.0으로 열었다면, 반드시 secret을 강하게 두고 방화벽으로 소스 IP를 제한하거나, SSH -L로 로컬 포트를 전달하는 편이 안전합니다.

Allow LAN과 external-controller는 어떤 관계인가요?

Allow LAN은 보통 mixed-port·SOCKS·HTTP 프록시가 LAN 인터페이스에서 접속을 받을지 여부와 연관됩니다. external-controller는 별도 키로 리슨 주소를 지정하는 것이 일반적이라, «프록시만 LAN에 열고 API는 루프백»처럼 역할을 분리할 수 있습니다. LAN 공유 전체 절차는 Windows 방화벽·포트 정리 글과 함께 보는 것이 좋습니다.

API Secret을 바꾼 뒤 패널이 401이면 어디를 확인하나요?

설정 YAML의 secret과 패널에 입력한 토큰이 일치하는지, 공백·따옴표·클라이언트가 덮어쓴 런타임 설정이 없는지 확인하세요. Clash 계열은 Authorization: Bearer 형태를 쓰는 경우가 많습니다. 구버전·포크는 헤더 이름이 다를 수 있으므로 해당 클라이언트 문서와 실제 401 응답 본문을 함께 보세요.

마무리: 편의와 안전의 균형

외부 제어는 규칙 실험·자동화·패널 시각화에 매우 유용하지만, 인증 없는 관리 포트는 작은 실수로 큰 노출로 이어집니다. 127.0.0.1 바인딩과 강한 secret은 구현 비용 대비 효과가 크고, 이미 무료 클라이언트구독 링크만으로도 충분히 적용할 수 있습니다. 정책 YAML을 더 깊게 다루려면 YAML 규칙 분기 가이드와 짝을 이루어 읽고, 설치·업데이트는 다운로드 페이지에서 플랫폼별 패키지를 맞추면 흐름이 끊기지 않습니다.

다른 주제의 심화 글은 기술 칼럼 목록에서 이어서 선택할 수 있습니다.

Clash 무료 다운로드 — 검증된 빌드로 클라이언트를 받고, 외부 제어는 루프백·시크릿으로 잠근 채 규칙·구독 링크를 안전하게 다루어 보세요.

추가 설정이 필요하면 도움말을 참고해 주세요.