Skip to content

Overview

Arael Espinosa edited this page Jul 13, 2026 · 2 revisions

Overview

Piro is an open-source uptime monitoring and status page platform. It continuously runs checks against your services, computes their health, and publishes the results to a public-facing status page — giving your users real-time visibility into your infrastructure.

Motivation

Most monitoring tools are either too heavy (full observability stacks) or too simple (single-URL ping services). Piro is designed to sit in between: a self-hosted, production-grade uptime monitor with a clean public status page, multi-region support, and flexible alerting — without requiring a complex setup.

The core idea is simple: define what you're monitoring, let Piro run the checks, and trust that your users are seeing accurate status.


Core Concepts

Service

A Service represents anything you want to monitor — a web app, an API, a database, a third-party dependency, or any infrastructure component. Services are what your users see on the public status page.

A service doesn't have a fixed status. Its status is computed from the checks attached to it — you never set it manually. If all checks are passing, the service is UP. If any check fails, the service reflects that accordingly.

Services can also depend on each other. If Service A depends on Service B and B goes down, A's status can automatically reflect that degradation.

Check

A Check is a single monitoring probe attached to a service. It runs on a configurable cron schedule and tests one specific thing: can we reach this URL? Does this DNS record resolve correctly? Is this TCP port open?

Each check has a type that determines how it runs:

Type What it tests
HTTP HTTP/HTTPS endpoint availability and response
DNS DNS record resolution (A, AAAA, CNAME)
TCP TCP port connectivity
Ping ICMP reachability
SSL TLS certificate validity and expiry
Heartbeat Passive — waits for your service to ping Piro
GCP Cloud Run Job Last execution status of a GCP Cloud Run Job

A service can have multiple checks. For example, you might have an HTTP check on your API's /health endpoint and a DNS check on your domain — both feeding into the same service's status.

Check Status

Every check execution produces one of the following statuses:

Status Meaning
UP The check passed — the service is healthy
DEGRADED The check passed, but with elevated latency or partial failure
DOWN The check failed — the service is unreachable or returning errors
MAINTENANCE The service is in a scheduled maintenance window
NO_DATA No data available yet (new check, or default status while waiting for first result)
FAILURE The check executor itself crashed (misconfiguration, internal error) — not a service outage; only visible in the admin panel

FAILURE is intentionally hidden from the public status page. If a check is misconfigured (e.g. an empty host, invalid name server, missing integration), it shows as NO_DATA to your users rather than falsely reporting a service outage.

Service Status

A service's status is automatically computed from all its checks using a priority order:

MAINTENANCE > DOWN > DEGRADED > UP > NO_DATA

The highest-priority status among all checks wins. So if one check is DOWN and three others are UP, the service is DOWN.

Service Dependencies

Services can declare dependencies on each other, forming a directed acyclic graph (DAG). When an upstream service degrades, the dependent service's status can automatically reflect that — without having to configure duplicate checks.

There are three propagation modes:

Mode Behavior
Blocking Full status cascades — if upstream is DOWN, dependent becomes DOWN
SoftBlocking Status cascades but caps at DEGRADED — downstream never goes DOWN due to this dependency alone
Advisory Visual indicator only — no status impact

Alerting

Alert Config

An Alert Config defines a threshold rule for a check: "fire a notification if this check has been DOWN for 3 consecutive minutes." You configure:

  • What metric to watch: Status, Latency, or Uptime
  • The threshold value: a status name, a latency in ms, or an uptime percentage
  • Failure threshold: how many consecutive failures before the alert fires
  • Recovery threshold: how many consecutive successes before the alert auto-resolves

Alerts are stateful — once fired, they don't re-fire until they recover and trigger again. Alerts are also suppressed when a check returns FAILURE (executor error), since that's not a real outage.

Notification Channels

A Notification Channel is a delivery endpoint for alerts. When an alert fires or recovers, Piro dispatches a message to all channels linked to that alert config.

Supported channel types:

Email · Telegram · Twilio SMS · Opsgenie · Pushover · Ntfy

Channels can be marked as global (auto-linked to all new alert configs) or locked (cannot be removed by regular users).

⚠️ Not currently supported: Webhook, Slack, Discord, Google Chat, and Microsoft Teams exist as trigger types in the codebase but are not registered as active dispatchers — selecting them will not deliver any notification. See Triggers for details.


Incidents & Maintenance

Incidents

An Incident is a manually declared service disruption. When something goes wrong that checks alone don't fully capture, you create an incident to communicate the situation to your users via the status page.

Incidents track an investigation state machine:

Investigating → Identified → Monitoring → Resolved

Each state transition is logged as a comment, creating a timestamped audit trail. Incidents are private by default — nothing is shown on the public status page until someone explicitly publishes it.

Incidents can affect specific services or be marked as global (affecting all services). Each affected service gets an impact level (DOWN, DEGRADED, etc.) that influences what users see.

Alerts never auto-create or auto-attach to incidents. Linking an Alert to an incident (new or existing) is always an explicit action taken from the Alerts panel. See Concepts-Alerts and Concepts-Incidents for details.

Maintenance

A Maintenance window declares planned downtime for one or more services. Maintenance windows:

  • Suppress alerts during the window (no false notifications)
  • Inject synthetic MAINTENANCE data points into the time series (preserving uptime history accuracy)
  • Support recurring schedules via iCalendar RRULE (e.g. "every Monday at 02:00")
  • Show up on the public status page so users know downtime is expected

Workers & Multi-Region

By default, Piro runs checks in-process within the API. For multi-region setups, you can connect additional Worker instances in different geographic locations.

Workers connect to the API via SignalR. When a check has multi-region enabled, it dispatches simultaneously to all connected workers. Results from each worker are stored independently (per-worker, per-minute) and then aggregated to compute the final check status.

This lets you detect regional outages: if your API is reachable from Europe but not from the US, Piro can reflect that as DEGRADED rather than ignoring the partial failure.


Public Status Page vs Admin Panel

Piro has two distinct interfaces:

Public Status Page (apps/web) — The Next.js status page your users see. It shows service health, uptime history, active incidents, and upcoming maintenance. It is fully public and requires no authentication. FAILURE statuses are hidden; check-level detail is optional per service.

Admin Panel (apps/admin) — The React SPA for your team. It exposes the full configuration: services, checks, alert configs, notification channels, incidents, maintenance windows, workers, integrations, and users. All internal statuses including FAILURE are visible here.

Clone this wiki locally