CONFIGURATION REFERENCE

V2Ray 설정 파일 가이드

JSON 객체에서 필드를 찾은 다음 인바운드, 라우팅, 아웃바운드 순서로 연결 경로를 확인하세요.

이 페이지는 설정 필드의 역할과 의존 관계, 적용 범위를 체계적으로 살펴보기 위한 참고 자료입니다. 클라이언트를 처음 사용한다면 먼저 빠른 시작 가이드에 따라 설정을 가져오고 연결한 뒤, 해당 항목으로 돌아와 세부 내용을 확인하세요. 데스크톱에서는 우선 v2rayN 설정 화면에서 변경하는 것이 좋습니다. 클라이언트와 시스템 패키지를 선택하려면 다운로드 페이지를 확인하세요.

JSON 구조 인바운드와 아웃바운드 라우팅과 DNS

JSON 구조 개요

설정 파일은 코어가 연결을 처리하는 방법을 정의하며, 클라이언트 화면의 모든 옵션을 저장하는 파일은 아닙니다. 데이터 흐름을 따라 읽으면 이해하기 쉽습니다. 앱이 연결을 인바운드로 전달하면 라우팅이 대상과 출처를 기준으로 아웃바운드를 선택하고, 아웃바운드는 대상에 직접 연결하거나 원격 서비스에 접속합니다. DNS는 이름 해석이 필요한 단계에 결과를 제공하고, 정책은 연결 제한 시간과 통계를 관리합니다. 객체는 태그나 사용자 레벨 등의 값으로 연결되므로 한 부분만 보면 전체 동작을 파악하기 어려울 수 있습니다.

클라이언트 파일과 실행 설정 구분하기

v2rayN의 구독 그룹, 화면 설정, 업데이트 옵션은 코어 JSON에 포함되지 않을 수 있습니다. 클라이언트는 보통 현재 서버와 라우팅 템플릿, 매개변수 설정을 바탕으로 실행 설정을 생성하며, 다시 연결할 때 새로 만들기도 합니다. 생성된 파일을 직접 수정하면 다음 서버 전환 때 변경 내용이 덮어써질 수 있습니다. 먼저 설정의 출처를 확인하세요. 일반 포트나 라우팅 옵션은 우선 화면에서 변경하고, 완전히 사용자 지정한 설정이 필요하다면 클라이언트에서 제공하는 가져오기 또는 사용자 지정 기능을 이용하세요.

이 페이지에서는 일반적인 객체형 V2Ray JSON을 기준으로 설명하며, 서로 다른 코어의 확장 필드를 하나의 표준처럼 다루지 않습니다. v2rayNG는 Xray 코어를, v2flyNG는 V2Fly 코어를 사용합니다. v2rayN에서 사용할 수 있는 기능은 현재 선택된 코어에 따라 달라집니다. 같은 필드 이름이라도 허용되는 값이 다를 수 있으며, 새 전송 방식이 다른 코어에서는 지원되지 않을 수도 있습니다. 알 수 없는 필드가 나오면 오류 주변의 내용을 하나씩 지우기 전에 실행 중인 코어와 설정 형식을 먼저 확인하세요.

실행 가능한 로컬 직결 기본 설정

아래 전체 설정은 로컬에서만 접속할 수 있는 인바운드 두 개를 만들고, 기본적으로 대상에 직접 연결하며, 트래픽 거부용 아웃바운드 하나를 준비합니다. 구조와 로컬 연결을 확인하기 위한 예시이며 원격 프록시 서버가 포함되어 있지 않고 시스템 프록시도 자동으로 변경하지 않습니다. 일반 UTF-8 텍스트 파일로 저장한 뒤 호환되는 코어의 사용자 지정 설정 기능으로 실행하세요. 클라이언트가 이미 같은 포트를 사용 중이라면 기존 인스턴스를 중지하거나 예시와 테스트 앱의 포트를 함께 바꾸세요.

{
  "log": {
    "loglevel": "warning"
  },
  "inbounds": [
    {
      "tag": "socks-in",
      "listen": "127.0.0.1",
      "port": 10808,
      "protocol": "socks",
      "settings": {
        "auth": "noauth",
        "udp": true
      }
    },
    {
      "tag": "http-in",
      "listen": "127.0.0.1",
      "port": 10809,
      "protocol": "http",
      "settings": {}
    }
  ],
  "outbounds": [
    {
      "tag": "direct",
      "protocol": "freedom",
      "settings": {}
    },
    {
      "tag": "block",
      "protocol": "blackhole",
      "settings": {}
    }
  ],
  "routing": {
    "domainStrategy": "AsIs",
    "rules": []
  }
}

JSON 객체에는 중괄호를, 배열에는 대괄호를 사용하며 키와 문자열은 큰따옴표로 감싸야 합니다. 숫자 포트에는 따옴표를 붙이지 않고 불리언 값은 소문자로 true 또는 false라고 씁니다. 이 페이지의 예시에는 주석과 마지막 쉼표가 없어 엄격한 JSON 파서에서도 사용할 수 있습니다. 일부 로더가 주석을 허용하더라도 모든 클라이언트 가져오기 기능이 같은 문법을 지원한다고 볼 수는 없습니다.

빈 객체와 객체 누락은 항상 같은 의미가 아닙니다. 일부 프로토콜의 settings는 비워 둘 수 있지만, 다른 프로토콜은 서버나 사용자 목록을 요구합니다. 필드의 대소문자도 그대로 유지해야 합니다. 예를 들어 outboundTag는 임의로 붙이는 설명 문구가 아닙니다. 반면 direct, socks-in은 예시에서 직접 정한 태그이므로 이름을 바꿀 수 있지만, 참조하는 곳도 모두 함께 변경하고 중복 태그는 피해야 합니다.

