Run Your Own Prober
Deploy a private prober inside your own infrastructure to monitor internal services and extend the global probe fleet.
Run Your Own Prober
Quick Reference
- Tier: Team or Enterprise plan required
- Connection: Single outbound wss:443 — no inbound ports needed
- wss URL: auto-derived from
API_COLLECTOR_URL(e.g.https://app.uptimehunt.io→wss://app.uptimehunt.io/v1/agent) - Token env var:
PROBE_TOKEN(falls back toAPI_COLLECTOR_TOKEN) - Container:
ghcr.io/uptimehunt/prober - Register: Settings → Probes → Add Probe
Overview
UptimeHunt operates a global probe fleet that monitors your services from multiple locations worldwide. Private probers let you extend that fleet with your own monitoring nodes — running inside your own infrastructure, data centre, or private network.
Why run a private prober?
- Monitor internal services (staging, VPNs, private APIs) that are unreachable from the public internet
- Add a monitoring location specific to your users, such as a region not yet covered by the platform fleet
- Validate how your service behaves from your own office network or data centre
- Supplement the global fleet with higher-frequency checks from a known location
Private probers are first-class citizens: their results flow through the same pipeline (realtime updates, history, incidents, alerts) as the platform fleet.
Requirements
| Requirement | Detail |
|---|---|
| Plan | Team or Enterprise — see pricing |
| Outbound network | Port 443/TCP only (HTTPS/WSS). No inbound ports required. |
| Runtime | Docker or Podman (any host that can run a container) |
| CPU / RAM | Minimal — ~50 MB RAM per prober under normal load |
Private probers are not available on Free or Pro plans. The registration UI shows an upsell card if your org is on a lower plan.
How It Works
A private prober maintains a single persistent WebSocket connection (over TLS, port 443) to the UptimeHunt broker. All communication is outbound from the prober — there are no inbound ports, no firewall holes, no public IP required on your side.
Connection lifecycle:
- Prober connects and sends a
helloframe containing its token. - The broker validates the token once (cached for the session), binds the connection to your org, and pushes the current check config (full desired state, including which services to monitor and their intervals).
- The prober persists the config to local disk and self-schedules using its own scheduler.
- Check results are streamed back to the broker, which validates authorship and forwards them to the internal pipeline.
- If the connection drops, the prober keeps running from its cached config and buffers results locally. On reconnect it receives a fresh config, then replays buffered results with their original timestamps — no data loss or duplicate counting, as long as the outage stays within the buffer's configured capacity (see Buffer size limit below).
Getting Started
1. Register a Private Prober
- Go to Settings → Probes in the UptimeHunt dashboard.
- Click Add Probe (disabled if your plan does not include private probers — see the upsell card for upgrade options).
- Fill in:
- Name — a label for this prober (e.g.
office-london,datacenter-eu-west) - Region / Location — optional expected geographic area
- Name — a label for this prober (e.g.
- Click Create.
Copy the token now
The connection token is shown only once immediately after creation. Copy it and store it in a secret manager. If you lose it, rotate to issue a new one — see Token Rotation.
2. Install and Run
Run the prober container with two environment variables:
PROBE_TOKEN— the token copied in the previous stepAPI_COLLECTOR_URL— the base URL of the UptimeHunt API (for the managed cloud this ishttps://app.uptimehunt.io)
podman run -d \
--name uptimehunt-prober \
--restart=always \
-e PROBE_TOKEN=your-token-here \
-e API_COLLECTOR_URL=https://app.uptimehunt.io \
ghcr.io/uptimehunt/proberdocker run -d \
--name uptimehunt-prober \
--restart=always \
-e PROBE_TOKEN=your-token-here \
-e API_COLLECTOR_URL=https://app.uptimehunt.io \
ghcr.io/uptimehunt/proberCreate /etc/systemd/system/uptimehunt-prober.service:
[Unit]
Description=UptimeHunt Private Prober
After=network-online.target
Wants=network-online.target
[Service]
Restart=always
RestartSec=5
Environment=PROBE_TOKEN=your-token-here
Environment=API_COLLECTOR_URL=https://app.uptimehunt.io
ExecStart=/usr/bin/podman run --rm --name uptimehunt-prober \
-e PROBE_TOKEN=${PROBE_TOKEN} \
-e API_COLLECTOR_URL=${API_COLLECTOR_URL} \
ghcr.io/uptimehunt/prober
[Install]
WantedBy=multi-user.targetEnable and start:
systemctl daemon-reload
systemctl enable --now uptimehunt-prober3. Verify the Connection
Go back to Settings → Probes. Your prober should show Online within a few seconds of starting. The Last contact timestamp updates with each heartbeat.
If the status stays Never connected, check the Troubleshooting section.
Connecting — How the wss URL is Derived
You do not set a separate WebSocket URL. The prober derives the broker address automatically from API_COLLECTOR_URL:
API_COLLECTOR_URL | Derived wss endpoint |
|---|---|
https://app.uptimehunt.io | wss://app.uptimehunt.io/v1/agent |
https://uptimehunt.example.com | wss://uptimehunt.example.com/v1/agent |
This means a single environment variable is all that is needed for both API connectivity and the broker WebSocket. No additional configuration is required.
Behaviour
Config Push
Check assignments are pushed to the prober over the WebSocket connection as a full desired-state config frame. The prober persists this config to a local SQLite file. Changes (new service, deleted service, updated interval) propagate within seconds of saving in the dashboard.
Self-Scheduling
The prober schedules checks entirely on its own from the cached config. It does not poll the API for tick instructions — it receives the config once (and again on change) and runs checks at the specified interval on its own clock. This is why the prober can keep running reliably during central downtime.
Downtime Buffering and Replay
If the prober loses its connection to the broker (network outage, broker restart, local reboot), it:
- Continues executing scheduled checks from the last-persisted config.
- Writes results to a local buffer queue (SQLite, path set by
QUEUE_DB_PATH— defaults to a path inside the container). - On reconnect, replays all buffered results to the broker with their original
@timestampvalues and stable per-result dedup IDs.
The pipeline (archiver, alert-engine, realtime) is designed to accept out-of-order, timestamped results, so a prober that was offline for an hour and then reconnects sends back ~N spaced check results without double-counting or false incident state.
Persist the buffer across container restarts
Mount a host directory for QUEUE_DB_PATH if you need the buffer to survive container restarts:
podman run -d \
--name uptimehunt-prober \
--restart=always \
-e PROBE_TOKEN=your-token-here \
-e API_COLLECTOR_URL=https://app.uptimehunt.io \
-e QUEUE_DB_PATH=/data/queue.db \
-v /var/lib/uptimehunt-prober:/data \
ghcr.io/uptimehunt/proberBuffer size limit
The result buffer is bounded to prevent unbounded disk usage, but the two caps are not equally reliable:
RESULT_QUEUE_MAX_ROWS(default: 50000) is a size-independent row cap that is always active. When the buffer exceeds this many rows, the oldest are discarded to make space for new ones. This is the bound you can rely on.RESULT_QUEUE_MAX_BYTES(default: 64 MiB / 67108864 bytes) is a best-effort on-disk byte cap. Reclaiming disk space this way only works if the prober's one-time SQLiteauto_vacuum=FULLmigration succeeded at startup — and that migration itself needs free disk roughly equal to the buffer database's current size to run. On a disk-constrained host (exactly the scenario this setting is meant for), that migration can fail, in which case the byte cap does nothing.
If your prober's logs show a result_queue.vacuum_failed or result_queue.bytecap_inactive warning, the byte cap is currently inactive on that prober — RESULT_QUEUE_MAX_ROWS is the only bound actually limiting buffer size. If your prober is expected to be offline for extended periods, size RESULT_QUEUE_MAX_ROWS for the outage you want to survive, and treat RESULT_QUEUE_MAX_BYTES as an additional safeguard rather than a guarantee:
-e RESULT_QUEUE_MAX_ROWS=100000
-e RESULT_QUEUE_MAX_BYTES=134217728 # 128 MiB — best-effort only, see aboveToken Rotation
If a token is compromised or you want to rotate it as a routine security practice:
Via the dashboard:
- Go to Settings → Probes.
- Click the menu ( ⋯ ) next to the prober.
- Select Rotate token.
- Copy the new token — it is shown only once.
- Update the
PROBE_TOKENenv var on your prober host and restart the container.
Via the API:
curl -X POST "https://app.uptimehunt.io/api/v1/probes/{id}/token" \
-H "Authorization: Bearer <your-jwt-token>" \
-H "Content-Type: application/json"The old token is immediately invalidated. The broker force-drops any live connection using it.
The live connection drops instantly
Rotating a token disconnects the running prober immediately. The prober reconnects with the new token automatically only if PROBE_TOKEN has been updated on the host first. Until it reconnects, checks continue from cached config and results buffer locally.
Probe Visibility
By default, private probers are not visible to the public (they show only to authenticated members of your organization). The public field on a probe controls this — it defaults to false for private probers.
If you want the probe to appear in the public probe list (e.g. to contribute a new location to the community view), set public: true via the dashboard or API.
Troubleshooting
Status shows "Never connected" or "Offline"
-
Check outbound connectivity to port 443. From the prober host, try:
curl -I https://app.uptimehunt.io/healthzYou should get a
200 OKresponse. If this fails, your network is blocking outbound HTTPS. -
Verify the token. Confirm
PROBE_TOKENmatches the token displayed at registration. Tokens are 32+ characters. Whitespace or newlines in the env var cause auth failures. -
Check container logs:
podman logs uptimehunt-proberLook for
connectedorauthentication failedmessages. -
Corporate proxy. If your network requires an HTTP proxy for outbound traffic, set
HTTPS_PROXYorALL_PROXY:-e HTTPS_PROXY=http://proxy.corp.example.com:3128The WebSocket upgrade travels over HTTPS and most corporate proxies pass it through. If your proxy blocks WebSocket upgrades, contact your network team — the connection must reach
wss://app.uptimehunt.io/v1/agenton port 443. -
Only outbound 443 is needed. There is no inbound port requirement. Firewalls only need to allow the prober to reach
app.uptimehunt.io:443outbound.
Status shows "Online" but I see no check results
- The prober only runs checks that are assigned to your organization. Create a service in the dashboard first.
- The prober must receive a config push for the check to run. This happens automatically within seconds of creating a service, but verify the prober is online at the moment the service is created.
- Check that the service is enabled in the dashboard.
Prober runs but results are missing after a restart
Mount the buffer queue to a persistent host path — see Downtime Buffering and Replay. Without a persistent mount, a container restart discards any buffered results from the offline window.
Related Documentation
Global Probe Network
UptimeHunt's global probe network monitors your services from multiple geographic locations worldwide. Learn how probes work, view the fleet, and run your own.
Kubernetes Auto-Discovery
Automatically turn Kubernetes Ingress resources into UptimeHunt monitoring checks using the auto-discovery operator.