설정 필드

V2Ray 설정 파일 완벽 가이드

JSON 최상위 구조부터 시작해 인바운드, 아웃바운드, 전송 계층, 라우팅, DNS, 정책과 로그 필드를 순서대로 살펴보며 트래픽이 코어로 들어와 매칭되고 출구를 선택하는 과정을 이해합니다.

문서 안내

빠른 작업과 체계적인 조회를 나누어 사용하세요

사용 안내서에 따라 “구독 가져오기, 서버 선택, 시스템 프록시 활성화, 연결 확인” 순서로 기본 작업을 완료하세요. 이 페이지에서는 클라이언트가 생성한 설정과 수동으로 필드 관계를 확인하는 방법을 다룹니다. 처음 사용하는 경우 먼저 빠른 시작 절차를 마친 뒤, 라우팅·DNS 조회·시작 오류가 발생하면 해당 장으로 돌아와 항목별로 점검하세요. 클라이언트나 설치 패키지를 다시 선택해야 한다면 설치 패키지 페이지로 이동하세요.

장별 목차

트래픽 처리 순서에 따라 살펴보기

전체 설정은 일반적으로 “인바운드 수신, 라우팅 판단, DNS 조회, 아웃바운드 전송” 순서로 처리됩니다. 목차는 필드 계층과 실제 문제 해결 흐름을 함께 고려해 구성했습니다.

01 / CONFIG

JSON 구조 개요: 객체 계층과 처리 흐름부터 확인하기

최상위 객체의 역할

V2Ray 설정 파일은 하나의 JSON 객체입니다. 일반적인 최상위 필드에는 log, dns, inbounds, outbounds, routing, policy, stats가 있습니다. 이 필드들은 파일에 적힌 순서대로 차례차례 실행되는 것이 아니라, 코어가 시작될 때 각각 해당 모듈로 파싱됩니다. routinginbounds보다 앞에 작성해도 실제 처리 순서는 달라지지 않습니다. 트래픽의 방향을 결정하는 것은 인바운드 태그, 라우팅 조건, 아웃바운드 태그와 모듈 간 참조 관계입니다. 설정을 읽을 때는 첫 줄부터 순서대로 읽기보다 먼저 모든 tag를 찾고 참조 관계를 따라 점검하는 것이 좋습니다.

inboundsoutbounds는 모두 배열입니다. 하나의 코어가 여러 로컬 포트를 동시에 수신하거나 여러 출구를 준비할 수 있기 때문입니다. routing.rules 역시 배열이며, 규칙은 일반적으로 위에서 아래 순서로 매칭됩니다. 반면 dns, log, policy는 보통 객체로 작성해 각각 조회 동작, 로그 동작, 세션 정책을 설명합니다. 필드의 데이터 형식은 정확해야 합니다. 배열은 대괄호, 객체는 중괄호를 사용하고, 불리언 값은 true 또는 false로 작성해야 하며 따옴표가 붙은 문자열로 쓰면 안 됩니다.

최소 구조 만들기

아래 골격에는 SOCKS 인바운드 하나, 직접 연결 아웃바운드 하나, 기본 라우팅 규칙 하나가 포함되어 있습니다. 계층 구조를 이해하기 위한 예시이며 완성된 원격 서버 설정은 아닙니다. SOCKS 요청이 로컬 리스닝 포트로 들어오면 라우팅 모듈이 대상 주소를 확인하고, 사설 주소 규칙에 매칭되면 direct 아웃바운드로 전달합니다. 매칭되지 않은 트래픽은 사용 가능한 기본 아웃바운드를 사용하므로, 실제 운영 설정에서는 주 프록시 출구를 명확히 준비하고 직접 연결·프록시·차단 결과를 규칙으로 구분하는 것이 일반적입니다.

{
  "log": {
    "loglevel": "warning"
  },
  "inbounds": [
    {
      "tag": "socks-in",
      "listen": "127.0.0.1",
      "port": 10808,
      "protocol": "socks",
      "settings": {
        "auth": "noauth",
        "udp": true
      },
      "sniffing": {
        "enabled": true,
        "destOverride": ["http", "tls"]
      }
    }
  ],
  "outbounds": [
    {
      "tag": "direct",
      "protocol": "freedom",
      "settings": {}
    }
  ],
  "routing": {
    "domainStrategy": "IPIfNonMatch",
    "rules": [
      {
        "type": "field",
        "ip": ["geoip:private"],
        "outboundTag": "direct"
      }
    ]
  }
}

JSON 문법 오류와 의미 오류를 구분하세요

문법 오류는 코어가 파일을 아직 해석하지 못하는 단계에서 발생하며, 흔한 원인은 후행 쉼표, 누락된 따옴표, 짝이 맞지 않는 괄호, 표준 JSON에 주석을 넣는 경우입니다. JSON 자체는 ///* */ 주석을 지원하지 않습니다. 클라이언트 화면에서 주석을 허용하더라도 보통 저장 전에 별도 변환을 수행하는 것이므로, 코어가 직접 읽는 파일도 같은 형식을 지원한다고 볼 수 없습니다. 의미 오류는 JSON 파싱은 가능하지만 필드 조합이 올바르지 않은 경우입니다. 예를 들어 존재하지 않는 outboundTag를 라우팅 규칙에서 참조하거나, 포트를 문자열로 작성하거나, 프로토콜 이름과 settings 구조가 맞지 않는 경우가 이에 해당합니다.

클라이언트는 설정을 생성할 때 실행 디렉터리, 리소스 파일 위치, 코어별 차이와 관련된 필드도 추가합니다. v2rayN은 Windows, macOS, Linux 데스크톱 설정을 관리하는 데 적합하며, v2rayNG와 v2flyNG는 Android 환경에서 서로 다른 코어 계열을 사용합니다. 그래픽 클라이언트의 구독 항목이 최종 실행 설정과 같은 것은 아닙니다. 클라이언트는 보통 노드 매개변수, 로컬 리스닝 설정, 라우팅 규칙, DNS 옵션을 병합한 뒤 코어에 전달합니다. 따라서 문제를 해결할 때는 구독 링크의 단일 노드 매개변수만 확인하지 말고, 클라이언트가 실제로 생성하거나 내보낸 실행 설정을 우선 확인해야 합니다.

tag는 모듈을 연결하는 지점입니다

tag는 설정 내부에서 사용하는 안정적인 이름이라고 이해하면 됩니다. 인바운드 태그는 라우팅 규칙의 inboundTag가 참조하고, 아웃바운드 태그는 outboundTagbalancerTag가 참조합니다. DNS 서버도 태그를 통해 특정 아웃바운드와 연결할 수 있습니다. 태그는 대소문자를 구분하므로 이름을 바꾸면 모든 참조 위치를 함께 수정해야 합니다. socks-in, proxy, direct, block처럼 의미가 분명한 짧은 이름을 사용하고, 서버 주소나 자주 바뀌는 메모를 태그로 직접 사용하지 않는 것이 좋습니다.

전체 설정을 점검할 때는 간단한 흐름을 그려볼 수 있습니다. 애플리케이션이 어느 로컬 포트에 연결하는지, 해당 포트가 어느 인바운드 태그에 속하는지, 라우팅 규칙이 어떤 도메인·IP·포트·프로토콜을 기준으로 매칭하는지, 매칭 후 어느 아웃바운드 태그로 전달되는지, 아웃바운드가 어떤 프로토콜과 전송 방식을 사용하는지를 확인합니다. 흐름의 모든 참조가 실제 객체로 연결되기만 해도 구조상의 문제 대부분을 발견할 수 있습니다. 다음 장부터는 이 흐름에 따라 각 모듈을 나누어 설명합니다.

02 / INBOUNDS

inbounds 인바운드: 로컬 트래픽이 코어로 들어오는 방식 정의

리스닝 주소, 포트 및 프로토콜

인바운드는 브라우저, 시스템 프록시, 로컬 네트워크 기기 또는 다른 프로그램의 연결을 수신합니다. 인바운드 객체에는 보통 tag, listen, port, protocol, settings가 최소한 포함됩니다. listen은 어떤 네트워크 인터페이스에 바인딩할지 결정합니다. 데스크톱 클라이언트에서 로컬로만 사용할 때는 127.0.0.1에 우선 리스닝하는 것이 좋습니다. 그러면 같은 네트워크의 다른 기기가 해당 포트에 직접 접근할 수 없습니다. 로컬 네트워크에 공유해야 할 때만 모든 인터페이스에서 리스닝하는 방식을 고려하고, 시스템 방화벽·접근 제어·SOCKS 인증 설정도 함께 확인하세요.