선택 항목을 한꺼번에 모두 채울 필요는 없습니다. 설정이 완전하다는 것은 필드가 많다는 뜻이 아니라, 입력한 각 필드에 분명한 목적이 있다는 뜻입니다. 살펴보기 전에 현재 인바운드 프로토콜과 포트, 기본 아웃바운드, 예상 분할 라우팅 동작을 기록해 두세요. 이후 각 설정을 이 네 가지 기준으로 확인하면 다른 곳에서 파일 전체를 복사한 뒤 어떤 규칙이 적용되는지 파악하기 어려운 상황을 줄일 수 있습니다.

inbounds 인바운드: 앱 연결 진입점

inbounds는 인바운드 배열입니다. 각 항목에는 최소한 수신 주소와 포트, 프로토콜을 지정하고 프로토콜별 설정도 입력해야 합니다. 앱이 실제로 이 인바운드에 연결해야 코어가 트래픽을 처리할 수 있습니다. 클라이언트가 실행 중이라고 해서 브라우저와 터미널, 다른 앱까지 모두 연결된 것은 아닙니다. 문제를 확인할 때는 라우팅 규칙을 바로 바꾸기보다 먼저 “앱이 연결을 어디로 보내는가?”를 확인하세요.

listen, port, 프로토콜 함께 확인하기

listen이 127.0.0.1이면 로컬 루프백 연결만 받습니다. 0.0.0.0은 모든 IPv4 인터페이스에서 수신하므로 접근 범위가 훨씬 넓습니다. 포트는 인바운드가 실제로 사용하는 로컬 포트이며 원격 서버의 포트가 아닙니다. 이 페이지에서는 SOCKS 10808과 HTTP 10809를 별도로 수신하는 예시를 사용합니다. 클라이언트에 따라 혼합 인바운드나 다른 포트를 쓸 수 있으므로 실제 실행 설정을 확인하고, 흔히 쓰이는 숫자만으로 프로토콜을 판단하지 마세요.

HTTP 프록시 설정에는 HTTP 인바운드를, SOCKS 설정에는 SOCKS 인바운드를 지정하세요. 브라우저의 HTTP 프록시를 SOCKS 전용 포트로 지정하면 정상적으로 연결되지 않을 수 있습니다. HTTPS 웹사이트도 HTTP 프록시의 CONNECT 터널로 접속할 수 있으며, 이때 로컬 프록시 주소를 HTTPS로 바꿀 필요는 없습니다. 앱 설정의 ‘보안 프록시’라는 이름은 대상 트래픽 유형을 뜻할 수 있으며, 로컬 인바운드 자체에서 TLS를 사용한다는 의미는 아닐 수 있습니다.

필드역할확인할 점
tag인바운드 내부 이름라우팅의 inboundTag와 일치하는지
listen바인딩할 로컬 주소로컬 전용인지 여부
port수신 포트포트 사용 여부와 앱 설정이 올바른지
protocol인바운드 프로토콜SOCKS와 HTTP를 혼동하지 않기
settings프로토콜별 매개변수인증, UDP 등의 옵션

UDP와 트래픽 스니핑의 범위

SOCKS 인바운드의 udp: true는 해당 UDP 전달 기능을 허용하지만, 전역 UDP 스위치는 아닙니다. 앱은 호환되는 SOCKS UDP 방식을 사용해야 하며 원격 프로토콜과 서버, 네트워크 경로도 이를 지원해야 합니다. TCP 요청만 정상이라고 해서 UDP도 통과한다고 볼 수는 없습니다. 일반 HTTP 프록시 인바운드도 임의의 UDP 앱을 대신할 수 없습니다. 게임이나 실시간 통신 앱은 연결 방식을 별도로 확인하세요.

sniffing은 일부 앱 계층 핸드셰이크 정보에서 대상 도메인을 파악해, 원래 IP만 있던 연결에 도메인 기반 라우팅을 적용하도록 돕습니다. 복호화 도구가 아니며 모든 암호화 트래픽에서 도메인을 알아낼 수 있는 것도 아닙니다. 아래 설정에서는 파악한 정보를 라우팅 판단에만 사용합니다. routeOnly의 사용 가능 여부는 현재 코어에서 확인하세요. 지원되지 않는다면 필드를 지우고 동작이 그대로라고 가정하지 말고, 대상 주소를 바꿔도 되는지 다시 확인해야 합니다.

{
  "sniffing": {
    "enabled": true,
    "destOverride": ["http", "tls"],
    "routeOnly": true
  }
}

이 설정은 인바운드 객체 하나에 protocol과 같은 수준으로 추가해야 하며, 해당 프로토콜의 settings 안에 넣는 항목이 아닙니다. 설정 트리에서 위치가 잘못되면 로더가 시작을 거부하거나 알 수 없는 내용을 무시할 수 있습니다. JSON 파싱에 성공하는 것만으로는 충분하지 않습니다. 코어가 구조를 받아들였는지 확인하고, 해당 도메인 규칙이 실제로 적용되는지도 살펴보세요.

LAN 공유에는 별도의 접근 제어가 필요합니다.

다른 기기에서 프록시를 사용하도록 설정하면 클라이언트의 ‘LAN 연결 허용’ 옵션이 수신 범위를 바꿀 수 있으며 운영체제 방화벽의 영향도 받습니다. 연결 주소에는 프록시 호스트의 LAN 주소를 입력해야 하며 상대 기기의 루프백 주소를 입력하면 안 됩니다. 허용할 출처를 제한하고 필요하다면 인증을 설정하세요. 수신 주소를 모든 인터페이스로 바꾸는 것만으로 불특정 네트워크에 인바운드를 노출해서는 안 됩니다.

Android의 v2rayNG와 v2flyNG는 보통 시스템 VPN 인터페이스와 앱별 선택 설정도 함께 사용합니다. 어떤 앱이 VPN 인터페이스를 통과하는지는 JSON에 SOCKS 인바운드가 있는지와는 별개의 문제입니다. 데스크톱의 시스템 프록시, 앱별 프록시, Android 앱별 규칙은 각각 확인하세요. 관련 권한과 백그라운드 실행 문제는 Android VpnService와 앱별 프록시 안내에서 확인할 수 있습니다.

