There is a particular kind of frustration that only happens once, and then you change how you work forever. You spend an evening tuning a rule list — routing your package manager direct, dropping a handful of telemetry domains, pinning a work intranet to the local interface — and it all behaves beautifully for a week. Then the profile refreshes on schedule and every one of those lines is gone.
Nothing malfunctioned. The client did precisely what it was asked to do: fetch the current version of a remote document and replace the local copy with it. The mistake was upstream, in where those hand-written rules were stored in the first place.
This guide covers the workflow that avoids that outcome entirely — how remote profiles are structured, which parts of a configuration survive a refresh, and how to keep several setups side by side so that switching between home, office and hotel Wi-Fi takes one click instead of an editing session.
What a Remote Profile Actually Contains
When you paste a URL into the profiles page, the client makes an HTTP request and stores whatever comes back. In practice that response is one of two things.
The first is a complete YAML configuration: ports, DNS block, proxies, proxy-groups and a full rule list, ready to load. The second is a base64-encoded list of node URIs — ss://, vmess://, trojan:// and friends — which the client decodes and wraps in a minimal generated config.
Providers often attach a response header describing your account state, which is why the profiles page can show traffic used and an expiry date without asking you anything:
subscription-userinfo: upload=1048576; download=2097152; total=107374182400; expire=1767225600
Either way, the important detail is the same: the document is authored by someone else and is replaced wholesale on every update. Nothing you type into it is protected.
Why a Refresh Wipes Your Edits
Updating is not a merge. There is no diff, no three-way reconciliation, no attempt to work out which lines were yours. The client fetches the remote document and writes it over the stored copy.
That is the correct behaviour, even though it feels hostile the first time. A provider needs to be able to retire a dead endpoint or roll out a new node list, and a client that tried to preserve arbitrary local edits would eventually merge them into something that no longer parses.
The consequence is a rule you can state in one line: anything you want to keep must live outside the file that gets overwritten. Everything below is a different way of honouring that rule.
Pattern One: Put Your Edits in an Override File
Most desktop clients support a layered model. The remote profile is the base, and a separate document you control is applied on top of it every time the base is loaded — including after each refresh.
Overrides typically operate in three modes, and knowing which one you need matters:
- Prepend — your entries are inserted above the remote ones. This is what you want for rules, because first match wins.
- Append — your entries go below the remote ones, useful for a fallback you want evaluated last.
- Replace — your block substitutes the remote block entirely. Correct for a DNS section you have carefully tuned; dangerous for a proxy list.
A minimal override that survives every update might look like this:
prepend-rules:
- DOMAIN-SUFFIX,intranet.mycompany.com,DIRECT
- DOMAIN-SUFFIX,registry.npmjs.org,DIRECT
- IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
- DOMAIN-KEYWORD,telemetry-endpoint,REJECT
dns:
enable: true
enhanced-mode: fake-ip
nameserver:
- 1.1.1.1
- 8.8.8.8
Some clients expose the same capability as a small script that receives the parsed config and returns a modified one, which is more flexible when you need conditional logic — for instance, only prepending a rule when a particular policy group exists in the incoming profile.
Pattern Two: Stop Writing Lists Inline
The stronger version of the same idea is to keep almost nothing in the config file at all. Providers let both nodes and rules live at their own URLs, refreshed on their own schedules.
proxy-providers for nodes
proxy-providers:
vendor-a:
type: http
url: "https://example.com/sub-a"
interval: 21600
path: ./providers/vendor-a.yaml
health-check:
enable: true
url: http://www.gstatic.com/generate_204
interval: 600
proxy-groups:
- name: AUTO
type: url-test
use: [vendor-a]
tolerance: 100
Notice that the group references the provider by name rather than listing nodes. The provider’s contents can change completely and the group definition stays valid — which is the whole point.
rule-providers for rule sets
rule-providers:
ads:
type: http
behavior: domain
url: "https://example.com/rules/ads.yaml"
path: ./rules/ads.yaml
interval: 86400
rules:
- RULE-SET,ads,REJECT
- MATCH,AUTO
With both in place your main config becomes a short skeleton of maybe forty lines, and the parts that change frequently update themselves. If you have never looked at what a clash subscription returns before it reaches your rule engine, it is worth fetching one with curl once — seeing the raw document makes the whole provider model click immediately.
Providers also accept local files with type: file, which is handy for a personal rule set you do not want to host anywhere.
Running Several Profiles at Once
A single configuration rarely fits every network you use. Office Wi-Fi may already route internal hosts correctly and need very little intervention. A hotel network may need everything captured. Home sits somewhere between.
Keeping three profiles and switching between them is far less work than editing one profile repeatedly. Desktop clients such as the one at clash-vergerev.co keep every imported profile as its own card on the profiles page, so switching is a click and the previous configuration stays exactly where it was.
ProfileTypical setupNotesHomeFull rule set, TUN mode, LAN bypassedNAS and printer must stay reachableWorkSystem proxy only, intranet forced DIRECTAvoid capturing corporate VPN trafficTravelTUN mode, fallback group, conservative DNSCaptive portals need a quick DIRECT toggleMinimalDirect everything except one groupDiagnostic baseline when something breaks
That last row earns its place. A stripped-back profile that does almost nothing is the fastest way to answer “is this my config or the network?” — switch to it, and if the problem persists, stop reading your rule list.
Update Intervals and the User-Agent Quirk
Two settings on the profile cause more confusion than the rest combined.
How often to refresh
The interval is a trade-off between staleness and pointless traffic. Six to twelve hours suits most providers. Every few minutes gains nothing, and some providers rate-limit or temporarily block clients that poll aggressively. A daily refresh is fine if your node list rarely changes.
Whatever you choose, do not disable updates entirely and forget about it. Nodes are retired without notice, and a profile that has not refreshed in three months will eventually fail everywhere at once.
Why the same URL returns different content
Many providers inspect the User-Agent header and return a different document depending on which client they think is asking — a full YAML config for one, a base64 node list for another, something else again for a plain browser. This is why pasting a URL into a browser can show you output that looks nothing like what your client received.
If a subscription imports as an empty or malformed profile, the User-Agent is the first thing to check. Most clients let you set it per profile, and providers usually document the string they expect. To see what you are actually being served:
curl -H "User-Agent: clash-verge/2.0" \ "https://example.com/your-subscription" | head -40
Compare that against the same request with a browser User-Agent and the difference is usually obvious immediately.
Backing Up and Versioning Your Config
Once your override file and skeleton config represent real work, treat them like code. A small Git repository is enough, and it turns “what did I change last Tuesday?” into a one-command answer.
- Create a directory holding your skeleton config, override files and any local rule sets.
- Run
git initin it and commit the current working state. - Add a
.gitignorefor generated provider caches and anything that refreshes automatically. - Commit after every change that survives a day of real use, with a message saying what you were fixing.
- Tag or branch before a large restructure so rolling back is trivial.
Be careful about what you commit. Subscription URLs frequently contain a token that functions as a credential, and node passwords are stored in plain text. Keep the repository private, or better, keep secrets in a file that is ignored and reference it from the tracked config.
# .gitignore providers/ rules/*.yaml secrets.yaml *.log
Testing a Profile Before Trusting It
Switching your only working setup to an untested profile is how a quiet evening becomes a debugging session. A short checklist avoids it:
- Import the new profile but do not activate it. It sits alongside the current one, inert.
- Read the rule list. Check that it ends with a final catch-all and that private ranges are bypassed.
- Verify your override file still applies — a profile using different policy group names will silently break rules that reference the old ones.
- Activate it and run a latency test across the groups.
- Exercise the things you actually care about: a video call, a package install, your intranet, the printer.
- Watch the connections log for a minute and confirm the rules firing are the ones you expect.
- Only then delete the old profile — and honestly, keeping it costs nothing.
Step three catches the most common failure. Override rules that point at a group name the new profile does not define will either be ignored or refuse to load, and the error message rarely says so plainly.
Common Questions
Can I merge two subscriptions into one setup?
Yes — define each as a separate proxy-provider and reference both from a single policy group with the use key. Each keeps its own update interval and health check, and one provider failing does not take the other down with it.
What happens to my custom rules if I re-import the same URL?
Anything typed directly into the profile is lost. Anything in an override file, a rule-provider or a local rule set is reapplied automatically. That asymmetry is the entire reason for the workflow described here.
Do I need to restart after an update?
Usually not — clients reload the configuration in place. Connections already open may keep using the old routing until they close, so if you are testing a rule change, close the relevant connection first rather than assuming the new rule did not work.
How do I move my setup to another machine?
Copy the repository, install the client, re-import the subscription URLs and point the client at your override file. Because your customisations are stored separately from the remote profiles, there is nothing to reconstruct by hand.
Closing Notes
The whole problem reduces to one boundary: content that someone else maintains, versus content that you maintain. Blur that line by editing a remote profile directly and every refresh becomes a small act of destruction. Keep it sharp and updates become routine background noise.
In practice that means a skeleton config you own, an override file for personal rules, providers for anything that changes on its own schedule, a couple of profiles for the networks you actually use, and a Git repository holding the lot.
It takes perhaps half an hour to set up the first time. After that, a subscription refresh is something you notice only because the node list got a little longer — which is exactly how it should feel.
