Skip to content

👻 ping-config: checking nodes for real

A group’s usual check is a HEAD to url. A node that answers the headers and then gets cut on the body (stalling after ~16–20 KB, say) passes it. ping-config adds a second check: after url the core asks destination, and the node is alive only when it answers in time. It is the counterpart of Xray’s burstObservatory.pingConfig.

proxy-groups:
- name: auto
type: url-test
proxies: [node1, node2]
url: https://www.gstatic.com/generate_204
interval: 300
timeout: 5000
ping-config:
destination: https://speed.cloudflare.com/__down?bytes=51200
http-method: GET
interval: 60s
sampling: 1
timeout: 3s
connectivity: http://connectivitycheck.gstatic.com/generate_204
FieldWhat it doesDefault
destinationthe address of the second checkthe group’s url
http-methodHEAD or GET; GET reads the whole body (up to 4 MiB)HEAD
intervalhow often checks run; "15s", "1m" or a number of seconds; at least 10 sthe group’s interval → 300 s
samplinghow many times a cycle checks each node (1–32)1
timeouttimeout of the destination request; "3s", "500ms" or a number of millisecondsthe group’s timeout → 5000 ms
connectivityan address checked DIRECT to see whether the device itself is onlineoff

Works in url-test, fallback, load-balance and smart. select makes no background checks: there the block only changes manual tests.

The field is Prizrak-Core’s only; mihomo does not have it.


  1. The delay, as before: a HEAD to url, with the global unified-delay. The numbers keep their usual scale.
  2. Then destination: the node is alive only when a 2xx/3xx answer comes within timeout and, with GET, the whole body arrives. A cut, a stall halfway or an error makes the node dead, even though its HEAD passed.
  3. A destination on the address of url goes over the same connection; when the site closed it, over a new one. A HEAD to url itself is not sent twice.

ping-config belongs to the group’s url. Every check of that url follows it: from any group, from a provider health-check on the same url, from the API and the apps. When two groups share a url with different blocks, the one higher in the config wins; the other is ignored with a warning in the log.


  • At start every node is checked at once.
  • Then a cycle lasts interval × sampling, and each node is checked sampling times at random moments of it — not all at once. At most 10 checks run together.
  • lazy and Prizrak-Box’s power saving on phones apply as to the usual checks.
  • A node in several groups or providers on the same url is checked once, not once for each.
  • A node just checked another way (a manual test, max-failed-times) is skipped once.
  • max-failed-times triggers an immediate check, by the profile too.

  • 1 — the last check decides, as before.
  • > 1 — a window of two cycles decides: the node is alive if any check in it succeeded, and its delay is the mean of the successful ones.

After a failed check the core makes one direct request past the VPN. With no answer the failure is not recorded, so a dropped Wi-Fi does not mark every node dead at once. The answer is cached for ~2 s.


The group’s testUrl stays the plain url, so dashboards (zashboard and others) and Prizrak-Box work unchanged. The group JSON gains a pingConfig object when its url has a profile.