outbounds 아웃바운드: 프로토콜과 기본 경로

outbounds는 연결을 처리하는 아웃바운드 목록입니다. 아웃바운드는 대상에 직접 연결하거나 원격 프록시 서버에 접속하거나 트래픽을 거부할 수 있습니다. 아웃바운드의 protocol은 코어가 해당 출구에서 사용할 프로토콜을 설명하며, 앱이 처음 사용한 인바운드 프로토콜을 뜻하지 않습니다. 같은 SOCKS 인바운드로 들어온 연결도 라우팅 결과에 따라 서로 다른 아웃바운드로 전달될 수 있습니다. 인바운드와 아웃바운드가 일대일로 대응할 필요는 없습니다.

기본 아웃바운드와 태그 참조

일반적인 객체형 설정에서는 라우팅 규칙에 일치하지 않는 연결이 첫 번째 아웃바운드를 사용합니다. 따라서 배열 순서도 실제 동작에 영향을 줍니다. 앞의 설정은 direct를 첫 번째 항목에 두므로 규칙에 일치하지 않는 모든 연결이 기본적으로 직접 연결됩니다. 원격 프록시 설정에서 일치하지 않는 트래픽을 프록시로 보내려면 기본 출구를 명시적으로 지정하세요. 태그 이름이 proxy라고 해서 자동으로 기본 경로가 되는 것은 아닙니다. 태그 자체에는 그런 특별한 의미가 없습니다.

tag는 라우팅 규칙에서 아웃바운드를 참조하는 이름입니다. 규칙의 outboundTag는 정의된 태그와 대소문자까지 정확히 일치해야 합니다. 알아보기 쉬운 짧은 이름을 사용하고 중복을 피하는 것이 좋습니다. 노드 이름이나 구독 그룹 이름을 아웃바운드 태그와 혼용하면 혼란이 생길 수 있습니다. 클라이언트 화면의 이름은 변환될 수 있고 실행 설정에 그대로 들어간다고 보장할 수 없으므로 실제 생성된 설정을 확인하세요.

{
  "outbounds": [
    {
      "tag": "direct",
      "protocol": "freedom",
      "settings": {}
    },
    {
      "tag": "block",
      "protocol": "blackhole",
      "settings": {
        "response": {
          "type": "none"
        }
      }
    }
  ]
}

freedom은 로컬 네트워크를 통해 대상에 직접 접속한다는 뜻이며, 코어를 거친다는 의미는 그대로 유지됩니다. 연결은 코어 DNS와 아웃바운드 설정, 시스템 네트워크 상태의 영향을 받을 수 있습니다. blackhole은 선택된 트래픽을 버리거나 거부하며, 명확한 차단 결과를 내는 데 주로 사용됩니다. 거부된 뒤 앱이 즉시 실패할 수도 있고 다시 시도하며 시간 초과까지 기다릴 수도 있습니다. 이는 앱의 재시도 방식에 따라 달라지므로 페이지가 계속 로딩된다는 이유만으로 원격 연결 문제라고 단정할 수는 없습니다.

원격 프로토콜의 settings는 서로 바꿔 쓸 수 없습니다.

프록시 프로토콜마다 서버 정보와 인증 구조가 다릅니다. VMess와 VLESS의 사용자 정보는 Trojan의 비밀번호 필드와 같지 않으며, Shadowsocks는 양쪽에서 같은 암호화 방식을 사용해야 합니다. 공유 링크에는 보통 원격 주소와 포트, 인증, 전송 정보가 함께 들어 있으므로 가져온 뒤 전체를 확인하세요. 주소 하나만 바꾸고 다른 연결의 전송이나 인증 설정을 그대로 사용하면 문법은 맞아도 연결되지 않을 수 있습니다.

원격 서버 주소는 ‘어느 서버에 연결할지’를, 요청 대상 주소는 ‘최종적으로 어디에 접속할지’를 나타내며 서로 다른 계층에 속합니다. 로컬 수신 포트와 원격 서버 포트, 대상 웹사이트 포트도 각각 구분해 기록하세요. 앱에서 로컬 포트에 연결되는 것은 첫 번째 구간이 정상이라는 뜻일 뿐입니다. 원격 포트에 접근할 수 없거나 인증이 맞지 않거나 TLS에 실패하면 최종 접속은 계속 실패합니다. 로그에 나온 주소가 어느 구간에 해당하는지 먼저 확인하세요.

객체 또는 필드담당 기능이 정보만으로는 판단할 수 없는 항목
protocol아웃바운드 프록시 프로토콜전송 및 인증서가 올바른지
settings서버, 사용자 등 프로토콜 매개변수로컬 앱이 프록시에 연결되었는지
streamSettings전송 및 연결 보안라우팅이 이 아웃바운드를 선택했는지
tag규칙에서 참조하는 식별자기본 출구 또는 유지보수 상태

선택 로직을 추가하기 전에 아웃바운드 하나를 검증하세요.

아웃바운드를 여러 개 추가하기 전에 동일한 테스트 요청으로 하나의 아웃바운드부터 검증하세요. 직결을 비교 기준으로 남겨 두면 대상 자체에 접근할 수 없는지, 프록시 경로에 문제가 있는지 구분하기 쉽습니다. 사용자 지정 전체 설정에서는 클라이언트의 ‘현재 서버 선택’ 기능이 아웃바운드 목록을 다시 쓰지 않을 수 있으므로 화면에서 선택을 바꾼 뒤 설정의 출처를 확인하세요. 클라이언트의 자동 선택 기능이 모든 사용자 지정 파일에도 적용된다고 가정하지 마세요.

다중화와 체인 연결, 부하 분산은 연결 실패 때 우선 켜는 해결책이 아니라 추가 동작 제어 기능입니다. 동시 처리와 의존성, 문제 해결의 복잡성을 높입니다. 인바운드와 라우팅, 원격 연결 하나가 모두 작동하는지 확인한 뒤 필요에 따라 추가하세요. 프로토콜 개념이 헷갈린다면 먼저 네 가지 프록시 프로토콜의 차이를 읽고 해당 프로토콜 필드를 확인하세요.

