At a glance

For readers who have imported a subscription but find the config file hard to follow. A complete example with a local inbound, direct connection, and blocking rule traces the request flow, then explains ports, outbound tags, rule order, and DNS behavior. It contains no remote proxy server and cannot replace a subscription. By the end, you’ll know whether to change a client setting or inspect the core config.

1. The five main sections of config.json

config.json is the config file read by the core. It is not a subscription link or the client’s complete settings. v2rayN manages nodes, subscription groups, and interface options, then converts your selections into a config the core can run. The same filename does not mean every field is interchangeable between V2Ray and Xray.

App request Local inbound Route match Selected outbound Destination

You don’t have to read the file from top to bottom. Start with inbounds to see where requests enter, then check how routing selects a path, and finally use outbounds to identify the actual exit. log helps with troubleshooting, while dns defines name resolution settings the core may use.

Top-level fieldWhat it doesWhat to check first
logSets the log level and output locationWhether the current log level records the error
inboundsAccepts connections from browsers and other appsListen address, port, and inbound protocol
outboundsDefines direct, blocked, or remote proxy connectionsProtocol, tag, and server settings
routingRoutes connections to an outbound based on rulesRule order and destination tag
dnsConfigures the built-in DNS resolverResolver address and when it is actually used

2. Complete example: local inbounds, direct connections, and domain blocking

This example uses traditional JSON fields found in V2Ray and Xray, making it easier to follow. It provides two inbounds accessible only from the local machine: SOCKS on port 10808 and HTTP on port 10809. Connections to example.org and its subdomains are blocked; all other connections through these inbounds go direct.

{
  "log": {
    "loglevel": "warning"
  },
  "inbounds": [
    {
      "tag": "local-socks",
      "listen": "127.0.0.1",
      "port": 10808,
      "protocol": "socks",
      "settings": {
        "auth": "noauth",
        "udp": false
      }
    },
    {
      "tag": "local-http",
      "listen": "127.0.0.1",
      "port": 10809,
      "protocol": "http",
      "settings": {}
    }
  ],
  "outbounds": [
    {
      "tag": "direct",
      "protocol": "freedom",
      "settings": {}
    },
    {
      "tag": "block",
      "protocol": "blackhole",
      "settings": {}
    }
  ],
  "routing": {
    "domainStrategy": "AsIs",
    "rules": [
      {
        "type": "field",
        "domain": [
          "domain:example.org"
        ],
        "outboundTag": "block"
      },
      {
        "type": "field",
        "inboundTag": [
          "local-socks",
          "local-http"
        ],
        "outboundTag": "direct"
      }
    ]
  },
  "dns": {
    "servers": [
      "1.1.1.1"
    ]
  }
}
10808
Example SOCKS inbound port
10809
Example HTTP inbound port
2
Routing rules evaluated in order

These ports are explicitly set in the example; they are not defaults for every client version. JSON objects use braces and arrays use square brackets. Keys and strings must use double quotes, and the last item must not have a trailing comma. Comments are omitted for compatibility across cores.

3. inbounds: listen address, port, and protocol

inbounds is an array, so a core can provide multiple local entry points. listen selects the network interface, port tells apps which port to connect to, and protocol specifies the proxy protocol an app should use. Check all three together; don’t rely on the port number alone.

Local SOCKS inbound

tag
local-socks
listen
127.0.0.1
port
10808
protocol
socks
udp
false

Configure the app to use a SOCKS proxy. This example does not accept SOCKS UDP relay traffic.

Local HTTP inbound

tag
local-http
listen
127.0.0.1
port
10809
protocol
http
settings
{}, using default settings

Configure the app to use an HTTP proxy. HTTPS destinations typically use CONNECT to establish a tunnel.

127.0.0.1 allows connections only from the local machine. Changing it to 0.0.0.0 listens on all IPv4 interfaces, potentially exposing the inbound to other devices on your local network. The example SOCKS inbound uses noauth, so don’t widen its listen scope just to troubleshoot.

In v2rayN, look under Settings → Parameter Settings for local listening port options. Then, from the main window’s System Proxy menu, select Auto-configure system proxy. Menu locations may vary by version; use the labels and ports shown in your current interface.

4. outbounds: protocols and their tag mappings

outbounds is also an array, but it describes how requests leave the core. In this example, freedom connects directly to the destination, while blackhole blocks the connection. direct and block are custom tags, not protocol names.

Field or protocolRole in this exampleWhat to watch when editing
tagLets routing rules refer to an outboundIf you rename it, update every reference and match the capitalization
freedomConnects directly to the destinationIt is not a remote proxy and does not provide a proxy server
blackholeTerminates matching connectionsIt is not a fallback outbound and won’t switch nodes automatically
settingsCarries the settings for the selected protocolProtocol settings are not interchangeable

A working proxy outbound also needs a server address, port, user ID, and transport and security settings that match the server. VMess and VLESS use different user parameters, while TLS, REALITY, and WebSocket each have their own fields and requirements. Changing "protocol": "freedom" to "vless" does not complete the configuration.

Bottom line: check the tag, then verify the server settings

If a route points to proxy, first confirm that the outbound array contains "tag": "proxy". Once the tag reference is correct, check the node settings. Otherwise, even complete server details won’t send requests to the intended outbound.

