설정 구조 · 필드 의미 · 실행 검증

JSON 설정 가이드

연결 흐름에 따라 로컬 인바운드, 아웃바운드 선택, 라우팅 매칭, 이름 확인, 연결 정책을 살펴봅니다.

처음 사용한다면 빠른 시작 가이드에 따라 구독을 가져오고 연결을 완료하세요. 이 페이지는 생성된 설정을 이해하고 분할 규칙을 수정하며 필드 오류를 찾는 데 도움을 주며, 클라이언트의 일상적인 조작을 대신하지 않습니다. 설치 방법과 플랫폼 선택은 클라이언트 페이지에서 확인하세요.

JSON 구조 개요

필드를 설명하기 전에 어떤 설정을 보고 있는지부터 확인하세요. v2rayN에 저장된 UI 설정, 구독 내용, 코어 실행 설정은 서로 다른 파일입니다. 구독에는 서버 연결 정보가 포함됩니다. 클라이언트는 현재 서버와 라우팅 템플릿, 리스너 설정을 바탕으로 코어에 전달할 설정을 생성합니다. 생성된 파일을 수정해도 이번 실행에만 적용되고, 서버를 바꾸거나 코어를 다시 시작하면 덮어써질 수 있습니다. 설정을 계속 유지하려면 먼저 클라이언트의 해당 메뉴에서 변경하세요.

객체, 배열, 필드 유형

JSON의 최상위는 중괄호로 감싼 객체입니다. 객체의 필드는 큰따옴표로 된 이름, 콜론, 값으로 구성하며 여러 필드 사이에는 쉼표를 넣습니다. 배열은 대괄호로 감싸며 여러 인바운드나 아웃바운드, 순서가 중요한 규칙을 표현할 때 사용합니다. 문자열, 숫자, 불리언은 서로 바꿔 쓸 수 없습니다. 리스너 포트는 숫자로, 스위치는 true 또는 false로, 프로토콜 이름은 문자열로 입력합니다. 마지막 항목 뒤에는 쉼표를 붙이지 말고, 엄격한 JSON에 주석을 넣지 마세요.

아래는 일반적인 V2Ray·Xray 코어에서 사용할 수 있는 로컬 직접 연결 기본 설정입니다. 루프백 주소에서만 SOCKS 연결을 받으며 원격 프록시 서버는 포함하지 않습니다. 앱이 이 로컬 리스너에 연결되면 기기에서 대상에 직접 접속합니다. 이 예제는 로컬 리스너 문제와 원격 연결 문제를 구분하기 위한 것으로, 가져오기만 하면 원격 프록시 연결이 이루어진다는 뜻은 아닙니다.

{
  "log": {
    "loglevel": "warning"
  },
  "inbounds": [
    {
      "tag": "socks-in",
      "listen": "127.0.0.1",
      "port": 10808,
      "protocol": "socks",
      "settings": {
        "auth": "noauth",
        "udp": true
      }
    }
  ],
  "outbounds": [
    {
      "tag": "direct",
      "protocol": "freedom",
      "settings": {}
    }
  ]
}

최상위 설정 블록의 역할

설정 블록담당 기능주요 확인 항목
inbounds앱 연결 수신리스너 주소, 포트, 인바운드 프로토콜
outbounds대상 연결 생성프로토콜, 서버 매개변수, 아웃바운드 태그
routing연결에 사용할 아웃바운드 선택규칙 순서, 매칭 조건, 태그 참조
dns내장 이름 확인 기능 제공서버, 도메인 범위, DNS 요청 경로
policy연결 정책과 통계 스위치 관리사용자 레벨, 시간 제한, 통계 의존성

각 블록은 텍스트에 나타난 순서대로 실행되는 것이 아니라 서로 참조하며 작동합니다. 라우팅의 outboundTag는 아웃바운드의 tag를 가리키고, 정책 레벨은 프로토콜 사용자 객체의 level과 연결됩니다. 객체 필드의 작성 순서는 대개 의미를 바꾸지 않지만 배열 순서는 동작에 영향을 줄 수 있습니다. 특히 라우팅 규칙과 기본 아웃바운드의 순서가 중요합니다. 설정을 읽을 때는 개별 값보다 먼저 참조 관계를 확인하세요.

전체 파일과 일부 설정 조각

이후 예제 대부분은 같은 이름의 설정 블록을 교체하거나 병합하는 최상위 조각입니다. routing이 들어 있는 두 객체를 그대로 이어 붙이거나, 이름이 같은 최상위 키를 중복해서 두지 마세요. 일부 파서는 중복 키를 허용하고 그중 한 값만 적용하기도 하지만, 이런 동작에 의존해서는 안 됩니다. 병합할 때는 최상위 객체 하나만 유지하고 대상 블록을 올바른 계층에 넣은 다음 괄호, 배열, 쉼표를 확인하세요.

코어마다 공통 개념은 있지만 모든 확장 필드가 동일하게 지원되는 것은 아닙니다. 전송 방식, DNS 옵션, 사용자 레벨의 지원 여부는 실제 실행 중인 코어를 기준으로 확인하세요. 필드를 최소한으로 구성해 먼저 실행한 뒤 기능을 하나씩 추가하는 편이 출처가 제각각인 설정 조각을 한꺼번에 가져오는 것보다 차이를 파악하기 쉽습니다. 클라이언트를 업그레이드한 뒤에는 생성된 설정을 다시 살펴보세요. 예전 스크린샷만으로 필드가 바뀌지 않았다고 단정할 수 없습니다.

설정을 기록할 때는 코어 이름, 클라이언트 메뉴 위치, 수정 목적을 함께 적어 두는 것이 좋습니다. 민감한 서버 인증 정보는 공개 스크린샷이나 문서에 포함하지 마세요. 오류가 발생하면 JSON 구문 분석 실패, 지원되지 않는 필드, 실행 중 연결 실패를 구분하세요. 뒤에서 같은 순서로 자세히 살펴봅니다. 이렇게 하면 포트 점유를 프로토콜 문제로 오인하거나 규칙이 매칭되지 않는 상황을 JSON 오류로 착각하지 않을 수 있습니다.