전송 및 보안: streamSettings의 계층

프록시 프로토콜과 전송 방식은 서로 다른 계층의 설정입니다. 프로토콜은 세션과 인증을 담당하고, 전송은 데이터를 네트워크로 전달하는 방식을 정합니다. 연결 보안은 TLS 등을 사용할지, 어떤 방식으로 적용할지 결정합니다. 같은 프로토콜이라도 전송 방식이 다를 수 있지만, 서버와 현재 코어가 모두 지원하는 조합만 작동합니다. 공유 링크를 가져온 뒤에는 프로토콜 이름만 같다고 호환된다고 판단하지 말고 프로토콜, 전송, 보안 방식 세 가지를 모두 확인하세요.

network와 security의 역할

streamSettings는 보통 아웃바운드의 settings와 같은 수준에 위치합니다. 그 안의 network는 하위 전송 유형을 지정하고, security는 해당 계층에서 사용할 연결 보안 방식을 지정합니다. 전송별 객체에는 경로와 요청 헤더, 서비스 이름 등의 세부 설정을 입력합니다. 필드 이름과 사용할 수 있는 값은 코어 기능에 따라 달라집니다. 특히 특정 코어의 새 전송 필드를 다른 코어에서도 통용되는 설정으로 간주하지 마세요.

아래는 TLS 설정의 구조와 인증서 이름 필드 위치를 보여 주는 예시입니다. 원격 아웃바운드 전체 설정은 아니며 예시 도메인은 문서용 예약 도메인입니다. 실제 설정에는 서버가 지정한 이름을 사용하세요. 이 예시로 구독의 전송 설정 전체를 대체하거나, TLS만 켜면 임의의 원격 포트와 핸드셰이크할 수 있다고 가정하지 마세요.

{
  "streamSettings": {
    "network": "tcp",
    "security": "tls",
    "tlsSettings": {
      "serverName": "example.com",
      "allowInsecure": false
    }
  }
}

serverName은 TLS 서버 이름 표시와 관련 인증서 이름 검증에 사용되며, 하위 연결에 입력한 서버 주소와 반드시 같을 필요는 없습니다. 하위 연결은 IP로 연결하면서 인증서에는 도메인이 필요할 수 있습니다. 반대로 서버 주소를 도메인으로 바꾸는 것만으로 앱 계층 요청 헤더와 전송 경로, TLS 이름이 모두 올바르게 설정되는 것도 아닙니다. 각 항목을 서버 요구 사항과 따로 대조하고 하나의 필드로 모든 이름을 대신하지 마세요.

경로, 요청 헤더, 인증서 확인

WebSocket을 사용할 때 경로는 전송 규약의 일부이므로 서버 또는 앞단 전달 설정과 일치해야 합니다. 슬래시와 대소문자, 추가 매개변수도 일치 여부에 영향을 줄 수 있습니다. 요청 헤더의 Host와 TLS 이름은 같을 수도, 특정 배포 환경에서는 다를 수도 있으므로 추측해서 입력하지 마세요. TLS 연결에 성공해도 이후 WebSocket 업그레이드나 프록시 프로토콜 인증까지 성공했다는 뜻은 아닙니다.

gRPC 서비스 이름도 서버가 정하는 항목이지 화면에 붙이는 메모가 아닙니다. 전송 이름이 맞아 보여도 서비스 이름이나 경로 전달, 중간 네트워크 장비의 제한 때문에 실패할 수 있습니다. 문제를 확인할 때는 TCP 연결, TLS 핸드셰이크, 전송 핸드셰이크, 프로토콜 인증 중 어느 단계에서 실패했는지 구분하세요. 각 단계는 앞 단계에 의존하므로 순서를 건너뛰고 여러 항목을 한꺼번에 바꾸면 원래 재현 가능한 문제도 파악하기 어려워집니다.

계층주요 확인 항목흔한 증상
네트워크 연결원격 주소, 포트, 네트워크 연결 가능 여부연결 거부 또는 시간 초과
TLS이름, 인증서 체인, 시스템 시간인증서 또는 핸드셰이크 오류
전송경로, Host, 서비스 이름업그레이드 실패 또는 연결 종료
프록시 프로토콜사용자, 비밀번호 및 프로토콜 매개변수인증 실패 또는 요청 중단

실행 중인 코어를 기준으로 호환성 확인하기

REALITY와 XTLS Vision 등의 기능은 필드 몇 개를 복사하는 것만으로 사용할 수 없습니다. 클라이언트 화면에서 지원하는 설정이라도 현재 실행 중인 코어가 해당 설정을 받아들인다는 뜻은 아닙니다. 관련 연결을 설정할 때는 먼저 서비스 제공 정보와 실제 코어를 확인한 다음 매개변수 전체를 대조하세요. V2Fly와 Xray는 공통된 기반이 있지만 확장 기능을 완전히 서로 바꿔 쓸 수는 없습니다. 자세한 내용은 코어 차이와 설정 호환성을 확인하세요.

코어를 바꾼 뒤 ‘알 수 없는 전송’ 또는 ‘보안 설정을 분석할 수 없음’ 오류가 발생하면, 시작할 때까지 필드를 하나씩 지우기보다 호환성이 확인된 설정으로 되돌리세요. 시작에 성공했다는 것은 파일이 받아들여졌다는 뜻일 뿐, 양쪽이 같은 연결 방식으로 동작한다는 의미는 아닙니다. 원본 연결 정보와 로컬 수정 내역을 보관하면 설정 복구 시 추측을 줄이고 호환성 문제와 네트워크 문제를 나누어 처리할 수 있습니다.

routing 라우팅: 조건, 순서, 태그