Connections that match no rule usually use the first outbound in the array. This is not automatic failover. The example puts direct first and uses a second rule to explicitly handle both local inbounds, making the match behavior easier to follow.

5. routing: rule order and domain matching

Common field rules are checked in array order. Once a rule matches, its outbound is selected; the core won’t keep looking for a “more specific” rule. This example blocks the specified domain first, then sends other traffic from the two inbounds direct. Swap the rules and the inbound rule will match first, preventing the domain block from taking effect.

  1. Receive the destination: The app passes a domain or IP address through the inbound, and the core uses it to make a routing decision.
  2. Check the first rule: domain:example.org matches the domain and its subdomains. Matching connections use block.
  3. Check the second rule: If the first rule doesn’t match, connections from local-socks or local-http use direct.
  4. Handle unmatched connections: If other inbounds exist and no rule matches, the default outbound behavior applies.

Different conditions in the same rule usually all need to match. Multiple values in an array for one condition usually mean any one of them can match. For example, putting both inboundTag and domain in one rule means “from one of these inbounds and the destination domain matches,” not that either condition alone is enough.

SyntaxWhat it matchesHow to read it
domain:example.orgThe domain itself and its subdomainsUseful for matching an entire domain namespace
full:example.orgAn exact match for the full domainDoes not include all subdomains
inboundTagMatches the inbound tag on the connectionNot a server name or subscription group name
outboundTagSets the outbound tag to use on a matchMust match an existing outbound

The example does not configure traffic sniffing. If an app resolves a domain to an IP address and passes only the IP to the core, a domain rule may not match. Check first whether the app is passing the domain through the proxy; don’t immediately broaden the blocking rule. Domain routing also can’t match URL paths: for example, /account is not a domain condition.

6. dns: resolver settings don’t take over system DNS

dns.servers defines the servers used by the built-in DNS resolver. In this example, 1.1.1.1 is an explicitly configured resolver address. Adding it does not change system DNS or guarantee that a browser’s encrypted DNS will use it. Whether the built-in resolver is queried depends on routing policy, outbound settings, and the type of request.

These values belong to routing.domainStrategy; don’t confuse them with an outbound’s own domainStrategy. Routing decides which outbound to use, while an outbound’s resolution strategy affects how it connects to the destination. The names are similar, but they apply at different stages.

If a config uses geoip: or geosite: conditions, check that the required data files are available in the runtime environment. This example omits those conditions so missing data files don’t get confused with JSON structure problems.

7. log and safe changes: change one variable at a time

The example sets loglevel to warning, which captures warnings and errors but may not show routing details for every connection. Temporarily switch to info to investigate a problem; more verbose debug logging is best for brief diagnostic sessions. Logs may contain destination domains and addresses, so remove sensitive details before sharing them.

  1. Identify the config source: First determine whether this is a runtime file generated by the client or a separately managed custom config. Don’t edit similarly named files in the installation directory without checking.
  2. Save the current state: Note the selected node, system proxy status, and listening ports. Keep a copy of the original config so you can roll back.
  3. Use the UI first: Change local ports under Settings → Parameter Settings in v2rayN. Check routing rules under Settings → Routing Settings. Names may vary by version.
  4. Change one setting at a time: Change the port and verify the inbound first, then adjust rule order. Don’t change DNS, transport settings, and outbound tags all at once.
  5. Check the first error after reloading: Fix JSON parsing, port binding, or tag reference errors before checking network reachability.
  6. Restore the usual log level: When troubleshooting is complete, switch back to a suitable level to avoid keeping excessive connection details in the logs.

Bottom line: change client-generated configs at their source

If a manually edited config.json reverts after you switch nodes, change the relevant client setting instead. Edit the full JSON directly only if you’ve confirmed that you’re using a custom config and understand how it is loaded.

v2rayN is a desktop client. On Android, v2rayNG uses the Xray core, while v2flyNG uses the V2Fly core. Their import workflows and supported fields differ. Successfully importing a subscription only means the client parsed it; it does not guarantee that every protocol combination is supported by the core currently in use.

8. Troubleshooting config errors and pages that won’t load

Break the problem into four layers: “Did the config load?”, “Is the app using the proxy?”, “Did routing choose the right outbound?”, and “Can the outbound connect?” This is usually more useful than repeatedly importing the subscription. The symptoms below can help narrow things down, but a single log line is not enough to conclude that the server is at fault.

SymptomCheck firstNext step
Core exits immediately on startupBrackets, commas, field types, and the first startup errorUndo the most recent change and compare the config before and after
Address already in useWhether another process is listening on 10808 or 10809Close duplicate instances, or change the port in the client and update the app settings to match
Outbound not foundWhether outboundTag exactly matches the outbound tagFix the reference, checking for capitalization or spelling differences
Domain block isn’t workingRule order, inbound tag, and whether the destination is still a domainVerify the match conditions first; don’t switch straight to blocking everything
Config loads, but pages time outApp proxy type, current outbound, destination resolution, and connection errorsTest the inbound and outbound separately to distinguish a direct connection failure from a remote proxy failure

Keep three distinctions in mind: the inbound port is not the remote server port; an outbound tag is not a protocol name; and DNS settings do not take over system traffic. Once these are clear, it’s easier to read real node configs and understand where complex transport settings belong.