Multi-region checks
Check one monitor from several places in the world, so a bad route or a regional outage does not look like your site being down, and so you can see how fast it is for people far from you.
Overview
By default a monitor is checked from where OpenUptime itself runs. That location is called auto. A region is an extra place a check can be sent from, served by a small probe that runs in that place. Regions are opt-in: a monitor uses them only when you pick regions for it, and everything else keeps running exactly as before.
- HTTP and TCP monitors only. DNS, heartbeat and database monitors always run from
auto. - One monitor can list several regions. A monitor with a single non-
autoregion is checked from that region alone. - Each region counts as one check of your allowance, so three regions cost three times as much per run.
Using regions
- Open a monitor (or create one) and find Check from. It lists the regions this deployment offers, with Auto first. The field only appears when at least one region besides
autois configured. - Tick the regions you want. On the hosted service the limit shown next to the label depends on your plan; a self-hosted deployment has no limit, so a monitor can use every region you have configured.
- Save. The next scheduled run goes out from every region you picked. The estimate on the form multiplies the number of checks per month by the number of regions.
A saved region that has since been removed from the deployment is shown as No longer available. Untick it and save, or the monitor keeps skipping it.
How a verdict is reached
A monitor has one status, so the results from its regions are folded into one result per run:
- The run fails when a strict majority of the regions that answered failed. With three regions, two failures fail the run and one does not. A tie counts as up, so one region's bad route does not open an incident.
- The run's latency is the mean of the regions that succeeded.
- The usual failure threshold and alert rules then apply to that single result, the same as for any other monitor.
- When the run fails, the incident reads Failed from 2 of 3 regions (eu-central: connection timed out), so you can see where it broke.
When a probe itself is down
A probe that cannot be reached, refuses the request or answers nonsense says nothing about your service, so it is left out of the vote instead of counted as a failure. If no probe answers at all, the check falls back to auto so that a probe outage can never leave a monitor blind. You will see the probe problem in the API's logs, not as a downtime of your monitor.
What you see on the monitor
- Regions card: uptime and average latency for each region over the last 24 hours, in the order you configured them.
- Recent checks has a Region column, so every raw result is attributed to the place it came from.
- Configuration lists the regions the monitor uses.
- Public status pages are unchanged. They show the monitor's single, combined status.
Test once from a region
Under Test once from on the monitor page, pick a region to send a single request from there. It is a diagnostic: you get the result straight away, nothing is recorded and the monitor's status does not change. It uses one check of your allowance. It is handy for "is it slow in Asia, or just for this customer?".
curl -X POST https://openuptime.app/api/monitors/<id>/check \
-H "x-api-key: ou_..." -H "Content-Type: application/json" \
-d '{"region":"eu-central"}'
{ "ok": true, "region": "eu-central",
"result": { "ok": true, "statusCode": 200, "latencyMs": 184 } }Without a body, the same endpoint runs the monitor's own regions and records the result. See the API reference for the error codes (unknown_region, regions_not_supported, regions_not_allowed, probe_unreachable).
How it works
scheduler ──signed POST──▶ probe (eu-central) ──▶ your target
──signed POST──▶ probe (us-east) ──▶ your target
◀──── { ok, statusCode, latencyMs, error } ────The scheduler sends the check (type, target, method, expected status, keyword, timeout and headers) to each probe over HTTPS. The probe runs it and answers with the outcome. Probes are stateless: they store nothing and hold no database credentials.
Requests are signed with HMAC-SHA256 over timestamp.body using a shared secret (PROBE_SECRET), and a timestamp more than 60 seconds off is rejected, so a captured request cannot be replayed later. Without a valid signature a probe would be an open proxy, so it answers 401. A probe also refuses private and internal addresses whatever the signature says, so it cannot be used to reach into someone's network.
Running your own probes
On the hosted service the available regions are already set up. When you self-host, you run the probes yourself. A probe is the small app in apps/probe, and it runs anywhere you can run Node:
| Where | How |
|---|---|
| Docker, any VPS | From a checkout of the repository: docker build -f apps/probe/Dockerfile -t openuptime-probe ., then docker run -d -p 8787:8787 -e PROBE_SECRET=… -e PROBE_REGION=sao-paulo openuptime-probe. The port speaks plain HTTP, so put HTTPS in front of it. apps/probe/docker-compose.yml does both for you and can add automatic HTTPS with Caddy: PROBE_DOMAIN=probe.example.com docker compose --profile tls up -d. |
| Plain Node 22 | From the repository root: pnpm install and pnpm --filter @openuptime/probe build:node, then PROBE_SECRET=… PROBE_REGION=sao-paulo node apps/probe/dist/server.mjs. It listens on port 8787 (PORT changes it) and needs HTTPS in front, like the Docker image. |
| Vercel | In apps/probe: pnpm build:vercel builds one function per region of regions.json, each pinned to a Vercel region. Run vercel link once and set PROBE_SECRET on the project, then vercel deploy --prebuilt --prod. Each region answers at https://<project>.vercel.app/api/probe/<id>. Running in several regions needs a paid Vercel plan. |
Run one probe per place you want to check from, in the countries that matter to your users. Any provider works, so a small VM in São Paulo, Mumbai or Sydney is as good as a Vercel region.
Then tell the API where the probes are. Set the same PROBE_SECRET on the API and on every probe, and list the regions as JSON in PROBE_REGIONS:
PROBE_SECRET=a-long-random-string
PROBE_REGIONS={
"us-east": "https://probe.example.app/api/probe/us-east",
"eu-central": { "url": "https://probe.example.app/api/probe/eu-central", "name": "Frankfurt" },
"sao-paulo": { "url": "https://probe-sao.example.com/", "name": "São Paulo" }
}- The key is a region id you choose: lowercase letters, digits and dashes, 2 to 24 characters, not
auto. It is what monitors store, so keep it stable. Renaming an id later means re-saving the monitors that use it. - A value is a URL, or
{ "url", "name" }to set the label shown in the app. Bare ids likeus-eastandeu-centralget a readable name. - URLs must be
https. Plainhttpis accepted forlocalhostonly. - With
PROBE_REGIONSset but noPROBE_SECRET, regions stay disabled and a warning is logged.
Check a probe with a plain GET: curl https://your-probe/ on Docker and Node, or curl https://<project>.vercel.app/api/probe/eu-central on Vercel, where the root path is a 404. It answers {"ok":true,"region":"…"} with the probe's PROBE_REGION label (the Vercel region code, such as fra1, on Vercel). The list the app offers is at GET /api/regions. Full deployment details are in the self-hosting guide.
Good to know
- International regions only. The bundled Vercel build covers regions outside mainland China. To check from inside mainland China, run a probe on a host there yourself.
- Probes only make outbound requests. They never see your monitors' stored secrets, and database checks stay on
autoso credentials are never sent to a probe. - Private and internal targets (
10.x,localhostand so on) are refused by every probe. To watch something inside your network, run a probe inside it and setALLOW_PRIVATE_TARGETS=trueon that probe only. - Set the same
CHECK_USER_AGENTon the API and the probes so your target sees one consistent client.
多区域检测
让同一个监控项从世界上的多个地方发起检测:线路问题或某个地区的故障不会被误判为你的网站宕机,也能看出远离你的用户访问有多快。
概览
默认情况下,监控项从 OpenUptime 自身所在的位置发起检测,这个位置叫 auto。区域则是检测请求可以额外发出的地点,由运行在该地点的一个小型探针提供。区域是显式开启的:只有你为监控项选了区域,它才会用到,其余监控项和以前完全一样。
- 仅适用于 HTTP 和 TCP 监控项。DNS、心跳和数据库监控项始终从
auto发起。 - 一个监控项可以选多个区域。只选一个非
auto区域时,仅从该区域检测。 - 每个区域各计一次检查额度,因此三个区域每轮消耗三倍额度。
如何使用
- 打开监控项(或新建),找到检查位置。它列出当前部署提供的区域,Auto 排在最前。只有配置了
auto之外的区域,这个字段才会出现。 - 勾选想用的区域,不超过标签旁显示的上限。托管服务的上限取决于套餐;自托管时,一个监控项最多可选 10 个区域。
- 保存。之后每次定时检测都会从你选的所有区域同时发出。表单上的月度估算会按区域数乘以检查次数。
已保存、但后来从部署中移除的区域会显示为不再可用。取消勾选并保存即可,否则监控项会一直跳过它。
如何得出结论
一个监控项只有一个状态,因此各区域的结果会合并成每轮的一个结果:
- 当多数(严格多于一半)应答的区域失败时,这一轮才判定失败。三个区域时,两个失败即失败,一个失败不算。平局算正常,所以单个区域的线路问题不会产生事件。
- 这一轮的延迟取成功区域的平均值。
- 之后照常应用失败阈值和告警规则,与其他监控项一样。
- 失败时,事件原因类似Failed from 2 of 3 regions (eu-central: connection timed out),能看出是哪里出了问题。
探针本身不可用时
探针连不上、拒绝请求或返回无法理解的内容,说明不了你的服务有问题,所以它会被排除在投票之外,不会算作失败。如果没有任何探针应答,检测会回退到 auto 执行,因此探针故障永远不会让监控“失明”。探针的问题会出现在 API 的日志里,而不是记为你监控项的宕机。
在监控项上看到什么
- 区域卡片:按你配置的顺序,显示每个区域最近 24 小时的可用率和平均延迟。
- 最近检查多了区域列,每条原始结果都标明来自哪里。
- 配置里列出该监控项使用的区域。
- 公开状态页不变,仍显示监控项合并后的单一状态。
从某个区域单次测试
在监控项页面的单次测试位置下选一个区域,就会从那里发出一次请求。这是诊断功能:立即返回结果,不会记录,也不会改变监控状态,消耗 1 次检查额度。适合排查“亚洲是不是变慢了,还是只有这个客户的问题”。
curl -X POST https://openuptime.app/api/monitors/<id>/check \
-H "x-api-key: ou_..." -H "Content-Type: application/json" \
-d '{"region":"eu-central"}'
{ "ok": true, "region": "eu-central",
"result": { "ok": true, "statusCode": 200, "latencyMs": 184 } }不带请求体时,同一接口会按监控项自己的区域执行并记录结果。错误码(unknown_region、regions_not_supported、regions_not_allowed、probe_unreachable)见 API 参考。
工作原理
调度器 ──签名 POST──▶ 探针 (eu-central) ──▶ 你的目标
──签名 POST──▶ 探针 (us-east) ──▶ 你的目标
◀──── { ok, statusCode, latencyMs, error } ────调度器通过 HTTPS 把检测内容(类型、目标、方法、期望状态码、关键字、超时和请求头)发给每个探针,探针执行后返回结果。探针是无状态的:不保存任何数据,也不持有数据库凭据。
请求使用共享密钥(PROBE_SECRET)对 timestamp.body 做 HMAC-SHA256 签名,时间戳与探针时钟相差超过 60 秒会被拒绝,因此截获的请求之后无法重放。没有有效签名,探针就成了开放代理,所以会返回 401。探针还会无视签名,始终拒绝私有和内网地址,因此不能被用来探测别人的内网。
运行你自己的探针
托管服务的可用区域已经配置好。自托管时,探针需要你自己运行。探针就是 apps/probe 里的小应用,能跑 Node 的地方都能运行:
| 位置 | 方式 |
|---|---|
| Docker、任意 VPS | 在仓库的检出目录中:docker build -f apps/probe/Dockerfile -t openuptime-probe .,然后 docker run -d -p 8787:8787 -e PROBE_SECRET=… -e PROBE_REGION=sao-paulo openuptime-probe。该端口是明文 HTTP,需要在前面放一层 HTTPS。apps/probe/docker-compose.yml 把这些都包好了,还能用 Caddy 自动加上 HTTPS:PROBE_DOMAIN=probe.example.com docker compose --profile tls up -d。 |
| 原生 Node 22 | 在仓库根目录:pnpm install 和 pnpm --filter @openuptime/probe build:node,然后 PROBE_SECRET=… PROBE_REGION=sao-paulo node apps/probe/dist/server.mjs。默认监听 8787 端口(用 PORT 修改),和 Docker 镜像一样需要在前面放 HTTPS。 |
| Vercel | 在 apps/probe 里:pnpm build:vercel 会按 regions.json 为每个区域生成一个函数,各自固定在一个 Vercel 区域。先运行一次 vercel link 并在项目上设置 PROBE_SECRET,再 vercel deploy --prebuilt --prod。每个区域的地址是 https://<project>.vercel.app/api/probe/<id>。在多个区域运行需要付费的 Vercel 套餐。 |
想从哪些地方检测,就在那里各运行一个探针,选你的用户所在的国家和地区。任何服务商都行,圣保罗、孟买或悉尼的一台小型虚拟机,和 Vercel 的一个区域一样好用。
然后告诉 API 探针在哪。在 API 和每个探针上设置相同的 PROBE_SECRET,并用 JSON 在 PROBE_REGIONS 中列出区域:
PROBE_SECRET=一串足够长的随机字符串
PROBE_REGIONS={
"us-east": "https://probe.example.app/api/probe/us-east",
"eu-central": { "url": "https://probe.example.app/api/probe/eu-central", "name": "法兰克福" },
"sao-paulo": { "url": "https://probe-sao.example.com/", "name": "圣保罗" }
}- 键是你自己定的区域 id:小写字母、数字和连字符,2 到 24 个字符,不能是
auto。监控项保存的就是它,请保持稳定。之后改 id,就需要重新保存用到它的监控项。 - 值可以是 URL,或
{ "url", "name" }以设置在应用中显示的名称。us-east、eu-central这类 id 会自动得到易读的名称。 - URL 必须是
https,只有localhost允许用http。 - 设置了
PROBE_REGIONS却没有PROBE_SECRET时,区域保持禁用并输出警告日志。
用一次普通的 GET 检查探针:Docker 和 Node 用 curl https://your-probe/;Vercel 的根路径是 404,请用 curl https://<project>.vercel.app/api/probe/eu-central。它会返回 {"ok":true,"region":"…"},其中是探针的 PROBE_REGION 标签(在 Vercel 上是 Vercel 区域代码,如 fra1)。应用提供的区域列表在 GET /api/regions。完整部署说明见自托管指南。
需要了解
- 仅限国际区域。自带的 Vercel 构建只覆盖中国大陆以外的区域。要从中国大陆境内检测,需要你自己在那里的主机上运行探针。
- 探针只发出站请求,看不到监控项保存的密钥;数据库检测始终留在
auto,凭据不会发给探针。 - 所有探针都会拒绝私有和内网目标(
10.x、localhost等)。要监控内网里的东西,请在内网中运行探针,并只在该探针上设置ALLOW_PRIVATE_TARGETS=true。 - 在 API 和探针上设置相同的
CHECK_USER_AGENT,让目标看到一致的客户端。
Last updated 2026-10-12最后更新:2026-10-12