inbounds: 로컬 인바운드 리스너

인바운드는 앱이 연결을 코어에 전달하는 방식을 정의합니다. 데스크톱에서는 앱이 로컬 SOCKS 또는 HTTP 프록시를 사용하고 클라이언트가 해당 리스너를 실행하는 방식이 일반적입니다. 앱에 입력한 주소, 포트, 프로토콜은 인바운드 설정과 일치해야 합니다. 클라이언트 창이 보인다고 해서 코어가 리스닝에 성공한 것은 아닙니다. 리스너가 열렸는지 확인하려면 시스템 트레이 아이콘만 보지 말고 시작 로그와 실제 포트 점유 상태를 확인하세요.

리스너 주소와 프로토콜 선택

listen은 원격 서버 주소가 아니라 로컬 바인딩 주소입니다. 127.0.0.1을 사용하면 로컬 루프백 연결만 받습니다. 0.0.0.0으로 바꾸면 IPv4 네트워크 인터페이스 전체에 바인딩되어 LAN 기기에서도 포트에 접근할 수 있습니다. 따라서 인증, 방화벽, 네트워크 경계 설정을 함께 적용해야 합니다. 클라이언트에서 LAN 연결 스위치를 켜는 것만으로 다른 기기의 접속이 보장되지는 않습니다.

{
  "inbounds": [
    {
      "tag": "socks-in",
      "listen": "127.0.0.1",
      "port": 10808,
      "protocol": "socks",
      "settings": {
        "auth": "noauth",
        "udp": true
      },
      "sniffing": {
        "enabled": true,
        "destOverride": ["http", "tls"],
        "routeOnly": true
      }
    },
    {
      "tag": "http-in",
      "listen": "127.0.0.1",
      "port": 10809,
      "protocol": "http",
      "settings": {}
    }
  ]
}

이 예제의 routeOnly는 Xray 설정 의미에 따라 사용합니다. 스니핑으로 얻은 정보는 라우팅에 활용되며 원래 대상을 직접 바꾸지는 않습니다. 다른 코어로 전환하기 전에 이 필드의 지원 여부를 확인하세요. 로컬 리스너만 테스트하려면 먼저 sniffing 블록 전체를 제거하고 기본 리스너를 유지하세요. 리스너가 안정적으로 동작한 뒤 스니핑과 도메인 규칙을 테스트하면 두 가지 변수를 한꺼번에 추가하는 일을 피할 수 있습니다.

SOCKS와 HTTP는 서로 다른 인바운드 프로토콜입니다. 앱이 HTTP 프록시만 지원한다면 HTTP 인바운드 포트를 입력해야 합니다. 두 포트가 모두 로컬에 있다고 해서 임의로 바꿔 쓸 수는 없습니다. SOCKS 인바운드에서 udp를 활성화하면 해당 UDP 전달 기능을 허용한다는 뜻입니다. 앱도 지원되는 방식으로 UDP 트래픽을 보내야 하고 원격 연결 경로에도 해당 기능이 있어야 합니다. 일반 HTTP 프록시 리스너는 모든 UDP 트래픽을 가로채는 기능과 다릅니다.

도메인 정보가 규칙에 전달되는 경로

앱은 도메인 이름을 프록시에 전달할 수도 있고, 로컬에서 먼저 DNS 조회를 한 뒤 대상 IP를 프록시에 전달할 수도 있습니다. 전자의 경우 도메인 규칙을 바로 사용할 수 있지만 후자의 경우 기존 대상 정보나 스니핑 결과를 함께 확인해야 합니다. 스니핑은 식별 가능한 프로토콜 특징을 읽는 기능이지 범용 콘텐츠 복호화 도구가 아닙니다. 연결에서 도메인 정보를 찾을 수 없거나 핸드셰이크가 다른 방식으로 보호되거나 프로토콜이 지원 범위 밖이면 정확한 도메인 정보가 자동으로 복원되리라 기대할 수 없습니다.

destOverride의 http와 tls는 스니핑 대상 프로토콜 유형이지, 아웃바운드 전송 방식을 선택하는 값이 아닙니다. 스니핑을 켜도 TLS가 자동으로 활성화되지 않으며 서버 인증서 문제도 해결되지 않습니다. 도메인 분할 라우팅을 확인할 때는 앱이 도메인을 전달하는지, 현재 인바운드에서 스니핑을 사용하는지, 규칙에 실제로 도메인과 IP 중 무엇이 전달되는지 함께 확인하세요. 스위치 하나만 점검해서는 충분하지 않습니다.

포트 충돌과 LAN 접속

두 프로세스가 같은 리스너 주소와 포트를 동시에 사용할 수는 없습니다. 클라이언트 시작 시 주소가 이미 사용 중이라는 오류가 나오면 중복 실행 중인 인스턴스를 종료하고 다른 프로그램이 같은 포트를 리스닝하는지 확인하세요. 인바운드 포트를 바꿨다면 앱의 프록시 설정과 시스템 프록시 설정도 함께 수정해야 합니다. 그렇지 않으면 새 코어가 정상 실행돼도 앱은 이전 포트에 연결합니다. 설정을 저장하기 전에 기존 값을 기록해 두면 테스트 실패 시 원래대로 복구할 수 있습니다.

LAN 기기에서 리스너를 사용하려면 먼저 기기끼리 통신할 수 있는 네트워크인지 확인하고, 바인딩 주소, 시스템 방화벽, 접속 인증을 점검하세요. noauth로 설정한 로컬 예제를 신뢰할 수 없는 네트워크에 그대로 노출하지 마세요. 전체 인터페이스를 열기보다 특정 기기만 허용하는 편이 안전합니다. 다른 기기의 연결이 인바운드에 도달한 뒤에도 라우팅 규칙을 거치므로, 리스너 연결과 대상 서버 접속은 별도로 확인해야 합니다.

인바운드 태그는 안정적이고 명확하며 고유하게 유지하는 것이 좋습니다. 예를 들어 브라우저와 테스트 프로그램에 서로 다른 태그를 지정한 뒤 라우팅의 inboundTag로 진입점별 동작을 확인할 수 있습니다. 태그는 인증 정보가 아니며 특별한 기본 의미도 없습니다. 설정에서 참조하는 이름일 뿐이므로 철자가 바뀌면 관련 규칙에 영향을 줍니다. 문제를 해결할 때 이름이 비슷해 보인다는 이유로 연결된 것으로 판단하지 말고 글자 단위로 확인하세요.

