config.json Reference

Explore the structure, parameters, and processing order of each configuration section. For installation, importing subscriptions, and connecting for the first time, start with the Getting Started Guide. This page explains client-generated configurations and helps diagnose issues involving inbounds, outbounds, routing, and DNS resolution.

JSON Structure Overview

In the V2Ray ecosystem, a configuration file describes an end-to-end traffic path: an application connects to a local listener, an inbound passes the request to the core, routing selects an outbound based on the source and destination, and the outbound establishes the connection. dns provides built-in name resolution, while policy controls time limits for some connection stages. The file is commonly named config.json, but its meaning depends on its contents and the core that loads it—not the filename. First identify whether you are using Xray or V2Fly, then check the configuration format supported by that core.

Objects, Arrays, and Field Types

The top level is a JSON object. inbounds and outbounds are arrays because a single process can expose multiple listeners and use multiple outbounds. routing, dns, and policy are objects that hold rules, servers, or policy mappings. Field names and strings use English double quotes; ports are usually numbers, and switches use the Boolean values true or false. Numbers and strings are not interchangeable. Paths, tags, and protocol names must also be spelled exactly.

Strict JSON does not allow comments, trailing commas, or typographic quotation marks. Some core tools may support additional configuration formats, but use strict JSON when sharing a file between clients. Indentation in examples is for readability; brackets, commas, and data types affect parsing. A JSON parser accepting a file confirms only that its syntax is valid—not that its protocol fields, outbound references, or runtime environment are correct. If startup fails, distinguish a syntax error from a core configuration error before changing anything, and avoid editing multiple layers at once.

config.json · Minimal Direct-Connection Baseline

This is a complete example with a local SOCKS inbound and a direct outbound. It illustrates the traffic path and does not include a remote proxy connection.

{
  "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": {}
    }
  ],
  "routing": {
    "domainStrategy": "AsIs",
    "rules": []
  },
  "dns": {
    "servers": ["localhost"]
  }
}

How Configuration Sections Reference Each Other

tag is an internal configuration name, not authentication information sent to a server. A routing rule's outboundTag must refer to an existing outbound; inboundTag can restrict a rule to requests from a particular inbound. Use short, stable names and keep tags unique within their respective arrays. When changing an outbound tag, update every rule that refers to it. Otherwise, the file may look complete while connections are routed incorrectly. The first outbound is usually the default, so array order is part of the configuration's behavior.

The order of top-level sections does not determine processing order. Putting dns before routing does not make every request pass through built-in DNS first; moving a rule to the top of an array can change which rule matches. When reading a configuration, distinguish object field order from array element order. The former is generally for organization, while the latter can affect routing and default outbound selection. Before merging configuration sections, check for duplicate top-level keys. A parser may silently overwrite duplicates, making them easy to miss.

Start by saving a baseline that launches successfully, then add sections one at a time in this order: inbounds, outbounds, routing, DNS, and policy. Reload and check the logs after each change. This narrows an error down to the latest change instead of leaving you to guess through a complex file. Graphical clients may generate auxiliary inbounds and internal tags; map the main traffic path first, then identify which parts the client maintains automatically.

Inbound Listeners

inbounds define where the core receives traffic. Local clients commonly use SOCKS or HTTP inbounds, which applications access through the corresponding proxy protocol. An inbound is not a remote server and does not choose the final proxy outbound. When troubleshooting, first check whether the application is actually connecting to this inbound. Routing and outbound settings matter only after the request reaches the core. A browser using the system proxy and an application configured with a SOCKS address use two different ways to connect.

Listen Address, Port, and Protocol

listen specifies the local address to bind to. For a proxy on a personal device, prefer 127.0.0.1 so only local connections can reach the inbound. Binding to all interfaces expands access and is not a general fix for connection problems. port must match the port configured in the application and must not be in use by another process. protocol determines how the application communicates with the inbound. Sending HTTP proxy requests to a SOCKS port usually causes a handshake failure; the protocols are not converted automatically.

Common Inbound Fields
FieldPurposeWhat to Check
tagInbound tagMust match the source tag in routing
listenBind addressFor local use, prefer the loopback address
portListen portMust match the application setting and be available
protocolInbound protocolMust match the application's proxy type
settingsProtocol-specific optionsCannot be copied between protocols unchanged
sniffingTraffic destination detection optionsDistinguish detected results from the original connection target

