How SingboxConfigTemplateService Generates sing-box Configuration in v2rayN

The SingboxConfigTemplateService merges user-defined JSON templates with auto-generated node configurations by deep-copying outbounds and endpoints into a customizable skeleton, applying detour logic and TUN-specific overrides.

When v2rayN (2dust/v2rayN) generates client configurations for the sing-box core, it delegates template-based customization to the SingboxConfigTemplateService. This service operates as the second stage of a pipeline, allowing power users to inject custom DNS, routing, and global options while preserving automatic node-specific generation. The implementation relies on JSON parsing, deep-copy operations, and conditional logic to blend user templates with generated outbounds.

Base Configuration Generation

Before template merging occurs, CoreConfigSingboxService.GenerateClientConfigContent constructs the foundation configuration. Located in v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs, this method validates the selected ProfileItem (rejecting unsupported transports like kcp or xhttp), loads the embedded Global.SingboxSampleClient resource, and deserializes it into a SingboxConfig object.

The service then populates critical sections through private helpers:

  • GenInbounds – Configures SOCKS/HTTP inbound listeners.
  • GenOutbounds – Builds proxy outbounds from the selected server nodes.
  • GenRouting – Sets up routing rules and rule sets.
  • GenDns – Configures DNS servers and rules.
  • GenExperimental – Enables experimental features like cache file settings.

Once the base _coreConfig object is fully populated, the method invokes SingboxConfigTemplateService.ApplyFullConfigTemplate to perform the optional template merge.

Template Merging Process

The SingboxConfigTemplateService resides in v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxConfigTemplateService.cs. Its entry point, ApplyFullConfigTemplate, accepts the generated configuration context and returns the final JSON string.

Loading the FullConfigTemplate

The service retrieves the template definition from context.FullConfigTemplate, which maps to the FullConfigTemplateItem model stored in SQLite. According to the source code in v2rayN/ServiceLib/Models/FullConfigTemplateItem.cs, this model contains:

  • Enabled – Boolean toggle for the feature.
  • Config – JSON string for standard proxy mode.
  • TunConfig – JSON string for TUN mode.
  • AddProxyOnly – When true, filters out direct and block outbounds.
  • ProxyDetour – Label injected into outbounds lacking a detour value.

Validation and Early Exit

The method performs strict validation before processing:

if (fullConfigTemplate is not { Enabled: true }) 
    return JsonUtils.Serialize(_coreConfig);
    
if (fullConfigTemplateItem.IsNullOrEmpty()) 
    return JsonUtils.Serialize(_coreConfig);

var fullConfigTemplateNode = JsonNode.Parse(fullConfigTemplateItem);
if (fullConfigTemplateNode == null) 
    return JsonUtils.Serialize(_coreConfig);

If any check fails, the service returns the unmodified base configuration, ensuring stability when templates are disabled or malformed.

TUN vs Standard Template Selection

The service selects the appropriate JSON template based on the connection mode:

var fullConfigTemplateItem = context.IsTunEnabled
    ? fullConfigTemplate.TunConfig
    : fullConfigTemplate.Config;

When TUN mode is active, the TunConfig block provides interface-specific settings; otherwise, the generic Config block applies.

Merging Outbounds and Endpoints

The core logic iterates through the base configuration's outbounds and injects them into the template's outbounds array. For each outbound, the service applies two critical transformations:

  1. Filtering – If AddProxyOnly is enabled, direct and block type outbounds are skipped.
  2. Detour Injection – If ProxyDetour is configured and the outbound lacks a detour, the service assigns the detour label only when the server is not a private address (verified via Utils.IsPrivateNetwork).
foreach (var outbound in _coreConfig.outbounds)
{
    if (outbound.type.ToLower() is "direct" or "block")
    {
        if (fullConfigTemplate.AddProxyOnly == true) continue;
    }
    else if (outbound.detour.IsNullOrEmpty()
        && !fullConfigTemplate.ProxyDetour.IsNullOrEmpty()
        && !Utils.IsPrivateNetwork(outbound.server ?? string.Empty))
    {
        outbound.detour = fullConfigTemplate.ProxyDetour;
    }

    customOutboundsNode.Add(JsonUtils.DeepCopy(outbound));
}

The same logic applies to endpoints in _coreConfig.endpoints, ensuring custom wireguard or other endpoint configurations inherit the detour settings.

Final Serialization

After merging, the modified JsonNode contains the user-defined template skeleton plus the deep-copied, processed outbounds and endpoints. The service finalizes the configuration with:

return JsonUtils.Serialize(fullConfigTemplateNode);

This JSON string represents the complete sing-box configuration ready for export or execution.

Practical Implementation Example

Below is a complete flow demonstrating how the services interact:

// Initialize context with server profile and template
var context = new CoreConfigContext
{
    Node = profileItem,
    AppConfig = appConfig,
    FullConfigTemplate = await AppManager.Instance.GetFullConfigTemplateItem(ECoreType.sing_box),
    IsTunEnabled = true  // Activate TUN-specific template
};

// Generate base configuration
var singboxService = new CoreConfigSingboxService(context);
RetResult result = singboxService.GenerateClientConfigContent();

if (result.Success)
{
    // result.Data contains the final merged JSON
    File.WriteAllText("singbox_config.json", result.Data);
}

In this example, AppManager.GetFullConfigTemplateItem loads the stored template from the SQLite database, and the SingboxConfigTemplateService automatically applies the TunConfig variations.

Summary

  • Two-stage pipelineCoreConfigSingboxService generates the base configuration, then SingboxConfigTemplateService applies user-defined templates.
  • Deep-copy merging – Outbounds and endpoints are cloned into the template array to prevent reference conflicts.
  • Conditional detour injection – The ProxyDetour setting only applies to public network servers, preserving private network direct connections.
  • Mode-aware selection – Separate Config and TunConfig templates allow distinct settings for standard proxy versus system TUN modes.
  • Fail-safe design – Invalid or disabled templates result in the base configuration being returned unchanged.

Frequently Asked Questions

What is the difference between Config and TunConfig in the template?

Config applies to standard proxy mode where applications connect to v2rayN's local SOCKS/HTTP ports, while TunConfig is used when TUN mode is enabled, requiring interface-specific settings like MTU, inet4_address, and auto_route. The SingboxConfigTemplateService selects between them based on context.IsTunEnabled.

How does the ProxyDetour parameter modify outbound behavior?

ProxyDetour specifies a detour label (such as "proxy" or "chain-outbound") that the service injects into any generated outbound or endpoint that lacks an explicit detour, provided the target server is not a private IP address. This enables automatic routing chains without manual per-node configuration.

What happens if the full-config template contains invalid JSON?

If JsonNode.Parse fails to deserialize the template string, or if the template is empty, the ApplyFullConfigTemplate method returns the unmodified base configuration generated by CoreConfigSingboxService. This ensures the application continues to function even with corrupted template data.

Can the template override inbounds and routing rules from the base configuration?

Yes, because the template JSON serves as the structural skeleton into which generated outbounds are merged. Any inbounds, routing rules, DNS settings, or experimental fields defined in the user's template JSON remain intact and take precedence, while the service appends the auto-generated node outbounds to the existing arrays.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →