CONFIGURATION REFERENCE

V2Ray 설정 파일: JSON 필드와 라우팅 로직

최상위 구조부터 시작해 inbounds 인바운드, outbounds 아웃바운드, routing 라우팅, DNS 조회와 policy 정책을 항목별로 설명합니다. 예제는 Xray에서 자주 사용하는 필드를 중심으로 구성했으며, 클라이언트가 설정을 생성할 때 발생하는 덮어쓰기 관계도 함께 짚습니다.

  • JSON 구조 한눈에 보기
  • Xray 코어
  • V2Ray 라우팅 규칙
  • DNS 분기

목표가 구독을 가져오고 시스템 프록시를 활성화한 뒤 첫 연결을 완료하는 것이라면 먼저 시작 가이드를 읽어 보세요. 이 페이지에서는 클라이언트가 생성한 설정을 이해하고, 규칙 충돌을 찾으며, 장기간 재사용할 JSON 조각을 관리하는 방법을 다룹니다.

V2Ray와 Xray 설정 파일의 핵심 역할은 연결을 “애플리케이션이 보낸 로컬 요청”에서 “지정한 출구가 처리하는 네트워크 요청”으로 변환하는 것입니다. 설정은 서로 무관한 필드의 단순한 모음이 아니라 명확한 순서를 가진 데이터 경로입니다. 애플리케이션이 먼저 인바운드 수신 포트에 연결하면 코어가 대상 주소를 읽고 트래픽을 탐지합니다. 이어 라우팅 모듈이 도메인, IP, 포트 또는 인바운드 태그를 기준으로 아웃바운드를 선택하고, 필요할 때 DNS 모듈이 조회에 참여한 뒤 해당 아웃바운드가 연결을 수립합니다. 이 흐름을 이해하면 무작위로 보이는 장애도 어느 단계에서 필요한 정보를 얻지 못했는지 추적할 수 있습니다.

v2rayN은 Windows, macOS와 Linux 데스크톱에서 주로 사용하는 그래픽 클라이언트이며, v2rayNG와 v2flyNG는 각각 Android용입니다. 그래픽 클라이언트는 일반적으로 화면에서 선택한 항목을 바탕으로 실행 설정을 생성하므로, 임시 설정 파일을 직접 편집하면 다음 시작이나 서버 전환 때 덮어써질 수 있습니다. 장기적으로 유지할 설정은 클라이언트가 제공하는 라우팅, DNS, 매개변수 설정 또는 사용자 지정 설정 메뉴에서 관리하는 편이 좋습니다. 설치 패키지를 선택하려면 다운로드 페이지로 이동하고, 첫 연결만 완료하려면 먼저 빠른 시작 안내를 따라가세요.

01

JSON 구조 개요와 설정 로딩 순서

최상위 객체는 어떻게 함께 작동할까

전체 설정은 하나의 JSON 객체를 루트 노드로 사용합니다. 일반적인 최상위 필드에는 log, dns, inbounds, outbounds, routing, policy, stats가 있습니다. 인바운드와 아웃바운드는 연결 경로의 양 끝이고, 라우팅은 두 끝을 연결합니다. DNS는 도메인 매칭과 대상 조회에 필요한 결과를 제공하며, policy 모듈은 타임아웃·통계·사용자 등급별 동작을 제어합니다. log 필드는 실행 중 남길 진단 정보의 양을 결정합니다. 일부 선택 모듈은 생략할 수 있지만, 요청을 받을 인바운드와 요청을 처리할 아웃바운드는 최소한 필요합니다. 그렇지 않으면 코어가 시작되더라도 완전한 데이터 경로를 만들 수 없습니다.

배열 순서와 태그는 설정 동작에 함께 영향을 줍니다. 각 인바운드나 아웃바운드는 tag로 고정된 이름을 부여할 수 있으며, 라우팅 규칙은 inboundTag 또는 outboundTag로 이를 참조합니다. 태그는 설정 내부 식별자일 뿐 서버 이름이 아니며 프로토콜 자체를 바꾸지도 않습니다. socks-in, proxy, direct, block처럼 짧고 의미가 일정한 영어 태그를 권장합니다. 같은 범위에서 태그를 재사용하면 규칙이 최종적으로 어느 객체를 가리키는지 판단하기 어려워지고, 일부 구현에서는 로딩 자체가 거부될 수 있습니다.

{
  "log": {
    "loglevel": "warning"
  },
  "dns": {
    "servers": [
      "1.1.1.1",
      "localhost"
    ]
  },
  "inbounds": [
    {
      "tag": "socks-in",
      "listen": "127.0.0.1",
      "port": 10808,
      "protocol": "socks",
      "settings": {
        "udp": true
      }
    }
  ],
  "outbounds": [
    {
      "tag": "direct",
      "protocol": "freedom"
    },
    {
      "tag": "block",
      "protocol": "blackhole"
    }
  ],
  "routing": {
    "domainStrategy": "AsIs",
    "rules": [
      {
        "type": "field",
        "ip": ["geoip:private"],
        "outboundTag": "direct"
      }
    ]
  }
}

JSON 문법과 데이터 형식

JSON은 많은 설정 언어보다 형식 규칙이 엄격합니다. 객체는 중괄호, 배열은 대괄호를 사용하며 키 이름과 문자열은 영문 큰따옴표로 감싸야 합니다. 불리언 값은 소문자 true 또는 false만 사용할 수 있고 숫자에는 따옴표를 추가하면 안 됩니다. 객체의 마지막 필드와 배열의 마지막 요소 뒤에는 쉼표를 둘 수 없습니다. 표준 JSON은 주석도 허용하지 않으므로 실제로 불러올 설정 안에 설명을 직접 넣지 마세요. 메모가 필요하다면 별도 문서에 기록하거나 클라이언트가 제공하는 전용 메모 필드를 사용하세요. 코어가 인식하지 못하는 필드를 임의로 추가하면 무시될 수도 있고 엄격한 파싱 모드에서 오류가 발생할 수도 있습니다.

필드의 데이터 형식은 겉보기와 비슷하다는 이유만으로 바꾸면 안 됩니다. 예를 들어 포트는 일반적으로 숫자 10808이지 문자열 "10808"이 아닙니다. 도메인 목록은 항목이 하나뿐이어도 배열로 작성해야 하므로 ["domain:example.com"]처럼 써야 합니다. 반면 규칙의 port"53" 또는 "80,443,1000-2000"처럼 범위를 문자열로 표현하는 경우가 많습니다. 이런 차이는 통일된 문법이 아니라 각 필드 정의에서 비롯됩니다. 편집 전에 해당 필드가 숫자, 문자열, 불리언, 객체 또는 배열인지 확인해 JSON 파싱은 통과하지만 코어가 필드를 읽을 때 실패하는 상황을 피하세요.

설정 로딩 및 연결 처리 순서

코어는 설정을 불러올 때 먼저 JSON을 파싱하고 모듈을 초기화한 다음 인바운드 수신 주소를 바인딩합니다. 포트를 다른 프로그램이 사용 중이거나, 수신 주소가 로컬 컴퓨터에 없거나, 필드 형식이 잘못되면 시작 단계에서 중단됩니다. 시작에 성공했다는 것은 설정 구조와 로컬 리소스를 기본적으로 사용할 수 있다는 뜻일 뿐, 원격 프로토콜 매개변수가 올바르다는 의미는 아닙니다. 실제 원격 연결은 보통 애플리케이션 요청이 들어온 뒤에 수립되므로 “코어가 시작됨”과 “대상에 접속 가능함”은 서로 다른 점검 단계입니다.

