Configuration Reference

V2Ray Configuration File Structure and Parameters

Starting with the top-level JSON structure, this guide breaks down inbounds, outbounds, routing, dns and policy in order. Each section explains where traffic goes, how to fill in the parameters, and how to combine the resulting configuration snippets.

JSON Structure Inbounds and Outbounds Traffic Routing DNS and Policy

If you only need to install the client, import a subscription and make your first connection, the quick-start tutorial is the more direct place to begin. This page is useful when you need to understand where configuration comes from, adjust a local listener, add routing rules or diagnose startup errors. With v2rayN, v2rayNG or v2flyNG, the graphical interface generates most of the configuration for you; understanding these fields still helps explain what the client options ultimately change.

Use v2rayN first on desktop systems; the installation entry point is on the client download page. The examples here use configuration patterns common to both V2Ray and Xray, but support for extension fields varies between cores. Before editing, confirm which core the client is running, then keep a copy of the original configuration so core-specific parameters are not moved directly into another environment.

01 / JSON STRUCTURE

Configuration Structure at a Glance

Understand the top-level object by following traffic flow

V2Ray and Xray configuration files are usually JSON objects. The first thing to remember is not the number of fields but the direction of traffic: an application connects to a local inbound listener, the core reads the routing rules, selects an outbound, and uses it to connect to the destination. DNS resolves domain names to addresses, policy controls runtime behavior such as session timeouts and statistics, and log determines where logs are written and how detailed they are.

Both inbounds and outbounds are arrays because one instance can listen on several local ports and prepare multiple exits. Each object in an array is usually named with a tag, which routing rules reference later. A tag is only an internal identifier and is never sent to the remote side; choose names yourself, but keep them short, stable and descriptive, such as socks-in, proxy, direct and block.

A readable configuration order is: log, DNS, inbounds, outbounds, routing and policy. JSON does not require this order, but consistent organization shortens troubleshooting. When startup fails, you can inspect the file from the top down; when comparing two configurations, changes are easier to spot. A graphical client may generate a different order. As long as the hierarchy and fields are valid, object key order does not change the result.

{
  "log": {
    "loglevel": "warning"
  },
  "dns": {},
  "inbounds": [],
  "outbounds": [],
  "routing": {},
  "policy": {}
}

JSON Syntax and Configuration Semantics Are Separate Checks

A file that parses as JSON only proves that its brackets, quotes, commas and data types are syntactically valid; it does not mean the current core accepts every field. For example, a quoted port may be valid JSON but invalid where an integer is required. An outbound tag with inconsistent spelling may not fail until a routing rule tries to reference it. Troubleshoot in two stages: first confirm that the JSON parses, then check core logs for unknown fields, type errors, missing tags or incomplete protocol settings.

Standard JSON does not allow comments or a trailing comma after the last item in an object or array. Be especially careful when copying examples. Documentation often shows fragments, but a fragment is valid only when placed under the correct parent object. For example, when copying a routing object by itself, it must become the value of top-level "routing", not be pasted directly at the end of the file. Strings require double quotes, while Boolean values use true or false without quotes.

Field Data Type Primary Purpose Common Checks
log Object Controls access logs, error logs and logging levels Path permissions and whether the log level is too low
inbounds Array Accepts connections from browsers, the system or local network devices Listen address, port conflicts and protocol type
outbounds Array Defines exits such as proxy, direct and block Server parameters, tags and transport settings
routing Object Selects an exit by domain, IP, port or inbound tag Rule order, tag references and resolution strategy
dns Object Defines DNS servers, static mappings and query conditions Query path, domain matching and fallback behavior
policy Object Controls runtime policies such as session timeouts and traffic statistics Policy levels, statistics switches and coordination with the statistics module

Create a rollback point before making changes

Before adjusting anything, start the current configuration successfully without edits and note the local ports, system proxy mode and core in use. Then copy the configuration file and give the copy a descriptive name. Change one logical unit at a time—for example, add a direct outbound first, verify it, and only then add routing rules. Changing several areas at once may seem faster, but when startup fails it is much harder to tell whether the cause is syntax, tags or protocol parameters.

A graphical client may regenerate its runtime configuration when updating a subscription, switching nodes or restarting the core. Direct edits to a temporary file may therefore disappear. In v2rayN, prefer the custom configuration, routing settings or advanced options provided by the client; on Android, first confirm whether the active configuration comes from a subscription node or a manual profile. For precise terminology, see the glossary as well, so “inbound,” “system proxy” and “routing mode” are not treated as the same feature.

02 / INBOUNDS

inbounds Inbound Settings

The listen address determines who can connect

