전체 구독과 노드 Provider부터 구분하기

구독 업데이트에 실패했다면 먼저 누가 무엇을 다운로드하는지 확인하세요. GUI 클라이언트의 구독 업데이트와 mihomo의 proxy-providers는 서로 다른 경로입니다. 전자는 보통 전체 설정을 가져오고, 후자는 노드 목록만 새로 고칩니다. 노드에 연결할 수 있어도 구독 주소에 접속할 수 있다는 뜻은 아니며, 구독 다운로드가 성공해도 모든 노드가 사용 가능한 것은 아닙니다.

  • 클라이언트 구독: dns, proxy-groups, rules 등 전체 설정이 포함될 수 있습니다. 업데이트 주기는 클라이언트가 관리하며, 화면에 설정된 자동 업데이트는 코어 Provider 타이머와 별개입니다.
  • 노드 Provider: mihomo가 실행 중에 읽습니다. 원격 콘텐츠는 지원되는 노드 목록 형식이어야 합니다. 여기서는 최상위에 proxies:를 두는 YAML 형식을 사용하며, 정책 그룹에서 use로 Provider를 참조합니다.
  • 상태 확인: 테스트 주소로 요청을 보내 노드의 연결 가능 여부와 지연 시간을 확인합니다. 구독을 다시 다운로드하거나 만료된 구독 인증 정보를 복구하는 기능은 아닙니다.

오류별 점검: HTTP부터 확인한 뒤 파싱과 노드 점검

업데이트에 실패한 시점의 로그를 저장하고 시간, 요청 도메인, 오류 메시지 끝부분을 기록하세요. 화면에 표시된 '업데이트 실패'만 캡처하지 마세요. 로그에 구독 쿼리 매개변수가 포함되어 있다면 공유하기 전에 토큰을 가리세요. 아래 오류는 서로 다른 단계에서 발생하므로 같은 방법으로 해결할 수 없습니다.

로그 또는 상태 우선 확인할 항목 다음 단계
no such host 구독 도메인 이름 확인 getent를 실행해 도메인 철자가 맞는지 확인
i/o timeout、context deadline exceeded 연결 경로, 외부 연결 지점, 시간 초과 단계 직접 연결과 로컬 프록시를 각각 테스트
x509: certificate has expired 로컬 시계와 서버 인증서 유효 기간 먼저 시각을 맞춘 뒤 사이트 인증서 확인
certificate signed by unknown authority 시스템 CA 및 기업 HTTPS 검사 신뢰할 수 있는 루트 인증서의 출처 확인
HTTP 401 / 403 토큰, 접근 정책, User-Agent 서비스 제공업체 안내와 응답 본문 확인
HTTP 429 요청 빈도 제한 Retry-After에 따라 기다린 뒤 주기를 늘리기
yaml: unmarshal errors 응답 형식, 필드 유형, 들여쓰기 응답이 HTML이나 오류 메시지인지 확인

시간 초과가 반드시 노드 장애를 뜻하지는 않습니다

구독 도메인은 특정 네트워크에서만 접속할 수 있거나 프록시 출구에서 요청이 제한될 수 있습니다. Linux 터미널의 HTTPS_PROXY 설정은 데스크톱 시스템 프록시 설정과 다를 수 있으며, 클라이언트 업데이트 기능도 같은 설정을 사용한다고 볼 수 없습니다. 따라서 브라우저에서 사이트가 열린다고 해서 백그라운드 구독 요청도 같은 경로를 사용한다는 뜻은 아닙니다.

토큰을 셸 기록에 직접 남기지 않도록 아래 명령은 먼저 구독 주소를 입력받습니다. 응답은 접근 권한이 제한된 임시 디렉터리에 저장됩니다. 명령은 리디렉션을 자동으로 따라가지 않으며 구독 본문도 출력하지 않습니다. 301 또는 302 응답을 받으면 로컬에서 이동 대상과 출처를 확인한 다음 접속하세요.

umask 077
workdir=$(mktemp -d)
read -r -s -p '구독 URL: ' SUB_URL
printf '\n'

curl --noproxy '*' --connect-timeout 10 --max-time 30 \
  -sS -D "$workdir/headers.txt" \
  -o "$workdir/body.txt" \
  -w 'HTTP=%{http_code} total=%{time_total}s\n' \
  "$SUB_URL"

getent ahosts example.com

마지막 줄의 example.com은 구독 URL의 호스트 이름으로 바꾸세요. 프로토콜과 토큰은 제외하고 도메인만 입력합니다. --noproxy '*'는 curl에 명시적으로 설정된 프록시를 제외합니다. 시스템에서 TUN이나 라우터 투명 프록시를 사용 중이면 트래픽이 여전히 가로채질 수 있으므로, 이 결과만으로 물리적 직접 연결을 증명할 수는 없습니다.

