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

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

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

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

Clash Dashboard에 원격 접속하려면 먼저 관리 진입점으로 보호하세요

Clash Dashboard는 external-controller가 제공하는 REST API를 통해 연결, 트래픽, 프록시 그룹, 규칙을 읽습니다. 이 인터페이스는 노드 전환, 설정 다시 로드, 일부 실행 설정 변경, 연결 종료도 할 수 있습니다. 따라서 9090 포트를 인터넷에 직접 노출하는 위험은 읽기 전용 상태 페이지 하나를 공개하는 것보다 훨씬 큽니다.

먼저 누가 접속해야 하는지 정하세요. 로컬 기기에서만 쓴다면 루프백 주소에서만 수신합니다. 같은 LAN에서 가끔 확인하더라도 출처 제한, secret, 방화벽이 필요합니다. 원격 관리가 필요하면 SSH 터널이나 통제된 Tailscale 네트워크를 통해 전달해야 하며 0.0.0.0:9090을 인터넷에 직접 매핑하면 안 됩니다.

접속 환경별 권장 진입점

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

기기 간 접속이 필요 없다면 수신 주소를 로컬 기기로 제한하세요

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

아래 REPLACE_WITH_RANDOM_SECRET은 자리표시자일 뿐입니다. 먼저 비밀번호 관리자로 긴 임의 값을 생성하고 설정과 Dashboard 연결 설정의 값을 모두 바꾼 뒤 Mihomo를 다시 로드하세요. 자리표시자를 그대로 비밀번호로 사용하지 마세요.

로컬 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을 설정한 뒤 인증되지 않은 요청이 실제로 거부되는지 검증하세요

secret은 외부 컨트롤러의 Bearer Token입니다. 빈 값, 짧은 암호, 여러 기기에서의 장기 재사용은 포트에 접속할 수 있는 사람에게 관리 권한을 넘기는 것과 같습니다. 임의 값을 생성해 Mihomo 설정과 Dashboard의 백엔드 주소 설정에 각각 입력하세요. 전체 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을 사용할 때도 tailnet 전체를 관리자로 간주하지 마세요. tailnet policy로 호스트와 포트에 접근할 수 있는 사용자 또는 기기를 제한하고 secret도 유지하세요. 가정용 라우터에서 LAN 주소를 반드시 수신해야 한다면 방화벽 규칙은 관리용 컴퓨터만 허용하고 Guest Wi-Fi나 WAN zone 전체를 허용하지 마세요.

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

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

장기 접속이 필요할 때만 9090 앞에 리버스 프록시를 추가하세요

고정 도메인과 장기 원격 접근이 필요할 때만 리버스 프록시를 배포할 가치가 있습니다. 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에 직접 접속하면 연결에 실패해야 합니다.

장기 원격 진입점의 필수 조건

  • external-controller는 계속 127.0.0.1에서만 수신
  • 공용 인터넷에 9090 포트 매핑이 없음
  • 리버스 프록시가 HTTPS를 강제하고 별도 인증을 사용함
  • WebSocket 로그와 트래픽 페이지가 정상적으로 갱신됨
  • Mihomo secret 검증이 계속 성공함
  • 승인되지 않은 출처에서는 접근할 수 없음

서버 자체와 다른 기기에서 각각 한 번씩 테스트하세요

전체 검수

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

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

  2. 승인되지 않은 접근

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

  3. 승인된 접근

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

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

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

  5. 재시작 후 다시 테스트

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

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

참고 자료