sing-box Failover and Mihomo Fallback: Set Up and Verify

sing-box Failover and Mihomo Fallback: Set Up and Verify

Ryan Foster
October 14, 2026· 10 min read

sing-box failover uses a urltest outbound that probes each exit and routes new connections to the best healthy one, while Mihomo offers a fallback group that always prefers the first available exit in your list. This guide configures both for two exits you own, then shows how to measure switching time, recovery, and what happens to open connections, DNS, and UDP.

Key Takeaways

  • Failover keeps one exit active and moves to another when checks fail; it does not add bandwidth.
  • sing-box urltest chooses by measured latency within a tolerance, not by your list order.
  • Mihomo fallback picks the first available proxy in order, so it returns to your preferred exit after recovery.
  • Switching takes up to about one check interval plus the timeout, so measure it instead of assuming.
  • An HTTP health check can pass while UDP on the same exit is broken.

This procedure is based on the official sources listed below; a complete end-to-end test has not been performed. It assumes sing-box 1.14.3 or Mihomo v1.19.32 on a Linux client and two working proxy exits you administer or are authorized to use. Plan ownership and recovery first with the self-hosting checklist.

How is sing-box failover different from load balancing?

Failover keeps traffic on one exit and changes exit only when that one stops passing checks. Load balancing spreads connections across several exits at once, and bonding combines links for one flow. The comparison of connection bonding, load sharing, and failover explains why only bonding can raise single-connection throughput.

Tool and typeHow it picks an exitAfter the preferred exit recovers
sing-box urltestLowest measured delay, with a tolerance to avoid flappingMoves back only if the recovered exit is faster by more than the tolerance
sing-box selectorManual choice, controlled through the Clash APIStays where you set it
Mihomo fallbackFirst available proxy in list orderReturns to the first proxy once it passes again
Mihomo url-testLowest measured delay, with a toleranceLike sing-box urltest

The sing-box urltest outbound tests a list of outbounds against a URL, by default every 3m with a 50 ms tolerance.[1] Its selector outbound can be switched only through the Clash API.[2] Mihomo's fallback group selects "the first available node" in the order of proxies when the current one times out.[3] Running two exits doubles your maintenance work, so weigh self-hosted servers against a managed VPN if uptime is the only goal.

Step 1: Prepare two exits and a health-check endpoint

You need two independent exits, here Shadowsocks 2022 servers at 203.0.113.10 (exit A) and 198.51.100.20 (exit B), each with its own key. They should sit in different data centers or providers, otherwise one outage takes both down. Confirm each works on its own before grouping them.

Both tools test a URL through each exit. sing-box falls back to a Google generate_204 address when url is empty.[1] Use an endpoint you control instead, such as https://check.example.net/generate_204, and add a second path such as /ip that returns the caller's address. Probing a third-party service every minute from several exits should respect that service's terms, and your own endpoint gives you logs to confirm which exit made each probe.

Step 2: Configure sing-box urltest for failover

If sing-box is not installed yet, the sing-box Linux client guide covers installing a pinned build and running a local listener. Save this as a private failover.json:

{
  "log": {"level": "warn"},
  "inbounds": [{"type": "mixed", "tag": "local", "listen": "127.0.0.1", "listen_port": 1084}],
  "outbounds": [
    {
      "type": "urltest",
      "tag": "auto-exit",
      "outbounds": ["exit-a", "exit-b"],
      "url": "https://check.example.net/generate_204",
      "interval": "1m",
      "tolerance": 300,
      "interrupt_exist_connections": true
    },
    {"type": "shadowsocks", "tag": "exit-a", "server": "203.0.113.10", "server_port": 8388,
     "method": "2022-blake3-aes-128-gcm", "password": "REPLACE_KEY_A"},
    {"type": "shadowsocks", "tag": "exit-b", "server": "198.51.100.20", "server_port": 8388,
     "method": "2022-blake3-aes-128-gcm", "password": "REPLACE_KEY_B"}
  ],
  "route": {"final": "auto-exit"}
}

A shorter interval detects failure sooner at the cost of more probes. A larger tolerance stops sing-box urltest from moving between two healthy exits whose delays differ slightly, which matters when sessions dislike address changes. interrupt_exist_connections closes inbound connections when the selected outbound changes; internal connections are always interrupted.[1] Leave it false if you prefer old connections to fail on their own.

Check the file with sing-box check -c failover.json using your pinned binary. A passing check confirms syntax, not that either exit works.

Step 3: Configure a Mihomo fallback group

For Mihomo, save a private config.yaml in its own directory:

mixed-port: 7891
allow-lan: false
bind-address: 127.0.0.1
mode: rule
log-level: warning
external-controller: 127.0.0.1:9090
secret: "REPLACE_LONG_RANDOM_SECRET"
proxies:
  - {name: exit-a, type: ss, server: 203.0.113.10, port: 8388, cipher: 2022-blake3-aes-128-gcm, password: "REPLACE_KEY_A", udp: true}
  - {name: exit-b, type: ss, server: 198.51.100.20, port: 8388, cipher: 2022-blake3-aes-128-gcm, password: "REPLACE_KEY_B", udp: true}
proxy-groups:
  - name: failover
    type: fallback
    proxies: [exit-a, exit-b]
    url: https://check.example.net/generate_204
    interval: 60
    timeout: 5000
    lazy: false
rules:
  - MATCH,failover

The Mihomo fallback group tests only the proxies listed in its proxies field; interval is in seconds, timeout in milliseconds, and lazy defaults to true, which skips tests for a group that is not selected.[4] Setting lazy: false keeps the group tested even when idle, so it has a current answer when traffic starts. max-failed-times (default 5) forces a fresh health check after repeated failures.[4] The 2022 cipher names come from Mihomo's Shadowsocks reference.[5]

