config.example.yml
Rama main · réplica de lectura del repositorio original.
# IsItDown — Light edition configuration.
#
# Copy this file to config.yml and edit it. In the container it is mounted at
# /app/config/config.yml, so it can be changed without rebuilding the image.
#
# Secrets are NEVER written here. Use ${ENV_VAR} references; the values come
# from the environment (see .env.example).
pollIntervalMinutes: 3 # how often to poll every provider
requestTimeoutSeconds: 8 # per-request timeout
maxRetries: 3 # attempts per provider per cycle, with backoff
failureThreshold: 5 # consecutive failures before a "monitoring degraded" warning
adaptivePolling: true # while a provider has an open incident, poll it on the cadence below
adaptiveIntervalMinutes: 1 # that cadence; never slower than the provider's own interval
confirmSamples: 1 # consecutive polls that must agree before a change notifies (1 = off)
# Correlated-outage detection (roadmap 2.7): when this many providers go bad
# inside the window below, one "this looks like a shared failure" alert replaces
# the individual ones. 0 and 1 are off, which is the default — it is the only
# setting here that replaces alerts rather than adding them.
correlationThreshold: 0
correlationWindowMinutes: 10
locale: en # language for notification messages: en | it (falls back to en)
services:
- name: GitHub
id: github
adapter: statuspage
baseUrl: https://www.githubstatus.com
# Optional: poll this provider on its own cadence instead of the global
# pollIntervalMinutes above. A page that publishes every few minutes and one
# that changes twice a year do not deserve the same one. Omit to follow the
# global interval.
intervalMinutes: 2
# Optional: the group this provider belongs to — "my stack". Providers in
# the same group get a combined status (worst member wins), and one routing
# rule below can cover all of them with `provider: group:deploy-path`. A
# lowercase slug; omit it to leave the provider ungrouped.
group: deploy-path
# Optional: the monthly uptime this provider is supposed to deliver, as a
# percentage. The UI edition turns it into an error budget, reports what the
# month has spent of it, and sends one alert when the rate says the month
# will miss. Omit it when nobody promised anything — most providers.
slaTarget: 99.9
# Optional: what an hour of this provider being down costs you, in your own
# currency. Shown beside each incident, in the reliability table and in the
# monthly report. Omit it and no figure is shown — an unpriced outage is not
# a free one.
outageCostPerHour: 1200
# Optional: what breaks here when this provider does, and who answers for
# it. Both are added under every message about it, so an alert at 3 a.m.
# reads as a handover note.
impact: deploys blocked, CI stopped
owner: "@alice"
# Optional: what to do when it is down, in Markdown. Shown on the provider's
# page; every alert ends with its first link, or its first line.
runbook: |
Switch CI to the GitLab mirror: https://wiki.example.com/runbooks/github
# Optional: free labels beside the group. A routing rule can name one as
# `provider: tag:critical`.
tags: [paid, critical]
# Optional: planned mutes — a weekly window (may wrap midnight) or one span.
# While one runs the provider is muted exactly like the dashboard's Mute.
muteSchedules:
- { days: [sun], start: "03:00", end: "04:00", timeZone: Europe/Rome }
# Optional: maintenance you declare because the provider does not. It
# silences, is announced and is drawn on the timeline like the provider's
# own; it always needs an end.
# maintenanceWindows:
# - { title: Our deploy, startsAt: "2026-12-01T22:00:00Z", endsAt: "2026-12-01T23:00:00Z" }
- name: Cloudflare
id: cloudflare
adapter: statuspage
baseUrl: https://www.cloudflarestatus.com
group: deploy-path
# Optional: watch only part of a provider. Component ids come from
# <baseUrl>/api/v2/summary.json, where Cloudflare groups its data centres by
# region. With scopeToComponents an incident attributed only to components
# outside this list is ignored, and the reported status is the worst of these
# components rather than the page-wide indicator. A notice the provider
# attaches to no component at all is page-wide and always reported.
scopeToComponents: true
components:
- id: 57ctn3f2qsyj
name: Amsterdam, Netherlands - (AMS)
- id: k8q1kmz4gfms
name: Milan, Italy - (MXP)
- name: Anthropic
id: anthropic
adapter: statuspage
# status.anthropic.com 301-redirects here; the canonical host avoids the hop
baseUrl: https://status.claude.com
# A page that publishes neither JSON nor a feed: read one element's text and
# map the words onto a severity. Fragile by nature — a selector that stops
# matching is reported as a failing provider, never as "operational" — so use
# it only where there is nothing better.
#
# - name: Example
# id: example
# adapter: html
# baseUrl: https://status.example.com/
# options:
# selector: ".status-banner"
# # Optional. Each severity keeps its built-in words unless you give it
# # your own; on the page, the longest match wins.
# operational: "all systems operational"
# major_outage: "outage, down"
# A probe of the service itself rather than of a page about it. Here it is
# also the second opinion on GitHub's own status page: when this probe cannot
# reach the API and githubstatus.com still reports operational with no
# incident open, the disagreement is itself an alert — the silent-outage
# cross-check.
#
# - name: GitHub API
# id: github-api
# adapter: http
# baseUrl: https://api.github.com
# crossChecks: github
# options:
# path: /meta
# expectStatus: "200-299"
#
# Which source is the record for a provider — `declared` (its own status page)
# or `observed` (our own reading), roadmap 9.1. Left out, which is the normal
# case, the adapter decides: a probe is `observed` because it *is* the
# reading, and anything that parses somebody's page is `declared`. Set it only
# to disagree with that default.
#
# - name: Acme
# id: acme
# adapter: statuspage
# baseUrl: https://status.acme.example
# authority: observed
notifications:
telegram:
enabled: true
botToken: "${TELEGRAM_BOT_TOKEN}"
chatId: "${TELEGRAM_CHAT_ID}"
# Optional, per channel (roadmap 3.20 and 3.15). `locale` overrides the
# notification language above for this channel alone — so this chat can read
# Italian while the webhook payload below stays English. `template` replaces
# the default message: substitution only, no conditions and no loops, and an
# unknown token stops the container with the token named. See
# docs/configuration.md#311-per-channel-locale-and-template for the tokens.
# locale: it
# template: "[{{severity}}] {{provider}} — {{title}}\n{{url}}"
webhook:
enabled: false
url: "${WEBHOOK_URL}"
# Optional. With a secret set, every request carries X-IsItDown-Timestamp
# and X-IsItDown-Signature (HMAC-SHA256 over "<timestamp>.<body>"), so a
# receiver can verify the payload came from here. Unset means unsigned.
secret: "${WEBHOOK_SECRET}"
discord:
enabled: false
# Server settings → Integrations → Webhooks → Copy Webhook URL
webhookUrl: "${DISCORD_WEBHOOK_URL}"
slack:
enabled: false
# An incoming webhook of a Slack app installed in the target channel
webhookUrl: "${SLACK_WEBHOOK_URL}"
ntfy:
enabled: false
# The topic URL, server included — ntfy.sh or an instance of your own
topicUrl: "${NTFY_TOPIC_URL}"
# Optional: only a server with access control needs a token
token: "${NTFY_TOKEN}"
gotify:
enabled: false
# The server itself, not a message path
serverUrl: "${GOTIFY_URL}"
# An application token, from the Gotify app you created for IsItDown
token: "${GOTIFY_TOKEN}"
pushover:
enabled: false
# The API token of the Pushover application you created for IsItDown
token: "${PUSHOVER_TOKEN}"
# Your user key, or a group key, from the Pushover dashboard
userKey: "${PUSHOVER_USER_KEY}"
# Optional: one registered device; empty delivers to every device
device: "${PUSHOVER_DEVICE}"
matrix:
enabled: false
# The homeserver's root, not a room path
homeserverUrl: "${MATRIX_HOMESERVER_URL}"
# The internal room id, not an alias: !abc:example.org
roomId: "${MATRIX_ROOM_ID}"
# An access token for the user that posts
accessToken: "${MATRIX_ACCESS_TOKEN}"
pagerduty:
enabled: false
# The integration key of an Events API v2 integration on a service. An
# incident that resolves closes the alert it opened, keyed on the change.
routingKey: "${PAGERDUTY_ROUTING_KEY}"
# Optional: "eu" for an account in PagerDuty's EU service region
region: "${PAGERDUTY_REGION}"
opsgenie:
enabled: false
# An API key from an Opsgenie API integration
apiKey: "${OPSGENIE_API_KEY}"
# Optional: "eu" for an account on Opsgenie's EU instance
region: "${OPSGENIE_REGION}"
apprise:
enabled: false
# An Apprise API server, which reaches the ~80 services Apprise knows
serverUrl: "${APPRISE_SERVER_URL}"
# Either the key of a configuration the server stores (preferred — the
# service URLs behind it are credentials) ...
configKey: "${APPRISE_CONFIG_KEY}"
# ... or the Apprise URLs themselves, comma-separated, for a stateless
# server. One of the two is required.
urls: "${APPRISE_URLS}"
teams:
enabled: false
# A Teams channel webhook: Workflows → "Post to a channel when a webhook
# request is received", or an Office 365 connector on an older tenant
webhookUrl: "${TEAMS_WEBHOOK_URL}"
email:
enabled: false
# An SMTP submission server. STARTTLS is used whenever the server offers it.
host: "${SMTP_HOST}"
# Optional, 587 by default. 465 is implicit TLS and is treated as such.
port: "${SMTP_PORT}"
# Optional: "true" forces TLS from the first byte, as on port 465
secure: "${SMTP_SECURE}"
# Optional. Credentials are never sent over an unencrypted connection
# unless this says "true" — meant for a relay on this machine.
allowInsecureAuth: "${SMTP_ALLOW_INSECURE_AUTH}"
# Optional: "true" accepts a certificate no public CA signed
allowSelfSigned: "${SMTP_ALLOW_SELF_SIGNED}"
# Optional: a relay that trusts this network needs no credentials
username: "${SMTP_USERNAME}"
password: "${SMTP_PASSWORD}"
from: "${SMTP_FROM}"
# One address, or several separated by commas
to: "${SMTP_TO}"
# On-call chains (roadmap 3.9). Like PagerDuty and Opsgenie, each keys its
# alert on the change, so a provider's own "resolved" closes what it opened.
splunk-oncall:
enabled: false
# The REST endpoint integration's API key, and the routing key that picks
# the escalation policy
apiKey: "${SPLUNK_ONCALL_API_KEY}"
routingKey: "${SPLUNK_ONCALL_ROUTING_KEY}"
squadcast:
enabled: false
# An Incident Webhook integration's URL
webhookUrl: "${SQUADCAST_WEBHOOK_URL}"
zenduty:
enabled: false
# An API integration's key
integrationKey: "${ZENDUTY_INTEGRATION_KEY}"
incident-io:
enabled: false
# An HTTP alert source: its config id and its bearer token
alertSourceId: "${INCIDENT_IO_ALERT_SOURCE_ID}"
token: "${INCIDENT_IO_TOKEN}"
grafana-oncall:
enabled: false
# A Formatted Webhook integration's URL
webhookUrl: "${GRAFANA_ONCALL_WEBHOOK_URL}"
# Team chat through each server's API, so an incident's updates edit the
# message they belong to instead of adding one each.
mattermost:
enabled: false
serverUrl: "${MATTERMOST_URL}"
# A bot account's access token, and the channel's id (not its name)
token: "${MATTERMOST_TOKEN}"
channelId: "${MATTERMOST_CHANNEL_ID}"
rocketchat:
enabled: false
serverUrl: "${ROCKETCHAT_URL}"
# The bot user's id and a personal access token of it, and the room's id
userId: "${ROCKETCHAT_USER_ID}"
token: "${ROCKETCHAT_TOKEN}"
roomId: "${ROCKETCHAT_ROOM_ID}"
zulip:
enabled: false
siteUrl: "${ZULIP_SITE_URL}"
botEmail: "${ZULIP_BOT_EMAIL}"
apiKey: "${ZULIP_API_KEY}"
# The channel ("stream") to post in
stream: "${ZULIP_STREAM}"
# Optional: one fixed topic. Unset, each provider gets a topic of its own.
topic: "${ZULIP_TOPIC}"
google-chat:
enabled: false
# A space's incoming webhook. An incident's messages share one thread.
webhookUrl: "${GOOGLE_CHAT_WEBHOOK_URL}"
# Phones. Numbers are E.164 (+39...). Route only what is worth waking up
# for to the call — a rule with minSeverity: major_outage.
twilio-sms:
enabled: false
accountSid: "${TWILIO_SMS_ACCOUNT_SID}"
authToken: "${TWILIO_SMS_AUTH_TOKEN}"
from: "${TWILIO_SMS_FROM}"
to: "${TWILIO_SMS_TO}"
twilio-call:
enabled: false
accountSid: "${TWILIO_CALL_ACCOUNT_SID}"
authToken: "${TWILIO_CALL_AUTH_TOKEN}"
from: "${TWILIO_CALL_FROM}"
to: "${TWILIO_CALL_TO}"
bark:
enabled: false
# The device key the Bark iOS app shows
deviceKey: "${BARK_DEVICE_KEY}"
# Optional: a self-hosted bark-server. Unset means https://api.day.app
serverUrl: "${BARK_SERVER_URL}"
signal:
enabled: false
# A signal-cli-rest-api server, which holds the account's keys
serverUrl: "${SIGNAL_API_URL}"
# The registered number to send from, and who receives: numbers or
# group.… ids, comma-separated
number: "${SIGNAL_NUMBER}"
recipients: "${SIGNAL_RECIPIENTS}"
# Machines.
syslog:
enabled: false
# udp://host:514, tcp://host:601 or tls://host:6514 — RFC 5424 messages
url: "${SYSLOG_URL}"
# Optional: local0 (the default) to local7
facility: "${SYSLOG_FACILITY}"
mqtt:
enabled: false
# mqtt://broker:1883, or mqtts:// for TLS
brokerUrl: "${MQTT_BROKER_URL}"
# Optional: the topic prefix, "isitdown" by default. Messages go to
# <prefix>/<provider>; a provider's state is published retained.
topic: "${MQTT_TOPIC}"
# Optional: only for a broker that wants credentials
username: "${MQTT_USERNAME}"
password: "${MQTT_PASSWORD}"
# Public posts. The operator's impact and owner notes are never posted.
mastodon:
enabled: false
instanceUrl: "${MASTODON_INSTANCE_URL}"
# An application's access token with write:statuses
accessToken: "${MASTODON_ACCESS_TOKEN}"
# Optional: public (the default), unlisted or private
visibility: "${MASTODON_VISIBILITY}"
bluesky:
enabled: false
handle: "${BLUESKY_HANDLE}"
# An app password (Settings → App passwords), never the account's own
appPassword: "${BLUESKY_APP_PASSWORD}"
# Optional: the account's PDS, when it is not bsky.social
serviceUrl: "${BLUESKY_SERVICE_URL}"
# Which channels hear about what. The first rule that matches a change decides,
# rules below it are not consulted — put specific ones on top. Leave this
# section out entirely and every change goes to every enabled channel, which is
# what happens without it.
#
# classes: status | incident | maintenance | monitoring (default: all)
# minSeverity: any | degraded | partial_outage | major_outage (default: any)
# channels: channel names from `notifications` above, ["*"] for all of
# them, or [] to stay silent
#
# A rule's severity is the worse of the status a change came from and the one
# it went to, so a recovery from a major outage reaches the same channels the
# outage did.
#
# routing:
# # A provider watched out of curiosity: on the dashboard, never in a message.
# - provider: anthropic
# channels: []
# # The whole deploy path, in one rule: it stays right when the stack gains a
# # fifth provider, which four provider ids never would.
# - provider: group:deploy-path
# classes: [status, incident]
# minSeverity: degraded
# channels: [telegram]
# # Real trouble, anywhere: every channel gets attention.
# - provider: "*"
# classes: [status, incident]
# minSeverity: major_outage
# channels: [telegram]
# # Everything else, including scheduled maintenance and IsItDown's own
# # polling trouble: somewhere quieter.
# - provider: "*"
# channels: [slack]
# How much of what the rules above admit actually goes out, and in how many
# messages. Leave this section out and all four controls are off, which is what
# every installation before them was doing.
#
# delivery:
# # Quiet hours: inside the window, only changes at or above the floor are
# # sent. Anything under it is dropped, not deferred — the digest below is the
# # control that defers. The window may wrap midnight, and is read in
# # `timeZone` ("auto" means the zone the container runs in).
# quietHours:
# enabled: true
# start: "23:00"
# end: "07:00"
# timeZone: "Europe/Rome"
# minSeverity: major_outage
# # Digest mode: collect changes under `immediateFloor` and send them as one
# # message per window. Anything at or above the floor still goes out the
# # moment it happens, so the window's length only ever delays the news you
# # said was not urgent. A batch collected when the container stops is lost
# # rather than sent an hour late.
# digest:
# enabled: true
# windowMinutes: 15
# immediateFloor: major_outage
# # A ceiling per provider, per rolling hour. What the cap holds back is
# # counted, and the next message that gets through says how much it hid.
# cap:
# enabled: true
# maxPerHour: 6
# # One incident becomes one message that is rewritten as the incident moves,
# # on channels that can edit one (telegram, discord). The others still get a
# # message per update.
# updateInPlace: true
#
# # A heads-up before a maintenance window the provider has declared opens
# # (not while it runs): "GitHub maintenance in 2 h, expected 30 min".
# maintenanceNotice:
# enabled: true
# leadMinutes: 120
#
# # A major change nobody took in charge is said again on another channel
# # after this long. UI edition only: it needs the "I'm on it" button to know
# # whether anybody answered.
# escalation:
# enabled: true
# afterMinutes: 15
# channel: pushover
# minSeverity: major_outage
#
# # When a channel refuses this many messages in a row, say so on the
# # others instead of leaving it to a badge in the delivery log.
# channelHealth:
# enabled: true
# afterFailures: 3
#
# # When several providers fail together and then recover, send one message
# # ("6 providers, 47 minutes, probable cause: cloudflare") instead of one
# # "resolved" per provider. The members' own recoveries are held back until
# # the last one is back.
# incidentSummary:
# enabled: true
#
# # A provider that posts several updates of the same incident in a short
# # time produces one message: the last state, sent once nothing newer has
# # arrived for this long.
# coalesce:
# enabled: true
# windowMinutes: 2
#
# # While a provider is already in major outage, further updates of its
# # incident go to the digest window instead of interrupting. A change of
# # severity or the resolution still goes out at once.
# knownOutage:
# enabled: true
#
# # UI edition only. Attach the provider's last 24 hours, as an SVG, to status
# # and incident messages. Only the email and webhook channels can carry it.
# attachChart: true
#
# # UI edition only. The fleet's week or month on one channel: fleet uptime,
# # the weakest providers, incidents, error budget spent. It is not an alert,
# # so routing rules do not apply, but it waits out quiet hours.
# report:
# enabled: true
# frequency: weekly # weekly | monthly
# channel: slack
#
# # Who is on call this week: a rotation of the recipients defined below,
# # one per week, Monday to Sunday UTC. Whoever's week it is also hears every
# # change at or above minSeverity, on top of what the routing rules chose.
# onCall:
# enabled: true
# minSeverity: major_outage
# startsOn: 2026-10-05 # any day of the first week
# rotation: [alice, bob]
#
# # UI edition only. Once a week every enabled channel gets a message that
# # says it is a routine test; a failure raises the failing-channel alert.
# deliveryTest:
# enabled: true
# People reached through more than one channel, preferred first. A change a
# rule sends to several of one person's channels goes to the first only, and to
# the next only if that one fails — so nobody hears it twice, and nobody has to
# mute their second channel to stop it.
#
# recipients:
# - id: alice
# name: Alice
# channels: [telegram, discord]