V2Ray Configuration File Reference
Follow the connection flow through JSON, inbounds, outbounds, routing, DNS, and policy. For a first install or subscription import, start with Getting Started. Use this page to look up fields, read exported configurations, and troubleshoot configuration-layer issues.
1. JSON Structure and Client Boundaries
From GUI Settings to Core Configuration
v2rayN is a popular desktop client for managing servers, subscription groups, system proxy settings, and core launch options. The selected core handles the actual connections. On Android, v2rayNG uses the Xray core, while v2flyNG uses the V2Fly core. The three clients have different settings interfaces, and their generated JSON may differ. Before inspecting a file, check which core is in use and whether the file is a complete runtime configuration or a single-server share. Subscription URLs, share links, client databases, and core configurations are distinct data sources; they are not interchangeable just because they contain server details.
A typical connection follows this path: an app sends traffic to an inbound on the local device, routing selects an outbound, and that outbound connects to the destination. inbounds define how connections are received, outbounds define how they are sent, and routing assigns connections to an outbound. dns configures lookups where needed, policy adjusts connection timers and statistics, and log controls which diagnostic details are recorded. Not every configuration needs every top-level object. An omitted field uses the core's default behavior; it does not mean the feature is absent from the connection flow.
Start with a Minimal Runnable Configuration
This complete configuration provides a SOCKS listener on the local loopback address and connects directly to every destination. It illustrates the configuration structure and listening behavior, but includes no remote proxy server and therefore creates no encrypted tunnel. Before running it, make sure no other client is using the port. The example explicitly names the route and outbound tags to make their references clear. With just one outbound, the core's default outbound behavior can also be used. Add the snippets in later sections at the appropriate levels; don't paste multiple top-level objects together at the end of the file.
{
"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": {}
}
],
"routing": {
"domainStrategy": "AsIs",
"rules": [
{
"type": "field",
"inboundTag": ["local-socks"],
"outboundTag": "direct"
}
]
}
}
How to Read Objects, Arrays, and Tags
Curly braces denote objects, and square brackets denote arrays. Inbounds and outbounds are usually arrays because one process can listen on multiple entries and use multiple exits. Write ports as numbers and switches as booleans; don't write true as a string. JSON keys and strings require double quotes. Trailing commas and ordinary comments are not allowed. Comments or notes accepted by a client interface may not be valid core configuration fields. If startup fails, check syntax first, then investigate protocol parameters. This avoids unnecessary changes.
tag is an internal identifier, not a server address or display name. A routing rule's outboundTag must exactly match an outbound tag. Changes to capitalization, spaces, or hyphens create a different reference. Use short, stable tags and check every reference after renaming one. Top-level object order usually does not determine execution order, but array order can matter, especially for routing rules and the default outbound. Reordering top-level keys won't fix a routing problem.
Before exporting a configuration, note the current proxy mode and active server. Save a separate copy of the export before making any changes. Files may contain subscription URLs, user IDs, and credentials; when asking for help, share only relevant fields and redact logs. See the download page for installers and platform options. If you haven't made a successful connection yet, follow Getting Started first, then return here to review the configuration section by section.
2. Inbound Listeners and Traffic Sniffing
The Listen Address Controls Who Can Reach an Inbound
An inbound is where the core accepts connections; it is not a remote server. listen sets the bind address, port sets the port, and protocol selects the inbound protocol. For a typical single-device setup, bind to 127.0.0.1 to accept connections only from the local loopback interface. Binding to 0.0.0.0 listens on all IPv4 interfaces, which may let other devices on your local network reach the inbound. Actual access also depends on firewalls, network isolation, and routing. If you need to share the inbound on a LAN, review authentication and access scope—not just the client's Allow LAN connections switch.
Matching port numbers is only one requirement for a working connection. If an app is configured to use an HTTP proxy, it must connect to an HTTP inbound; for a SOCKS proxy, it must connect to a SOCKS inbound. Some clients offer a mixed port that combines proxy protocols at the interface level. This guide shows separate inbounds so one client's port conventions aren't mistaken for universal core defaults. Check the actual listening port in the settings, then enter that address in the app. Don't run two configurations that try to bind the same address and port.
Separate SOCKS and HTTP Examples
Replace the top-level inbounds array with this snippet to provide separate SOCKS and HTTP listeners. SOCKS udp allows the inbound to handle relevant UDP forwarding requests, but the app must also use SOCKS UDP and the outbound must support that traffic. Enabling this field alone won't proxy UDP for every system app. An HTTP inbound is suitable for apps configured explicitly to use an HTTP proxy; whether an app follows the system proxy is up to the app.
{
"inbounds": [
{
"tag": "local-socks",
"listen": "127.0.0.1",
"port": 10808,
"protocol": "socks",
"settings": {
"auth": "noauth",
"udp": true
},
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls"],
"routeOnly": true
}
},
{
"tag": "local-http",
"listen": "127.0.0.1",
"port": 10809,
"protocol": "http",
"settings": {}
}
]
}
Sniffing Only Helps Identify Some Connections
Traffic sniffing tries to extract details such as domain names from protocol handshakes. For example, if an app supplies only a destination IP, the core may still find a domain in a recognizable HTTP host field or TLS handshake, allowing domain rules to match. destOverride specifies which protocol types may be sniffed; it does not let the core decrypt arbitrary traffic. Encrypted handshakes, application protocols, and core implementation all limit what can be identified. If no domain is detected, troubleshoot using the original destination supplied by the app and IP-based rules. Don't assume every connection has an available domain name.
routeOnly uses sniffed information primarily for routing decisions, without directly replacing the connection destination. This separates “which name to match against rules” from “where to connect.” Check the current core's support for this field and sniffing; don't invent a key based on a similar name if the field isn't recognized. If domain-based routing changes when sniffing is disabled, the rules may depend on sniffed data. Next, check how DNS is handled and whether the app preserves the destination domain instead of assuming the server is at fault.
| Field | What to Check |
|---|---|
listen | Local use or LAN sharing; whether the bound interface exists. |
port | The app's configured address and port match the actual listener; no other process is using the port. |
protocol | The app's proxy protocol matches the inbound protocol. |
sniffing | Whether domain sniffing is needed and the current core supports the fields in use. |
The system proxy switch configures the operating system through the client; it is not an inbound field here. After the system proxy is disabled, an app with a manually configured SOCKS address may still connect to the inbound. With the system proxy enabled, apps that ignore it may still connect directly. TUN involves a virtual network interface, route capture, and permissions; it can't be replaced by adding a regular SOCKS inbound. First identify how the app connects, then check the corresponding entry point. Avoid changing three unrelated switches at once.
3. Outbound Protocols and Tag References
Read Outbound Definitions Separately from Routing
An outbound sends a connection to the next hop. protocol selects direct access, blocking, or a proxy protocol; settings holds parameters specific to that protocol; and streamSettings describes the transport and security layers to the remote server. Routing selects an outbound but doesn't supply authentication details. Even if routing logs show a proxy tag was selected, the connection will fail if the server address, port, or security settings are wrong. Treat “the right outbound was selected” and “the outbound connected successfully” as separate checks.
freedom connects directly to the destination from the current device, while blackhole terminates matching traffic. Both handle traffic locally and need no remote address from a subscription. The snippets below provide two reusable outbounds that can be combined with the inbound from the first section. Tags have no special behavior: renaming a direct outbound doesn't change its protocol. The protocol field determines what it does. After renaming, update routing, proxy chains, and every other reference, or the configuration may fail to start or forward traffic as expected.
{
"outbounds": [
{
"tag": "direct",
"protocol": "freedom",
"settings": {}
},
{
"tag": "block",
"protocol": "blackhole",
"settings": {}
}
]
}
Check Remote Outbound Parameters as a Set
Build a working proxy outbound from real server details. The settings structure varies by protocol, so don't move a user field from one protocol into another. A VLESS outbound commonly includes a server list, address, port, user ID, and encryption settings; Trojan uses a different authentication structure. The server address determines where to connect, the user ID or password identifies the user, and TLS or REALITY parameters control the secure handshake. These fields work together; changing one value can make the whole set incompatible.
A graphical client’s server editor is a better place to manage these related parameters. Import complete share details from a trusted source, then compare them with the exported outbound object. This is usually safer than building one from scratch and helps keep fields consistent. This guide doesn't include account details that could be mistaken for a real server. When reporting a problem, include the protocol, transport type, whether security is enabled, and the stage where the error occurs—but remove credentials. Never post an outbound object with full user details in a public discussion.
Default Outbound and Array Order
In a common setup with no routing rules, unmatched connections use the first outbound in the array. Putting direct access first instead of a proxy changes the fallback behavior. Client modes such as Global or Bypass LAN may rebuild rules or reorder outbounds, so don't infer the final configuration from the mode name alone. Check the first outbound in the exported file, then look for a final rule that matches all traffic. If the configuration uses load balancing or outbound chains, follow those references rather than treating it as a single-outbound setup.
Multiple outbounds don't mean the client connects to every server at once. A regular routing rule selects an outbound by tag and hands the connection to it. Server testing, automatic selection, and failover require features provided by the client or core. Adding two proxy objects to the array doesn't automatically select the faster one. Duplicate tags can create ambiguity or configuration errors, so give each logical outbound a unique identifier. To sync across devices, see the guide to syncing subscriptions, QR codes, and exported configurations and distinguish syncing server details from syncing routing settings.
When extending a minimal configuration that already connects directly, keep one known-working inbound, add just one remote outbound, then add a rule that targets it. Add traffic splitting only after the connection works. This separates inbound, protocol parameters, and routing issues. If the client launches custom configuration differently from its built-in server mode, confirm that the current mode actually loads this file. Editing a configuration that isn't in use won't change the active connection.
4. Routing Rules and Match Order
Rules Are Evaluated in Array Order
Routing sends connections that have entered the core to a selected outbound. Common field rules use type: "field" to filter by destination domain, destination IP, port, network type, or inbound tag. Rules are usually evaluated from top to bottom; the first applicable match selects an outbound. Put specific exceptions before broader fallback rules. If a broad match comes first, later rules may never be evaluated. When reviewing routing, don't just search for the destination domain—check whether an earlier rule already catches the connection.
Conditions in the same rule usually all need to match. For example, inboundTag together with domain means the connection must come from the specified inbound and match the specified domain. Multiple entries in a domain array represent alternative acceptable matches. Don't mistake conditions across different fields for an either-or relationship. If you need to express two independent conditions, use two rules. Every inbound and outbound tag referenced by a rule must exist; a comment describing a tag doesn't replace an actual reference.
Exact Domains, Domain Suffixes, and IP Ranges
full: matches an exact domain, making it useful for a single hostname. domain: matches a domain and its subdomains, which suits a group of services under the same domain. regexp: specifies a regular expression for cases that truly require pattern matching. Check the core documentation for how plain strings match; don't assume they always mean exact matches. Regular expressions need additional backslash escaping in JSON, and a typo can be valid JSON but never match. If a rule can be expressed with a clear domain, a complex regular expression is usually unnecessary.
{
"routing": {
"domainStrategy": "AsIs",
"rules": [
{
"type": "field",
"domain": ["full:blocked.example"],
"outboundTag": "block"
},
{
"type": "field",
"ip": [
"127.0.0.0/8",
"10.0.0.0/8",
"172.16.0.0/12",
"192.168.0.0/16",
"::1/128",
"fc00::/7"
],
"outboundTag": "direct"
},
{
"type": "field",
"inboundTag": ["local-socks", "local-http"],
"network": "tcp,udp",
"outboundTag": "direct"
}
]
}
}
Use this snippet with the direct and blocking outbounds from the previous section. The reserved domain demonstrates exact matching, the private IP range illustrates an IP condition, and the final rule sends other connections from both local inbounds directly. This is not a proxy-routing setup. To use a proxy as the fallback, first add a real, working proxy outbound, then change the final tag. Whether a domain that resolves to a private IP matches the IP rule depends on whether the destination IP is available and whether the domain strategy triggers resolution.
domainStrategy and Rule Data Files
AsIs uses information already available for the connection as much as possible and doesn't actively resolve domains for routing. IPIfNonMatch attempts resolution when a domain doesn't match, then checks IP rules. IPOnDemand may resolve a domain when it encounters a rule that needs an IP. The latter options rely more on DNS and can change which rule matches. These strategies are for routing decisions; they aren't the resolution strategy used when an outbound connects, and they don't replace the operating system's DNS settings.
geoip: and geosite: rules depend on available data files and the categories they contain. A correctly written string doesn't guarantee the client includes the required data. If startup reports a missing file or category, check the core's resource directory and the client's rule-data management options rather than substituting a similar-looking category name. When moving a custom configuration between devices, account for these external dependencies too. Copying a JSON file alone doesn't make the environments equivalent.
To troubleshoot a routing rule, first note whether the inbound receives a domain or an IP from the app. Then check whether sniffing adds a domain, and evaluate each rule in order. Temporarily moving a specific domain rule higher can help determine whether an earlier rule is catching it, but restore a sensible order after testing. Rule changes generally affect new connections only. A browser or app may reuse an existing connection, so the result can lag behind the change. Start a fresh test connection before judging the outcome; don't keep changing the configuration while an old session is still active.
5. DNS Resolution and Routing Boundaries
First Find Out Which Resolver Is in Use
A single request may involve the operating system resolver, an app's own resolver, the core's built-in DNS, and resolution by the remote server. The top-level dns object only controls lookups the core performs; it doesn't automatically take over every DNS request on the system. If an app resolves a domain to an IP before passing it to a SOCKS inbound, the core sees an IP as the original destination. If the app passes the domain to the proxy, resolution may happen elsewhere. Start by checking what the app actually sends. A DNS object in the configuration doesn't prove that all queries use it.
This example uses standard DNS server addresses to show the field structure; it isn't a recommended setup for any particular network. servers is a list of resolvers and can contain simple addresses or objects with matching conditions. hosts statically maps names to addresses, which can help with temporary troubleshooting or fixed internal services. Those mappings won't update automatically when a service's address changes. The example's test domain and documentation addresses illustrate the format and shouldn't be kept as real website records.
{
"dns": {
"hosts": {
"full:service.example": "192.0.2.10"
},
"servers": [
"1.1.1.1",
"8.8.8.8"
],
"queryStrategy": "UseIP"
}
}
Query Strategy Isn't Connection Strategy
queryStrategy controls which address families the core uses for DNS queries. UseIP allows both IPv4 and IPv6 results, while UseIPv4 and UseIPv6 limit the query to one family. Check support in the current core. Restricting queries to IPv4 can help diagnose certain IPv6 path issues, but it won't fix an incorrect server handshake. Conversely, if the device can reach a service only over one address family, restricting DNS too much can remove the addresses needed to connect.
The domain strategy in routing, the query strategy in DNS, and an outbound's own domain resolution options apply at different stages. Routing may resolve a domain to match IP rules, then the outbound may handle the destination according to its own logic. If the strategies differ, the observed addresses may not match. First decide whether you want to “select an outbound by domain” or “select an outbound by the resolved address,” then choose where resolution is needed. Don't set similarly named options to the same value just for consistency.
The Resolver Itself Needs a Reachable Path
Both regular DNS queries and encrypted DNS requests need a route to their resolver. Core implementations differ in DNS address formats, direct connection modes, and query routing, so don't copy an address format from one core to another without checking. If the resolver is specified by a domain, consider how the resolver itself will be resolved on the first request—this is the bootstrap DNS problem. If the resolver is reachable only through a proxy, but the proxy server's address also depends on that resolver, the setup can create a dependency loop. Keep an independent startup path for at least one part of the chain.
Don't treat a DNS server list as a fixed, ordered failover checklist. Whether queries run in parallel, when a fallback is used, and whether a domain-specific server excludes the default fallback depend on the core and object fields. To route queries by domain, first verify that each server is reachable in a simple setup, then add domain conditions and fallback behavior. Adding several servers while changing routing at the same time makes timeouts hard to diagnose. Record the query, destination address family, and error time to distinguish DNS timeouts from connection timeouts.
Caching can affect what you see. An app may cache its own domain results, the operating system may cache records, and the core may reuse resolution data. Existing connections may not be rebuilt immediately after a DNS change, and the old address may still appear. Close old sessions in the test app, then make a new request. If needed, restart the core using the client's available controls to clear runtime state. A single page refresh doesn't prove the new DNS strategy is fully active. Don't mistake a short-lived cache difference for random routing failures.
If a domain fails but a known IP address is reachable, consider the certificate and server name before treating the site's URL as interchangeable with its IP. Troubleshoot in order: confirm the DNS response, confirm the selected outbound, check that the outbound can reach the destination, then inspect the handshake. Keeping these stages separate prevents DNS and security-layer errors from getting lumped into a single “site won't open” report.
6. Policy: Connection Timeouts and Statistics
Policies Are Selected by User Level, Not UI Group
policy manages connection lifetimes and some statistics; it doesn't choose an outbound or change protocol authentication. Keys in levels are strings representing user levels, such as "0". Protocols that support a user-level field use it to select the corresponding policy. A level is not a subscription group, server priority, or routing rule index. Adding a level object alone won't assign every protocol object to it. When reviewing an exported configuration, check the user object's level as well as whether the core supports it for that protocol.
This example shows the structure of user-level policies and system statistics switches. The numbers illustrate the fields; they aren't performance recommendations for every device. Most users can start with the client defaults and change them only when logs and connection behavior point to a timeout issue. Defaults, buffer allocation, and statistics interfaces vary by core, so check that fields are still supported before migrating a configuration, then compare runtime behavior. Copying the same network parameters to every device doesn't guarantee the same results.
{
"policy": {
"levels": {
"0": {
"handshake": 4,
"connIdle": 300,
"uplinkOnly": 2,
"downlinkOnly": 5,
"statsUserUplink": false,
"statsUserDownlink": false
}
},
"system": {
"statsInboundUplink": false,
"statsInboundDownlink": false,
"statsOutboundUplink": false,
"statsOutboundDownlink": false
}
}
}
Four Timeout Fields, Four Different Stages
handshake sets a time limit, in seconds, for the inbound protocol handshake. It isn't the total page load time or a universal control for every remote TLS handshake. If the local port is unreachable before the handshake starts, increasing this value won't help. If the remote outbound fails due to an authentication error, extending the inbound handshake timeout won't fix it either. Use logs to identify where the connection stalls before deciding whether more time is needed.
connIdle limits how long a connection can remain without data activity. Too short a value may disrupt long-lived connections that send data intermittently; too long a value can keep idle connections around and using resources. Application heartbeats, server idle policies, and network device timeouts also affect connection lifetime, so increasing the client timer alone can't override other limits. When investigating periodic disconnects, note whether data was being exchanged before the disconnect and whether the client and server have different timeout limits.
uplinkOnly and downlinkOnly set the wait time after one side of a connection closes while the other direction can continue transmitting. This half-closed state isn't the same as the whole connection being idle: the end of an upload doesn't mean the download is done, and the end of a download doesn't mean every app has stopped sending. Values that are too aggressive can cut off a transfer that needs to finish; values that are too large may leave sessions open longer than necessary. For large files or errors at the end of a request, check the application protocol and logs. These fields don't limit upload or download speed.
Enabling Statistics Doesn't Make Data Appear in the UI
User statistics require the relevant user identity and core support; system statistics count activity around inbound and outbound objects. Setting a field to true allows the corresponding statistics to be collected, but doesn't create an API to read them or add a dashboard to the client. Some setups also need a top-level statistics module, an API service, and a client that can query it. A graphical client may already manage these settings. Adding a duplicate API inbound or statistics service by hand can cause a port conflict. For everyday connection details, start with the client's existing logs and status views.
Buffer-related policy fields aren't universal speed boosters. Buffer size, concurrent connections, device memory, and protocol behavior all affect resource use. A larger buffer can increase memory pressure without changing the capacity of the remote connection. Keep defaults unless you can reproduce a specific bottleneck and have clear documentation for the core. On mobile devices in particular, background restrictions and battery-saving settings may be the cause of interruptions; core policies can't replace permission for background activity.
Change one policy setting at a time and keep the last working configuration. Test a short request, a sustained transfer, and a connection that resumes after idling; check each for issues. If the client regenerates the file, save changes in a supported advanced settings area instead of repeatedly editing a temporary runtime file. Successful startup shows that the syntax and some semantics were accepted; it doesn't prove the timeouts suit your app. Verify their behavior with real use.
7. Transport, Security Layers, and Core Differences
Proxy Protocols Are Only One Part of the Stack
A server entry usually combines a proxy protocol, a transport, and a security layer. The proxy protocol handles authentication and proxy behavior, the transport carries the data, and the security layer protects the relevant handshake. These may appear next to each other in the UI, but they aren't the same field. The outbound's protocol and streamSettings.network serve different purposes. Putting a transport type in the proxy protocol field produces the wrong structure. If a configuration works in one client but not another, compare all three layers first, then check whether each core accepts the syntax.
This snippet shows WebSocket with TLS transport settings. Place it inside an outbound with real server parameters, not directly at the JSON top level. The reserved domain illustrates field placement; it isn't a usable server address. The settings must also match the server's transport, path, and certificate name. Copying this snippet without the right outbound protocol and authentication settings won't establish a working connection.
{
"streamSettings": {
"network": "ws",
"security": "tls",
"tlsSettings": {
"serverName": "edge.example",
"allowInsecure": false
},
"wsSettings": {
"path": "/connect",
"headers": {
"Host": "edge.example"
}
}
}
}
Address, serverName, and Host Are Different
The outbound server address specifies which host to connect to. serverName participates in the TLS handshake and certificate name check; the WebSocket Host is the host information in the HTTP handshake. These values may be identical in some deployments and deliberately different in others. Don't force them to match for consistency's sake. If you see a certificate error, check the device clock, server name, and server-side certificate configuration before disabling certificate verification. Disabling verification changes the connection's trust requirements and can conceal an incorrect destination.
The WebSocket path must match the transport endpoint on the server, including capitalization and path. It isn't an arbitrary directory from a browser address bar and shouldn't be copied from an unrelated server entry. If the response looks like a regular web page or the handshake status is wrong, the connection may have reached another service on the same host. Check the transport, path, and host fields rather than repeatedly changing the user ID. A basic port check only proves that something responds on the port; it doesn't prove the proxy protocol combination is correct.
REALITY and Core Selection
REALITY is a security-layer feature, not a top-level proxy protocol or a generic enhancement switch. Verify support in the core and check the server-provided server name, public key material, short ID, and other required parameters. Different cores and configuration generations may use different field names; guessing keys won't solve compatibility issues. This guide doesn't provide a generic REALITY template without server details. Start with complete share information the client can recognize, then compare it with the generated outbound object.
The features available in v2rayN depend on the selected core and client integration. v2rayNG and v2flyNG aren't interchangeable just because their interfaces look similar. If you need a particular protocol or security layer, confirm that the core implements it before choosing a client. Changing cores may cause old configuration fields to be rejected or behave differently by default. Save the original configuration, regenerate it using a supported client workflow, then compare the important parameters. For background, see how the Xray and V2Fly cores differ.
| Layer | What to Check |
|---|---|
| Proxy Protocol | Protocol type, user identity, and protocol-specific settings. |
| Transport | Whether the carrier, path, and transport handshake fields match the server. |
| Security Layer | Security type, server name, and required authentication material. |
| Core Implementation | Whether the combination is supported and the field structure is correct. |
Mux is a separate connection-multiplexing mechanism. It can't fix a security handshake or authentication error, and it doesn't benefit every app. A Mux switch in the client may change the generated outbound configuration, so check protocol compatibility and core limitations before using it. For troubleshooting, first disable extra connection options and test the basic setup, then restore them one at a time. Don't change Mux, DNS, routing, and sniffing together before the protocol connects; even if it starts working, you won't know which change helped.
When moving between platforms, keep the system environment in mind. Windows, macOS, and Linux use different system proxy mechanisms. Android VPN routing and per-app selection aren't JSON transport fields either. Even with correct transport settings, no expected connection will be made if the app never reaches the inbound. For macOS first-launch approval or network permissions, see the installation approval and network permissions guide. Don't try to fix system permission issues by changing protocol parameters.
8. Configuration Checks, Logs, and Rollback
Check Syntax, Startup, Inbound, and Outbound in Order
Start troubleshooting with a working copy you can restore. Save the current client settings and custom configuration, change one layer, restart the relevant core, and make a new connection. If startup fails, check the first meaningful error. A missing comma is a JSON syntax issue; an unknown field or protocol points to a compatibility issue; a listener failure often means an address or port conflict. These problems occur before normal traffic forwarding, so don't start by investigating remote server speed or website availability. Fix the earliest error, then review subsequent logs to avoid chasing knock-on errors.
This snippet can temporarily replace the top-level log object to provide more diagnostic detail. debug produces a lot of output and may include destination addresses and connection details. After troubleshooting, restore a level suited to everyday use. The example doesn't specify a file path; the startup method and client determine where logs go. If the UI doesn't show more detail, check whether the client supports that level and whether the running process loaded the modified file before assuming the logging module has failed.
{
"log": {
"loglevel": "debug"
}
}
Narrow Down the Problem by Where It Occurs
Once the core starts normally, first check whether the app actually sends a connection to an inbound. If there's no matching entry, check the app's proxy address and protocol, system proxy mode, and per-app settings. If there's an entry but the wrong outbound is selected, check tags, rule order, and the destination type. If the correct outbound is selected but the connection fails, check the remote address, authentication, transport, and security layer. If the connection works but certain domains don't, then investigate DNS, domain matching, and the destination service. This order helps avoid labeling every issue “the server is broken.”
A connection refusal usually means the destination port isn't listening or actively rejected the connection; it isn't the same as a DNS failure. A resolution timeout occurs before an address is returned. A handshake failure means some form of protocol negotiation has begun, but logs are needed to identify the reason. A timeout alone doesn't pinpoint the problem: it can occur while connecting, during a handshake, or while waiting for a response. When describing an issue, state the stage and steps to reproduce it rather than sharing a vague one-line error. Timestamps help match an action to its log entries.
Create a Minimal, Reproducible Case
Start with one active server, one clear inbound, and a simple outbound rule. Temporarily remove extra routing. Once the basic connection works, restore domain rules, IP rules, DNS conditions, and advanced policies one at a time. If the problem returns after restoring a layer, keep only the relevant conditions from that layer and investigate them. If the configuration depends on rule data files, say whether the files exist and the categories are valid. Don't submit a full export packed with unrelated rules as your first troubleshooting report; too much detail can hide the real cause.
Client-generated configuration is a common variable. If a change works briefly but stops after switching servers, you may have edited a temporary file or the current mode may not save custom settings. Go back to a client-supported settings area, confirm where changes are saved, then compare a fresh export. Subscription updates only update the server data they manage; don't assume they preserve every manually added field. For the main window, see the server list, log panel, and settings overview. For configuration structure, continue with a section-by-section guide to config.json.
Common Troubleshooting Questions
Why isn't my app using the proxy even though the configuration starts?
A successful startup only means the core is running. Confirm that the app reaches the right inbound through the system proxy, an explicit proxy setting, or client capture. Then check whether routing selects the expected outbound. First look for an inbound entry, then review the protocol settings.
Why didn't an existing web connection change after I edited a rule?
An existing connection may keep using its original outbound and address. Close the test app's old session and make a new connection, then check the new logs. Restart the core if needed, but don't use a restart as a substitute for checking the rules.
To roll back, restore the last known-good client settings or complete configuration, restart the core, and verify the active server, proxy mode, and inbound port. If the issue persists, the JSON change may not be the only cause; also check system networking, permissions, and server status. Review the basic steps in Getting Started. To choose a client for your device again, use the download page. Don't switch clients repeatedly instead of identifying where the error occurs.