port는 정수이며 다른 프로그램과 중복되지 않아야 합니다. v2rayN에서 사용하는 로컬 SOCKS 및 HTTP 포트는 클라이언트 설정에 따라 생성되므로, 수동 설정 시 특정 포트가 반드시 비어 있다고 가정하면 안 됩니다. 코어에서 주소가 이미 사용 중이라고 표시되면 다른 클라이언트 인스턴스가 실행 중인지 먼저 확인한 뒤 충돌한 프로그램을 종료할지 리스닝 포트를 바꿀지 결정하세요. 자세한 절차는 v2rayN 포트 사용 중으로 시작되지 않을 때 문제 해결을 참고하세요.

protocol은 인바운드 프로토콜 구조를 결정합니다. 로컬 환경에서는 sockshttp를 흔히 사용합니다. SOCKS 인바운드는 SOCKS5를 지원하는 프로그램에 적합하며 설정에 따라 UDP를 전달할 수 있습니다. HTTP 인바운드는 HTTP 프록시 설정을 사용하는 애플리케이션에 적합합니다. 투명 프록시나 포트 포워딩은 시스템 네트워크 스택과 추가 권한이 필요하므로 기본 설정에서 함부로 활성화하지 마세요. 먼저 프록시 주소가 명확히 설정된 애플리케이션의 연결을 성공시킨 후 점차 적용 범위를 넓히면 문제 해결 흐름이 더 분명해집니다.

SOCKS와 HTTP 인바운드를 함께 제공하기

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

두 인바운드는 서로 다른 포트를 사용해야 합니다. 애플리케이션에서 SOCKS5를 선택하면 127.0.0.1:10808을 입력하고, HTTP 프록시를 선택하면 127.0.0.1:10809를 입력하세요. 운영체제에서 프록시 포트를 하나만 입력할 수 있다면 클라이언트의 시스템 프록시 모드가 생성한 값을 사용하고, SOCKS 포트를 HTTP 프록지만 받는 입력란에 잘못 넣지 마세요. 포트에 TCP 연결이 가능하다는 사실은 로컬 리스너가 존재한다는 뜻일 뿐이며, 원격 아웃바운드·DNS·라우팅까지 모두 올바르다는 의미는 아닙니다.

트래픽 스니핑의 용도와 한계

sniffing.enabled를 활성화하면 코어가 일부 연결의 애플리케이션 계층 정보에서 대상 도메인을 복원할 수 있습니다. destOverride의 일반적인 httptls는 HTTP Host 또는 TLS 핸드셰이크의 서버 이름으로 원래 대상을 덮어쓸 수 있음을 뜻합니다. 이 기능은 도메인 라우팅에 도움이 됩니다. 애플리케이션이 먼저 IP를 조회하더라도 라우팅 모듈이 도메인을 얻어 geosite나 전체 도메인 규칙과 매칭할 수 있기 때문입니다.

스니핑은 웹 페이지 내용을 복호화하는 기능이 아니며, 모든 연결에서 도메인을 복원할 수 있는 것도 아닙니다. 식별 가능한 호스트 정보가 없는 프로토콜은 원래 대상이 유지됩니다. 일부 애플리케이션은 대상 주소 변경에 민감하므로 덮어쓰기를 활성화하면 예상과 다른 연결 동작이 발생할 수 있습니다. 특정 애플리케이션에 이상이 있을 때는 스니핑을 잠시 끄고 비교해 보세요. 끈 뒤 정상화된다면 아웃바운드 프로토콜을 바로 의심하기보다 도메인 규칙, DNS 결과, destOverride 범위를 확인해야 합니다.

UDP, 인증 및 로컬 네트워크 접근

SOCKS 인바운드의 udp는 UDP 전달 요청을 받을지 결정합니다. 이 필드를 활성화한다고 해서 모든 아웃바운드 전송이 대상 UDP를 자동 지원하는 것은 아니며, 애플리케이션이 반드시 SOCKS를 통해 UDP를 보내는 것도 아닙니다. 애플리케이션 동작, 아웃바운드 프로토콜 기능, 라우팅 규칙을 함께 확인해야 합니다. DNS 조회를 코어 내장 DNS에 맡기는 경우와 애플리케이션이 외부로 UDP 조회를 직접 보내는 경우의 처리 경로도 다르므로 각각 따로 판단해야 합니다.

리스닝 범위를 로컬 네트워크로 넓혔다면 접근 제어를 기본적인 로컬 환경처럼 취급해서는 안 됩니다. SOCKS는 auth와 계정 목록으로 사용자 이름·비밀번호 인증을 설정할 수 있지만, 클라이언트마다 이러한 필드를 그래픽 화면에서 지원하는 수준이 다릅니다. 필요한 인터페이스와 방화벽의 허용 출발지 주소만 열고, 모바일 기기에서 신뢰할 수 없는 네트워크로 포트가 노출되지 않는지 확인하는 편이 안전합니다. 로컬에서만 사용한다면 루프백 주소로 리스닝하는 것이 가장 간단하며 포트를 실수로 외부에 개방할 가능성도 줄어듭니다.

인바운드 출처에 따른 라우팅

여러 인바운드는 서로 다른 프록시 프로토콜에 대응하는 용도뿐 아니라 트래픽 분기 입구로도 사용할 수 있습니다. 예를 들어 일반 애플리케이션용 main-in과 직접 연결이 필요한 프로그램용 direct-in을 만들고, 라우팅 규칙에서 inboundTag로 구분할 수 있습니다. 이 방식은 전역 모드를 자주 바꾸는 것보다 명확하지만, 애플리케이션이 프록시 포트를 각각 지정할 수 있어야 합니다. 이런 구조를 설계할 때는 포트 용도를 설정 옆에 기록하고, 클라이언트가 설정을 다시 생성할 때 태그가 덮어써지지 않는지 확인하세요.

인바운드 문제는 네 단계로 점검할 수 있습니다. 프로세스가 포트 바인딩에 성공했는지, 애플리케이션이 올바른 프록시 유형을 사용하는지, 인바운드가 해당 TCP 또는 UDP 요청을 받는지, 스니핑과 라우팅이 대상을 바꾸었는지를 순서대로 확인하세요. 앞 단계가 해결된 뒤 다음 단계로 넘어가야 합니다. 브라우저에 프록시 서버가 응답하지 않는다고 표시되면 먼저 리스너와 포트를 확인하고, 코어 로그에 이미 연결 기록이 있는데 대상에 접근하지 못할 때 아웃바운드·라우팅·DNS 장을 살펴보세요.

03 / OUTBOUNDS

outbounds 아웃바운드: 프록시, 직접 연결 및 차단 출구 정의

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

아웃바운드 객체는 코어가 연결을 다음 홉 또는 최종 대상에 어떻게 보낼지 설명합니다. 일반적으로 주 프록시 출구, 직접 연결 출구, 차단 출구라는 세 가지 논리 출구를 준비합니다. 프록시 출구에는 VLESS, VMess, Trojan 등의 프로토콜을 사용할 수 있으며 구체적인 매개변수는 서버 설정에서 가져옵니다. 직접 연결은 보통 freedom, 차단은 보통 blackhole을 사용합니다. 세 출구에 명확한 tag를 각각 지정한 뒤 라우팅 규칙에서 outboundTag로 선택하세요.

라우팅 규칙에 매칭되지 않으면 코어는 기본 아웃바운드를 사용합니다. 코어 종류와 설정 구성 방식에 따라 기본 항목의 처리 세부 사항이 다를 수 있으므로, 중요한 분기를 모호한 배열 위치에 맡기면 안 됩니다. 일반 트래픽에는 명확한 규칙을 두고, 사설 주소·직접 연결이 필요한 도메인·차단 대상도 각각 확실한 태그로 보내는 방식이 유지 관리에 유리합니다. 클라이언트가 생성한 설정을 확인할 때는 추가 DNS 아웃바운드나 루프백 아웃바운드를 삽입했는지도 살펴보세요.

VLESS 클라이언트 아웃바운드 구조