outbounds: 아웃바운드와 프로토콜 매개변수

아웃바운드는 코어가 다음 연결 구간을 어떻게 만들지 결정합니다. 직접 연결, 차단, 원격 프록시 아웃바운드는 모두 이 계층에 속하지만 역할은 서로 다릅니다. 아웃바운드가 설정되어 있다고 해서 사용되는 것은 아닙니다. 라우팅 규칙이 해당 아웃바운드를 선택하는지, 규칙에 매칭되지 않을 때 기본 아웃바운드가 무엇인지도 확인해야 합니다. 일반적으로 의도한 기본 아웃바운드를 배열 첫 번째에 두고, 규칙에서 참조할 아웃바운드에는 고유한 태그를 지정하세요. 구분하기 어려운 배열 위치에 의존하지 않는 편이 좋습니다.

프로토콜과 전송 계층 구분

protocol은 아웃바운드에서 사용할 프록시 프로토콜 또는 처리 방식을 지정합니다. 원격 주소, 포트, 사용자 매개변수는 보통 settings에, 전송 및 연결 보안 설정은 대개 streamSettings에 지정합니다. 프로토콜, 전송, 보안은 서로 연동하는 세 가지 요소입니다. 프로토콜 이름 하나만으로 완전한 연결 방식이 정해지는 것은 아닙니다. 양쪽 프로토콜이 같더라도 전송 경로, 서비스 이름, 보안 매개변수가 다르면 핸드셰이크에 실패할 수 있습니다.

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

이 예제에는 원격 서버가 없으며 아웃바운드 참조를 이해하는 데 사용할 수 있습니다. freedom은 로컬에서 대상에 연결합니다. 도메인 이름을 조회하는지, 어떤 주소를 선택하는지는 관련 설정의 영향을 받습니다. blackhole은 매칭된 트래픽을 버리는 아웃바운드로, 명확히 차단해야 하는 범위에 적합합니다. 기본 동작에서는 앱에 연결 실패나 시간 초과로 나타날 수 있으며, 이를 대상 웹사이트의 장애로 해석해서는 안 됩니다. 문제를 진단할 때 먼저 규칙이 트래픽을 차단 아웃바운드로 보냈는지 확인하세요.

VLESS 필드 구성

VLESS 원격 연결 매개변수는 서버 설정이나 신뢰할 수 있는 공유 정보에서 가져와야 합니다. vnext는 서버 목록을 정의하며, 그 안의 address와 port는 연결 대상을 지정합니다. users의 id는 사용자를 식별합니다. 예제만으로 실제 연결 인증 정보를 만들지 말고 구독 그룹 이름을 서버 주소로 입력하지 마세요. 주소, 사용자 매개변수, 전송 보안 설정은 모두 같은 서버 설정에서 가져와야 합니다.

VLESS에서 encryption의 일반적인 값인 none은 프로토콜 사용자 설정이며 연결 전체에 전송 보안이 없다는 뜻은 아닙니다. TLS와 REALITY 같은 연결 보안 방식은 해당 코어가 지원하는 전송 설정에서 처리하며 서로의 매개변수를 혼용할 수 없습니다. 서버 이름, 인증서 검증, 공개 키, 식별자 매개변수는 각각 의미가 다릅니다. 필드의 의미를 모른다면 검증을 끄고 오류를 우회하지 말고 원본 공유 정보를 다시 확인하세요.

VMess, VLESS, Trojan은 인증 구조도 서로 다릅니다. 한 프로토콜의 사용자 객체를 다른 프로토콜 설정에 그대로 복사하지 마세요. 가장 안전한 방법은 클라이언트에서 유효한 공유 링크를 가져온 뒤 생성된 설정을 살펴보며 각 연결 매개변수가 어느 계층에 들어가는지 확인하는 것입니다. 프로토콜 개념을 비교하려면 용어 가이드를 참고하세요. 이 페이지는 필드 위치와 참조 관계에 중점을 두며, 사용 환경과 관계없이 프로토콜의 순위를 매기지 않습니다.

기본 아웃바운드와 연결 확인

프록시 아웃바운드를 설정했더라도 어떤 규칙도 가리키지 않고 기본 아웃바운드도 아니라면 트래픽이 자동으로 해당 서버를 사용하지 않습니다. 반대로 프록시 아웃바운드를 배열 첫 번째에 두면 다른 규칙에 매칭되지 않은 연결이 프록시를 사용합니다. 배열 순서를 바꾸면 기본 동작도 달라집니다. 수정하기 전에 어떤 연결은 직접 연결할지, 어떤 연결은 차단할지, 나머지는 어느 아웃바운드에 맡길지 한 문장으로 정리하세요. 그 문장은 실제 배열과 규칙에 대응해야 합니다.

원격 연결을 확인할 때는 먼저 로컬 기기에서 서버 주소와 포트에 연결할 수 있는지 보고, 다음으로 전송 핸드셰이크, 마지막으로 대상 요청을 확인하세요. 서버 포트에 연결할 수 있다는 것은 네트워크 계층에서 응답한다는 뜻일 뿐 인증에 성공했다는 뜻은 아닙니다. 인증서 이름 불일치, 전송 매개변수 불일치, 잘못된 사용자 ID는 이후 단계에서 실패를 일으킬 수 있습니다. 클라이언트의 지연 시간 결과만으로 실제 앱 요청을 대신 검증할 수는 없으므로 로그의 오류 발생 단계를 함께 확인하세요.

코어를 바꾼 뒤에는 현재 코어가 프로토콜과 전송 방식을 모두 지원하는지, 생성된 설정에 필요한 옵션이 그대로 있는지 확인하세요. 화면에 같은 서버 이름이 표시된다는 이유만으로 내부 매개변수까지 완전히 같다고 볼 수는 없습니다. 사용자 지정 아웃바운드라면 원본 가져오기 정보와 작동하는 설정 사본을 보관해 두세요. 가져오기 변환 문제, 코어별 차이, 서버 설정 변경을 구분하는 데 도움이 됩니다.

