JSON structure and configuration boundaries
A configuration file describes how the core accepts connections, selects routes, and establishes outbound connections. It does not include every client setting. Window position, subscription groups, update intervals, and system proxy toggles are usually saved by the graphical client; listener ports, protocol parameters, and routing rules belong in the runtime configuration. Keep these layers separate to know whether to change a UI option, a custom template, or a standalone JSON file.
Top-level objects and data types
The outermost JSON structure is an object, and field names and strings use double quotes. Objects use braces; arrays use square brackets. Ports are usually numbers, and Boolean values are lowercase true or false. Do not add a comma after the last member. Avoid curly quotes, comments, and invisible characters introduced when copying from a web page. A format accepted by some tools may not be readable by every core entry point.
Both inbounds and outbounds are arrays: one process can provide multiple entry points and define multiple exits. routing, dns, and policy are objects that manage rules, name resolution, and connection policies. Field names are case-sensitive, and tags must match exactly. Changing the capitalization of outboundTag will not be corrected automatically.
{
"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": {}
},
{
"tag": "block",
"protocol": "blackhole",
"settings": {}
}
]
}
Start with a minimal configuration
This is a complete basic example with a local SOCKS inbound and a direct outbound. Once an application sends a request to the specified local port, the core uses freedom to connect over the current network. The example does not include a remote proxy server or automatically configure a browser or the operating system to use a proxy. Use it to verify that the configuration loads, the port listens, and the application can reach the core—not to test a remote node.
This example has no routing rules, so connections not matched by a rule use the first outbound. The order of the outbound array therefore matters; it is not just for display. When adding a remote outbound, decide on the default route first. Otherwise, adding a single node may change the path for every request that does not match a rule. Write down where unmatched traffic should go before arranging the array and fallback rules.
Complete files, snippets, and client templates
A configuration snippet shows the structure around a specific field, such as a routing object or an outbound entry. When merging it, place it under the matching top-level field rather than concatenating two complete objects. Do not repeat a top-level field: parsers may handle duplicate keys differently, and a file that starts successfully does not mean both sets of rules are active. Prefer combining the content into one clearly defined array or object.
Graphical clients often generate runtime files from the selected server, routing preset, and local ports. Direct edits may be overwritten the next time you switch servers or restart the core. Look for the client’s custom configuration, routing editor, or import options first. Treat a file as a long-term source of configuration only when you know it is managed independently. Avoid having the UI and manual edits compete over the same field.
| Contents | Usually found in | What to check |
|---|---|---|
| Subscription groups, automatic updates | Client settings | Whether updates recreate server entries |
| Inbounds, outbounds, routing | Core runtime configuration | Whether fields and tags match |
| System proxy, background permissions | System and client interaction | Whether application traffic reaches an inbound |
Omitted fields use core defaults, but defaults should not make a configuration hard to understand. Specify security boundaries, default outbounds, and routing DNS policies explicitly; leave complex features unused for now. When consulting examples, confirm which core family they target. V2Fly and Xray share a similar basic structure, but not every extension field is interchangeable. If you encounter an unknown field or startup error, check feature support before investigating network issues.
Keep a working baseline and record the purpose of each change in a separate plain-text note. Do not add explanatory text to strict JSON. Change one related group of fields at a time, then test the corresponding behavior after the configuration loads. This makes it easier to distinguish syntax errors, misplaced structure, and mismatched connection parameters—and gives you a reliable rollback point instead of leaving you with a large untested edit.
Inbound listeners and local ports
An inbound is the entry point through which an application hands a connection to the core. The first things to check are not the remote server, but the local address, port, and proxy protocol the application actually uses. Even with correct remote node settings, a browser pointed at an old port will not use this configuration. Check the application’s proxy settings alongside the inbound listener instead of relying only on the client’s running status.
Listen address and exposure
listen sets the local address to bind to, and port sets the listening port. For local use, prefer 127.0.0.1, the IPv4 loopback address. When an application uses localhost, the system may resolve it to the IPv6 loopback address. If the core listens only on IPv4 while the application tries only IPv6, the connection may fail. For troubleshooting, explicitly use the same loopback address on both sides.
Listening on all interfaces and allowing devices on your local network to connect are not the same as a single toggle. If you broaden the bind address, also consider firewall rules, network exposure, and inbound authentication. Do not expose an unauthenticated proxy to an untrusted network. Before sharing access, define who can use it and where the network boundary lies, then configure authentication and firewall source restrictions. Remote server credentials do not control access to your local inbound.
{
"inbounds": [
{
"tag": "local-socks",
"listen": "127.0.0.1",
"port": 10808,
"protocol": "socks",
"settings": {
"auth": "noauth",
"udp": true
}
},
{
"tag": "local-http",
"listen": "127.0.0.1",
"port": 10809,
"protocol": "http",
"settings": {}
}
]
}
SOCKS and HTTP inbounds
The snippet above defines two inbounds, one SOCKS and one HTTP, on separate ports. An application configured for SOCKS5 should use the first; one configured for an HTTP proxy should use the second. HTTP proxies can carry HTTPS connections using CONNECT, so an HTTPS destination does not mean the proxy inbound itself must use TLS. The proxy protocol and the destination website’s protocol are separate layers.
The udp option on a SOCKS inbound allows SOCKS UDP forwarding, but it does not guarantee UDP support across the entire connection path. The application must support the method, the remote outbound and server must carry UDP, and the network path must allow the relevant packets. An HTTP inbound is not a general-purpose UDP replacement. If web browsing works but a real-time app does not, check that app’s transport separately rather than repeatedly changing the web proxy port.
Inbound tags and sniffing
tag gives an inbound a name that routing rules can reference. For example, if a browser and a test tool use different inbounds, inboundTag can distinguish their traffic. A tag does not create a listener or restrict an application; the address, port, and protocol determine whether an application can connect. Keep tags short and stable. If you rename one, update any routing rules that reference it.
{
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls"]
}
}
The sniffing object belongs inside a specific inbound, at the same level as settings. It attempts to identify domain names from supported protocol handshakes to help with domain-based routing. It cannot read all encrypted content or recover a domain from every connection. For requests made directly to an IP address, sniffing results may affect how the target is handled. Check support in the core you use before relying on options such as using sniffing only for routing.
Port conflicts and the system proxy
If a listener fails to start, first check the address and port in the logs. Another client instance, a system service, or a different local proxy may already be using them. Do not stop after changing one number: update browsers, terminal tools, and other applications that have manual proxy settings. A client-managed system proxy usually follows its settings, but confirm the actual values on the system proxy page.
The system proxy tells applications that honor the setting to connect to a particular inbound; it does not take over every connection on the device. Some applications have their own proxy settings, and others ignore the system proxy entirely. This is separate from whether the inbound can start. If the client offers TUN mode, traffic capture, routing, and permissions involve system-level mechanisms; adding a SOCKS inbound alone cannot provide them. Test first with an application known to support proxies.
A useful inbound test confirms all three: the core starts successfully, the target port is listening, and the application request appears in the relevant logs. Seeing the process running is not enough; the client UI may remain visible even if the configuration failed to load. Check these three points before investigating the outbound to avoid mistaking a local entry-point problem for a remote connection failure. This also gives you a stable baseline for routing traffic by inbound later.
Outbounds and tag relationships
An outbound determines how the core reaches a destination after accepting a connection. It can connect directly, send traffic through a remote proxy server, or discard the connection according to a rule. For each object in outbounds, check the protocol first, then the corresponding settings. Settings are not interchangeable across protocols; changing only the protocol name does not convert an existing configuration to another protocol.
Direct, proxy, and block
freedom establishes a connection directly over the device’s current network; blackhole discards matching traffic. direct, proxy, and block are common tags, not built-in protocols. An outbound tagged direct still uses a remote exit if its protocol points to one. Check both the tag and protocol when reading a configuration; do not infer behavior from an English tag alone.
{
"outbounds": [
{
"tag": "direct",
"protocol": "freedom",
"settings": {}
},
{
"tag": "block",
"protocol": "blackhole",
"settings": {}
}
]
}
This snippet can serve as the outbound section of a basic test configuration. If no rule selects another outbound, the first one usually provides the default route. Clients may arrange the default outbound and fallback rules themselves, so inspect the final runtime file rather than relying only on the server name shown in the UI. Adding an outbound does not send traffic through it automatically; it needs to be selected by the default order or referenced by a routing rule.
Remote outbound parameters
A remote proxy configuration usually includes the server address, port, user credentials, and transport security settings. The address identifies the server to connect to; the port identifies where its service listens; user fields must match the selected protocol. Transport paths, service names, and TLS server names belong to other layers. Pasting all these values into an address field, or putting encoded data from a link directly into a credentials field, breaks the configuration structure.
Subscriptions and share links carry server parameters; they are not complete runtime configurations. After importing a link, the client also generates a file using local ports, DNS, and routing settings. A link being recognized only means its format was readable; it does not prove that credentials are valid, certificates match, or the transport endpoint exists. Use remote parameters from a service you are authorized to access. Do not assemble credentials or paths from unrelated examples.
| Layer | Common parameters | What a mismatch looks like |
|---|---|---|
| Connection target | Server address and port | Resolution failure, connection refused, or timeout |
| Protocol authentication | User ID, password, encryption parameters | Authentication fails or the connection closes after it is established |
| Transport and security | Path, service name, TLS parameters | Handshake failure or unexpected endpoint response |
Multiple outbounds and failover
A configuration can define multiple remote outbounds and reference each from different rules. Give every tag a unique, clear meaning; duplicate names make it hard to tell which outbound a rule selects. When changing a tag manually, check routing and any other features that may reference it. Reordering the outbound list does not create health checks or automatic failover. Without a configured mechanism, the core will not switch routes just because one path is slow.
Some protocols also offer DNS resolution policies, connection reuse, and low-level socket options. Adjust these only after the basic connection works. A resolution policy may affect how a direct outbound resolves a domain, but it does not replace domain handling in the routing object. Connection reuse changes how connections are organized; it does not fix incorrect server credentials. Keep performance tuning separate from availability troubleshooting.
If a remote outbound uses a domain name, that name must be resolved when the core starts. The resolution path must work before the proxy is established; otherwise, you can end up with a loop where the proxy is needed to connect to the proxy. Break the loop using local resolution, a clearly defined bootstrap resolver, or a valid address provided by the service. Repeatedly toggling the client’s system proxy does not solve it.
How configuration and clients work together
On desktop, v2rayN is suited to managing servers and routing templates. On Android, v2rayNG uses the Xray ecosystem, while v2flyNG is an alternative for the V2Fly line. Basic outbound concepts can carry over, but verify core-specific extensions, transport fields, and import behavior separately. Choose a client based on your device and configuration needs. Find installers on the downloads page, and do not enter a client name as a core configuration field.
Before saving remote parameters, check each one against its source: the connection address, port, authentication, transport, and security settings must all belong to the same service configuration. Once connected, confirm that requests actually use the intended outbound; a successful connection test does not mean every destination matches that route. If a local direct test works but the remote outbound fails, narrow the investigation to server resolution, the handshake, and authentication. Leave the inbound unchanged for now.
Routing match order and rules
Routing connects inbounds to outbounds. It checks the target domain, IP address, port, or inbound tag, then selects a defined outbound. Rules are generally evaluated from top to bottom, and the first match determines the route. Put specific exceptions first and broad rules later—a more reliable principle than memorizing a preset. Connections that match no rule fall back to the default outbound; the core does not automatically decide based on the destination’s region.
Choose the destination, then define the conditions
outboundTag must exactly match an outbound’s tag. Referencing a name that does not exist will not create an outbound; it may cause configuration validation or forwarding to fail. When a rule has type set to field, its condition fields define what it matches. Confirm that the outbound exists before adding rules one at a time. Otherwise, it is hard to tell whether a condition failed to match or the selected outbound could not be found.
{
"routing": {
"domainStrategy": "AsIs",
"rules": [
{
"type": "field",
"domain": ["full:blocked.example"],
"outboundTag": "block"
},
{
"type": "field",
"ip": ["geoip:private"],
"outboundTag": "direct"
},
{
"type": "field",
"domain": ["geosite:cn"],
"outboundTag": "direct"
}
]
}
}
This routing snippet can be used with the direct and block outbounds described above. blocked.example is a reserved example domain that demonstrates exact-match syntax; replace it with a test domain you are authorized to manage. geosite and geoip rely on external rule data, which must be available in the runtime environment. If the data files are missing, do not mistake the resulting load error for a network problem.
Logic within and across fields
Multiple entries in the same domain array usually mean that any one match is sufficient. Conditions across different fields in one rule—such as domain, port, and network type—must all match. To send “this domain or this IP” through the same outbound, use two rules rather than putting both in one and expecting OR logic. Map out the condition relationships before writing JSON to avoid rules that look complete but never match.
full: matches an exact domain, domain: matches a domain and its subdomains, and regexp: uses a regular expression. A string without a prefix may match more broadly than expected, so avoid it for narrowly scoped exceptions. Rules match hostnames, not full URLs. Do not include https://, paths, or query parameters in domain conditions; routing does not match the entire address-bar URL.
Domain strategies and IP rules
AsIs does not resolve a domain solely to evaluate an IP routing condition. If an application passes a domain to the core, an IP-only rule may not behave as expected. IPIfNonMatch attempts resolution when no domain rule matches, then continues matching; IPOnDemand triggers resolution when a rule requires an IP. These options provide more opportunities to resolve domains and can change the practical effect of rule order.
A lookup can return multiple addresses, and a service’s addresses can change. An IP rule matching a result does not mean that address will always belong to the same domain; shared infrastructure may also put multiple services on the same address range. Prefer domain conditions when they express your intent reliably. Use IP conditions when you need to control local subnets or fixed service addresses. Categories in a data set are not definitive proof of a certificate or service’s ownership.
{
"type": "field",
"inboundTag": ["local-socks"],
"network": "tcp",
"port": "443",
"outboundTag": "direct"
}
This standalone rule sends connections from the specified SOCKS inbound to port 443 over TCP through the direct outbound. All three conditions must match; it does not globally allow that port. The port is the destination port, not the local listening port. If you place the rule near the top of the array, check whether it will override a later domain block. The broader the rule, the more carefully you should consider its position.
Default outbound and verification
To define an explicit fallback, add a rule at the end that covers TCP and UDP and points to an already defined default outbound. Later rules of the same kind will generally have no effect, so put the fallback last. If the first outbound is the default, note that in your configuration notes to avoid unexpected changes when someone reorders the list. Do not confuse a client’s “global proxy” mode with system-wide traffic capture; the former primarily describes routing behavior.
If a rule does not work, check in order whether the application passed a domain or an IP address, whether an earlier rule intercepted the request, whether the tags match, and whether the data files load. Reload the relevant configuration in the core after making changes; existing long-lived connections may continue on their original route. Close old connections and start new requests to avoid mistaking connection reuse for a rule that did not update.
How DNS and routing work together
DNS maps domain names to addresses, but more than one layer can perform the lookup in a proxy setup. An application may resolve the name before handing off the request; the core may resolve it for routing or a direct outbound; or the remote server may resolve the final destination. Adding a dns object only configures the core’s resolver. It does not mean every domain lookup on the device passes through it. First identify which layer performs the lookup, then choose where to make changes.
Basic structure of core DNS
servers specifies the resolvers the core can use, while hosts provides static mappings for specific domains. The example below shows a loopback domain mapping and a sample resolver address. It does not include an inbound that intercepts system DNS or change the application’s own resolver settings. When changing resolvers, confirm that the current network allows access and that the choice meets your environment’s requirements; do not use an address merely because it looks familiar.
{
"dns": {
"hosts": {
"loopback.example": "127.0.0.1"
},
"servers": [
"1.1.1.1"
]
}
}
This static mapping is useful for testing the core’s DNS flow; it does not modify the operating system’s hosts file. It affects only requests that use the core’s DNS. Addresses obtained directly by a browser or through another resolver are not rewritten by it. Static mappings also need maintenance in production: an old address may stop working after a service moves. Do not use a fixed IP indefinitely in place of a dynamic service domain unless the provider explicitly supports that setup.
Split DNS and fallback
In cores that support the relevant fields, a server object can use domains to prioritize domain matches and expectIPs to check the range of returned addresses. These fields do different jobs: the first filters queries; the second checks answers. Neither is a routing rule. Even after DNS selects a resolver, the outbound and routing rules determine the path of the actual connection. A resolver group does not mean the connection has already been routed.
{
"dns": {
"servers": [
{
"address": "223.5.5.5",
"domains": ["geosite:cn"],
"expectIPs": ["geoip:cn"]
},
"1.1.1.1"
]
}
}
This example depends on an available rule data set and shows how a preferred resolver can coexist with a general-purpose one. Exact fallback behavior also depends on the fallback options supported by the core; array order alone does not mean requests always go through a sequential primary-and-backup queue. If a type of query must never fall back to another server, check the fallback controls for your version instead of simply removing or changing an address. Test both matching and non-matching domains after configuration.
The path taken by DNS traffic
Ordinary UDP resolution, DNS over HTTPS, and resolution using the local network stack can take different outbound paths. Some address formats are forwarded internally by the core; some local modes bypass the usual routing flow. Follow the actual core documentation for resolver URL syntax. Adding a prefix to a regular address does not guarantee that it will go through a proxy. In particular, check how the resolver’s hostname is resolved before an encrypted connection can be made.
A remote outbound domain and a remote resolver domain can depend on each other, creating a common startup loop. You may see the first connection fail, a long wait after switching networks, or normal behavior with cached results followed by failure after a restart. Provide a bootstrap resolution path that works before the proxy connection is established, and specify which essential domains it handles. Do not route every resolver and outbound through the same connection before that connection exists just to eliminate one timeout.
IPv4, IPv6, and cache differences
Getting an IPv6 address from DNS does not mean the device has a working IPv6 route to the destination. Similarly, disabling IPv6 is not a universal fix for timeouts. Check the address family support of the local network, remote service, and outbound before restricting DNS results. Query strategy fields vary across core families. Configure only fields supported by the core you use rather than setting an unrecognized field as a network policy.
Application, system, core, and recursive resolver caches may all be involved. If a page still behaves the same after a DNS change, that does not immediately prove the configuration failed. Recreate the application connection first, then clear the relevant cache if needed and observe a fresh query. Use a controlled domain or record query times during testing; a large website’s changing address is not a reliable way to tell whether the resolver switched.
If a page is slow but the logs show no clear DNS error, compare the first visit with subsequent visits. A slow first visit may involve resolution or handshaking; slow ongoing downloads are more likely related to the route, load, or local processing. Follow the layered guide to diagnosing slow speeds for further checks. Avoid changing DNS, nodes, and routing at the same time, or you will not know which change helped.
Policies, logs, and statistics
policy controls connection behavior and statistics; it is not another domain-routing table. It can set handshake timeouts and idle timeouts by user level, and control system-wide traffic statistics. Routing determines where a connection goes; policy determines how it is managed. Confusing the two can lead to repeatedly changing timeouts without addressing the actual cause of a routing problem.
Levels and timeout settings
The keys in levels are level numbers represented as strings. Protocol users that support this mechanism are associated with a level. If an inbound has no explicit user, or its protocol does not use levels, do not assume that any level setting will affect it. Start by confirming the default level, then observe connection behavior. A level number is not a priority or bandwidth tier; it does not automatically route a group of traffic through a faster outbound.
{
"policy": {
"levels": {
"0": {
"handshake": 4,
"connIdle": 300,
"uplinkOnly": 2,
"downlinkOnly": 5
}
},
"system": {
"statsInboundUplink": true,
"statsInboundDownlink": true,
"statsOutboundUplink": true,
"statsOutboundDownlink": true
}
},
"stats": {}
}
The duration fields here are in seconds. This example shows the structure, not a tuning recipe for every network. handshake limits the handshake wait; connIdle limits how long a connection can remain idle. The other two fields control how long one side waits after it has finished sending for the other side to finish. A timeout may be expected when a connection has no application data for a long time. Increasing values indefinitely only delays cleanup; it cannot restore a failed network path.
For long-lived connections, first check whether the application sends heartbeats, whether the server permits persistent connections, and whether network equipment reclaims idle sessions. Changing the core’s idle timeout cannot override limits imposed by intermediate devices. Conversely, making it too short may cause healthy, low-frequency requests to reconnect unnecessarily. Record the time between disconnects and check the logs before deciding which layer closed the connection. Do not attribute every disconnect to battery use or background restrictions.
Statistics settings are not a statistics interface
The example includes both a statistics object and a system statistics switch, but these do not automatically create a chart or management page. Reading statistics also requires a suitable interface and client support. Some counters depend on inbound and outbound tags or user IDs. If the numbers in the UI do not update, first confirm that the client is reading statistics from this core rather than adding more routing fields. Statistics show traffic volume; they do not explain why a remote request failed.
If you configure a management interface yourself, restrict its listener to a trusted local address and understand its routing and permission boundaries. Do not bind an administrative endpoint to every network interface just to make it easier for a tool to access. Most desktop users should use the statistics features already provided by their client. Keep standalone configuration limited to what you actually need to reduce unnecessary listeners and maintenance.
Log levels and troubleshooting
{
"log": {
"loglevel": "info"
}
}
This log snippet is for temporarily observing connections. Use a moderate level in everyday use, raise the detail briefly while troubleshooting, then restore it after reproducing the issue. Access logs, error logs, and log verbosity are separate settings. If no file path is specified, check how the client captures core output. To write logs to a file, choose a writable directory and manage its size; the application directory is not necessarily writable on every platform.
Follow logs in chronological order: did the configuration load, did the inbound start listening, did the request arrive, which outbound was selected, and at what stage did it end? A single timeout line is rarely enough to pinpoint the problem; an earlier DNS or handshake failure may be the root cause. Before sharing logs, remove server credentials, subscription URLs, and personal destinations. Keep only the error type, the stage where it occurred, and any necessary anonymized tags.
How to verify policy changes
Connection reuse, caching, and existing connections can delay the effect of a policy change. After changing a timeout, existing application connections may not immediately adopt the new behavior, so reconnect before testing. Keep the destination and steps consistent, and record idle time and reconnect behavior. Do not mistake a change in server load for a policy improvement. Keep a setting long term only if the difference is reproducible.
Background operation and battery optimization on Android are also affected by system scheduling; increasing connIdle alone will not fix them. If the system stops v2rayNG, its core configuration cannot keep running. Check the app’s battery permissions and operating mode first. For details, see the guide to v2rayNG battery drain and background operation. Test the system and core layers separately rather than trading extra battery use for a longer timeout that makes no difference.
Transport parameters and the TLS security layer
The same proxy protocol can run over different transports, and a transport can carry different protocols. To understand a configuration, separate it into three layers: proxy protocol, transport, and security. The protocol handles user authentication and request semantics; the transport carries bytes to the server; the security layer encrypts and authenticates the relevant connection. Getting one layer right does not configure the others automatically.
Where streamSettings belongs
streamSettings usually belongs inside a specific outbound object, at the same level as protocol and settings. It does not go inside a protocol’s user object or belong arbitrarily at the top level. The example below shows only a WebSocket and TLS transport snippet; combine it with the actual outbound parameters supplied by your service. The domain is reserved for examples, and the path demonstrates syntax only—it does not identify a working remote service.
{
"streamSettings": {
"network": "ws",
"security": "tls",
"tlsSettings": {
"serverName": "gateway.example",
"allowInsecure": false
},
"wsSettings": {
"path": "/transport",
"headers": {
"Host": "gateway.example"
}
}
}
}
The server address used for the connection is not in this snippet; it comes from the outbound protocol’s server settings. serverName is used for the TLS server name and certificate verification. WebSocket Host selects the application-layer host. These values may be the same in some deployments, but in others they have distinct purposes. Do not swap them just because both look like domain names; follow the server configuration.
Paths, hosts, and certificates
The WebSocket path must match the endpoint accepted by the server. Its leading slash, capitalization, and any additional content can affect matching. An incorrect path may still return a normal web page or another HTTP response, even though the proxy handshake never succeeded. Being able to open the server’s home page does not confirm that the transport endpoint is configured correctly. Check the upgrade handshake and core errors rather than only testing whether the domain opens in a browser.
If certificate verification fails, check the device clock, the domain covered by the certificate, the trust chain, and which service you actually reached. Setting allowInsecure to disable verification changes the security boundary and should not be a permanent certificate fix. When connecting by IP to a service whose certificate is issued to a domain, configure the correct server name. Certificate validation and proxy user authentication are separate mechanisms; changing a user ID cannot fix a domain mismatch.
Do not reuse transport fields across types
Switching transports means more than changing the network field. WebSocket paths, gRPC service names, and other transport parameters belong to different settings objects and must match the server configuration. Unused fields may be ignored or may cause loading or handshake errors. Keep only the settings for the transport you actually use, and match each parameter to the server’s configuration instead of mixing details from multiple share links.
Basic TCP, WebSocket, and gRPC differ in resource use, connection management, and deployment requirements, but no transport is universally fastest regardless of the server. If the server does not provide the endpoint for the transport selected in the client, the connection cannot be established. When tuning, keep the working transport unchanged and compare behavior on the same network. A transport’s name alone does not guarantee speed.
| Field or concept | Primary purpose | Where to verify |
|---|---|---|
| Server address | Identifies the actual connection destination | Outbound server settings |
| TLS serverName | Server name and certificate match | Security layer settings |
| WebSocket Host and path | Selects the application-layer endpoint | Server transport configuration |
| gRPC serviceName | Selects the corresponding service | Service name agreed by both sides |
Core families and extensions
V2Fly and Xray are related proxy core ecosystems, but their capabilities evolve separately. Use a core that supports proprietary security features such as REALITY, and configure them according to that core’s field specifications. Do not simply substitute the feature name into the TLS example in this section. Similar-looking JSON does not guarantee compatible parameters. After importing a share link, confirm that the client’s selected core meets the node’s requirements.
Connection reuse also depends on the protocol and server configuration. It may reduce the cost of some new connections, but can behave differently on particular routes or with certain applications. If a single long-lived connection has issues, return to a baseline without additional connection reuse and compare while keeping other parameters the same. Do not change reuse, transport, TLS, and DNS all at once; too many variables make a one-off success hard to reproduce.
If the local inbound works and the server port is reachable but logs stop at the TLS or transport handshake, pause changes to routing and policy. Check that the system time, server name, path, service name, and authentication all come from the same configuration, then inspect the endpoint mapping on any intermediate reverse proxy. Layered troubleshooting usually preserves more useful clues than repeatedly importing a subscription, and avoids overwriting working rules.
Merging, testing, and rolling back configuration
Good configuration maintenance is not about collecting more fields at once; it is about making every change explainable, testable, and reversible. Before you start, confirm the client, the core actually running, the configuration source, and the default outbound. Save a working baseline. It should include both the JSON and the client’s current mode and system proxy state. Saving only the file and forgetting external toggles can produce a different result when you restore it.
Merge snippets in dependency order
Start with an inbound and direct outbound that can run, add a remote outbound, then add a route for a single destination, and finally adjust DNS and policy. This order is not a functional limitation; it follows the troubleshooting dependencies. You cannot verify an outbound if the inbound does not work, rules cannot be tested if their outbound does not exist, and timeout tuning is pointless if the basic connection fails. Save a record after each successful step to create clear rollback points.
When merging arrays, add entries; when merging objects, check each key. Do not simply paste snippets onto the end of the file. Pay particular attention to duplicate routing, dns, and log fields, as well as tags defined more than once. If a template tool generates some fields automatically, determine whether it replaces the whole object or appends to an array. Understanding how it merges matters more than seeing that all the content is present.
Checks before and after startup
First use a local editor or JSON validator to check syntax, then have the core that will actually run check the configuration structure. Valid JSON does not guarantee that the fields are supported, and successful loading does not mean the remote server is reachable. Interpret errors by layer: for a parse error, check quotes and commas; for an unknown field, check core support; for a listener failure, check the local port; for a handshake failure, check remote parameters. Do not let network testing distract from a file that has not loaded successfully.
| Stage | Test | Check first if it fails |
|---|---|---|
| Configuration loading | Check core startup output | JSON structure, supported fields, data files |
| Local connection | Explicitly configure the application to use the local proxy | Listen address, port, inbound protocol |
| Remote connection | Use a fixed test destination | Resolution, authentication, transport, security layer |
| Rule-based routing | Check which outbound handled the request | Match conditions, rule order, tags |
Specify the proxy explicitly in your test tool to avoid confusion about system proxy settings. The request below checks whether a local SOCKS inbound can handle an HTTPS destination; socks5h passes domain resolution to the SOCKS side. Results still depend on the selected outbound and network. This is not a latency score and does not prove that every application is using the proxy. On Windows, using the explicit program name avoids differences caused by aliases in the terminal environment.
curl.exe --proxy socks5h://127.0.0.1:10808 --head https://example.com
curl --proxy http://127.0.0.1:10809 --head https://example.com
Client regeneration and subscription updates
In v2rayN, switching servers, changing a routing preset, or restarting the core may regenerate the runtime configuration. If manual changes disappear, look for a persistent settings option instead of continuing to edit temporary output. Use the v2rayN first-install settings checklist to check the install location, write permissions, and startup settings. For the basic connection steps, return to the getting started guide.
Subscription updates may also change server entries, node names, and available parameters. If custom rules depend on an entry name that often changes, check how the client maps it to the runtime tag; do not assume the displayed name always matches the outbound tag. See how to organize and filter subscription groups for managing multiple sources. Compare the configuration before and after an update; that is more useful than simply noting that something stopped working.
Frequently asked questions and recovery
The configuration starts, so why is the application still connecting directly?
First check whether the application follows the system proxy or explicitly uses the current inbound. Then check the default outbound and which routing rule matched. A running core process proves only that the program started—not that the application’s requests pass through it.
Why do existing connections keep using the old route after I change a rule?
Established connections generally do not move automatically when rules change. Close the application’s existing connections and start a new request, then check the new connection logs. If needed, reload the core configuration and make sure the client has not overwritten your changes.
What should I restore first if the connection suddenly fails?
Restore the last working core configuration and client mode, then test just one inbound and one destination. Keep the failure logs and reapply changes one at a time. If the baseline also fails, check the network, server status, and whether subscription parameters have changed.
A useful verification record answers four questions: which inbound received the request, whether the destination was a domain or an IP, which rule matched, and which outbound established the connection. “It works” does not prove that routing is correct, and “timeout” alone does not identify the failing layer. Record one successful and one failed request along this path to narrow the issue to a few fields instead of rewriting the entire configuration.
When maintenance is complete, restore a suitable log level, remove test inbounds and temporary static mappings you no longer need, and save the long-term configuration in a location supported by the client. A concise, understandable ruleset is easier to maintain than a stack of presets. For connection instructions, use the tutorial; to understand fields, dependencies, or merging, return to the relevant section using this page’s contents.