v2rayN을 사용해 봤고 코어 설정 파일을 읽고 싶은 사용자에게 적합한 글입니다. 로컬 인바운드와 직접 연결·차단 아웃바운드만 포함한 JSON부터 실행한 다음, ‘앱 → 인바운드 → 라우팅 → 아웃바운드’ 순서로 각 필드를 확인합니다. 예제에는 원격 노드가 필요하지 않으며, 수신 포트와 태그 참조, 규칙 순서를 검증할 수 있습니다. VMess 또는 VLESS를 연결할 때는 서버 설정에 맞춰 아웃바운드를 바꾸면 됩니다.
1. 설정 흐름: 클라이언트·코어·JSON 구분하기
inbounds는 앱에서 전달된 트래픽을 받고, outbounds는 트래픽을 목적지나 원격 서버로 보냅니다. routing은 그사이에서 사용할 아웃바운드를 선택합니다. JSON은 설정 형식이지 노드 프로토콜이 아닙니다. 파일 확장자가 같다고 해서 서로 다른 코어에서 설정 파일 전체를 바꿔 쓸 수 있는 것은 아닙니다.
v2rayN은 구독 관리, 서버 편집, 라우팅 설정 기능을 제공하는 데스크톱 클라이언트입니다. 실제로 포트를 열고 연결을 처리하는 것은 선택한 코어입니다. Android용 v2rayNG는 Xray 코어를, v2flyNG는 V2Fly 코어를 사용합니다. 필드 호환성을 확인할 때는 클라이언트 이름만 보지 말고 실제로 실행 중인 코어를 먼저 확인하세요.
두 가지 설정 방법: 클라이언트에서 생성하기 또는 직접 관리하기
클라이언트에서 설정 생성
- 구독 또는 서버 편집 창에서 노드 정보를 입력합니다.
- 클라이언트가 로컬 포트, DNS, 라우팅 규칙을 구성해 코어에 전달합니다.
- 서버를 바꾸거나 코어를 다시 시작할 때 생성된 파일이 덮어써질 수 있습니다.
독립 JSON 설정 파일
- 인바운드와 아웃바운드, 태그 참조를 직접 관리합니다.
- 별도 디렉터리에서 코어 명령으로 먼저 설정을 검증합니다.
- 클라이언트에 가져오기 전에 사용자 지정 설정을 처리하는 방식을 확인하세요.
구조를 익힐 때는 별도 파일을 사용하세요. 일상적으로 사용하는 구독 노드는 클라이언트의 해당 설정 메뉴에서 수정하는 것이 좋습니다. 임시로 생성된 파일을 편집하면 변경 내용이 사라질 수 있습니다.
아래에서는 V2Ray의 기존 JSON 설정 구조에서 기본 필드를 사용하고, Xray 명령으로 검증하는 방법을 보여 줍니다. V2Fly는 메이저 버전에 따라 설정 형식과 명령이 다를 수 있습니다. 특히 TLS, REALITY, 전송 계층 설정은 코어 간에 그대로 옮겨 쓰지 마세요.
2. 최소 실행 설정: 인바운드 2개, 아웃바운드 2개
아래 내용을 UTF-8 인코딩의 config.json 파일로 저장하세요. 로컬에서 SOCKS 및 HTTP 프록시 포트를 열고 일반 트래픽은 직접 연결합니다. HTTP 인바운드로 들어온 요청 중 대상 도메인이 example.com인 경우에만 차단합니다. 여기서 ‘프록시 포트’는 로컬 접속 방식이며, 원격 프록시 서버를 거친다는 뜻은 아닙니다.
{
"log": {
"loglevel": "warning"
},
"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": "direct",
"protocol": "freedom",
"settings": {}
},
{
"tag": "block",
"protocol": "blackhole",
"settings": {}
}
],
"routing": {
"domainStrategy": "AsIs",
"rules": [
{
"type": "field",
"inboundTag": ["http-in"],
"domain": ["full:example.com"],
"outboundTag": "block"
},
{
"type": "field",
"ip": [
"10.0.0.0/8",
"172.16.0.0/12",
"192.168.0.0/16"
],
"outboundTag": "direct"
}
]
},
"dns": {
"servers": ["localhost"]
}
}
이 포트는 이 글에서 지정한 값이며 모든 클라이언트 버전의 기본값은 아닙니다. 실행 전에 같은 포트를 사용하는 프록시 프로세스를 종료하거나 JSON과 테스트 명령에 지정된 포트를 함께 변경하세요. 시스템 프록시와 TUN은 활성화하지 않았으므로, 지정된 포트로 요청을 보내는 앱만 코어에 연결됩니다.
3. inbounds: 수신 주소·포트·인바운드 태그
inbounds는 배열이며, 각 객체가 하나의 접속 지점을 나타냅니다. listen은 연결을 수신할 로컬 주소를, port는 수신 포트를, protocol은 앱과 코어 사이에서 사용할 프로토콜을 지정합니다. 앱에서 프로토콜을 잘못 선택하면 포트에 연결되더라도 요청이 제대로 전달되지 않습니다.
SOCKS 접속 지점
- tag
socks-in- listen
127.0.0.1- port
10808- protocol
socks- udp
true
앱에서 SOCKS5를 선택하세요. UDP 사용 가능 여부는 앱 자체와 이후 아웃바운드의 기능에도 달려 있습니다.
HTTP 접속 지점
- tag
http-in- listen
127.0.0.1- port
10809- protocol
http- settings
{}
앱에서 HTTP 프록시를 선택하세요. HTTPS 대상은 일반적으로 HTTP CONNECT를 통해 터널을 만듭니다.
127.0.0.1은 이 기기에서만 접속할 수 있습니다. 이를 0.0.0.0으로 바꾸면 IPv4 수신 범위가 넓어지므로 일반적인 호환성 문제 해결 방법으로 사용해서는 안 됩니다. 특히 예제의 SOCKS 인바운드는 noauth를 사용하므로 신뢰할 수 없는 네트워크에 직접 노출하지 마세요.
- 태그는 고정된 키워드가 아닙니다:
socks-in의 이름은 바꿀 수 있지만, 이를 참조하는 모든inboundTag도 함께 변경해야 합니다. - 인바운드 프로토콜은 노드 프로토콜이 아닙니다: 로컬 SOCKS 인바운드는 VMess 아웃바운드나 직접 연결 아웃바운드에 연결할 수 있습니다. 양쪽의 프로토콜이 같을 필요는 없습니다.
- UDP는 전체 기능을 켜는 스위치가 아닙니다:
udp: true는 SOCKS 인바운드에서 관련 기능을 허용할 뿐, 일반 HTTP 인바운드를 UDP 접속 지점으로 바꾸지는 않습니다.
4. outbounds: 기본 아웃바운드와 원격 노드의 차이
outbounds는 사용할 출구를 정의합니다. 예제의 direct는 freedom을 사용해 목적지에 직접 연결하고, block은 blackhole을 사용해 일치하는 연결을 버립니다. 일치하는 규칙이 없을 때 일반 라우팅은 아웃바운드 배열의 첫 번째 항목을 사용하므로, 이 예제의 기본 동작은 직접 연결입니다.
| 필드 또는 프로토콜 | 기능 | 설정 시 확인 사항 |
|---|---|---|
tag | 라우팅에서 참조할 아웃바운드 이름 | 고유하고 의미를 알기 쉬운 이름 사용 |
freedom | 목적지 주소에 직접 연결 | 원격 서버 계정 불필요 |
blackhole | 연결 차단 | 테스트 요청이 실패하는 것이 정상 |
vmess | VMess 서버에 연결 | 주소, 포트, 사용자 정보, 전송 설정 확인 |
vless | VLESS 서버에 연결 | 사용자 정보, 암호화 필드, 보안 계층 설정 확인 |
원격 노드를 연결할 때 protocol만 vless로 바꿔서는 안 됩니다. 프로토콜에 맞는 settings, 전송 계층의 streamSettings, 서버 설정이 모두 서로 맞아야 합니다. 주소, 포트, UUID, 전송 유형, TLS 서버 이름, 필요한 경우 flow는 각각 다른 역할을 합니다.
VMess와 VLESS는 ‘암호화 강도’를 선택하는 항목도 아닙니다. 특히 VLESS 자체는 서비스 트래픽의 전송 암호화를 제공하지 않으므로 서버 요구 사항에 맞는 TLS 또는 다른 보안 계층과 함께 사용해야 합니다. REALITY는 Xray 관련 기능입니다. 해당 필드를 V2Fly 설정에 그대로 넣어도 정상 작동하지 않습니다.
먼저 직접 연결 예제 유지
권장먼저 로컬 포트, JSON 형식, 라우팅 태그를 확인한 뒤 아웃바운드 설정을 한 번에 한 묶음씩 바꾸세요. 이렇게 하면 로컬 설정 오류와 원격 연결 오류를 구분하기 쉽습니다.
적합한 경우: 처음 설정 파일을 읽을 때, 시작 오류를 찾을 때, 규칙 순서를 검증할 때
사용 가능한 노드 아웃바운드 사용
정상 작동이 확인된 노드 설정에서 아웃바운드 객체 전체를 가져오세요. 서버가 요구하는 전송 및 보안 매개변수는 유지하고 로컬 태그 참조를 조정합니다.
적합한 경우: 사용 가능한 노드가 있고 기존 설정에 라우팅 규칙을 추가하려는 경우
5. routing: tag로 연결 흐름 구성하기
routing.rules는 위에서 아래로 검사되며, 처음 일치한 규칙이 해당 연결의 라우팅 결과를 결정합니다. 예제의 첫 번째 규칙에는 inboundTag와 domain이 함께 있으므로 두 조건이 모두 충족되어야 합니다. 같은 domain 배열에 여러 도메인을 넣으면 그중 하나만 일치해도 됩니다.
- 앱이
127.0.0.1:10809에 연결하면 코어는 해당 연결에 인바운드 태그http-in을 지정합니다. - 요청 대상은
example.com이며full:example.com의 정확한 도메인 조건과 일치합니다. - 첫 번째 규칙이 일치하면
outboundTag: "block"을 통해 해당 아웃바운드를 찾습니다. blackhole이 해당 연결을 처리하므로, 이후의 사설망 규칙은 이번 선택에 적용되지 않습니다.
full:example.com은 정확히 해당 도메인만 가리키며 하위 도메인은 포함하지 않습니다. 기본 도메인과 하위 도메인을 모두 일치시키려면 domain:example.com을 사용할 수 있습니다. 도메인 배열에 일반 문자열을 입력한 경우에도 이를 단순한 정확 일치로 이해해서는 안 됩니다.
두 번째 규칙에는 세 개의 IPv4 사설 네트워크 대역이 있으며, 목적지가 해당 IP 주소로 라우팅되면 직접 연결됩니다. 예제는 AsIs를 사용하므로 IP 조건에 일치시키기 위해 라우팅 단계에서 도메인을 먼저 조회하지 않습니다. 따라서 도메인이 최종적으로 사설 IP 주소로 해석되더라도 이 규칙에 반드시 일치하는 것은 아닙니다. 기본 동작도 직접 연결이므로 실제 결과는 같을 수 있지만, 일치하는 과정은 다릅니다.
기본 경로를 원격 노드로 지정하려면 사용 가능한 원격 아웃바운드를 배열 첫 번째에 두거나 규칙 마지막에 명시적인 기본 규칙을 추가하세요. 기본 규칙을 구체적인 차단 및 사설망 직접 연결 규칙보다 앞에 두면, 앞선 광범위한 조건이 뒤의 세부 규칙을 가릴 수 있습니다.
6. dns와 log: 이름 확인 정책과 로그 확인
dns.servers는 내장 DNS가 사용할 상위 DNS 서버를 정의합니다. 예제의 localhost는 시스템의 로컬 이름 확인 방식을 사용한다는 뜻입니다. 이 설정은 운영체제 DNS를 자동으로 바꾸거나 다른 앱의 DNS 요청을 자동으로 가로채지 않습니다. 코어의 관련 모듈이 이름 확인을 필요로 할 때에만 실제 처리 과정에 적용됩니다.
AsIs: 라우팅에서 원래 대상 형식을 유지하며, IP 규칙에 맞추기 위해 도메인을 IP로 변환하지 않습니다.IPIfNonMatch: 도메인이 기존 규칙에 일치하지 않으면 조회를 시도해 IP 규칙과 비교할 수 있습니다.IPOnDemand: 처리 중 IP 판별이 필요한 규칙을 만나면 도메인 조회를 수행할 수 있습니다.
이는 라우팅 계층의 정책이며 아웃바운드 연결 시의 이름 확인 정책과는 다릅니다. 라우팅에서 AsIs를 사용하더라도 직접 연결 아웃바운드가 도메인 대상에 연결할 때는 이름 확인이 필요할 수 있습니다. 앱이 처음부터 도메인을 IP로 변환했다면 코어가 원래 도메인을 알 수 없는 경우도 있습니다. 이 글의 테스트에서 socks5h를 사용하는 이유는 SOCKS 요청에 도메인 이름을 전달하기 위해서입니다.
log.loglevel을 warning으로 설정하면 경고와 오류부터 확인하기 좋습니다. 문제를 찾을 때는 일시적으로 info로 바꾸고, 필요하면 debug를 사용하세요. 액세스 로그와 오류 로그는 출력 설정이 따로 있으므로 로그 수준을 높인다고 전체 액세스 기록이 자동으로 활성화되지는 않습니다.
"log": {
"access": "access.log",
"error": "error.log",
"loglevel": "info"
}
위 코드는 전체 설정의 log 객체를 대체하기 위한 조각이며, 단독으로 실행할 수 있는 설정 파일이 아닙니다. 상대 로그 경로는 일반적으로 프로세스의 작업 디렉터리를 기준으로 해석됩니다. 클라이언트에서 실행할 때 작업 디렉터리가 JSON 파일이 있는 폴더와 다를 수 있습니다. 문제 해결이 끝나면 적절한 로그 수준으로 되돌리고, 로그를 공유하기 전에 서버 주소, 구독 주소, 계정 정보를 삭제하세요.
7. 저장·테스트·검증: 한 번에 하나씩 변경하기
먼저 현재 코어가 JSON을 읽을 수 있는지 확인하고, 다음으로 포트를 검증한 뒤 규칙 결과를 확인하세요. 설정 테스트 통과는 해당 검사를 통과했다는 뜻일 뿐, 실행 중 포트를 바인딩할 수 있다거나 원격 서버에 연결된다는 뜻은 아닙니다.
-
설정 파일 저장
Windows 11 파일 탐색기에서 ‘보기’ → ‘표시’ → ‘파일 이름 확장명’을 선택해 파일 이름이
config.json인지 확인하세요.config.json.txt로 저장하면 안 됩니다. 본문에는 영문 큰따옴표를 사용하고 주석이나 마지막 항목 뒤의 쉼표는 넣지 마세요. -
필드 검증
Xray 실행 파일이 있는 별도의 테스트 디렉터리에 설정 파일을 넣고, 해당 디렉터리에서 PowerShell을 열어 아래 테스트 명령을 실행하세요. V2Fly를 사용하는 경우에는 해당 코어의 명령 도움말을 먼저 확인하고 Xray 매개변수를 그대로 적용하지 마세요.
-
코어 실행
10808및10809를 사용하는 다른 프록시 프로세스를 종료한 다음 실행 명령을 입력하세요. 터미널 창을 열어 둔 채 포트 바인딩 실패나 필드 파싱 오류가 표시되는지 확인합니다. -
규칙 검증
SOCKS와 HTTP 테스트를 각각 실행하세요. 먼저 일반 사이트에 접속할 수 있는지 확인한 다음, 두 인바운드에서
example.com의 결과가 다른지 살펴봅니다. 테스트가 끝나면 코어 터미널에서 Ctrl+C를 눌러 프로세스를 중지하세요.
.\xray.exe run -test -config .\config.json
.\xray.exe run -config .\config.json
코어를 실행한 상태에서 다른 PowerShell 창을 열고 아래 명령을 입력하세요. 일부 환경에서 curl이 다른 명령으로 해석되는 일을 피하려면 curl.exe를 명시적으로 사용합니다. 각 명령의 15초 제한은 대기 시간을 제한하기 위한 것이며 성능 테스트를 뜻하지 않습니다.
curl.exe --max-time 15 --proxy socks5h://127.0.0.1:10808 https://example.org/
curl.exe --max-time 15 --proxy http://127.0.0.1:10809 https://example.com/
curl.exe --max-time 15 --proxy socks5h://127.0.0.1:10808 https://example.com/
| 테스트 요청 | 예상 라우팅 | 판단 기준 |
|---|---|---|
| SOCKS → example.org | direct | 규칙에 일치하지 않아 첫 번째 아웃바운드 사용 |
| HTTP → example.com | block | 인바운드 태그와 정확한 도메인이 모두 일치 |
| SOCKS → example.com | direct | 인바운드 태그가 달라 차단 규칙에 일치하지 않음 |
직접 연결 테스트에서 웹페이지를 받을 수 있는지는 현재 네트워크, 시스템 이름 확인, 대상 서버의 접근 가능 여부에 달려 있습니다. HTTP 차단 요청은 실패해야 하지만 실패 문구와 걸리는 시간은 연결 단계에 따라 달라질 수 있습니다. 한 번의 시간 초과만으로 규칙이 적용됐다고 단정하지 마세요. 인바운드, 대상 도메인, 규칙 순서, 로그를 함께 확인해야 합니다.
8. 자주 발생하는 설정 오류: 오류 위치에서 필드 확인하기
설정 문제는 구문, 구조, 실행 환경, 연결 매개변수의 네 단계로 나눌 수 있습니다. 오류가 표시되면 먼저 어느 단계인지 파악하세요. 로컬 포트 충돌을 노드 문제로 보거나 알 수 없는 필드를 네트워크 장애로 오해하지 않도록 합니다.
- JSON을 파싱할 수 없음: 오류 행 주변의 쉼표, 괄호, 따옴표를 확인하세요. 배열의 마지막 요소 뒤에 쉼표를 추가하면 안 됩니다. 필드 이름에는 큰따옴표를 사용하고 설명 문구를 파일에 그대로 붙여 넣지 마세요.
- 알 수 없는 프로토콜 또는 필드: 실제 실행 중인 코어와 버전을 확인하고 해당 코어의 설정 구조와 대조하세요. 다른 설정 파일에 같은 필드가 있다고 해서 현재 코어에서도 지원되는 것은 아닙니다.
- 포트 바인딩 실패:
10808및10809가 이미 사용 중인지 확인하세요. 포트를 변경한다면 앱의 프록시 설정과 테스트 명령도 함께 수정해야 합니다. - 시작은 되지만 규칙이 적용되지 않음: 앱이 지정된 인바운드로 연결되는지 확인한 뒤, 도메인이 여전히 도메인 형식으로 전달되는지, 태그가 일치하는지, 광범위한 규칙이 앞에 배치되어 있지는 않은지 살펴보세요.
- 가져온 뒤 설정이 바뀜: 직접 관리하는 전체 설정과 클라이언트가 생성하는 설정을 구분하세요. 생성 파일을 수정하는 동시에 클라이언트 UI에서 같은 실행 설정을 다시 저장하지 마세요.
전체 JSON, 단일 아웃바운드 객체, 노드 공유 링크, 구독 주소는 서로 다른 네 가지 입력입니다. 전체 설정에는 로컬 인바운드와 라우팅이 포함되지만, 구독은 일반적으로 클라이언트가 노드 정보를 가져오는 데 사용됩니다. 구독 주소 입력란에 전체 JSON을 붙여 넣거나 구독 주소를 아웃바운드 서버 주소로 사용해도 설정 구조가 자동 변환되지는 않습니다.