Keep allow-lan: false and bind-address: 127.0.0.1 so other devices cannot use the port.[6] The controller lets you read the group state; protect it as described in the guide to securing the Mihomo controller API.

Step 4: Run the client and watch the selected exit

Start one tool at a time in the foreground and point a test terminal at its local port (1084 for sing-box, 7891 for Mihomo). For Mihomo, read the group's current choice through the API, which accepts a bearer secret:[7]

curl -s -H "Authorization: Bearer $MIHOMO_SECRET" http://127.0.0.1:9090/proxies/failover

The response names the proxy the group is using now. For sing-box, compare the address returned by your /ip endpoint with each exit's known egress address. In a browser set to the same local port, the IP address tool should show exit A or exit B, never your own connection.

How do you measure switching time and recovery?

Run a timestamped probe loop through the local port, then stop the proxy service on exit A during a maintenance window. Do not cut a shared server that other people depend on.

while true; do
  printf '%s ' "$(date +%T)"
  curl -s -m 5 --proxy socks5h://127.0.0.1:1084 https://check.example.net/ip || printf 'FAIL'
  echo; sleep 2
done
Check methodExpected behaviorIf it differs
Both exits upLoop shows one exit address consistentlyAddress alternates between exits: raise the sing-box tolerance
Stop exit A's proxy serviceFAIL lines, then exit B's address within about one interval plus timeoutGroup never switches: check the URL is reachable through exit B
Restore exit A, Mihomo fallbackReturns to exit A after the next successful checkStays on B: confirm list order and lazy: false
Restore exit A, sing-box urltestStays on B unless A is faster by more than the toleranceConstant switching: tolerance is too low for your delay spread
Stop both exitsAll requests failRequests succeed: traffic is bypassing the group

Record the time from stopping exit A to the first successful line through exit B. That gap, not the configured interval, is your real switching delay. Repeat the test a few times, because the check timer is not synchronized with the moment you stop the service.

What happens to DNS, UDP, and open connections?

Open TCP connections stay on the exit they started on. They fail if that exit dies, or close early when sing-box interrupt_exist_connections is on; applications must reconnect either way. New connections use whatever exit the group has chosen at that moment.

Health checks are HTTP requests, so they exercise TCP through each exit. An exit can pass the check while its UDP relay is blocked or broken, and UDP-based apps will then fail without triggering a switch. Test a UDP workload through each exit separately, and in Mihomo use the group's disable-udp option if you would rather block UDP than send it to an unreliable path.[4]

DNS behavior depends on your mode. With FakeIP, the client hands applications synthetic addresses and the real lookup happens later through the selected exit; the FakeIP versus redir-host comparison explains why a switch can leave cached mappings that look stale. Clear application caches or restart the app if a site keeps failing after a switch.

How do you roll back?

Keep each exit's standalone profile. To roll back, stop the failover client, restore the application's previous proxy setting, and confirm a fresh request through the single exit. Remove the test endpoint's probe logs on your schedule, and rotate any key you pasted into a shared terminal during testing.

Summary

  • Use sing-box urltest when you want the fastest healthy exit, and Mihomo fallback when you want a fixed preference order.
  • Set probe intervals, timeouts, and tolerance deliberately, and probe an endpoint you control.
  • Measure the real switching gap and the recovery behavior instead of relying on configuration values.
  • Check UDP and DNS separately, because HTTP health checks do not cover them.

FAQ

Does sing-box have an ordered fallback like Mihomo?

The documented urltest outbound selects by measured delay within a tolerance, not list order. For a fixed preference, use Mihomo's fallback group or switch a selector manually.

How long does sing-box failover take to switch?

Expect up to about one test interval plus the probe time, depending on when the outage starts. Measure it with a timestamped loop instead of trusting the setting alone.

Will failover keep my video call or download running?

Usually not. Existing connections stay on the failed exit or are closed, and the application must reconnect through the new exit to continue its session.

Why does UDP still fail after a successful health check?

The check is an HTTP request over TCP. It proves that TCP forwarding works through that exit, not that UDP relay or QUIC traffic is allowed.

Should I use a public URL for health checks?

You can, but your own endpoint avoids depending on someone else's service and its terms, and its logs show which exit made each probe.

Is load balancing a better choice than failover for two exits?

It depends on your goal. Load balancing spreads connections across exits but cannot speed up a single flow, and it can confuse services that expect one address.

Why does Mihomo return to the first exit after it recovers?

The fallback type always prefers the first available proxy in its list. Once the first exit passes a health check again, new connections move back to it.

Disclaimer: This article is for general informational purposes only and does not constitute legal, technical, or other professional advice. We make no guarantees regarding the accuracy, completeness, or timeliness of the content.

Sources:

  1. sing-box: URLTest outbound — https://sing-box.sagernet.org/configuration/outbound/urltest/
  2. sing-box: Selector outbound — https://sing-box.sagernet.org/configuration/outbound/selector/
  3. Mihomo wiki: Fallback proxy group — https://wiki.metacubex.one/en/config/proxy-groups/fallback/
  4. Mihomo wiki: Proxy groups — https://wiki.metacubex.one/en/config/proxy-groups/
  5. Mihomo wiki: Shadowsocks proxy — https://wiki.metacubex.one/en/config/proxies/ss/
  6. Mihomo wiki: General configuration — https://wiki.metacubex.one/en/config/general/
  7. Mihomo wiki: API — https://wiki.metacubex.one/en/api/

Sources checked 14 October 2026.

Related Articles:

Start your 3-day free trial

Sign up to experience all premium features at no cost.

*Available only to new users. Each user is limited to one trial.

sing-box Failover and Mihomo Fallback: Set Up and Verify | AethoVPN