Config structure · Field semantics · Runtime validation
JSON Configuration Guide
Follow the connection path: local inbound, outbound selection, routing, name resolution, and connection policies.
New to V2Ray? Start with the quick-start guide to import a subscription and connect. This page explains generated configuration, routing rules, and field errors; it is not a substitute for everyday client operations. Find installation options and platform choices on the client downloads page.
JSON Structure Overview
First identify which configuration you are looking at before interpreting its fields. v2rayN's saved interface settings, subscription content, and the core's runtime configuration are separate things. A subscription provides server connection details; the client combines the selected server with routing templates and listener settings to generate the configuration passed to the core. Editing a generated file may affect only the current run; switching servers or restarting the core can overwrite it. For settings that need to persist, make changes through the corresponding client option.
Objects, Arrays, and Field Types
A JSON document has an object at the top level, enclosed in curly braces. Each object field consists of a double-quoted name, a colon, and a value; separate fields with commas. Arrays use square brackets and are useful for lists of inbounds, outbounds, or ordered rules. Strings, numbers, and booleans are not interchangeable: write listener ports as numbers, switches as true or false, and protocol names as strings. Do not add a comma after the last item or comments to strict JSON.
This is a minimal direct-connection baseline understood by common V2Ray and Xray cores. It exposes a SOCKS listener on the loopback address only and includes no remote proxy server. Applications that connect to this listener reach their destinations directly from the local machine. The example helps isolate local listener issues from remote connection issues; importing it does not create a remote proxy chain.
{
"log": {
"loglevel": "warning"
},
"inbounds": [
{
"tag": "socks-in",
"listen": "127.0.0.1",
"port": 10808,
"protocol": "socks",
"settings": {
"auth": "noauth",
"udp": true
}
}
],
"outbounds": [
{
"tag": "direct",
"protocol": "freedom",
"settings": {}
}
]
}
What Each Top-Level Section Does
| Section | Purpose | What to Check |
|---|---|---|
inbounds | Accepts connections from applications | Listen address, port, and inbound protocol |
outbounds | Connects to the destination | Protocol, server parameters, and outbound tag |
routing | Selects an outbound for each connection | Rule order, match conditions, and tag references |
dns | Provides built-in name resolution | Servers, domain scope, and resolution path |
policy | Manages connection policies and statistics switches | User levels, timeouts, and statistics dependencies |
These sections work together through references; they do not run in the order they appear in the file. In routing rules, outboundTag points to an outbound's tag; policy levels correspond to the level used by protocol users. Object field order usually does not change meaning, but array order can affect behavior, especially for routing rules and the default outbound. Follow the references before interpreting individual values.
Complete Files and Partial Snippets
Most examples below are top-level snippets intended to replace or merge with a section of the same name. Do not concatenate two objects that both contain routing, or leave duplicate top-level keys. Some parsers accept duplicate keys and use one of the values, but that behavior is unreliable. When merging, keep a single top-level object, place each section at the correct level, and check the braces, arrays, and commas.
Core implementations share common concepts, but extensions are not guaranteed to match. Check the core you actually run for support of transport implementations, DNS options, and user levels. Start with a minimal configuration that runs, then add one feature at a time; this makes differences easier to diagnose than importing a large collection of snippets from various sources. After upgrading the client, review the generated configuration again rather than assuming fields are unchanged based on an old screenshot.
When documenting a configuration, note the core, the client setting used to edit it, and the reason for the change. Never include sensitive server credentials in public screenshots or documents. When something goes wrong, distinguish among JSON parse errors, unsupported fields, and runtime connection failures. The sections below follow that order. This helps avoid mistaking a port conflict for a protocol issue, or a rule that never matches for invalid JSON.
inbounds: Local Listeners
An inbound defines how applications pass connections to the core. On desktop, a common setup is to have applications use a local SOCKS or HTTP proxy, with the client starting the corresponding listener. The application's address, port, and protocol must match the inbound. Seeing the client window does not mean the core is listening successfully. Check the startup log and whether the port is actually bound instead of relying on the system tray icon.
Listener Addresses and Protocols
listen is the address bound on the local machine, not the remote server address. With 127.0.0.1, only local loopback connections can reach the listener. Changing it to 0.0.0.0 exposes it on IPv4 network interfaces, potentially making the port accessible to devices on the LAN. Authentication, firewall rules, and network boundaries must then work together to restrict access. Enabling the client's LAN option alone does not guarantee that other devices can connect.
{
"inbounds": [
{
"tag": "socks-in",
"listen": "127.0.0.1",
"port": 10808,
"protocol": "socks",
"settings": {
"auth": "noauth",
"udp": true
},
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls"],
"routeOnly": true
}
},
{
"tag": "http-in",
"listen": "127.0.0.1",
"port": 10809,
"protocol": "http",
"settings": {}
}
]
}
This example uses routeOnly according to Xray configuration semantics: sniffed information is used for routing without replacing the original destination. Check whether this field is supported before switching to another core. To verify the local listener alone, you can first remove the entire sniffing section and keep the basic listener. Once that works, test sniffing and domain rules separately to avoid introducing two variables at once.
SOCKS and HTTP are different inbound protocols. If an application supports only HTTP proxies, configure it to use the HTTP inbound port; the fact that both ports are local does not make them interchangeable. Enabling udp on a SOCKS inbound only allows the relevant UDP forwarding capability. The application must also send UDP traffic in a supported way, and the remote path must support it. A regular HTTP proxy listener does not route all UDP traffic.
How Domains Reach Routing Rules
An application may pass a domain to the proxy, or resolve it locally first and pass the destination IP instead. In the first case, domain rules can match directly; in the second, you may need to use the available destination information or sniffing results. Sniffing reads recognizable protocol characteristics; it is not a general-purpose decryption tool. Do not expect it to recover a reliable domain when the connection lacks recognizable domain information, the handshake is protected by another mechanism, or the protocol is outside its coverage.
In destOverride, http and tls identify protocol categories for sniffing; they do not select the outbound transport. Enabling sniffing does not turn on TLS or fix server certificate problems. To troubleshoot domain-based routing, check whether the application passes a domain, whether sniffing is enabled on the inbound, and whether the rule receives a domain or an IP. Checking just one switch is not enough.
Port Conflicts and LAN Access
Two processes cannot freely bind the same listen address and port. If the client reports that the address is already in use at startup, close duplicate instances and check whether another program is listening on that port. After changing the inbound port, update the application's proxy settings and the system proxy settings too; otherwise, the new core may run normally while applications keep connecting to the old port. Note the previous value so you can restore it if the test fails.
To let devices on your LAN use the listener, first make sure they can reach one another on the network, then check the bind address, system firewall, and access authentication. Do not expose the unauthenticated local example using noauth to an untrusted network. Restricting access to specific devices is usually safer than exposing the entire interface. Incoming connections from other devices still pass through routing rules, so verify listener connectivity separately from destination reachability.
Keep inbound tags stable, clear, and unique. For example, you can give a browser and a test program separate tags, then use routing's inboundTag to compare their behavior. Tags are not authentication and have no built-in special meaning; they are reference names in the configuration. Changing a tag's spelling affects the rules that refer to it. When troubleshooting, compare the exact text rather than assuming similar-looking names are linked.
outbounds: Protocols and Connection Parameters
An outbound determines how the core establishes the next connection. Direct, blocking, and remote proxy outbounds all belong here but serve different purposes. An outbound's presence does not mean it will be used: check whether routing selects it and which outbound is used by default when no rule matches. Usually, put the intended default outbound first in the array and assign unique tags to outbounds that routing rules need to reference. Avoid relying on hard-to-follow positional assumptions.
Separate Protocols from Transports
protocol specifies the proxy protocol or handling method used by an outbound. Remote address, port, and user parameters usually go in settings, while transport and connection security options typically go in streamSettings. Protocol, transport, and security are three cooperating dimensions; a protocol name alone does not describe a complete connection setup. Even when both ends use the same protocol, a mismatch in transport path, service name, or security parameters can still cause the handshake to fail.
{
"outbounds": [
{
"tag": "direct",
"protocol": "freedom",
"settings": {}
},
{
"tag": "block",
"protocol": "blackhole",
"settings": {}
}
]
}
This example has no remote server and is intended to illustrate outbound references. freedom connects to the destination directly from the local machine; whether and how it resolves domain names also depends on related settings. blackhole discards matching traffic and is useful when you explicitly want to block it. By default, applications may report a failed connection or timeout; do not assume the destination site is at fault. Check first whether routing sent the connection to the blocking outbound.
How VLESS Fields Fit Together
VLESS connection parameters must come from the server configuration or trusted share information. vnext describes the server list; its address and port specify the connection target, and id in users identifies the user. Do not invent working credentials from an example or use a subscription group name as a server address. The address, user parameters, and transport security settings must all come from the same server configuration.
With VLESS, encryption commonly uses none as a protocol user setting; this does not mean the connection has no transport security. TLS and REALITY are configured through the transport settings supported by the relevant core, and their parameters are not interchangeable. Server names, certificate verification, public keys, and identity parameters each have distinct meanings. If you are unsure what a field does, check the original share information rather than bypassing an error by disabling verification.
VMess, VLESS, and Trojan also use different authentication structures. Do not copy a user object from one protocol directly into another. The safest approach is to import a valid share link in the client, then inspect how each connection parameter appears in the generated configuration. For protocol concepts, see the glossary. This page focuses on field placement and references rather than ranking protocols for every use case.
Default Outbounds and Connection Checks
If a proxy outbound is configured but no rule points to it and it is not the default outbound, traffic will not use that server automatically. Conversely, putting the proxy outbound first sends connections that match no other rule through the proxy. Array order changes the fallback behavior. Before each edit, write down the intended behavior in one sentence: which connections should go direct, which should be blocked, and where everything else should go. That sentence should match the actual array and rules.
To verify a remote connection, first check whether the local machine can connect to the server address and port, then check the transport handshake, and finally check the destination request. A reachable server port only indicates a response at the network layer; it does not mean authentication succeeded. A certificate name mismatch, incorrect transport parameters, or invalid user ID can all cause failure at a later stage. A latency result shown in the client is no substitute for a complete application request; use the error stage in the logs as well.
After switching cores, first check whether the selected core supports the protocol and transport, then confirm that the generated configuration still includes the required options. Seeing the same server name in the interface does not prove the underlying parameters are identical. For custom outbounds, keep the original import information and a known-working configuration copy. This makes it easier to distinguish import conversion issues, core differences, and changes to the server configuration.
routing: Matching Rules and Traffic Routing
Routing selects an outbound; it does not modify the remote server configuration. Rules are checked in array order, and usually the first match determines where a connection goes. If none match, the default outbound is used. Put narrow, clearly defined exceptions before broader rules. If an earlier rule already matches every destination, later rules will never take effect even if their syntax is valid. Troubleshooting requires more than checking whether a rule exists.
Domain Rules and IP Rules
{
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"domain": ["full:example.com"],
"outboundTag": "block"
},
{
"type": "field",
"domain": ["geosite:cn"],
"outboundTag": "direct"
},
{
"type": "field",
"ip": ["geoip:private"],
"outboundTag": "direct"
}
]
}
}
This snippet requires both block and direct outbounds to exist in the configuration. full:example.com matches only that exact domain; it does not include all subdomains. To match a domain and its subdomains, use the appropriate domain: form. In common implementations, a string without a prefix may be treated as a keyword. Make the match type explicit to avoid unintentionally matching similarly named domains.
geosite:cn and geoip:private refer to categories in rule data; they are not sets inferred from their names at runtime. They depend on the corresponding data files being available to the core and containing the relevant entries. Missing data may prevent startup, and updates can change what a category covers. If a domain routes differently than expected, first test with an explicit domain rule, then check whether the difference comes from the data category or rule order.
What domainStrategy Does—and Doesn't Do
AsIs means routing mainly matches the destination information already available, without resolving domains for IP rules. With IPIfNonMatch, the core attempts to resolve a domain if it has not matched a rule, then checks relevant rules using the resulting address. IPOnDemand triggers resolution when the matching process encounters a condition that requires IP information. These options affect routing-stage matching; they are not global system DNS switches and do not guarantee that other applications' DNS requests enter the core.
| Condition | Typical Use | Keep in Mind |
|---|---|---|
domain | Route by domain category | The connection must include or recover domain information |
ip | Route by address or subnet | A domain destination may need to be resolved first |
port | Restrict destination port ranges | Not the local inbound listener port |
inboundTag | Distinguish local entry points | Must match an actual inbound tag |
network | Distinguish TCP from UDP | The connection path must support the relevant forwarding capability |
Different types of conditions in the same rule usually all have to match; multiple candidate values of the same type usually match if any one of them matches. For example, putting both a domain and a port in one rule means connections to that domain on the specified port, not a match on either the domain or the port alone. To express two independent cases, use two rules. Shorter rules are easier to verify against logs and test results.
Fallback Rules and Rollback
Common routing template problems include a fallback rule placed too early, a mistyped tag, or confusing the destination port with the inbound listener port. Start with one test domain and a minimal rule, confirm it reaches the intended outbound, then expand to data categories and additional conditions. Change one set of rules at a time and note which outbound tag matched after each test. Merging rules from multiple sources all at once makes it difficult to identify which change caused rules to mask one another.
Deciding whether to route private addresses directly also depends on how the network is used. LAN services may use internal domains, and an application may resolve them to private addresses first; rules for public domains alone may not cover those connections. Before expanding private subnet matches, make sure you will not send internal traffic that needs a special path to the wrong place. Rules should reflect actual network boundaries; the word “private” is not a reason to ignore access controls.
The client's global, bypass, and rule modes may generate routing from different templates; similar names do not guarantee identical configuration. After switching modes, inspect the newly generated configuration rather than continuing to analyze the old file. Check DNS alongside routing: routing may need a resolved address, while the DNS server itself needs a reachable outbound. When the two depend on each other, the underlying network path must be clear.
dns: Resolution Paths and Address Selection
The core's DNS provides resolution results to internal processes that use it. A top-level dns section does not automatically replace the system resolver. If an application first resolves a name through system DNS and then passes an IP to the proxy, the core may see only the address. If the application passes a domain to the proxy, routing or the outbound may call the built-in DNS. To troubleshoot resolution, first identify who made the query, then which server received it.
Static Mappings and Server Scope
{
"dns": {
"hosts": {
"local.test": "127.0.0.1"
},
"servers": [
{
"address": "223.5.5.5",
"domains": ["geosite:cn"]
},
"1.1.1.1"
],
"queryStrategy": "UseIPv4"
}
}
This snippet demonstrates static mappings inside the core, domain-specific preferred servers, and address-family queries. It does not write entries to the system hosts file. local.test illustrates the mapping hierarchy; whether an application can reach it depends on whether that application uses the core for resolution. domains sets the domain scope a server should handle preferentially, but it is not a network firewall rule that blocks other resolution paths.
Server selection for multiple DNS servers also depends on the core implementation and fallback options; it is not simply “try the next server only if the first fails.” To strictly control where a domain is resolved, check the core's fallback and matching behavior and verify it with real queries. The public resolver addresses in the example only illustrate the field format. In deployment, choose a resolver that is reachable on your network and meets your needs.
How DNS and Routing Depend on Each Other
With routing set to IPIfNonMatch, a domain connection may first be checked against domain rules. If none match, the core requests a resolution and then continues matching by address. A failed lookup leaves later decisions without the necessary information, but the symptom may look like an ordinary connection timeout. DNS requests also need a network path: depending on the resolution method, they may go through core routing or take a local path. Setting a resolver address does not by itself determine which outbound DNS traffic uses.
With encrypted DNS services, consider how the resolver's hostname is resolved initially. If reaching the resolver requires resolving its domain, and that lookup in turn depends on a proxy connection that has not been established, the setup can create a dependency loop. Provide a working path for basic resolution or the server address first, then add routing rules step by step. To narrow down an issue, you can temporarily use a known-reachable address and determine whether the failure occurs during name resolution, transport setup, or the destination server's response.
hosts is useful for a small number of explicit internal mappings or test overrides, but not for maintaining large lists of public service addresses that change frequently. Service addresses can vary by region, load, and network; a stale mapping may direct connections to an unsuitable destination. Note why you add a mapping and remove it when testing is done. Otherwise, an old entry may keep taking precedence long after the server configuration changes.
IPv4, IPv6, and Destination Connections
queryStrategy controls which address types the built-in resolver requests or selects. The example's UseIPv4 can help isolate IPv6 path issues, but it is not the best long-term choice for every network. Resolving an IPv6 address does not mean the outbound has working IPv6 connectivity; getting only an IPv4 address does not prove the application did not obtain an IPv6 address through another resolution path. Verify query results and connection results separately.
Routing's domainStrategy, DNS's queryStrategy, and the address strategy in a direct outbound belong to different layers. Their names may look similar, but they affect different things. If changing a strategy has no effect, check which section contains the field and whether the relevant code path is actually used. If the application already passed an IP, changing a DNS server entry that is not involved in processing that connection will usually make no difference.
A useful troubleshooting sequence is: confirm the server address resolves, confirm the resolver is reachable, check that the destination returns the expected address, then verify that routing selects the right outbound. Do not change several resolvers, switch address families, and reorder all routing rules at once. Change one thing at a time and note the failure stage to distinguish a resolver problem from an unreachable address or an outbound handshake failure.
policy, Logging, and Connection Policies
Policies manage connection lifecycles and statistics; they do not select a proxy server or automatically improve network performance. Before changing them, identify whether the issue occurs during connection setup, idle time, or the end of an upload or download. Increasing every timeout may only make failures take longer; reducing all values may end valid requests on a poor connection too soon. Policy settings should address specific, observable application behavior, not act as a general-purpose speed switch.
User Levels and Connection Timeouts
{
"policy": {
"levels": {
"0": {
"handshake": 4,
"connIdle": 300,
"uplinkOnly": 2,
"downlinkOnly": 5,
"statsUserUplink": false,
"statsUserDownlink": false
}
},
"system": {
"statsInboundUplink": false,
"statsInboundDownlink": false,
"statsOutboundUplink": false,
"statsOutboundDownlink": false
}
}
}
Times here are in seconds. The values illustrate a common combination of fields; they are not recommended settings for every application. handshake limits the time allowed for a protocol handshake; connIdle sets how long an idle connection can remain open; and fields such as uplinkOnly and downlinkOnly govern one-way upload or download phases. Their exact effect depends on the protocol implementation and connection state. They are not universal timeouts for every operating system socket.
Keys in levels use string-form level numbers. They should correspond to the level in protocol user objects that support user levels. Adding a level definition does not automatically move all connections to that level. If a change has no effect, first check whether the active protocol uses the policy and whether the user level matches; only then consider the values. Verify support for the relevant inbound and protocol in the core you use.
Statistics Switches and Data Display
Boolean statistics options in a policy determine whether the corresponding data is recorded; they do not mean a queryable statistics service is already available. A complete statistics pipeline may also require stats, an API service, tags, and client-side reading logic. If only one part is enabled, the absence of data in the interface does not prove that traffic bypassed the core. Desktop clients may generate the sections needed for statistics; do not blindly overwrite them in a custom configuration.
Traffic figures shown to users are not a reliable basis for billing or a complete network audit. Which inbounds are counted, whether direct traffic is included, and when counters reset depend on the implementation. For troubleshooting, use statistics as a supporting signal: does the selected outbound show activity after a rule matches, and does traffic appear on the new outbound after switching servers? Do not rely on a single cumulative figure instead of testing actual requests and checking logs.
Log Levels and Sensitive Information
{
"log": {
"loglevel": "warning",
"dnsLog": false
}
}
For everyday use, you can start with warning-level logs and increase detail briefly while reproducing an issue. More detailed logs are more likely to include target domains, connection addresses, and internal network information. Before sharing logs, remove server credentials, full subscription URLs, and unnecessary personal browsing records, while keeping the error type, event order, and relevant tags. Removing all context and leaving only “connection failed” usually makes the failure hard to diagnose.
Without a file path configured, logs may go to the process output and be collected by the client. If you set a file output path, make sure the directory exists and the running account can write to it. The client being able to write to its own settings directory does not mean the core can write to any path. An invalid log path, full disk, or restricted directory may prevent expected logs from appearing; that alone does not mean the core never ran.
For dropped long-lived connections, first compare four possible causes: the application's own timeout, the server's idle limit, network equipment keeping the connection alive, and the core policy. Change values such as connIdle only when the evidence points to the core's idle handling. Some applications send keep-alive requests and others do not, so the same policy can affect them differently. Do not generalize a single test to every program.
Policies are not the first place to look when startup fails. Check JSON syntax, field compatibility, and listener ports first, then resource paths and permissions. If the core starts but only specific requests fail, investigate the outbound handshake, DNS, and connection timeouts. Troubleshooting in the order of failure stages avoids guesswork and preserves a configuration you can explain and roll back.
Client Settings vs. Core Configuration
The client organizes servers, subscriptions, routing templates, and runtime behavior; the core handles connections. For desktop, v2rayN is the recommended starting point. On Android, choose v2rayNG or v2flyNG, which is based on V2Fly, as needed. The three clients do not use identical interface labels or generation workflows, so do not assume every switch in a desktop screenshot maps to a universal JSON field. First identify whether a setting belongs to the client, the system, or the active core.
Subscriptions and Generated Configuration
A subscription distributes server information; it is not a top-level V2Ray subscription section. In v2rayN, subscription groups, automatic update intervals, and update request methods are saved by the client. The core typically receives outbound parameters generated after the subscription is parsed. Changing the subscription update interval does not change existing connection timeouts, and editing outbound user parameters will not fix an invalid subscription URL.
Keep a copy of the current working configuration before updating a subscription. After the update, check for changes to groups, server counts, and the selected server; pay particular attention if the selected server was removed or renamed. Manual edits to subscription-managed entries may be overwritten on the next update. For persistent custom settings, use client-supported options or a separate custom configuration rather than treating the runtime file as a subscription database.
If an update fails, determine whether the request URL is unreachable, the server returned an error, or the content format was not recognized. A page opening in a browser does not mean it contains subscription data the client can parse. Full links may contain access credentials, so do not post them publicly. For import steps and share link formats, see how to import a subscription link. For your first setup, follow the getting-started guide.
TUN Mode and Traffic Capture
TUN receives network-layer traffic through a virtual network interface and involves system routes, permissions, DNS capture, and exclusion rules. It is not a matter of adding a tun field to an ordinary V2Ray top-level object. A client may use a different core configuration to implement this feature, with a structure unlike the standard V2Ray or Xray configuration on this page. Check the TUN mode controls in v2rayN to see the actual generated configuration and related logs.
Before enabling TUN, confirm that the regular proxy listener works, then verify permissions, virtual interface creation, and system routes. If the regular proxy works but TUN does not, focus on the traffic capture path rather than rewriting remote protocol parameters. Check that the server connection is not mistakenly routed back through the virtual interface, creating a loop, and whether LAN services need to be excluded. When other virtual networking software is running, route priorities may also affect the result.
Switching Between Cores
Switching cores is more than changing a name. It affects protocol support, transport fields, rule data, and the configuration format used by the client's generator. v2rayNG commonly uses Xray, while v2flyNG uses V2Fly; the options available in v2rayN depend on the installed components. After switching, recheck server parameters, routing, and DNS rather than copying extensions from one core to another. For ecosystem context, see About this site.
System Proxy and Application Behavior
The client writes system proxy settings to the operating system or desktop environment; this is not a universal top-level core field. It affects only applications that follow those settings. If an application still connects directly, first check whether it has its own proxy configuration and then consider its traffic type. If the core is stopped while the system proxy still points to the old local port, applications may keep reporting connection failures. Clear the system proxy rather than just deleting a configuration file.
Before upgrading or resetting the client, back up subscription groups, routing templates, and custom configuration separately. Restore them in layers: first a working server, then routing rules, and finally the traffic capture method. If you import all old settings at once and the problem returns, it is hard to tell whether the cause is an incompatible old field, a changed generation process, or a system proxy or virtual network state that was not restored as expected.
Configuration Validation and Troubleshooting
Validate a configuration step by step, from “it parses” to “it behaves as expected.” Valid syntax only means the file can be read; it does not mean every field is supported. Supported fields do not guarantee the remote server is reachable, and a successful connection does not prove that all routing rules work as intended. Set a separate test goal for each layer. If one layer fails, do not try to fix it by changing parameters at the next layer.
Create a Recoverable Test Baseline
Save the current working configuration and its client settings first, and note which core is running. In a test copy, change only one section and define a clear success criterion, such as the local port accepting a request, a domain using a specific outbound, or a LAN address staying direct. Do not update subscriptions, switch cores, and reorder rules at the same time. The fewer variables you change, the easier it is to explain the result.
If the client provides a configuration check or a way to view the generated configuration, use it first. Confirm the runtime configuration actually contains the change you made, then inspect the error output. Some clients generate a temporary file before starting the core, so editing an old file by hand will not affect the next launch. If your changes disappear after saving, check where the setting comes from instead of repeatedly editing a file that gets overwritten.
Narrow the Search by Failure Stage
| Symptom | Check First | Next Test |
|---|---|---|
| Configuration cannot be parsed | Braces, commas, types, and duplicate keys | Restore a minimal top-level object |
| Core fails to start | Unsupported fields, ports, and resource paths | Find the first meaningful error |
| Application cannot connect to the listener | Listen address, port, and inbound protocol | Set the local proxy explicitly |
| Listener works, but remote connection fails | Server address, authentication, and transport security | Distinguish connection from handshake failures |
| Only some domains are affected | Rule order, DNS, and address family | Test a minimal rule for one domain |
| Changes disappear after restart | Configuration source and generation process | Make the change through the persistent settings |
For syntax errors, check the field near the reported location, but also look for a missing or extra comma on the previous line. Type errors can hide in values that look plausible, such as a port written as text when the field expects a number. For startup failures, address the earliest substantive error first; later messages like “process exited” are often just consequences. Keeping the full error sequence is more useful than capturing only the final line.
If the core is running, first configure an application that explicitly supports proxies to use the local listener, without relying on automatic system proxy detection. If that works but other applications fail, focus on their proxy settings and the system proxy. If no applications can connect, continue checking the listener and core process. If the local listener works but the destination does not, investigate the remote handshake and routing. Do not collapse these stages into a single “no internet” problem.
Use a Narrow Test to Verify Routing
For routing issues, choose a destination you can reproduce consistently. Temporarily put it in an explicit domain rule near the top and point it to a known-working outbound. Once behavior changes as expected, restore the original category rules and extra conditions one by one. If the explicit rule has no effect, check whether the application passes the domain, uses the expected inbound, and is reading the current runtime configuration. Adding more rule data will not usually solve the underlying problem.
When troubleshooting DNS, record both the query path and the destination address used for the connection. If the domain resolves but remains unreachable, check the address family and outbound connectivity; if resolution itself fails, focus on the resolver and the underlying network path. Do not diagnose the issue from a browser error page alone: the same timeout message can come from the listener port, a DNS request, remote authentication, or the destination service. Log timestamps help correlate these stages.
Rollback and Reproducible Notes
After a failed test, restore the latest working settings and restart the relevant core. Confirm that the listener and system proxy are in sync. When disabling TUN, also make sure the virtual interface and system routes were restored through the client's normal process. If the client itself will not start, see troubleshooting launch crashes to distinguish an environment issue from a core configuration issue; a window that will not open is not necessarily caused by JSON.
The final configuration should answer three questions: which inbound the application uses, why a rule selects a particular outbound, and where the domain is resolved. Do not keep fields as permanent settings if you cannot explain them. After testing, return to the everyday usage guide to manage connections and modes. To change installation platforms, visit the client downloads page. Keeping routine use separate from configuration experiments makes future updates and troubleshooting clearer.