An inbound is the entry point where local applications hand traffic to the core. The most common local entrances are SOCKS and HTTP proxies. listen determines the network address, port determines the port, and protocol determines which proxy protocol the application should use. For device-only access, use 127.0.0.1. This address accepts connections only from the same device, allowing browsers, the system proxy and other local programs to connect while preventing direct access from other devices on the LAN.

To let a desktop client serve a phone, TV or another computer on the same LAN, the inbound usually listens on 0.0.0.0 or a specific LAN address. You must also handle the firewall, network profile and access controls; changing only the listen address is not enough. Shared devices should use the LAN address of the computer running the core and the inbound port—not 127.0.0.1. See the v2rayN LAN proxy sharing setup guide for related steps.

{
  "inbounds": [
    {
      "tag": "socks-in",
      "listen": "127.0.0.1",
      "port": 10808,
      "protocol": "socks",
      "settings": {
        "auth": "noauth",
        "udp": true
      },
      "sniffing": {
        "enabled": true,
        "destOverride": [
          "http",
          "tls"
        ]
      }
    },
    {
      "tag": "http-in",
      "listen": "127.0.0.1",
      "port": 10809,
      "protocol": "http",
      "settings": {}
    }
  ]
}

The Boundary Between SOCKS, HTTP and Transparent Interception

A SOCKS inbound is suitable for applications that explicitly support SOCKS and can carry TCP, with UDP support when enabled. An HTTP inbound is intended for programs that connect through HTTP CONNECT or a standard HTTP proxy. Both require the application or system proxy to point to the correct port. An application configured for HTTP cannot point to a SOCKS port; even with the right port number, using the wrong protocol commonly causes an immediate disconnect, a browser proxy error or unrecognized handshake data in the logs.

TUN mode differs from an ordinary local proxy. It receives a wider range of system traffic through a virtual network interface and also requires routing-table, DNS-interception and permission settings. Do not treat TUN as simply adding another SOCKS inbound. v2rayN assembles runtime parameters from its TUN options, so enable it through the client interface first and then inspect the logs instead of inserting a complete TUN fragment from another environment. When the ordinary system proxy already covers browsers and common desktop programs, there is no need to enable multiple interception methods just to cover more traffic.

How sniffing Helps with Domain-Based Routing

sniffing recovers a destination domain from protocol characteristics in a connection. Some applications resolve a domain themselves and pass only the resulting IP address to the proxy; if routing contains only domain rules, the core cannot match those rules against a bare IP. With sniffing enabled, host information in an HTTP request or the server name in a TLS handshake can provide a domain to the routing module. In the example, destOverride allows the recognized HTTP or TLS destination to replace the original destination address for subsequent rule evaluation.

Sniffing is not a replacement for DNS, and not every connection reveals a domain. Protocols without recognizable host information still appear as IP addresses; encrypted handshakes and application behavior also affect the result. When a route is not matched, check whether the access log records a domain or an IP, then decide whether to adjust domainStrategy, add IP rules or inspect sniffing. Do not repeatedly stack identical domain and IP conditions without first reviewing the logs; that only makes the rules harder to maintain.

Configuration Principles for Ports, Authentication and Tags

Two processes cannot occupy the same port on one address, and two inbounds cannot listen on the same address and port. If the client immediately reports that an address is already in use, close duplicate instances and check other proxy tools or old core processes. Changing the port alone solves only half the conflict: the system proxy, browser extensions and LAN devices must use the new port too. Keeping SOCKS and HTTP ports adjacent can reduce confusion, but never infer the protocol from a fixed port number.

auth: "noauth" is suitable for a local SOCKS inbound that listens only on the loopback address. When listening on a LAN address, assess authentication support and firewall restrictions together, and allow access only from trusted networks. Give each inbound its own tag so inboundTag can apply different routes to different entry points—for example, normal split routing for local traffic and restricted ports for a shared LAN entry. After renaming a tag, search the entire configuration for routing references so no rule still points to the old name.

Parameter How to Understand It Common Mistake
listen Defines the range of connection sources Keeping the loopback address when sharing, or exposing all interfaces for local-only use
port The local port applications use to connect to the core Conflicting with another program or failing to update the system proxy
protocol Defines the inbound handshake method The application uses HTTP while connecting to a SOCKS port
tag An internal name referenced by routing rules Renaming it while routing still uses the old tag
sniffing Helps recover domains and participate in traffic routing Assuming every IP can be converted into a domain once it is enabled

03 / OUTBOUNDS

outbounds Outbound Settings

Proxy, direct and block form the basic exits

An outbound defines where the core sends traffic. A complete setup usually includes at least a proxy outbound and a direct outbound; add a block outbound when a class of connections must be explicitly rejected. A proxy outbound stores the server address, port, user identity and encryption or transport settings. A direct outbound lets the core access the destination itself, while a block outbound terminates traffic matched by a rule. routing does not establish connections; it only hands each request to an outbound tag.

