Subscription Manager

  • Name: subscription
  • Type: Service
  • ID: service.subscription

Subscription Manager automatically refresh server information and turn them into outbounds. (v5.13.0+)

Subscription

imports : [ SubscriptionImportObject ]

SubscriptionImportObject

name: string The name of subscription import source. url: string URL of the import source. Currently 2 kinds of Subscription URL are supported

  • HTTP(S) URL : Download a subscription document over http(s).
  • DataURL : the url itself will be the subscription document. The media type must be "application/vnd.v2ray.subscription-singular" for it to be accepted.

tagPrefix: string

The prefix of outbound created from this subscription source.

importUsingTag: string

The outbound tag to download the subscription document.

defaultExpireSeconds: number

The default time to fetch subscription document again. This time is not strictly honored.

Subscription Manager will

  1. Check ImportSources from time to time to download subscription documents
  2. Parse subscription documents with Subscription Container parsing components. The subscription documents will then be converted into individual server definitions.
  3. Try to parse the server definitions as standardized outbound format one by one, if fails, try to convert the document into outbound format with Subscription Converter.
  4. Compare the successfully converted server definition set with the servers already instanced as outbounds, and apply the difference. Only the modified server will have their Outbound Handlers recreated.

Subscription Container

Container is the document includes a set of server definitions plus metadata. There is currently 3 supported containers, all of them are generic containers that does not, on their own, compliant with any subscription specs. Instead, they are the simplest way to capture whatever information contained in a subscription document without verifying schema.

The 3 currently supported container formats are:

  • Base64URLLine: A superset of base64 or V2RayN format. The document contains a base64 encoded newline separated server definitions.
  • JsonFieldArray: A superset of SIP008 or OOCv1 format. The document contains one or more array field at root object. And each item in the arrays is a server definition.
  • Yaml2Json+JsonFieldArray: A superset of Clash format. The document are converted to json from Yaml format and processed with JsonFieldArray.
  • DataURLSingle: A single server spec wrapped in DataURL. The media type must be "application/vnd.v2ray.subscription-singular" for it to be accepted.

Use v2ray engineering subscriptionEntriesExtract -input filename to output a zipped file contains what would be captured by V2Ray's Subscription Container parser.

Use v2ray engineering encodeDataURL -type application/vnd.v2ray.subscription-singular to generate a dataURL.

If you are generating these documents, instead of trying to parse one generated by someone else. You should be aware that V2Ray does not check for schema of formats mentioned. For this reason, a document could by parsed by V2Ray may be rejected by other applications.

Subscription Converter

If the server definition is in V2Ray natively supported outbound format, it will be directly loaded with outbound converter. It is recommended for all service providers to generate their subscription in outbound format so that V2Ray could parse their with predictable result.

Otherwise, if the input is not of native outbound format, the non-native input will be converted with conversion rules. The input will be preprocessed with AbstractNonNativeLink info extractor and split up input into many strings that can be referenced with their keys, and then all conversion rules will be tried one by one, until one successfully completed without error.

To see what keys and values will be extracted from server definition run: v2ray engineering nonnativelinkextract and input server definition into stdin. A sorted key value set will be output to stdout for examination.

The converter rules are either embedded into V2Ray or provided by user. The user defined rules always take precedence. The embedded converter rules are placed in app/subscription/entries/nonnative/definitions directory. The user defined rules are provided as a zipped file as nonnative_converter_overlay_file field of subscription manager configuration.

Subscription converters output a V2Ray native outbound format, which will then be converted to a V2Ray's internal format.

Currently, embedded converter rules have limited support for different protocols and vendors. Contributions are welcome.

Subscription Converter: Nonnative converter definition format

The converters use syntax as defined by Golang Templateopen in new window with some additional functions to access input and process subscriptions.

To run an embedded template against a server definition input, run v2ray engineering nonnativelinkexec -name vmess.jsont

To run an external template against a server definition input, run v2ray engineering nonnativelinkexec -templatePath .... -name vmess.jsont

templatePath should point to a directory with a directory named definitions with all the templates. The content of this directory can be zipped and pointed to at nonnative_converter_overlay_file to overlay over embedded definitions.

In addition to functions defined by template package, the following domain specific functions are defined.

assertExists

assertExists . key1 [key2 ...]