라우팅 규칙은 연결을 어느 아웃바운드로 보낼지 결정합니다. 일반적인 필드 기반 규칙은 배열 순서대로 확인하며 먼저 일치한 규칙이 결과를 결정합니다. 일치하는 규칙이 없으면 기본 아웃바운드를 사용합니다. 라우팅 규칙은 인바운드 연결을 대신하지 않으며 연결할 수 없는 아웃바운드를 고쳐 주지도 않습니다. 분할 라우팅을 설정하기 전에 기본 경로를 확인한 다음 목적이 명확한 규칙을 몇 개씩 추가하세요. 처음부터 조건을 설명하기 어려운 규칙을 대량으로 가져오지 않는 것이 좋습니다.

규칙 내부의 일치 조건 이해하기

같은 규칙에서 서로 다른 종류의 조건은 모두 충족해야 하는 경우가 많습니다. 예를 들어 출처 인바운드와 대상 도메인이 모두 일치해야 규칙이 적용됩니다. 같은 필드의 배열은 일치 가능한 항목을 여러 개 나열하는 데 사용합니다. 따라서 한 규칙에 도메인 목록과 IP 목록을 넣어도 ‘도메인 또는 IP’를 뜻하지는 않습니다. 두 종류의 대상을 각각 처리하려면 보통 규칙을 둘로 나누고 같은 아웃바운드 태그를 지정하세요.

{
  "routing": {
    "domainStrategy": "AsIs",
    "rules": [
      {
        "type": "field",
        "domain": ["full:example.com"],
        "outboundTag": "block"
      },
      {
        "type": "field",
        "ip": ["geoip:private"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "domain": ["geosite:cn"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "ip": ["geoip:cn"],
        "outboundTag": "direct"
      }
    ]
  }
}

이 예시를 사용하려면 direct와 block 아웃바운드, 그리고 해당 도메인 및 IP 데이터 파일이 있어야 합니다. 첫 번째 규칙은 규칙 우선순위를 확인하기 위해 문서용 예시 도메인을 정확히 차단하고, 뒤의 세 규칙은 일반적인 직결 분류를 보여 줍니다. 모든 네트워크에 적합한 완성형 분할 라우팅 설정은 아닙니다. 일치하지 않은 트래픽은 첫 번째 아웃바운드에서 처리됩니다. 기본 아웃바운드도 직결이면 뒤의 규칙이 다른 트래픽을 자동으로 프록시로 보내지는 않습니다.

도메인 표기와 데이터 파일

full:은 정확한 도메인 일치, domain:은 도메인과 하위 도메인 일치, regexp:는 정규 표현식, geosite:는 도메인 분류 참조에 사용합니다. 일반 문자열은 생각보다 넓은 범위에 일치할 수 있으므로 정확한 조건이 필요하다면 적절한 접두사를 지정하세요. 정규 표현식의 백슬래시는 JSON 문자열 이스케이프도 거쳐야 합니다. 문제 해결이 어렵다면 복잡한 표현식 대신 명시적인 도메인 조건을 몇 개 사용하세요.

geosite:cn과 geoip:cn은 각각 도메인 분류와 IP 분류를 참조합니다. 실시간 위치 정보가 아니며 두 데이터 집합이 일대일로 대응하는 것도 아닙니다. 데이터 파일이 없거나 분류가 존재하지 않거나 파일 형식이 호환되지 않으면 로드에 영향을 줄 수 있습니다. 클라이언트나 데이터를 업데이트하면 일부 대상의 규칙 적용 결과가 달라질 수도 있습니다. 장기간 유지해야 할 예외는 알아보기 쉬운 사용자 지정 도메인 규칙으로 표현하는 것이 좋습니다.

domainStrategy는 DNS 서버 선택 설정이 아닙니다.

AsIs는 보통 원래 대상 형식을 유지하며 라우팅 일치를 위해 도메인을 IP로 바꾸지 않습니다. IPIfNonMatch는 도메인 단계에서 일치하는 규칙이 없을 때 이름을 해석한 뒤 다시 확인합니다. IPOnDemand는 라우팅 판단에 IP가 필요할 때 이름을 해석합니다. 실제 동작은 코어 구현에 따라 달라질 수 있습니다. 이 옵션은 ‘라우팅에서 언제 IP가 필요한가’를 정하고, DNS 객체는 ‘이름 해석 요청을 어떻게 처리할 것인가’를 정하므로 서로 혼동하지 마세요.

앱이 IP를 직접 전달하면 도메인 규칙에 사용할 정보가 없을 수 있습니다. 반대로 대상이 도메인으로 유지될 때 IP 규칙이 적용되는지는 이름 해석 정책에 따라 달라집니다. 트래픽 스니핑으로 일부 정보를 보완할 수 있지만 모든 연결에서 도메인을 얻을 수 있는 것은 아닙니다. 규칙이 적용되지 않는다면 먼저 코어가 받은 대상이 도메인인지 IP인지 확인하고, 그다음 규칙 순서와 데이터 분류를 살펴보세요. 모든 트래픽을 같은 출구로 보내는 것부터 시도하지 마세요.

분할 라우팅을 검증할 때는 정확한 도메인 하나와 예상대로 직결될 대상 하나, 기본 경로를 확인할 대상 하나를 골라 각각 새 연결을 만드세요. 브라우저 연결 풀에서 기존 세션을 재사용할 수 있으므로 설정을 바꾼 뒤에는 연결을 새로 만든 다음 로그를 확인해야 합니다. 시스템 프록시의 우회 목록 때문에 요청이 코어에 들어오기 전에 직접 연결될 수도 있습니다. 이는 코어 라우팅과 별개의 기능입니다. 자주 발생하는 증상은 FAQ의 연결 문제 해결 항목에서 확인하세요.

dns 설정: 이름 해석이 이루어지는 위치

DNS 설정에서 먼저 확인할 것은 이름 해석이 이루어지는 위치입니다. 브라우저와 운영체제, 앱 자체의 리졸버, 코어 내장 리졸버, 원격 서비스가 모두 관여할 수 있습니다. dns 객체를 작성하는 것은 코어 내장 리졸버의 동작을 설정할 뿐, 시스템의 모든 DNS 요청을 자동으로 넘겨받는다는 뜻은 아닙니다. 앱이 먼저 도메인을 IP로 해석해 프록시에 전달하면 코어가 처음 받은 대상에는 도메인 정보가 없을 수 있습니다.

servers, hosts, 조회 정책

servers는 이름 해석 서버를 정의합니다. 목록 항목에는 단순 주소를 넣거나 일치 조건이 포함된 객체를 사용할 수 있습니다. 아래는 도메인별로 서버를 나누는 일반적인 구조를 보여 주며, 이러한 필드를 지원하는 코어에서 사용할 수 있습니다. IP 주소는 공개 리졸버의 예시일 뿐이며 모든 네트워크에서 접속할 수 있거나 항상 권장된다는 뜻은 아닙니다. 실제 환경에 적용하기 전에 현재 네트워크와 예상 경로에서 사용할 수 있는지 확인하세요.

{
  "dns": {
    "hosts": {
      "example.com": "192.0.2.10"
    },
    "servers": [
      {
        "address": "223.5.5.5",
        "domains": ["geosite:cn"],
        "expectIPs": ["geoip:cn"]
      },
      "1.1.1.1"
    ],
    "queryStrategy": "UseIPv4"
  }
}

hosts는 코어 리졸버의 정적 매핑을 설정하며 시스템 hosts 파일을 수정하지 않습니다. 예시에 나온 192.0.2.10은 문서용으로 예약된 주소이므로 실제 서비스에 접속하는 데 사용할 수 없습니다. 정적 매핑은 명확하고 안정적인 특수 용도에 적합합니다. 자주 바뀌는 웹사이트를 특정 IP에 오래 고정하면 일반적인 연결 분산을 우회하고 인증서나 연결 가능성, 서비스 지역이 예상과 달라질 수 있습니다.

domains가 포함된 서버 항목은 특정 도메인의 일치 조건을 지정합니다. expectIPs는 응답이 예상된 분류에 맞는지 확인하는 데 사용하지만, ‘특정 지역에서만 접속을 허용’하는 방화벽은 아닙니다. 리졸버 후보와 대체 동작, 결과 수용 방식은 코어와 다른 옵션에 따라서도 달라집니다. 서버 배열은 첫 번째 항목이 실패한 뒤에만 항상 두 번째 항목을 시도한다고 단순하게 이해하지 마세요. 순서만 보고 모든 조회의 경로를 판단할 수도 없습니다.

이름 해석 경로와 연결 경로를 따로 검증하기

DNS 서버까지 이름 해석 요청이 도달하는지와 최종 웹사이트 연결이 프록시를 통과하는지는 서로 다른 문제입니다. 일부 이름 해석 방식은 코어 라우팅에 참여하지만, 로컬 경로를 사용하는 방식도 있으므로 실제 구현을 확인해야 합니다. 프록시를 향하는 도메인 규칙 하나를 추가해도 모든 DNS 요청의 출구가 바뀌는 것은 아닙니다. DNS 주소만 바꿔도 잘못된 원격 인증이나 전송 설정이 수정되지는 않습니다.

HTTPS 기반 이름 해석 서비스를 사용하면 서비스 자체의 도메인을 먼저 해석해야 하는 부트스트랩 문제가 생길 수 있습니다. DNS 서버 주소가 도메인이고 현재 이름 해석 경로가 그 주소에 의존하면 순환 의존성이 발생할 수 있습니다. 시작 단계에서 리졸버와 프록시 서버를 찾는 방법을 정리하고 연결 가능한 부트스트랩 경로를 남겨 두세요. 프록시 서버 도메인의 이름 해석이 아직 연결되지 않은 같은 프록시 연결에 의존하지 않도록 해야 합니다.

설정 위치주요 영향별도로 확인할 항목
시스템 DNS시스템 리졸버를 사용하는 앱앱 자체 리졸버 사용 여부
코어 dns 객체코어에서 발생하는 해당 조회내장 리졸버가 실제로 호출되는지
라우팅 domainStrategy라우팅 단계에서 이름 해석을 시도하는지아웃바운드가 대상에 연결하는 방식
아웃바운드 이름 해석 정책대상 주소 연결 준비현재 프로토콜에서 필드를 지원하는지

IPv4, IPv6, 캐시

UseIPv4는 해당 이름 해석 정책을 제한하는 옵션이며 기기 전체의 IPv6를 끄지는 않습니다. 앱이 자체 리졸버를 사용하면 IPv6 주소를 받아 연결을 시도할 수 있습니다. 반대로 AAAA 레코드를 해석할 수 있어도 현재 네트워크에 사용할 수 있는 IPv6 경로가 있다는 뜻은 아닙니다. 주소 해석 결과와 연결 결과를 각각 확인하고, 특정 주소 계열을 전부 끄는 것으로 개별 실패 경로를 찾는 일을 대신하지 마세요.

이름 해석 설정을 바꾼 뒤에도 앱 및 시스템 캐시와 기존 연결이 확인 결과에 영향을 줄 수 있습니다. 새 요청을 만든 다음 로그에 나온 대상 형식과 라우팅 선택을 대조하세요. 명령줄의 시스템 이름 해석 도구는 보통 시스템 해석 경로를 측정하므로 코어 리졸버의 동작과 다를 수 있습니다. 코어 DNS를 확인하려면 실제 인바운드로 테스트 요청을 보내고 실행 로그도 함께 살펴보세요. 시스템에서 한 번 조회해 본 것만으로 설정이 적용됐다고 판단하면 안 됩니다.

policy 정책: 연결 제한 시간과 통계

policy는 주로 사용자 레벨별 연결 동작과 시스템 통계 옵션을 관리합니다. 여기서 말하는 ‘정책’은 도메인 분할 라우팅 규칙이나 시스템 프록시 모드가 아닙니다. 라우팅은 연결을 어느 출구로 보낼지 결정하고, 정책은 관련 연결의 대기 시간과 종료 시점, 일부 통계 기록 여부를 정합니다. 두 객체를 구분하면 라우팅 오류를 제한 시간 단축으로 해결하려는 식의 엉뚱한 조치를 피할 수 있습니다.

levels와 사용자 레벨의 관계

levels의 키는 "0"과 같은 레벨 번호 문자열입니다. 사용자 레벨을 지원하는 프로토콜 객체는 사용자 설정에서 레벨을 참조할 수 있습니다. 명시하지 않으면 보통 기본 레벨이 적용되지만, 구체적인 동작은 프로토콜과 코어에 따라 달라집니다. 레벨은 우선순위가 아니며 특정 사용자의 네트워크 연결을 자동으로 빠르게 해 주지도 않습니다. 설정을 바꾸기 전에 관리 대상 사용자 객체가 실제로 해당 레벨을 사용하는지 확인하세요.

{
  "policy": {
    "levels": {
      "0": {
        "handshake": 4,
        "connIdle": 300,
        "uplinkOnly": 2,
        "downlinkOnly": 5,
        "statsUserUplink": false,
        "statsUserDownlink": false
      }
    },
    "system": {
      "statsInboundUplink": false,
      "statsInboundDownlink": false,
      "statsOutboundUplink": false,
      "statsOutboundDownlink": false
    }
  }
}

아래 값은 필드를 설명하기 위한 예시이며 모든 상황에 권장되는 값은 아닙니다. handshake는 관련 핸드셰이크 단계의 제한 시간을, connIdle은 유휴 연결의 제한 시간을 설정합니다. uplinkOnly와 downlinkOnly는 연결 한쪽이 종료된 뒤 다른 쪽이 계속 동작하도록 기다리는 시간과 관련됩니다. 일반적인 구현에서는 초 단위를 사용하지만, 이 제한 시간은 코어의 연결 처리 과정에 적용되며 브라우저의 페이지 로딩 시간과 같지 않습니다.

제한 시간을 지나치게 짧게 설정하면 지연이 큰 네트워크에서 핸드셰이크가 끝나기 전에 연결이 중단되거나 롱 폴링과 푸시 알림, 잠시 데이터가 없는 연결에 영향을 줄 수 있습니다. 너무 길면 유휴 리소스를 더 오래 유지할 수 있습니다. 간헐적으로 연결이 끊긴다면 단순 시간 초과인지, 원격에서 닫았는지, 앱이 직접 종료했는지 먼저 확인하세요. 연결이 끊긴다고 해서 모든 값을 한꺼번에 늘리면 안 됩니다. 과도한 조정은 경로 품질 문제를 가리고 재현을 어렵게 만들 수 있습니다.

통계 스위치는 완전한 모니터링 인터페이스가 아닙니다.

사용자 트래픽 통계와 인바운드 통계, 아웃바운드 통계는 서로 다른 대상을 집계합니다. 옵션 하나를 켜도 클라이언트에 해당 값이 반드시 표시되는 것은 아닙니다. 통계 모듈과 조회 API, 클라이언트 자체의 수집 방식도 함께 작동해야 합니다. 사용자 통계에는 식별 가능한 사용자 정보가 필요할 수도 있습니다. 이 집계값을 네트워크 카드 트래픽과 동일시하지 마세요. 프로토콜 오버헤드와 재전송, 다른 프로세스의 트래픽으로 집계 기준이 달라질 수 있습니다.

사용자 지정 설정에서 통계를 사용하려면 보통 코어 요구 사항에 맞춰 통계 객체와 조회 기능도 설정해야 합니다. API 인바운드는 관리용이므로 로컬 또는 통제된 네트워크로 접근을 제한해야 하며, 트래픽을 확인하려고 신뢰할 수 없는 인터페이스에 직접 노출해서는 안 됩니다. 이 페이지에서는 관리 포트를 공개하는 설정 예시를 제공하지 않습니다. 그래픽 클라이언트에서는 기존 통계 기능을 우선 사용해 서로 충돌하는 관리 기능을 중복으로 켜지 마세요.

정책, 로그, 동시 처리는 따로 조정하기

로그 수준은 log 객체가 관리하며 policy의 통계 스위치와는 다릅니다. 정책 통계는 바이트 수를 집계하고 로그는 실행 이벤트를 기록하므로 서로 대체할 수 없습니다. 다중화에도 별도의 설정 위치가 있으며 사용자 통계를 켠다고 자동으로 활성화되지 않습니다. 리소스 사용량을 확인할 때는 연결 수와 작업 동시성, 로그 출력, 통계 요구 사항을 각각 살펴본 뒤 필요한 항목만 변경하세요.

데스크톱과 모바일 기기에서는 운영체제가 백그라운드 연결을 제한할 수도 있습니다. Android의 배터리 최적화가 클라이언트를 일시 중지하거나 네트워크 전환으로 기존 연결이 끊길 수 있으며, 이런 문제는 connIdle을 늘리는 것만으로 해결되지 않습니다. 먼저 프로세스가 계속 실행 중인지와 시스템 네트워크 인터페이스가 유효한지 확인한 뒤 코어 정책을 점검하세요. 그렇지 않으면 시스템 계층의 중단을 설정의 유휴 시간 초과로 오인할 수 있습니다.

변경 효과를 확인하려면 같은 네트워크와 앱을 사용하고 비슷한 방식으로 다시 테스트하세요. 짧은 요청이 정상이어도 장기 연결은 실패할 수 있고, 장시간 연결이 유지되어도 리소스를 적절히 사용한다고 볼 수는 없습니다. 일반적인 최적화 값을 반복해서 적용하는 것보다 실패 단계와 로그를 기록하는 편이 도움이 됩니다. 명확한 요구가 없는 옵션은 신중하게 다루는 것이 유지 관리와 이후 버전 호환에 유리합니다.

검증 및 문제 해결: 파일부터 실제 요청까지

설정 검증은 네 단계로 나뉩니다. 텍스트를 파싱할 수 있는지, 코어가 불러올 수 있는지, 앱이 연결됐는지, 최종 경로가 예상과 일치하는지 확인합니다. 앞 단계가 통과해도 다음 단계까지 정상이라는 뜻은 아닙니다. 올바른 JSON이라도 존재하지 않는 아웃바운드를 참조할 수 있고, 코어가 시작되어도 앱 연결이 전달되지 않을 수 있습니다. 접속에 성공하더라도 시스템이 프록시를 우회해 직접 연결했을 가능성이 있습니다. 각 단계에서 확인 가능한 근거를 남겨야 변경이 실제로 어디에 영향을 줬는지 판단할 수 있습니다.

먼저 문법과 로드 오류 확인하기

큰따옴표와 쉼표, 괄호 짝, 필드 유형을 먼저 확인하세요. 코드를 복사할 때 설명 문구나 코드 펜스까지 파일에 넣지 마세요. JSON 파싱에 성공하면 코어 시작 로그에서 알 수 없는 프로토콜이나 누락된 데이터 파일, 잘못된 태그, 포트 충돌 여부를 확인하세요. 오류에 표시된 행과 열은 파싱이 멈춘 위치일 수 있으며 실제로 빠진 쉼표는 앞 행에 있을 수 있습니다. 앞뒤 객체의 경계까지 함께 확인하세요.

방금 수정한 파일이 실제로 실행 중인지, 클라이언트가 다시 생성한 다른 설정이 실행 중인지 확인하세요. 그래픽 클라이언트에서는 보통 로그나 실행 정보를 볼 수 있지만 메뉴 이름은 화면에 따라 다를 수 있습니다. 처음부터 클라이언트를 바꿀 필요는 없습니다. 원본 파일을 백업하고 충돌하는 인스턴스를 종료한 뒤 한 번 다시 시작하고 처음 나타난 오류를 기록하세요. 이후 반복되는 오류는 같은 원인으로 연쇄 재시도가 발생한 결과일 수 있습니다.

지정한 인바운드로 테스트 요청 보내기

아래 두 명령은 앞에서 분리한 SOCKS 및 HTTP 인바운드에 맞춰 작성했습니다. SOCKS 주소의 socks5h는 도메인 해석을 프록시 측에 맡긴다는 뜻이므로 로컬 이름 해석 경로와 구분하는 데 적합합니다. Windows 명령 환경에서는 curl.exe를 명시적으로 사용할 수 있으며, 다른 시스템에서는 사용 가능한 curl 명령을 이용하세요. 테스트 대상은 문서용 예시 사이트입니다. 속도 측정이 아니며 모든 앱이 프록시를 사용한다고 확인해 주지도 않습니다.

curl --noproxy "" --proxy socks5h://127.0.0.1:10808 --head https://example.com/
curl --noproxy "" --proxy http://127.0.0.1:10809 --head https://example.com/

비어 있는 우회 목록을 명시한 이유는 현재 프록시 환경 변수가 테스트에 영향을 주지 않도록 하기 위해서입니다. 로컬 포트에서 바로 연결이 거부되면 프로세스와 수신 주소, 포트부터 확인하세요. 로컬 연결은 성공했지만 원격에서 시간 초과가 발생한다면 아웃바운드와 네트워크를 점검하세요. 앞의 직결 기본 설정과 비교해 성공하더라도 ‘앱에서 코어를 거쳐 대상까지’ 이어지는 기본 경로가 작동한다는 뜻일 뿐, 사용 가능한 원격 프록시 서버가 있다는 의미는 아닙니다.

로그 단계에 따라 확인할 필드 찾기

warning은 일반적인 실행에 적합합니다. 세부 정보를 확인하기 어렵다면 잠시 로그 상세 수준을 높이세요. 쉽게 구분할 수 있는 요청을 새로 보내고 시간과 대상, 인바운드, 선택된 아웃바운드를 기록한 뒤 평소 로그 수준으로 되돌리세요. 상세 로그에는 도메인과 주소, 연결 정보가 포함될 수 있습니다. 공유하기 전에 구독 주소와 인증 정보 등 민감한 내용을 삭제하고 실행 파일 전체를 그대로 보내지 마세요.

증상우선 확인할 항목다음 단계
시작할 수 없음문법, 코어 호환성, 포트 충돌실행 가능한 기본 설정으로 되돌리기
로컬 연결 거부프로세스, 주소, 수신 포트앱 프록시 프로토콜 확인
원격 핸드셰이크 실패이름, 시간, 전송, 인증서버 요구 사항을 단계별로 대조
일부 대상이 잘못된 출구를 사용함규칙 순서, 대상 형식, 기본 아웃바운드정확한 조건으로 범위 좁히기
브라우저는 정상인데 터미널은 실패각 앱의 프록시 설정 및 우회 목록인바운드를 지정해 다시 테스트

‘시간 초과’는 결과일 뿐, 원인이 하나로 정해져 있지는 않습니다. 대상에 접근할 수 없거나 이름 해석에 실패했거나 출구가 잘못됐거나 원격 핸드셰이크가 멈춰도 비슷하게 나타날 수 있습니다. 먼저 실패 위치를 확인한 뒤 해당 필드를 점검하세요. 대표적인 로그 해설은 실행 로그와 흔한 오류에서, 터미널에서만 적용되지 않는다면 시스템 프록시 및 터미널 경로 점검에서 확인하세요. 라우팅 전체를 먼저 바꾸지는 마세요.

복구할 수 있도록 변경 내용 기록하기

수정할 때마다 어떤 객체를 변경했는지, 무엇이 달라질 것으로 예상하는지, 어떤 요청으로 검증할지 세 가지를 기록하세요. 구독을 업데이트하거나 서버를 바꾼 뒤에는 클라이언트가 사용자 지정 설정을 유지했는지 다시 확인하세요. 되돌려야 할 때는 패치를 계속 덧붙이지 말고 가장 최근에 작동한 설정으로 복구하세요. 문제가 여전히 분명하지 않다면 기본 튜토리얼에 따라 설정 가져오기와 모드, 연결을 다시 확인한 다음 이 페이지의 객체 순서대로 사용자 지정 내용을 한 단계씩 추가하세요.