SOCKS vs. HTTP Inbounds

A SOCKS inbound is suitable for applications that explicitly support SOCKS proxies. Enabling settings.udp only allows the inbound to handle SOCKS UDP forwarding; the application must also use the appropriate protocol, and the outbound and remote connection must support that traffic. An HTTP inbound is generally for applications that support HTTP proxies or CONNECT, not arbitrary UDP traffic. The system proxy setting affects only applications that honor it, so it does not mean every connection on the device enters the core.

{
  "inbounds": [
    {
      "tag": "http-in",
      "listen": "127.0.0.1",
      "port": 10809,
      "protocol": "http",
      "settings": {}
    }
  ]
}

This snippet adds one HTTP inbound. To combine it with the baseline in the previous section, append the object to the existing inbounds array rather than adding another top-level key with the same name. The port is an example, not a value all clients use. v2rayN and Android clients may generate different ports depending on their settings, so check the active client configuration. If you change the listen port, update the application's proxy settings too; otherwise, it will keep trying the old port.

Destination Detection and Connection Scope

sniffing can extract domain names from supported traffic patterns, providing more information for domain-based routing. It does not decrypt all traffic or guarantee that a domain can be recovered from every connection. Support for destination overrides and routing-only options varies by core and should be checked separately. When first troubleshooting, keep the client's default detection settings and confirm that ordinary requests get through. Then check whether domain information affects routing, rather than conflating inbound problems with detection behavior.

Allowing LAN access requires considering the bind address, authentication, host firewall, and trusted network. Changing only listen does not guarantee that other devices can connect, nor does it make the inbound safe to expose to the public internet. For personal use on the same device, loopback binding is usually easier to control. If the logs report that an address is already in use, stop the old client or choose an available port. If there are no inbound requests at all, check the application's proxy address and type, and whether a rule bypasses the local proxy.

TUN interception and ordinary SOCKS or HTTP listeners operate at different connection layers. A client can pass traffic to the core through a virtual network interface, but the interface name, permission requests, and system routes are often managed by the client—not by one generic inbound field. See the v2rayN TUN Mode Setup Notes. Before troubleshooting this section, determine whether you are diagnosing an application proxy inbound or the virtual-interface interception path.

Outbounds and the Default Route

outbounds holds the routes the core can use. An outbound can connect directly to a destination, reject a connection, or forward it through a remote proxy. Routing rules select an outbound tag, not the display name shown in a subscription. When a client switches nodes, it often regenerates the proxy outbound's address and authentication parameters. Selecting a node and editing outbound JSON are different steps along the same path. When inspecting an exported configuration, identify which outbound corresponds to the selected node and which rules actually reference it.

Separate Protocol and Transport Settings

protocol specifies the outbound protocol, and settings contains the parameters it requires. For remote protocols such as VMess, the server address, port, user ID, and other parameters must match the server. streamSettings describes the transport and security layers, such as the transport type, whether to use TLS, and the server name. Protocol authentication and transport establishment are separate stages, so not every failure is caused by an incorrect server address.

The server address shown in the interface, the TLS server name, and the Host value used by HTTP-based transports can serve different purposes. The server address identifies the connection endpoint, the TLS server name is used during the handshake and certificate identity check, and the transport Host is a request parameter for the relevant protocol. They may sometimes be the same, but should not be forced to match. Use the connection details provided by the server operator when making changes. Disabling certificate verification can hide identity and connection issues; it is not a sound routine troubleshooting step.

Direct, Block, and Proxy Outbounds

{
  "outbounds": [
    {
      "tag": "direct",
      "protocol": "freedom",
      "settings": {}
    },
    {
      "tag": "block",
      "protocol": "blackhole",
      "settings": {}
    }
  ]
}

This snippet uses freedom to connect directly to the destination and blackhole to reject traffic assigned to that outbound. Direct is the first outbound, so requests that match no rule use it by default. If the block outbound is moved to the top, unmatched requests may all be rejected. There is no proxy outbound here, so this example cannot test a remote proxy. When adding a real proxy outbound, decide whether unmatched traffic should use the proxy or connect directly, then set the array order or add a final fallback rule accordingly.

