CONFIG.JSON / FIELD REFERENCE

V2Ray Configuration Reference

Connections enter through inbounds, then routing selects an outbound. Find issues by field, and keep client UI options distinct from core configuration.

For first-time setup and subscription imports, start with the Quick Start. Use this page to inspect generated configs, write custom snippets, and review runtime logs. Desktop users should first choose the right platform from the v2rayN client page, then return here to look up configuration fields.

JSON Structure and Configuration Boundaries

Separate Client Settings from Runtime Core Files

Configuration in the V2Ray ecosystem generally has two layers. The first is the GUI client's subscriptions, groups, interface preferences, and proxy mode. The second is the runtime configuration generated when the core starts. Both may use JSON, but their fields do not mean the same thing. A subscription refresh interval belongs to client management logic and cannot simply be added to the core's root object. Before inspecting a file, determine whether it is a client database, subscription data, or the configuration actually read by the core. The same file extension does not make files interchangeable.

Think of runtime configuration as a data flow: inbounds accept application connections, routing selects an outbound, outbounds handle direct connections, proxying, or blocking, dns configures built-in name resolution, and policy adjusts connection behavior. log provides startup and runtime details. These modules can reference one another, but you do not need to enable every feature from the start. The more features you add, the more conditions you need to verify. For troubleshooting, keep the path minimal and restore features one at a time.

Minimal Config: Local SOCKS Inbound and Direct Outbound

This is a complete basic configuration that does not rely on a remote proxy. Once an application is explicitly set to use the local SOCKS port, the core connects directly to the destination. Use it to check whether the config loads, the port listens, and the application actually reaches the inbound. It is not a remote-node setup and will not take over system traffic automatically. The example port is for illustration only. If the client already uses it, close the other process or choose an unused port to prevent two instances from competing for the same address.

{
  "log": {
    "loglevel": "warning"
  },
  "inbounds": [
    {
      "tag": "local-socks",
      "listen": "127.0.0.1",
      "port": 10808,
      "protocol": "socks",
      "settings": {
        "auth": "noauth",
        "udp": true
      }
    }
  ],
  "outbounds": [
    {
      "tag": "direct",
      "protocol": "freedom",
      "settings": {}
    }
  ]
}

Valid JSON Is Only the First Check

JSON objects use braces, arrays use square brackets, and field names and strings use double quotes. Numeric ports should not be quoted as text; Boolean values use true or false. Do not add comments, trailing commas, or single quotes to a production file. Snippets in articles usually show only one module, so place them at the correct level. Putting the entire root object inside an inbound's settings may still produce valid JSON, but it does not meet the core's structural requirements.

After checking syntax, verify that the current core supports the fields, all referenced tags exist, and external file paths are accessible. Xray and V2Fly share some configuration concepts, but their newer protocols, transport fields, and test options are not fully identical. Do not judge compatibility by the client name alone; check which core actually starts and review its logs. A GUI's ability to import a share link does not mean the selected core can run every transport parameter it contains. Importing successfully and connecting successfully are separate stages.

Before making changes, save a working configuration and note whether each change was made in the client interface or a custom file. If the client generates the runtime file automatically, direct edits may be overwritten when you switch nodes or restart. Instead, make regular changes in the interface, then add extensions through an explicitly supported custom configuration option. If you cannot find that option, export or inspect the generated config first; repeatedly editing a temporary file is not a persistent solution. This layered approach applies throughout the guide and helps distinguish overwritten changes from ineffective fields.

Inbounds: Listen Address, Port, and Protocol

An Inbound Defines How Applications Connect to the Core

inbounds is an array; each object represents an entry point that accepts connections. tag is the name used by routing, listen sets the local bind address, port sets the listening port, and protocol determines the inbound protocol. If an application is configured to use an HTTP proxy, it needs an HTTP inbound; if it uses a SOCKS proxy, it needs a SOCKS inbound. The two cannot be interchanged by changing the port alone. A successful TCP connection to the port does not mean the application and inbound use the same proxy handshake.

For local use, prefer 127.0.0.1 as the listen address. It binds the entry point to the IPv4 loopback interface, so connecting the computer to another network will not automatically expose it to the LAN. 0.0.0.0 binds to all available IPv4 interfaces. This may suit a carefully considered LAN-sharing setup, but you should also restrict access with a firewall. The listen address is neither the remote server address nor the destination address other devices should use. Those devices should connect to the computer running the client using its actual address on the same LAN.