요청이 들어오면 코어는 먼저 인바운드 태그, 대상 주소, 대상 포트와 네트워크 유형을 확인합니다. sniffing을 활성화한 경우 HTTP 요청이나 TLS 핸드셰이크에서 도메인을 식별할 수도 있습니다. 그다음 routing이 위에서 아래로 규칙을 검사하며, 일반적으로 처음으로 완전히 일치한 규칙이 출구를 결정합니다. 일치하는 규칙이 없으면 기본 아웃바운드를 사용하며, 기본값은 대개 아웃바운드 배열의 첫 항목이나 클라이언트 생성 로직과 관련됩니다. DNS가 개입하는지는 대상 조회가 필요한지와 domainStrategy 선택에 따라 달라집니다. 마지막으로 아웃바운드 모듈이 프로토콜, 전송 계층, 보안 계층과 서버 매개변수를 사용해 연결을 수립합니다. 문제를 해결할 때도 같은 순서로 확인하는 편이 옵션을 무작정 바꾸는 것보다 효과적입니다.

설정은 단일 책임을 유지하며 관리해야 합니다. 인바운드는 로컬 접속 방식만, 아웃바운드는 출구 기능만, 라우팅은 선택 조건만, DNS는 조회 경로만, policy는 연결 수명과 통계만 설명하도록 구성하세요. 여러 목적을 하나의 규칙에 섞으면 단기적으로 줄 수는 줄어들지만 장기적으로 규칙 덮어쓰기와 회귀 테스트가 어려워집니다. 한 번에 하나의 모듈만 수정하고, 저장 전에 JSON 문법을 확인하며, 시작 후 warning 또는 info 로그를 확인하세요. 그런 다음 명확한 도메인·IP·포트 시나리오를 하나씩 테스트하는 것이 좋습니다.

02

inbounds 인바운드: 수신 주소, 포트와 트래픽 탐지

인바운드는 무엇을 받을까

inbounds는 인바운드 객체 배열이며 각 객체가 하나의 로컬 접속 방식을 설명합니다. 데스크톱 클라이언트에서 가장 흔한 것은 SOCKS 인바운드와 HTTP 인바운드입니다. SOCKS를 지원하는 애플리케이션은 SOCKS 포트에 연결하고, HTTP 프록시만 지원하는 애플리케이션은 HTTP 포트에 연결합니다. 시스템 프록시 모드에서는 보통 클라이언트가 운영체제의 프록시 설정을 로컬 포트 중 하나로 지정합니다. 투명 프록시, 가상 네트워크 카드 또는 리디렉션 인바운드는 추가적인 플랫폼 권한과 네트워크 스택 설정이 필요하므로 일반적인 로컬 프록시 포트와 혼동해서는 안 됩니다.

listen은 어느 로컬 주소에서 수신할지 결정합니다. 127.0.0.1로 설정하면 로컬 컴퓨터의 연결만 받으므로 개인용 데스크톱 환경에서 흔히 사용됩니다. 0.0.0.0으로 설정하면 사용 가능한 모든 IPv4 인터페이스에서 수신하므로 같은 네트워크의 다른 기기가 해당 포트에 접근할 수 있습니다. v2rayN의 “LAN 연결 허용”과 같은 옵션은 본질적으로 수신 범위와 관련 방화벽 조건에 영향을 줍니다. 같은 네트워크의 다른 기기에 명확히 접속점을 제공해야 할 때만 수신 범위를 넓히고, 운영체제 방화벽과 네트워크 환경도 함께 확인하세요.

port는 로컬 컴퓨터에서 사용 중이지 않은 유효한 포트여야 합니다. 로컬 SOCKS 수신 포트로 10808을 자주 사용하지만 프로토콜이 강제하는 값은 아니므로 환경에 맞게 변경할 수 있습니다. 변경 후에는 브라우저, 개발 도구, 시스템 프록시와 기타 호출자도 함께 수정해야 합니다. 코어의 포트만 바꾸고 애플리케이션 설정을 바꾸지 않으면 애플리케이션이 로컬 프록시에 연결하지 못합니다. 여러 인바운드는 같은 주소의 같은 포트에 바인딩할 수 없으며 프로토콜이 달라도 충돌합니다.

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

SOCKS, HTTP와 UDP 동작

SOCKS 인바운드의 settings.udp는 UDP 요청을 받을지 결정합니다. 활성화했다고 해서 모든 애플리케이션이 자동으로 UDP를 사용하는 것은 아니며, 해당 아웃바운드와 원격 프로토콜이 모든 UDP 상황을 처리한다는 보장도 없습니다. 애플리케이션은 호환되는 방식으로 UDP 요청을 SOCKS 인바운드에 전달해야 하고, 라우팅 규칙도 이를 적합하지 않은 출구로 보내지 않아야 합니다. “웹페이지는 정상인데 일부 실시간 애플리케이션만 이상함”을 점검할 때는 애플리케이션 접속 방식, 인바운드 UDP 옵션, 라우팅 네트워크 조건과 아웃바운드 프로토콜의 지원 범위를 각각 확인해야 합니다.

HTTP 인바운드는 주로 HTTP 프록시 요청과 CONNECT 메서드로 수립되는 HTTPS 터널을 받습니다. 일반 웹 서버가 아니며 해당 포트로 들어오는 임의의 프로토콜을 자동 처리하지도 않습니다. 일부 애플리케이션은 시스템 HTTP 프록시 설정만 읽고, 일부는 별도의 SOCKS 설정을 지원하며, 시스템 프록시를 완전히 무시하는 애플리케이션도 있습니다. 인바운드를 구성할 때는 수신 포트를 많이 추가하기보다 호출자가 실제로 어떤 접속 방식을 지원하는지 먼저 확인하세요. 포트가 많아질수록 포트 점유, 규칙 출처와 방화벽 동작을 추적하기가 복잡해집니다.

수신 주소를 로컬 네트워크로 확대할 때는 인바운드 설정에서 인증을 고려할 수 있지만, 인증 기능은 구체적인 인바운드 프로토콜과 클라이언트 생성 방식에 따라 달라집니다. 더 안전한 방법은 먼저 네트워크 경계를 제한하고 관리되는 기기만 접근하도록 하며, 로컬 프록시 포트를 신뢰할 수 없는 네트워크에 노출하지 않는 것입니다. 로컬 컴퓨터에서만 사용할 경우 루프백 주소로 충분한 경우가 많습니다. Windows, macOS와 Linux는 방화벽 안내와 네트워크 권한 표시 방식이 다르지만 판단 원칙은 같습니다. 먼저 코어가 예상한 주소를 실제로 수신 중인지 확인한 뒤, 접속 기기가 해당 주소와 포트에 도달할 수 있는지 확인하세요.

sniffing으로 라우팅 보완하기

트래픽 탐지 sniffing은 연결 내용에서 대상 도메인을 식별하는 기능입니다. 대표적인 식별 정보로는 HTTP Host, TLS Server Name, QUIC에서 확인 가능한 대상 정보가 있습니다. 애플리케이션이 먼저 도메인을 IP로 조회한 뒤 순수 IP 대상을 프록시에 전달하는 경우, 라우팅은 IP만 보게 되어 geosite나 도메인 접미사 규칙이 일치하지 않을 수 있습니다. 탐지를 활성화하면 코어가 식별한 도메인을 라우팅에 활용할 수 있어 도메인 규칙에 더 안정적인 입력을 제공할 수 있습니다.

destOverride는 어떤 프로토콜 특징에서 대상 정보를 덮어쓰거나 보완할지 지정하며, 흔히 http, tls, quic을 사용합니다. routeOnlytrue이면 탐지 결과를 주로 라우팅 판단에만 사용하고 최종 연결 대상을 직접 바꾸지 않으므로 대상 교체에 따른 부작용을 줄이는 데 도움이 됩니다. 이 옵션의 사용 여부는 실제 규칙 설계에 맞춰 결정하세요. IP 규칙만 사용한다면 탐지 효과가 제한적이고, geosite·전체 도메인·접미사 규칙을 많이 사용한다면 탐지의 가치가 커집니다.