Configuration LayerWhat It ContainsTypical Mistake
tagOutbound tagA routing rule refers to a tag that does not exist
protocolOutbound protocolThe core does not support the selected protocol
settingsProtocol authentication and destination parametersFields do not match the protocol's expected structure
streamSettingsTransport and security layersTransport type, path, or server name does not match

Core Differences and Connection Support

Xray and V2Fly share some configuration conventions, but their fields are not freely interchangeable. Even features with the same name may differ in accepted values, defaults, or support requirements. This is especially important for newer protocols, transports, security layers, and DNS policies: check the capabilities of the core you are actually using. Before handing a configuration to a different core, check its protocols and transports, then its extension fields. A file being named config.json does not mean it will run unchanged.

UDP traffic requires support across the entire connection path. The inbound must allow UDP, the outbound protocol must be able to carry it, the server must allow forwarding, and the network path must be reachable. Any missing link can cause a failure. A working website only confirms that the relevant TCP requests work; it says nothing about whether voice, games, or other UDP applications have a working path. When only some applications fail, identify the network protocol they use before checking the inbound, outbound, or remote forwarding settings.

For your first setup, use v2rayN's node editor or subscription import to generate a remote outbound, then refer to this section. Avoid filling in authentication details by hand from snippets. On Android, v2rayNG and v2flyNG offer different core choices; see the Xray vs. V2Fly Core Selection Notes. When sharing diagnostic information, include only the fields and error details needed for troubleshooting. Hide subscription addresses, user IDs, and other credentials to avoid exposing full connection details in logs.

Routing Rules and Match Order

routing determines which outbound handles each request. It applies to traffic that has already entered the core; it does not replace operating-system routing or automatically connect applications that ignore proxy settings. The most common structure is a rules array. Each field rule can check the request's domain, IP, port, network type, or inbound tag. Rules are checked in order, and the selected action is applied when a rule matches. An overly broad rule can therefore prevent later, more specific rules from being reached.

How Rule Conditions Combine

In field rules, multiple values in the same list usually mean that any one of them can match. For example, a domain array can list several domains. Different condition fields in one rule, however, must all match. For example, specifying both inboundTag and domain means the request must come from the specified inbound and have a destination domain on the list. Mistaking this for an either-or condition makes the rule narrower than expected. When troubleshooting, start with one condition, confirm it matches, then add restrictions one at a time.

{
  "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", "192.168.0.0/16"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "network": "tcp,udp",
        "outboundTag": "direct"
      }
    ]
  }
}

This snippet can be combined with the direct and block outbounds from the previous section. The reserved example domain blocked.example demonstrates exact-match syntax; all other requests connect directly. The final rule is an explicit fallback and does not demonstrate proxy routing. To use a proxy as the fallback, first add a real proxy outbound, then set the final rule to its exact tag. Adding an undefined proxy tag to a rule does not create a working outbound.

Domains, IPs, and Resolution Strategy

full: matches an exact domain, while domain: matches a domain and its subdomains. Plain strings and regular expressions have different meanings, so do not assume they cover the same scope based on how they look. IP conditions can use a single address or a CIDR range. For geographic classifications, make sure the runtime environment has the required data files, the category name exists, and the data source is trustworthy. To isolate issues, start testing with one specific domain or address before introducing large classification lists.

domainStrategy determines how routing uses DNS resolution. AsIs preserves the destination information in the request. IPIfNonMatch can try resolving the domain and continue with IP matching if no domain rule matches. IPOnDemand can trigger resolution when a match requires IP information. Check the behavior supported by your core for exact details. When choosing a strategy, consider resolution overhead, DNS reachability, and fallback rule placement; more aggressive resolution is not necessarily more accurate.

If the original request contains only an IP address, domain rules may never match. The application may have resolved the name through the operating system or obtained an address using its own encrypted DNS. Inbound destination detection can add domain information for some supported traffic, but only in limited cases. Conversely, a domain request may not immediately have an address available for IP rules. When diagnosing a rule, check the logs to see the actual destination the core received instead of relying on the browser's address bar.