Two-Inbound Example and Field Descriptions

{
  "inbounds": [
    {
      "tag": "local-socks",
      "listen": "127.0.0.1",
      "port": 10808,
      "protocol": "socks",
      "settings": {
        "auth": "noauth",
        "udp": true
      }
    },
    {
      "tag": "local-http",
      "listen": "127.0.0.1",
      "port": 10809,
      "protocol": "http",
      "settings": {}
    }
  ]
}

The example assigns separate ports to the two protocols so they are easy to distinguish in application settings. The SOCKS udp option lets the inbound handle applicable UDP requests, but does not guarantee UDP will work end to end. The application must use that capability, the outbound protocol and remote endpoint must support it, and the network along the way may still restrict packets. If web browsing works but a real-time app does not, check separately whether the app reaches the inbound, sends UDP, and has a compatible outbound path. Repeatedly toggling the inbound option alone is unlikely to help.

FieldPurposeWhat to Check
tagInbound reference nameMust match the routing rule's inboundTag
listenLocal bind addressConfigure loopback access separately from LAN sharing
portListening portMust be unused and match the port set in the application
protocolInbound protocolMust match whether the application uses HTTP or SOCKS

Sniffing, system proxy, and TUN are separate features

An inbound can use sniffing, where supported by the core, to identify details such as the destination domain from some protocol handshakes. This can help with domain-based routing, but it is not a general-purpose content parser. The information available depends on encrypted handshake details, the application, and core settings. Sniffing can also affect how the original destination and detected domain are used, so it should not be treated as the default fix for every routing issue. First check whether the application passes a domain or an IP, then decide whether sniffing is needed and review how the selected core handles its options.

A system proxy tells the operating system to advertise a proxy endpoint to applications that honor that setting; it does not create an inbound by itself. TUN involves a virtual network interface, traffic routing, and DNS coordination. You cannot enable it by adding a Boolean field with the same name to the JSON above. Its capabilities depend on the client, selected core, and supporting implementation. To check the path, first confirm the local port is listening, then make sure the system proxy points to it, and finally check whether the target application honors system settings. Separating these steps helps prevent an application's direct connection from being mistaken for a core routing error.

LAN sharing also requires accounting for changing device addresses, guest network isolation, and computer sleep. Similar device names or connection to the same access point do not prove that two devices can reach each other. Check connectivity on the same subnet first, open only the required port, and close unneeded inbounds after testing. See Allow LAN Connections in v2rayN for the full setup. Do not leave the computer's firewall disabled as a troubleshooting measure; prefer a rule limited to the required port and source network, and document its purpose.

Outbounds: Destination Connections and Tag References

Outbounds Handle Connections, Not Subscription Management

outbounds is also an array; each object describes one way for traffic to leave the core. The common freedom protocol connects directly to the destination, while blackhole blocks traffic. Proxy protocols require connection parameters that match the remote endpoint. tag is the name routing uses to select an outbound; it is not the protocol itself. Naming a tag proxy does not give it remote proxy capabilities. Its behavior is determined by protocol, settings, and any applicable transport settings.

When no rule matches, the first outbound in the array is generally used, so array order matters. If traffic should use a proxy by default, make sure the first item is the intended proxy outbound; for direct connections by default, the first item can be a direct outbound. Do not assume unmatched connections automatically find an object named proxy. A GUI client may reorder or regenerate outbounds based on the selected mode. Check the runtime config rather than inferring the default behavior from the order shown in a subscription list.

Use a Local Upstream to Demonstrate Proxying, Direct, and Blocked Traffic

This snippet uses another local SOCKS service as its upstream to keep the example separate from real remote credentials. The first outbound can connect only if a working SOCKS service is actually available at 127.0.0.1:10810. Do not point it back to the inbound port, or you may create a loop. If you are only testing the direct connection from the first chapter, you do not need this snippet. Before adding an upstream, verify that it can handle requests independently.

{
  "outbounds": [
    {
      "tag": "proxy",
      "protocol": "socks",
      "settings": {
        "servers": [
          {
            "address": "127.0.0.1",
            "port": 10810
          }
        ]
      }
    },
    {
      "tag": "direct",
      "protocol": "freedom",
      "settings": {}
    },
    {
      "tag": "block",
      "protocol": "blackhole",
      "settings": {}
    }
  ]
}