탐지는 범용 복호화 기능이 아니며 모든 연결을 식별할 수 있는 것도 아닙니다. 암호화된 애플리케이션 프로토콜, 비표준 핸드셰이크, IP 직접 접속 또는 미리 수립된 다중화 연결에서는 사용할 수 있는 도메인이 제공되지 않을 수 있습니다. 모든 연결에서 반드시 탐지 도메인을 얻는다고 가정하지 말고 합리적인 IP 규칙과 기본 출구를 남겨 두세요. 도메인 규칙이 간헐적으로 일치하지 않는다면 로그 수준을 잠시 info로 바꾸고 애플리케이션의 원래 대상, 탐지 결과와 최종 아웃바운드 태그를 비교하세요. 진단이 끝나면 warning으로 되돌려 로그가 불필요하게 쌓이지 않도록 합니다.

여러 인바운드는 서로 다른 태그와 라우팅을 조합해 분기할 수도 있습니다. 예를 들어 브라우저를 browser-in에, 개발 도구를 dev-in에 연결한 뒤 inboundTag로 두 요청 유형에 서로 다른 출구를 지정할 수 있습니다. 이 방식은 프로세스 이름으로 매칭하는 것보다 여러 플랫폼에서 재사용하기 쉽지만, 각 애플리케이션이 독립 프록시 포트를 설정할 수 있어야 합니다. v2rayN의 시스템 프록시 모드를 사용한다면 보통 클라이언트가 생성한 표준 인바운드만 유지하면 됩니다. 명확한 격리 목적이 있을 때만 사용자 지정 접속점을 추가하세요.

03

outbounds 아웃바운드: 프로토콜 매개변수, 태그와 전송 계층

아웃바운드 배열과 기본 출구

outbounds는 연결이 코어를 빠져나갈 때 사용할 처리 방식을 설명합니다. 프록시 프로토콜 아웃바운드는 원격 서버에 연결하고, freedom 아웃바운드는 대상에 직접 접속하며, blackhole 아웃바운드는 일치한 연결을 종료합니다. 실무에서는 보통 proxy, direct, block처럼 의미가 분명한 태그를 최소한 유지해 프록시·직접 연결·차단을 라우팅 규칙에서 구분합니다. 태그 이름은 직접 정할 수 있지만 규칙의 outboundTag와는 대소문자까지 완전히 일치해야 합니다.

라우팅 규칙에 일치하지 않았을 때 어느 출구를 사용할지는 코어의 동작과 클라이언트가 설정을 생성하는 방식을 함께 확인해야 합니다. 많은 설정은 주 프록시 아웃바운드를 배열 첫 번째에 두어 미일치 트래픽의 기본 경로로 사용하고, 일부 클라이언트는 별도의 대체 규칙을 생성합니다. 실제 실행 설정을 볼 때는 화면에 표시된 서버만 확인하지 말고 아웃바운드 순서와 라우팅 끝에 catch-all 규칙이 있는지도 살펴보세요. 동작을 명확히 하려면 규칙 끝에 네트워크 범위를 충분히 포함하는 기본 조건을 둘 수 있지만, 지나치게 넓은 규칙이 모든 트래픽을 먼저 가로채지 않도록 주의해야 합니다.

