This guide is for users familiar with v2rayN who want to understand the configuration used by the core. Start with a working JSON file containing only local inbounds, direct and blocked outbounds, then trace each field through “application → inbound → routing → outbound.” No remote server is needed to test the listening ports, tag references, and rule order. When you connect a VMess or VLESS server, replace the outbound settings with the server’s parameters.
1. How the configuration fits together: client, core, and JSON
inbounds receive traffic from applications, outbounds send it to its destination or a remote server, and routing selects an outbound. JSON is a configuration format, not a proxy protocol. Using the same file extension does not mean configurations can be shared between different cores.
v2rayN is a desktop client with interfaces for managing subscriptions, editing servers, and setting up routing. The selected core is what actually listens on ports and handles connections. On Android, v2rayNG uses the Xray core, while v2flyNG uses the V2Fly core. When checking whether a field is supported, first identify the core that is actually running—not just the client name.
Two ways to configure: use the client or edit JSON manually
Client-generated configuration
- Enter server details through a subscription or the server editor.
- The client combines local ports, DNS, and routing rules, then passes the configuration to the core.
- Generated files may be overwritten when you switch servers or restart the core.
Standalone JSON configuration
- Maintain the complete configuration, including inbounds, outbounds, and tag references.
- Validate the configuration with a core command in a separate directory first.
- Before importing it into a client, check how the client handles custom configurations.
Use a standalone file to learn the configuration structure. For subscription-based setups, make changes in the relevant client settings to avoid editing a temporary generated file.
The examples below use basic fields from the traditional V2Ray JSON configuration format and Xray commands for validation. Different major V2Fly versions may use different configuration formats and commands. Do not copy TLS, REALITY, or transport settings between cores without checking compatibility.
2. A minimal working configuration: two inbounds and two outbounds
Save the following as a UTF-8 encoded config.json. It opens local SOCKS and HTTP proxy ports and sends ordinary traffic directly to the internet. Only requests that enter through the HTTP inbound and target example.com are blocked. Here, “proxy ports” refers to the local connection method; traffic is not sent through a remote proxy server.
{
"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"]
}
}
These ports are explicitly set for this guide; they are not defaults for every client version. Before running the configuration, close any proxy process using the same ports, or change the ports in both the JSON and test commands. The example does not enable the system proxy or TUN. Only application requests explicitly sent to these ports enter the core.
3. inbounds: listen address, port, and inbound tag
inbounds is an array in which each object defines an entry point. listen specifies the local address to accept connections on, port sets the listening port, and protocol determines the protocol between the application and the core. If the application uses the wrong protocol, connections may reach the port but requests will not be forwarded correctly.
SOCKS inbound
- tag
socks-in- listen
127.0.0.1- port
10808- protocol
socks- udp
true
Select SOCKS5 in the application. UDP support also depends on the application and the capabilities of subsequent outbounds.
HTTP inbound
- tag
http-in- listen
127.0.0.1- port
10809- protocol
http- settings
{}
Select HTTP proxy in the application. HTTPS destinations are usually tunneled using HTTP CONNECT.
127.0.0.1 allows connections from this machine only. Changing it to 0.0.0.0 exposes the listener on all IPv4 interfaces; this is not a routine compatibility fix. In particular, the example SOCKS inbound uses noauth and should not be exposed to untrusted networks.
- Tags are not reserved keywords: You can rename
socks-in, but update everyinboundTagreference to match. - Inbound and outbound protocols don’t have to match: A local SOCKS inbound can connect to a VMess outbound or a direct outbound. The protocols on either end can differ.
- UDP is not a global switch:
udp: trueenables the relevant capabilities on a SOCKS inbound; it does not turn a standard HTTP inbound into a UDP entry point.
4. outbounds: default routing versus remote servers
outbounds defines the available exits. In this example, direct uses freedom to connect directly to the destination, while block uses blackhole to discard matching connections. When no rule matches, normal routing uses the first outbound in the array, so this example defaults to a direct connection.
| Field or protocol | Purpose | What to check |
|---|---|---|
tag | Outbound name referenced by routing rules | Use a unique, descriptive name |
freedom | Connect directly to the destination | No remote server credentials required |
blackhole | Block the connection | The test request should fail |
vmess | Connect to a VMess server | Check the address, port, user settings, and transport |
vless | Connect to a VLESS server | Check the user settings, encryption fields, and security settings |
Connecting to a remote server takes more than changing protocol to vless. The protocol’s settings, transport-layer streamSettings, and server configuration must all match. The address, port, UUID, transport type, TLS server name, and—when required—flow each serve a different purpose.
VMess and VLESS are not “encryption strength” options. VLESS in particular does not encrypt application traffic in transit by itself; it must be paired with TLS or another security layer required by the server. REALITY is a feature associated with Xray. Adding its fields to a V2Fly configuration will not make it work.
Start with the direct-connection example
RecommendedFirst verify the local ports, JSON syntax, and routing tags, then replace one set of outbound settings at a time. This helps distinguish local configuration errors from remote connection issues.
Best for: learning the configuration, diagnosing startup failures, and checking rule order.
Use an outbound for a working server
Copy the complete outbound object from a verified working server configuration. Keep the required transport and security settings, then update the local tag references as needed.
Best for: users with a working server who want to add routing rules to an existing configuration.
5. routing: how tags connect the entire request path
routing.rules are checked from top to bottom; the first matching rule determines how the connection is routed. The first rule in this example includes both inboundTag and domain, so both conditions must match. Multiple domain entries in the same domain array are alternatives: any one can match.
- An application connects to
127.0.0.1:10809, and the core assigns the connection the inbound taghttp-in. - The request targets
example.com, matching the exact-domain conditionfull:example.com. - The first rule matches and selects the outbound identified by
outboundTag: "block". blackholehandles the connection. The private-network rule below is not considered for this routing decision.
full:example.com matches only the exact domain, not its subdomains. To match both the domain and its subdomains, use domain:example.com. A plain string in the domain array does not necessarily mean an exact match.
The second rule lists three private IPv4 ranges. Requests routed with a destination IP in one of these ranges go direct. Because the example uses AsIs, routing does not resolve a domain to an IP solely to check IP-based rules. So a domain resolving to a private IP does not necessarily match this rule. The example defaults to a direct connection anyway, so the final result may be the same even though the matching process differs.
To send unmatched traffic through a remote server by default, put a working remote outbound first in the array or add an explicit fallback rule at the end. Do not place a fallback before specific block and private-network direct rules, or the broader match may prevent those rules from being reached.
6. dns and log: check resolution and logging separately
dns.servers defines the upstream servers used by the built-in DNS module. In this example, localhost uses the system’s local resolution mechanism. This does not change the operating system’s DNS settings or automatically intercept DNS requests from other applications. These settings are only used when a relevant core module needs to resolve a name.
AsIs: Routing keeps the original destination as-is and does not resolve domain names to IP addresses for IP-based rules.IPIfNonMatch: If a domain does not match any existing rule, the core can try resolving it and checking IP-based rules.IPOnDemand: The core can resolve a domain when a rule requires an IP-based check.
These are routing-layer strategies, not resolution policies for outbound connections. Even with AsIs, a direct outbound may need to resolve a domain destination. If an application resolves a domain to an IP address first, the core may no longer have the original domain. The tests in this guide use socks5h so the SOCKS request carries the domain name.
log.loglevel set to warning is a good starting point for monitoring warnings and errors. For troubleshooting, temporarily switch to info, then use debug if needed. Access and error logs have separate output settings; increasing the log level does not automatically enable full access logging.
"log": {
"access": "access.log",
"error": "error.log",
"loglevel": "info"
}
Use the snippet above to replace the log object in a complete configuration; it is not a standalone configuration file. Relative log paths are usually resolved from the process working directory, which may differ from the JSON file’s directory when launched by a client. Restore an appropriate log level when troubleshooting is complete, and remove server addresses, subscription URLs, and account details before sharing logs.
7. Save, test, and verify: change one variable at a time
First check that the current core accepts the JSON, then verify the ports, and finally check the routing results. Passing a configuration test only confirms that the configuration passed that check. It does not guarantee that the ports can be bound at runtime or that a remote server is reachable.
-
Save the configuration
In Windows 11 File Explorer, select “View” → “Show” → “File name extensions” and confirm the file is named
config.json, notconfig.json.txt. Use standard double quotes in the JSON. Do not add comments or a trailing comma. -
Validate the fields
Place the configuration in a separate test directory alongside the Xray executable. Open PowerShell in that directory and run the test command below. If you use V2Fly, check the relevant core’s command help first; do not assume Xray options apply.
-
Start the core
Stop any other proxy processes using
10808or10809, then run the startup command. Keep the terminal open and watch for port-binding or field-parsing errors. -
Test the routing rules
Run the SOCKS and HTTP tests separately. First confirm that a regular website is reachable, then compare what happens to
example.comthrough each inbound. When finished, press Ctrl+C in the core’s terminal to stop the test process.
.\xray.exe run -test -config .\config.json
.\xray.exe run -config .\config.json
Keep the core running and execute the commands below in another PowerShell window. Use curl.exe explicitly to avoid environments where curl is interpreted as a different command. Each command has a 15-second timeout to limit waiting time; this is not a performance test.
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/
| Test request | Expected route | How to interpret it |
|---|---|---|
| SOCKS → example.org | direct | No rule matches; the first outbound is used |
| HTTP → example.com | block | Inbound tag and exact domain both match |
| SOCKS → example.com | direct | Inbound tag does not match, so the block rule is skipped |
Whether a direct-connection test returns a web page depends on the current network, system DNS resolution, and whether the destination is reachable. The blocked HTTP request should fail, but the error and time to failure may vary depending on the connection stage. A single timeout does not prove that the rule matched; check the inbound, destination domain, rule order, and logs together.
8. Common configuration errors: trace the message back to a field
Configuration issues fall into four categories: syntax, structure, runtime environment, and connection parameters. Identify the category before troubleshooting so you don’t mistake a local port conflict for a server problem or an unsupported field for a network failure.
- JSON parsing error: Check the commas, brackets, and quotes near the reported line. The last item in an array must not have a trailing comma. Field names must use double quotes, and explanatory text cannot be pasted directly into the file.
- Unknown protocol or field: Confirm which core and version are running, then check their configuration format. A field appearing in another configuration does not mean the current core supports it.
- Port binding failed: Check whether
10808or10809is already in use. If you change a port, update the application’s proxy settings and the test commands too. - Startup succeeds, but routing doesn’t work: Confirm that the application is using the intended inbound, then check whether the destination was passed as a domain name, whether the tags match, and whether a broad rule appears before the specific one.
- Settings change after import: Distinguish a manually maintained complete configuration from one generated by the client. Don’t edit a generated file and then save the same runtime settings again through the client interface.
A complete JSON configuration, a single outbound object, a server share link, and a subscription URL are four different types of input. A complete configuration includes local inbounds and routing; subscriptions are generally parsed by clients to retrieve server details. Pasting a complete JSON file into a subscription URL field—or using a subscription URL as a server address—will not convert it into the required format.