Checks if key1 [key2 ...] all exists in the extracted link attributes. If not, then template halt with an error.

assertIsOneOf

assertIsOneOf . key [values ...]

Check if the content of attribute[key] is one of the values. If it is not in one of the values, then template halt with an error.

assertValueIsOneOf

assertValueIsOneOf checkedValue [values ...]

Check if the checkedValue is one of the values. If it is not in one of the values, then template halt with an error.

tryGet

tryGet . key1 [key2 ...] ["<default>"]

Returns the first value found in key1 or key2... .If they are all not found and the last key is not <default> then halt with an error, if he last key is <default> then returns "" when nothing is found.

splitAndGetNth

splitAndGetNth sep n content

Split content with sep, and return the nth element. A negative n will be treated as len(splited_content) + n, If there is less than n element after split, then halt with an error.

splitAndGetAfterNth

splitAndGetNth sep n content

Split content with sep, and return the nth element and elements after it. A negative n will be treated as len(splited_content) + n, If there is less than n element after split, then halt with an error.

splitAndGetBeforeNth

splitAndGetBeforeNth sep n content

Split content with sep, and return the nth element and elements before it. A negative n will be treated as len(splited_content) + n, If there is less than n element after split, then halt with an error.

jsonEncode

jsonEncode anyData

Return anyData encoded with json

stringCutSuffix

stringCutSuffix suffix content

Remove suffix from content's tail. If suffix is not found, halt with an error.

unalias

unalias standardName [alias...] input

if input is one of the alias return standardName, otherwise return input.

Subscription Spec: outbound format

The outbound format is the recommended subscription format for V2Ray, and what converters generates. Its protocol, settings, streamSettings.transport, streamSettings.security, streamSettings.transportSettings, streamSettings.securitySettings all have the same meaning with jsonv5 format's outbound.

The metadata is an associative array of strings.

  • TagName means the name of outbound tag. If it is of letters and numbers and less than 24 characters, it will be used as is and appended to user defined tag prefix as outbound's tag. Otherwise a generated one will be used.
{
  "protocol": "vmess",
  "settings": {
    "address": "1234",
    "port": 1234,
    "uuid": "1234"
  },
  "streamSettings": {
    "transport": "grpc",
    "security": "tls",
    "transportSettings": {
      "serviceName": "1234"
    },
    "securitySettings": {
      "serverName": "1234"
    }
  },
  "metadata": {
    "TagName": "1234"
  }
}

Example

Finally, here is a neat example of using subscription system with load balancing and observatory.

{
  "log": {
    "error": {
      "level": "Debug",
      "type": "Console"
    },
    "access": {
      "type": "None"
    }
  },
  "outbounds": [
    {
      "tag": "deny",
      "protocol": "blackhole"
    },
    {
      "tag": "direct",
      "protocol": "freedom"
    }
  ],
  "router": {
    "domainStrategy": "AsIs",
    "rule": [
      {
        "balancingTag": "subscriptions",
        "inboundTag": [
          "user-in"
        ]
      },
      {
        "tag": "commander",
        "inboundTag": [
          "commander"
        ]
      }
    ],
    "balancingRule": [
      {
        "tag": "subscriptions",
        "outbound_selector": [
          "subscription_"
        ],
        "strategy": "leastping"
      }
    ]
  },
  "inbounds": [
    {
      "tag": "user-in",
      "protocol": "socks",
      "settings": {
        "udpEnabled": true,
        "address": "127.0.0.1",
        "packetEncoding": "Packet"
      },
      "port": 19828,
      "listen": "127.0.0.1"
    },
    {
      "tag": "commander",
      "protocol": "dokodemo-door",
      "settings": {
        "address": "127.0.0.1",
        "port": 65535,
        "networks": ["tcp"]
      },
      "port": 19829,
      "listen": "127.0.0.1"
    }
  ],
  "services": {
    "backgroundObservatory": {
      "subject_selector": [
        "subscription_"
      ],
      "probe_interval": 5000000000
    },
    "subscription": {
      "imports": [
        {
          "name": "VDA",
          "url": "https://123",
          "tagPrefix": "subscription_vda",
          "importUsingTag": "direct",
          "defaultExpireSeconds": 3600
        }
      ]
    },
    "commander": {
      "tag": "commander",
      "name": [
        "observatory"
      ]
    }
  }
}