routing: 규칙 매칭과 트래픽 분기

라우팅은 사용할 아웃바운드를 선택하며 원격 서버 설정을 바꾸지는 않습니다. 규칙은 배열 순서대로 확인되고 일반적으로 처음 매칭된 규칙이 연결 경로를 결정합니다. 매칭되는 규칙이 없으면 기본 아웃바운드를 사용합니다. 규칙을 설계할 때는 범위가 좁고 목적이 명확한 예외를 먼저 두고, 범위가 넓은 규칙을 뒤에 배치하세요. 앞의 규칙이 모든 대상을 먼저 매칭하면 뒤의 규칙은 구문이 올바르더라도 적용되지 않습니다. 문제를 해결할 때 특정 규칙이 있는지만 확인해서는 부족합니다.

도메인 규칙과 IP 규칙

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

이 설정 조각을 사용하려면 block과 direct 아웃바운드가 있어야 합니다. full:example.com은 해당 도메인 전체 이름에만 매칭되며 모든 하위 도메인을 자동으로 포함하지 않습니다. 도메인과 하위 도메인을 모두 대상으로 하려면 적절한 domain: 형식을 사용하세요. 접두사가 없는 문자열은 일반적인 구현에서 키워드로 처리될 수 있습니다. 규칙을 작성할 때 매칭 방식을 명확히 지정해 비슷한 이름까지 잘못 포함되지 않도록 하세요.

geosite:cn과 geoip:private는 규칙 데이터 범주를 참조합니다. 실행 중 이름만으로 집합을 추측하는 방식이 아닙니다. 코어가 읽을 수 있는 해당 데이터 파일과 파일 안의 항목에 의존합니다. 데이터가 없으면 시작에 실패할 수 있고 데이터가 업데이트되면 실제 적용 범위도 바뀔 수 있습니다. 특정 도메인의 분기 결과가 예상과 다르면 명시적인 도메인 규칙으로 먼저 확인한 다음 데이터 분류와 규칙 순서 중 무엇이 차이를 일으켰는지 살펴보세요.

domainStrategy의 적용 범위

AsIs는 라우팅 단계에서 이미 확보한 대상 정보를 주로 사용하며 IP 규칙을 위해 도메인을 능동적으로 조회하지 않습니다. IPIfNonMatch는 도메인 규칙에 매칭되지 않으면 조회를 시도한 뒤 결과를 사용해 관련 규칙을 확인합니다. IPOnDemand는 매칭 과정에서 IP 정보가 필요한 조건을 만나면 조회를 시작합니다. 세 옵션은 라우팅 매칭 단계에 영향을 줍니다. 시스템 DNS 전체를 켜고 끄는 스위치가 아니며 다른 앱의 조회 요청이 코어에 들어온다고 보장하지도 않습니다.

조건주요 용도유의 사항
domain도메인 목록에 따라 트래픽 분기연결에 도메인 정보가 전달되거나 복원되어야 함
ip주소와 IP 대역으로 트래픽 분기도메인 대상은 먼저 조회해야 할 수 있음
port대상 포트 범위 제한로컬 인바운드 리스너 포트가 아님
inboundTag로컬 진입점 구분실제 인바운드 태그와 일치해야 함
networkTCP와 UDP 구분연결 경로에도 해당 전달 기능이 필요함

한 규칙 안에서 서로 다른 유형의 조건은 보통 모두 충족해야 합니다. 같은 유형의 후보 값이 여러 개 있으면 대개 하나만 매칭되어도 됩니다. 예를 들어 한 규칙에 도메인과 포트를 함께 쓰면 해당 도메인의 지정 포트 연결을 뜻하며, 도메인 또는 포트 중 하나만 매칭되면 된다는 의미가 아닙니다. 서로 독립적인 두 상황을 표현하려면 규칙을 나누세요. 규칙이 간결할수록 로그와 테스트 결과에서 실제 매칭 조건을 파악하기 쉽습니다.

기본 규칙과 롤백 방법

라우팅 템플릿에서 자주 발생하는 문제는 기본 규칙을 너무 앞에 두거나 태그를 잘못 입력하거나 대상 포트를 인바운드 포트로 착각하는 것입니다. 먼저 테스트 도메인 하나만 사용하는 최소 규칙을 만들고 지정한 아웃바운드로 연결되는지 확인한 다음 데이터 범주와 여러 조건으로 확장하세요. 매번 규칙 집합 하나만 수정하고 테스트 후 매칭된 아웃바운드 태그를 기록하세요. 여러 출처의 규칙을 한꺼번에 합치면 규칙끼리 가려질 때 어떤 수정이 동작을 바꿨는지 파악하기 어렵습니다.

사설 IP 직접 연결 여부는 네트워크 용도를 함께 고려해야 합니다. LAN 서비스가 내부 도메인을 사용하고 앱이 이를 사설 IP로 먼저 조회하는 경우 공개 도메인 규칙만으로는 해당 연결을 처리하지 못할 수 있습니다. 반대로 사설 IP 대역의 매칭 범위를 넓히기 전에는 특별한 경로가 필요한 내부 네트워크 트래픽까지 잘못 보내지 않는지 확인하세요. 규칙은 실제 네트워크 경계를 표현합니다. ‘사설’이라는 이유만으로 접근 제어를 무시해서는 안 됩니다.

클라이언트의 전역, 우회, 규칙 모드는 서로 다른 템플릿으로 라우팅을 생성할 수 있습니다. 이름이 비슷해도 설정이 완전히 같다고 볼 수 없습니다. 모드를 바꾼 뒤에는 변경 전 파일을 계속 분석하지 말고 생성된 설정을 다시 확인하세요. 라우팅과 DNS도 함께 점검해야 합니다. 라우팅에서 조회 결과를 요구하고 DNS 서버 자체는 아웃바운드 연결을 필요로 할 수 있습니다. 두 기능이 서로 의존한다면 기본 네트워크 경로를 명확히 설정해야 합니다.

dns: 이름 확인 경로와 주소 선택