Maintaining Rules and Regression Testing

Organize block rules, service-specific rules, LAN rules, and fallback rules in clear layers. Whenever you add a rule, record the expected destination and outbound, then check whether an earlier rule matches first. Rule order is not just a matter of presentation: moving a rule can change behavior. If the client offers preset routing modes, check whether a preset overrides your custom list and whether switching modes regenerates the entire configuration section.

For a closer look at how the three main configuration sections work together, read Inbounds, Outbounds, and Routing: A Section-by-Section Breakdown. If you only want to change which everyday applications are intercepted, first check the client's system proxy or TUN status, then edit core routing. Adding more domain rules will not change an application's connection path if it has not connected to the client.

DNS Servers and Domain-Based Routing

dns configures the core's built-in resolver, but does not automatically take over every DNS request on the device. System resolution, application-specific resolution, resolution performed by the core for routing, and resolution on the remote outbound may all be involved. Before reading the configuration, identify which layer needs the address. If an application has already supplied an IP, changing the built-in servers may not affect the connection. The built-in resolver can directly affect routing when routing needs to resolve a domain to an IP address.

The servers List and Server Objects

servers can contain simple server entries or server objects with conditions such as domain ranges. localhost uses the system's local resolution path and is useful for a minimal diagnostic baseline, though its results still depend on system DNS, the network, and local settings. Specifying a public resolver only sets the query destination; it does not guarantee that the query goes through a proxy or returns the expected result. Whether the server is reachable and how the query is sent depend on the core and related routing settings.

{
  "dns": {
    "servers": [
      {
        "address": "1.1.1.1",
        "port": 53,
        "domains": ["domain:example.com"],
        "expectIPs": ["93.184.216.0/24"]
      },
      "localhost"
    ]
  }
}

This example uses a reserved domain to illustrate query matching and result filtering. The address range in expectIPs demonstrates filter syntax; it does not mean the domain currently resolves to that range. Domain addresses can change, so copying this value may cause the filter to fail. Before deployment, specify a range that matches the resolution scope you manage, or remove the condition if you are unsure of the expected addresses. This example does not claim that queries to the first server go through a proxy; check the query path separately when troubleshooting.

domains, expectIPs, and Fallback Behavior

domains describes the domain ranges that a server should prioritize; it should not be mistaken for the final outbound selection made by routing. expectIPs applies an expected range to resolution results to help identify unexpected addresses; it does not correct the answers returned by a resolver. A range that is too narrow or out of date can reject valid results and make an otherwise reachable domain fail to resolve. Before using these conditions, understand how the domain is hosted and whether its addresses are stable.

How matching servers, non-matching servers, and fallback after query failures behave depends on the core and related switches. Do not assume that all queries run strictly in array order just because of a server's position. Before excluding a server from ordinary fallback, verify the meaning of the corresponding field in your core and test it in isolation. For complex routing, first confirm that each server can resolve the target domain independently, then combine them in a policy. This is easier to troubleshoot than stacking multiple restrictions at once.

SymptomCheck FirstOften Confused With
All domains fail to resolveResolver reachability and query pathBuilt-in DNS vs. system DNS
Only some domains failDomain conditions and result filtersResolution filtering vs. connection blocking
Results do not change after editing the configurationCache, reload, and application-specific resolutionExisting connections vs. new queries
Domain resolves, but direct connections to the address failOutbound selection and destination service requirementsSuccessful resolution vs. service reachability

Resolution Loops, Caching, and Address Families

When using an encrypted DNS endpoint, its hostname may need to be resolved too. If resolving that hostname depends on the same resolution path that has not yet been established, a startup dependency loop can occur. To fix it, map out the bootstrap resolution path and the route for DNS queries instead of repeatedly changing server names. Core support for local queries, remote queries, and DNS routing tags varies. Check these details again when switching cores; a transport name alone does not fully describe how it behaves.

Also distinguish between IPv4 and IPv6 results. Receiving an IPv6 address does not mean the current outbound has a working IPv6 route; querying only IPv4 is not suitable for every network either. During testing, record the address family of the resolution result and compare it with the address used by the failed connection. After changing DNS, reload the configuration and establish a new connection. The operating system, application, and core may each cache results, so old entries can affect observations for a while. Refreshing a page once is not enough to conclude that a change had no effect.

