Self-hosted on-call routing, alert delivery, and escalation for teams that want control over their incident workflow.
IncidentRelay helps SRE, DevOps, platform, infrastructure, and operations teams route alerts to the right people through the right channels — without depending on a hosted incident-management platform.
It gives you the core building blocks of an on-call system:
- access groups and RBAC-style group roles;
- teams and on-call rotations;
- alert intake routes with per-route tokens;
- Alertmanager, Zabbix, and generic webhook integrations;
- Mattermost, Slack, Telegram, Discord, Microsoft Teams, email, webhook, and voice-call notifications;
- acknowledge and resolve workflows;
- reminders and escalation to the next on-call user;
- rotation overrides;
- calendar view for on-call schedules;
- personal API tokens;
- Swagger/OpenAPI documentation.
IncidentRelay is designed for self-hosted environments where teams need predictable behavior, clear ownership, easy integrations, and full control over alert routing.
Many teams need on-call routing, but do not always need a large SaaS incident platform.
IncidentRelay focuses on the practical workflow:
Monitoring system -> Route -> Team -> Rotation -> Notification channels -> ACK / Resolve
A route owns its own intake token, so external systems send alerts to an exact alert path:
ROUTE_INTAKE_TOKEN -> Route -> Team -> Rotation -> Channels
Channels only describe where notifications are delivered.
Routes decide which team receives the alert and which channels are used.
This keeps alert delivery easier to reason about, easier to audit, and safer for self-hosted deployments.
Run IncidentRelay in your own environment, with your own database, your own network rules, and your own operational policies.
Alert intake tokens belong to routes, not channels. This makes it clear which incoming integration is allowed to submit alerts to which team and rotation.
Use groups as access boundaries. Teams, rotations, routes, channels, alerts, and silences are scoped through groups and memberships.
Unacknowledged alerts can trigger repeated reminders and then escalate to the next on-call user according to the team configuration.
Mattermost Bot API mode supports interactive Acknowledge and Resolve buttons, message updates, and severity-based attachment colors.
IncidentRelay can be extended with custom voice providers for self-hosted installations. Providers can implement text-to-speech calls, call status callbacks, DTMF button callbacks, ACK / Resolve actions from phone keypad, and optional call status polling.
IncidentRelay includes Swagger/OpenAPI documentation and personal API tokens with scopes for alerts, resources, and profile access.
| Source | Endpoint |
|---|---|
| Alertmanager | POST /api/integrations/alertmanager |
| Zabbix | POST /api/integrations/zabbix |
| Generic webhook | POST /api/integrations/webhook |
| Channel | Notes |
|---|---|
| Mattermost | Incoming webhook mode or Bot API mode with buttons and updates |
| Slack | Webhook notifications |
| Telegram | Bot notifications |
| Discord | Webhook notifications |
| Microsoft Teams | Webhook notifications |
| Email recipients | |
| Webhook | Generic outbound webhook |
| Voice call | Pluggable provider API for self-hosted voice integrations |
IncidentRelay can be installed as two systemd services:
incidentrelay-web.service # HTTP API, UI, webhooks
incidentrelay-scheduler.service # reminders, escalations, periodic jobs
Quick start:
sudo git clone https://github.com/roxy-wi/IncidentRelay.git /var/www/incedentrelay
cd /var/www/incedentrelay
sudo python3 -m venv /var/www/incedentrelay/venv
sudo /var/www/incedentrelay/venv/bin/pip install --upgrade pip
sudo /var/www/incedentrelay/venv/bin/pip install -r requirements.txt
sudo /var/www/incedentrelay/venv/bin/pip install gunicorn
sudo mkdir -p /etc/incedentrelay /var/lib/incidentrelay /var/log/incidentrelay
sudo cp etc/incedentrelay/incedentrelay.conf /etc/incedentrelay/incedentrelay.conf
sudo chown -R www-data:www-data /var/www/incedentrelay
sudo chown -R www-data:www-data /var/lib/incidentrelay
sudo chown -R www-data:www-data /var/log/incidentrelay
sudo cp systemd/incidentrelay-web.service /etc/systemd/system/
sudo cp systemd/incidentrelay-scheduler.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo -u www-data \
INCEDENTRELAY_CONFIG_FILE=/etc/incedentrelay/incedentrelay.conf \
/var/www/incedentrelay/venv/bin/python app/migrate.py migrate
sudo systemctl enable --now incidentrelay-web
sudo systemctl enable --now incidentrelay-schedulerCreate the first admin user:
sudo -u www-data \
INCEDENTRELAY_CONFIG_FILE=/etc/incedentrelay/incedentrelay.conf \
/var/www/incedentrelay/venv/bin/python manage.py create-admin \
--username admin \
--password 'change-me-123' \
--email admin@example.comRead more:
The recommended self-hosted installation method is Docker Compose.
By default, IncidentRelay starts with SQLite and two containers:
incidentrelay-web # HTTP API, UI, webhooks
incidentrelay-scheduler # reminders, escalations, periodic jobs
Start:
docker compose up -d --buildSQLite data is stored in the incidentrelay-data Docker volume.
The scheduler runs in a separate container, so reminder and escalation jobs are not duplicated by web workers.
For PostgreSQL:
docker compose \
-f docker-compose.yml \
-f docker-compose.postgres.yml \
up -dFor production behind Nginx/HAProxy, bind the container port to localhost:
ports:
- "127.0.0.1:8080:8080"and set:
[server]
public_base_url = https://incidentrelay.example.comRead more:
After the first login:
1. Create a group
2. Create users
3. Add users to the group
4. Create a team
5. Add users to the team
6. Create a rotation
7. Add rotation members
8. Create notification channels
9. Create a route
10. Copy the route intake token
11. Configure Alertmanager, Zabbix, or webhook sender
12. Send a test alert
13. Acknowledge or resolve the alert
Detailed guide:
curl -X POST http://127.0.0.1:8080/api/integrations/alertmanager \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer ALERTMANAGER_ROUTE_TOKEN' \
-d '{
"status": "firing",
"alerts": [
{
"status": "firing",
"labels": {
"alertname": "DiskFull",
"severity": "critical",
"team": "infra",
"instance": "host1"
},
"annotations": {
"summary": "Disk is full",
"description": "/var is 95% full"
},
"fingerprint": "disk-full-host1-var"
}
]
}'More examples:
Mattermost has two modes.
Incoming webhook mode sends plain messages only.
Bot API mode is recommended when you want:
Acknowledgebutton;Resolvebutton;- message updates after ACK / Resolve;
- severity-based colors.
More details:
IncidentRelay supports custom voice providers for self-hosted installations.
A provider is a Python module that can be placed into:
/usr/local/lib/incidentrelay/voice_providers
Custom providers can implement:
- text-to-speech call creation;
- provider call ID tracking;
- call status callbacks;
- DTMF button callbacks;
- ACK / Resolve actions from phone keypad;
- optional call status polling.
Start here:
- Custom Voice Providers
- Provider API
- Configuration
- Callbacks and DTMF
- Security
- Troubleshooting
- Example providers
| Topic | Link |
|---|---|
| Getting started | docs/getting-started/ |
| Installation | docs/getting-started/installation.md |
| Configuration | docs/getting-started/configuration.md |
| First login | docs/getting-started/first-login.md |
| Groups and RBAC | docs/concepts/groups-and-rbac.md |
| Teams, rotations, routes | docs/concepts/teams-rotations-routes.md |
| Route intake tokens | docs/concepts/route-intake-tokens.md |
| Channels | docs/concepts/channels.md |
| Alertmanager | docs/integrations/alertmanager.md |
| Zabbix | docs/integrations/zabbix.md |
| Generic webhook | docs/integrations/generic-webhook.md |
| Mattermost | docs/integrations/mattermost.md |
| Alerts | docs/usage/alerts.md |
| Calendar | docs/usage/calendar.md |
| Silences | docs/usage/silences.md |
| Rotation overrides | docs/usage/rotation-overrides.md |
| Profile and API tokens | docs/usage/profile-and-tokens.md |
| Logging | docs/administration/logging.md |
| Troubleshooting | docs/administration/troubleshooting.md |
| Custom voice providers | docs/voice-providers/index.md |
| Swagger/OpenAPI notes | docs/api/voice-call-openapi.md |
Swagger UI is available at:
/docs
OpenAPI JSON is available at:
/api/openapi.json
The documentation is ready to be published with MkDocs Material.
Install MkDocs Material:
pip install mkdocs-materialRun local preview:
mkdocs serveOpen:
http://127.0.0.1:8000
Create demo data:
python manage.py demo-dataThe command creates demo groups, users, teams, rotations, channels, routes, and route intake tokens.
Static demo-data check:
python app/check_demo_data.pyMore details:
After running migrations, verify that all Peewee model tables and columns exist in the configured database:
python app/check_schema.pyExpected output:
Schema check OK: all model tables and columns exist.
More details:
If an alert is not visible or not delivered:
1. Check that the correct route intake token was used.
2. Check that the endpoint matches the route source.
3. Check that route matchers match alert labels.
4. Check that the group is active.
5. Check that the team is active.
6. Check that the UI active group is correct.
7. Select "All my groups" and reload the Alerts page.
8. Check routing_error in the integration response.
9. Check JSON logs by error_id if the server returned one.
More details:
Add your project license here.