This guide is for users who can import nodes but are not yet comfortable reading core configuration or log fields. By the end, you will know which section handles local listening, remote connections, and traffic routing—and how to follow a tag from request entry to rule match to final outbound.
Start with the big picture: a config file is more than one node
V2Ray 5.x uses JSON to describe how the core runs. A complete client configuration usually includes more than a server address and user ID: it defines local traffic entry points, outbound connections, DNS behavior, log level, and routing rules. The “one node” shown in a graphical client mainly represents a set of server parameters in a proxy outbound, not the complete runtime configuration.
When reading a configuration, set protocol details aside and think of the data flow in three stages: an application sends a request to a local listening port, inbounds receives and identifies it, routing selects a destination based on the domain, IP, port, or protocol, and an outbounds entry sends it onward. Inbounds and outbounds are named with tag, and routing rules refer to those names.
Top-level fields do not have a required order. A JSON parser will not change the result just because routing appears before outbounds. Array order can matter, however: routing rules are usually checked from top to bottom, while traffic that matches no rule generally goes to the first outbound. When reading a config, check both the tag and the item’s position in its array.
inbounds
- Direction
- Application to core
- Common protocols
- SOCKS、HTTP
- Key fields
- listen、port、tag
- Typical ports
- 10808
Determines which local addresses and ports can pass traffic to the core.
outbounds
- Direction
- Core to destination
- Proxy protocols
- VMess、VLESS
- Auxiliary outbounds
- freedom、blackhole
- Identification
- tag
Node server details, transport, and TLS parameters are mainly defined here.
routing
- Rule type
- field
- Match target
- Domain, IP, port
- Result
- outboundTag
- Evaluation order
- Top to bottom
Selects the outbound; it does not establish the remote protocol connection.
dns and log
- dns
- Resolution strategy
- log
- Log level
- Common level
- warning
- Troubleshooting level
- info
Not every configuration declares these explicitly, but they directly affect name resolution and troubleshooting.
inbounds: where traffic enters from the local machine
inbounds is an array in which each object represents a local entry point. Desktop clients commonly create both SOCKS and HTTP inbounds—for example, SOCKS on 127.0.0.1:10808 and HTTP on 127.0.0.1:10809. Once a browser, command-line tool, or system proxy sends a request to the relevant port, the core can process the connection.
listen sets the listening address. With 127.0.0.1, only local connections are accepted; with 0.0.0.0, every network interface is listened on, which may expose the port to devices on the local network. Unless a LAN proxy is explicitly needed, a loopback address is the safer choice for desktop use. port must be unused by other programs. A conflict commonly produces log messages such as bind or address already in use.
protocol identifies the inbound protocol, not the remote node protocol. A SOCKS inbound can send requests to a VLESS or VMess outbound; the two protocols do not need to match. settings stores parameters specific to that inbound protocol. For a SOCKS inbound, udp: true commonly means that UDP requests are accepted.
sniffing recovers the destination domain from connection contents. An application may resolve a domain to an IP first and then connect to the local proxy; if the core sees only the IP, domain-based routing rules cannot match. With sniffing enabled and destOverride configured, the core can identify domains in applicable HTTP and TLS traffic before passing them to routing.
{
"tag": "socks-in",
"listen": "127.0.0.1",
"port": 10808,
"protocol": "socks",
"settings": {
"auth": "noauth",
"udp": true
},
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls"]
}
}
tagonly needs to be unique within the current configuration. Use readable names such assocks-inorlan-in.- The system proxy sends only traffic from applications that support system proxy settings to an HTTP or SOCKS entry; it does not capture traffic from every program.
- After changing a port, the caller must be updated as well. Changing only the core configuration while leaving the system proxy unchanged usually results in an immediate connection refusal.
- Whether UDP works reliably also depends on the application, inbound protocol, outbound protocol, and server configuration.
outbounds: proxy nodes, direct access, and blocked traffic
outbounds is also an array. A proxy node is usually just one entry; the client typically creates a direct outbound and a blocking outbound as well. A proxy outbound connects to a remote service using protocols such as VMess or VLESS; freedom lets the core access the destination directly, while blackhole terminates connections selected by a rule.
A proxy outbound can be understood in two layers. settings describes the protocol identity and server port, such as a VMess address, port, user ID, and security parameters. streamSettings describes the underlying transport and security layer, such as TCP, WebSocket, TLS, or Reality. Even with correct protocol fields, a mismatched transport path, SNI, or security layer will still cause the connection to fail.
VMess + WebSocket + TLS
- protocol
- vmess
- network
- ws
- security
- tls
- Remote port
- 443
- Path
- /v2ray
User identity goes in settings; the transport path and TLS settings go in streamSettings.
VLESS + TCP + Reality
- protocol
- vless
- network
- tcp
- security
- reality
- flow
- xtls-rprx-vision
- Fingerprint
- chrome
Reality parameters must match the server; simply renaming the security field is not enough.
Direct outbound
- tag
- direct
- protocol
- freedom
- Remote node
- Not required
- Purpose
- Local and direct-access rules
After direct is selected, the local network connects to the destination directly.
Blocking outbound
- tag
- block
- protocol
- blackhole
- Remote connection
- Not established
- Purpose
- Block selected traffic
When a routing rule refers to block, the request is not sent on to its destination.
An outbound tag is the most important index when troubleshooting a configuration. If a routing rule contains "outboundTag": "direct", return to outbounds and find the object whose tag is direct. If a rule references a nonexistent tag, the core will usually report a configuration error during startup instead of guessing an outbound.
A subscription usually provides node connection parameters, not the complete set of local ports, log levels, and routing rules. After importing a subscription, v2rayN, v2rayNG, or v2flyNG combines the node fields with its own settings and generates the runtime configuration for the core. As a result, the complete JSON generated from the same subscription may differ between clients.
Takeaway: troubleshoot outbound errors layer by layer
For authentication failures, first verify the address, port, and user information in settings. For TLS, Reality, or WebSocket handshake failures, check streamSettings next. Mixing the two layers while editing is the easiest way to end up with a seemingly complete configuration that still times out.
routing: send requests to the right outbound in order
routing.rules is an array of rules. The commonly used field rule can match conditions such as domain, ip, port, network, protocol, and inboundTag. A rule does not forward data itself; it uses outboundTag to specify which outbound should handle the request.
Rule order changes the result. If the first rule sends a particular domain to the proxy and the second sends a broader domain set direct, the first rule wins and matching stops. Put more specific blocking or forced-proxy rules first, followed by broad direct rules and the final fallback.
| Match field | Match target | Typical use | Result |
|---|---|---|---|
domain |
Full domain, suffix, or domain set | Route traffic by site category | Send to the specified outboundTag |
ip |
Single IP, CIDR, or IP set | Route LAN and target subnets separately | Direct, proxy, or block |
port |
Single port or port range | Control traffic for a specific service | Select the corresponding outbound |
network |
tcp, udp, or both | Final fallback rule | Cover remaining connections |
inboundTag |
One or more inbound tags | Use different outbounds for different local entry points | Implement entry-point-based routing |
domainStrategy determines when the router resolves a domain to an IP. AsIs prioritizes the original domain and does not actively resolve it for IP rules; IPIfNonMatch checks domain rules first, then resolves the IP and tries IP rules if nothing matches; IPOnDemand triggers resolution earlier when a rule may require an IP. The right choice depends on the rule design—not on choosing the most aggressive option.
If no rule matches, V2Ray typically uses the first outbound. To avoid relying on implicit order, add a final fallback rule covering both TCP and UDP and explicitly set its outboundTag. Reordering outbounds then will not unexpectedly change the direction of default traffic.
{
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"protocol": ["bittorrent"],
"outboundTag": "block"
},
{
"type": "field",
"ip": ["geoip:private"],
"outboundTag": "direct"
},
{
"type": "field",
"domain": ["geosite:cn"],
"outboundTag": "direct"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
}
Takeaway: start routing troubleshooting with the first rule
First confirm which rule actually matched the destination domain or IP, then inspect the outboundTag referenced by that rule. If the node is reachable but traffic takes the wrong path, the usual causes are rule order, domain sniffing, or DNS results—not a broken proxy protocol.
A readable minimal client configuration
The example below puts logging, one SOCKS inbound, three outbounds, and four routing rules in a single file. The address and user ID are for structure only and cannot be used as a real node. The configuration uses standard JSON: keys and strings require double quotes, trailing commas are not allowed, and comments cannot be inserted directly.
From the data-flow perspective, the application first connects to 127.0.0.1:10808. The core checks routing: BitTorrent traffic goes to block, private addresses and the specified domain set go to direct, and all other TCP and UDP requests go to proxy. proxy then connects to the example server’s port 443 using VMess, WebSocket, and TLS.
{
"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": "proxy",
"protocol": "vmess",
"settings": {
"vnext": [
{
"address": "server.example.com",
"port": 443,
"users": [
{
"id": "00000000-0000-4000-8000-000000000000",
"alterId": 0,
"security": "auto"
}
]
}
]
},
"streamSettings": {
"network": "ws",
"security": "tls",
"tlsSettings": {
"serverName": "server.example.com"
},
"wsSettings": {
"path": "/v2ray"
}
}
},
{
"tag": "direct",
"protocol": "freedom",
"settings": {}
},
{
"tag": "block",
"protocol": "blackhole",
"settings": {}
}
],
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"protocol": ["bittorrent"],
"outboundTag": "block"
},
{
"type": "field",
"ip": ["geoip:private"],
"outboundTag": "direct"
},
{
"type": "field",
"domain": ["geosite:cn"],
"outboundTag": "direct"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
}
}
- First validate the JSON syntax, especially whether double quotes, commas, and square brackets are properly paired.
- Then verify that every tag is unique and that each outboundTag referenced by routing actually exists.
- Make sure the inbound port is not in use, and point the system proxy or application to the same port.
- Verify that the proxy outbound’s protocol, server port, transport, and security layer match as a complete set.
- Finally, check rule order and confirm that the fallback rule comes after more specific rules.
How the graphical client maps to core JSON
v2rayN, v2rayNG, and v2flyNG expose common fields as form controls. The address, port, user ID, transport, and security settings on the node editor mainly map to the proxy outbound; the local SOCKS port and LAN access options map to inbounds; routing modes, rule sets, and custom rules map to routing.
In v2rayN, local ports and basic behavior are typically adjusted under Settings → Parameter Settings, while node parameters are edited in the server editor. When the client starts the core, it combines node data, global parameters, and routing settings into a runtime configuration. Direct edits to a temporary core JSON may be overwritten the next time you switch nodes, update a subscription, or restart the core.
v2rayNG and v2flyNG on Android use a similar layered model, but their cores differ: v2rayNG uses the Xray core, while v2flyNG uses the v2fly core. Some advanced fields and defaults differ, so a complete configuration exported by one client cannot be used unchanged as the other client’s UI configuration file.
Why does the UI show one node while the runtime config has three outbounds?
The node corresponds only to the proxy outbound. The client also creates direct and block for direct-access and blocking rules, so the number of outbounds is usually greater than the number of nodes.
Why does the generated JSON revert after a restart?
The generated file is a runtime artifact. Change the source data under Settings → Parameter Settings, in the node editor, or in routing settings, then restart the core to verify the result.
Why didn’t the local port change after importing a subscription?
A subscription mainly provides node connection parameters; the local listening port belongs to the client settings. Check whether the SOCKS port is still 10808 and update the system proxy accordingly.
Why is traffic still using the wrong outbound when the routing rule contains a domain?
First enable applicable domain sniffing, then check domainStrategy, DNS results, and rule order. Temporarily set the log level to info to observe the actual destination and outbound tag.
Troubleshoot startup and routing errors by following the logs
Configuration problems fall into startup and runtime stages. Startup failures usually involve JSON syntax, field types, duplicate ports, or invalid tags; the core may not even start listening on an inbound. Runtime problems are more often related to node parameters, DNS, rule matches, and the destination network.
When troubleshooting, do not change multiple sections at once. Temporarily change loglevel from warning to info, reproduce the issue once, and record the time. Determine whether the inbound is not listening, the wrong outbound was selected, or the proxy outbound failed to connect, then edit the relevant section. Restore warning afterward to reduce routine log volume.
- JSON parsing error: Check the commas, double quotes, and array or object closing symbols near the reported line.
- The core starts but the port is not listening: Check
listen,port, and port usage; make sure two inbounds are not using the same address and port. - The application immediately reports a connection refusal: Verify that the application proxy address is
127.0.0.1and that its port matches the actual inbound. - The node connects but traffic is routed incorrectly: Check routing.rules from top to bottom and confirm which rule matched the destination first.
- Domain rules never match: Check whether sniffing is enabled, whether DNS returns the expected result, and whether the rule uses a domain or IP condition.
- Only some UDP applications fail: Confirm that the SOCKS inbound permits UDP, then check whether the outbound protocol, server, and network all support the traffic.
{
"log": {
"loglevel": "info"
}
}
The inbound tag, destination address, and outbound tag in the logs can be linked into a complete path. For example, if a request enters through socks-in, shows a particular domain as its destination, and ultimately selects direct, the node was not involved in that connection. If proxying was expected, inspect routing instead of repeatedly changing VMess or VLESS identity parameters.
Conversely, if the logs already show that the rule selected proxy and a TLS handshake or connection timeout occurs afterward, routing has essentially done its job. Focus next on the proxy outbound’s address, port, SNI, transport path, system time, and reachability of the remote service.
Takeaway: trace the entire path with tags
Use this troubleshooting sequence: “inbound tag → destination domain or IP → matched rule → outbound tag → transport connection.” Each step maps to one configuration section, helping separate port conflicts, routing mistakes, and node handshake failures.