The order of the outbound array matters. When a connection matches no routing rule, common implementations use the first outbound as the default. Putting the proxy first or the direct outbound first therefore changes where unmatched traffic goes. Do not rely on array order alone for important policies—write explicit rules for important traffic. Still, make the first item match the intended default so new domains or missed conditions do not produce surprises.

{
  "outbounds": [
    {
      "tag": "proxy",
      "protocol": "vless",
      "settings": {
        "vnext": [
          {
            "address": "server.example.com",
            "port": 443,
            "users": [
              {
                "id": "11111111-2222-4333-8444-555555555555",
                "encryption": "none"
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "tcp",
        "security": "tls",
        "tlsSettings": {
          "serverName": "server.example.com"
        }
      }
    },
    {
      "tag": "direct",
      "protocol": "freedom",
      "settings": {}
    },
    {
      "tag": "block",
      "protocol": "blackhole",
      "settings": {
        "response": {
          "type": "none"
        }
      }
    }
  ]
}

Separate Protocol Identity from Transport Parameters

When troubleshooting a proxy outbound, divide its fields into two groups. The first contains protocol identity parameters such as the server address, port, user ID and protocol-specific settings. The second is the transport configuration in streamSettings, such as TCP, WebSocket, gRPC, TLS or REALITY. Each group can be correct on its own while the combination is wrong. For example, the remote side may use WebSocket while the local side specifies TCP; the certificate name may differ from serverName; or the user identity may be correct while the port points to another service.

One benefit of importing a subscription is that the provider’s protocol, transport, security layer and host parameters are written into the client together. When migrating manually, do not copy only the address and port. If a node passes a basic test but websites do not open, do not assume all outbound identity parameters are correct: the client’s test may cover only part of the path, while real applications also involve DNS, UDP, routing and the system proxy. Use runtime logs to determine whether the failure occurs during resolution, remote connection, handshake or destination access.

Direct Outbounds Are Also Affected by DNS and the Network Environment

freedom means that the current device establishes the destination connection directly. It does not bypass the configuration flow: traffic still passes through the inbound and routing before the core performs the direct connection. When direct access fails, check the local network, system DNS, destination address and the outbound’s domain strategy. If a domain rule selects direct but the destination must be resolved before connecting, the result and address family can affect what happens next. In some environments, an available IPv6 record with an incomplete path can cause a long wait followed by a timeout.

You can set an appropriate domain resolution strategy for a freedom outbound, but supported values and behavior may differ between cores. Unless there is a clear reason, keep the default generated by the client. To determine whether split routing is the problem, temporarily create a narrow rule for one explicit target and send it to direct instead of deleting all rules. Restore the configuration after testing so the temporary check does not change other applications’ traffic paths.

Start Simple with Proxy Chains and Multiple Outbounds

A configuration can contain several proxy outbounds selected by routing tags, or let one outbound establish its underlying connection through another. This is useful when the network path is intentional, but tag dependencies quickly become complex. Before configuring, draw the sequence “inbound → routing → first outbound → underlying outbound” and ensure there are no circular references. If proxy-a depends on proxy-b and proxy-b points back to proxy-a, the core cannot build a valid path.

Multiple-node selection is usually handled by the configuration management features in v2rayN, v2rayNG or v2flyNG. When switching nodes, the client changes the active outbound or regenerates the runtime configuration. Adding many server objects directly to the generated file may not work with the client’s switching logic. On desktop, let v2rayN manage nodes and place only stable custom routing and DNS requirements in extension points supported by the client; this is easier to roll back than maintaining a complete node list by hand.

Example Tag Protocol Purpose Troubleshooting Focus
proxy Use the node’s actual protocol Connects to a remote server and forwards destination traffic Address, port, identity, transport and security layers must match as a set
direct freedom Accesses the destination directly through the local network Local network, DNS, address family and destination reachability
block blackhole Terminates matched traffic Whether the rule is too broad or blocks a required connection

04 / ROUTING

routing Routing Rules

Rules are checked from top to bottom; the first match wins

The routing module selects an outbound using the connection’s destination domain, IP, port, network type, protocol characteristics or inbound tag. The key behavior is rule order: rules are normally checked from top to bottom, and once one matches, its outboundTag is used while later rules are ignored. Put specific rules first and broad rules later. If “all TCP traffic goes through the proxy” is the first rule, later direct-domain rules can never take effect.

When designing rules, define the default policy first, then list exceptions. If the proxy is the default outbound, place block conditions and explicit direct conditions first, letting everything else fall through to the proxy. If direct is the default, list the destinations that need the proxy first. Do not express one policy simultaneously through array order, complex domain lists and multiple fallback rules. Choose one clear default and use rules only for exceptions; future maintenance becomes much easier.

{
  "routing": {
    "domainStrategy": "IPIfNonMatch",
    "rules": [
      {
        "type": "field",
        "protocol": [
          "bittorrent"
        ],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "domain": [
          "domain:intranet.example.com",
          "full:printer.example.net"
        ],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "ip": [
          "geoip:private"
        ],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "network": "tcp,udp",
        "outboundTag": "proxy"
      }
    ]
  }
}

Domain Matching Determines Rule Boundaries

Common domain conditions include exact matches, a domain and its subdomains, keyword matches and built-in domain sets. full:printer.example.net matches only that complete hostname and suits one clearly bounded service. domain:example.com generally covers the domain and its subdomains and suits a related group of hosts. A string without a prefix may be interpreted differently depending on context, so explicit match types are easier to maintain and preserve the original intent.

Keyword matching is broad, so a short string may unexpectedly match unrelated domains. Unless classification by a name fragment is intentional, prefer full or domain. When a rule does not match, first check whether the core sees a domain or an IP address. If the application resolved the destination locally and inbound sniffing did not recover the domain, even a precise domain rule will not run. Check access logs, enable suitable sniffing or add IP conditions for known ranges.

domainStrategy Connects Domain Rules with IP Rules

domainStrategy controls when the routing module resolves a domain in order to match IP rules. AsIs emphasizes the form received, so the domain is not actively converted to an IP solely for routing; IPIfNonMatch generally resolves the address only after domain rules fail and then tries IP rules. Other strategies may resolve more aggressively. The more active the strategy, the more domain traffic can participate in IP classification, but the tighter the coupling between DNS behavior and routing results.

Before choosing a strategy, ask whether the rules mainly depend on domains or IPs. If most rules use explicit domains and only a few networks need additional checks, IPIfNonMatch is easier to understand. If every domain must first be classified by address, DNS must match the intended outbound. Otherwise different resolvers, caches or address families can produce different results and change routing. After changing domainStrategy, test domain rules, IP rules and unmatched destinations rather than judging success from one webpage.

IP, Port, Network and Inbound Tags Can Be Combined

IP conditions can specify a single address, a CIDR range or a built-in set supported by the core. Private addresses should usually go direct so routers, printers and LAN services are not sent to a remote server. Port conditions suit a defined service range, such as 53 or 80,443, and can also express intervals. Common network values are tcp, udp or both. Different fields in one rule generally must all match; multiple values in one field array usually mean that any value can match.

inboundTag is useful for separating traffic sources. For example, socks-in can use normal split routing while lan-in is limited to a designated outbound. This avoids running multiple core instances for different sources. Confirm that the inbound tags actually exist, and put source restrictions near the beginning of the rules so broader destination rules do not win first. Be conservative when blocking ports and protocols: an overly broad range may let an application open its home page but prevent playback, login or synchronization.

Verify Rules with Logs, Not Guesswork

The most effective way to verify routing is to prepare a few clear test cases: an internal domain that should go direct, a target that should use the proxy and a condition that should be blocked. Then inspect the outbound tag in the access log. If the log shows the target but not the expected tag, temporarily increase logging detail and restore a restrained level afterward to prevent unbounded growth. Reload or restart the core after changing rules, and confirm that the client is not still using an old runtime configuration.

As the rule set grows, keep maintenance notes outside the configuration explaining why each group exists; this is more useful than recording only a domain list. Standard JSON cannot contain comments, so store the notes in a separate document. Subscription updates generally affect nodes and proxy outbounds and should not overwrite manual routing. If rules disappear after every update, you are probably editing a temporary generated file; use the client’s routing configuration entry point instead.

05 / DNS

dns DNS Configuration

First distinguish system resolution from core resolution

DNS is easy to misconfigure because a device may have several resolution paths at once. An application may call the system DNS and pass the resulting IP to the proxy; the core may resolve a domain itself for routing; and in TUN mode the client may take over system queries. The configuration file’s dns mainly defines how the core resolves names itself; it does not automatically route every application query through it. Before diagnosing a problem, check whether the core receives a domain or an already-resolved IP in the logs.

If an app passes a domain directly to a SOCKS or HTTP proxy, the core may resolve it using its own DNS settings. If the app resolves it locally first, routing may see only an IP address, so the DNS settings may not apply to that original query. Sniffing can recover domains from some connections, but it cannot replace full query interception. In other words, having a dns object does not mean every application uses that DNS.

{
  "dns": {
    "hosts": {
      "router.home.arpa": "192.168.1.1"
    },
    "servers": [
      {
        "address": "1.1.1.1",
        "domains": [
          "domain:example.com"
        ],
        "skipFallback": true
      },
      "localhost"
    ],
    "queryStrategy": "UseIP"
  }
}

The servers Array Has Both Order and Conditions

servers can contain simple addresses or objects with domain conditions, expected address ranges and fallback behavior. A simple setup can start with one or two stable resolvers. More servers do not automatically mean more reliable resolution; unclear conditions make failures difficult to trace. An object’s domains field sends specified domains to that server first, which is useful for internal names or services with a known resolver.

skipFallback controls whether a query matching the current server’s conditions may participate in later fallback. Before enabling it, confirm that the server can resolve every listed domain; otherwise a failed query may not try another source. For LAN hostnames, a local resolver or static hosts mapping is usually clearer. Sending internal names to a public resolver may return nothing and can send troubleshooting in the wrong direction.

hosts Is Best for Stable Mappings, Not Dynamic Addresses

hosts maps domains to fixed addresses and can also represent a small number of aliases. It is useful for testing a new service, overriding a LAN hostname or temporarily bypassing a bad resolution. Because mappings take priority over ordinary queries, a typo can keep sending connections to the wrong target. When using hosts for troubleshooting, record each addition and decide whether to keep it after validation; otherwise a stale address may remain fixed weeks later.

Mapping values must use the data type required by the core, and domain keys should be written as the expected complete names. If a target has both IPv4 and IPv6, one fixed mapping changes normal address selection. Do not permanently pin a service-provider-managed domain with hosts; you may lose failover and address updates. For intermittent connection problems, compare resolution results with connection logs before hardcoding the current IP.

queryStrategy Affects Address-Family Selection

queryStrategy controls whether queries favor IPv4, IPv6 or both address families. Supported values may differ between cores, so use the valid configuration for the core used by the current client. If the local network has only stable IPv4, forcing IPv6-only results makes destinations unreachable; having IPv6 does not mean every remote path is suitable for it. Choose a strategy based on the local network, proxy server address and the capabilities of the destination outbound.

A typical symptom is fast domain resolution followed by a long wait on one address family, then fallback or a timeout. Compare the A and AAAA records returned and observe which destination address the core actually tries. Do not classify every timeout as a node failure. If changing the query strategy restores connectivity, continue checking the local IPv6 route, the remote server listener and the destination path instead of permanently relying on a setting that happened to work.

Check DNS and routing as One Complete Path

When domainStrategy must resolve a domain to match an IP rule, routing calls DNS; the query itself may then be sent through an outbound. Poor design can create a dependency loop: the domain’s outbound cannot be chosen until a query is made, while the query’s outbound depends on domain classification that has not finished. Keep DNS routing simple in basic environments. Make ordinary queries work first, then add direct or proxy rules for clearly identified DNS server addresses.

Check the full path in four steps: first, determine whether the application gives the inbound a domain or an IP; second, check whether the routing strategy requires resolution; third, identify which server handles the query; fourth, determine which outbound carries the query connection. Any mismatch can appear as an unreachable website or incorrect routing. v2rayN logs help locate the resolution and connection stages; see How to Read V2Ray Runtime Logs.

Symptom Check First Do Not Start By
Domain fails, but the IP responds directly Query server, DNS outbound path and whether the application uses system resolution Adding many DNS servers at once
Domain rule does not match Whether the inbound sees a domain or IP, sniffing and domainStrategy Adding the same domain keyword repeatedly
LAN hostname cannot be resolved Local DNS, hosts mappings and search domains Sending it to a resolver unrelated to the LAN
Resolution succeeds, but the connection waits for a long time Address family, destination routing and the address the outbound actually tries Judging node health from resolution speed alone

06 / POLICY

policy Policy and Statistics

policy controls runtime behavior, not routing direction

policy is often mistaken for an extension of routing, but it mainly controls session timeouts, idle detection and statistics switches. Whether traffic uses a proxy or direct access is still determined by routing and the outbound. Policies are usually organized by user level, and the level in an outbound user object can link to the corresponding level; most configurations use the default level unless a special behavior is required. Add multiple levels only when different session behavior is genuinely needed.

Shorter timeouts are not automatically better. A brief period without data does not mean a connection is dead. Long polling, intermittent file transfers, remote terminals and persistent applications can all have idle periods. A very low idle value causes frequent reconnects; an excessively high value delays cleanup of dead connections. Start with the client or core defaults and adjust only when logs and application behavior demonstrate a need.

{
  "policy": {
    "levels": {
      "0": {
        "handshake": 4,
        "connIdle": 300,
        "uplinkOnly": 2,
        "downlinkOnly": 5,
        "statsUserUplink": false,
        "statsUserDownlink": false
      }
    },
    "system": {
      "statsInboundUplink": false,
      "statsInboundDownlink": false,
      "statsOutboundUplink": false,
      "statsOutboundDownlink": false
    }
  }
}

handshake and connIdle Handle Different Stages

handshake limits how long the connection may wait during establishment. It applies to a handshake that has not completed, not to the total time required to load a webpage. If it is too short, network fluctuation or a slow remote response can cause premature failure; if too long, clearly impossible connections consume resources longer. For handshake timeouts, check the server address, port, transport layer and local network before simply increasing the value.

connIdle controls how long a connection is kept when there is no data activity. After an idle connection closes, the application will usually reconnect, though some programs show this as a session interruption. During debugging, check whether the failure occurs after a consistent interval: repeated disconnects after a similar idle period point to policy; random timing with remote resets is more likely a network or server behavior.

uplinkOnly and downlinkOnly handle connections with activity in only one direction. They are not upload or download speed limits and do not allocate bandwidth to an application. Without understanding the existing connection behavior, do not shorten them casually as an “optimization.” Defaults generated by a graphical client are generally suitable for ordinary use; long-lived connections, resource constraints or a clearly defined service are reasons for separate evaluation.

Statistics Switches Only Grant Collection Permission

statsUserUplink, statsUserDownlink and the inbound and outbound statistics fields under system allow the core to record traffic in the corresponding directions. Enabling these Boolean values does not necessarily create visible charts or interface counters; a supported statistics module and query method are also required. If the client does not consume the data, enabling every statistics item only adds unnecessary state maintenance.

Do not use statistics as a connection-success test. Bytes in one direction only show that some data passed through the relevant counter; they do not prove that the destination content returned completely or that routing matched expectations. Judge connection quality from access results and error logs as well. Client traffic figures may come from a system interface, core interface or client-side counter, so their definition may not match every policy switch exactly.

Multiple User Levels Need an Explicit Link

When a configuration contains several user objects, assign different level values and define the corresponding policies under levels in policy. Level keys appear as strings in JSON, such as "0" and "1". If a user references an undefined level, the core may use default behavior or report an error, depending on the implementation. Check user levels and policy levels together rather than copying only half of the relationship.

Ordinary client outbounds rarely need a complex level hierarchy. The identity supplied by a node subscription is mainly for remote protocol authentication; it does not mean that every node needs its own local policy level. Multiple levels are more common when the configuration serves inbound users with different session policies. This page focuses on client configuration, so a single default level is usually best—put the effort into inbound security, outbound parameters and readable routing.

Use Log Levels Alongside Policy Troubleshooting

Policy issues often look like “the connection is established, then drops,” so logs need to provide a timeline. For everyday operation, use a restrained level such as warning; during troubleshooting, temporarily increase detail and record the start time and reproduction steps. If the log path points to a directory without write permission, the core may fail to start or leave no diagnostic information. Graphical clients usually handle log locations; check file paths carefully when running a standalone core.

After reproducing the issue, compare three times: connection start, last data activity and connection close. If the close follows a policy threshold, change one setting and test again. If the log clearly shows a remote close or lower-level connection failure, policy is not the main lead. Restore a reasonable log level after debugging and remove statistics switches enabled only for testing.

Field Controlled Stage What It Does Not Control
handshake Handshake wait Total webpage load time
connIdle Keeping a connection with no data activity Network speed limits
uplinkOnly Handling a connection after uplink-only activity Upload bandwidth allocation
downlinkOnly Handling a connection after downlink-only activity Download bandwidth allocation
statsInboundUplink Allowing inbound uplink statistics to be recorded Automatically generating visual reports

07 / ASSEMBLY

Assemble the Complete Configuration and Check It Before Startup

Build the smallest working path first, then add capabilities layer by layer

The most reliable way to assemble a configuration is to build a minimal working path first: one SOCKS inbound listening only on the local device, one valid proxy outbound, one direct outbound and a few clearly directed routing rules. Once it starts and completes a connection, add the HTTP inbound, DNS conditions, block rules and policy. Each addition then has a limited scope, making it easy to return to the previous working configuration.

Every tag in the complete file must form a valid reference chain. Each outboundTag used by routing must exist in outbounds; each inboundTag must match an inbound tag; and a user’s level must have a corresponding policy if it is referenced. When tags are case-sensitive, Proxy and proxy are different names. Prefer lowercase letters, numbers and hyphens to reduce typing errors.

{
  "log": {
    "loglevel": "warning"
  },
  "dns": {
    "servers": [
      "localhost"
    ],
    "queryStrategy": "UseIP"
  },
  "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": "vless",
      "settings": {
        "vnext": [
          {
            "address": "server.example.com",
            "port": 443,
            "users": [
              {
                "id": "11111111-2222-4333-8444-555555555555",
                "encryption": "none"
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "tcp",
        "security": "tls",
        "tlsSettings": {
          "serverName": "server.example.com"
        }
      }
    },
    {
      "tag": "direct",
      "protocol": "freedom",
      "settings": {}
    },
    {
      "tag": "block",
      "protocol": "blackhole",
      "settings": {}
    }
  ],
  "routing": {
    "domainStrategy": "IPIfNonMatch",
    "rules": [
      {
        "type": "field",
        "ip": [
          "geoip:private"
        ],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "network": "tcp,udp",
        "outboundTag": "proxy"
      }
    ]
  },
  "policy": {
    "levels": {
      "0": {
        "handshake": 4,
        "connIdle": 300
      }
    }
  }
}

A Complete Example Does Not Mean Its Node Parameters Are Ready to Use

The JSON hierarchy above is complete and shows how the sections fit together, but its server domain and user ID are documentation examples. A real configuration must replace them with the complete parameters from your own subscription or service, and streamSettings must match the remote side. If the actual node uses a different protocol or transport, replace the entire proxy outbound object instead of changing only the protocol name. Protocol objects have different internal structures, and changing one string can leave incompatible fields behind.

With v2rayN, v2rayNG or v2flyNG, import the node first and inspect the outbound structure generated by the client. Then apply the required routing logic where the client supports it. Do not discard correctly generated node parameters just to use the example here. A configuration reference explains structure and supports troubleshooting; it is not a requirement for every user to handwrite all connection details from an empty file.

Run Syntax and Core Configuration Checks

For the first layer, use a JSON-aware editor to check brackets, quotes and commas. The second layer requires the actual core to read the configuration. When running Xray independently, a common test is xray run -test -config config.json; for V2Ray, use v2ray test -c config.json if supported by the local executable. Follow the help output of the core installed on the device, since client wrappers and executable locations may differ.

Graphical-client users usually do not need to test a temporary configuration manually in a terminal. Restart the core and inspect the client logs instead. If the client regenerates the file before startup, save changes through its provided editing entry point. When a test reports an unknown field, first confirm whether the core is V2Fly or Xray, then check whether the field belongs at the top level, in inbound settings, protocol settings or streamSettings. A valid field at the wrong level is still invalid.

Validate Four Stages After Startup by Following Traffic Flow

After the configuration loads successfully, verify the runtime path. First check the inbound: confirm that the port is listening and that the application’s proxy type matches it. Second check routing: visit a target and see whether the log selects proxy or direct. Third check the outbound: confirm that the remote connection and handshake complete. Fourth check the destination response: make sure the application receives real content, not merely a successful local proxy connection.

If stage one fails, focus on port conflicts and the listen address. If stage two is wrong, check rule order, target form and tags. If stage three fails, check the node, network and transport parameters. If the first three stages pass but the fourth fails, inspect DNS, the destination service and the application itself. This staged approach is more effective than constantly changing nodes and prevents local port problems from being mistaken for remote failures.

Preserving Changes When the Client Overwrites Configuration

v2rayN may reorganize the core’s runtime configuration when switching servers, updating subscriptions or changing proxy modes. Content that must persist should go into the client’s supported custom routing, DNS or custom-configuration features, not only into a temporary JSON in the runtime directory. Export or record the current settings before editing, then confirm that custom rules are still merged after an update. For installation and configuration-file location details, see the complete v2rayN first-install and initial-setup guide.

Android clients may also store single-node profiles, subscription entries and runtime configuration separately. Editing one node changes that node’s protocol parameters, but not necessarily global routing. First confirm whether the page you are editing controls a node, routing or app settings, then test the result. v2rayNG primarily uses the Xray core path, while v2flyNG is an alternative for the v2fly core; because their extension fields differ, do not copy complete JSON between them without checking compatibility.

08 / TROUBLESHOOTING

Troubleshooting Configuration Errors and Connection Failures

Startup Fails Immediately: Find the First Clear Error

When the core fails to start, the log may contain several cascading messages. The real cause is usually near the earliest clear error. Common types include JSON parsing failures, unknown fields, invalid data types, port conflicts, inaccessible file paths and missing tags referenced by routing. Fix the first error and restart; do not modify several areas at once based on later messages, because they may only be consequences of the initial failure.

A JSON parsing error usually includes a line number or character position. Check for a missing comma, a trailing comma, an unclosed quote or full-width punctuation around that location. The position may indicate where the parser noticed the problem while the actual omission is on the previous line. In a long file, temporarily remove the entire recently added object, confirm that the base configuration works, then restore the fragment one level at a time.

The Core Runs, but the Application Cannot Connect to the Local Proxy

Do not check the remote node first. Confirm that the application’s proxy address is 127.0.0.1, that the port matches the inbound and that the proxy type is correct. If using the system proxy, check that the client has enabled the corresponding mode; starting the core alone does not necessarily change system settings. Browser extensions, in-app proxies and the system proxy can coexist, creating duplicate paths or pointing to an old port. For testing, keep one clear path.

On Windows, macOS and Linux desktops, an old process occupying the port is common. Exit the client, confirm that the core process has ended, and then reopen it. If you changed the inbound port, update the system proxy too. Android clients use system-provided network interfaces to intercept application traffic, so troubleshooting differs from a desktop SOCKS port; first check that the client is connected and that the core started successfully in the runtime logs.

The Local Proxy Connects, but the Remote Handshake Fails

When logs show a refused connection, failed handshake or early remote close, check in this order: address and port → user identity → protocol → transport → security layer. A resolvable domain does not prove that the port serves the right service, and a successful TCP connection does not prove that the TLS name and application transport match. For subscription nodes, perform a normal update first and confirm that the current entry is not using old parameters; for manual nodes, compare each field with the original configuration.

An obviously incorrect system clock can break time-dependent secure connections, so restore the device time first. If switching networks makes the problem disappear, also check the current network, DNS and address family rather than changing only the protocol. Follow the node timeout troubleshooting checklist step by step instead of repeatedly editing the outbound object while skipping the local network and system time.

Only Some Websites or Applications Fail

Failures limited to certain targets usually mean the basic inbound and at least one outbound work; focus next on routing, DNS, UDP and destination characteristics. Compare which outbound a successful target uses with the one used by a failed target, then check whether the failed request entered the core as a domain or IP. If a mistaken rule sends a domain to direct, a healthy node will not participate. If domainStrategy resolves a different address family, the result may also differ from the domain rule’s intent.

Login, voice, video and synchronization features may use different domains, ports and network types. Opening the home page proves only that some requests succeeded. Do not assign an application’s entire domain to one broad rule based on the home page alone. During reproduction, record the logged destination for the failed feature and add only the necessary conditions. For UDP, check whether the SOCKS inbound allows it, whether the protocol and server support the path, and whether routing sends UDP to the correct outbound.

The Rule Looks Correct but Never Matches

First check the rule’s position. Is there a broader domain, IP, network or port condition above it? Next check the target form: does the log show a complete domain, a subdomain, an IP or a name recovered through sniffing? Then verify the prefix: full does not automatically cover every subdomain, while keywords may be too broad. Finally check the spelling of outboundTag and the active runtime file; you may have edited a backup while the client loads another configuration.

To verify a rule, temporarily move it near the top and restrict it to one explicit domain. Check the outbound tag in the log. If it still does not match, the problem is the target form or an unloaded configuration. If it matches only after being moved up, an earlier rule intercepted it. Once the cause is clear, reorganize the order instead of permanently piling every new rule at the top, which eventually causes specific rules to override one another.

The Connection Drops After Running for a While

First determine whether the disconnect occurs at a consistent interval. If it repeatedly happens near connIdle or a one-way connection policy threshold, inspect policy. If the timing is random, check remote resets, network changes, device sleep and address changes. When a laptop moves between networks, old connections becoming invalid is normal and the client usually needs to establish them again. Do not attribute a single post-sleep interruption directly to node parameters.

timeout, context canceled and connection reset in the logs represent different stages and initiators. Do not apply the same fix to every message containing “error.” For timeout, use the preceding record to determine whether the issue is DNS, dialing or the handshake. context canceled may mean that an upper-layer request ended deliberately; reset means one side reset the connection. Find the earliest anomaly on the timeline before treating later errors as cancellation or cleanup.

Keep Reproducible Troubleshooting Notes

For a complex configuration, keep a short record containing the client name, core family, inbound port, default outbound, recently changed areas and reproduction steps. Do not store sensitive node information; the structure is enough. For each test, write down what changed, what you expected and what the logs showed. After two or three rounds, most guesses can be eliminated. Switching many options without taking notes makes it hard to identify the cause even if the problem happens to disappear.

When recovery is needed, return to the minimal working configuration, then add DNS, split routing and policy one at a time. If the minimal setup still fails, the problem is more likely the client installation, local network or node itself; return to the quick-start path to recheck import and connection steps. If only custom rules fail, keep the verified node outbound and focus on routing and target logs instead of reinstalling the client.

Failure Layer Typical Symptom Priority Action
JSON and Fields The core cannot start Fix the first parsing or field error and inspect recent changes
Inbound The application cannot connect to the local proxy Check the address, port, protocol type and port usage
Routing The target uses the wrong outbound or no rule matches Check the target form, rule order and actual outbound tag
DNS Domain failure or unexpected resolution result Confirm the query path, server conditions and address family
Outbound The remote side refuses, the handshake fails or the connection times out Check address, identity, protocol, transport and security layer as a set
Policy and Session The connection drops after a fixed idle period Compare policy thresholds with the log timeline
Download v2rayN