아래 예시는 VLESS 아웃바운드의 기본 계층을 보여줍니다. 서버 주소는 예시 도메인을 사용하고, 사용자 식별자는 형식만 보여주기 위한 값이므로 실제 연결에 그대로 사용할 수 없습니다. settings.vnext는 서버 배열이며 각 서버 객체에는 주소, 포트, 사용자 목록이 들어갑니다. 사용자 객체의 id는 서버 설정과 일치해야 하고, VLESS에서 흔히 사용하는 encryption 값은 none입니다. 전송 방식, TLS, 서버 이름은 streamSettings에 위치하며 사용자 객체 안에 넣으면 안 됩니다.

{
  "outbounds": [
    {
      "tag": "proxy",
      "protocol": "vless",
      "settings": {
        "vnext": [
          {
            "address": "edge.example.com",
            "port": 443,
            "users": [
              {
                "id": "11111111-1111-4111-8111-111111111111",
                "encryption": "none"
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "tcp",
        "security": "tls",
        "tlsSettings": {
          "serverName": "edge.example.com",
          "allowInsecure": false
        }
      }
    },
    {
      "tag": "direct",
      "protocol": "freedom",
      "settings": {}
    },
    {
      "tag": "block",
      "protocol": "blackhole",
      "settings": {}
    }
  ]
}

address는 코어가 실제로 연결하는 서버 주소이고, serverName은 TLS 핸드셰이크에 사용하는 이름입니다. 두 값은 같을 수도 있지만 배포 구조에 따라 다를 수도 있습니다. “보기 좋게 일치시키기” 위해 임의로 같은 값으로 바꾸면 안 됩니다. 포트, 전송 유형, 보안 계층, 서버 이름과 기타 확장 매개변수는 서버 설정과 전체적으로 대응해야 합니다. 어느 하나라도 맞지 않으면 연결 직후 종료되거나 TLS 핸드셰이크 실패, 장시간 대기 등으로 나타날 수 있습니다.

freedom과 blackhole의 실제 역할

freedom은 코어가 로컬 네트워크에서 대상에 직접 접근하도록 합니다. 코어를 우회하는 것은 아닙니다. 트래픽은 여전히 인바운드와 라우팅을 먼저 거치며, 아웃바운드 단계에서만 원격 프록시 서버로 보내지 않습니다. 사설 주소, 로컬 개발 서비스, 로컬 네트워크 기기, 로컬 출구가 명확히 필요한 사이트는 보통 이 아웃바운드로 보냅니다. 시스템 자체에서 대상을 조회하거나 접근할 수 없다면 freedom으로 보내도 로컬 네트워크 문제가 자동으로 해결되지는 않습니다.

blackhole은 규칙에 매칭된 연결을 버리는 데 사용하며, 명확히 필요하지 않은 도메인·IP·프로토콜을 차단할 수 있습니다. 이는 “아웃바운드에 매칭되지 않음”과 다릅니다. 전자는 의도적으로 차단 출구를 선택한 것이고, 후자는 일반적으로 설정 참조 오류에 해당합니다. 문제를 해결할 때는 로그의 라우팅 결과로 구분할 수 있습니다. 차단 규칙은 구체적으로 작성해야 하며, 너무 넓은 도메인 접미사나 IP 범위는 정상적인 하위 도메인과 공유 주소의 다른 서비스까지 차단할 수 있습니다.

다중 서버와 부하 분산 정책

여러 서버를 하나의 아웃바운드 객체에 넣는다고 해서 예상한 방식으로 자동 전환되는 것은 아닙니다. 여러 출구가 필요하다면 보통 각 출구에 독립적인 태그를 지정하고, 라우팅의 로드 밸런서나 클라이언트가 제공하는 선택 기능으로 관리합니다. 이렇게 하면 각 서버를 개별적으로 테스트할 수 있고 어떤 규칙이 어느 출구를 선택했는지도 명확히 확인할 수 있습니다. 그래픽 클라이언트는 현재 선택한 노드에 따라 proxy 아웃바운드를 동적으로 생성할 수 있으므로, 수동으로 추가한 병렬 아웃바운드가 다음 설정 적용 때 다시 만들어질 수 있습니다.

구독은 노드 매개변수의 출처이며 실행 설정과 같은 계층으로 보면 안 됩니다. 구독을 갱신한 뒤 노드가 비어 있거나 필드 파싱에 실패하면 먼저 구독 형식과 클라이언트 호환성을 확인하세요. 구독 만료 및 파싱 실패 문제 해결을 참고할 수 있습니다. 노드는 가져와지지만 특정 출구만 연결되지 않는다면 전체 구독을 반복해서 갱신하기보다 주소, 포트, 사용자 식별자, 전송 계층, 보안 계층을 비교해야 합니다.

아웃바운드 문제를 계층별로 해결하기

먼저 라우팅이 실제로 대상 아웃바운드 태그를 선택했는지 확인합니다. 다음으로 서버 주소를 조회할 수 있고 로컬 네트워크에서 해당 포트에 도달할 수 있는지 확인한 뒤, 프로토콜 인증 필드를 점검하고 마지막으로 streamSettings를 대조합니다. 처음부터 노드 교체, DNS 비활성화, 라우팅 모드 변경, TLS 조정을 동시에 하면 어떤 변경이 효과가 있었는지 알 수 없습니다. 정상 작동이 확인된 직접 연결 아웃바운드를 하나 보관하는 것도 중요합니다. 이를 통해 문제가 코어 전체 시작, 라우팅 선택, 특정 프록시 출구 중 어디에 있는지 판단할 수 있습니다.

04 / STREAM

streamSettings: 전송 방식과 보안 계층은 함께 맞춰야 합니다

프로토콜 계층, 전송 계층, 보안 계층의 차이

아웃바운드의 protocol은 VLESS, VMess, Trojan 같은 프록시 프로토콜을 설명하고, streamSettings.network는 연결을 운반하는 전송 방식을 설명하며, streamSettings.security는 TLS, REALITY 또는 추가 보안 계층을 사용하지 않는 선택을 설명합니다. 세 계층은 서로 다른 문제를 해결하지만 실제 연결에서는 서버 설정과 항목별로 일치해야 합니다. “VLESS를 사용한다”는 정보만으로는 연결할 수 없습니다. TCP, WebSocket, gRPC 같은 전송 방식과 서버 이름, 경로, 서비스 이름, 보안 매개변수도 알아야 합니다.

클라이언트는 공유 링크나 구독을 가져온 뒤 이 매개변수들을 코어가 인식하는 필드로 변환합니다. 코어 계열에 따라 일부 필드명, 허용 값, 확장 기능이 완전히 같지 않을 수 있습니다. v2rayNG는 일반적으로 Xray 코어를 사용하고, v2flyNG는 v2fly 계열을 사용하며, v2rayN은 데스크톱 코어와 노드 설정을 관리할 수 있습니다. 클라이언트 간에 설정을 옮길 때는 내부 JSON 일부만 복사해 모든 필드가 동일하게 파싱된다고 가정하지 말고, 대상 클라이언트가 실제로 사용하는 코어의 기능을 확인하세요.

TCP 및 TLS 예시

일반 TCP 전송은 보통 networktcp로 설정합니다. TLS를 활성화할 때는 securitytls로 작성하고 tlsSettings를 제공합니다. serverName은 인증서 이름 확인과 핸드셰이크에 사용하므로 서버가 안내한 값을 사용해야 합니다. allowInsecurefalse로 설정하면 정상적인 인증서 검증을 수행합니다. 이를 true로 바꾸면 일부 검증만 우회할 뿐 잘못된 포트·프로토콜·서버 미실행 문제를 해결하지 못하며, 일반적인 문제 해결책으로 계속 사용해서도 안 됩니다.

{
  "streamSettings": {
    "network": "tcp",
    "security": "tls",
    "tlsSettings": {
      "serverName": "edge.example.com",
      "allowInsecure": false,
      "alpn": ["h2", "http/1.1"]
    }
  }
}

alpn은 애플리케이션 계층 프로토콜 협상에 사용됩니다. 입력 필요 여부와 값의 순서는 서버 배포 설정과 일치해야 합니다. 필드가 많다고 더 완전한 설정이 되는 것은 아닙니다. 서버에서 요구하지 않는다면 클라이언트의 자동 협상이 더 적절한 경우가 많습니다. 연결 실패 시에도 모든 ALPN 값을 무작정 바꾸지 마세요. 핸드셰이크 결과는 포트, 서버 이름, 중간 프록시, 서버 인증서 설정의 영향도 받습니다.

WebSocket 경로와 요청 헤더

WebSocket 전송은 wsSettings를 사용하며, 그중 일반적인 필드는 path입니다. 경로는 시작 슬래시와 쿼리 문자열이 있을 경우 이를 포함해 서버 설정과 완전히 일치해야 합니다. 일부 배포에서는 특정 Host 요청 헤더도 필요하며, 구체적인 필드 구조는 코어의 지원 방식에 따라 달라집니다. 설정을 옮길 때 가장 흔한 문제는 서버 주소와 포트만 복사하고 경로나 호스트 이름을 빠뜨리는 것입니다. 이 경우 TLS 연결은 가능하지만 이후 일반 웹 페이지 응답을 받거나 연결이 종료될 수 있습니다.

{
  "streamSettings": {
    "network": "ws",
    "security": "tls",
    "tlsSettings": {
      "serverName": "edge.example.com",
      "allowInsecure": false
    },
    "wsSettings": {
      "path": "/vless-connect",
      "headers": {
        "Host": "edge.example.com"
      }
    }
  }
}

주소, TLS 서버 이름, HTTP Host는 같은 도메인을 가리킬 수도 있지만 연결 대상, 인증서 검증, 리버스 프록시 분기라는 서로 다른 역할을 맡을 수도 있습니다. 서버 구조를 정확히 알고 있을 때만 수정해야 합니다. 경로의 대소문자는 보통 의미가 있으며 끝의 슬래시도 다른 라우팅 결과를 만들 수 있습니다. 클라이언트 화면에서 이 필드를 “주소”, “위장 도메인”, “경로” 등으로 나누어 제공한다면 내보낸 실제 JSON을 기준으로 매핑을 확인하세요.

gRPC와 서비스 이름

gRPC 전송은 보통 grpcSettings를 사용하며 핵심 필드는 serviceName입니다. 일반 웹 경로가 아니므로 슬래시를 기계적으로 붙이면 안 됩니다. 배포에 따라 다중화 관련 옵션이 필요할 수도 있지만, 기본 문제 해결은 서비스 이름, TLS 서버 이름, 포트부터 확인하는 데서 시작합니다. 서버가 gRPC를 사용하는데 클라이언트에서 WebSocket을 선택하면 양쪽 모두 TLS를 활성화했더라도 인증서가 올바르다는 이유만으로 호환되지 않습니다.

{
  "streamSettings": {
    "network": "grpc",
    "security": "tls",
    "tlsSettings": {
      "serverName": "edge.example.com",
      "allowInsecure": false
    },
    "grpcSettings": {
      "serviceName": "vless-grpc"
    }
  }
}

REALITY 설정 점검 순서

REALITY는 보안 계층 기능이며 VLESS와 함께 사용하는 경우가 많지만 VLESS와 같은 의미는 아닙니다. 클라이언트 매개변수에는 보통 서버 이름, 공개 키, 짧은 식별자, 지문 등이 포함되며 구체적인 필드는 대상 코어의 지원 범위를 따라야 합니다. 먼저 현재 코어가 이 보안 계층을 지원하는지 확인하고, 주소와 포트를 점검한 다음 서버 이름·공개 키·짧은 식별자·전송 방식을 하나씩 비교하세요. 하나의 아웃바운드에 TLS 설정 블록과 REALITY 설정 블록을 동시에 섞었다면 가져오기나 수동 병합 과정에 문제가 있을 가능성이 큽니다.

전송 계층 문제를 해결할 때는 값을 하나씩 추측하며 바꾸지 마세요. 신뢰할 수 있는 동일한 서버 매개변수에서 다시 대조해 프로토콜, 네트워크 유형, 보안 유형이라는 세 진입 필드를 확인한 뒤 해당 설정 객체로 들어가는 것이 올바른 방법입니다. 로그에 인증서 이름·핸드셰이크·서비스 경로·프로토콜 응답 오류가 표시될 때 해당 분기를 따라 점검하세요. 로그가 타임아웃만 표시한다면 DNS 조회, 대상 포트 접근 불가, 잘못 선택된 라우팅 출구부터 배제해야 합니다.

다중화와 성능 매개변수

일부 설정은 아웃바운드에서 다중화를 설정해 여러 논리 연결이 하나의 하위 연결을 공유하도록 지원합니다. 반복적인 핸드셰이크를 줄일 수도 있지만 서버 지원 여부, 장시간 연결 특성, 애플리케이션 트래픽 유형에 따라 반대 효과가 날 수도 있습니다. 명확한 문제가 없다면 먼저 클라이언트 기본값을 사용하세요. 단일 연결은 정상인데 동시 접속에서 문제가 생기거나 장시간 실행 후 멈춘다면 다른 필드를 그대로 둔 채 다중화를 끄고 비교해 볼 수 있습니다. 성능 매개변수는 연결이 정상적으로 성립한 뒤 조정해야 하며, 프로토콜이나 전송 계층의 불일치를 가리는 용도로 사용하면 안 됩니다.

05 / ROUTING

routing 라우팅 규칙: 순서대로 매칭하고 출구 선택하기

라우팅은 출구만 결정하며 연결 기능을 만들지는 않습니다

routing 모듈은 대상 도메인, 대상 IP, 포트, 출처 인바운드, 네트워크 유형, 프로토콜 등의 조건에 따라 연결을 지정된 아웃바운드로 전달합니다. 아웃바운드 자체의 프로토콜 매개변수를 바꾸거나 연결할 수 없는 서버를 복구하지는 않습니다. 특정 도메인만 접속되지 않고 다른 도메인은 정상이라면 라우팅과 DNS를 중점적으로 확인해야 하며, 모든 트래픽이 같은 프록시 출구를 통과하지 못한다면 먼저 아웃바운드 연결 능력을 확인하세요.

rules 배열은 보통 위에서 아래로 검사하며 먼저 매칭된 규칙이 결과를 결정합니다. 따라서 구체적인 규칙을 포괄적인 규칙보다 앞에 배치해야 합니다. 예를 들어 특정 전체 도메인은 프록시로 보내야 하지만 해당 도메인의 전체 접미사는 직접 연결로 설정되어 있다면 전체 도메인 규칙을 접미사 규칙보다 앞에 둬야 합니다. 규칙이 많을 때는 “차단, 사설 주소, 특수 프록시, 특수 직접 연결, 지역 분류, 기본 처리”처럼 그룹으로 관리하고 각 그룹에 명확한 설명을 남기세요.

domain, ip, port 작성법

도메인 조건에는 정확한 도메인, 접미사, 키워드, 정규 표현식, geosite 분류를 사용할 수 있습니다. 매칭 형식마다 접두사와 의미가 다르므로 일반 문자열을 정확히 일치하는 값으로 이해하면 안 됩니다. IP 조건에는 단일 주소, CIDR 네트워크, geoip 분류를 입력할 수 있습니다. 포트는 단일 숫자나 범위 문자열로 작성할 수 있습니다. 한 규칙에 여러 조건 유형을 함께 입력하면 보통 모든 유형이 동시에 충족되어야 하며, 같은 유형의 배열에 있는 여러 값은 그중 하나라도 일치하면 됩니다.

{
  "routing": {
    "domainStrategy": "IPIfNonMatch",
    "rules": [
      {
        "type": "field",
        "domain": ["full:updates.example.com"],
        "outboundTag": "proxy"
      },
      {
        "type": "field",
        "domain": ["domain:example.net", "geosite:cn"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "ip": ["geoip:private", "geoip:cn"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "network": "tcp,udp",
        "outboundTag": "proxy"
      }
    ]
  }
}

full:은 하나의 완전한 호스트 이름만 매칭할 때 적합하고, domain:은 일반적으로 해당 도메인과 하위 도메인을 함께 포함합니다. geosite:는 코어가 해당 지역 분류 리소스 파일을 찾을 수 있어야 하며, geoip:도 IP 데이터 리소스에 의존합니다. 리소스 파일이 없거나 경로가 잘못되었거나 클라이언트 업데이트 후 제대로 로드되지 않으면 관련 규칙이 시작 단계에서 오류를 내거나 예상대로 작동하지 않습니다. 홈페이지의 “geosite 데이터 업데이트”는 실제 유지 관리 작업이지만 실행 빈도는 클라이언트 업데이트 방식과 규칙 요구 사항에 따라 정해야 합니다.

domainStrategy가 도메인 및 IP 규칙에 미치는 영향

domainStrategy는 IP 규칙과 매칭하기 위해 라우팅 단계에서 도메인을 조회할지 결정합니다. AsIs는 요청에 포함된 도메인을 유지하고 IP 규칙을 위해 적극적으로 조회하지 않는 경향이 있습니다. IPIfNonMatch는 일반적으로 도메인 규칙에 매칭되지 않을 때 IP를 조회해 IP 규칙을 시도합니다. IPOnDemand는 IP 규칙과 관련된 조회를 더 일찍 실행합니다. 구체적인 동작은 코어 구현과 DNS 설정을 함께 고려해야 합니다.

전략을 선택할 때는 먼저 규칙의 중심을 명확히 하세요. 주로 geosite와 명시적인 도메인 목록에 의존한다면 불필요한 조회를 피하는 것이 경로 복잡도를 줄일 수 있습니다. geoip에 크게 의존한다면 도메인에서 라우팅 판단에 사용할 IP를 얻을 수 있어야 합니다. 결과가 어디에서 오는지도 중요합니다. 시스템 DNS, 코어 내장 DNS, 원격 조회는 서로 다른 결과를 내놓을 수 있고 IP 분류 매칭도 달라집니다. 따라서 domainStrategy를 바꾼 뒤에는 DNS 로그와 라우팅 결과를 함께 관찰해야 합니다.

인바운드, 네트워크, 프로토콜에 따른 분기

inboundTag를 사용하면 특정 입구에서 들어온 트래픽에만 규칙을 적용할 수 있습니다. 예를 들어 직접 연결 전용 입구를 만든 뒤 해당 입구의 모든 트래픽을 direct로 보낼 수 있습니다. network는 TCP와 UDP를 구분하며 특정 아웃바운드가 특정 네트워크 유형을 처리하지 못할 때 유용합니다. 일부 코어는 특정 애플리케이션 계층 프로토콜도 식별할 수 있지만, 트래픽 스니핑으로 충분한 정보를 얻을 수 있어야 합니다. 프로토콜 식별에 의존하는 규칙은 보조 수단으로 사용하고 명확한 도메인 또는 포트 조건을 대신하게 하지 마세요.

{
  "type": "field",
  "inboundTag": ["direct-in"],
  "network": "tcp,udp",
  "outboundTag": "direct"
}

규칙 충돌과 우선순위 확인

라우팅 충돌은 규칙 자체는 모두 유효하지만 포괄적인 규칙이 먼저 매칭되어 뒤의 구체적인 규칙이 실행될 기회를 잃는 경우가 가장 흔합니다. 점검할 때는 대상 연결에서 시작해 도메인, 조회된 IP, 포트, 네트워크 유형, 인바운드 태그를 기록한 뒤 첫 번째 규칙부터 하나씩 판단하세요. 예상한 규칙이 존재하는지만 검색하지 말고 그 앞에 이미 매칭될 수 있는 규칙이 있는지도 확인해야 합니다. domain, ip, geosite 구성 방법은 사용자 지정 라우팅 규칙과 매칭 우선순위 자세히 보기를 참고하세요.

또 다른 흔한 문제는 규칙이 잘못된 태그를 참조하는 경우입니다. 클라이언트가 노드를 전환하면 주 아웃바운드 태그를 다시 생성할 수 있으므로, 수동 규칙이 이전 태그를 참조하면 작동하지 않거나 시작 오류가 발생합니다. 안정적으로 유지하려면 노드 메모가 아니라 클라이언트가 보존하는 논리 태그를 사용하세요. 클라이언트에 “로컬 네트워크 주소 우회” 옵션이 있다면 사설 주소 직접 연결 규칙을 생성하는지, 적절한 우선순위에 배치되는지 확인하세요. 서로 겹치는 규칙을 수동으로 다시 추가하는 것은 피해야 합니다.

기본 규칙과 유지 관리성

네트워크 유형만 지정하고 주 출구로 보내는 규칙은 기본 처리 규칙으로 자주 사용됩니다. 대부분의 연결과 매칭되므로 배열의 마지막에 배치해야 합니다. 앞부분에는 차단, 사설 주소, 특수 분기를 두고 마지막에 나머지 트래픽을 처리하면 동작을 가장 쉽게 예측할 수 있습니다. 기본 아웃바운드에만 의존하고 기본 규칙을 작성하지 않아도 작동할 수 있지만, 읽는 사람이 배열 위치와 코어 동작을 추가로 추론해야 하므로 장기 유지 관리에는 불리합니다.

대규모 규칙 세트에서는 모든 도메인을 주 설정에 흩어 놓지 않는 것이 좋습니다. 클라이언트가 지원하는 규칙 세트 관리 방식을 사용할 수 있지만, 최종적으로 생성된 JSON이 올바른 리소스를 참조하는지는 확인해야 합니다. 규칙 데이터를 업데이트한 뒤 연결 동작이 갑자기 달라졌다면 서버 노드를 먼저 바꾸기보다 분류 내용, 리소스 로드 로그, 규칙 순서를 비교하세요. 라우팅은 결정적인 매칭 시스템이므로 문제 해결의 핵심은 실제로 어떤 규칙이 매칭되었는지 찾는 것입니다.

06 / DNS

DNS 설정: 조회 출처, 도메인 매칭 및 결과 범위 제어

코어 DNS와 시스템 DNS의 관계

dns 모듈은 코어 내부에서 조회해야 하는 도메인에 서버와 매칭 규칙을 제공하지만, 운영체제의 모든 DNS 요청이 자동으로 코어를 통과하도록 보장하지는 않습니다. 애플리케이션이 시스템 조회를 직접 호출하는지, 도메인을 SOCKS에 전달하는지, 독립적인 DNS 패킷을 보내는지에 따라 실제 경로가 달라집니다. 설정에 dns.servers가 있다고 해서 브라우저의 모든 조회가 이 서버를 사용한다고 단정할 수 없습니다. 문제를 해결할 때는 “코어가 아웃바운드 서버 주소를 조회하는 경우”, “라우팅이 대상 도메인을 조회하는 경우”, “애플리케이션이 직접 조회하는 경우”를 구분해야 합니다.

코어 DNS의 장점은 조회 선택과 라우팅 규칙을 연동할 수 있다는 데 있습니다. 특정 도메인을 지정된 조회 서버로 보내고 그 결과를 IP 라우팅에 사용하거나, 특정 도메인 그룹에 예상 IP 범위를 설정해 조건에 맞지 않는 응답을 받지 않도록 할 수 있습니다. 완전한 구성을 위해서는 DNS 조회 자체가 어느 출구를 통과하는지, 조회 결과가 어느 단계에 사용되는지, 애플리케이션이 최종 연결할 때 도메인을 여전히 유지하는지를 함께 고려해야 합니다.

servers 배열과 조건부 서버

servers에는 단순한 서버 주소와 매칭 조건이 포함된 객체를 모두 작성할 수 있습니다. 객체 형식에서는 domains로 적용할 도메인을 지정하고 expectIPs로 허용할 결과 범위를 제한할 수 있습니다. 아래 예시는 특정 분류를 로컬 네트워크에서 접근 가능한 조회 주소로 보내고 나머지 도메인은 다른 DNS 서버로 보냅니다. 예시 주소는 구조 설명을 위한 것이므로 실제 배포에서는 현재 네트워크와 출구 경로에서 접근 가능한 조회 서비스를 선택해야 합니다.

{
  "dns": {
    "hosts": {
      "router.internal.example": "192.168.1.1"
    },
    "servers": [
      {
        "address": "223.5.5.5",
        "domains": ["geosite:cn"],
        "expectIPs": ["geoip:cn"]
      },
      {
        "address": "1.1.1.1",
        "domains": ["geosite:geolocation-!cn"]
      },
      "localhost"
    ],
    "queryStrategy": "UseIP"
  }
}

domains의 매칭 방식은 도메인 규칙 체계와 관련되며 의존하는 분류 리소스도 로드되어야 합니다. expectIPs는 조회 결과를 특정 네트워크로 바꾸는 기능이 아니라 응답이 예상 범위에 맞는지 필터링하거나 판단하는 데 사용됩니다. 조건이 지나치게 좁으면 분류 범위 밖의 합법적인 주소가 거부되어 해당 도메인의 조회가 실패할 수 있습니다. 문제를 해결할 때는 먼저 단순한 서버 설정으로 비교한 뒤 도메인 조건과 결과 제한을 단계적으로 복원하세요.

hosts 정적 매핑

hosts는 특정 이름에 정적 매핑을 제공하며, 고정된 로컬 서비스·테스트 환경·명확히 덮어써야 하는 레코드에 적합합니다. 대규모 동적 DNS를 대신하는 용도로는 적합하지 않습니다. 대상 주소가 바뀌어도 정적 값은 자동으로 업데이트되지 않으며, 설정에 남은 오래된 매핑이 도메인을 계속 잘못된 주소로 보낼 수도 있습니다. “한 도메인만 항상 이전 서버에 연결되는” 문제를 확인할 때는 hosts, 시스템 hosts 파일, 클라이언트 사용자 지정 DNS 매핑을 모두 검색해야 합니다.

정적 매핑된 이름도 라우팅 모듈로 전달될 수 있습니다. 라우팅 판단이 원래 도메인을 기준으로 하는지, 조회된 IP를 기준으로 하는지, 해당 IP가 어느 출구와 매칭되는지 확인하세요. 로컬 도메인이 사설 주소로 매핑되었다면 보통 사설 주소 직접 연결 규칙도 필요합니다. 그렇지 않으면 연결이 잘못 프록시 아웃바운드로 전송되어 로컬 네트워크 서비스에 접근하지 못할 수 있습니다.

queryStrategy와 주소 체계 선택

queryStrategy는 조회할 주소 유형을 제한합니다. 일반적으로 사용 가능한 주소를 모두 사용하거나 IPv4만, IPv6만 요청하도록 설정할 수 있으며 구체적인 허용 값은 코어 구현에 따라 다릅니다. 현재 네트워크가 해당 주소 체계로 실제 연결 가능한지를 기준으로 선택하세요. 네트워크가 IPv6 주소를 반환하지만 안정적인 IPv6 출구가 없다면 애플리케이션이 접근할 수 없는 주소를 먼저 시도해 지연이나 타임아웃이 발생할 수 있습니다. 반대로 IPv4만 강제하면 IPv6만 제공되는 대상에 접근할 수 없습니다.

주소 체계 문제를 전략을 반복해서 바꾸는 것만으로 판단해서는 안 됩니다. DNS 반환 결과, 시스템 라우팅 테이블, 코어 연결 로그를 각각 확인해 최종적으로 어떤 유형의 주소를 시도했는지 확인할 수 있습니다. 프록시 서버 자체를 도메인으로 입력했다면 해당 도메인을 조회하는 주소 체계도 아웃바운드 연결 가능성에 영향을 줍니다. 대상 웹사이트는 정상적으로 조회되는데 서버 도메인 조회만 실패한다면 문제가 발생한 단계가 다릅니다.

DNS 조회에서 아웃바운드를 선택하는 방식

DNS 서버도 하나의 대상이므로 조회 트래픽 역시 네트워크 출구를 거쳐야 합니다. 일부 설정은 DNS 서버에 태그를 지정하거나 전용 아웃바운드로 처리할 수 있으며, 클라이언트가 전용 DNS 라우팅을 생성하기도 합니다. 설계할 때 순환 의존을 피해야 합니다. 프록시 서버 주소를 조회하는 DNS가 아직 연결되지 않은 프록시 아웃바운드에 의존하면 시작 단계에서 첫 연결을 완료하지 못할 수 있습니다. 일반적으로 서버 주소 조회에는 사용 가능한 로컬 경로를 마련하고, 대상 도메인 조회는 규칙에 따라 직접 연결 또는 프록시 출구를 선택하게 합니다.

조회 서버를 IP가 아닌 도메인으로 작성하면 해당 서버 자체도 먼저 조회해야 하므로 의존성이 한 단계 더 늘어납니다. 기본 설정에서는 먼저 경로를 이해하기 쉽게 구성하고 작동을 확인한 뒤 암호화 DNS, 조건부 서버, 복잡한 아웃바운드 연결을 추가하세요. 중국 본토와 해외 도메인을 나누어 조회하는 방식 및 servers, domains, expectIPs 조합은 V2Ray DNS 설정 자세히 보기에서 계속 확인할 수 있습니다.

캐시와 문제 해결 순서

DNS 결과는 애플리케이션, 운영체제, 클라이언트, 코어 중 한 곳의 캐시에 남을 수 있습니다. 설정을 바꾼 직후 다시 접속해도 오래된 결과를 사용할 수 있습니다. 올바른 순서는 설정 저장, 해당 코어 재시작, 필요하면 테스트 애플리케이션을 종료 후 다시 실행, 새 로그 관찰입니다. 매번 시스템 네트워크 상태 전체를 초기화할 필요는 없습니다. 먼저 어느 계층이 결과를 캐시했는지 확인하세요. 코어를 재시작한 뒤에도 새 조회 기록이 없다면 애플리케이션이 도메인 조회를 코어에 맡기지 않았을 가능성이 있습니다.

DNS 문제는 일정한 순서로 해결할 수 있습니다. 먼저 서버 주소에 접근 가능한지 확인하고, 조건 없는 규칙으로 결과가 반환되는지 확인한 다음 domains를 추가하고 마지막으로 expectIPs와 아웃바운드 연결을 추가하세요. 단계마다 변수 하나만 늘려야 합니다. 조회가 성공했는데도 연결되지 않는다면 라우팅과 아웃바운드를 점검하고, 모든 연결 오류를 DNS 탓으로 돌리지 마세요.

07 / POLICY

policy, stats, log: 세션 정책, 통계 스위치 및 진단 기록

policy가 연결 세션 동작을 제어하는 방식

policy는 사용자 수준과 시스템 수준의 실행 정책을 설정합니다. 일반적인 항목에는 핸드셰이크 대기 시간, 유휴 연결 시간, 업링크·다운링크만 종료된 뒤의 지연 시간, 사용자 트래픽 통계 활성화 여부가 포함됩니다. 도메인 라우팅을 담당하거나 전송 프로토콜을 바꾸지는 않습니다. 데스크톱 클라이언트에서는 기본 정책으로 충분한 경우가 많으며, 장시간 연결 회수·서버 사용자 등급·통계 요구가 명확할 때만 조정하세요.

사용자 수준은 프로토콜 사용자 객체의 levelpolicy.levels에 대응합니다. 사용자가 등급을 지정하지 않으면 일반적으로 기본 등급을 사용합니다. 등급은 정책 인덱스이지 회선 품질이나 권한 점수가 아닙니다. 수동 설정에서 사용자가 level: 1을 지정했지만 등급 0만 정의했다면 의도한 정책이 적용되지 않습니다. 서버와 클라이언트 설정 방식에서 이 메커니즘을 명확히 사용하는 경우가 아니라면 클라이언트 노드에 등급을 임의로 추가할 필요는 없습니다.

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

handshake는 연결 수립 단계에서 기다릴 수 있는 시간을 제한합니다. 너무 짧으면 네트워크가 불안정할 때 정상 연결도 조기에 종료되고, 너무 길면 응답 없는 연결이 리소스를 더 오래 차지합니다. connIdle은 유휴 연결을 처리하며, 장시간 연결을 유지하지만 잠시 데이터가 없는 애플리케이션에 영향을 줄 수 있습니다. uplinkOnlydownlinkOnly는 반쯤 종료된 연결의 유지 시간을 처리합니다. 충분한 이유가 없다면 “더 빨리 해제”하려고 이 값을 지나치게 낮추지 마세요.

stats 객체와 통계 스위치의 관계

stats 객체만 작성한다고 모든 통계 데이터가 생성되는 것은 아닙니다. policy.system 또는 사용자 등급 정책에서 해당 방향의 통계 스위치를 활성화한 뒤 클라이언트나 API가 데이터를 읽어야 합니다. 인바운드·아웃바운드 통계는 해당 태그의 전체 트래픽을 관찰하는 데 사용되고, 사용자 통계는 프로토콜 사용자와 등급 정책에 관련됩니다. 통계 기능은 일정한 상태 관리 비용을 발생시키므로 클라이언트 화면에서 데이터를 읽지 않는다면 꺼 두어도 됩니다.

그래픽 클라이언트에 표시되는 트래픽 정보는 코어 통계 API에서 가져올 수도 있고 클라이언트가 연결을 자체 집계한 결과일 수도 있습니다. 화면에 트래픽 숫자가 보인다고 해서 설정의 모든 stats 필드가 활성화된 것은 아닙니다. 반대로 통계를 활성화했더라도 읽기 API가 없으면 화면에 결과가 표시되지 않을 수 있습니다. 문제를 해결할 때는 먼저 데이터가 생성되는 위치를 확인한 뒤 읽기 방식을 점검해 표시 계층 문제와 전달 장애를 구분하세요.

log의 액세스 기록, 오류 기록 및 수준

log에는 일반적으로 액세스 로그 위치, 오류 로그 위치, loglevel이 포함됩니다. 로그 수준은 문제 해결 필요에 따라 조정할 수 있습니다. 평상시에는 경고 수준을 사용하면 출력량을 줄일 수 있고, 설정 참조·DNS 선택·연결 핸드셰이크 문제가 있을 때는 일시적으로 상세 수준을 높일 수 있습니다. 문제를 재현하고 기록한 뒤에는 장기간 실행에 적합한 수준으로 되돌려 로그가 계속 커지거나 관련 없는 정보가 쌓이지 않도록 하세요.

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

상대 로그 경로는 보통 설정 파일이 있는 디렉터리가 아니라 코어의 작업 디렉터리를 기준으로 합니다. v2rayN 등의 클라이언트가 코어를 실행할 때 작업 디렉터리는 클라이언트가 결정할 수 있으므로, 파일을 직접 확인하기 전에 실제 실행 디렉터리를 확인해야 합니다. 경로의 디렉터리에 쓰기 권한이 없으면 코어가 로그 파일을 만들지 못하거나 시작 자체에 실패할 수 있습니다. 경로 차이를 피하려면 클라이언트가 제공하는 로그 보기 기능을 우선 사용하세요. 사용자 지정 경로가 필요할 때는 현재 시스템에서 확실히 쓸 수 있는 디렉터리를 지정하세요.

액세스 로그는 연결 대상과 처리 결과를 기록하고, 오류 로그는 조회·핸드셰이크·리소스 로드·모듈 이상을 기록합니다. 로그에는 대상 도메인, 주소, 로컬 연결 정보가 포함될 수 있으므로 문제와 무관한 개인 설정 데이터는 공유 전에 삭제해야 합니다. 전체 설정에 포함된 사용자 식별자, 서버 매개변수, 구독 내용도 공개 환경에 그대로 붙여 넣어서는 안 됩니다. 일반적으로 오류 행, 관련 모듈, 단순화한 필드 구조만 제공하면 충분합니다.

DNS 로그 및 라우팅 진단

일부 코어는 dnsLog 또는 더 상세한 로그를 통해 DNS 조회를 관찰할 수 있습니다. 이 옵션의 존재 여부와 구체적인 동작은 현재 코어 문서와 클라이언트가 생성한 설정을 기준으로 확인해야 합니다. 활성화한 뒤에는 조회 도메인, 선택된 서버, 반환 주소, 실패 원인을 중점적으로 확인하세요. 라우팅 진단에서는 인바운드 태그, 대상 정보, 매칭된 규칙, 최종 아웃바운드를 확인합니다. 두 기록을 함께 봐야 “도메인이 특정 주소로 조회된 뒤 왜 특정 IP 규칙에 의해 특정 출구로 분기되었는지” 설명할 수 있습니다.

로그의 첫 번째 오류는 뒤따르는 연쇄 오류보다 보통 더 중요합니다. 예를 들어 리소스 파일을 로드하지 못하면 많은 geosite 규칙이 연이어 실패하고, 포트 바인딩에 실패하면 애플리케이션 측에서 프록시를 사용할 수 없다는 알림이 잇따릅니다. 시간 순서대로 코어 시작 단계에서 가장 먼저 발생한 이상을 찾고, 이후 내용이 단순한 결과인지 판단하세요. 코어는 정상적으로 시작되지만 특정 대상을 방문할 때만 오류가 난다면 단일 연결 기록을 따라가면 됩니다.

API 및 관리 인터페이스의 경계

일부 설정은 API 인바운드를 통해 클라이언트에 통계, 로그, 실행 제어 기능을 제공합니다. 보통 그래픽 클라이언트가 자동으로 생성하며 로컬 주소에 바인딩됩니다. 이러한 인바운드의 태그·서비스 목록·라우팅 규칙을 수동으로 수정하면 클라이언트가 코어 상태를 읽지 못할 수 있습니다. API 포트를 일반 SOCKS나 HTTP 프록시 포트로 사용해서는 안 되며 로컬 네트워크에 함부로 공개해서도 안 됩니다. 클라이언트가 코어를 정상적으로 시작하지만 상태 표시줄이 갱신되지 않는다면 API 인바운드, API 아웃바운드로 보내는 라우팅 규칙, 클라이언트가 기대하는 포트를 비교하세요.

policy, stats, log, API는 모두 실행 관리 계층에 속합니다. 연결을 관찰하는 데 도움이 되지만 인바운드·라우팅·DNS·아웃바운드 흐름을 점검하는 일을 대신할 수는 없습니다. 최소 설정에서는 먼저 트래픽이 올바르게 통과하도록 만든 다음 통계와 관리 기능을 하나씩 활성화하세요. 이렇게 하면 관리 인터페이스에 문제가 생겨도 “코어가 전달하지 못하는 문제”와 “클라이언트가 상태를 표시하지 못하는 문제”를 명확히 구분할 수 있습니다.

08 / CHECK

구성 및 문제 해결: 문법 테스트부터 단일 연결 추적까지

검증 가능한 전체 흐름부터 만들기

구성을 조합할 때 많은 규칙, 여러 출구, 복잡한 DNS가 들어 있는 파일에서 바로 시작하지 마세요. 먼저 로컬 SOCKS 인바운드 하나, 매개변수가 완전히 확인된 프록시 아웃바운드 하나, 직접 연결 아웃바운드 하나, 명확한 라우팅 몇 개를 구성합니다. 코어가 시작되고 애플리케이션이 연결되며 두 출구가 각각 작동하는 것을 확인한 뒤 도메인 분류, 조건부 DNS, 차단 규칙, 통계 모듈을 추가하세요. 계층을 하나 추가할 때마다 테스트하면 문제가 발생했을 때 가장 최근 변경을 바로 확인할 수 있습니다.

그래픽 클라이언트 환경에서 설정 출처는 보통 세 계층입니다. 구독 또는 수동 노드는 원격 매개변수를 제공하고, 클라이언트 설정은 로컬 포트와 시스템 프록시 동작을 제공하며, 라우팅·DNS 템플릿은 트래픽 분기 로직을 제공합니다. 최종 실행 파일은 이 세 계층을 병합한 결과입니다. 노드 정보는 올바른데 실행에 실패한다면 실제 설정을 내보내거나 확인해 클라이언트가 서버 이름, 전송 방식, 아웃바운드 태그를 덮어쓰지 않았는지 확인하세요. 코어를 업그레이드하거나 전환한 뒤에는 이전 필드를 현재 코어가 여전히 허용하는지도 점검해야 합니다.

문법 및 설정 테스트 실행

코어에는 보통 설정만 테스트하고 장시간 실행하지 않는 명령이 제공됩니다. 명령 이름과 매개변수 형식은 코어 프로그램에 따라 다르며, 일반적인 형식은 다음과 같습니다. 실행할 때는 클라이언트가 실제로 호출하는 코어 파일과 실제 설정 경로를 사용해야 합니다. 그래픽 클라이언트에 “설정 확인”이나 로그 보기 기능이 있다면 이를 우선 사용하세요. 올바른 작업 디렉터리와 리소스 경로를 함께 적용하기 때문입니다.

v2ray test -c config.json

xray run -test -config config.json

테스트 통과는 JSON을 파싱할 수 있고 기본 모듈을 구성할 수 있다는 뜻이지, 원격 서버에 접근 가능하거나 모든 라우팅이 예상대로 작동한다는 뜻은 아닙니다. 테스트에 실패하면 출력된 필드 경로와 가장 먼저 발생한 오류부터 처리하세요. 지리 데이터 로드 실패라면 리소스 파일과 작업 디렉터리를 확인하고, 태그를 찾을 수 없다면 라우팅 참조를 확인하세요. 주소가 이미 사용 중이라면 인바운드 포트를 확인하고, 알 수 없는 필드라면 현재 코어 계열이 해당 설정을 지원하는지 확인하세요.

로컬 구조 검증용 통합 예시

아래 예시는 원격 프록시 인증 정보를 포함하지 않고 직접 연결과 차단 출구로 전체 모듈 관계를 보여줍니다. 로컬 인바운드, DNS, 라우팅, 로그 계층을 검증하는 데 사용할 수 있습니다. 실제 프록시 출구를 추가할 때는 서버가 제공한 프로토콜과 전송 필드를 하나의 완전한 객체로 삽입하고, 기본 규칙의 outboundTag를 해당 프록시 태그로 바꾸세요.

{
  "log": {
    "loglevel": "warning"
  },
  "dns": {
    "servers": ["localhost"]
  },
  "inbounds": [
    {
      "tag": "socks-in",
      "listen": "127.0.0.1",
      "port": 10808,
      "protocol": "socks",
      "settings": {
        "auth": "noauth",
        "udp": true
      },
      "sniffing": {
        "enabled": true,
        "destOverride": ["http", "tls"]
      }
    }
  ],
  "outbounds": [
    {
      "tag": "direct",
      "protocol": "freedom",
      "settings": {}
    },
    {
      "tag": "block",
      "protocol": "blackhole",
      "settings": {}
    }
  ],
  "routing": {
    "domainStrategy": "IPIfNonMatch",
    "rules": [
      {
        "type": "field",
        "domain": ["full:block.example"],
        "outboundTag": "block"
      },
      {
        "type": "field",
        "ip": ["geoip:private"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "network": "tcp,udp",
        "outboundTag": "direct"
      }
    ]
  }
}

증상에 따른 문제 해결 시작점 선택

증상 우선 확인할 항목 다음 단계
코어가 시작되지 않음 JSON 문법, 알 수 없는 필드, 리소스 경로, 포트 사용 여부 시작 단계의 첫 번째 오류 확인
애플리케이션이 로컬 프록시에 연결되지 않음 리스닝 주소, 포트, 프록시 유형, 프로세스 상태 인바운드에 연결 기록이 남는지 확인
모든 프록시 대상이 타임아웃됨 라우팅 출구, 서버 조회, 대상 포트, 전송 계층 direct와 proxy 아웃바운드를 각각 테스트
일부 도메인만 실패 DNS 조건, 라우팅 순서, 스니핑, 정적 매핑 조회 결과와 매칭된 규칙 기록
로컬 네트워크 주소에 접근할 수 없음 geoip:private, 로컬 네트워크 우회, 인바운드 리스닝 범위 private 규칙이 기본 규칙보다 앞서는지 확인
클라이언트 상태가 표시되지 않음 API 인바운드, 통계 스위치, 관리 라우팅 전달 장애와 표시 장애 구분

증상 분류의 목적은 관계없는 변경을 줄이는 것입니다. 코어가 시작되지 않을 때 서버 접근 가능 여부는 중요하지 않습니다. 애플리케이션이 로컬 포트에 연결되지 않으면 먼저 인바운드를 확인하고 원격 노드를 바꿀 필요가 없습니다. 일부 도메인만 실패한다면 해당 도메인과 정상 도메인이 DNS, 라우팅, 스니핑에서 어떻게 다른지에 집중하세요. 각 테스트에는 같은 출구에서 정상인 도메인, 같은 도메인을 direct로 연결한 결과, 복잡한 라우팅을 끈 같은 노드의 결과처럼 비교 대상을 하나씩 포함해야 합니다.

설정 수정 후 고정 점검 목록

저장 후 먼저 JSON 및 설정 테스트를 실행해 문법 오류와 모듈 초기화 오류가 없는지 확인하세요. 이어서 모든 태그 참조를 점검합니다. 각 outboundTag가 존재하고, 각 inboundTag가 실제 입구를 찾을 수 있으며, 부하 분산 또는 API 관련 태그 이름도 바뀌지 않았는지 확인하세요. 로컬 포트 충돌이 없고 클라이언트의 프록시 유형이 인바운드 프로토콜과 일치하는지도 확인합니다. 코어가 시작되면 직접 연결 규칙, 프록시 규칙, 사설 주소 규칙을 각각 테스트하고 마지막으로 UDP나 특수 애플리케이션을 테스트하세요.

DNS를 수정할 때는 조회 서버와 반환 주소를 추가로 기록하고, 라우팅을 수정할 때는 실제 매칭 규칙을 기록하며, 전송 계층을 수정할 때는 서버 매개변수와 대조하세요. 정책을 수정했다면 웹 페이지를 한 번 여는 것보다 장시간 연결의 동작을 관찰해야 합니다. 결과를 모듈별로 기록하는 편이 “수정하니 좀 빨라진 것 같다”는 판단보다 신뢰할 수 있습니다. 특정 애플리케이션에서만 문제가 재현된다면 해당 애플리케이션이 도메인을 직접 조회하는지, SOCKS UDP를 지원하는지, 시스템 프록시를 무시하는지, 기존 연결을 유지하는지도 비교해야 합니다.

클라이언트 설정과 수동 설정을 함께 관리하는 방법

v2rayN은 데스크톱 플랫폼에서 우선 고려할 관리 클라이언트로, 화면에서 구독·노드·라우팅·DNS를 관리하는 데 적합합니다. v2rayNG와 v2flyNG는 Android에서 사용하며 서로 다른 코어 계열에 대응합니다. 설치하거나 클라이언트를 다시 선택해야 한다면 설치 패키지 페이지로 이동하세요. 클라이언트가 실행 설정을 생성하는 경우에는 임시 생성 파일을 직접 편집하기보다 사용자 지정 설정, 라우팅 설정, DNS 설정 메뉴를 통해 변경하는 것이 좋습니다. 직접 편집한 내용은 재시작하거나 노드를 전환할 때 사라질 수 있습니다.

JSON을 수동으로 관리해야 한다면 안정적인 설정과 클라이언트의 임시 파일을 분리해 보관하고, 누가 코어를 시작할지 명확히 정하세요. 두 클라이언트가 같은 포트를 동시에 리스닝하게 하지 말고, 시스템 프록시가 이미 중지된 인스턴스를 계속 가리키지 않는지도 확인하세요. 구독 업데이트는 노드 출처만 갱신할 뿐 사용자 지정 라우팅과 DNS가 여전히 호환된다는 것을 보장하지 않습니다. 업데이트 후에는 병합 결과, 특히 아웃바운드 태그와 전송 계층 필드를 다시 확인해야 합니다.

재현 가능한 문제 해결 기록 만들기

효과적인 문제 해결 기록에는 발생 시간, 클라이언트와 코어 유형, 관련 인바운드 태그, 대상 도메인 또는 주소, 매칭된 아웃바운드, 첫 번째 오류 메시지, 이번에 변경한 필드가 포함되어야 합니다. 민감한 연결 매개변수가 들어 있는 설정 전체를 복사할 필요는 없습니다. 문제를 최소 구조로 줄이면 문법, 코어 호환성, 네트워크 접근성, 규칙 로직 중 어디에 문제가 있는지 판단하기 쉬워집니다.

기본 설정을 완료한 뒤 사용 안내서로 돌아가 클라이언트 작업 흐름을 확인하세요. 구독 이상, 라우팅 우선순위, DNS 분기, 포트 충돌을 처리할 때는 글 목록에서 장애 유형별로 계속 살펴볼 수 있습니다. 체계적인 설정의 목표는 필드를 무작정 늘리는 것이 아니라 모든 입구·매칭 조건·출구의 역할을 명확히 하고 로그와 비교 테스트로 그 동작을 설명할 수 있게 만드는 것입니다.

플랫폼에 맞는 클라이언트 선택

데스크톱 플랫폼에서는 v2rayN을 우선 사용하고, Android에서는 코어 요구 사항에 따라 v2rayNG 또는 v2flyNG를 선택하세요. 설치 후 이 페이지를 참고해 생성된 설정을 점검하세요.

설치 패키지 보기