코어가 실제로 7890 포트에서 mixed-port를 수신하는지 확인한 다음, 명시적인 HTTP 프록시 요청과 비교할 수 있습니다. 아래 명령은 앞 단계에서 설정한 변수를 사용합니다. 결과는 해당 요청의 실제 상태를 나타내며, 성공을 전제로 하지 않습니다.

curl --noproxy '' --proxy http://127.0.0.1:7890 \
  --connect-timeout 10 --max-time 30 \
  -sS -D "$workdir/proxy-headers.txt" \
  -o "$workdir/proxy-body.txt" \
  -w 'HTTP=%{http_code} total=%{time_total}s\n' \
  "$SUB_URL"

# 로컬 점검이 끝나면 구독 정보가 포함된 임시 파일 삭제
unset SUB_URL
rm -rf -- "$workdir"
unset workdir

인증서 오류, User-Agent 거부, 형식 불일치

인증서 오류: 먼저 시각을 맞추고 검증을 건너뛰지 마세요

먼저 timedatectl status를 실행해 날짜, 시간대, 시간 동기화 상태를 확인하세요. 인증서 유효 기간은 절대 시간을 기준으로 판단하므로 시간대 표시가 다르다는 것만으로 인증서가 만료되지는 않습니다. 시계가 정확하다면 시스템 CA 패키지 설치 여부, 기업 네트워크의 HTTPS 인증서 대체 여부, 구독 서비스 인증서의 만료 여부를 확인하세요.

Debian 및 Ubuntu에서는 ca-certificates 패키지를 확인할 수 있습니다. 관리자가 기업 루트 인증서를 제공한 경우 배포판의 절차에 따라 설치하고 출처를 확인하세요. curl -k를 사용하거나 인증서 검증을 건너뛰는 방법을 상시 해결책으로 삼지 마세요. 구독에는 연결 자격 증명이 포함되므로 검증을 끄면 콘텐츠가 바뀔 위험이 커집니다.

401·403 오류: 자격 증명부터 확인한 다음 User-Agent 점검

401 오류는 토큰 만료가 원인인 경우가 많습니다. 403은 요금제 상태, IP 제한, User-Agent 정책 또는 보안 차단 페이지 때문에 발생할 수도 있습니다. 서비스 제공업체가 반환한 응답을 기준으로 확인하고, 403이 떴다고 User-Agent를 계속 바꾸지는 마세요. 브라우저에서 HTTP 200을 받아도 유효한 구독이 아니라 로그인 페이지일 수 있습니다.

서비스 제공업체가 mihomo의 User-Agent를 명시적으로 요구한다면 Provider에 요청 헤더를 설정할 수 있습니다. header의 각 값은 문자열 목록으로 지정합니다. 다음 필드 작성 예시를 해당 HTTP Provider에 넣으세요. 계정 권한을 대체하지 않으며 접근 제어를 우회하는 용도로 사용해서는 안 됩니다.

header:
  User-Agent:
    - mihomo

파싱 오류: 파일 확장자만 보지 말고 본문 구조 확인

구독 주소가 .yaml로 끝나더라도 서버가 YAML을 반환한다고 단정할 수 없습니다. 로컬에서 응답 헤더와 본문 앞부분을 확인하세요. HTML 보안 차단 페이지, JSON 오류 메시지, Base64 노드 목록, 전체 설정, Provider 노드 목록은 서로 다른 데이터 형식입니다. HTTP 200은 요청 단계가 성공했다는 뜻일 뿐입니다.

이 문서에서 사용하는 Provider 본문은 다음과 같은 최상위 구조여야 합니다. 예시에는 실제 노드가 없으며 proxies: []는 필드 유형을 보여 주기 위한 것입니다. 실제 서비스에서는 내용이 포함된 노드 목록을 제공해야 합니다. 전체 설정을 노드 Provider로 그대로 사용하지 마세요. 특히 그 안의 rules가 주 설정에 자동으로 합쳐질 것으로 기대해서는 안 됩니다.

proxies: []
  • 주 설정의 Provider 이름은 고유해야 합니다. airport처럼 일관된 영문 이름을 사용하는 것이 좋습니다.
  • YAML 들여쓰기에는 공백을 사용하고 Tab은 사용하지 마세요. 특수 문자로 인한 오해를 막으려면 URL을 따옴표로 감싸는 것이 좋습니다.
  • 노드 형식 변환은 신뢰할 수 있는 환경에서 진행하세요. 토큰이 포함된 구독을 출처가 불분명한 변환 사이트에 제출하지 마세요.

