보안 및 개인정보 보호 · Clash 기술 블로그

Clash Dashboard에 안전하게 원격 접근하는 방법

Dashboard는 실제로 노드 전환, 구성 변경 및 연결 종료가 가능한 제어 인터페이스에 연결됩니다. 원격으로 사용해야 한다면 수신 주소를 제한하고 secret을 설정한 뒤 내부 네트워크나 터널을 통해 접근하세요.

  • 보안
  • Dashboard
  • secret
이 글의 목차

원격 패널은 트래픽을 보여 주는 것뿐 아니라 설정을 바꾸고 연결을 종료할 수 있는 제어 인터페이스에도 연결됩니다. 페이지가 열린다고 해당 인터페이스에 안전하게 연결된 것은 아닙니다. 수신 대기 범위, 접속 인증, 웹페이지 출처를 각각 확인해야 하며 출처 제한으로 인증을 대신할 수는 없습니다. 인증 정보가 없거나 잘못된 요청이 모두 거부되는지 확인한 뒤 임시 터널이나 장기 원격 접속 방식을 선택하세요.

구성을 변경할 수 있는 Dashboard의 접근 권한 제한

external-controller 설정에서 실제 수신 대기 포트(예: 9090)와 접속 가능한 범위를 확인하세요. Clash Dashboard는 이 REST API로 연결, 트래픽, 프록시 그룹, 규칙을 읽으며, 노드 전환, 설정 다시 로드, 일부 실행 설정 변경, 연결 종료도 할 수 있습니다. 인터넷에 직접 공개하는 것은 읽기 전용 상태 페이지를 공개하는 것보다 훨씬 위험합니다.

접속 환경별 권장 진입점

상황수신 방식접속 제한
로컬 클라이언트 내장 패널127.0.0.1:9090강력한 secret을 사용해 임의의 웹페이지가 로컬 인터페이스를 호출하지 못하게 함
홈 LAN 내부 관리명시적인 LAN 주소 또는 제한된 수신방화벽에서 관리 기기 또는 사설 네트워크 대역만 허용
외부에서 일시적으로 유지보수수신은 계속 로컬 기기로 제한SSH 로컬 포워딩 사용, 필요하면 Tailscale을 통해 해당 포워딩 연결
인터넷 공개 서비스직접 공개는 권장하지 않음최소한 독립된 리버스 프록시, TLS, 인증, 출처 제한이 필요함

로컬 수신 대기와 secret 인증 설정 및 테스트

최종 적용되는 Mihomo 설정에서 external-controller를 127.0.0.1에 바인딩하세요. 그래픽 클라이언트가 '설정 → 외부 컨트롤러' 또는 덮어쓰기 파일을 통해 이 필드를 생성할 수 있으므로 구독 원문을 수정해도 적용되지 않을 수 있습니다. 다시 로드한 뒤 최종 설정과 실제 수신 상태를 확인해야 합니다.

REPLACE_WITH_RANDOM_SECRET은 자리 표시자입니다. 비밀번호 관리자로 긴 무작위 값을 생성하고 Mihomo 구성과 Dashboard 연결 설정의 값을 바꾼 뒤 다시 불러오세요. 예시 자리 표시자를 비밀번호로 사용하지 마세요.

로컬 Dashboard 전용 시작 설정
external-controller: 127.0.0.1:9090
secret: "REPLACE_WITH_RANDOM_SECRET"
9090에서 수신 중인 프로세스 확인
# Windows PowerShell
Get-NetTCPConnection -LocalPort 9090 -State Listen

# Linux / OpenWrt
ss -lntp | grep ':9090'

secret은 이 글에서 다루는 TCP 제어 인터페이스의 Bearer Token입니다. 빈 값은 이 인증을 제공하지 않으며 짧은 비밀번호는 추측하기 쉽습니다. 여러 기기에서 재사용하면 유출 피해도 커집니다. 전체 token을 스크린샷, 프런트엔드 저장소, 공개 장애 로그에 넣지 마세요.

인증 정보 없음, 잘못된 인증 정보, 올바른 인증 정보를 각각 테스트하기
# 无 Authorization,应返回未授权,而不是接口数据
curl -i http://127.0.0.1:9090/version

# 错误 token 也必须被拒绝
curl -i -H "Authorization: Bearer WRONG_TOKEN" http://127.0.0.1:9090/version

# 只在自己的终端中替换 REAL_TOKEN
curl -i -H "Authorization: Bearer REAL_TOKEN" http://127.0.0.1:9090/version

인증 적용 확인 결과

  • Authorization이 없는 요청은 버전 JSON 대신 401을 받음
  • 올바른 secret으로 /version을 읽을 수 있음
  • 잘못된 secret도 거부됨
  • Dashboard를 새로 고친 뒤 연결과 프록시 그룹이 정상적으로 표시됨
  • 로그와 브라우저 주소 표시줄에 secret이 노출되지 않음

Dashboard가 열리지 않는다고 CORS를 임의의 출처에 허용하지 마세요

원격 호스팅 Dashboard는 브라우저에서 external-controller로 요청을 보내는 웹페이지 출처입니다. CORS는 어떤 웹페이지 출처가 인터페이스를 호출할 수 있는지만 제한하며 사용자 인증을 대신할 수 없습니다.

allow-origins를 *로 설정하고 사설 네트워크 요청까지 허용하면 임의의 웹페이지가 로컬 호스트나 로컬 네트워크의 제어 포트에 접근을 시도하기 쉬워집니다. secret을 설정했더라도 유출 후 악용될 수 있는 범위가 더 넓어집니다.

