This guide is for users who can already import a server and want to understand V2Ray configuration in greater depth. The goal is not to memorize every field, but to build a clear model of traffic entering through an inbound, passing through routing decisions, and leaving through an outbound—and to learn how tags, logs, and configuration boundaries help isolate problems.
Start with the traffic flow
A V2Ray configuration file is a JSON object whose top-level fields control logging, DNS resolution, inbounds, outbounds, and routing. The core does not execute the file line by line; at startup, it reads the full configuration and builds listeners, outbound handlers, and routing rules. Read the configuration as a data flow, not as a sequence of line numbers.
An application first sends a request to a local SOCKS or HTTP proxy port, represented by inbounds. After identifying the destination, the inbound passes the connection to the routing module. routing selects an outbound tag according to rule order, and the handler associated with that tag in outbounds either establishes a remote connection or connects directly to the destination. dns provides results for domains that need resolution, while log records warnings and errors along the way.
The sample uses local SOCKS port 10808, with one VMess proxy outbound and one freedom direct outbound. Private addresses use the direct route, while other TCP and UDP traffic goes through the proxy outbound. The example domain is the reserved example.com; it demonstrates structure only and is not a usable server configuration.
{
"log": {
"loglevel": "warning"
},
"dns": {
"servers": [
"localhost",
"1.1.1.1"
]
},
"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": "11111111-2222-4333-8444-555555555555",
"security": "auto"
}
]
}
]
},
"streamSettings": {
"network": "tcp",
"security": "none"
}
},
{
"tag": "direct",
"protocol": "freedom",
"settings": {}
}
],
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"ip": [
"geoip:private"
],
"outboundTag": "direct"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
}
}
inbounds: define who can send traffic to the core
Configuration note
inbounds is an array of inbound entries, with each element representing a listening endpoint. The sample restricts the address to 127.0.0.1, uses port 10808, and selects the socks protocol. Only programs on the same device can connect to this port; other devices on the LAN cannot use it directly.
listen and port determine where the core waits for connections, while protocol determines how incoming data is interpreted. A port has no special magic: it only needs to be valid, unused by another program, and identical to the proxy port configured in the application. If the browser uses 127.0.0.1:10808 but the configuration listens on 10809, requests will never reach the core.
What settings and sniffing control
Configuration note
The inbound settings object depends on the selected protocol. In a SOCKS inbound, auth and udp are meaningful, but copying these fields unchanged into an inbound for another protocol may not work. When reading the documentation, first confirm which protocol owns a field instead of moving settings based only on similar names.
sniffing supplements the destination domain using the initial connection data. An application may resolve a domain to an IP address first and submit only that IP to the proxy. With sniffing enabled, the core may recover the domain from an HTTP host field or TLS handshake, allowing domain-based routing rules to match. Sniffing is not a DNS resolver and does not replace dns.
tagis an inbound's internal identifier. Routing rules can useinboundTagto distinguish traffic sources.listen: 127.0.0.1is suitable for a local proxy endpoint intended only for the current device.- When
portconflicts, the log usually reports that listening failed or that the address is already in use. udp: trueallows a SOCKS inbound to handle UDP requests, but successful delivery still depends on the outbound protocol and server configuration.
outbounds: define where traffic leaves
Configuration note
outbounds is also an array, but its role is the opposite of inbounds: it describes how the core connects to the final destination. A proxy outbound typically contains the server address, server port, user identifier, protocol parameters, and transport settings. A direct outbound uses freedom to access the destination from the current device. To block traffic explicitly, use a dedicated reject outbound and reference it by tag.
In the sample, proxy and direct are both tags. Routing does not copy outbound contents; it only records which tag should handle the traffic. When renaming a tag, update the routing rules as well. For example, after changing direct to local-direct, an outboundTag that still uses the old name will no longer point to the intended outbound.
proxy outbound
- Protocol
- VMess
- Remote port
- 443
- Transport
- TCP
- User identifier
- UUID format
The server address, user identifier, and transport parameters must match the server configuration.
direct outbound
- Protocol
- freedom
- Remote server
- Not required
- Referenced tag
- direct
- Typical use
- Direct LAN access
The connection is established directly through the local network, and remains subject to the local DNS, routing, and firewall.
Protocol and transport parameters are different layers
Using VMess as an example, settings → vnext describes the remote server and user, while streamSettings describes the underlying network and security method. If the server port is correct but the transport differs, the TCP connection may be established while the protocol handshake still fails. When troubleshooting, do not check only the address, port, and user identifier.
| Field location | What it controls | Common errors |
|---|---|---|
settings.vnext |
Server address, port, and user parameters | Invalid address, wrong port, or mismatched user identifier |
streamSettings.network |
TCP, WebSocket, and other transport types | Client and server use different transports |
streamSettings.security |
Transport-layer security method | Security method does not match the server |
tag |
Internal name referenced by routing | Rules were not updated after a rename |
Takeaway: check the hierarchy before comparing values
Addresses and ports belong to protocol settings; network type and transport security belong to streamSettings. If parameters are placed at the wrong level, the core will not interpret them as intended—even when the values themselves are correct.
routing: send inbound connections to outbounds by rule
Configuration note
routing.rules is an ordered array of rules. The core checks them from top to bottom and uses the outboundTag specified by the first matching rule. Put more specific rules first and broad fallback rules later. If a rule covering all TCP and UDP traffic comes first, a later direct-LAN rule will never match.
The first sample rule matches private addresses with geoip:private and sends them to direct. Common private ranges include 10.0.0.0/8, 172.16.0.0/12, and 192.168.0.0/16. The second rule matches TCP and UDP as the proxy outbound for all remaining traffic. Although the sample has only a few rules, it demonstrates the core principle: specific rules first, broad rules later.
- Make sure the rule's
typeis supported by the core. For commonly used field matches, usefield. - Check whether each condition matches a domain, IP, port, network type, or inbound tag.
- Search from top to bottom for the first rule that could match; do not inspect only the rule you expect to apply.
- Verify that
outboundTagexactly matches a tag in outbounds, including letter case. - Temporarily increase the log level and restart the core to confirm the actual destination and the stage where the error occurs.
domainStrategy determines when routing resolves domains
Configuration note
The sample uses IPIfNonMatch. When the destination arrives as a domain and no domain rule matches, the routing module can resolve it and then try IP rules. This lets address-based rules handle domain destinations, but adds another resolution step.
domainStrategy is not a switch that determines which outbound handles all DNS requests, nor is it the same as the system DNS setting. It mainly controls whether and when routing resolves a domain to an IP during matching. DNS server selection, the path used for DNS queries, and the destination address for the final connection must be evaluated together with dns, routing rules, and outbound settings.
| Match condition | Example | What it is useful for |
|---|---|---|
| Domain | domain |
Route by the full domain, subdomain scope, or predefined domain category |
| IP | ip |
Route by CIDR, individual address, or address category |
| Port | port |
Send a specified destination port to a particular outbound |
| Inbound tag | inboundTag |
Apply different outbound policies to different local endpoints |
| Network type | network |
Distinguish TCP and UDP traffic |
Takeaway: check rule order first when routing is unexpected
When traffic always uses the same outbound, first check whether a broad rule earlier in the list catches it prematurely. Then verify whether the domain has become an IP and whether the outbound tag exists.
dns and log: tools for resolution and troubleshooting
dns defines the DNS servers and related resolution policies available to the core. The sample lists localhost and 1.1.1.1 in sequence to illustrate the server-list structure. In a real configuration, choose the resolution method according to the network environment and routing goals, and check whether queries are handled by the intended outbound.
Distinguish carefully between an application's own resolution, operating-system resolution, and V2Ray's built-in DNS. If an application resolves a domain first and sends only the IP to a SOCKS inbound, the core may not perform the same domain lookup again. Sniffing may recover the domain, but success depends on whether the protocol traffic contains extractable information. When troubleshooting domain routing, first confirm whether the core actually received a domain or an IP.
dns section
- Example server
- localhost
- Fallback address
- 1.1.1.1
- Primary role
- Resolve domain names
- Related module
- routing
The result may be used for IP-rule matching, but dns itself does not determine the final outbound.
log section
- Example level
- warning
- Troubleshooting level
- info or debug
- Primary role
- Record runtime status
- Key details
- Listening and connection errors
Detailed logs are useful for temporary diagnosis; after troubleshooting, restore a more concise level.
loglevel controls the amount of detail in the output. For everyday operation, warning retains warnings and errors. To observe the request path, temporarily switch to info or debug. Higher verbosity produces more records and should not be left enabled after the issue is resolved.
- No listening port appears after startup: check the JSON syntax, field types, and whether the port is already in use.
- The local port accepts connections but the remote connection fails: verify the server, protocol, and transport parameters in outbounds.
- The proxy works but traffic is routed incorrectly: check routing order, the destination form, and outboundTag.
- Domains fail while IP addresses work: check DNS responses, the resolution path, and the domain strategy.
- Only UDP applications fail: confirm that the inbound allows UDP and verify UDP support in the outbound and on the server.
From client-generated configuration to manual troubleshooting
v2rayN, v2rayNG, and v2flyNG generate the core configuration from the server and routing options selected in their graphical interfaces. A subscription address or share link mainly provides the protocol parameters for one server; the client also adds local inbounds, logging, DNS, and routing. As a result, the fields in a share link usually do not equal the complete JSON ultimately passed to the core.
When using a graphical client, avoid treating its runtime-generated file as a permanent configuration source. The file may be overwritten when the client restarts the core, switches servers, or updates settings. A safer approach is to change the relevant option in the interface, then verify the fields through the logs or generated output. If an independent configuration is required, manage it as a separate file and run syntax checks and a startup test after every change.
The configuration syntax is valid. Why does the core still exit immediately?
Valid JSON only means that the text can be parsed. Continue with the startup log and check for unknown fields, incorrect field types, port conflicts, and routing rules that reference a nonexistent outbound tag.
The browser is set to 10808. Why are there no request logs?
Confirm that inbounds is actually listening on 127.0.0.1:10808, then check that the browser is using a SOCKS proxy rather than an HTTP proxy. The protocol types on both ends must match.
Traffic still uses proxy after adding a direct rule?
Move the direct rule before the broad proxy rule, verify that outboundTag is exactly direct, and confirm whether the destination reaches the core as a domain or an IP.
Can this JSON be imported directly into v2rayN?
A complete core configuration has a different structure from a client's server entry. To manage a complete configuration, use the appropriate configuration entry provided by the client. For a regular server import, use a VMess or VLESS share link or a subscription address.
Why is there no visible change after changing loglevel?
Save the file, restart the core, and confirm that you are editing the configuration actually read by the current process. A graphical client may regenerate the runtime configuration every time it starts.
Recommended minimal troubleshooting sequence
- First confirm that the JSON parses and that all objects, arrays, commas, and quotation marks are correctly placed.
- Start the core and check whether
127.0.0.1:10808is listening. - Temporarily keep one clearly defined proxy outbound and one direct outbound to reduce the number of variables.
- Use two routing rules to verify that private addresses go direct and all other traffic uses the proxy.
- Once the basic connection works, add domain categories, port conditions, and additional outbounds one at a time.
- Change only one related group of fields at a time, restart, and read the relevant log immediately.
The key to understanding V2Ray configuration is to reconstruct the connection path from its fields: inbounds accept traffic, routing chooses a path, outbounds send it, dns supplies resolution results for domain matching and connections, and log provides diagnostic clues at every stage. When something fails, narrowing the scope across these five boundaries is more reliable than changing the protocol, port, DNS, and routing all at once.