proxy-providers 자동 새로고침: 전체 필드와 참조 관계

아래 설정은 연결 관계를 설명하기 위한 예시입니다. 노드 목록은 3600초마다 가져오고 상태 확인은 600초마다 실행합니다. 정책 그룹 PROXY는 use: [airport]로 노드를 참조하고, 마지막 규칙은 일치하는 항목이 없는 트래픽을 이 그룹으로 보냅니다. 실제 구독 설정은 아니며 example.com은 문서용 예시 도메인입니다. 사용하기 전에 서비스 제공업체가 안내한 Provider 주소로 바꾸세요.

mixed-port: 7890
allow-lan: false
mode: rule
log-level: info

proxy-providers:
  airport:
    type: http
    url: "https://example.com/subscription.yaml"
    path: ./providers/airport.yaml
    interval: 3600
    health-check:
      enable: true
      url: "https://www.gstatic.com/generate_204"
      interval: 600
      timeout: 5000
      lazy: true

proxy-groups:
  - name: PROXY
    type: select
    use:
      - airport

rules:
  - MATCH,PROXY
필드 예시 값 기능 및 단위
interval 3600 원격 Provider 업데이트 주기(초)
path ./providers/airport.yaml 코어 작업 디렉터리를 기준으로 한 로컬 캐시 경로
health-check.interval 600 노드 상태 확인 주기(초)
health-check.timeout 5000 1회 확인 시간 제한(밀리초)
health-check.lazy true 사용하지 않을 때는 주기 확인을 생략해 탐색 요청 줄이기

health-check.url에는 예상한 응답을 안정적으로 반환하는 가벼운 주소를 지정해야 합니다. 위 URL은 흔히 쓰이는 예시일 뿐 모든 네트워크에서 접속할 수 있는 것은 아닙니다. 테스트 주소에 문제가 생기면 정상 노드 다수가 동시에 비정상으로 표시될 수 있습니다. 이때는 노드를 한꺼번에 삭제하기보다 먼저 테스트 대상의 문제인지 확인하세요.

업데이트 요청이 사용하는 출구

현재 mihomo의 HTTP Provider는 proxy 필드로 다운로드에 사용할 프록시나 정책 그룹을 지정할 수 있습니다. 지정하지 않았을 때 데스크톱 시스템 프록시를 그대로 사용한다고 가정하지 마세요. 구독에 프록시가 필요하다면 구독을 처음 다운로드하기 전부터 지정된 출구를 독립적으로 사용할 수 있어야 합니다.

새로고침 주기를 지나치게 짧게 설정하지 마세요. 3600초는 1시간이므로 보통 매분 요청하는 것보다 적절합니다. 구체적인 주기는 서비스 제공업체의 제한을 따르세요. 상태 확인은 노드별 요청이 발생할 수 있어 노드가 많을수록 전체 요청 수도 늘어납니다. 확인 주기만 줄여도 구독 업데이트가 빨라지지는 않습니다.

설정 파일 적용: 검증, 권한, 재시작 순서

먼저 현재 실행 방식을 확인하세요. GUI 클라이언트가 생성한 실행 설정은 다음에 구독을 전환할 때 수동 변경 사항을 덮어쓸 수 있으므로 클라이언트가 지원하는 지속적 병합 방식을 사용해야 합니다. mihomo를 독립 실행하는 경우 실제 시작 인수의 -d와 -f를 기준으로 하세요. 읽히지 않는 동명 파일을 수정하지 않도록 주의하세요.

  1. 기존 설정을 백업해 복구할 수 있는 버전을 보관하세요.
  2. Provider와 정책 그룹을 주 설정에 함께 추가하고 use 값이 Provider 이름과 정확히 일치하는지 확인하세요.
  3. 캐시 디렉터리를 만들고 코어를 실행하는 사용자에게 쓰기 권한이 있는지 확인하세요.
  4. 설정을 검사하고 검사를 통과한 뒤에만 서비스를 재시작하세요.
  5. 시작 및 이후 업데이트 로그를 확인해 다운로드, 파싱 또는 권한 오류가 없는지 살펴보세요.

아래 예시는 작업 디렉터리가 ~/.config/mihomo이고 설정 파일이 config.yaml이며 mihomo.service라는 systemd 사용자 서비스가 이미 만들어져 있다고 가정합니다. 시스템 서비스라면 실제 배포 방식에 맞게 설정 디렉터리와 명령의 사용자 범위를 조정하세요.

