2026-10-15 · 설정 해설 · 약 12분

V2Ray config.json 설정 완벽 해설: inbounds·outbounds·routing 작성법

V2Ray config.json의 기본 구조부터 inbounds, outbounds, routing 규칙까지 살펴봅니다. JSON 예제로 클라이언트 설정을 이해해 보세요.

이 글 한눈에 보기

노드를 가져왔지만 클라이언트가 생성한 설정 파일을 이해하기 어려운 분을 위한 글입니다. 먼저 로컬 10808 포트와 직접 연결 출구로 설정 구조를 확인한 다음, VMess 출구와 도메인 라우팅 예제로 각 필드의 관계를 살펴봅니다. 로컬 수신, 원격 연결, 규칙 매칭, 클라이언트 설정을 구분하고 구독 링크와 config.json의 차이를 이해할 수 있습니다.

1. config.json의 최상위 구조와 요청 흐름

config.json은 코어가 읽는 설정 파일 이름 중 하나일 뿐, 저장 위치가 정해져 있는 것은 아닙니다. v2rayN 등의 클라이언트는 임시 실행 설정을 생성할 수 있으며, 생성된 파일을 직접 수정하면 다음에 노드를 바꿀 때 변경 내용이 덮어써질 수 있습니다. 먼저 현재 실행 중인 코어가 Xray인지 V2Fly인지 확인한 뒤, 실제로 불러온 설정 파일과 시작 로그를 살펴보세요.

앱 요청 인바운드 수신 라우팅 매칭 아웃바운드 연결 대상 서비스

inbounds와 outbounds는 각각 여러 개의 인바운드와 아웃바운드를 설정할 수 있는 배열입니다. routing은 객체이며, 그 안의 rules가 규칙 배열입니다. tag는 설정 내부에서 참조하는 이름이지 서버 주소가 아닙니다. 규칙은 outboundTag로 아웃바운드를 지정합니다.

아래는 로컬 직접 연결 테스트에만 사용하는 기본 설정 전체 예시입니다. 루프백 주소에서 SOCKS 서비스를 열고, 규칙에 걸리지 않은 요청은 첫 번째 아웃바운드인 direct로 보냅니다. 원격 프록시 노드는 포함되어 있지 않으며 시스템 프록시도 자동으로 변경하지 않습니다.

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

2. inbounds: 수신 주소, 포트, 로컬 프로토콜

인바운드는 앱이 트래픽을 코어에 전달하는 방식을 정합니다. 위 예시의 127.0.0.1:10808은 로컬 SOCKS 인바운드이며 원격 노드 포트가 아닙니다. 브라우저, 명령줄 도구 등 SOCKS를 지원하는 프로그램에서 이 주소를 명시적으로 사용해야 트래픽이 코어로 들어옵니다.

로컬 SOCKS 인바운드

tag
local-socks
listen
127.0.0.1
port
10808
protocol
socks

로컬 기기의 연결만 받습니다. 앱에서 SOCKS 프로토콜을 선택해야 합니다.

선택 사항: HTTP 인바운드

tag
local-http
listen
127.0.0.1
port
10809
protocol
http

inbounds에 별도로 추가해야 합니다. SOCKS 인바운드에 자동으로 포함되지 않습니다.

10808과 10809는 이 글에서 사용하는 예시 값이며, 모든 버전의 고정 기본값은 아닙니다. 앱의 HTTP 프록시를 SOCKS 포트에 바로 연결하면 프로토콜이 맞지 않습니다. 클라이언트가 혼합 인바운드를 제공한다면 포트 번호를 보고 추측하지 말고, 해당 인바운드가 실제로 지원하는 프로토콜을 확인하세요.

아래 명령으로 앱이 예시 인바운드를 통해 HTTPS 요청을 보낼 수 있는지 확인하세요. Windows에서는 curl.exe, macOS와 Linux에서는 curl을 사용할 수 있습니다. socks5h는 대상 도메인을 프록시 쪽에서 처리하도록 지정합니다. 프록시가 실제로 도메인을 해석하는 방식은 설정에 따라 달라집니다.

curl --proxy socks5h://127.0.0.1:10808 --connect-timeout 10 -I https://example.com

3. outbounds: 원격 노드와 전송 매개변수

아웃바운드는 코어가 대상에 연결할 경로를 정합니다. freedom은 직접 연결, blackhole은 차단, vmess는 원격 서버와의 연동을 뜻합니다. 인바운드는 SOCKS, 아웃바운드는 VMess로 설정할 수 있습니다. 연결 경로에서 담당하는 위치가 다르므로 두 이름이 같을 필요는 없습니다.

아래는 최상위 outbounds를 교체하는 예시입니다. 192.0.2.10은 문서용 예시 주소이며 UUID와 도메인도 구조 설명을 위한 값이므로 그대로 연결할 수 없습니다. 실제로 사용할 때는 주소, 포트, 사용자 식별자, 전송 방식, TLS 매개변수를 모두 권한이 있는 서버 설정에 맞춰야 합니다. 필드 하나만 바꿔서는 안 됩니다.

