Notification Stack Documentation¶
The notification stack provides a unified, multi-channel notification system for the entire infrastructure, enabling alerts, monitoring, and communication through various channels and protocols.
Overview¶
The notification stack consists of four integrated components:
- Apprise - Universal notification aggregator supporting 100+ services
- ntfy - Push notification server with authentication and topics
- Mailrise - SMTP to push notification gateway
- Uptime Kuma - Service monitoring with integrated notifications
Architecture¶
graph LR
subgraph Sources
A[Services]
B[Scripts]
C[n8n Workflows]
D[Prometheus Alerts]
E[Legacy Apps]
F[Monitoring]
end
subgraph Notification Stack
G[Apprise API]
H[ntfy Server]
I[Mailrise SMTP]
J[Uptime Kuma]
end
subgraph Destinations
K[WhatsApp]
L[Telegram]
M[Email]
N[Discord]
O[Mobile Push]
P[Desktop Notifications]
end
A --> G
B --> G
B --> H
C --> G
C --> H
D --> G
E --> I
I --> G
F --> J
J --> G
G --> K
G --> L
G --> M
G --> N
G --> H
H --> O
H --> P
Components¶
Apprise¶
URL: https://apprise.rbnk.uk
Purpose: Universal notification aggregator that can send to 100+ different notification services
Key Features: - REST API for easy integration - Tag-based notification routing - Persistent configuration storage - Support for multiple notification formats (text, markdown, HTML) - Batch notifications to multiple services
Configuration: - Stores notification URLs in persistent configuration - Supports tagging for selective notifications - Can chain multiple services together
API Usage:
# Send notification to all configured services
curl -X POST https://apprise.rbnk.uk/notify/apprise \
-H "Content-Type: application/json" \
-d '{
"title": "Alert Title",
"body": "Alert message body",
"type": "info"
}'
# Send to specific tags
curl -X POST https://apprise.rbnk.uk/notify/apprise \
-H "Content-Type: application/json" \
-d '{
"title": "Critical Alert",
"body": "System failure detected",
"tag": "critical,oncall"
}'
ntfy¶
URL: https://ntfy.rbnk.uk
Purpose: Self-hosted push notification server with authentication
Key Features: - Real-time push notifications to mobile and desktop - Authentication required for publishing and subscribing - Topic-based message routing - Priority levels (1-5) - Attachment support - Scheduled notifications
Authentication:
Service accounts are created for different components:
- admin - Administrative access
- prometheus - Monitoring alerts
- backup - Backup job notifications
- n8n - Workflow automation
- monitoring - General monitoring alerts
Topic Structure:
Topics follow the pattern: service-severity-category
Examples:
- backup-error-daily - Daily backup errors
- monitoring-warning-disk - Disk space warnings
- deployment-info-production - Production deployment notifications
- security-critical-breach - Security incidents
Publishing Messages:
# Using curl with authentication
curl -u USERNAME:PASSWORD \
-d "Backup completed successfully" \
-H "Title: Backup Success" \
-H "Priority: 3" \
-H "Tags: white_check_mark" \
https://ntfy.rbnk.uk/backup-info-daily
# Using the notify helper script
notify "Backup Complete" "All backups finished successfully" 3 backup-info-daily
Mailrise¶
Port: 8025 (SMTP)
Purpose: SMTP gateway that converts emails to push notifications
Key Features: - SMTP server interface for legacy applications - Converts emails to Apprise notifications - No authentication required (internal use only) - Supports plain text and HTML emails - Configurable recipient-to-notification mapping
Configuration (/srv/dockerdata/mailrise/mailrise.conf):
# Example configuration mapping email addresses to notification URLs
configs:
# Default notifications
[email protected]:
urls:
- "apprise://apprise.rbnk.uk/notify/apprise"
# Critical alerts with specific routing
[email protected]:
urls:
- "apprise://apprise.rbnk.uk/notify/apprise?tag=critical"
- "ntfy://ntfy.rbnk.uk/monitoring-critical-system"
Usage Example:
# Send email that converts to notification
echo "Test notification" | mail -s "Test Subject" [email protected]
Uptime Kuma¶
URL: https://uptime.rbnk.uk
Purpose: Service monitoring and uptime tracking
Key Features: - Real-time service monitoring - Multiple monitor types (HTTP, TCP, Docker, etc.) - Incident tracking and status pages - Integrated notification support via Apprise - Historical uptime data - Maintenance windows
Monitor Configuration: - HTTP/HTTPS monitors for all public services - Docker container health checks - Database connectivity tests - Certificate expiration monitoring
Notification Integration: Uptime Kuma sends notifications through Apprise for: - Service down/up events - Certificate expiration warnings - Response time degradation - Maintenance reminders
Helper Scripts¶
notify Command¶
A convenience script installed at /usr/local/bin/notify for sending notifications:
#!/bin/bash
# Usage: notify "title" "message" [priority] [channel]
TITLE="${1:-Notification}"
MESSAGE="${2:-No message provided}"
PRIORITY="${3:-3}"
CHANNEL="${4:-general}"
# Send to Apprise
curl -s -X POST https://apprise.rbnk.uk/notify/apprise \
-H "Content-Type: application/json" \
-d "{
\"title\": \"$TITLE\",
\"body\": \"$MESSAGE\",
\"type\": \"info\"
}"
# Also send to ntfy if high priority
if [ "$PRIORITY" -ge 4 ]; then
curl -s -u "$NTFY_USER:$NTFY_PASS" \
-d "$MESSAGE" \
-H "Title: $TITLE" \
-H "Priority: $PRIORITY" \
https://ntfy.rbnk.uk/$CHANNEL
fi
Usage Examples:
# Simple notification
notify "Deployment Complete" "Application v1.2.3 deployed successfully"
# High priority alert
notify "Disk Space Warning" "Server disk usage at 79%" 4 monitoring-warning-disk
# Backup notification
notify "Backup Status" "Daily backup completed: 5.2GB transferred" 3 backup-info-daily
Integration Patterns¶
1. Direct API Integration¶
Services call the Apprise or ntfy API directly:
import requests
def send_notification(title, message, tags=None):
"""Send notification via Apprise API"""
data = {
"title": title,
"body": message,
"type": "info"
}
if tags:
data["tag"] = tags
response = requests.post(
"https://apprise.rbnk.uk/notify/apprise",
json=data
)
return response.status_code == 200
2. ntfy Topic Publishing¶
Services publish to specific ntfy topics:
const axios = require('axios');
async function publishToNtfy(topic, title, message, priority = 3) {
const auth = Buffer.from(`${process.env.NTFY_USER}:${process.env.NTFY_PASS}`).toString('base64');
await axios.post(
`https://ntfy.rbnk.uk/${topic}`,
message,
{
headers: {
'Title': title,
'Priority': priority.toString(),
'Authorization': `Basic ${auth}`
}
}
);
}
// Usage
await publishToNtfy('backup-info-daily', 'Backup Complete', 'All systems backed up successfully');
3. SMTP Gateway (Legacy Apps)¶
Applications that only support email notifications:
# Application configuration
email:
smtp_host: mailrise
smtp_port: 8025
from_address: [email protected]
to_address: [email protected] # Configured in Mailrise
4. Webhook Integration via n8n¶
n8n workflows handle complex notification logic:
// n8n workflow node example
{
"nodes": [
{
"name": "HTTP Request",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"url": "https://apprise.rbnk.uk/notify/apprise",
"method": "POST",
"jsonParameters": true,
"bodyParametersJson": {
"title": "={{$json.alert_title}}",
"body": "={{$json.alert_message}}",
"tag": "={{$json.severity}}"
}
}
}
]
}
5. Prometheus AlertManager¶
AlertManager routes to Apprise for alert notifications:
# alertmanager.yml
receivers:
- name: 'apprise'
webhook_configs:
- url: 'https://apprise.rbnk.uk/notify/apprise'
send_resolved: true
Best Practices¶
1. Topic Naming Convention¶
Use consistent topic naming for ntfy:
- Format: service-severity-category
- Severities: info, warning, error, critical
- Categories: backup, monitoring, deployment, security, maintenance
2. Priority Levels¶
Use appropriate priority levels: - 1-2: Low priority, silent notifications - 3: Default, normal notifications - 4: High priority, override quiet hours - 5: Urgent, may trigger loud alerts
3. Notification Grouping¶
Use tags in Apprise to group related notifications:
- critical: On-call alerts
- daily: Daily reports
- backup: Backup job status
- monitoring: System monitoring
- deployment: Deployment notifications
4. Rate Limiting¶
Implement rate limiting to prevent notification spam:
# Example: Max 10 notifications per minute per service
if [ $(redis-cli GET "notify:$SERVICE:count") -gt 10 ]; then
echo "Rate limit exceeded for $SERVICE"
exit 1
fi
5. Testing Notifications¶
Test notification channels regularly:
# Test all channels
notify "Test Alert" "Testing notification system at $(date)" 3 test
# Test specific severity
notify "Critical Test" "Testing critical alerts" 5 monitoring-critical-test
# Test Apprise tags
curl -X POST https://apprise.rbnk.uk/notify/apprise \
-H "Content-Type: application/json" \
-d '{"title": "Tag Test", "body": "Testing tag routing", "tag": "critical,oncall"}'
Troubleshooting¶
Common Issues¶
-
Authentication Failures:
-
Message Not Delivered:
- Check Apprise logs:
docker compose -f apprise/docker-compose.yml logs -f - Verify ntfy topic exists and user has access
-
Check network connectivity
-
SMTP Gateway Issues:
- Verify Mailrise is running:
docker ps | grep mailrise - Check configuration mapping in
mailrise.conf -
Test SMTP connection:
telnet localhost 8025 -
Rate Limiting:
- Check for rate limit errors in logs
- Implement exponential backoff for retries
- Consider batching notifications
Debug Commands¶
# Check service status
docker compose -f apprise/docker-compose.yml ps
docker compose -f ntfy/docker-compose.yml ps
# View recent notifications (ntfy)
curl -u admin:PASSWORD https://ntfy.rbnk.uk/backup-info-daily/json?poll=1
# Test Apprise configuration
docker exec apprise apprise -t "Test" -b "Test message" --config /config/apprise.yml --dry-run
# Monitor notification flow
docker compose -f apprise/docker-compose.yml logs -f &
docker compose -f ntfy/docker-compose.yml logs -f &
Security Considerations¶
- Authentication:
- ntfy requires authentication for all operations
- Each service has unique credentials
-
Credentials stored in service-specific
.envfiles -
Network Security:
- All services behind Traefik with SSL
- Mailrise only accessible internally
-
No public SMTP exposure
-
Data Privacy:
- Notifications may contain sensitive information
- Use encryption for sensitive notification channels
-
Implement audit logging for critical notifications
-
Access Control:
- Limit ntfy topic access by service
- Use Apprise tags for routing control
- Regular credential rotation
Monitoring the Notification Stack¶
Grafana dashboards available for: - Notification delivery success rate - Message queue lengths - Service uptime status - Notification volume by channel
Prometheus metrics:
- apprise_notifications_sent_total
- ntfy_messages_published_total
- mailrise_emails_processed_total
- uptimekuma_monitors_up
Integration Examples¶
Docker Service Health Notifications¶
# docker-compose.yml
services:
myapp:
image: myapp:latest
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/health"]
interval: 30s
timeout: 10s
retries: 3
labels:
- "autoheal=true" # Auto-restart unhealthy containers
- "notify.unhealthy=monitoring-error-container" # ntfy topic for alerts
Backup Job Notifications¶
#!/bin/bash
# backup-with-notifications.sh
BACKUP_START=$(date +%s)
notify "Backup Starting" "Beginning daily backup job" 2 backup-info-daily
if perform_backup; then
BACKUP_END=$(date +%s)
DURATION=$((BACKUP_END - BACKUP_START))
notify "Backup Success" "Backup completed in ${DURATION}s" 3 backup-info-daily
else
notify "Backup Failed" "Backup job failed with error: $?" 5 backup-error-daily
exit 1
fi
Application Error Notifications¶
# Python application example
import logging
import requests
from functools import wraps
class NotificationHandler(logging.Handler):
def emit(self, record):
if record.levelno >= logging.ERROR:
requests.post(
"https://apprise.rbnk.uk/notify/apprise",
json={
"title": f"Application Error: {record.name}",
"body": record.getMessage(),
"tag": "error,application"
}
)
# Add to logger
logger = logging.getLogger(__name__)
logger.addHandler(NotificationHandler())
Maintenance¶
Regular Tasks¶
-
Clean Up Old Notifications (Monthly):
-
Test Notification Channels (Weekly):
-
Update Notification URLs (As needed):
- Update Apprise configuration through web UI
-
Restart services after configuration changes
-
Monitor Resource Usage:
Real-World Integration Examples¶
Rclone Backup Notifications¶
The Rclone backup scripts use notifications to report status:
# From backup-infrastructure.sh
notify_backup_status() {
local status=$1
local message=$2
local priority=3
if [ "$status" = "error" ]; then
priority=5
topic="backup-error-infrastructure"
else
topic="backup-info-infrastructure"
fi
notify "Infrastructure Backup: $status" "$message" $priority $topic
}
# Usage in script
notify_backup_status "started" "Beginning infrastructure backup to R2"
if rclone sync /srv/dockerdata cloudflare:infrastructure-backups; then
notify_backup_status "success" "Backup completed: ${size} transferred"
else
notify_backup_status "error" "Backup failed with exit code $?"
fi
Prometheus Alert Integration¶
AlertManager sends notifications through Apprise:
# alertmanager.yml
global:
resolve_timeout: 5m
route:
group_by: ['alertname', 'cluster', 'service']
group_wait: 10s
group_interval: 10s
repeat_interval: 12h
receiver: 'apprise'
routes:
- match:
severity: critical
receiver: 'apprise-critical'
receivers:
- name: 'apprise'
webhook_configs:
- url: 'http://apprise:8000/notify/apprise'
send_resolved: true
- name: 'apprise-critical'
webhook_configs:
- url: 'http://apprise:8000/notify/apprise?tag=critical,oncall'
send_resolved: true
n8n Workflow Notifications¶
n8n workflows use multiple notification methods:
// Infrastructure Health Check Workflow
{
"nodes": [{
"name": "Check Services",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"url": "http://prometheus:9090/api/v1/query",
"qs": {
"query": "up{job=~'node|docker'}"
}
}
}, {
"name": "Process Results",
"type": "n8n-nodes-base.function",
"parameters": {
"code": `
const results = $input.all();
const downServices = results[0].json.data.result
.filter(r => r.value[1] === "0")
.map(r => r.metric.instance);
if (downServices.length > 0) {
return [{
json: {
status: "error",
services: downServices,
priority: 5,
topic: "monitoring-error-services"
}
}];
}
return [{
json: {
status: "ok",
priority: 1,
topic: "monitoring-info-services"
}
}];
`
}
}, {
"name": "Send Notification",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"url": "https://ntfy.rbnk.uk/{{ $json.topic }}",
"method": "POST",
"authentication": "basicAuth",
"credentials": {
"name": "ntfy"
},
"body": "{{ $json.status === 'error' ? 'Services DOWN: ' + $json.services.join(', ') : 'All services operational' }}",
"headers": {
"Title": "Infrastructure Health Check",
"Priority": "{{ $json.priority }}"
}
}
}]
}
Docker Health Check Integration¶
Services can trigger notifications on health status changes:
# docker-compose.yml with health notifications
services:
critical-app:
image: myapp:latest
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
labels:
- "autoheal=true"
autoheal:
image: willfarrell/autoheal
environment:
- AUTOHEAL_CONTAINER_LABEL=all
- WEBHOOK_URL=http://apprise:8000/notify/apprise
volumes:
- /var/run/docker.sock:/var/run/docker.sock
Git Push Notifications¶
Gitea webhooks trigger notifications on repository events:
# Git post-receive hook
#!/bin/bash
while read oldrev newrev refname; do
branch=$(git rev-parse --symbolic --abbrev-ref $refname)
if [ "$branch" = "main" ] || [ "$branch" = "production" ]; then
author=$(git log -1 --pretty=format:'%an' $newrev)
message=$(git log -1 --pretty=format:'%s' $newrev)
curl -X POST https://apprise.rbnk.uk/notify/apprise \
-H "Content-Type: application/json" \
-d "{
\"title\": \"Git Push: $branch\",
\"body\": \"$author: $message\",
\"tag\": \"deployment\"
}"
fi
done
Future Enhancements¶
Planned improvements for the notification stack:
- Notification Templates: Standardized message formats
- Delivery Confirmation: Track notification acknowledgment
- Escalation Policies: Automatic escalation for unacknowledged alerts
- Analytics Dashboard: Notification metrics and trends
- Mobile App: Native app for ntfy notifications
- Webhook Retries: Automatic retry with exponential backoff