CONFIG / JSON REFERENCE

V2Ray Configuration File Reference

From the top-level JSON object to inbounds, outbounds, routing, dns, and policy, this guide breaks down each section by data flow, responsibility, matching order, and troubleshooting scope.

Applies to: V2Fly / Xray configuration systems Format: JSON Updated: 2026-08-19

READING MAP

Tutorials guide the workflow; the reference covers the fields.

The user guide walks through “import a configuration, choose a node, enable the proxy, and check the connection.” This page avoids repeating interface buttons and instead explains the configuration that the client ultimately passes to the V2Fly or Xray core. When a field’s meaning is unclear, a rule does not match, or DNS traffic takes an unexpected path, return here and troubleshoot by module.

Start by forming a data-flow model: application traffic enters an inbound listener, the routing module reads the domain, IP, port, and inbound tag, selects an outbound tag, and lets that outbound establish the connection. DNS, policy, and logging do not replace this path; they provide resolution results, runtime constraints, and diagnostic data.

01 / ROOT OBJECT

JSON structure overview and data-flow boundaries

The top-level object is not an execution checklist

The root of a V2Ray configuration file is a JSON object. Common top-level fields include log, dns, inbounds, outbounds, routing, policy, and stats. Their order in the file usually does not determine execution order: placing routing before inbounds does not make routing start first. Runtime behavior is defined by module responsibilities and tag references. Arrange fields for readability, but do not mistake visual order for control flow.

Both inbounds and outbounds are arrays because one core instance can listen on multiple entrances and prepare multiple exits. Each object in an array usually gets a stable name through tag. Routing rules use inboundTag to restrict the source and outboundTag to select the destination. Tags are internal reference keys, not protocol names; labels such as proxy, direct, or a more specific role are all fine as long as every reference matches and remains maintainable.

JSON syntax and client-generated configurations

Standard JSON requires double quotes around property names and strings, disallows trailing commas, and has no native comment syntax. Booleans must be written as true or false, and numbers such as ports should not be quoted. Chinese text, paths, and domain names can appear directly in a UTF-8 file, but backslashes in Windows paths must be escaped. After manual edits, if the client reports that the configuration cannot be parsed, check syntax first and protocol fields second. Until parsing succeeds, the core has not reached the network-connection stage.

v2rayN, v2rayNG, and v2flyNG generate or combine core configurations from their interface settings. v2rayN is the preferred desktop client for reviewing routing, system proxy settings, and core logs; on Android, v2rayNG uses the Xray core, while v2flyNG uses the V2Fly core. Temporary configurations generated by a client may be overwritten after a restart, node switch, or subscription update. Maintain persistent rules through the client’s custom configuration, routing settings, or supported template entry points instead of editing temporary files in the runtime directory.

{
  "log": {
    "loglevel": "warning"
  },
  "dns": {
    "servers": [
      "1.1.1.1",
      "8.8.8.8"
    ]
  },
  "inbounds": [
    {
      "tag": "socks-in",
      "listen": "127.0.0.1",
      "port": 10808,
      "protocol": "socks",
      "settings": {
        "udp": true
      }
    }
  ],
  "outbounds": [
    {
      "tag": "direct",
      "protocol": "freedom"
    }
  ],
  "routing": {
    "domainStrategy": "AsIs",
    "rules": []
  }
}

A minimal configuration needs only one inbound that can receive traffic and one outbound that can establish a connection, but real clients may add a local API, statistics, DNS, or several routing groups. When reading a large configuration, hide modules unrelated to the issue: if nothing starts, inspect JSON, the inbound, and the outbound; if only some domains use the wrong exit, inspect routing; if domains fail while IP addresses work, start with DNS. Narrowing the scope by failure boundary is more reliable than changing lines blindly.

02 / INBOUND

inbounds: listeners, protocols, and traffic identification

listen, port, protocol, and tag