The goal of DNS configuration is to align where a name is resolved, how the query is routed, and which outbound makes the connection—not simply to add more servers. For domain-based resolution rules, follow the DNS Split Resolution Setup Notes and check each step. A short list of tested rules with clearly defined scopes is easier to maintain than a long list without a testing basis.

policy: Connection Stages and User Levels

policy is neither a routing rule nor a client-wide interception mode. It mainly defines policies for connection stages, idle periods, and some statistics. A common misconception is to treat time limits in policy as network acceleration settings. Shortening a timeout usually makes a failure appear sooner; it does not reduce the actual network latency. Aggressive limits may also interrupt connections that would otherwise recover. Unless you are addressing a specific issue, keep the core defaults.

How levels and level Relate

levels uses user levels as keys, with a set of policies for each level. JSON object keys must be strings, so the example uses "0". In protocol user objects that support user levels, level is usually a number. These values are associated, but they are not the same field. Defining a level does not make every connection use it automatically. Whether it takes effect depends on whether the relevant protocol supplies a user context and which level that user has.

{
  "policy": {
    "levels": {
      "0": {
        "handshake": 4,
        "connIdle": 300,
        "uplinkOnly": 2,
        "downlinkOnly": 5
      }
    }
  }
}

This snippet shows only the structure of a policy object; the values are in seconds and are not recommendations for every network. It does not create users, outbounds, or listeners, and it does not guarantee that every protocol applies these limits. If the client does not expose user-level settings, first check the mapping in its generated configuration. In particular, levels is not a node priority list: a higher number does not mean a faster node or higher routing priority.

Handshake, Idle, and One-Way Connections

handshake sets how long the relevant connection-establishment stage may wait. Some networks have slower authentication or handshakes, so an overly short value can cause repeated retries. connIdle sets an idle limit for a connection with no data activity, but actual behavior also depends on the protocol, application keepalives, and intermediate network devices. Even if the core allows a long idle period, a router or remote service may close the connection earlier. Increasing this value alone cannot guarantee that a long-lived connection stays open.

uplinkOnly and downlinkOnly set the remaining wait time after one direction of data flow ends; they are not upload or download speed limits. Interpret uplink and downlink as directions in connection handling, not as terms from a speed test. Some applications finish sending before waiting for a server response. If the remaining wait is too short, the connection may close before the response arrives. To analyze this, check when the connection half-closes rather than looking only at whether the page reports a timeout.

FieldStage to ConsiderNot a
handshakeConnection handshake waitA switch to reduce physical latency
connIdleIdle period with no data activityA guarantee that the connection will stay open
uplinkOnlyUplink-only stage remainingAn upload speed limit
downlinkOnlyDownlink-only stage remainingA download speed limit

Statistics Settings and Client Displays

Some policies control user-level or system-level traffic statistics, but enabling a policy field alone may not provide a complete statistics pipeline. The core may also require a statistics module, a management interface, and client-side reading logic. User statistics may depend on a protocol user ID as well. Traffic shown in the interface does not necessarily come from policy; a blank display does not prove that traffic bypassed the core. Troubleshoot statistics separately from connectivity, and first confirm that requests are being handled correctly.

If you do not need remote management, do not expose a management listener just to display statistics. If the client maintains an internal interface, keep its default access scope and make sure custom configuration does not override it. Cores differ in statistics fields, memory-related options, and default policies. Copying a policy with many extension fields may only increase the risk of startup failures. Check each field's purpose and remove settings you cannot explain or do not need.

Regression testing should cover at least three cases: a short request, a sustained transfer, and recovery after an idle period. A single ordinary web request does not show whether a policy suits long-lived connections. Record the field values before and after, the actual wait behavior, and the error type. Revert to the default if there is no consistent improvement. Making one small change is easier to validate than changing handshake, idle, and several client settings at once.

Client-Generated Configuration and Reloading

