Tutorial · Estimated reading 16 mins

Fix Mihomo subscription HTTP 403 or zero proxies
User-Agent, redirects, TLS, and encoding—step by step

You already pasted a working-looking airport link into a Clash-compatible client, but the subscription update spins forever, the log says 403, or the profile loads with an empty proxy list. This is the fetch-and-parse layer—not the same problem as turning a non-Clash link into YAML with a sub-converter, and not the same as hiding your tweaks behind mixin overrides after a clean download. Work through headers, HTTP redirect chains, certificates, and response bodies before you touch routing rules.

Mihomo · User-Agent · 403 · airport · redirects

1 What “HTTP 403” and “zero proxies” really mean

A hard HTTP 403 is the server telling the client it understood the request and refuses it—often because a User-Agent looks like a bot, the link token is wrong, the client IP is on a blocklist, or a CDN policy fired. In contrast, a profile that returns 200 with an empty proxies: list is usually a parse failure, an expired or placeholder URL, or a body that is HTML (login page) instead of YAML or base64. Mihomo and other Clash Meta cores are strict: they are not a browser; if the body is a Cloudflare challenge, a “subscribe in panel first” page, or gzip-compressed data mislabeled as text, the engine may end up with no usable proxy lines even though the transfer “succeeded.”

Separate the problem in your head before you change YAML. Subscription refresh sits upstream of rules: and policy groups. If the fetch is rejected, no amount of DOMAIN-SUFFIX surgery fixes it. If the fetch is fine but the body is the wrong kind of document, the fix is at the airport dashboard or the conversion step—not your routing stack. The guides above for sub-converter workflows and mixin are invaluable once a valid Clash file exists; this article is about the moment before that, when the bytes never become nodes.

2 Reproduce the fetch outside the GUI

Open a terminal on the same network path the client will use. Run curl -I (and then curl -L -v) against the subscription URL, first without extra flags, then with a User-Agent string copied from a mainstream browser, then with a UA string your airport documents for Clash, if they publish one. The -L switch follows HTTP redirect hops so you can see whether a short link expands to HTTPS on a new host, whether cookies appear in Set-Cookie headers, and whether a final 200 is actually a tiny JSON error. Save one response to a file and open it in a plain text editor: if you see <!DOCTYPE html> at the top, the subscription is not a machine-readable profile yet.

If curl on the laptop works but the client still shows zero proxies, compare time skew (TLS validity), per-app proxy settings, or a captive portal. If you run Mihomo on a headless Linux service, the server’s egress IP may differ from your home PC—airport panels that bind tokens to a region or AS number are common, and a VPS in another country can therefore see HTTP 403 where your desktop did not. That is policy, not a missing YAML key. The Linux Mihomo with systemd article stays useful for how the daemon starts; combine it with the network checks here when fetch behavior diverges by machine.

Log line vocabulary When your UI says “update failed,” copy the exact status code, final URL, and the first 200 bytes of the body from a manual curl. Those three fields usually pinpoint whether you are in UA-land, redirect-land, or parse-land.

3 User-Agent blocks and legacy expectations

Many airport back ends and edge CDN products filter requests whose User-Agent is empty, default-library-looking, or historically associated with abuse. A minimal clash or Clash token still works in plenty of places, but some operators whitelist browser-like strings or a vendor-specific label that matches the documentation page. When HTTP 403 appears in both the GUI and curl without a browser UA, retry with a recent Chrome or Safari UA, then with the string your subscription page literally prints. If 403 flips to 200, you have a header problem, not a core bug.

Do not treat “random UAs from forums” as permanent infrastructure. A copied string may be outdated in a year, or it may break when the provider flips to a new policy. The durable fix is: store the User-Agent in config alongside the URL (see below) or ask the airport to document a stable, machine-oriented identifier. In enterprise environments, outbound proxies sometimes strip or rewrite User-Agent headers; if your corporate path normalizes UAs, you will see the same 403 in Mihomo as in curl, which is a networking ticket, not a Clash patch.

4 Redirect chains, short links, and final URLs

Subscription panels love indirection: a short https entry point issues 302 to a storage bucket, or rotates hosts for load. Some HTTP clients cap redirect depth or mishandle cross-scheme moves; others drop query parameters when they should not, invalidating a signed token. Walk the redirect list with curl -L -v and look for 301/302 loops, HTTP→HTTPS upgrades, and unexpected geographic hops. A chain that ends on a 403 at a CDN you never intended usually means the first hop lost a token, not that your YAML is wrong.

Where a provider allows it, prefer pasting the final HTTPS URL shown after redirects into the client. That shortens the failure surface. If the panel insists on a single canonical short URL, you may need a custom header (for example, an Authorization bearer the dashboard gives you) in addition to the User-Agent. Mihomo’s proxy-providers (and similar sections, depending on your profile schema) let you add structured header: maps—keep those secrets out of public screenshots, because your subscription link is already a password.

5 TLS, SNI, clock skew, and MITM