먼저 Dashboard의 실제 origin(예: https://dashboard.example.com)을 확인한 뒤, 이 전체 출처만 허용하세요. 도메인, 프로토콜 또는 포트가 바뀌면 각각 다른 origin이 됩니다. 설정에 있는 UI 정적 파일 경로와 API 수신 주소도 서로 다릅니다. 페이지가 열린다고 해서 제어 API가 안전하게 연결된 것은 아닙니다.

예제 도메인을 실제 Dashboard origin으로 바꾸기
external-controller-cors:
  allow-origins:
    - "https://dashboard.example.com"
  allow-private-network: false

일시적인 원격 유지보수에는 SSH 터널로 9090을 로컬 기기에 전달하세요

Mihomo가 홈 서버에서 실행 중이라면 external-controller를 127.0.0.1:9090에 그대로 두고, SSH 로컬 포워딩으로 원격 루프백 포트를 현재 컴퓨터에 매핑할 수 있습니다. 브라우저는 계속 자신의 127.0.0.1에 접속하며, 공용 인터넷에는 9090이 노출되지 않습니다.

예시: 원격 컨트롤러를 로컬 호스트의 19090에 매핑
ssh -N -L 19090:127.0.0.1:9090 [email protected]

# Dashboard 后端填写
http://127.0.0.1:19090

Tailscale로 서버에 연결한 뒤에도 루프백에서만 수신하는 컨트롤러에 접속하려면 위 SSH 포워딩을 사용해야 합니다. tailnet에 참여했다고 이 포트가 자동으로 열리지는 않습니다. tailnet policy로 호스트와 포워딩에 필요한 포트에 접근할 사용자나 기기를 제한하고 secret도 유지하세요.

가정용 라우터가 LAN 주소에서 반드시 수신해야 한다면 방화벽은 관리 컴퓨터만 허용하고 Guest Wi-Fi나 WAN zone 전체는 허용하지 마세요.

원격 관리 패널에 안전하게 접근하는 경로
  1. 사용자의 브라우저신뢰할 수 있는 기기에서만 접근
  2. SSH 포워딩(VPN을 통해 연결 가능)제어 포트를 직접 노출하지 않음
  3. 127.0.0.1:9090external-controller는 로컬 호스트에서만 수신
  4. Mihomosecret으로 제어 요청 검증

로컬 네트워크 주소를 반드시 수신해야 한다면 방화벽의 허용 출처도 함께 제한하고 충분히 긴 secret을 유지하세요.

장기 원격 접근에 필요한 리버스 프록시 보호

고정 도메인과 장기 원격 접근이 필요할 때만 리버스 프록시를 배포할 가치가 있습니다. Mihomo의 external-controller는 계속 127.0.0.1:9090에서 수신하고, 같은 호스트의 Nginx, Caddy 또는 다른 게이트웨이가 외부에 HTTPS를 제공합니다. 공용 인터넷에는 리버스 프록시 포트만 열고 9090은 열지 않습니다.

리버스 프록시에는 최소한 신뢰할 수 있는 TLS, 별도 로그인 또는 클라이언트 인증, 출처 제한, 접근 로그가 있어야 하며 Dashboard가 사용하는 WebSocket을 올바르게 전달해야 합니다. Mihomo의 secret도 그대로 유지하세요. secret과 리버스 프록시 로그인은 서로 대체할 수 없는 두 계층의 보호입니다. secret은 공개 URL에 넣지 말고 Dashboard의 연결 설정에 입력하세요.

Dashboard 웹페이지와 API가 서로 다른 도메인을 사용한다면 실제 웹페이지의 origin도 CORS에 정확히 추가해야 합니다. 설정을 마친 뒤 공용 인터넷에서 스캔하거나 다른 기기로 테스트하세요. HTTPS 도메인에는 로그인할 수 있어야 하고, 서버의 공인 IP:9090에 직접 접속하면 연결에 실패해야 합니다.

컨트롤러 인증과 허용되지 않은 네트워크의 접속 결과를 확인하세요

전체 검수

  1. 로컬 호스트에서 수신 상태 확인

    포트가 예상한 주소에 바인딩되어 있고 프로세스가 이전 인스턴스가 아닌 현재 Mihomo인지 확인합니다.

  2. 승인되지 않은 접근

    curl로 /version을 요청해 token이 없거나 잘못된 경우 모두 401을 반환하는지 확인합니다.

  3. 승인된 접근

    Dashboard를 열고 테스트용 정책 그룹을 전환한 뒤 Mihomo에도 같은 결과가 표시되는지 확인합니다.

  4. 권한이 없는 네트워크에서 테스트

    권한이 없어야 하는 LAN, Guest Wi-Fi 또는 공인 주소에서 테스트합니다. 연결은 시간 초과되거나 거부되어야 합니다.

  5. 재시작 후 다시 테스트

    Mihomo를 재시작한 뒤 수신 주소, secret, 방화벽 규칙이 클라이언트에 의해 덮어쓰이지 않았는지 확인합니다.

컨트롤러가 노출되었을 가능성이 있다면 먼저 수신 범위와 방화벽을 강화한 뒤 secret을 교체하세요. 이어서 포트 매핑, 클라우드 보안 그룹, 리버스 프록시 접근 로그, 설정 저장소 기록을 확인하세요. Dashboard 비밀번호만 바꿔서는 이미 유출된 Bearer Token을 무효화할 수 없습니다.

참고 자료