An inbound determines which local or network connections may enter the core. Common local entry points are SOCKS and HTTP proxies: a browser, terminal, or system proxy sends requests to the listener, and the core handles the remaining routing. With listen set to 127.0.0.1, only local connections are accepted, which suits a single-device client. Listening on all interfaces expands access; unless LAN access is explicitly required, do not expose it casually. The port must be free, and the same address-and-port pair cannot be bound by two inbounds.

protocol defines the entry protocol, while the structure of settings depends on that protocol. A SOCKS inbound commonly uses udp to control UDP forwarding; an HTTP inbound accepts standard HTTP proxy and CONNECT requests. tag lets routing identify the source—for example, tagging a browser-specific listener as browser-in allows dedicated rules. A tag cannot replace a port: the application must still connect to the correct listener port before the routing module can read the tag.

{
  "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 purpose and limits of sniffing

When an application gives the proxy only a destination IP but routing needs the domain name, sniffing can identify the domain from an HTTP request or TLS handshake. destOverride specifies which traffic types may be identified. This gives routing more complete domain information and usually makes domain-based splitting more consistent. Sniffing is not a replacement for DNS, however, and it cannot recover arbitrary content from every encrypted flow; it uses only destination information visible during connection setup.

When troubleshooting sniffing, separately observe the “original destination submitted by the application” and the “destination actually used by routing.” If rules work again after sniffing is disabled, the detected domain may be triggering another earlier rule. If domain rules still do not match with sniffing enabled, confirm that traffic really passes through the expected inbound rather than another proxy port on the system. Transparent proxying, virtual network interfaces, and ordinary SOCKS listeners receive different traffic sources, and enabling a mode in the client can change the generated inbound.

Field Purpose Common checks
listen Restricts the local address to listen on For local-only use, bind to the loopback address
port Port that accepts application connections Match the system proxy settings and confirm the port is free
protocol Defines the entry protocol The application’s proxy type must match
tag Referenced by routing and statistics modules Match the references in the rules exactly, including case

Inbound failures usually appear as an application unable to connect to the local proxy, a port-binding error, or UDP requests failing on their own. First use the client log to confirm that the listener started, then check the system proxy address and port. If a browser works but one application does not, check whether that application supports the selected proxy type, bypasses the system proxy, or requires UDP. Do not repeatedly change remote nodes before confirming that the local entry point is reachable; the traffic may never have entered the core.

03 / OUTBOUND

outbounds: protocol objects and exit selection

Remote, direct, and blocking exits

An outbound sends a routed connection to its final destination or a remote service. A complete configuration usually includes at least a remote proxy outbound and a direct outbound, with a blocking outbound added when needed. The remote outbound’s protocol may be VMess, VLESS, Trojan, or another protocol supported by both client and server. settings stores the server address, port, and authentication details; streamSettings describes the transport, security layer, and related parameters. These fields must match the server as a complete set: a correct protocol name does not make transport parameters interchangeable.

freedom means the device connects to the destination directly, commonly with the tag direct. blackhole actively terminates connections selected by a rule, commonly with the tag block. Both are standard outbounds, so routing only needs a different outboundTag rather than special action syntax. If a rule references a missing tag, loading may fail or the core may be unable to find the target outbound at runtime. After renaming a tag, search for and update every reference.

{
  "outbounds": [
    {
      "tag": "proxy",
      "protocol": "vless",
      "settings": {
        "vnext": [
          {
            "address": "server.example.com",
            "port": 443,
            "users": [
              {
                "id": "11111111-2222-3333-4444-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"
        }
      }
    }
  ]
}

Review streamSettings as a complete set

streamSettings.network describes the underlying transport, such as TCP, WebSocket, or gRPC; security selects a security layer such as TLS or REALITY. Transport-specific settings live in their corresponding child objects—for example, WebSocket uses a path and request headers, while TLS uses parameters such as the server name. Troubleshoot a remote outbound in three layers: first confirm that the server address and port are reachable, then verify the user credentials and protocol, and finally check transport and security details. “Connection closed” alone does not identify the failing layer.

When a server address is a domain name, the core must resolve it first, so an outbound failure may also originate in DNS. If the log shows an address was resolved but the handshake failed, inspect the protocol, time, server name, and transport parameters. If there is no resolution result, check dns and the system network first. Testing with a direct IP can separate resolution from connectivity issues, but TLS usually still requires the correct server name; an IP test is not automatically a valid final configuration.

Adjust connection multiplexing such as mux only after basic connectivity is stable. Multiplexing is not guaranteed to be faster on every network or protocol, and adding optimization parameters too early increases the number of variables. Start with one remote outbound, one direct outbound, and the minimum transport fields. Once it works, add routing, multiplexing, or extra outbounds step by step. Record each change so you can quickly identify the cause when rolling back.

Importing a client subscription automatically generates remote outbounds, so understand the update mechanism before overriding them manually. A subscription update may replace node parameters, while local routing is usually managed separately by the client. To get the client again, visit Get the client; to understand the difference between share links and subscription URLs, read Share links and subscription imports.

04 / ROUTING

routing: match order and traffic-splitting rules

Rules match in order; they are not merged automatically

The routing module reads connection attributes and selects an outbound. rules is an ordered array, normally checked from top to bottom. Once a connection matches an executable rule, that rule’s outbound is used. Put specific rules and rules that must take priority first, followed by broad fallback rules. Even when two rules overlap, the system does not calculate “more specific first”; actual priority comes from array position.

Common conditions include domain, ip, port, network, inboundTag, and protocol. Multiple conditions from different categories in one rule generally require the connection to satisfy all those categories, while multiple values within one category mean any one of them may match. For example, a rule containing both a domain and a port handles only connections meeting the domain condition and falling within that port range. Packing unrelated conditions into one rule often makes it look complete while ensuring it never matches.

{
  "routing": {
    "domainStrategy": "IPIfNonMatch",
    "rules": [
      {
        "type": "field",
        "ip": [
          "geoip:private"
        ],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "domain": [
          "domain:example.cn",
          "full:intranet.example"
        ],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "domain": [
          "geosite:category-ads-all"
        ],
        "outboundTag": "block"
      },
      {
        "type": "field",
        "network": "tcp,udp",
        "outboundTag": "proxy"
      }
    ]
  }
}

Domains, IPs, and domainStrategy

Domain conditions support several matching forms. full: matches a complete domain and suits a fixed hostname; domain: covers the specified domain and its subdomains; regexp: provides regular-expression matching, but complex expressions reduce readability and should be used only when ordinary matching is insufficient. geosite: references a domain collection in the core’s data files, whose availability depends on the resources bundled with the client. Naming a collection does not guarantee it exists in the current environment; check the log when loading fails or a rule has no effect.

IP conditions support individual addresses, CIDR ranges, and geoip: collections. Private addresses should usually go direct so LAN services are not sent through a remote exit. Whether a domain rule is resolved to an IP first depends on domainStrategy. AsIs mainly matches the original domain; IPIfNonMatch resolves it and checks IP rules when no domain rule matches; IPOnDemand triggers resolution more proactively for IP rules. More aggressive resolution can add DNS queries and change split-routing results; it is not automatically “more advanced.”

Strategy Primary behavior When to use it
AsIs Preserve the domain form from the request for matching Rules rely mainly on domains and should avoid extra resolution
IPIfNonMatch Resolve and check IP rules after no domain match Both domain rules and IP-range rules are used
IPOnDemand Resolve when an IP-based decision is required The resolution path is understood and IP classification is needed

Do not validate routing only by whether a website opens, since multiple exits may work. Temporarily place the target domain in an early rule with a clear tag, then use the log to confirm which outbound was selected. If it does not match, check in order whether traffic passed through the expected inbound, whether sniffing supplied a domain, whether the matching prefix is correct, whether an earlier rule captured the traffic, and whether the outbound tag exists. For a complete approach to DNS split routing and avoiding polluted results, continue with the V2Ray DNS split-resolution guide.

05 / DNS

DNS configuration: servers, hosts, and resolution paths

Built-in DNS handles only queries that enter its path

The dns module defines how the core resolves domains, but configuring DNS servers does not mean every query on the system will automatically use the core. An application may resolve domains itself, or the operating system may resolve them first and pass only an IP to the proxy. Whether a query reaches built-in DNS depends on the client mode, inbound type, routing policy, and application behavior. When DNS fails, first determine which layer performed the query instead of repeatedly replacing server addresses.

servers can contain simple addresses or server objects with domain matching. The simple form provides general resolution sources in list order; object form can use domains to send certain domains to a preferred server and expectIPs to restrict the expected address ranges. hosts provides static mappings or aliases and is useful for known fixed results, internal-service mappings, and test rules, but it is not suited to maintaining large lists of frequently changing public domains.

{
  "dns": {
    "hosts": {
      "domain:internal.example": "192.168.10.20",
      "dns-alias.example": "target.example"
    },
    "servers": [
      {
        "address": "223.5.5.5",
        "domains": [
          "geosite:cn"
        ],
        "expectIPs": [
          "geoip:cn"
        ]
      },
      {
        "address": "1.1.1.1",
        "domains": [
          "geosite:geolocation-!cn"
        ]
      },
      "localhost"
    ],
    "queryStrategy": "UseIP"
  }
}

Query strategy and DNS outbounds

queryStrategy controls which address families are preferred, such as allowing both IPv4 and IPv6 or requesting only one. Before choosing, confirm that the current network, remote exit, and target service actually support the selected address family. If the network lacks a stable IPv6 path but IPv6 results are preferred, resolution may succeed while connections time out. That is not necessarily a failed DNS server; the result may simply be incompatible with the available exit.

Advanced configurations can add a dns protocol outbound and route core-generated DNS traffic through a chosen exit. Check three objects together: dns.servers determines whom to query, the DNS outbound determines how queries are sent, and routing.rules determines which outbound handles them. Changing only one may create a resolution loop or an unexpected path. In particular, do not make DNS queries for the remote server’s domain depend on that same remote connection before it has been established.

{
  "outbounds": [
    {
      "tag": "dns-out",
      "protocol": "dns"
    }
  ],
  "routing": {
    "rules": [
      {
        "type": "field",
        "protocol": [
          "dns"
        ],
        "outboundTag": "dns-out"
      }
    ]
  }
}

Troubleshoot DNS in a fixed order: use system tools to confirm that the device itself has network access; check the core log to see whether a query was sent, which server received it, and what type of address was returned; then confirm that the address is reachable through the selected outbound. If the domain fails but a test IP establishes a TCP connection, continue checking DNS and the TLS server name. If resolution returns an address but every address times out, inspect routing and the outbound. Clearing the cache removes stale results but cannot repair an incorrect rule chain.

Keep split-routing configurations explainable. A stable starting point is to send local domains, local addresses, and clearly internal services to local resolution, then choose remote resolution for the rest as needed instead of stacking many exceptions. Change one variable at a time and record query logs before and after each edit. For a detailed field breakdown and practical ways to prevent DNS leaks, cross-check the earlier DNS configuration guide.

06 / POLICY

policy: timeouts, statistics, and resource limits

How level maps to policy objects

policy sets user-level and system-level runtime policies. User policies live under levels, whose keys are strings containing level numbers; the level in a protocol user object selects the policy set. This is not a network-quality score or a permission rank—it maps connection parameters to a given user. Most single-user clients can use level 0; add more levels only when different connection behaviors are genuinely needed.

Common user-level fields include handshake timeout, connection idle time, retention time when only upload or only download remains, and whether user upload and download statistics are enabled. Confirm the exact units and scope of each time field against the core documentation and logs; do not assume every value is milliseconds. Values set too low can terminate long-lived connections, background sync, or infrequent requests early, while values set too high can leave inactive connections consuming resources. Observe the actual failure before tuning; a policy object is not a universal speed switch.

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

How policy, stats, and API work together

Enabling statistics in policy only permits collection for the selected dimensions; the top level usually also needs a stats object. If the client interface needs to read statistics, it may additionally generate a local API inbound and related routing rules. Their roles differ: policy enables dimensions, stats starts the statistics module, and the API provides the access point. Copying only one part may leave the interface with no data.

Statistics add some runtime work, and whether they are needed depends on the client’s features. For checking connectivity, logs are often more direct than cumulative counters; enable the relevant dimensions when you need to monitor inbound and outbound traffic over time. Do not enable every switch for the sake of completeness or judge a protocol from a short sample. Application caching, concurrent connections, system updates, and background tasks all affect the result.

Policy item What it controls What an overly strict value looks like
handshake Time allowed during connection establishment Frequent handshake timeouts on a slightly slow network
connIdle How long an inactive connection is retained Low-frequency long-lived connections close early
uplinkOnly Retention window when only upload activity remains One-way transfers terminate too soon
downlinkOnly Retention window when only download activity remains The final part of a download or response stream is interrupted

Start policy troubleshooting with the defaults. If a connection type drops after a fixed idle period, compare connIdle. If failures occur only when the remote network occasionally slows down, check whether the handshake timeout is too low. If only statistics are missing while connections work, inspect the statistics switches, top-level module, and client API instead of changing the outbound protocol. Separating connection behavior from observability prevents a display problem from breaking a healthy link.

A client may manage policy and statistics automatically from its graphical settings. When manual configuration and client settings coexist, inspect the final generated file rather than only the custom fragment. v2rayN is well suited to checking generated output and logs on desktop systems; mobile configurations in v2rayNG and v2flyNG are usually managed by the apps, so import manual fields through supported entry points. Core support for extension fields varies; when migrating, add fields gradually from the essentials.

07 / LOGGING

Logging and observability: identify the module by the failure stage

loglevel controls information density

log is the first place to look when troubleshooting a configuration. Common loglevel values, from most to least detailed, include debug, info, warning, error, and none. Keep warning for normal operation; temporarily raise it to info or debug when reproducing complex routing or DNS problems, then restore it. Detailed logs may contain domains, addresses, tags, and connection steps, so do not publish an unredacted full file.

access and error specify where access and error logs are written. Without file paths, the client usually collects them from standard output or its own log window. Relative paths are based on the process working directory, which may not be the configuration file’s directory; restricted directories can also cause permission failures. When a graphical client already provides a log panel, prefer its managed output to avoid conflicts with updates, permissions, or portable directories.

{
  "log": {
    "access": "",
    "error": "",
    "loglevel": "warning",
    "dnsLog": false
  }
}

Read logs by stage instead of searching only for error

A connection broadly passes through configuration loading, inbound acceptance, destination identification, DNS resolution, route selection, outbound dialing, protocol and security handshakes, and data transfer. The last log line is only the visible result; the real cause often appears earlier. “Connection closed” may mean a remote disconnect, mismatched handshake parameters, or an upstream timeout. “Outbound not found” points more directly to a tag reference problem, while “address already in use” occurs during inbound listening and has nothing to do with node parameters.

When troubleshooting, record the reproduction time and target, then clear old logs or start reading near that timestamp. Repeated attempts interleave records, and testing with several applications makes it difficult to identify the relevant connection. Close unrelated programs, send one browser request, and follow the complete path from inbound to outbound. For routing, focus on the inbound tag, domain or IP conditions, and final outbound tag; for DNS, inspect the query server, returned address, and subsequent connection; for handshakes, inspect the server name, transport, security layer, and system time.

If the client exits immediately after launch, first check the runtime environment, directory permissions, core files, and port conflicts. Windows desktop clients may also be affected by runtime libraries or restrictions on writing to protected directories; Android clients require a check for background-execution limits. See Troubleshooting v2rayN startup crashes and v2rayNG sudden exits for related steps. These failures occur outside the configuration path or early during loading and should not be attributed directly to the remote protocol.

Comparing logs is more useful than relying on a single screenshot. Keep the startup and connection records from a working configuration, then compare them with the modified records: is a listener missing, did DNS return different addresses, did the same domain choose another outbound, or did the handshake fail before rather than after resolution? Comparing stages quickly narrows the scope. After diagnosis, remove temporary debug settings and test rules so excessive logging does not accumulate and high-priority test rules do not affect daily routing.

08 / VALIDATION

Configuration validation and troubleshooting: a fixed execution order

Syntax first, references second, network last

Run validation in layers. First check JSON syntax: matching brackets, correct commas, closed strings, and valid number and boolean types. Next check internal references: every outboundTag, inboundTag, and policy level must correspond to an existing object, with matching tag case. Only then check the network: listener ports, DNS, server address, protocol authentication, transport, and security. Replacing a node before these first two layers are verified can hide a simple error behind network symptoms.

The core usually supports testing a configuration or starting with a specified configuration, but clients may wrap these functions differently and core command-line parameters vary. Users of graphical clients should start with the client’s configuration-check and log interfaces instead of running commands without knowing the runtime directory. In a standalone core environment, view the current executable’s help first, then load the configuration with supported parameters. Successful validation means the structure and fields were accepted; it does not prove that the remote service is reachable.

{
  "log": {
    "loglevel": "info"
  },
  "inbounds": [
    {
      "tag": "test-in",
      "listen": "127.0.0.1",
      "port": 10808,
      "protocol": "socks",
      "settings": {
        "udp": true
      }
    }
  ],
  "outbounds": [
    {
      "tag": "direct",
      "protocol": "freedom"
    }
  ],
  "routing": {
    "rules": [
      {
        "type": "field",
        "inboundTag": [
          "test-in"
        ],
        "outboundTag": "direct"
      }
    ]
  }
}

Use a minimal configuration to isolate the failure

The minimal configuration above validates only a local SOCKS inbound, routing tags, and a direct outbound. If it cannot start, focus on syntax, the port, and the local runtime environment. If it starts and reaches the target, replace the direct outbound with the real remote outbound to determine whether the issue has entered the remote protocol layer. Then restore DNS, domain rules, IP rules, blocking rules, statistics, and policy in sequence. Restore one group of fields at a time so a failure can be tied to the module just added.

Classify common errors by symptom. Immediate startup failure usually involves JSON, unknown fields, tag references, port conflicts, or file permissions. An unreachable local proxy usually means the listener address, port, and application proxy type do not match. All domains failing while some IPs work usually points to the DNS path. Only certain domains using the wrong exit usually points to rule order, sniffing, or matching-prefix issues. A connection that drops soon after establishment calls for checks of policy timeouts, the remote handshake, and network stability. Classification is not the final diagnosis, but it tells you which part of the log to read first.

Symptom Priority module First check
Configuration will not load JSON / field structure The line with the parse error and the comma on the preceding line
Local port cannot be reached inbounds Whether the listener started and the port matches
Domain fails but the address is reachable dns / routing Whether the query reached the core and what it returned
Only one rule group behaves incorrectly routing Rule order and the final outbound tag
Disconnects immediately after the handshake outbounds Whether the protocol, transport, and security layer match as a complete set

Client environments also introduce configuration overwrites. v2rayN may regenerate the runtime configuration after switching nodes, updating a subscription, or changing routing mode; v2rayNG and v2flyNG likewise build core parameters from app settings. If a manual edit to a temporary file works briefly and disappears after restart, the core usually did not ignore it—the client regenerated the file. Put persistent settings in the client’s supported custom routing, template, or import entry point.

Final acceptance testing should not stop at whether one webpage opens. Verify at least direct access to a local address, ordinary domain resolution, the expected proxy domain, UDP requirements, client restart behavior, and behavior after a subscription update; confirm in the log that the selected outbound tags match the design. If you are new to the client, complete the basic path through the user guide first, then return here to add rules. To choose another installer, visit Get the client and download for Windows, macOS, Android, or Linux. Reliable complex configurations come from clear boundaries, staged validation, and rollback records—not from the number of fields.

NEXT STEP

Expand the configuration from a working baseline

For a first setup, install the client and import a subscription; once the basic path works, adjust inbound, outbound, routing, DNS, and policy sections in that order.