cp ~/.config/mihomo/config.yaml \
  ~/.config/mihomo/config.yaml.bak
mkdir -p ~/.config/mihomo/providers
chmod 700 ~/.config/mihomo/providers
chmod 600 ~/.config/mihomo/config.yaml

mihomo -t -d ~/.config/mihomo \
  -f ~/.config/mihomo/config.yaml

# 검사에 통과한 경우에만 실행
systemctl --user restart mihomo.service
journalctl --user -u mihomo.service -n 100 --no-pager

mihomo -t는 설정을 검사하는 명령이며, 모든 원격 콘텐츠와 노드가 작동한다는 사실까지 보장하지는 않습니다. 설정 검사를 통과했는데도 업데이트가 실패한다면 실제 실행 로그를 계속 확인하세요. 서비스에서 permission denied 오류가 발생하면 디렉터리 소유자, 서비스 사용자, 캐시 경로를 점검하세요. 설정 디렉터리 전체에 모든 사용자의 쓰기 권한을 부여하지 마세요.

Provider 캐시가 있으면 업데이트에 실패해도 기존 노드를 계속 사용할 수 있습니다. 화면에 노드가 남아 있다고 해서 새로고침에 성공한 것은 아닙니다. 로그와 stat ~/.config/mihomo/providers/airport.yaml을 함께 확인해 캐시 상태를 살펴보세요. 수정 시간은 참고 자료일 뿐 원격 콘텐츠가 바뀌었다는 증거로 단독 사용해서는 안 됩니다.

자주 묻는 질문: 자동 새로고침이 작동하지 않는 것처럼 보이는 이유

interval을 설정하면 클라이언트를 종료한 뒤에도 업데이트되나요?

이 YAML 설정만으로 종료된 코어가 다시 시작되지는 않습니다. Provider 자동 새로고침은 mihomo가 계속 실행 중이어야 하며 컴퓨터 절전, 서비스 종료, 네트워크 연결 끊김의 영향을 받습니다. Linux에서 상시 실행이 필요하다면 배포 방식에 맞게 systemd를 설정하세요. 한 번 정상적으로 실행됐다고 해서 부팅 시 자동 시작까지 설정된 것은 아닙니다.

구독은 업데이트됐는데 규칙과 DNS는 왜 바뀌지 않나요?

proxy-providers는 노드 목록을 업데이트할 뿐 전체 주 설정을 업데이트하지 않습니다. 규칙은 별도로 rule-providers에서 가져올 수 있지만, 규칙 세트도 rules에서 참조해야 합니다. 전체 설정을 교체하려면 클라이언트의 구독 업데이트 절차를 사용하고 로컬 오버라이드 규칙의 우선순위를 확인하세요. 필드 간 관계는 설정 참고에서 확인할 수 있습니다.

상태 확인은 성공했는데 특정 사이트가 열리지 않는 이유는 무엇인가요?

상태 확인은 테스트 대상만 검사하며 모든 웹사이트를 확인하지는 않습니다. 특정 사이트는 DNS 조회, 규칙 일치, 출구 지역 또는 대상 서비스의 제한에 영향을 받을 수 있습니다. 실제로 적용된 정책 그룹과 노드를 먼저 확인한 뒤 대상 도메인을 점검하세요. 한 번의 상태 확인이 정상이라고 해서 전체 접속 경로에 문제가 없다고 단정하지 마세요.

문제가 해결됐는지 어떻게 확인하나요?

  • 구독 요청에서 로그인 페이지나 오류 본문이 아닌 유효한 콘텐츠가 반환됩니다.
  • 실행 로그에 Provider 파싱 오류가 없고 정책 그룹에 예상한 노드가 표시됩니다.
  • 기존 캐시 없이 처음 실행해도 구독을 가져올 수 있습니다.
  • 설정한 주기만큼 기다린 뒤 후속 새로고침이 실행되는지 확인합니다.
  • 클라이언트를 다시 시작한 뒤에도 설정이 유지되며 토큰과 노드 자격 증명이 공개 로그에 노출되지 않습니다.

문제 해결 순서는 다운로드 경로 → HTTP 상태 → 콘텐츠 형식 → Provider 참조 → 자동 새로고침 → 노드 점검으로 유지하세요. 이렇게 하면 '구독을 가져올 수 없음'과 '노드를 사용할 수 없음'을 구분할 수 있어 문제 지점을 해결하지 않은 채 클라이언트를 반복해서 재설치하는 일을 막을 수 있습니다. 처음 배포한다면 빠른 시작에 따라 기본 설정을 완료한 다음 자동 새로고침 설정을 하나씩 추가하세요.