Settings saved by a graphical client are not necessarily identical to the JSON ultimately read by the core. Subscription groups, node labels, interface themes, system proxy settings, and auto-start are generally client-level settings. Inbounds, outbounds, routing, and DNS may be generated by the client from those settings. Directly editing a file in the runtime directory may be undone the next time the client starts or switches nodes. Before editing, identify where the configuration comes from so you can decide whether to change a client setting or use an explicitly provided custom configuration option.

Subscriptions, Nodes, and Complete Configurations

A subscription usually provides multiple connection entries and related information; the client parses and stores them, then generates outbounds. A node share describes one remote connection and may not include local listeners or complete routing. A full core configuration must describe all the components needed to run. Saving a node string as config.json does not turn it into JSON configuration. Importing a snippet containing only dns as a complete configuration may leave out required inbounds and outbounds. Use the import option that matches the content type.

v2rayN is suited to node management and configuration review on desktop systems. On Android, choose v2rayNG based on your core requirements, or consider v2flyNG if you need an existing V2Fly configuration. The three clients may use different menu names and support different fields; do not treat one client's interface steps as universal core requirements. Find download links and platform options on the Client Download Page. For the full process from importing a connection to verifying it, see the Getting Started Guide.

Client and Core Responsibilities
SettingMainly Managed ByWhere to Check
Subscription updates and groupsClientSubscription management interface
System proxy statusClient and operating systemClient toggle and system settings
Virtual network interface interceptionClient connection layerTUN, permissions, and system routes
Outbound and routing fieldsCoreConfiguration actually generated or loaded
DNS server policyCore and client templateDNS interface and runtime configuration

Save a Recoverable State Before Making Changes

Record the current client, operating system, selected core, interception method, and reproducible issue. Save the existing settings or export the necessary configuration, and keep subscription addresses and credentials stored separately as sensitive information. Do not upload diagnostic backups publicly. If you are testing one DNS rule, leave the node and routing unchanged. If you are switching cores, do not also update the subscription or change the transport at the same time. Changing one variable at a time makes failures easier to explain and rollback easier.

When using a custom configuration, check whether the client still adds internal inbounds, statistics settings, or routing rules. Some clients load a complete configuration, while others override only specific fields; their merge behavior differs. The most reliable reference is the runtime configuration passed to the core, not a partial text file in an editor. If an export contains only node information, it is not a snapshot of the entire runtime configuration. Check it against the current mode and global settings too.

Save, Load, and Create a New Connection

  1. Check the JSON syntax and tag references. Confirm that only the intended configuration section has changed.
  2. Save the settings in the client, then use its reload, service restart, or reconnect option.
  3. Check the startup logs to confirm that the new core process loaded successfully and that no listen port is already in use.
  4. Create a new test connection and check that the request reaches the expected inbound and selects the expected outbound.
  5. If the result is wrong, restore the previous configuration and confirm the baseline still works before investigating the difference.

Saving does not necessarily mean the configuration has loaded, and reloading does not necessarily move existing connections to a new outbound immediately. Browsers and other applications may reuse existing connections, and DNS results may come from a cache. To test a routing change, create a new request session; close the application and try again if needed, rather than continuing to use the existing page. Make sure the client logs show events from the test you just ran—otherwise, you may be looking at activity from an older connection.

Windows, macOS, and Linux differ in how applications follow system proxy settings and run in the background, so buttons with the same name may not work the same way. Linux desktop auto-start can also depend on the desktop session and installation method; see the Linux Installation and Auto-Start Notes. On Android, system VPN permission, per-app routing, and background restrictions are part of the connection environment and should be checked separately from JSON routing.

Finally, confirm that you can roll back: keep a working node, the original mode, and the settings from before the change. Do not let diagnostic edits replace your everyday configuration. If a client update stops accepting a field, restore the generated configuration's default template and check core support. Avoid piling old fields into a configuration that is hard to explain. Being able to describe the purpose of every custom field makes future maintenance easier.

Configuration Validation and Troubleshooting

Troubleshoot along the traffic path, one layer at a time: confirm the file loads, verify that the inbound receives a request, check that routing selects the right outbound, then investigate DNS, the handshake, and the destination response. Test one assumption at a time. Changing the node, DNS, routing, and timeout settings all at once may restore a connection by chance without revealing which change helped. Use the same connection method and a stable set of test destinations, and keep the corresponding logs so you can compare the results before and after.