When the log shows certificate errors, handshake timeouts, or “unknown issuer,” the problem is TLS before HTTP status. Verify the system clock on the device running the core—a drift of weeks can make valid certificates look expired. In schools and hotels, captive portals or TLS-inspecting gateways sometimes replace certificates; your browser may trust a corporate root that Mihomo does not, so the GUI looks fine in Chrome while the subscription client fails. Test from the same host with openssl s_client -connect or a short curl -v and compare the cert chain. If a middlebox rewrites SNI or alpn, you may need a different network, a documented fingerprint trust (only if you understand the risk), or to stop TLS interception for that host entirely.

IPv4-only airport endpoints on dual-stack clients can also produce confusing failures: happy eyeballs may race down a v6 path your policy does not yet steer. While debugging, temporarily disabling IPv6 on the test machine, or making resolver behavior explicit, can isolate a class of “works once, then not” subscription issues that masquerade as HTTP 403 or empty lists when the connection never reaches the right edge.

6 Encoding, Content-Encoding: gzip, and “looks empty”

Some panels serve compressed payloads without a matching client decode path in older tools. Current Meta stacks generally handle gzip transparently, but a broken transparent proxy in the middle can strip headers and leave a garbage body. If you save a response that appears binary in a text editor, check whether a plain curl --compressed run yields readable Clash YAML. Likewise, a base64 text bundle must arrive without BOM surprises or HTML wrappers. When the decoded content is a blank stub or a comment-only file, the airport account may be out of quota, banned, or reset—ask the operator before spending another evening on rule-providers: tuning.

7 CDN challenges and HTML 403 pages

A 403 with an HTML error body from a well-known CDN is not a Clash error—it is a front door saying “come back with a browser cookie” or “this ASN is not welcome.” Zero proxies after a 200 is similar: the subscription body might be a JavaScript-gated interstitial, not a profile. The fix is to move the hosted file to a direct-download endpoint the provider offers for API and client use, or to authenticate through official means. Random third-party mirror links should be treated with suspicion; they are both a security risk and a frequent source of stale User-Agent requirements.

Do not disable TLS verification “just to try” on public airport subscription URLs The rare legitimate exception is a private, pinned internal endpoint. In every other case, you risk importing an attacker’s node list, not “fixing” a 403.

8 How to set headers in a Mihomo proxy-providers (HTTP) block

When you have identified the correct User-Agent and any other required header, encode them in the profile so every refresh reuses the same values. A typical proxy-providers entry with type: http supports a header: map. Example (adjust names, paths, and fields to your layout):

config.yaml (example)
proxy-providers:
  my-airport:
    type: http
    url: "https://example.com/sub?token=YOUR_TOKEN"
    path: ./providers/my-airport.yaml
    interval: 3600
    header:
      User-Agent: "Clash/1.0(compatible; example)"
      Accept: "application/x-yaml, text/yaml, */*"

If you merge multiple subscription sources in a GUI, the same header ideas apply through the form fields your client exposes—export the final YAML and search for the User-Agent line to confirm the GUI did not drop it. After editing, hit “update subscription” once and re-read the log. A healthy sequence shows the expected status code, a non-trivial file size, and a parser that enumerates the expected number of proxy groups or nodes, depending on how your airport exports data.

9 Clash GUI, system proxy, and per-app firewalls

Desktop Clash front ends that launch Mihomo already share the system’s network—if the subscription request must go through a parent HTTP proxy to reach the public Internet, the core’s fetcher might need a chained outbound or a dedicated DDNS route. Misconfigured loopbacks (core tries to go through itself) show up as timeouts rather than 403, but the troubleshooting rhythm is the same: reproduce with curl using the same host routing table. On locked-down Windows images, a corporate firewall that blocks long URLs or specific User-Agent strings is common; a temporary allow rule for the airport host often reveals the class of issue in minutes, which beats blind YAML edits.

When everything finally downloads and parses, you can return to policy work—url-test groups, region selectors, and rules—knowing the proxy list is real. The documentation hub links to broader topics if you are expanding an advanced policy set, but the fetch step has to be green first.

10 Wrap-up

Mihomo and other Clash Meta cores are honest about the HTTP story they see: a 403 is a refusal, a redirect loop is a path problem, and a 200 with HTML is not a subscription just because a browser would render it. Match User-Agent and redirect behavior to your airport’s expectations, prove TLS end-to-end, and confirm the decoded body is actually YAML or base64. Pair that with the sub-converter guide when you are converting non-native links, and with mixin overrides when you are customizing a profile that already downloads. Compared with stabbing in the dark at rules, that order of operations saves a lot of evenings—and keeps you off mystery mirrors.

A maintained client from the site download page lines up with the features this workflow assumes; treat upstream repositories as the place for source and issues, not as your everyday installer. When you are ready, grab a current build, walk the checklist again, and let the log tell you whether the next problem is the network or the policy layer.

→ Download Clash for free and experience the difference

Tags: Mihomo User-Agent HTTP 403 Subscription Redirect Clash Proxy-providers Airport
Clash client logo for Mihomo subscription troubleshooting

Clash Verge Rev

Next-gen Clash client · Free and open source

Logs you can read, a Mihomo-class core, and a familiar GUI for subscriptions—so when a 403 is gone, you spend time on policy, not guesswork.

Clear subscription errors High-performance core Sensible defaults Easy YAML export TUN on supported OS

Related reading