코어 DNS는 이를 사용하는 내부 절차에 조회 결과를 제공하지만, 최상위에 dns가 있다고 시스템 DNS 리졸버가 자동으로 바뀌지는 않습니다. 앱이 먼저 시스템 DNS로 주소를 얻은 뒤 IP를 프록시에 전달하면 코어에는 IP만 보일 수 있습니다. 앱이 도메인을 프록시에 전달하면 라우팅이나 아웃바운드에서 내장 DNS를 호출할 수 있습니다. DNS 문제를 분석하려면 먼저 누가 조회를 시작하는지, 그 요청이 어느 서버로 전달되는지 확인하세요.

정적 매핑과 서버 적용 범위

{
  "dns": {
    "hosts": {
      "local.test": "127.0.0.1"
    },
    "servers": [
      {
        "address": "223.5.5.5",
        "domains": ["geosite:cn"]
      },
      "1.1.1.1"
    ],
    "queryStrategy": "UseIPv4"
  }
}

이 설정 조각은 코어 내부의 정적 매핑, 도메인별 우선 서버, 조회 주소 유형을 보여 줍니다. 시스템 hosts 파일에는 항목을 쓰지 않습니다. local.test는 매핑 계층을 설명하기 위한 이름이며 앱이 코어를 통해 이름을 조회하는 경우에만 접근할 수 있습니다. domains는 해당 서버가 우선 처리할 도메인 범위를 지정하지만, 다른 DNS 경로를 차단하는 네트워크 방화벽 규칙과는 다릅니다.

여러 DNS 서버 중 무엇을 선택할지는 코어 구현과 대체 조회 옵션의 영향도 받으므로 첫 번째 서버 실패 후 다음 서버를 순서대로 시도한다고 단순하게 볼 수 없습니다. 특정 도메인 유형의 조회 경로를 엄격히 제한하려면 사용 중인 코어의 대체 및 매칭 동작을 더 확인하고 실제 조회 결과로 검증하세요. 예제의 공개 DNS 주소는 필드 형식을 보여 주기 위한 것입니다. 실제 배포에서는 현재 네트워크에서 연결 가능하고 용도에 맞는 DNS 서비스를 선택하세요.

DNS와 라우팅의 상호 의존성

라우팅에서 IPIfNonMatch를 사용하면 도메인 연결이 먼저 도메인 규칙에 매칭됩니다. 매칭되지 않으면 주소를 조회한 뒤 그 결과로 다시 규칙을 확인할 수 있습니다. 조회에 실패하면 다음 결정을 내릴 정보가 부족해지지만, 일반적인 연결 시간 초과처럼 보일 수 있습니다. DNS 요청 자체에도 네트워크 경로가 필요합니다. 조회 방식에 따라 코어 라우팅을 통과할 수도 있고 로컬 경로를 사용할 수도 있습니다. DNS 주소를 설정했다고 해서 조회 트래픽이 어느 아웃바운드를 쓸지까지 지정된 것은 아닙니다.

암호화 DNS 서비스를 사용할 때는 DNS 서버 이름을 처음 조회하는 경로도 고려해야 합니다. DNS 서비스에 접속하려면 먼저 해당 도메인을 조회해야 하는데 이 단계가 아직 설정되지 않은 프록시 연결에 의존한다면 순환 의존성이 생길 수 있습니다. 먼저 기본 DNS 조회나 서버 주소에 사용할 수 있는 경로를 마련한 뒤 분할 라우팅을 추가하세요. 문제를 해결할 때는 일시적으로 연결 가능한 주소를 명시해 이름 조회, 전송 연결, 대상 서버 응답 중 어느 단계에서 실패하는지 구분할 수 있습니다.

hosts는 소수의 명확한 내부 매핑이나 테스트용 재정의에 적합합니다. 자주 바뀌는 공용 서비스 주소를 장기간 수동으로 관리하는 용도에는 적합하지 않습니다. 서비스 주소는 지역, 부하, 네트워크에 따라 바뀔 수 있으며 너무 오래 고정하면 부적절한 대상으로 연결될 수 있습니다. 매핑을 추가할 때 목적을 기록하고 테스트가 끝나면 제거하세요. 그렇지 않으면 서버 설정을 바꾼 뒤에도 오래된 매핑이 계속 우선 적용될 수 있습니다.

IPv4, IPv6와 대상 연결

queryStrategy는 내장 리졸버에서 조회하거나 선택할 주소 유형을 제어합니다. 예제의 UseIPv4는 IPv6 경로 문제를 분리해 확인할 때 유용하지만 모든 네트워크에서 장기적으로 최선인 설정은 아닙니다. IPv6 주소를 조회했다고 해서 현재 아웃바운드에 사용 가능한 IPv6 연결이 있다는 뜻은 아닙니다. IPv4 주소만 얻었더라도 앱이 다른 조회 경로를 통해 IPv6를 얻었을 수 있습니다. 조회 결과와 연결 결과를 각각 확인하세요.

라우팅의 domainStrategy, DNS의 queryStrategy, 직접 연결 아웃바운드의 주소 정책은 서로 다른 계층에 속합니다. 이름은 비슷하지만 적용 대상이 다릅니다. 정책을 바꿔도 변화가 없다면 먼저 필드가 어느 블록에 있는지, 해당 코드 경로가 실제로 호출되는지 확인하세요. 앱에서 이미 IP를 전달했다면 처리에 관여하지 않는 DNS 서버 항목을 바꿔도 연결에 변화가 없을 수 있습니다.

일반적인 확인 순서는 서버 주소를 조회할 수 있는지, DNS 서비스에 연결할 수 있는지, 대상에서 예상한 주소를 얻는지, 라우팅이 올바른 아웃바운드를 선택하는지 확인하는 것입니다. 여러 DNS 서비스를 동시에 바꾸고 주소 유형을 수정하며 모든 라우팅 순서까지 바꾸지 마세요. 한 번에 한 가지씩 변경하고 실패 단계를 기록해야 리졸버 장애, 주소 연결 불가, 아웃바운드 핸드셰이크 문제를 구분할 수 있습니다.

policy, 로그와 연결 정책