{
  "outbounds": [
    {
      "tag": "proxy",
      "protocol": "vmess",
      "settings": {
        "vnext": [
          {
            "address": "192.0.2.10",
            "port": 443,
            "users": [
              {
                "id": "b43b4b90-a710-4ee4-883d-b8c574099d11",
                "alterId": 0,
                "security": "auto"
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "tcp",
        "security": "tls",
        "tlsSettings": {
          "serverName": "proxy.example.net"
        }
      }
    },
    {
      "tag": "direct",
      "protocol": "freedom",
      "settings": {}
    },
    {
      "tag": "block",
      "protocol": "blackhole",
      "settings": {}
    }
  ]
}
필드 위치예시 값확인 사항
settings.vnext[].address192.0.2.10원격 연결 주소입니다. 로컬 수신 주소가 아닙니다.
settings.vnext[].port443서버가 연결을 받는 포트입니다. 10808이 아닙니다.
users[].securityautoVMess 사용자 암호화 옵션이며 TLS 설정이 아닙니다.
streamSettings.networktcp이 예시는 TCP 전송을 사용합니다. 다른 전송 방식에는 별도 설정이 필요합니다.
streamSettings.securitytls전송 계층의 보안 방식입니다. 프로토콜 내부의 security와는 의미가 다릅니다.
tlsSettings.serverNameproxy.example.netTLS 서버 이름입니다. 서버 설정 및 인증서와 일치해야 합니다.

정리: 프로토콜을 확인한 다음 전송 방식을 점검하세요

VMess를 VLESS로 바꿀 때 protocol만 수정해서는 안 됩니다. 사용하는 코어의 설정 규격에 따라 settings를 확인한 다음 streamSettings를 점검하세요. TLS 연결에 실패하면 도메인, 인증서, 시스템 시간을 확인하고, 일반적인 해결책으로 인증서 검증을 끄지는 마세요.

v2rayNG는 Xray 코어를 사용하고 v2flyNG는 V2Fly 코어를 사용합니다. v2rayN에서 사용할 수 있는 코어는 실제 설치 및 선택 상태에 따라 다릅니다. 최상위 구조가 비슷하더라도 확장 필드가 모두 호환되는 것은 아니며, 특히 VLESS의 일부 보안 조합은 주의해야 합니다. 이 글의 TCP 필드 예시는 일반적인 설정을 설명하기 위한 것입니다. 실제 필드 이름과 호환 여부는 설치된 코어 버전에 맞춰 확인하세요.

4. routing: 규칙 순서, 태그 참조, 기본 출구

라우팅은 도메인을 몇 개 그룹으로 묶으면 자동으로 적용되는 기능이 아닙니다. 규칙을 순서대로 확인하며, 일반적으로 먼저 일치한 규칙이 출구를 결정합니다. 한 규칙에 지정된 서로 다른 조건은 모두 충족해야 하고, 같은 조건 배열에 있는 여러 값은 그중 하나와 일치하면 됩니다. outboundTag는 기존 아웃바운드의 tag와 정확히 일치해야 합니다.

아래 예시는 앞 절에서 설정한 proxy, direct, block 아웃바운드를 사용합니다. 예시 도메인 하나를 먼저 차단하고, 사설 IP 주소는 직접 연결하며, 나머지 트래픽은 프록시로 보냅니다. 두 도메인은 규칙 설명을 위한 예시일 뿐, 실제 접속을 권장하는 것은 아닙니다.

{
  "routing": {
    "domainStrategy": "AsIs",
    "rules": [
      {
        "type": "field",
        "domain": ["full:blocked.example.org"],
        "outboundTag": "block"
      },
      {
        "type": "field",
        "ip": ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "domain": ["domain:example.org"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "network": "tcp,udp",
        "outboundTag": "proxy"
      }
    ]
  }
}
  1. full:blocked.example.org는 해당 도메인 전체와 일치합니다. example.org의 하위 도메인이기도 하지만, 차단 규칙이 앞에 있으므로 우선 차단됩니다.
  2. 사설 네트워크 대역 규칙은 대상 IP가 지정된 범위에 속하는 요청을 처리합니다. 모든 특수 주소를 망라한 목록은 아니며 IPv6 로컬 주소도 자동으로 포함하지 않습니다.
  3. domain:example.org는 해당 도메인과 하위 도메인에 일치합니다. 문자열에 임의로 포함되는 것과는 다릅니다.
  4. 마지막의 network: "tcp,udp"는 이 예시의 기본 규칙입니다. 구체적인 규칙 뒤에 배치해야 하며, 앞에 두면 의도한 분기 규칙이 먼저 적용되지 않을 수 있습니다.

일치하는 규칙이 없으면 보통 outbounds 배열의 첫 번째 아웃바운드를 사용합니다. 첫 번째 절에서는 첫 아웃바운드가 direct였고, 세 번째 절에서는 proxy로 바뀌었습니다. 따라서 배열 순서만 바꿔도 기본 동작이 달라질 수 있습니다. 배열에 프록시 노드가 있다는 이유만으로 모든 요청이 프록시를 거친다고 판단하지 마세요.

5. dns, 로그, 클라이언트 생성 설정의 범위

routing.domainStrategy는 라우팅 매칭 단계에서 도메인을 처리하는 방식을 제어합니다. DNS 서버 주소나 전체 DNS 분기 설정이 아닙니다. AsIs는 가능한 한 원래 대상 정보를 유지해 매칭하고, IPIfNonMatch는 도메인 규칙이 일치하지 않을 때 IP로 해석한 뒤 IP 규칙을 추가로 확인하며, IPOnDemand는 IP 규칙을 확인하는 과정에서 필요에 따라 DNS 조회를 수행할 수 있습니다.

아래 예시는 내장 DNS 설정만 추가하며 운영체제 DNS를 자동으로 변경하지 않고, 모든 앱의 DNS 요청이 코어로 전달된다고 보장하지도 않습니다. 앱이 연결 전에 로컬에서 이미 도메인을 해석했다면 코어에는 IP만 전달될 수 있습니다. 프록시 프로토콜로 도메인을 전달하는 경우에는 아웃바운드와 서버에 따라 최종 해석 위치가 달라질 수 있습니다.

{
  "dns": {
    "servers": ["localhost"]
  }
}

클라이언트에서 내보낸 설정을 볼 때는 먼저 inbounds[].port, outbounds[].tag, routing.rules를 찾고 DNS와 전송 설정을 확인하세요. 알 수 없는 관리용 인바운드나 추가 필드를 바로 삭제하지 마세요. 클라이언트 통계, 제어 인터페이스 또는 런타임 기능에 필요할 수 있습니다. 로그를 공유하기 전에는 사용자 식별자, 구독 주소, 서버 정보를 삭제하세요.

6. 설정 변경 후 확인 순서와 자주 묻는 질문

변경 전에 복구 가능한 설정 사본을 보관하고, 한 번에 한 항목만 수정하세요. 먼저 JSON 문법과 코어 필드를 확인하고, 포트 수신 상태를 점검한 다음 원격 연결과 규칙 매칭을 테스트합니다. 아래 명령은 해당 명령줄 인터페이스를 제공하는 최신 코어에서 사용할 수 있습니다. 실제 매개변수는 설치된 프로그램의 도움말을 확인하고, 클라이언트가 관리하는 설정은 실제로 불러오는 파일 경로를 사용하세요.

xray run -test -config config.json
v2ray test -c config.json

테스트 명령이 성공해도 노드가 정상 작동한다는 뜻은 아닙니다. 현재 코어가 설정을 받아들이는지만 주로 확인하며, 원격 인증, TLS 핸드셰이크, 대상 서비스 접속을 대신 테스트하지 않습니다. 코어는 시작되지만 앱 연결이 실패한다면 로컬 인바운드, 원격 아웃바운드, 라우팅 결과 순으로 범위를 좁혀 보세요.

address already in use가 표시되면 어떤 포트를 먼저 바꿔야 하나요?

먼저 사용 중인 인바운드 포트를 확인하세요. 로그에 10808이 표시되면 중복 실행 중인 코어를 종료하거나 inbounds의 포트를 10810으로 변경하고 앱의 프록시 주소도 함께 수정하세요. 이 문제 때문에 원격 노드의 443 포트를 변경해서는 안 됩니다.

코어는 시작되는데 curl 연결은 계속 실패하나요?

먼저 첫 번째 절의 직접 연결 설정과 socks5h 테스트 명령으로 인바운드를 확인하세요. 로컬 포트 연결부터 실패한다면 수신 주소, 포트, 프록시 프로토콜을 점검하세요. 연결이 코어에 도달한 뒤 시간 초과가 발생한다면 원격 주소, 인증, TLS 로그를 확인하세요.

direct 규칙을 추가했는데 왜 여전히 proxy로 연결되나요?

규칙 순서와 outboundTag 철자를 확인하고, 코어에 도메인과 IP 중 무엇이 전달됐는지 살펴보세요. 기본 규칙이 앞에 놓여 있지 않은지 확인한 다음, 수정한 파일이 실제로 현재 프로세스에서 사용되는지도 확인하세요. 클라이언트가 설정을 다시 생성해 다른 파일을 불러오고 있을 수 있습니다.

구독을 업데이트했더니 직접 수정한 JSON이 사라졌어요. 왜 그런가요?

클라이언트가 노드와 전역 설정을 바탕으로 실행 설정을 다시 생성했을 수 있습니다. 설정을 계속 유지하려면 클라이언트가 제공하는 라우팅, 인바운드 또는 사용자 지정 설정 기능을 이용하세요. 완전한 JSON을 직접 관리하려면 파일 경로와 코어 실행 방식도 명확히 정해 두어야 두 설정이 서로 덮어쓰는 일을 막을 수 있습니다.

정리: 요청 하나로 변경 사항 하나씩 확인하세요

먼저 로컬 인바운드 127.0.0.1:10808과 테스트 대상을 고정한 뒤 직접 연결, 프록시, 라우팅을 각각 확인하세요. 포트, DNS, 전송 매개변수를 한꺼번에 바꾸기보다 설정을 다시 불러올 때마다 로그를 확인하면 문제가 발생한 계층을 찾기 쉽습니다.

클라이언트 다운로드