Startup Failures: Read the First Error

When a file fails to load, start with the earliest clear error, not the later messages caused by the shutdown. Bracket or comma problems are JSON syntax errors. An unknown protocol, incorrect field type, or missing required parameter is a configuration error. An address conflict, insufficient permissions, or unreadable file path is an environment issue. These require different fixes. Even if an editor reports valid syntax, have the selected core validate the file; success with a different core is not a substitute.

If an error points to a configuration section, revert its most recent change first. For merged files, check for duplicate top-level keys, arrays accidentally replaced instead of extended, and numbers changed into strings. For a port conflict, check whether multiple client instances are running and stop the older one before trying again. For a permissions issue, identify the resource and operation involved—for example, creating a virtual network interface requires different permissions than listening on a high-numbered local port. Do not run everything with elevated privileges long-term to work around an ordinary configuration mistake.

Starts but Won't Connect: Narrow It Down Section by Section

If no requests reach the inbound, check the application's proxy address, port, type, and whether the system proxy is active. If requests arrive but use the wrong outbound, check rule order, whether the destination is a domain, and the tag references. If the outbound is correct but the connection fails, check DNS resolution, remote reachability, authentication, and transport parameters. If only one destination fails, consider whether the destination service itself is having problems before concluding that the whole configuration is broken. For LAN resources, first check whether a fallback rule sends them through an unsuitable outbound.

Observed ResultNext StepDo Not Change First
Core failed to startSyntax, fields, and listener errorsDomain routing list
Application requests never reach the inboundApplication and system connection settingsRemote protocol authentication parameters
Routing selects the wrong outboundRule order and the destination information actually seenConnection idle timeout
Outbound handshake failsProtocol, transport, and security settingsNumber of local classification rules
Only UDP applications failUDP support across the inbound and connection pathBrowser cache settings

Log level and a minimal reproduction

During diagnosis, temporarily increase the log detail to observe inbounds, routing, and connection errors. Logs may include destination domains, addresses, and usage patterns, so limit what you collect and restore the usual level when finished. Before sharing logs, hide sensitive connection details and include only what is needed to explain the error. Never paste a full subscription or authentication fields into a support request. Most configuration problems can be explained using the field structure, error type, and sanitized destination details.

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

This snippet changes only the log level. The client may manage the actual log location; if no file path is specified, check the client's log viewer. After increasing the level, make one request to the test destination, capture the surrounding events, and restore the previous level. Do not collect all application activity for an extended period to find one error. If the information level does not show which stage failed, use a more detailed level if supported by the core and keep the collection window short.

For a minimal reproduction, start with the direct-connection baseline in the first section of this page. Confirm that the local inbound and ordinary network access work, then restore the real proxy outbound. A successful direct connection does not prove that the proxy path works; it only rules out some local connection issues. Next, restore routing, DNS, and policy in order, reloading and creating a new connection at each step. If direct testing is unsuitable for a service, do not force a different access path; use a test destination you control to verify the same configuration stages.

Frequently Asked Questions and References

Why does the core fail to start even though the JSON parses?

JSON parsing checks only the text structure. The core also validates protocol names, field types, required parameters, and runtime resources. Read the first clear error, then address the relevant configuration section or environment issue such as a port conflict or permissions.

Why does traffic still use the old outbound after I change routing?

Confirm the settings were saved and reloaded, and that the client did not overwrite your custom rules. Then create a new connection, check whether an earlier rule already matched, and see whether the core received a domain or an IP. Existing connections may continue using the old outbound.

Why does an application still use system DNS when I configured dns?

Built-in DNS does not automatically replace resolution for every application. The application may already have an IP before connecting, or it may use its own resolution method. First identify who sent the query and whether the request reached the core as a domain or an IP, then adjust the resolution strategy.

This page is a field reference and troubleshooting guide. For your first setup, follow the Getting Started Guide; for protocol and ecosystem terminology, see the Glossary. After troubleshooting, keep a brief change log: which section you edited, what you observed, whether a reload was needed, and how to roll back. A configuration that is explainable, reproducible, and recoverable is more maintainable than one with a growing stack of parameters.

Download Clients