이 글의 핵심

노드를 가져온 뒤 실제 작동 설정을 이해하려는 사용자를 위한 글입니다. 로컬 포트에서 inbounds를 확인하고, 라우팅 규칙의 태그를 따라 outbounds를 찾은 다음 노드·전송·클라이언트 설정을 구분합니다. 연결이 어느 단계에서 실패했는지 파악하고, 설정 로드 성공과 노드 연결 성공이 서로 다르다는 점을 확인할 수 있습니다.

1. 클라이언트 설정과 코어 실행 설정 구분하기

config.json은 보통 코어가 읽는 JSON 파일을 가리키며, 파일명만으로 내용이 정해지지는 않습니다. v2rayN의 서버 목록, 구독 그룹, 화면 설정은 클라이언트가 관리하는 데이터입니다. 코어를 시작할 때 클라이언트는 선택한 서버와 라우팅 설정을 바탕으로 실행 설정을 생성합니다. 공유 링크 하나만 내보낸 파일은 inbounds와 라우팅을 포함한 전체 설정이 아닙니다.

설정을 읽을 때는 실제 실행 파일을 기준으로 삼아야 합니다. v2rayN은 버전에 따라 내보내기 메뉴와 생성 파일의 위치가 달라질 수 있으므로, 서버 공유 정보가 아니라 전체 설정을 내보냈는지 먼저 확인하세요. Android용 v2rayNG는 Xray 코어를, v2flyNG는 V2Fly 코어를 사용합니다. 기본 구조는 비슷하지만 확장 필드까지 모두 호환된다고 볼 수는 없습니다.

앱 요청로컬 인바운드라우팅 규칙 매칭아웃바운드 선택대상 서버

2. 익명화한 전체 config.json 예시

아래 예시는 클라이언트에서 내보낸 전체 설정 구조를 바탕으로, 로컬 인바운드 2개와 아웃바운드 3개, 라우팅 규칙 2개를 담았습니다. 주소와 사용자 정보는 예시 값으로 바꿨습니다. 완전한 JSON 문서이지만 실제 연결에 사용할 수 있는 노드는 아닙니다. example.com:443에 해당하는 VMess 서버가 있다는 뜻이 아니므로 네트워크 테스트에 그대로 사용하지 마세요.