Check Protocol and Transport Parameters Separately

VMess, VLESS, Trojan, and Shadowsocks use different authentication structures. Do not copy one protocol's settings object under another protocol. Matching server addresses and ports only means the destination endpoint is the same; it does not prove the authentication parameters are correct. For subscription-provided nodes, preserve the imported parameters first, then check that the client recognizes the protocol and review the transport type, security layer, and server name. When troubleshooting, change only one field you have confirmed is wrong. Changing the protocol, transport, and routing all at once makes results difficult to compare.

streamSettings holds applicable transport and security settings, but its structure varies by protocol and core capabilities. A WebSocket path, a TLS server name, and REALITY parameters are not interchangeable strings. The transport must match the server, as must the security layer. Do not disable certificate verification to conceal a name or time mismatch; first check the system clock, server name, and server certificate requirements. If a connection fails during the handshake, changing the routing rules will usually not fix mismatched remote parameters.

Whether the same remote node works across different cores depends on both protocol and transport features. Do not choose based on the protocol name alone: recognizing VLESS does not guarantee support for every security parameter in a link. For differences between the two core branches, see Xray vs. V2Fly Core. Confirm compatibility before switching cores, then inspect the generated file to make sure the client has not retained outdated settings or dropped parameters it cannot represent.

Keep a clear fallback when managing outbounds. When adding a proxy outbound, retain verifiable direct and block tags, then use a narrowly scoped rule to test a destination. Expand the rule only after the test succeeds. Before deleting an outbound, search routing and other modules for references to it; dangling tags can cause config errors or unexpected connection handling. Features such as connection reuse and chaining are best assessed separately after the basic connection is stable, not included by default in a minimal example.

Routing: Rule Order and the Default Outbound

Rules Match in Order, Not by How Their Labels Read

Routing determines which outbound receives a connection; it does not determine whether the remote node is reachable. The rules array is generally checked from top to bottom, and a matching rule selects its target outbound. Put specific rules before broad ones—for example, handle LAN destinations first, then a category of domains, and only then consider rules covering a wider range. If the first rule already matches all TCP and UDP traffic, later specific rules never take effect. A large number of rules does not make routing more precise; what matters is whether their conditions overlap or are overridden.

Different types of conditions in one rule generally all need to match; multiple values in the same condition array generally offer alternative matches. For example, including both domain and port means the destination must match the domain condition and the port condition, not either one. To match a domain or an IP, it is usually clearer to use two rules. When reviewing imported rules, restate their conditions as a complete sentence. This makes it easier to spot an intersection mistakenly written as a union.

Direct LAN Traffic and Block Specific Domains

