For users familiar with subscriptions who are ready to explore core configuration. Start with a SOCKS inbound that listens only on localhost, then verify the config with direct and blocked outbounds before looking at tag references, rule order, and DNS boundaries. This example has no remote proxy node. After testing, add the server-provided protocol settings to an outbound so JSON syntax, node connectivity, and routing issues stay easy to distinguish.
1. Save a Standalone Test config.json
This example uses the traditional V2Ray JSON config format supported by V2Fly cores. Run v2ray version to identify the program in use, then check v2ray help. V2Fly and Xray share some fields, but their extensions and command-line options are not identical. Don't assume a config for one core is universally compatible.
Save the following as UTF-8-encoded config.json. It exposes a SOCKS endpoint at 127.0.0.1:10808, blocks connections to example.org and its subdomains, and sends all other requests direct by default. “Working” here means the inbound, routing, and outbound paths run—not that a remote proxy is available.
{
"log": {
"loglevel": "warning"
},
"inbounds": [
{
"tag": "socks-local",
"listen": "127.0.0.1",
"port": 10808,
"protocol": "socks",
"settings": {
"auth": "noauth",
"udp": false
}
}
],
"outbounds": [
{
"tag": "direct",
"protocol": "freedom",
"settings": {}
},
{
"tag": "blocked",
"protocol": "blackhole",
"settings": {}
}
],
"routing": {
"domainStrategy": "AsIs",
"rules": [
{
"type": "field",
"inboundTag": ["socks-local"],
"domain": ["domain:example.org"],
"outboundTag": "blocked"
}
]
},
"dns": {
"servers": [
"1.1.1.1",
"8.8.8.8"
]
}
}
- Objects use braces and arrays use square brackets. Even with a single entry,
inboundsandoutboundsmust remain arrays. - Use double quotes around keys and strings. Numbers such as
10808and booleans such asfalseare unquoted. - Don't add a comma after the last property. This example avoids comments and trailing commas for easier validation across tools.
- The order of top-level fields doesn't determine request flow. Order matters for the routing rules array and for which outbound is first by default.
2. log: Know Where to Find Errors
log controls logging; it doesn't handle proxying or routing. This example sets only loglevel, with no log file path. When launching from a terminal, watch the process output. When running as a service, check that service's logs instead of looking for a default log file in an arbitrary directory.
| Field or value | Purpose | When to use it |
|---|---|---|
loglevel: warning | Keep higher-severity messages, such as warnings and errors | For everyday use; routine connections may not generate log entries |
loglevel: info | Show more runtime details | For a quick look at connection and config behavior |
loglevel: debug | Provide more detailed diagnostic information | Reproduce the issue, then restore the previous log level |
access / error | Set separate paths for access and error logs | If using file paths, make sure the directory exists and the process can write to it |
If startup fails, start with the first clear error. Parse errors usually point to a field or location; address already in use means the listening port is occupied; permission errors call for checking the config file and log directory. Changing the node address won't fix a local port conflict.
3. inbounds: Apps Connect to a Local Endpoint
inbounds defines how the core accepts requests. In this example, protocol: socks is the SOCKS protocol between an app and the local core—not the protocol used by a remote server. Configure your browser or terminal to use this endpoint explicitly. Starting the process alone won't change system proxy settings or capture traffic from every app.
Local SOCKS inbound
- Tag
socks-local- Listen address
127.0.0.1- Listen port
10808- Protocol
socks
Accepts local connections only. Make sure the test app uses a SOCKS proxy, not an HTTP proxy.
Default direct outbound
- Tag
direct- Protocol
freedom- Protocol settings
{}- Array position
- First entry
Used when no rule matches. Connects directly to the destination without a remote proxy server.
listen controls who can access the endpoint; port sets its port number. The loopback address used here prevents other devices on your LAN from connecting via your computer's local network address. Don't switch to 0.0.0.0 to troubleshoot and leave authentication disabled—that would expose the listener more widely.
With settings.auth set to noauth, the local SOCKS proxy requires no username or password. udp: false means this example doesn't enable SOCKS UDP forwarding. This guide tests TCP requests only, so it doesn't establish whether games, voice calls, or other UDP apps will work.
4. outbounds: Separate Protocol Settings from Outbound Tags
outbounds defines how requests leave the core. In this example, freedom connects directly, while blackhole rejects or discards requests. Neither is a remote node, so neither needs a server address, user ID, or transport security settings.
- Start with protocol. It determines which protocol fields are valid in
settings. Don't copy authentication fields from a SOCKS inbound into a VMess outbound. - Next, check settings. This section holds connection parameters for the selected protocol. When adding a real proxy node, use the server's details and documentation for your core version rather than guessing default values.
- Then check tag. This is the name used to reference an outbound in the config. In this example,
directandblockedare custom tags, not reserved protocol names. - Check streamSettings. When needed, configure transport and transport security settings in the outbound object. These are sibling fields of the protocol's
settings, not fields to nest arbitrarily.
VMess and VLESS are different proxy protocols; changing only protocol won't convert one into the other. For VLESS, check your core version and its supported features. In particular, don't copy Xray-specific transport extensions into a V2Fly config just because the fields look similar.
Takeaway: Keep a Direct Baseline, Then Add a Real Node
First, verify that the 10808 endpoint works with a direct connection. Then add a proxy outbound and route a rule to it. If the new setup fails, you can focus on the protocol and server settings without questioning the inbound config at the same time.
5. routing: Route Requests to Outbounds in Rule Order
Once a request enters the core, the routing module selects an outbound based on conditions such as the destination domain, destination IP, port, and inbound tag. The flow in this example is shown below. It doesn't use a virtual network adapter or automatically configure the system proxy.
The rule in this example requires both the socks-local inbound tag and a destination matching domain:example.org, then sends the request to blocked. Both conditions in this rule must match. If the domain array lists multiple domains, matching any one of them satisfies the domain condition.
| Config item | Reference or meaning | Common mistake |
|---|---|---|
inboundTag | Matches the inbound object's tag | Using the protocol name socks as the inbound tag |
outboundTag | References the outbound object's tag | Using a tag that doesn't exist or has different capitalization |
domain:example.org | Matches the domain and its subdomains | Assuming it matches only the exact hostname |
full:example.org | Matches only the exact domain | Expecting it to match all subdomains too |
rules array | Checked from top to bottom; the first matching rule selects an outbound | Putting broad rules before more specific ones |
If no rule matches, the first entry in outbounds is used by default. The first entry here is direct, so ordinary requests connect directly. Moving a proxy outbound to the first position also changes how unmatched requests are handled. If every site seems to use the same route, check the first array entry as well as the rules.
domainStrategy: AsIs means routing matches against the target information already available, without resolving domain names just to match IP rules. If an app sends an IP address to SOCKS, this domain rule alone can't recover the original hostname. This example doesn't configure sniffing, so make sure the app passes the domain name to the SOCKS endpoint when testing.
6. dns: Configuring DNS Servers Doesn't Take Over System DNS
The top-level dns section configures the core's built-in DNS module. This example lists 1.1.1.1 and 8.8.8.8, but adding this section doesn't change the operating system's DNS settings or mean every app's queries will automatically go through the core.
- App resolves first: The app gets the destination IP, then sends that IP to SOCKS. The core usually can't see the original domain, so domain-based routing may not match.
- App passes the domain: The app sends the domain name as the SOCKS destination, allowing the routing module to match domain rules directly.
- Routing triggers a lookup: With a routing strategy that requires resolution, the routing module may call the built-in DNS module to continue matching IP rules.
- Outbound resolves the name: A direct outbound is also affected by its own domain resolution strategy. With the default
AsIs, don't assume it will query the servers listed in the top-level DNS section.
So the DNS section here mainly illustrates the structure; it doesn't guarantee that DNS will be used in every test. Routing's domainStrategy and the direct outbound's settings.domainStrategy operate at different layers: the first affects rule matching, while the second affects how direct connections handle destination addresses. Don't assume changing either field with the same name will alter every resolution path.
Takeaway: First Find Out Who Resolves the Domain
If a domain rule doesn't match, retry with socks5h://127.0.0.1:10808 so curl passes the destination domain to SOCKS. Once you've confirmed how the request is sent, decide whether to adjust DNS or routing.
7. Test the Config with Two Requests
For V2Fly versions with test and run subcommands, run the commands below from the directory containing the config file. On Windows, use .\v2ray.exe when running from the current directory. For other versions, check the local help output for supported options. Before starting, make sure no desktop client is already using 10808.
v2ray version
v2ray help
v2ray test -c config.json
v2ray run -c config.json
A successful test means only that the current core accepts the config; it doesn't prove network connectivity. Keep the core running and execute the commands below in another terminal. On Windows, use curl.exe to avoid conflicts with terminal aliases.
curl --connect-timeout 10 --max-time 20 --proxy socks5h://127.0.0.1:10808 -I https://example.com/
curl --connect-timeout 10 --max-time 20 --proxy socks5h://127.0.0.1:10808 -I https://example.org/
- First, test a direct connection. If the destination is reachable on your current network, the first command should return HTTP response headers. The status code depends on the destination site and doesn't have to be
200. - Next, test blocking. The second request should fail to complete a normal HTTPS response. The exact error varies by curl and core version, so don't judge the result by one specific error message.
- Keep the timeouts in mind. The command sets a 10-second connection timeout and a 20-second overall timeout to prevent long waits. These are not latency measurements or performance results.
- Change one thing at a time. Change the block rule's
outboundTagtodirect, then test again after restarting the core. If the second request now gets a response, that confirms the tag reference and rule are participating in request handling.
After editing the JSON on disk, don't assume the running process has reloaded it. For the manual setup in this guide, stop the old process, test the config, and start it again. When using subscription nodes in v2rayN, the client may regenerate its runtime config. Distinguish client-generated files from custom configs you maintain yourself, and keep a copy before editing.
8. Common Config Problems and Fixes
The config test passes, so why isn't my browser using the proxy?
A config test doesn't set the system proxy. First run the curl commands in this guide to verify the endpoint, then check the browser's proxy type and port. In this config, 10808 is a SOCKS port; it won't work in a setting that accepts HTTP proxies only.
Why can I still open a site when it's routed to blocked?
First, confirm the request really goes through 127.0.0.1:10808, then use socks5h to pass the domain name. Next, check that inboundTag is set to socks-local and that no earlier rule matches first. Restart the process before testing your changes.
Startup says port 10808 is in use. What should I change?
Stop the old core process, or change the inbound port to an unused 10818 and update the port in the test command to 10818 as well. Don’t change only the application’s port while leaving the core listening on the original one; the ports must match.
Can I put a subscription URL directly in outbounds?
No. A subscription is how a client retrieves node information; outbounds requires structured objects the core can recognize. Import the subscription into v2rayN first, then inspect the config it generates for the selected node. Before sharing a troubleshooting snippet, remove the subscription URL, server credentials, and other sensitive settings.
Follow the same checks every time: validate the JSON, start the core, connect to the inbound, match a rule, and reach the destination through the outbound. Change one layer at a time and keep a working baseline config. That way, even after adding VMess, VLESS, or more complex DNS routing, you can narrow failures down to specific fields instead of repeatedly replacing the whole config.
Choose a Client and Platform
Choose an installer for your operating system. Use v2rayN on desktop; on Android, choose v2rayNG or v2flyNG based on your core requirements. Follow the setup guide to establish a basic connection, then return here to review the config structure and rule references.