{
  "log": {
    "loglevel": "warning"
  },
  "dns": {
    "servers": ["localhost"]
  },
  "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": "proxy",
      "protocol": "vmess",
      "settings": {
        "vnext": [
          {
            "address": "example.com",
            "port": 443,
            "users": [
              {
                "id": "11111111-1111-4111-8111-111111111111",
                "alterId": 0,
                "security": "auto"
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "tcp",
        "security": "tls",
        "tlsSettings": {
          "serverName": "example.com"
        }
      }
    },
    {
      "tag": "direct",
      "protocol": "freedom",
      "settings": {}
    },
    {
      "tag": "block",
      "protocol": "blackhole",
      "settings": {}
    }
  ],
  "routing": {
    "domainStrategy": "AsIs",
    "rules": [
      {
        "type": "field",
        "domain": ["full:example.org"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "ip": ["geoip:private"],
        "outboundTag": "direct"
      }
    ]
  }
}

3. inbounds: 리슨 주소·포트·앱 프록시 유형

첫 번째 인바운드는 127.0.0.1:10808에서 SOCKS 요청을 받고, 두 번째 인바운드는 127.0.0.1:10809에서 HTTP 프록시 요청을 받습니다. 이 포트는 이 글의 예시 값이며 사용 중인 클라이언트와 다를 수 있습니다. 앱에 입력할 포트는 앱에서 선택한 프록시 유형에 따라 달라집니다. 대상 웹사이트가 HTTP인지 HTTPS인지는 기준이 아닙니다.

SOCKS 인바운드

태그
socks-in
리슨 주소
127.0.0.1
포트
10808
프로토콜
socks

앱에서 SOCKS5를 선택한 경우 이 주소를 입력하세요. UDP를 사용하려면 앱과 이후 연결 경로도 UDP를 지원해야 합니다.

HTTP 인바운드

태그
http-in
리슨 주소
127.0.0.1
포트
10809
프로토콜
http

앱에서 HTTP 프록시를 선택한 경우 이 주소를 입력하세요. HTTPS 대상은 보통 CONNECT로 터널을 만듭니다.

listen이 루프백 주소이면 이 컴퓨터에서만 연결할 수 있습니다. LAN에서 공유하려고 0.0.0.0으로 바꾸면 리슨 범위가 넓어지므로 인증과 방화벽도 함께 고려해야 합니다. 주소만 바꾸면 되는 것이 아닙니다. 이 예시의 SOCKS 인바운드에 설정된 auth: "noauth"는 인증을 요구하지 않는다는 뜻이므로 로컬에서만 사용해야 합니다.

udp: true는 SOCKS 인바운드에서 UDP를 사용할 수 있게 할 뿐, 시스템 전체의 UDP 트래픽을 자동으로 프록시로 보내지는 않습니다. HTTP 인바운드도 같은 기능을 지원한다는 뜻은 아닙니다. 앱이 이 인바운드를 사용하지 않으면 코어가 정상적으로 시작되어도 기대한 프록시 연결은 이루어지지 않습니다.

4. outbounds: 노드 정보·전송 방식·출구 태그

outbounds는 여러 출구를 담을 수 있는 배열입니다. 이 예시의 첫 번째 출구 태그는 proxy이고 프로토콜은 VMess입니다. vnext의 address와 port는 원격 서버 주소와 포트이며, users의 id는 사용자 식별 정보입니다. 여기서 443은 원격 포트로, 로컬 포트 10808이나 10809를 대신하지 않습니다.

필드예시 값확인할 내용
protocolvmess프록시 프로토콜과 해당 settings 구조를 결정합니다.
users[].securityautoVMess 사용자 계층의 암호화 옵션이며 TLS 설정은 아닙니다.
users[].alterId0VMess AEAD에서 흔히 사용하는 설정으로, 서버 요구 사항과 일치해야 합니다.
streamSettings.networktcp이 예시에서 사용하는 전송 방식입니다. 이름과 지원 값은 코어 버전에 따라 달라질 수 있습니다.
streamSettings.securitytls전송 계층 TLS를 활성화합니다. 사용자 계층의 security와는 별개로 동작합니다.
tlsSettings.serverNameexample.comTLS 서버 이름과 인증서 이름을 확인할 때 사용합니다.

direct는 freedom을 사용해 대상에 직접 연결하고, block은 blackhole을 사용해 트래픽을 차단합니다. 두 이름은 태그일 뿐이며 실제 동작은 protocol이 결정합니다. freedom의 태그를 “proxy”로 바꿔도 원격 프록시로 바뀌지 않습니다. 이 예시에서는 어떤 규칙도 block을 참조하지 않으므로, 아웃바운드를 선언하는 것만으로 요청이 차단되지는 않습니다.

설정 호환성 확인: 프로토콜과 코어 필드부터 살펴보기

VMess의 protocol을 VLESS로 바꾸고 바로 실행하지 마세요. 두 프로토콜은 사용자 정보와 암호화 필드 구조가 다릅니다. REALITY 같은 확장 기능을 사용할 때는 파일명만 보고 판단하지 말고, 현재 실행 중인 코어가 해당 필드를 지원하는 Xray인지 확인해야 합니다.

5. routing: 규칙 순서·tag 참조·기본 출구

라우팅 규칙은 위에서 아래로 확인하며, 조건에 맞는 규칙이 나오면 해당 출구를 선택합니다. 이 예시의 첫 번째 규칙은 도메인 전체가 example.org와 일치하는 연결만 direct로 보냅니다. full:은 도메인 전체 일치를 뜻하며 하위 도메인까지 함께 매칭하지 않습니다. 두 번째 규칙은 사설 IP 범위에 해당하는 대상을 같은 출구로 보냅니다. 어떤 규칙에도 해당하지 않는 연결은 outbounds의 첫 번째 항목인 proxy를 사용합니다.

  1. 연결 대상이 도메인 example.org인 경우: 첫 번째 규칙이 적용되어 tag: "direct"인 아웃바운드를 찾습니다.
  2. 연결 대상이 주소 192.168.1.20인 경우: 두 번째 사설 주소 규칙이 적용되어 LAN 대상에 직접 연결합니다.
  3. 다른 규칙에 해당하지 않는 도메인에 연결하는 경우: 첫 번째 아웃바운드인 proxy를 사용해 예시 VMess 서버에 연결을 시도합니다.

outboundTag는 아웃바운드의 tag와 대소문자까지 정확히 일치해야 합니다. 인바운드 태그는 규칙의 inboundTag 배열에 넣어 매칭에 사용할 수 있습니다. 예를 들어 ["socks-in"]의 연결만 처리할 수 있습니다. 인바운드 태그와 아웃바운드 태그는 자동으로 짝을 이루지 않으며 이름이 같을 필요도 없습니다.

이 예시는 domainStrategy: "AsIs"를 사용하므로 라우팅 단계에서 IP 규칙을 위해 도메인을 먼저 해석하지 않습니다. 따라서 연결이 도메인 형태로 들어오면 두 번째 사설 IP 규칙이 실제로 연결될 LAN 주소를 인식하지 못할 수 있습니다. 이런 동작이 필요하다면 IPIfNonMatch 또는 IPOnDemand의 DNS 조회 시점을 먼저 확인하고 DNS 설정과 함께 조정하세요. 모든 도메인 요청에 대상 IP가 이미 있다고 가정해서는 안 됩니다.

라우팅을 바꾸기 전에 첫 번째 아웃바운드 기록하기

direct를 배열 첫 번째로 옮기면 어떤 규칙에도 해당하지 않는 연결의 기본 출구가 바뀝니다. 규칙 변경과 아웃바운드 순서 변경은 따로 진행하고, 한 번에 하나씩만 수정하세요. 그래야 기본 직접 연결을 규칙 오작동으로 오해하지 않습니다.

6. dns와 log: 설정 로드와 연결 성공은 별개

이 예시의 dns.servers는 localhost를 사용합니다. 내장 DNS가 이름을 해석해야 할 때 시스템의 DNS 해석 기능을 호출할 수 있다는 뜻입니다. 로컬에 DNS 서버 포트를 연다는 뜻도 아니고, 앱이 다른 DNS 서버로 보내는 요청을 자동으로 가로챈다는 뜻도 아닙니다. 라우팅용 DNS 조회, 아웃바운드용 DNS 조회, 앱 자체의 DNS 조회는 서로 다른 위치에서 일어나므로 실제 인바운드 방식에 맞춰 확인해야 합니다.

loglevel: "warning"은 일반 연결 정보를 줄여 표시합니다. 문제를 확인할 때는 잠시 info로 바꾸고 코어를 재시작한 뒤 실패한 요청을 한 번 재현하세요. 확인이 끝나면 원래 설정으로 되돌립니다. 로그에는 접속 도메인, 대상 주소, 설정 파일 경로가 포함될 수 있으므로 공개적으로 도움을 요청하기 전에 구독 링크, 사용자 식별 정보, 개인 경로를 삭제하세요.

7. config.json 자주 묻는 질문

파일은 열리는데 코어에서 설정 오류가 발생하는 이유는 무엇인가요?

텍스트 편집기에서 파일을 열 수 있다고 해서 올바른 JSON이라는 뜻은 아닙니다. 먼저 끝에 붙은 쉼표, 큰따옴표, 괄호를 확인한 뒤 로그를 참고해 문제가 있는 필드를 찾으세요. 문법이 맞더라도 현재 코어에서 지원하는 구조인지 확인해야 합니다. 예를 들어 아웃바운드 객체를 inbounds 배열에 넣으면 안 됩니다.

HTTP 프록시 설정에 10808을 입력했는데 연결되지 않는 이유는 무엇인가요?

이 예시에서 10808은 SOCKS 요청을 받고 10809는 HTTP 프록시 요청을 받습니다. 앱에서 프록시 유형을 SOCKS5로 바꾸고 10808을 사용하거나, HTTP 유형을 유지한 채 10809를 입력하세요. 실제로 설정하기 전에는 현재 실행 설정의 포트를 다시 확인해야 합니다.

설정에 proxy가 있는데 트래픽이 직접 연결되는 이유는 무엇인가요?

먼저 앱이 로컬 인바운드에 실제로 연결되어 있는지 확인한 다음, 적용된 규칙이 direct를 가리키는지 살펴보세요. proxy는 태그일 뿐 시스템 프록시를 자동으로 켜지 않습니다. 클라이언트의 시스템 프록시 스위치와 코어의 라우팅 설정을 각각 확인해야 합니다.

PC의 전체 설정을 Android 클라이언트에 그대로 가져올 수 있나요?

먼저 대상 클라이언트가 지원하는 코어 필드와 가져오기 방식을 확인하세요. PC의 리슨 포트, 로그 경로, 라우팅 데이터 의존성은 Android 환경에 적합하지 않을 수 있습니다. 서버 정보만 동기화하려면 구독이나 노드 공유 정보를 가져온 뒤 대상 클라이언트에서 로컬 리슨과 라우팅을 설정하세요. 실행 설정 전체를 덮어쓰지는 마세요.