{
  "routing": {
    "domainStrategy": "AsIs",
    "rules": [
      {
        "type": "field",
        "ip": ["geoip:private"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "domain": ["full:blocked.example"],
        "outboundTag": "block"
      }
    ]
  }
}

This config requires existing direct and block outbounds, and a core that can load the relevant regional IP data. The example domain is for illustration and does not represent a real service. Connections that match no rule use the default outbound; if the proxy is first as in the previous chapter, the remaining traffic goes through it. Note that AsIs does not actively resolve a domain destination for IP-based rules. If you access an internal service by domain, a private-IP rule alone does not guarantee a direct connection. Add a separate domain rule for internal domains, or carefully assess the resolution strategy.

Domain Rules, IP Rules, and Data Files

full: matches a complete domain name, while domain: matches a specified domain and its subdomains. Plain text and regular expressions each have their own semantics. For a specific host, exact matching is easier to audit; use domain matching when you need to cover an entire domain. Use regular expressions only after confirming simpler rules cannot meet the requirement, and remember to escape backslashes in JSON strings. Pasting text straight from a regex tester into JSON may change its meaning because the escaping levels differ.

geosite: and geoip: reference data categories; they are not live lookup services. Whether a category exists, what records it contains, and whether it changes after an update all depend on the data file actually loaded. A correctly spelled rule can still fail to start if the file is missing, the path is wrong, or the category does not exist. After updating data through the client's supported option, restart the relevant core and check its logs. Do not replace data files from multiple sources at once and judge success only by browser results. First verify that the core loaded the expected file from the expected path.

StrategyBehaviorWhat to Know
AsIsDoes not resolve domains for routing matchesA domain destination does not automatically gain an IP-based condition
IPIfNonMatchTries to resolve the domain for matching if no domain rule matchesResolution results may affect subsequent IP rules
IPOnDemandTries to resolve when a matching condition requires an IPCreates an earlier dependency on DNS; check DNS settings too

These strategies determine when routing performs resolution. They are not the DNS module's address-family setting, nor do they determine how a direct outbound ultimately connects. A domain may first be used for rule matching, while the outbound or remote endpoint resolves it later for the connection. Troubleshooting requires distinguishing the address used to select a route from the address used for the actual connection. If these stages use different resolvers, an IP in the logs may not match the final access path. Do not assume the entire route is fixed just because you see one resolution result.

To test a new rule, choose a specific destination, note whether the input is a domain or an IP, and temporarily narrow the rule's scope. Check the access logs to see whether the request reaches the expected inbound and outbound, then restore the full rule. Application caches or existing long-lived connections may bypass a new routing decision, so close old connections and make a fresh request before testing. If the client automatically updates routing templates, also confirm that custom rules survive the update. You can cross-reference common rule questions with the FAQ rather than repeatedly switching between templates.

DNS Configuration: Resolvers, Address Families, and Connection Paths

First, Identify Where DNS Resolution Happens

The first DNS question is not which server to enter, but where resolution takes place. An application may use the system resolver to get an IP and then pass that IP to the proxy; it may pass a domain to a SOCKS or HTTP inbound; the core may resolve it proactively because of a routing strategy; or the remote proxy may handle the final lookup. Changing the dns module affects a stage only when the request actually uses core DNS. System DNS, a browser's own resolution settings, and core DNS are separate controls. One setting change cannot explain every application's behavior.

When investigating, record the destination input, the application's proxy method, and the routing strategy. If the application has already passed an IP, the core generally cannot recover the original domain from DNS settings alone. Sniffing may provide some clues, but it cannot identify every connection. Conversely, when the application passes a domain, AsIs may prevent routing from triggering resolution. Reconstruct the request path first, then decide whether to change system resolution, application settings, or the core module. This helps avoid treating resolver caches, rule matching, and remote connection failures as the same DNS issue.

Static Mapping and DNS Server Examples

{
  "dns": {
    "hosts": {
      "full:reference.example": "192.0.2.10"
    },
    "servers": [
      "223.5.5.5",
      "1.1.1.1"
    ],
    "queryStrategy": "UseIP"
  }
}

The static mapping here uses documentation-only example addresses, not a reachable service; it illustrates how to override a domain. The two server addresses show configuration format only and are not suitable for every network. How multiple DNS servers are selected, queried concurrently, or used as fallbacks depends on the config format and core implementation. Do not assume an array behaves like a browser's bookmark list, tried in order. Before using it in production, confirm that the servers are reachable from the current network and that requests follow the expected path. Static mappings change results for the relevant domains, so remove entries you no longer need after testing.

Address-Family Strategies and IPv6

queryStrategy constrains which address families built-in DNS queries or uses. UseIP considers both IPv4 and IPv6, while UseIPv4 or UseIPv6 imposes a specific family. Choose an address-family setting based on actual network capabilities, not whether the device interface displays an IPv6 address. A local IPv6 address does not prove there is a complete IPv6 route to the destination. Conversely, permanently disabling IPv6 system-wide to work around one timeout may affect other applications that work correctly.

If some domains resolve but cannot connect, compare the returned address family with outbound reachability. If failures occur only when an IPv6 result is returned, test IPv4 resolution within a limited scope, then check local routing, the remote exit, and server listening status. If resolution itself times out, first verify the path to the DNS server. Do not treat “an address was resolved” and “the service at that address is reachable” as the same thing. DNS success only confirms that a response was received; the subsequent port connection and security handshake still need separate checks.

With domain-based DNS routing, a server object may include matching domains, desired IP ranges, and fallback options. Their interactions are more complex than a simple server array, and extended fields vary between cores. Establish a working baseline with one server before adding domain scopes and fallback conditions. If you start by adding several categories, address restrictions, and fallback switches at once, an empty response is difficult to diagnose: the upstream could be unreachable, the answer could be filtered, or the match conditions might not cover the current destination.

Encrypted DNS still needs a network path that can establish a connection. If resolving an upstream's hostname requires using that same upstream, startup dependencies may arise. If the proxy node's address also depends on a proxy path that is not yet available, the dependencies compound. Before configuring it, map the sequence: resolve the node address, connect to the node, reach the DNS upstream, and resolve the service domain. Make sure nothing is waiting on itself. An encrypted transport name does not guarantee reachability; address resolution, routing, and connection permissions still apply.

When testing DNS changes, account for caches. The system, browser, application, and core may each cache results, and existing connections may continue using an old address. Prefer fresh connections to a known test domain and inspect the logs. If needed, clear the relevant cache or restart the application using the platform's normal procedure. Do not keep changing multiple servers when you do not know which cache layer is involved; an earlier setting may take effect during a later test and produce a misleading result. Recording the test time and configuration is more useful than simply noting whether a webpage loaded.

Policy: Connection Lifetimes and Statistics

Policy Is Not a Route Selector

policy adjusts connection handling and statistics; it does not assign a domain to a proxy node. Common structures include levels, organized by user level, and system for global system statistics settings. Level keys are represented as JSON strings, such as "0". Which level a user uses depends on the protocol configuration and how the core interprets it. Unless you have a specific need, there is no reason to add multiple levels just to make a config look complete. Keep the defaults first, then adjust a small number of parameters to address a reproducible issue in the logs.

Before tuning policy, distinguish the handshake phase, normal data transfer, and one-way closure. A handshake timeout applies to initial negotiation; an idle timeout applies when a connection has been inactive for a period; waiting after one direction closes concerns whether data still needs to flow in the other direction. Setting every value very low can terminate healthy long-lived connections, while making every value very high can let broken connections tie up resources longer. Higher values are not automatically more stable. Choose them based on the application's connection pattern and the failure you actually observe.

User-Level Policy and System Statistics Snippet

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

Durations in this snippet are in seconds and show how fields are organized; they are not tuning recommendations for every application. handshake limits the handshake wait for applicable connections, connIdle controls idle connections, and uplinkOnly and downlinkOnly affect how long a connection waits after one direction closes. Check the protocol and core implementation to confirm their scope. If changing them causes downloads to stop when uploads finish, or background connections to restart periodically, restore the original values first and use connection logs to narrow down the cause instead of stacking on more policy settings.

Understand Statistics Toggles Separately from Display

Enabling statistics does not mean the client will immediately show every value. The statistics module, query interface, and client reading logic must work together; user-level statistics also depend on conditions such as protocol support for user identifiers. The example explicitly disables user-level upload and download statistics and demonstrates only system-level inbound and outbound toggles. If the client already generates statistics and interface settings, do not blindly add another module with the same name. Duplicate configuration may conflict, or the interface may keep reading an old endpoint, leaving the display unchanged even though the core is running.

FieldStage to CheckCommon Misconception
handshakeInitial connection negotiationIncreasing it will not fix incorrect authentication parameters
connIdleWhile a connection is idleIt is not a limit on total application download time
uplinkOnlyOnly the uplink remains after the downlink closesIt is not an upload bandwidth limit
downlinkOnlyOnly the downlink remains after the uplink closesIt is not a download speed setting

Idle connections and slow connections are not the same thing. Whether a connection is considered idle while it continues sending small amounts of data depends on how the core detects activity. Application-level keepalives also affect connection persistence. To investigate periodic disconnects, compare application reconnect times with the core's connection-closure reason and system sleep records. Computer sleep, Wi-Fi changes, or background restrictions on mobile devices can produce similar symptoms. A disconnect at a particular time does not by itself mean the connIdle setting is wrong.

For statistics, prefer the client's existing status screen and a restricted local interface. Do not expose a management interface on every network interface just to view numbers. Whether the interface exists, where it listens, and who can access it are separate security boundaries. Ordinary desktop use does not require setting up a remote management endpoint to follow this chapter. Statistics may also reset when the core restarts. Do not subtract client history totals from the current process's counters and infer that configuration was lost or traffic bypassed the proxy.

A sensible way to adjust policy is to describe the symptom, choose a field, then check for side effects. For example, evaluate the relevant idle wait only after confirming that the core is terminating a particular application's connection after inactivity. If the failure occurs during authentication, go back to the outbound parameters. Record the original value, the change, and the test conditions each time, keeping other settings unchanged. To roll back, restore the complete known-good snippet rather than trying to remember each value. Policy is fine-tuning; it should come after the basics: a reachable inbound, a working outbound, and correct routing.

Client Integration: Generated Files, Subscriptions, and Core Switching

Use Persistent Client Settings as the Starting Point for Changes

v2rayN is the primary desktop option for Windows, macOS, and Linux. On Android, choose v2rayNG or v2flyNG based on your configuration needs. All installation links are on the client downloads page. These clients organize nodes, modes, and routing options into a runnable config, so their interface does not need to correspond to the JSON field by field. When using this guide, first find the current client's config preview, logs, or custom configuration feature, then decide whether a change belongs in the interface or a separate file.

After importing a subscription, the client typically saves its source details and node list, then generates a runtime config based on the current selection. Node groups, filter keywords, and automatic updates belong to the client layer; they are not general-purpose routing or policy fields. Adding a group name to a core file will not organize the subscription list, and editing node parameters generated from a subscription may be undone at the next update. For lasting changes, distinguish source data from local overrides so a subscription refresh does not silently alter the config you are testing.

Check These Four Mappings in the Generated Config

First, does the node selected in the interface correspond to the actual outbound? Second, does the system proxy or application point to the actual inbound port? Third, does the current routing mode generate the expected rules and default outbound? Fourth, does the core selected in the interface match the one shown in the startup log? Check these four before digging into protocol parameters. They explain many cases where “the config looks right but behaves differently,” such as an old connection still using the previous exit after a node switch, or another background instance occupying the port targeted by the system proxy.

{
  "inbounds": [
    {
      "tag": "local-http",
      "listen": "127.0.0.1",
      "port": 10809,
      "protocol": "http",
      "settings": {}
    }
  ],
  "outbounds": [
    {
      "tag": "direct",
      "protocol": "freedom",
      "settings": {}
    }
  ],
  "routing": {
    "rules": [
      {
        "type": "field",
        "inboundTag": ["local-http"],
        "outboundTag": "direct"
      }
    ]
  }
}

This standalone example maps an HTTP inbound directly to a direct outbound to show how interface ports correspond to tags; it is not intended to replace an existing subscription. If the client's custom configuration mode takes over the entire runtime file, first confirm whether it still sets the system proxy, updates ports, or generates a statistics interface automatically. Different configuration options serve different purposes. Do not paste a complete file containing all inbounds and outbounds into a field meant only for additional routing rules. Read the option's description before saving, then inspect the generated result rather than relying only on a success message in the interface.

Test Core Switching and Traffic Capture Modes Separately

Shared field names do not guarantee that Xray and V2Fly configurations are compatible. Before switching cores, confirm support for the required protocol and transport, and keep the old config. After switching, restart and check the core identifier in the logs, then see whether the generated config changed. If you use a custom file, the client may not convert core-specific fields into a structure supported by the other branch. If you see an unknown field or protocol, switch back to the original core and confirm the basic connection works before building a compatible config one field at a time. Do not start by deleting every field reported as an error.

Establish separate test baselines for system proxy and TUN. First verify the local proxy port without taking over all traffic. Then enable the system proxy and test applications that honor it. Only then evaluate TUN. TUN may require additional permissions, a virtual interface, routing, and DNS settings, and its capabilities depend on the client and supporting core. If LAN access breaks after enabling it, check the capture scope and private-network rules. If only one application ignores the system proxy, do not assume the subscription is damaged.

SettingPrimarily Managed ByWhere to Verify
Subscription sources, groups, and filtersClient management layerSubscriptions and node list
Listen ports and outbound parametersCore runtime layerGenerated config and startup logs
System proxy targetClient and system settingsSystem settings and the application's actual connection
TUN capture and permissionsClient, system, and supporting implementationPermission status, interface, and routing

When managing multiple subscription sources, organize sources and groups before adding complex custom configuration. This makes it easier to identify where parameters came from after a node update and to roll back to a known-good setup. See v2rayN Subscription Groups and Node Filters for details. For desktop permissions, follow the platform setup path, such as macOS Installation and Network Permissions. Repeatedly adjusting JSON usually cannot override the system's refusal to grant network capture permissions.

When migrating settings, record subscription sources, custom rules, and platform-specific options separately. Configuration directories, file permissions, and network permissions differ by platform; copying an absolute path does not guarantee it will work. After migration, test one node first, restore routing and DNS extensions, and then check the traffic capture mode. For the initial setup sequence, follow the Quick Start guide. This page explains fields but does not replace the current client's interface instructions.

Validation and Troubleshooting: From Config Loading to Destination Connection

Narrow Down the Issue by Failure Stage

Troubleshoot in sequence: startup, listening, application access, routing, resolution, and remote connection. If the core has not started, a webpage result says nothing about whether routing is correct. If the application has not reached an inbound, changing the outbound proves nothing. Open the client logs, restart the core once, and find the earliest error from that startup rather than picking a random line from many later retries. Early errors can trigger a chain of follow-up messages. Fixing the first clear failure is usually more effective than addressing every warning at once.

During file loading, check JSON structure, field types, and paths. If an error mentions a field, the actual problem may be earlier: a missing comma on the previous line, an unclosed string, or an incorrectly closed array. Do not just delete the reported line. First clarify the root object and module hierarchy, then compare the latest changes. If you use an editor to inspect a file containing node details, keep it local; do not upload the full config to an unfamiliar data-processing site. Remove addresses and authentication details before sharing logs.

Test Before Running Long-Term

If you manage core files yourself, start by running the config test command supported by your current core. The command below is for Xray and requires that the executable is available on your system and the target file is in the working directory. V2Fly may use different arguments, so check the local program's help rather than copying options from another core. GUI client users should start with the client's logs and built-in validation tools. If you do not need to manage the core separately, there is no need to install another runtime just to run a command.

xray run -test -config config.json

Passing the test means the current program accepts the file; it does not prove that the remote endpoint is reachable or that an application is using the proxy. Next, check whether the port is listening. If the address is already in use, look for duplicate clients, an old core process, or another local service. Do not change the port only in JSON and forget to update system proxy and application settings. The core may start normally while the application keeps connecting to the old port. After changing a port, make a new request and check the inbound log.

Use Observable Logs to Verify the Connection Path

{
  "log": {
    "loglevel": "info"
  }
}

Temporarily setting the log level to info can provide more runtime detail, but what you see depends on how the client captures core output and whether access logging is configured separately. To confirm routing, check the connection records or access logs provided by the client, distinguishing the inbound tag, destination format, and outbound tag. Restore a suitable everyday log level once the issue is resolved. Detailed logs may contain destinations, device addresses, and connection times. Do not keep them indefinitely without a reason or post them publicly without removing sensitive details.

SymptomCheck FirstDo Not Prioritize Yet
Core exits immediatelySyntax, field compatibility, and data file pathsSystem proxy mode
Listen failureAddress availability, port conflicts, and permissionsRemote authentication parameters
No application traffic in the logsApplication proxy settings, system proxy, and port mappingRouting rule order
Traffic uses the wrong outboundRule order, condition logic, and tag referencesConnection timeout policy
Domain resolution timeoutActual resolution layer, upstream path, and cachesSubscription group name

If the inbound and routing are correct, check resolution and the remote handshake next. A connection timeout may occur while reaching the remote port or the service destination; authentication failures, server-name mismatches, and resolution failures each require different fixes. Compare the actual destination and failure stage in the logs rather than assuming the node is broken just because you see “timeout.” If the same config behaves differently across networks, record network changes, address family, and permission conditions. Compare without changing the config so network differences are not confused with configuration changes.

Restore settings one at a time as the final validation step. First use a known-good minimal config to establish one connection, then add the intended outbound, one routing rule, and finally DNS and policy extensions. Save the result after each addition so you can identify the latest change if something breaks. Test both a destination that should match and one that should not; a broad rule may make one webpage work while sending all other traffic through the wrong outbound. Close existing connections and retry to ensure the new config is actually being applied.

For more detailed log analysis, see Find config.json Errors in Logs. For recurring basic questions, check the FAQ; for terminology, see the glossary. Keep a validated baseline config and clearly note which parts come from subscription updates, which are generated by the client, and which are maintained locally. Before upgrading or migrating, compare against that baseline and decide whether any fields need to change instead of guessing from the entire file again.