First, distinguish the subscription URL, proxy list, and full configuration
A “subscription” in a Clash client is not a single fixed file format. What users receive is usually an HTTPS URL. When the client requests it, the server may return a complete Clash YAML config, a proxy-provider file containing only nodes, or a Base64-encoded list of generic node links. The URLs may look similar, but their responses can be completely different.
A complete Clash config can include not only nodes, but also listening ports, run mode, proxy groups, rule sets, DNS, TUN, and traffic-sniffing settings. A generic Base64 subscription usually only carries node URIs such as ss://, trojan://, vmess://, or vless://. A node list does not specify which group should handle websites outside mainland China, whether LAN addresses should bypass the proxy, or what should happen to traffic that matches no rule.
A third common type is a Mihomo or Clash proxy-provider file. It is also YAML, but its top level usually contains only proxies:, which the main config references through proxy-providers. It may not start directly as a complete configuration. Distinguishing these three types tells you whether to import the file directly, use it as a provider, or convert it first.
| Content type | Common opening lines or fields | Includes rules and proxy groups | Typical use |
|---|---|---|---|
| Full Clash YAML | mixed-port:、proxies:、proxy-groups: |
Usually included | Import as the client’s main configuration |
| Proxy-provider YAML | Top level mainly contains proxies: |
Usually not included | Loaded periodically through proxy-providers |
| Base64 node subscription | Long strings of letters, numbers, plus signs, slashes, or URL-safe characters | Not included | Read by compatible clients or converted into a Clash config |
| Single-node URI | ss://、trojan://、vmess:// |
Not included | Manually import one node |
What a Clash YAML config contains
YAML is readable, structured text. Indentation represents hierarchy, and list items usually begin with a hyphen. When Clash and Mihomo read a config, they parse field names, data types, and indentation, so spaces, Boolean values, quotation marks, and colons can all affect the result. If a node name contains a colon, hash, or square brackets, quoting it is usually safer.
Here is a reduced structural example. Ports 7890 and 9090 are common example values, not fixed defaults for every client; check the client’s Settings or runtime log for the actual listening ports.
mixed-port: 7890
allow-lan: false
mode: rule
external-controller: 127.0.0.1:9090
proxies:
- name: "Tokyo-01"
type: ss
server: edge.example.net
port: 443
cipher: aes-128-gcm
password: demo-password
proxy-groups:
- name: "Node Selection"
type: select
proxies:
- "Tokyo-01"
- DIRECT
rules:
- DOMAIN-SUFFIX,example.org,Node Selection
- GEOIP,LAN,DIRECT
- MATCH,Node Selection
proxies defines available nodes, proxy-groups organizes them into manual selection, latency-testing, or failover groups, and rules determine where connections go in order. Rules are matched from top to bottom, with MATCH typically handling connections that matched nothing earlier. A client can fill in missing proxy groups and rules through an additional template when given only nodes, but that is secondary processing performed by the client or converter.
The boundary between a full config and a provider file
A proxy-provider file has a narrower role. The main config declares the download URL, refresh interval, and health check, while the remote file delivers only nodes. In the example, interval: 86400 means updating every 86,400 seconds, or every 24 hours; the health check visits a test URL every 600 seconds.
proxy-providers:
airport-main:
type: http
url: "https://sub.example.net/clash-provider.yaml"
path: ./providers/airport-main.yaml
interval: 86400
health-check:
enable: true
interval: 600
url: "https://www.gstatic.com/generate_204"
If you use a provider file containing only proxies: as the main config, the client may report missing proxy groups, or the imported profile may lack the expected routing controls. Conversely, putting a full config with DNS, TUN, and rules in a provider path does not match the provider data structure.
What a Base64 subscription actually encodes
Base64 is text encoding, not encryption. It converts raw node URIs into text made from a limited character set, making them easier to transmit through an API. After decoding, the result is usually one node per line, and the client still needs to parse each line according to its protocol. Base64 may use the standard character set or a URL-safe variant that replaces plus and slash with hyphens and underscores.
ss://[email protected]:443#Tokyo-01
trojan://[email protected]:443?security=tls#Singapore-02
vless://[email protected]:443?security=tls&type=ws#Los-Angeles-03
These URIs describe the server, port, authentication details, transport, and remarks, but they cannot uniformly carry Clash proxy groups and rules. To produce a working config, a converter must apply an additional template—for example, putting all nodes into a select group named “Node Selection,” then adding DIRECT and a final MATCH rule.
Why decoded content can still be hard to read
- After the outer Base64 layer is decoded, the result may contain multiple URI lines, while one of them still contains a separate Base64-encoded JSON string after
vmess://. - The server may compress the response with gzip first. Browsers and
curl --compressedusually handle this automatically, but copying the raw bytes directly may produce garbled text. - The response may be an error page. An expired login session, rate limit, or expired token can make the server return HTML instead of a subscription.
- The subscription may use URL-safe Base64 and omit trailing padding characters such as
=, which can cause some strict decoders to fail. - The node protocol or extension parameters may exceed the capabilities of an older Clash core. The content can decode successfully while the client still refuses to load it.
Four steps to identify your subscription format
Step 1: Start with the client’s error location
“Download failed” and “Parse failed” are different problems. The former usually occurs during DNS, TLS, network connectivity, HTTP status handling, or subscription-token validation; the latter means the client received a response but could not read it in the expected format. If the log shows HTTP 401 or 403, update the subscription URL first. Continue inspecting the content and core compatibility only when the log shows errors such as yaml: line 18, mapping values are not allowed, or proxy 2: unsupported type.
Step 2: Save the response instead of inspecting only the URL
You can save a test subscription to a file from the terminal. Real subscription URLs usually contain access tokens, so do not paste them into public screenshots, online forums, or shared command histories. The example below uses a demonstration domain and token.
curl -L --compressed \
'https://sub.example.net/api/v1/client/subscribe?token=demo-token' \
-o subscription.txt
wc -c subscription.txt
head -c 160 subscription.txt
-L follows redirects, while --compressed allows the server to return compressed content. If the file is only a few dozen bytes and starts with <html, {"error", or a login prompt, the problem is usually the API response rather than the Clash format. A normal subscription may range from a few KB to hundreds of KB; there is no universal length standard.
Step 3: Check the visible fields
- If you see
proxies:,proxy-groups:, andrules:, it is usually a complete Clash YAML config. - If the top level contains only
proxies:and a node array, it is usually provider YAML. - Multiple plaintext lines beginning with
ss://,trojan://, orvless://indicate a plaintext node list. - If the body is one long Base64 string, decode it and then classify it using the first three checks.
- A web page title, CAPTCHA, login form, or JSON error object means the server did not return subscription data.
Step 4: Confirm the target core
Clash Premium, Clash Meta, and the later Mihomo core are not identical configuration targets. Mihomo supports more protocol fields, rule capabilities, DNS options, and TUN parameters. Choosing the broad “Clash” target may produce a conservative format for an older core, or include fields that an older client cannot recognize. For clients using the Mihomo core, prefer an output target explicitly labeled Mihomo or Clash Meta.
How to convert between Base64 and YAML
Method 1: Use the client’s built-in compatibility import
Some desktop clients recognize generic URI lists during subscription import and automatically generate a local config. In clients built on the Mihomo core, the usual process is to add a remote URL from the Subscriptions or Config page and let the client parse the response. The entry may appear as “Subscriptions” → “New Subscription” or “Config” → “Import URL.” After importing, inspect the config details to confirm that proxy groups and a final rule were generated instead of relying only on an “Update successful” message.
Automatic compatibility is convenient, but the client controls the generation strategy. One client may place every node in a manual selection group, while another may add an automatic latency-testing group. When moving to another client, group names, rules, and DNS settings may not match.
Method 2: Use a subscription conversion service
A conversion service typically accepts the source subscription, target format, and template parameters, then downloads the source, parses the nodes, and outputs Clash or Mihomo YAML. A common workflow is to select Mihomo as the target, enter the subscription URL, specify a remote config template, and generate a new subscription URL. The client then accesses the converted URL instead of reading the original Base64 directly.
The template determines the quality of the final config. At minimum, check the following:
- Whether all required nodes are included in the proxy groups, and whether any group names are referenced without being defined.
- Whether the end of the rules contains a sensible fallback, such as
MATCH,Node Selection. - Whether LAN, common private addresses, and local host addresses bypass the proxy as intended.
- Whether the DNS settings match the current network environment and do not use an unreachable upstream.
- Whether TUN, sniffing, and IPv6 settings suit the current operating system instead of being inherited mechanically from the template.
- Whether the output target matches the Mihomo or Clash core actually used by the client.
Method 3: Decode locally and apply a config template
If you only need to inspect Base64 content, decode it locally instead of sending the subscription to a third-party website. The Python 3 command below reads a file, restores missing Base64 padding, and writes the result to decoded.txt. It only decodes the content; it does not convert URIs into Clash node objects.
python3 -c "import base64,pathlib; p=pathlib.Path('subscription.txt').read_text().strip(); p += '=' * (-len(p) % 4); pathlib.Path('decoded.txt').write_bytes(base64.urlsafe_b64decode(p))"
head -n 5 decoded.txt
A complete conversion still requires parsing each protocol URI and correctly mapping parameters for TLS, WebSocket, gRPC, Reality, UDP, and certificate verification. Manually copying a few fields can easily omit transport settings, so it is suitable for debugging a small number of nodes, not for long-term maintenance. For larger node sets, use a locally maintained conversion tool that clearly supports the target core.
Import the converted config into Clash or Mihomo
Once you have the YAML, do not immediately overwrite the working config. Save it as a new profile first, then run a syntax check and limited connection tests. A typical desktop-client workflow is “Config” → “New” or “Import from URL” → “Update” → “Set as current.” Labels vary slightly between clients, but keep the old profile until the new one has been verified.
Check the YAML structure first
At minimum, confirm that names in proxies, proxy-groups, and rules correspond to one another. A proxy group that references a nonexistent node, or a rule that points to a nonexistent group, can cause startup failures or incorrect routing. YAML indentation must use spaces rather than tabs; two spaces per level is recommended.
Then check the listening ports
After the config sets mixed-port: 7890, the system proxy should also point to 127.0.0.1:7890. If the client actually uses HTTP port 7890 and SOCKS port 7891, terminal environment variables must select the matching protocol. If a port is already occupied by another process, the log commonly shows address already in use; changing the format will not help.
HTTP_PROXY=http://127.0.0.1:7890
HTTPS_PROXY=http://127.0.0.1:7890
ALL_PROXY=socks5://127.0.0.1:7891
Finally verify rules, DNS, and TUN
- On the proxy page, manually select a working node to rule out an incorrect automatic group choice.
- Open the connections page and confirm that the test request matched the expected proxy group rather than
DIRECTorREJECT. - Check domain-resolution results in the log and make sure DNS timeouts are not occurring continuously.
- Enable TUN only after ordinary system-proxy testing succeeds, reducing the number of variables being investigated at once.
- After enabling TUN, confirm that the client has the required system permissions and check that the default route and LAN access work normally.
TUN mode addresses traffic interception for apps that do not use the system proxy. It does not repair invalid nodes, incorrect credentials, or damaged YAML. If ordinary proxy connections all fail after conversion, return to the node parameters, core support, and subscription validity instead of repeatedly switching TUN.
Common import failures and how to handle them
| Symptom | First check | What to do |
|---|---|---|
| A YAML parse error appears immediately after updating the subscription | The response is Base64, HTML, or has damaged indentation | Save the response and inspect its beginning; confirm the target format and convert it again |
| The import succeeds but the proxy page is empty | A provider file was imported, or no proxy group references the nodes | Check the top-level fields and proxy-groups references |
| Nodes are present but all time out | The nodes are inactive, protocol fields are incompatible, or DNS/network access is restricted | Review the single-node error log and verify the target core and transport parameters |
| All traffic goes DIRECT after conversion | The template’s group name does not match the rule target | Check that the third field in the rule exactly matches the proxy-group name |
| Subscription updates return 401 or 403 | The token is expired, access is restricted, or the request method is incorrect | Get a new subscription URL and confirm the account status and required request headers |
| An older client reports unsupported proxy type | The output contains a protocol or field unsupported by the current core | Upgrade to a compatible Mihomo client or choose a target for the older core |
| The converted URL works once and then stops updating | The temporary URL expired, the converter cached stale data, or the source token changed | Check the conversion service’s validity period, regenerate the URL, and verify the source address |
Avoid repeated conversions
Sending a subscription through converter A to generate Clash YAML and then passing that result to converter B can change node remarks, rebuild proxy groups, overwrite rule templates, and drop parameters. Keep the chain as simple as possible: send the original subscription directly to the target converter, then let the client read the final URL.
Do not treat a subscription update as a config overwrite
Some clients let users add local overrides on top of a remote config, such as changes to ports, DNS, or rules. Whether those overrides survive a remote update depends on the client. Before editing, distinguish between editing the downloaded cache file, editing a copy of the remote config, and adding a persistent override; otherwise, the next update may restore the original content.
Practical conclusions for choosing a format
If the subscription provider can output Mihomo or Clash YAML directly, prefer the native format that matches your current core. It can fully represent node parameters and may include proxy groups and rules. Use a client compatibility layer or trusted conversion tool to generate YAML only when the source is available as generic Base64.
If you need to maintain the rules yourself, a stable structure is to put nodes in a provider file and let the local main config manage proxy groups, rules, DNS, and TUN. Node updates then do not overwrite routing logic, and the main config does not need to be regenerated with every subscription refresh. The provider refresh interval can be set to 86400 seconds, with health checks every 300 to 600 seconds depending on the number of nodes and network conditions.
Always break the investigation into four layers: can the subscription URL be reached, what format does the response use, can the target core parse it, and do the resulting rules and network behavior work correctly? Format conversion addresses the second layer and part of the third; it cannot replace checks for node validity, port binding, DNS, or system-proxy behavior.