정책은 연결 수명과 통계 동작을 관리합니다. 프록시 서버를 선택하거나 네트워크 품질을 자동으로 높이는 기능은 아닙니다. 값을 바꾸기 전에 문제가 연결 설정, 유휴 상태 유지, 업로드나 다운로드 종료 중 어느 단계에서 발생하는지 확인하세요. 모든 시간 제한을 늘리면 실패가 늦게 나타날 뿐일 수 있고, 모두 줄이면 네트워크가 약한 환경에서 정상 요청도 일찍 종료될 수 있습니다. 정책 값은 설명 가능한 앱 동작에 맞춰야 하며 범용 속도 향상 스위치로 사용해서는 안 됩니다.

사용자 레벨과 연결 시간

{
  "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 등의 필드가 제어에 관여합니다. 실제 적용 여부는 프로토콜 구현과 연결 상태에 따라 달라지므로 운영체제의 모든 소켓에 공통으로 적용되는 시간 제한으로 보면 안 됩니다.

levels의 키는 레벨 번호를 문자열로 지정합니다. 사용자 레벨을 지원하는 프로토콜 객체의 level과 일치해야 합니다. 레벨 정의를 추가해도 모든 연결이 자동으로 해당 레벨로 이동하지는 않습니다. 수정 후 동작이 달라지지 않는다면 값의 크기를 조정하기 전에 현재 프로토콜에서 정책을 사용하는지, 사용자 레벨이 일치하는지 확인하세요. 지원 범위는 사용 중인 코어를 기준으로 확인해야 합니다.

통계 스위치와 표시 경로

정책의 통계 불리언 값은 해당 유형의 데이터를 기록할지 결정할 뿐, 조회 가능한 통계 서비스가 이미 갖춰졌다는 뜻은 아닙니다. 통계를 완전히 사용하려면 stats, API 서비스, 태그, 클라이언트의 읽기 로직이 추가로 필요할 수 있습니다. 일부 단계만 활성화되어 있으면 화면에 데이터가 표시되지 않아도 트래픽이 코어를 통과하지 않았다고 단정할 수 없습니다. 데스크톱 클라이언트가 통계에 필요한 블록을 자체 생성할 수 있으므로 사용자 지정 설정으로 이를 무작정 덮어쓰지 마세요.

사용자에게 표시되는 트래픽 수치는 요금 계산이나 완전한 네트워크 감사의 근거로 바로 사용하기에 적합하지 않습니다. 어떤 인바운드를 통과하는지, 직접 연결 트래픽을 포함하는지, 언제 통계를 초기화하는지는 실제 구현에 따라 달라집니다. 문제를 해결할 때 통계는 보조 신호로 활용하는 편이 좋습니다. 규칙 매칭 후 해당 아웃바운드에 활동이 있는지, 서버를 바꾼 뒤 새 아웃바운드에 데이터가 들어오는지 확인하세요. 누적 수치 하나만으로 실제 요청과 로그 검증을 대신하지 마세요.

로그 수준과 민감 정보

{
  "log": {
    "loglevel": "warning",
    "dnsLog": false
  }
}

평소에는 경고 수준을 유지하고 문제를 재현하는 짧은 시간 동안만 로그 상세도를 높이세요. 상세 로그에는 대상 도메인, 연결 주소, 내부 네트워크 정보가 포함될 수 있습니다. 문제를 신고하기 전에 서버 인증 정보, 전체 구독 주소, 불필요한 개인 접속 기록을 삭제하되 오류 유형, 발생 순서, 관련 태그는 남기세요. 맥락을 전부 지우고 ‘연결 실패’만 남기면 오류 단계를 구분하기 어렵습니다.

파일 경로를 지정하지 않으면 로그가 프로세스 출력에 기록된 뒤 클라이언트가 수집할 수 있습니다. 파일에 직접 출력하도록 설정한 경우 대상 폴더가 있고 실행 계정에 쓰기 권한이 있는지 확인하세요. 클라이언트가 자체 설정 폴더에 쓸 수 있다고 해서 코어도 임의 경로에 쓸 수 있는 것은 아닙니다. 잘못된 로그 경로, 디스크 공간 부족, 다른 프로그램의 폴더 접근 제한 때문에 예상한 로그가 생성되지 않을 수 있습니다. 로그가 없다는 이유만으로 코어가 실행되지 않았다고 판단하지 마세요.

장시간 연결이 끊기는 경우 먼저 앱 자체 시간 제한, 서버의 유휴 시간 제한, 네트워크 장비의 연결 유지 설정, 코어 정책을 비교하세요. 코어의 유휴 연결 처리가 원인이라는 근거가 있을 때만 connIdle 등의 값을 조정하세요. 일부 앱은 유지 연결 요청을 주기적으로 보내지만 그렇지 않은 앱도 있습니다. 같은 정책이라도 동작이 다를 수 있으므로 한 번의 테스트 결과를 모든 프로그램에 적용하지 마세요.

시작에 실패했다면 정책은 우선 확인할 항목이 아닙니다. 먼저 JSON 구문, 필드 호환성, 리스너 포트를 확인하고 다음으로 리소스 경로와 권한을 살펴보세요. 실행은 되지만 특정 요청만 실패한다면 그때 아웃바운드 핸드셰이크, DNS, 연결 시간 제한을 확인하세요. 장애 단계에 맞춰 순서대로 점검하면 근거 없는 값 조정을 줄이고 설명과 롤백이 가능한 설정을 유지할 수 있습니다.

클라이언트 설정과 코어 설정의 경계

클라이언트는 서버, 구독, 라우팅 템플릿, 실행 방식을 구성하고 코어는 연결을 처리합니다. 데스크톱에서는 v2rayN을 우선 추천하며, Android에서는 필요에 따라 v2rayNG 또는 V2Fly 기반의 v2flyNG를 선택할 수 있습니다. 세 클라이언트는 메뉴 이름과 설정 생성 절차가 서로 다르므로 데스크톱 화면의 스위치를 모두 공통 JSON 필드 하나에 대응시킬 수는 없습니다. 설정을 살펴볼 때는 먼저 클라이언트, 시스템, 현재 코어 중 어느 쪽에 속하는지 확인하세요.

구독 관리와 생성 파일

구독은 서버 정보를 배포하는 방식이지 V2Ray 최상위의 subscription 설정 블록이 아닙니다. v2rayN의 구독 그룹, 자동 업데이트 간격, 업데이트 요청 방식은 클라이언트에 저장됩니다. 코어가 받는 것은 대개 파싱 후 생성된 아웃바운드 매개변수입니다. 구독 업데이트 간격을 바꿔도 기존 연결의 시간 제한 정책은 달라지지 않습니다. 아웃바운드 사용자 매개변수를 바꿔도 만료된 구독 주소가 자동으로 복구되지 않습니다.

구독을 업데이트하기 전에 현재 작동하는 설정을 보관하세요. 업데이트 후에는 그룹, 서버 수의 변화, 현재 선택 항목을 확인하고 특히 선택된 서버가 삭제되거나 이름이 바뀌었는지 살펴보세요. 구독 관리 대상 항목을 수동으로 수정하면 다음 업데이트 때 덮어써질 수 있습니다. 사용자 지정 매개변수를 계속 유지하려면 클라이언트가 지원하는 저장 설정이나 별도 사용자 지정 설정을 사용하세요. 실행 파일을 구독 데이터베이스로 취급하지 마세요.

업데이트 실패 시 요청 주소에 연결할 수 없는지, 서버가 오류를 반환했는지, 콘텐츠 형식을 인식하지 못하는지 먼저 구분하세요. 브라우저에서 페이지가 열린다고 해서 클라이언트가 해당 페이지를 구독으로 파싱할 수 있는 것은 아닙니다. 전체 링크에 접속 인증 정보가 포함될 수 있으므로 공개적으로 붙여 넣지 마세요. 가져오기 경로와 공유 링크 형식은 구독 링크 가져오기 방법에서 확인할 수 있으며, 처음 사용하는 경우 기본 튜토리얼부터 따라가세요.

TUN 모드와 트래픽 가로채기

TUN은 가상 네트워크 인터페이스로 네트워크 계층의 트래픽을 받습니다. 시스템 라우팅, 권한, DNS 가로채기, 제외 규칙이 관련되며 일반 V2Ray 최상위 객체에 tun 필드 하나를 추가하는 방식이 아닙니다. 클라이언트가 다른 코어 설정을 사용해 이 기능을 구현할 수 있으며, 필드 구조는 이 페이지의 일반 V2Ray·Xray 설정과 다를 수 있습니다. v2rayN의 TUN 모드 메뉴에서 실제 생성된 내용과 관련 로그를 확인하세요.

활성화하기 전에 일반 프록시 리스너가 작동하는지 확인하고 권한, 가상 인터페이스, 시스템 라우팅이 정상적으로 생성됐는지 살펴보세요. 일반 프록시는 작동하지만 TUN이 작동하지 않는다면 원격 프로토콜 매개변수를 바로 다시 작성하지 말고 트래픽 가로채기 경로부터 확인하세요. 서버 연결이 가상 인터페이스로 다시 전송되어 루프가 생기지 않는지, LAN 서비스에 제외 설정이 필요한지도 확인해야 합니다. 다른 가상 네트워크 프로그램을 함께 실행 중이라면 라우팅 우선순위도 결과에 영향을 줄 수 있습니다.

멀티 코어 전환

코어 선택은 이름 하나를 바꾸는 것만이 아닙니다. 프로토콜 지원, 전송 필드, 규칙 데이터, 클라이언트가 사용하는 설정 생성 형식에 영향을 줍니다. v2rayNG는 일반적으로 Xray를 사용하고 v2flyNG는 V2Fly를 사용합니다. v2rayN에서 실제로 선택할 수 있는 항목은 설치된 구성요소에 따라 달라집니다. 코어를 바꾼 뒤에는 서버 매개변수, 라우팅, DNS를 다시 확인하고 한 코어의 확장 설정을 다른 코어에 그대로 복사하지 마세요. 생태계 배경은 사이트 소개에서 확인할 수 있습니다.

시스템 프록시와 앱 동작

시스템 프록시는 클라이언트가 운영체제나 데스크톱 환경의 프록시 설정에 기록합니다. 코어 공통 최상위 필드가 아닙니다. 이 설정을 따르는 앱에만 적용됩니다. 특정 앱이 계속 직접 연결한다면 앱 자체 프록시 설정을 사용하는지, 어떤 유형의 트래픽인지 먼저 확인하세요. 코어를 종료한 뒤에도 시스템 프록시가 이전 로컬 포트를 가리키면 앱에서 계속 연결 오류가 발생할 수 있습니다. 이 경우 설정 파일만 지우지 말고 시스템 프록시를 해제하세요.

클라이언트를 업그레이드하거나 초기화하기 전에 구독 그룹, 라우팅 템플릿, 사용자 지정 설정을 각각 백업하세요. 복원할 때도 단계별로 진행합니다. 먼저 작동하는 서버를 복원하고, 다음으로 규칙을 복원한 뒤, 마지막에 트래픽 가로채기 방식을 복원하세요. 이전 설정을 한꺼번에 가져온 뒤 문제가 재현되면 오래된 필드의 호환성, 설정 생성 과정의 변경, 시스템 프록시와 가상 네트워크 상태의 복구 중 무엇이 원인인지 판단하기 어렵습니다.

설정 검증과 단계별 문제 해결

설정 검증은 ‘파싱 가능’에서 시작해 ‘예상한 결과’까지 단계적으로 진행해야 합니다. 구문이 올바르다는 것은 파일 구조를 읽을 수 있다는 뜻이지 필드가 지원된다는 뜻은 아닙니다. 필드가 지원되어도 원격 서버에 연결할 수 있다는 보장은 없습니다. 연결에 성공해도 모든 규칙이 예상대로 분기된다는 뜻은 아닙니다. 각 단계에 독립적인 테스트 목표를 두세요. 이전 단계가 통과하지 못했다면 다음 단계의 값을 바꿔 요행을 기대하지 마세요.

복구 가능한 테스트 기준 설정

현재 작동하는 설정과 이에 대응하는 클라이언트 설정을 저장하고 사용 중인 코어를 기록하세요. 테스트용 사본에서는 설정 블록 하나만 수정하고 성공 기준을 명확히 정합니다. 예를 들어 로컬 포트가 요청을 받는지, 특정 도메인이 지정한 아웃바운드를 사용하는지, LAN 주소가 직접 연결되는지 확인할 수 있습니다. 테스트 도중 구독 업데이트, 코어 전환, 규칙 재정렬을 동시에 하지 마세요. 변경 요인이 적을수록 결과를 설명하기 쉽습니다.

클라이언트에 설정 검사나 생성 설정 조회 기능이 있다면 먼저 사용하세요. 실행 설정에 방금 수정한 내용이 실제로 들어 있는지 확인한 다음 오류 출력을 살펴보세요. 일부 클라이언트는 코어를 시작하기 전에 임시 파일을 생성하므로 오래된 파일을 직접 수정해도 다음 실행에 반영되지 않습니다. 저장한 뒤 내용이 사라진다면 같은 파일을 반복해서 수정하지 말고 설정의 원본 위치를 확인하세요.

오류 발생 단계에 따라 범위 좁히기

증상우선 확인할 항목다음 검증 단계
설정을 읽지 못함괄호, 쉼표, 유형, 중복 키최소한의 최상위 객체로 복원
코어 시작 실패지원되지 않는 필드, 포트, 리소스 경로처음 발생한 실제 오류 확인
앱이 리스너에 연결하지 못함리스너 주소, 포트, 인바운드 프로토콜로컬 프록시를 직접 지정
리스너는 작동하지만 원격 연결 실패서버 주소, 인증, 전송 보안연결 단계와 핸드셰이크 단계 구분
일부 도메인만 문제 발생라우팅 순서, DNS, 주소 유형도메인 하나로 최소 규칙 테스트
재시작 후 수정 내용이 사라짐설정 원본과 생성 방식지속 설정 메뉴에서 수정

구문 오류가 발생하면 오류 메시지 근처의 필드부터 살펴보되 바로 앞 줄에 쉼표가 빠졌거나 불필요한 쉼표가 들어갔는지도 확인하세요. 숫자 포트에 필드가 요구하는 형식과 맞지 않는 문자열을 입력하는 등 겉보기에는 그럴듯한 값에 유형 오류가 숨어 있을 수 있습니다. 시작 오류라면 가장 먼저 발생한 실제 오류부터 처리하세요. 뒤이어 나오는 ‘프로세스 종료’는 대개 앞선 오류의 결과입니다. 마지막 한 줄만 잘라 보내기보다 전체 오류의 발생 순서를 남기는 편이 진단에 도움이 됩니다.

코어가 실행 중이라면 먼저 프록시를 명시적으로 지원하는 앱 하나에서 로컬 리스너를 직접 사용해 보세요. 시스템의 자동 프록시 판단에는 의존하지 않습니다. 이 테스트는 성공하지만 다른 앱은 실패한다면 앱의 연결 경로와 시스템 프록시를 중점적으로 살펴보세요. 모든 앱이 연결되지 않는다면 리스너와 코어 프로세스를 확인하세요. 로컬 리스너에는 연결되지만 대상에 접속하지 못한다면 원격 핸드셰이크와 라우팅을 살펴보세요. 두 단계를 하나의 ‘인터넷 연결 불가’ 문제로 취급해서는 안 됩니다.

좁은 범위의 규칙으로 실제 경로 확인

라우팅을 진단할 때는 안정적으로 재현할 수 있는 대상을 하나 선택하고, 임시로 우선순위가 높은 명시적 도메인 규칙에 넣어 정상 작동이 확인된 아웃바운드로 보냅니다. 동작이 달라진 것을 확인한 뒤 원래 분류 규칙과 추가 조건을 하나씩 복원하세요. 명시적 규칙도 적용되지 않는다면 앱이 도메인을 전달하는지, 예상한 인바운드를 통과하는지, 현재 실행 설정을 보고 있는지 확인하세요. 이 상황에서 규칙 데이터베이스를 더 확대해도 근본 문제는 해결되지 않는 경우가 많습니다.

DNS를 진단할 때는 조회 경로와 연결 대상 주소를 함께 기록하세요. 도메인에서 주소를 얻었는데도 연결되지 않는다면 해당 주소 유형과 아웃바운드 연결을 확인하세요. 조회 자체가 실패할 때는 DNS 서비스와 기본 네트워크 경로를 중점적으로 살펴보세요. 브라우저의 오류 페이지만으로 문제 위치를 판단하지 마세요. 같은 시간 초과 메시지도 인바운드 포트, DNS 요청, 원격 인증, 대상 서비스 중 어느 단계에서든 발생할 수 있습니다. 로그의 시간 순서는 각 단계를 연결하는 데 중요한 단서입니다.

롤백과 재현 가능한 기록

테스트에 실패하면 가장 최근에 정상 작동했던 설정으로 복원하고 관련 코어를 다시 시작한 뒤 리스너와 시스템 프록시 상태가 일치하는지 확인하세요. TUN을 끌 때는 클라이언트 절차에 따라 가상 인터페이스와 시스템 라우팅이 복원됐는지도 확인해야 합니다. 클라이언트 자체가 시작되지 않으면 시작 직후 강제 종료 문제 해결을 참고해 실행 환경 문제와 코어 설정 문제를 먼저 구분하세요. 창이 열리지 않는다고 해서 반드시 JSON이 원인인 것은 아닙니다.

최종 설정에는 세 가지 질문에 답할 수 있어야 합니다. 앱이 어떤 인바운드로 들어오는가, 규칙이 왜 이 아웃바운드를 선택하는가, 도메인은 어디에서 조회되는가. 설명할 수 없는 필드는 장기 설정으로 남기지 마세요. 검증을 마친 뒤에는 일상 사용 가이드에서 연결과 모드를 관리하고, 설치 플랫폼을 바꿔야 할 때 클라이언트 다운로드 페이지를 이용하세요. 일상적인 사용과 설정 실험을 분리하면 이후 업데이트와 문제 복구가 쉬워집니다.