{
  "outbounds": [
    {
      "tag": "proxy",
      "protocol": "vless",
      "settings": {
        "vnext": [
          {
            "address": "server.example.com",
            "port": 443,
            "users": [
              {
                "id": "11111111-1111-4111-8111-111111111111",
                "encryption": "none",
                "flow": "xtls-rprx-vision"
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "tcp",
        "security": "reality",
        "realitySettings": {
          "serverName": "www.example.com",
          "fingerprint": "chrome",
          "publicKey": "dGVzdC1wdWJsaWMta2V5LWZvci1kb2N1bWVudA",
          "shortId": "0123456789abcdef",
          "spiderX": "/"
        }
      }
    },
    {
      "tag": "direct",
      "protocol": "freedom",
      "settings": {
        "domainStrategy": "UseIP"
      }
    },
    {
      "tag": "block",
      "protocol": "blackhole",
      "settings": {
        "response": {
          "type": "none"
        }
      }
    }
  ]
}

위 프록시 매개변수에는 문서 예시용 주소와 자격 증명이 사용되었으며 실제 연결을 만들 수 없습니다. 실제 설정에서는 주소, 포트, 사용자 식별자, 전송 방식과 보안 계층 매개변수를 하나의 묶음으로 일치시켜야 합니다. 구독을 가져오면 보통 이 필드가 자동 생성됩니다. 직접 수정할 때는 프로토콜 이름만 보고 단일 값만 바꾸지 마세요. 같은 프로토콜도 TCP, WebSocket, gRPC, TLS, REALITY와 서로 다른 흐름 제어 방식을 조합할 수 있습니다.

protocol 설정과 streamSettings의 역할 분담

protocol은 애플리케이션 계층의 프록시 프로토콜을 결정하고, settings에는 해당 프로토콜에 필요한 서버와 사용자 정보가 저장됩니다. streamSettings는 하위 전송 네트워크와 보안 계층을 설명합니다. VLESS를 예로 들면 서버 주소·포트·사용자 식별자는 settings.vnext에, TCP·WebSocket·gRPC는 streamSettings.network에, TLS·REALITY는 streamSettings.security에 있습니다. 이 계층들은 서로 연관되지만 위치를 바꿔 쓸 수는 없습니다.

VMess, VLESS, Trojan과 Shadowsocks는 사용자 필드 구조가 서로 다릅니다. VMess에는 보통 id와 보안 설정이 포함되고, VLESS는 id와 encryption을 사용하며 flow를 함께 지정할 수 있습니다. Trojan은 비밀번호를 사용하고, Shadowsocks는 암호화 방식과 비밀번호를 사용합니다. 클라이언트 구독은 수동 입력 오류를 줄여 주지만, 가져온 뒤에도 프로토콜, 전송 유형, TLS 서버 이름과 포트가 모두 입력되었는지 확인해야 합니다. 구독 업데이트가 실패하거나 공유 링크 형식이 이상하다면 구독 업데이트 실패 자가 점검 목록을 참고해 항목별로 확인하세요.

mux 다중화는 여러 논리 연결이 더 적은 수의 하위 연결을 공유하도록 합니다. 어떤 환경에서나 켜면 속도가 빨라지는 스위치는 아니며, 효과는 프로토콜·전송 방식·서버 설정과 업무 유형에 따라 달라집니다. 일부 장시간 연결이나 순서에 민감한 요청에는 추가 다중화가 적합하지 않을 수 있습니다. 연결 수립은 정상인데 지속적인 전송이 불안정하다면 프로토콜·보안 계층·라우팅을 동시에 바꾸지 말고 Mux만 끄는 방식으로 독립 테스트를 진행하세요.

direct, block과 출구 제약

freedom 아웃바운드는 대상에 직접 연결하며, 사설 주소·로컬 네트워크 도메인 또는 로컬 네트워크에서 처리해야 하는 요청에 주로 사용합니다. 그래도 로컬 DNS, 네트워크 라우팅과 방화벽의 영향을 받으므로 “direct”는 프록시 프로토콜을 거치지 않는다는 뜻일 뿐 대상에 반드시 도달할 수 있다는 의미는 아닙니다. settings.domainStrategy는 freedom이 도메인을 만났을 때 조회를 처리하는 방법을 제어하므로, 최상위 DNS와 routing의 도메인 정책을 함께 고려해 단계마다 결과가 달라지지 않도록 해야 합니다.

blackhole은 대상에 정상적인 연결을 수립하지 않으며, 차단할 도메인·IP·포트에 적합합니다. 차단 규칙은 가능한 한 구체적으로 작성하고 우선 실행할 위치에 배치하세요. 지나치게 넓은 조건은 업데이트·로그인·로컬 네트워크 서비스가 시간 초과되는 원인이 될 수 있습니다. 문제를 확인할 때는 의심스러운 규칙의 출구를 잠시 direct 또는 별도 태그로 바꿔 규칙이 원인인지 확인한 뒤 원래 동작으로 되돌리세요.

일부 설정은 sendThrough로 아웃바운드 연결이 특정 로컬 주소에서 나가도록 지정하거나 sockopt로 하위 소켓 옵션을 조정합니다. 이런 필드는 여러 네트워크 카드, 특정 라우팅 테이블 또는 고급 네트워크 환경에 적합하며 일반적인 연결 장애를 해결할 때 가장 먼저 사용할 방법은 아닙니다. 주소가 로컬 인터페이스에 할당되어 있지 않으면 아웃바운드가 즉시 실패합니다. 데스크톱에서는 먼저 클라이언트 기본값을 유지하고, 대상 네트워크 카드·주소 계열·라우팅 요구를 명확히 설명할 수 있을 때만 바인딩을 추가하세요.

아웃바운드 역할 자주 사용하는 protocol 주요 용도 주요 확인 항목
프록시 출구 vless、vmess、trojan、shadowsocks 원격 프로토콜에 따라 연결 수립 주소·포트·사용자 매개변수·전송 및 보안 계층이 일치하는가
직접 연결 freedom 로컬 네트워크로 대상에 접속 로컬 DNS, 기본 라우팅, 방화벽과 주소 계열
연결 차단 blackhole 규칙에 일치한 요청 종료 규칙 범위와 순서가 지나치게 넓지 않은가

아웃바운드를 관리할 때는 태그를 안정적으로 유지하는 것이 우선입니다. 라우팅 규칙은 배열 위치가 아니라 태그를 참조하므로, 안정적인 태그를 사용하면 서버 매개변수 업데이트와 라우팅 정책을 분리할 수 있습니다. 구독 노드를 전환하면 클라이언트가 프록시 아웃바운드를 다시 만들 수 있지만 direct와 block의 의미는 보통 바뀌지 않습니다. 사용자 지정 설정에서 클라이언트가 이름을 바꿀 수 있는 내부 태그를 참조한다면 업데이트할 때마다 실제 생성 결과를 확인해 규칙이 존재하지 않는 출구를 가리키지 않도록 하세요.

04

routing 라우팅 규칙: 매칭 순서, 도메인과 IP 분기

규칙은 순서대로 매칭됩니다

routing.rules는 라우팅 규칙 배열입니다. 흔히 사용하는 규칙 유형은 field이며 도메인, IP, 포트, 네트워크 유형, 인바운드 태그, 프로토콜과 사용자 등의 조건을 조합할 수 있습니다. 규칙은 위에서 아래로 검사하므로 더 구체적이고 우선순위가 높은 조건을 앞에, 범위가 넓은 규칙을 뒤에 배치해야 합니다. 하나의 규칙이 일치하면 보통 뒤에 있는 대체 규칙을 계속 찾지 않으므로 순서 자체가 정책의 일부입니다.

하나의 field 규칙 안에서 서로 다른 조건은 보통 “모두 충족” 관계를 이룹니다. 예를 들어 domainport를 함께 작성하면 도메인과 포트 조건을 모두 만족할 때 해당 출구를 사용한다는 뜻입니다. 같은 배열 안의 여러 도메인 값은 보통 “하나라도 일치”하는 관계입니다. 서로 무관한 조건을 한 규칙에 넣으면 각각 독립적으로 작동한다고 오해하기 쉽습니다. 업무 목적에 따라 규칙을 나누고, 각 규칙에는 설명 가능한 하나의 일치 이유만 남기는 편이 명확합니다.

{
  "routing": {
    "domainStrategy": "IPIfNonMatch",
    "domainMatcher": "hybrid",
    "rules": [
      {
        "type": "field",
        "ip": ["geoip:private"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "domain": [
          "geosite:cn",
          "domain:example.cn",
          "full:service.example.cn"
        ],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "ip": ["geoip:cn"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "domain": ["geosite:category-ads-all"],
        "outboundTag": "block"
      },
      {
        "type": "field",
        "network": "tcp,udp",
        "outboundTag": "proxy"
      }
    ]
  }
}

이 예제는 먼저 사설 IP를 처리한 뒤 지정 도메인과 지역 도메인, 지역 IP를 차례로 처리합니다. 이어 특정 분류를 차단하고, 마지막으로 남은 TCP와 UDP 요청을 proxy로 보냅니다. 실제 사용에서는 차단 규칙을 지역 직결보다 앞에 둘지 여부가 분류 데이터와 대상 정책에 따라 달라집니다. 한 도메인이 두 집합에 동시에 속한다면 더 앞에 있는 규칙이 제어권을 가집니다. 규칙 순서를 바꾸기 전에 규칙 이름만 보지 말고 겹칠 수 있는 집합을 먼저 나열하세요.

domainStrategy는 언제 조회할지 결정합니다

domainStrategy는 도메인 규칙으로 바로 결과를 얻지 못했을 때 라우팅 모듈이 도메인을 IP로 조회해 IP 규칙을 다시 시도할지 제어합니다. AsIs는 일반적으로 현재 가진 대상 형식만 사용하므로 도메인 대상이 IP 규칙과 일치하도록 적극적으로 조회하지 않습니다. IPIfNonMatch는 먼저 도메인 규칙을 시도하고, 일치하지 않으면 IP를 조회한 뒤 IP 규칙을 확인합니다. IPOnDemand는 라우팅 중 IP 결과를 더 적극적으로 준비합니다. 구체적인 동작은 코어 구현과 설정 조합의 영향도 받지만 원칙은 분명합니다. 도메인 대상이 geoip 또는 CIDR 규칙에 참여해야 할 때만 라우팅 단계에서 조회를 도입하면 됩니다.

조회에는 비용이 따릅니다. DNS 요청이 늘어나고 조회 서버·캐시·주소 계열에 따라 라우팅 결과가 달라질 수 있습니다. 중요한 대상이 모두 geosite, 전체 도메인 또는 접미사 규칙으로 처리된다면 AsIs가 이해하기 쉽습니다. 도메인 대상에 geoip:cn이나 사용자 지정 CIDR을 적용해야 한다면 IPIfNonMatch가 보통 더 적합합니다. 특정 템플릿이 그 값을 사용한다는 이유만으로 복사하지 말고, 규칙에 IP 조건이 있는지와 애플리케이션이 도메인을 제출하는지를 기준으로 선택하세요.

sniffing을 활성화하면 라우팅이 트래픽에서 식별한 도메인을 얻을 수 있습니다. 활성화하지 않은 상태에서 애플리케이션이 IP를 제출하면 도메인 규칙에 매칭할 대상이 없습니다. 반대로 애플리케이션이 도메인을 제출할 때 IP 규칙을 적용할지는 domainStrategy에 달려 있습니다. 따라서 인바운드 탐지, 라우팅 도메인 정책과 DNS는 서로 독립적인 세 개의 스위치가 아닙니다. 규칙을 점검할 때는 요청이 처음부터 도메인이었는지 IP였는지, 탐지로 도메인을 얻었는지, 라우팅이 조회를 실행했는지, 최종적으로 어떤 IP를 받았는지를 기록해야 합니다.

도메인·IP·포트·태그 조건

도메인 규칙에는 full:, domain:, regexp:, geosite: 같은 표기가 자주 사용됩니다. full:example.com은 완전한 도메인만 일치시키고, domain:example.com은 해당 도메인과 하위 도메인을 포함할 수 있습니다. 정규 표현식은 더 유연하지만 복잡할수록 가독성이 떨어지고 의도하지 않은 매칭이 발생하기 쉽습니다. geosite는 분류 데이터 집합을 사용하므로 범위가 큰 규칙을 관리하는 데 적합합니다. 하나의 명확한 사이트에는 full 또는 domain을 우선 사용하고, 집합 규모가 클 때만 분류 데이터를 사용하세요.

IP 규칙은 192.168.0.0/16 같은 CIDR로 작성하거나 geoip:private와 같은 데이터 집합을 참조할 수 있습니다. 사설 주소 규칙은 보통 앞쪽에서 direct로 처리해야 합니다. 그렇지 않으면 로컬 네트워크 관리 페이지, 파일 서비스와 로컬 개발 환경이 프록시 출구로 전송될 수 있습니다. 도메인이 사설 주소로 조회되었을 때 이 규칙에 일치하는지는 라우팅이 조회를 실행했는지에 달려 있습니다. private 규칙 하나만 추가한다고 모든 로컬 네트워크 도메인 문제가 자동으로 해결되지는 않습니다.

port는 단일 포트, 쉼표로 구분한 목록과 범위를 지원하며, network에는 보통 tcp, udp 또는 두 값을 함께 사용합니다. 포트는 연결 대상 포트만 나타내며 애플리케이션 종류와 같은 의미는 아닙니다. 많은 서비스가 443을 공유하므로 포트만으로는 도메인을 판단할 수 없습니다. 53도 다양한 형태의 DNS 요청을 전달할 수 있습니다. 포트 규칙은 명확한 네트워크 정책을 표현할 때 적합하고 도메인 식별을 대신할 수는 없습니다.

inboundTag로 요청이 어느 인바운드에서 왔는지에 따라 분기할 수 있어 여러 로컬 포트를 격리할 때 유용합니다. protocol 조건은 코어의 식별 결과에 의존하며, 예를 들어 탐지 후 특정 프로토콜로 인식된 경우에 사용할 수 있습니다. 이런 고급 조건을 사용할 때는 인식하지 못한 트래픽에도 명확한 출구가 있도록 끝에 기본 규칙을 남겨 두세요. 라우팅을 수정한 뒤에는 사설 IP, 명확한 직결 도메인, 명확한 프록시 도메인, 일반 미분류 도메인과 UDP 요청을 최소 한 번씩 테스트하고 실제 아웃바운드 태그를 확인해야 합니다.

v2rayN의 라우팅 설정 화면은 보통 프리셋, 규칙 집합과 현재 프록시 모드를 조합해 최종 설정을 만듭니다. 화면에서 “전체”나 다른 모드를 선택하면 기본 출구가 바뀌거나 추가 규칙이 생성될 수 있으므로, 수동 설정 조각과 클라이언트 모드를 함께 확인해야 합니다. 프로토콜별 특성과 라우팅 상황의 선택 기준을 이해하려면 VMess, VLESS, Trojan, Shadowsocks 프로토콜 비교도 읽어 보세요.

05

DNS 설정: 조회 서버, 매칭 도메인과 주소 계열

내장 DNS와 시스템 DNS의 경계

최상위 dns 모듈은 코어가 수행해야 하는 도메인 조회를 위해 서버, 정적 매핑과 조회 정책을 제공합니다. 기기의 모든 DNS 요청을 자동으로 가로채는 기능은 아닙니다. 코어 처리 경로로 들어오거나, 라우팅 모듈이 조회를 요청하거나, 특정 DNS 인바운드가 코어에 전달한 조회만 이 설정을 사용합니다. 애플리케이션이 외부 조회 서버에 직접 연결하거나, 브라우저가 별도의 보안 DNS를 사용하거나, 요청이 프록시를 완전히 우회하면 최상위 dns 설정이 적용되지 않을 수 있습니다.

이 구분은 문제 해결에 매우 중요합니다. 어떤 도메인의 조회 결과가 예상과 다르다면 먼저 누가 조회를 시작했는지 확인하세요. 운영체제 해석기인지, 애플리케이션 자체 해석기인지, Xray 내장 DNS인지 구분해야 합니다. 시스템 DNS, 브라우저 설정, 코어 서버 목록과 라우팅 규칙을 동시에 수정하면 결과가 바뀌어도 어느 계층이 영향을 주었는지 알 수 없습니다. 먼저 애플리케이션의 독립 조회 기능을 끄고 비교한 뒤 로그에서 코어가 실제로 조회를 보냈는지 확인하는 방법이 좋습니다.

{
  "dns": {
    "hosts": {
      "domain:internal.example": "192.168.10.20",
      "full:router.example": "192.168.1.1"
    },
    "servers": [
      {
        "address": "1.1.1.1",
        "port": 53,
        "domains": [
          "geosite:geolocation-!cn"
        ],
        "skipFallback": true
      },
      {
        "address": "223.5.5.5",
        "port": 53,
        "domains": [
          "geosite:cn"
        ],
        "expectIPs": [
          "geoip:cn"
        ]
      },
      "localhost"
    ],
    "queryStrategy": "UseIP",
    "disableCache": false,
    "disableFallback": false,
    "disableFallbackIfMatch": true
  }
}

예제는 domains로 조회 서버의 적용 범위를 제한하고, 후속 선택지로 localhost를 남겨 둡니다. 공용 조회 주소, 시스템 해석기 또는 다른 전송 방식이 필요한지는 현재 네트워크와 대상 환경에 따라 결정해야 합니다. 서버 순서, 매칭 도메인과 fallback 옵션이 최종 선택에 함께 영향을 주므로 servers를 단순히 순서대로 순회하는 목록으로 이해하면 안 됩니다.

servers, hosts와 조회 정책

servers에는 문자열 형식과 객체 형식을 모두 사용할 수 있습니다. 객체 형식은 포트, 매칭 도메인, 기대 IP 범위와 fallback 동작을 추가로 지정할 수 있습니다. domains는 어떤 도메인을 해당 서버가 우선 처리할지 지정하며 표기법은 라우팅 도메인 규칙과 비슷합니다. expectIPs는 반환 주소가 예상 범위에 맞는지 판단하는 조건이며, 임의의 주소를 특정 지역으로 강제 변환하는 기능은 아닙니다. 설정이 잘못되면 정상적인 결과도 거부되어 후속 조회가 실행될 수 있습니다.

hosts는 정적 도메인 매핑을 제공하며 고정된 로컬 네트워크 서비스나 명확한 테스트 대상에 적합합니다. 대형 hosts 파일을 대신하는 기능은 아니므로 항목이 많아질수록 관리 비용이 커집니다. 완전한 도메인에는 full:을 사용하고, 하위 도메인까지 포함할 때는 domain:을 사용하세요. 사설 주소로 매핑한 뒤에는 routing의 private 규칙이 연결을 direct로 보낼 수 있는지도 확인해야 합니다. 조회가 올바르더라도 출구 선택은 예상과 다를 수 있습니다.

queryStrategy는 어떤 주소 계열의 결과를 사용할지 제어합니다. 흔히 IPv4와 IPv6를 모두 허용하거나 IPv4만 또는 IPv6만 사용하는 전략이 있으며, 정확한 이름은 현재 코어가 지원하는 필드 정의를 따라야 합니다. 한 주소 계열만 선택하기 전에 로컬 네트워크와 원격 서비스가 실제로 해당 경로를 지원하는지 확인하세요. 로컬 컴퓨터에 IPv6 주소가 있어도 출구가 불안정하면 도메인이 IPv6를 우선 반환한 뒤 연결이 실패할 수 있습니다. 반대로 IPv4를 강제하면 IPv6만 제공하는 대상에 접근할 수 없습니다. 기기에 특정 주소가 표시되는지만 보지 말고 조회 결과와 실제 라우팅을 따로 테스트하는 것이 안전합니다.

fallback, 캐시와 라우팅의 순환 구조

fallback은 우선 조회 결과가 조건을 만족하지 않거나 결과가 없을 때 다른 서버를 시도하는 기능입니다. skipFallback은 특정 서버를 일반 fallback에서 제외하고, disableFallback은 fallback을 전체적으로 끄며, disableFallbackIfMatch는 도메인이 특정 서버와 일치했을 때 추가 fallback을 제한합니다. 여러 옵션을 겹쳐 쓰면 “서버를 설정했지만 한 번도 호출되지 않는” 상황이 생기기 쉬우므로 최소 설정부터 시작하세요. 먼저 단일 서버가 작동하는지 확인한 뒤 도메인 범위와 fallback 제한을 추가하는 방식이 좋습니다.

캐시는 반복 조회를 줄여 주지만 설정을 바꾼 뒤에도 결과가 잠시 즉시 변하지 않게 할 수 있습니다. disableCache는 단기 진단에 적합하며, 한 번 오래된 결과가 나왔다고 장기간 캐시를 끄는 것은 권장하지 않습니다. 문제를 해결할 때는 운영체제와 애플리케이션 자체 캐시도 고려해야 하며, 이들은 코어 캐시와 별개입니다. 코어를 재시작해도 브라우저나 시스템의 조회 캐시까지 반드시 지워지는 것은 아닙니다.

DNS와 라우팅은 순환 구조를 만들 수 있습니다. 라우팅이 IP 규칙과 매칭하기 위해 DNS 조회를 시작할 수 있고, DNS 서버로 연결하는 과정에도 라우팅이 적용되기 때문입니다. 조회 서버 주소가 도메인이라면 연결을 위해 그 도메인을 먼저 조회해야 하므로 의존성이 지나치게 길어지거나 순환할 수 있습니다. 기본 조회 서버에는 명확한 주소를 우선 사용하거나, 해당 서버의 도메인이 시스템 해석기로 안정적으로 조회되도록 하세요. DNS 조회를 특정 출구로 보내려면 태그와 규칙을 명확히 구성하고, 그 규칙이 같은 조회 경로를 다시 호출하지 않도록 해야 합니다.

대표적인 문제는 “도메인 규칙은 맞아 보이는데 최종적으로 잘못된 출구로 간다”는 것입니다. 점검 순서는 다음과 같습니다. 애플리케이션이 도메인과 IP 중 무엇을 제출했는지, sniffing이 도메인을 식별했는지, 도메인 규칙이 먼저 일치했는지, domainStrategy가 조회를 실행했는지, DNS가 어느 서버를 사용했는지, IPv4·IPv6 중 무엇을 반환했는지, IP 규칙이 그 결과를 포함하는지, 최종 아웃바운드 태그가 무엇인지 확인하세요. 이 흐름을 항목별로 기록하면 문제는 대개 하나의 명확한 단계로 좁혀집니다.

필드 역할 적합한 상황 흔한 오해
hosts 정적 도메인 매핑 제공 로컬 네트워크 서비스와 고정 테스트 대상 모든 애플리케이션의 시스템 조회를 바꾼다고 생각함
domains 조회 서버의 매칭 도메인 제한 도메인 집합에 따라 조회 경로 선택 서버 순서와 fallback 조건을 무시함
expectIPs 범위에 맞는 조회 결과 필터링 반환 주소를 범위 기준으로 판단해야 할 때 고정 주소 매핑으로 오해함
queryStrategy 조회에 사용할 주소 계열 제어 IPv4와 IPv6 경로 차이 처리 네트워크 지원 여부를 확인하지 않고 하나의 주소 계열을 강제함

v2rayNG와 v2flyNG는 Android 네트워크 환경에서 실행되며, 시스템의 비공개 DNS, 애플리케이션 내부 조회와 클라이언트 코어 DNS가 동시에 존재할 수 있습니다. 점검 방법은 데스크톱과 같습니다. 먼저 요청 경로를 명확히 한 다음 어느 계층이 조회를 담당하는지 확인하세요. 시스템 설정의 DNS 옵션과 설정 파일 최상위 dns 필드를 같은 스위치로 보면 안 됩니다.

06

policy 정책: 연결 타임아웃, 사용자 등급과 통계

level 정책은 사용자와 어떻게 연결될까

policy는 연결 수명, 사용자 등급과 시스템 통계 동작을 설정합니다. 서버를 선택하거나 라우팅 출구를 바꾸는 기능은 아닙니다. levels 객체는 등급 숫자를 키로 사용하며, 각 등급에 핸드셰이크 타임아웃, 유휴 타임아웃, 상·하행 중 한 방향만 활동할 때 연결을 유지하는 시간과 사용자 트래픽 통계 옵션을 설정할 수 있습니다. 프로토콜 사용자 항목의 level은 여기의 등급 키와 연결되며, 사용자가 명시하지 않으면 보통 기본 등급이 적용됩니다.

등급은 서비스 품질 점수가 아니며 대역폭 우선순위를 자동으로 제공하지도 않습니다. 해당 사용자에게 일련의 정책 매개변수를 적용하는 식별자일 뿐입니다. 데스크톱 클라이언트가 단일 사용자 도구로 사용되는 경우 흔히 등급 0만 있으면 충분합니다. 서버에서 여러 사용자를 관리한다면 사용자별로 다른 등급을 할당할 수 있지만, 이 페이지의 초점은 클라이언트 실행 설정입니다. 실제 사용자 객체가 참조하는지 확인하지 않고 “성능 최적화”를 위해 등급을 많이 추가하지 마세요.

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

수치의 단위와 허용 범위는 현재 코어의 필드 정의를 따라야 합니다. 예제는 일반적인 구조를 보여 줄 뿐 모든 네트워크에 같은 타임아웃이 적합하다는 뜻은 아닙니다. 핸드셰이크 시간이 너무 짧으면 지연이 큰 네트워크에서 연결이 완료되기 전에 종료되고, 너무 길면 실패한 연결이 자원을 오래 점유합니다. 유휴 타임아웃도 “길수록 안정적”이라고만 볼 수 없습니다. 활동이 없는 연결을 많이 유지하면 리소스 사용량이 증가합니다.

핸드셰이크·유휴·단방향 연결 타임아웃

handshake는 연결 수립 단계에서 기다릴 수 있는 시간을 제어합니다. 원격 대상에 도달할 수 없거나, 도메인 조회가 느리거나, 보안 계층 매개변수가 일치하지 않으면 이 시간이 소모될 수 있습니다. 로그에 핸드셰이크 타임아웃이 계속 나타난다면 수치를 크게 늘리기 전에 주소·포트·전송 방식과 네트워크 도달 가능성을 먼저 확인하세요. 연결이 최종적으로 성공하지만 경로가 느리다는 사실을 확인한 경우에만 적절히 늘리는 것이 좋습니다.

connIdle은 상·하행 활동이 없을 때 연결을 얼마나 유지할지 제어합니다. 일반적인 웹 단기 연결에는 긴 유휴 시간이 필요하지 않지만 메시지 동기화, 원격 터미널이나 롱 폴링은 일정 시간 동안 눈에 띄는 트래픽이 없을 수 있습니다. 특정 애플리케이션이 일정한 유휴 시간 뒤 항상 끊긴다면 애플리케이션의 하트비트 간격과 connIdle을 비교하세요. 원격 서버, 전송 계층과 중간 네트워크 장비도 연결을 닫을 수 있으므로 함께 확인해야 합니다.

uplinkOnlydownlinkOnly는 한 방향의 활동만 남은 상황을 처리합니다. 한 방향이 끝나면 코어가 전체 연결을 즉시 닫지 않고 다른 방향의 완료를 기다립니다. 값이 너무 짧으면 아직 전송되지 않은 데이터가 잘릴 수 있고, 너무 길면 리소스 해제가 늦어집니다. 일반 클라이언트는 코어 또는 클라이언트가 생성한 합리적인 기본값을 사용하는 것이 좋으며, 로그와 수집한 연결 상태가 단방향 종료 문제를 명확히 가리킬 때만 조정하세요.

bufferSize는 연결 버퍼와 관련된 값입니다. 버퍼를 크게 한다고 속도가 반드시 빨라지는 것은 아니며 연결마다 사용하는 메모리도 증가합니다. 저성능 기기, 동시 연결 수가 많은 환경과 대용량 파일 전송은 서로 다른 버퍼 요구를 가집니다. 최적화할 때는 한 번에 하나의 값만 바꾸고 메모리·연결 안정성·실제 처리량의 변화를 관찰하세요. 서버 고동시성 환경용 매개변수를 일반 데스크톱 클라이언트에 그대로 복사하지 마세요.

통계 옵션과 실행 비용

statsUserUplinkstatsUserDownlink은 사용자별 업로드·다운로드 통계를 제어하고, system 아래의 필드는 인바운드·아웃바운드 방향 통계를 제어합니다. 최상위 stats는 통계 모듈을 활성화하는 데 사용되지만 빈 객체만으로 모든 통계 차원에 데이터가 자동 생성되지는 않습니다. 관련 policy 옵션과 통계를 읽는 인터페이스도 필요합니다. v2rayN 화면에 특정 통계가 표시되는지는 클라이언트가 코어를 시작하고 데이터를 읽는 방식에도 달려 있습니다.

통계가 필요하지 않다면 관련 옵션을 꺼 두어 불필요한 상태 관리를 줄이세요. 특정 인바운드나 아웃바운드에 트래픽이 발생하는지 확인해야 한다면 필요한 차원만 단기간 활성화할 수 있지만, 트래픽 변화가 연결 품질을 직접 의미하지는 않습니다. 통계는 데이터가 특정 방향을 통과했음을 보여 줄 뿐 도메인 규칙, DNS 결과와 원격 애플리케이션 응답이 모두 올바르다는 것을 증명하지 않습니다. 진단에는 여전히 로그와 명확한 테스트 요청이 필요합니다.

policy 모듈과 관련된 흔한 오해는 연결 장애를 타임아웃 값 탓으로 돌리는 것입니다. 실제로는 프로토콜 매개변수 오류, 도달할 수 없는 DNS 주소, 잘못 선택된 라우팅 출구와 포트 점유가 더 흔합니다. 먼저 구조 로딩, 인바운드 수신, 규칙 일치와 아웃바운드 핸드셰이크를 확인한 뒤 연결이 수명 정책 때문에 조기에 종료되었는지 판단하세요. 연결이 수립된 뒤 반복 가능한 특정 시점에 종료된다는 로그가 있을 때 policy를 중점적으로 확인하면 됩니다.

Windows, macOS, Android와 Linux는 전면·백그라운드 네트워크 동작이 서로 다르며, 특히 모바일 기기는 애플리케이션이 백그라운드로 전환된 뒤 네트워크 활동을 제한할 수 있습니다. 이런 시스템 수준 동작은 connIdle을 늘리는 것만으로 해결할 수 없습니다. v2rayNG 또는 v2flyNG가 백그라운드에서 멈춘다면 먼저 시스템의 애플리케이션 네트워크·배터리 사용 제한을 확인하세요. v2rayN이 데스크톱에서 시작 직후 종료된다면 포트, 설정 파싱과 코어 시작 로그부터 살펴봐야 합니다.

policy는 설정이 안정된 후 세밀하게 조정할 때 적합하며 첫 연결에 반드시 필요한 모듈은 아닙니다. 단순한 클라이언트 설정은 기본 정책만으로 충분할 수 있습니다. 장시간 연결, 통계 또는 리소스 사용에 명확한 요구가 있을 때만 policy를 명시적으로 추가하세요. 필드가 적을수록 코어 업그레이드와 클라이언트 이전 시 관리해야 할 호환 지점도 줄어듭니다.

07

설정 검증, 로그 읽기와 체계적인 문제 해결

조회·시작·연결 단계를 먼저 구분하기

설정 장애는 먼저 세 단계로 나누어야 합니다. 첫 번째는 JSON 파싱입니다. 괄호 불일치, 누락된 큰따옴표, 후행 쉼표와 필드 형식 오류가 있으면 설정을 읽을 수 없습니다. 두 번째는 코어 시작입니다. 포트 충돌, 유효하지 않은 수신 주소와 지원되지 않는 모듈 필드는 프로세스가 정상 실행 상태에 진입하지 못하게 합니다. 세 번째는 요청 처리입니다. 서버 매개변수, DNS, 라우팅, 보안 계층 또는 네트워크 환경 문제는 보통 애플리케이션이 요청을 보낸 뒤 발생합니다. 단계를 구분하면 JSON 문법 오류인데 서버를 계속 바꾸는 일을 피할 수 있고, 원격 핸드셰이크 실패를 로컬 포트 문제로 잘못 판단하는 일도 줄어듭니다.

그래픽 클라이언트에 “시작됨”이 표시된다고 해서 프로세스가 실제로 정상 실행 중이라는 뜻은 아닙니다. 로컬 포트가 수신 중인지, 시스템 프록시가 올바른 포트를 가리키는지, 애플리케이션이 실제 요청을 보내는지, 요청이 최종적으로 어느 아웃바운드를 선택했는지 계속 확인해야 합니다. v2rayN의 매개변수 설정에서는 Core 유형, 로컬 SOCKS 수신 포트, LAN 연결 허용, sniffing, Mux, 로그 수준과 시스템 프록시 모드를 확인할 수 있습니다. v2rayNG와 v2flyNG에서는 현재 설정, 연결 모드와 시스템 네트워크 권한을 확인하세요.

JSON을 직접 편집할 때는 먼저 로컬 JSON 파서로 문법을 확인할 수 있지만, 실제 서버 매개변수가 포함된 전체 설정을 신뢰할 수 없는 온라인 도구에 제출해서는 안 됩니다. 로컬 편집기의 JSON 문법 지원을 사용하거나 코어가 테스트 설정으로 파일을 읽게 하는 방법이 더 안전합니다. 코어와 설치 방식에 따라 명령줄 매개변수가 다를 수 있으므로 실제 클라이언트 호출 방식을 기준으로 하고 다른 프로그램의 옵션을 그대로 적용하지 마세요.

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

warning은 일상적인 실행에 적합하며 주요 이상만 남겨 출력량이 과도해지지 않도록 합니다. 규칙과 DNS를 추적해야 할 때는 잠시 info로 전환하고 진단이 끝나면 낮은 출력 수준으로 되돌리세요. 로그에는 대상 도메인, 주소와 연결 시간 같은 실행 정보가 포함될 수 있으므로 공유하기 전에 문제와 무관한 민감한 내용을 삭제해야 합니다. 마지막 오류 한 줄만 잘라 공유하지 마세요. 앞부분의 조회·규칙·핸드셰이크 정보가 원인을 더 잘 보여 주는 경우가 많습니다.

데이터 경로를 따라 단계별로 좁히기

첫 단계는 인바운드입니다. 클라이언트에 표시된 SOCKS 또는 HTTP 포트가 애플리케이션 설정과 일치하는지, 다른 프로그램이 포트를 사용하고 있지 않은지, 수신 주소가 로컬 전용인지 로컬 네트워크용인지 확인하세요. 먼저 프록시 설정을 명확히 지원하는 애플리케이션으로 테스트하면 시스템 프록시·브라우저의 독립 설정·애플리케이션의 프록시 무시가 동시에 개입하는 상황을 피할 수 있습니다. 애플리케이션이 로컬 포트에도 연결하지 못한다면 당장은 원격 프로토콜을 확인할 필요가 없습니다.

두 번째 단계는 라우팅 입력입니다. 애플리케이션이 도메인과 IP 중 무엇을 제출했는지, sniffing이 켜져 있는지, 대상 프로토콜을 식별할 수 있는지 기록하세요. 그런 다음 rules의 첫 번째 항목부터 확인하고 예상한 규칙만 보지 마세요. 모든 포트·모든 네트워크 또는 대규모 도메인 집합을 포함하는 규칙처럼 앞에 있는 넓은 범위의 규칙을 특히 주의해야 합니다. 일치한 뒤에는 outboundTag가 실제로 존재하고 철자가 정확히 일치하는지 확인하세요.

세 번째 단계는 DNS입니다. 도메인 규칙이 직접 일치했다면 DNS는 아웃바운드 연결 대상에서만 사용될 수 있습니다. geoip 규칙에 의존한다면 routing이 먼저 대상을 조회할 수 있습니다. 어떤 조회 서버를 사용했는지, 어떤 주소 계열을 반환했는지, fallback이 결과를 바꾸었는지 확인하세요. 완전한 도메인과 조회 후의 단일 IP를 각각 테스트할 수도 있습니다. 도메인만 실패하고 IP가 성공한다면 DNS와 도메인 규칙을 중점적으로 보고, 둘 다 실패하면 출구와 네트워크 도달 가능성을 확인하세요.

네 번째 단계는 아웃바운드입니다. 프록시 프로토콜의 주소·포트·사용자 매개변수·전송 유형·보안 계층과 서버 이름은 하나의 묶음으로 일치해야 합니다. 구독을 가져온 뒤 필드가 누락되었다면 먼저 구독을 업데이트하고 클라이언트가 해당 공유 형식을 지원하는지 확인하세요. REALITY와 XTLS Vision 같은 조합은 Xray 코어와 일치하는 원격 매개변수에 의존하며, 자세한 원리는 REALITY와 XTLS Vision 핸드셰이크 및 흐름 제어 안내를 참고하세요. flow, fingerprint 또는 serverName을 추측으로 하나씩 바꾸면 원래 문제를 재현하기 어려워집니다.

다섯 번째 단계는 시스템 경로입니다. 시스템 프록시는 해당 설정을 따르는 애플리케이션에만 영향을 주며 기기의 모든 연결이 로컬 인바운드를 통과한다는 뜻은 아닙니다. 한 애플리케이션은 정상인데 다른 애플리케이션이 직접 연결된다면 후자가 시스템 프록시를 지원하는지 먼저 확인하세요. Windows, macOS와 Linux는 프록시 설정 위치가 다르고, Android 클라이언트는 보통 시스템이 제공하는 네트워크 연결 기능으로 트래픽을 처리합니다. 플랫폼별 설치와 클라이언트 선택은 클라이언트 비교를 참고하세요.

증상 우선 확인할 항목 다음 단계
코어가 시작되지 않음 JSON 문법, 필드 지원 여부, 포트 점유 최소 설정으로 되돌린 뒤 모듈을 단계별로 추가
애플리케이션이 로컬 프록시에 연결하지 못함 수신 주소, 포트, 애플리케이션 프록시 유형 SOCKS와 HTTP 설정을 혼용하지 않았는지 확인
일부 도메인의 출구가 잘못됨 규칙 순서, sniffing, domainStrategy 도메인 입력과 IP 입력의 매칭 차이 확인
도메인은 실패하지만 IP는 연결 가능 DNS 서버, hosts, 주소 계열 fallback과 애플리케이션 독립 조회 확인
연결 수립 후 일정 시간이 지나면 끊김 connIdle, 단방향 타임아웃, 시스템 백그라운드 제한 로그의 연결 수립 및 종료 시간 비교

최소 설정과 이분 복구 방법

설정을 여러 번 수정해 어느 부분이 잘못되었는지 알 수 없다면 최소 설정으로 되돌리는 방법이 가장 효과적입니다. 로컬 SOCKS 인바운드 하나, 매개변수가 완전한 것으로 확인된 프록시 아웃바운드 하나, direct 아웃바운드와 간단한 기본 규칙만 남기고 사용자 지정 DNS, 복잡한 라우팅, 통계와 policy는 잠시 제거하세요. 최소 설정이 작동하면 관련 필드 묶음 하나씩 복원하면서 매번 동일한 테스트를 수행합니다.

규칙이 많을 때는 이분법을 사용할 수 있습니다. 먼저 사용자 지정 규칙의 절반을 비활성화해 테스트하세요. 문제가 사라지면 비활성화한 부분에 원인이 있고, 계속되면 남겨 둔 부분이나 다른 모듈에 원인이 있습니다. 범위를 계속 좁히면 무작위로 규칙을 하나씩 옮기는 것보다 빠른 경우가 많습니다. DNS 서버 목록과 hosts 매핑에도 같은 방법을 적용할 수 있습니다. 매 테스트마다 서버·애플리케이션·대상 도메인과 네트워크 환경을 동일하게 유지해야 결과를 비교할 수 있습니다.

안정적인 설정에는 클라이언트 유형, Core 유형, 인바운드 포트, 아웃바운드 태그, 라우팅 규칙의 목적, DNS 선택 이유와 조정한 policy 필드를 구조화해 기록하는 것이 좋습니다. 설정만 저장하는 것보다 선택 이유를 기록하는 일이 중요합니다. 데이터 집합, 네트워크 환경과 클라이언트 생성 로직이 바뀌면 기존 규칙이 더 이상 적합하지 않을 수 있기 때문입니다. 용도를 설명할 수 없는 예외 규칙은 정기적으로 삭제해 설정이 추가만 가능하고 수정은 두려운 상태로 변하지 않게 하세요.

그래픽 클라이언트에서 구독을 업데이트하거나 코어를 전환한 뒤에는 사용자 지정 필드가 최종 실행 설정에 계속 기록되는지 다시 확인해야 합니다. v2rayN의 Avalonia 데스크톱 버전과 Windows WPF 버전은 화면과 플랫폼 지원에서 차이가 있지만 핵심 문제 해결 경로는 같습니다. 구체적인 선택은 v2rayN 데스크톱 버전과 WPF 버전의 차이를 참고하세요. macOS에서 첫 실행이나 네트워크 권한에 문제가 있다면 macOS 설치 및 네트워크 권한 처리 방법을 확인하세요.

오류 메시지를 여전히 분류하기 어렵다면 문제 해결에서 기본 개념, 설치 및 설정, 사용 팁과 문제 해결 항목으로 나누어 계속 확인하세요. 질문하거나 문제를 기록할 때는 “사용할 수 없음”이라고만 쓰지 말고 재현 절차, 클라이언트 이름, 운영체제, 코어 유형, 관련 설정 조각과 정리한 로그를 포함해야 합니다. 정보가 실제 데이터 경로에 가까울수록 문제가 인바운드·라우팅·DNS·아웃바운드·시스템 네트워크 계층 중 어디에 속하는지 판단하기 쉽습니다.

설정 파일의 목표는 필드를 가장 많이 쌓는 것이 아니라 각 연결의 처리 과정을 예측 가능하게 만드는 것입니다. 먼저 클라이언트가 생성한 기본 구조로 작동하는 기준선을 만든 다음 명확한 요구에 따라 라우팅·DNS·policy를 추가하세요. 모든 변경에는 테스트 시나리오와 복구 경로를 남겨야 합니다. 이렇게 하면 v2rayN, v2rayNG 또는 v2flyNG의 그래픽 관리 기능을 활용하면서도 문제가 발생했을 때 실행 설정을 직접 읽고 어느 모듈에서 발생했는지 찾을 수 있습니다.

v2rayN 다운로드