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
- Check
ImportSources
from time to time to download subscription documents - Parse subscription documents with
Subscription Container
parsing components. The subscription documents will then be converted into individual server definitions. - 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
. - 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 Template 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"
]
}
}
}