Set up Uptime Kuma with advanced API endpoints, custom notification channels, and automated monitoring workflows. Configure health check automation, status page customization, and enterprise alerting rules for production environments.
Prerequisites
- Running Uptime Kuma instance
- Admin access to monitoring system
- Basic understanding of REST APIs
- Python 3.8 or higher
What this solves
Uptime Kuma's web interface works well for basic monitoring, but production environments need programmatic control, custom integrations, and advanced alerting workflows. This tutorial shows you how to configure Uptime Kuma's API, set up automated monitor management, integrate with external services, and build sophisticated alerting chains that scale with your infrastructure.
Prerequisites
You need a running Uptime Kuma instance with admin access. This tutorial builds on basic monitoring concepts and requires familiarity with REST APIs and webhook integrations. If you need to set up basic monitoring first, check out our Uptime Kuma installation guide.
Step-by-step configuration
Enable API access and authentication
First, enable API access in Uptime Kuma's settings. The API requires authentication tokens for security.
curl -X POST http://localhost:3001/api/login \
-H "Content-Type: application/json" \
-d '{"username": "admin", "password": "your_password"}'
Save the returned token. Create a dedicated API user for automation scripts:
curl -X POST http://localhost:3001/api/user \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{
"username": "api-user",
"password": "secure_password_123",
"active": true,
"role": "user"
}'
Configure API token management
Generate long-lived API tokens for automation. Store these securely and rotate them regularly.
{
"api_base_url": "http://localhost:3001/api",
"auth_token": "your_api_token_here",
"timeout": 30,
"retry_attempts": 3,
"rate_limit": {
"requests_per_minute": 60,
"burst_limit": 10
}
}
Set proper file permissions to protect the API configuration:
sudo chown root:uptime-kuma /etc/uptime-kuma/api-config.json
sudo chmod 640 /etc/uptime-kuma/api-config.json
Create automated monitor management scripts
Build scripts to programmatically create, update, and delete monitors. This enables infrastructure-as-code workflows.
#!/usr/bin/env python3
import requests
import json
import sys
import os
from datetime import datetime
class UptimeKumaAPI:
def __init__(self, config_file='/etc/uptime-kuma/api-config.json'):
with open(config_file) as f:
self.config = json.load(f)
self.base_url = self.config['api_base_url']
self.headers = {
'Authorization': f"Bearer {self.config['auth_token']}",
'Content-Type': 'application/json'
}
def create_monitor(self, monitor_config):
"""Create a new monitor with advanced configuration"""
response = requests.post(
f"{self.base_url}/monitor",
headers=self.headers,
json=monitor_config,
timeout=self.config['timeout']
)
response.raise_for_status()
return response.json()
def bulk_create_monitors(self, monitors_file):
"""Create multiple monitors from configuration file"""
with open(monitors_file) as f:
monitors = json.load(f)
results = []
for monitor in monitors:
try:
result = self.create_monitor(monitor)
results.append({'status': 'success', 'monitor': result})
print(f"Created monitor: {monitor.get('name', 'unnamed')}")
except Exception as e:
results.append({
'status': 'error',
'monitor': monitor.get('name', 'unnamed'),
'error': str(e)
})
print(f"Failed to create {monitor.get('name')}: {e}")
return results
if __name__ == '__main__':
if len(sys.argv) != 3:
print("Usage: uk-monitor-manager.py ")
sys.exit(1)
api = UptimeKumaAPI()
action, config_file = sys.argv[1], sys.argv[2]
if action == 'create-bulk':
results = api.bulk_create_monitors(config_file)
print(f"Processed {len(results)} monitors")
else:
print(f"Unknown action: {action}")
sys.exit(1)
Make the script executable and secure:
sudo chmod 750 /usr/local/bin/uk-monitor-manager.py
sudo chown root:uptime-kuma /usr/local/bin/uk-monitor-manager.py
Set up advanced notification integrations
Configure custom webhook notifications that integrate with your existing alerting infrastructure.
{
"slack_critical": {
"type": "slack",
"webhook_url": "https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK",
"username": "Uptime Kuma",
"channel": "#alerts-critical",
"icon_emoji": ":rotating_light:",
"color": "danger",
"conditions": {
"status": ["down"],
"tags": ["critical", "production"]
}
},
"pagerduty_escalation": {
"type": "webhook",
"url": "https://events.pagerduty.com/v2/enqueue",
"method": "POST",
"headers": {
"Content-Type": "application/json",
"Authorization": "Token token=YOUR_PAGERDUTY_TOKEN"
},
"body_template": {
"routing_key": "YOUR_INTEGRATION_KEY",
"event_action": "trigger",
"dedup_key": "uptime-kuma-{monitor_id}",
"payload": {
"summary": "Monitor {monitor_name} is {status}",
"source": "uptime-kuma",
"severity": "critical",
"component": "infrastructure",
"group": "monitoring",
"custom_details": {
"monitor_id": "{monitor_id}",
"monitor_url": "{monitor_url}",
"response_time": "{response_time}",
"status_code": "{status_code}",
"timestamp": "{timestamp}"
}
}
},
"conditions": {
"consecutive_failures": 3,
"tags": ["production"]
}
}
}
Create advanced monitor configurations
Define comprehensive monitor templates for different service types with proper health check logic.
[
{
"name": "Web Service - Production",
"type": "http",
"url": "https://api.example.com/health",
"method": "GET",
"interval": 60,
"timeout": 30,
"maxretries": 3,
"headers": {
"User-Agent": "Uptime-Kuma/1.0",
"Accept": "application/json"
},
"body": "",
"httpBodyEncoding": "json",
"expectedStatusCodes": ["200", "201"],
"keyword": "healthy",
"invertKeyword": false,
"ignoreTls": false,
"tags": ["production", "api", "critical"],
"notification_ids": [1, 2, 3],
"advanced_settings": {
"follow_redirect": true,
"max_redirects": 5,
"check_certificate": true,
"certificate_expiry_warning": 30
}
},
{
"name": "Database Connection",
"type": "postgres",
"hostname": "db.example.com",
"port": 5432,
"database": "production",
"username": "monitor_user",
"password": "secure_password",
"interval": 120,
"timeout": 15,
"maxretries": 2,
"query": "SELECT 1 as health_check",
"tags": ["production", "database", "critical"],
"notification_ids": [1, 3]
},
{
"name": "TCP Service Check",
"type": "port",
"hostname": "service.example.com",
"port": 22,
"interval": 300,
"timeout": 10,
"maxretries": 3,
"tags": ["infrastructure", "ssh"],
"notification_ids": [2]
}
]
Implement automated health check workflows
Create scripts that automatically adjust monitoring based on service discovery and infrastructure changes.
#!/bin/bash
Uptime Kuma Auto-Discovery Script
Automatically creates monitors for discovered services
set -euo pipefail
API_CONFIG="/etc/uptime-kuma/api-config.json"
DISCOVERY_CONFIG="/etc/uptime-kuma/discovery-config.json"
LOG_FILE="/var/log/uptime-kuma/auto-discovery.log"
TEMP_DIR="/tmp/uk-discovery"
Create required directories
sudo mkdir -p /var/log/uptime-kuma "$TEMP_DIR"
log_message() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | sudo tee -a "$LOG_FILE"
}
discover_docker_services() {
log_message "Discovering Docker services..."
# Get running containers with health checks
docker ps --format "table {{.Names}}\t{{.Ports}}\t{{.Status}}" | \
grep -E "(healthy|Up)" | \
tail -n +2 | \
while IFS=$'\t' read -r name ports status; do
if [[ "$ports" =~ ([0-9]+):([0-9]+) ]]; then
host_port="${BASH_REMATCH[1]}"
container_port="${BASH_REMATCH[2]}"
cat > "$TEMP_DIR/docker-${name}.json" << EOF
{
"name": "Docker - ${name}",
"type": "http",
"url": "http://localhost:${host_port}/health",
"interval": 120,
"timeout": 15,
"tags": ["docker", "auto-discovered", "${name}"],
"auto_managed": true
}
EOF
log_message "Created monitor config for Docker service: $name"
fi
done
}
discover_systemd_services() {
log_message "Discovering systemd services..."
# Get critical systemd services
systemctl list-units --type=service --state=active | \
grep -E "(nginx|apache2|postgresql|mysql|redis|mongodb)" | \
awk '{print $1}' | \
while read -r service; do
service_name=$(echo "$service" | sed 's/\.service$//')
cat > "$TEMP_DIR/systemd-${service_name}.json" << EOF
{
"name": "SystemD - ${service_name}",
"type": "http",
"url": "http://localhost/server-status",
"interval": 180,
"timeout": 10,
"tags": ["systemd", "auto-discovered", "${service_name}"],
"auto_managed": true
}
EOF
log_message "Created monitor config for systemd service: $service_name"
done
}
create_discovered_monitors() {
log_message "Creating monitors from discovered services..."
# Combine all discovered monitors into a single file
echo "[" > "$TEMP_DIR/all-monitors.json"
first=true
for config_file in "$TEMP_DIR"/*.json; do
if [[ "$config_file" != "$TEMP_DIR/all-monitors.json" ]]; then
if [[ "$first" == "false" ]]; then
echo "," >> "$TEMP_DIR/all-monitors.json"
fi
cat "$config_file" >> "$TEMP_DIR/all-monitors.json"
first=false
fi
done
echo "]" >> "$TEMP_DIR/all-monitors.json"
# Create monitors using our Python script
if [[ -s "$TEMP_DIR/all-monitors.json" ]]; then
/usr/local/bin/uk-monitor-manager.py create-bulk "$TEMP_DIR/all-monitors.json"
log_message "Completed monitor creation from auto-discovery"
else
log_message "No new services discovered"
fi
}
cleanup() {
rm -rf "$TEMP_DIR"
}
trap cleanup EXIT
Main discovery workflow
log_message "Starting auto-discovery process"
discover_docker_services
discover_systemd_services
create_discovered_monitors
log_message "Auto-discovery process completed"
Make the script executable and set up automated execution:
sudo chmod 755 /usr/local/bin/uk-auto-discovery.sh
Create systemd timer for automated discovery
sudo tee /etc/systemd/system/uk-auto-discovery.timer << 'EOF'
[Unit]
Description=Uptime Kuma Auto-Discovery Timer
Requires=uk-auto-discovery.service
[Timer]
OnCalendar=*:0/15
Persistent=true
[Install]
WantedBy=timers.target
EOF
sudo tee /etc/systemd/system/uk-auto-discovery.service << 'EOF'
[Unit]
Description=Uptime Kuma Auto-Discovery Service
After=network.target uptime-kuma.service
[Service]
Type=oneshot
User=root
ExecStart=/usr/local/bin/uk-auto-discovery.sh
TimeoutSec=300
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now uk-auto-discovery.timer
Configure status page automation
Set up programmatic status page management with custom styling and maintenance scheduling.
#!/usr/bin/env python3
import requests
import json
import sys
from datetime import datetime, timedelta
class StatusPageManager:
def __init__(self, config_file='/etc/uptime-kuma/api-config.json'):
with open(config_file) as f:
self.config = json.load(f)
self.base_url = self.config['api_base_url']
self.headers = {
'Authorization': f"Bearer {self.config['auth_token']}",
'Content-Type': 'application/json'
}
def create_status_page(self, config):
"""Create a public status page with custom configuration"""
status_page_config = {
'title': config.get('title', 'Service Status'),
'description': config.get('description', 'Real-time status of our services'),
'theme': config.get('theme', 'auto'),
'published': config.get('published', True),
'show_tags': config.get('show_tags', True),
'domainNames': config.get('domains', []),
'customCSS': config.get('custom_css', ''),
'footerText': config.get('footer', 'Powered by Uptime Kuma'),
'showPoweredBy': config.get('show_powered_by', False)
}
response = requests.post(
f"{self.base_url}/status-page",
headers=self.headers,
json=status_page_config
)
response.raise_for_status()
return response.json()
def schedule_maintenance(self, maintenance_config):
"""Schedule maintenance windows with automatic notifications"""
maintenance = {
'title': maintenance_config['title'],
'description': maintenance_config['description'],
'strategy': maintenance_config.get('strategy', 'single'),
'active': True,
'intervalDay': maintenance_config.get('interval_days', 0),
'dateTime': maintenance_config['start_time'],
'dateTimeEnd': maintenance_config['end_time'],
'monitors': maintenance_config.get('monitor_ids', []),
'statusPages': maintenance_config.get('status_page_ids', [])
}
response = requests.post(
f"{self.base_url}/maintenance",
headers=self.headers,
json=maintenance
)
response.raise_for_status()
return response.json()
def update_incident_status(self, incident_data):
"""Update incident information on status pages"""
incident = {
'title': incident_data['title'],
'content': incident_data['description'],
'style': incident_data.get('style', 'warning'),
'created_date': datetime.utcnow().isoformat(),
'last_updated_date': datetime.utcnow().isoformat()
}
response = requests.post(
f"{self.base_url}/incident",
headers=self.headers,
json=incident
)
response.raise_for_status()
return response.json()
if __name__ == '__main__':
manager = StatusPageManager()
# Example: Create status page
if len(sys.argv) > 1 and sys.argv[1] == 'create-page':
config = {
'title': 'Example.com Service Status',
'description': 'Real-time status of example.com services',
'theme': 'dark',
'domains': ['status.example.com'],
'custom_css': '.header { background: #2563eb; }'
}
result = manager.create_status_page(config)
print(f"Created status page: {result['slug']}")
# Example: Schedule maintenance
elif len(sys.argv) > 1 and sys.argv[1] == 'schedule-maintenance':
config = {
'title': 'Database Migration',
'description': 'Upgrading database servers for improved performance',
'start_time': (datetime.now() + timedelta(days=1)).isoformat(),
'end_time': (datetime.now() + timedelta(days=1, hours=2)).isoformat(),
'monitor_ids': [1, 2, 3]
}
result = manager.schedule_maintenance(config)
print(f"Scheduled maintenance: {result['id']}")
Make the status manager executable:
sudo chmod 755 /usr/local/bin/uk-status-manager.py
Set up advanced alerting rules
Configure complex alerting workflows with escalation chains and conditional logic.
{
"rules": [
{
"name": "Critical Service Down",
"conditions": {
"monitor_tags": ["critical", "production"],
"status": "down",
"consecutive_failures": 2,
"time_of_day": {
"business_hours": true,
"timezone": "UTC"
}
},
"actions": [
{
"type": "notification",
"notification_id": 1,
"delay_seconds": 0
},
{
"type": "pagerduty",
"integration_key": "YOUR_PAGERDUTY_KEY",
"severity": "critical",
"delay_seconds": 300
},
{
"type": "webhook",
"url": "https://api.example.com/incidents",
"method": "POST",
"delay_seconds": 600
}
]
},
{
"name": "Certificate Expiry Warning",
"conditions": {
"monitor_type": "http",
"certificate_days_remaining": 30,
"tags": ["production"]
},
"actions": [
{
"type": "email",
"recipients": ["ops@example.com"],
"template": "certificate_expiry"
},
{
"type": "slack",
"channel": "#infrastructure",
"severity": "warning"
}
]
},
{
"name": "Performance Degradation",
"conditions": {
"response_time_threshold": 5000,
"response_time_samples": 5,
"tags": ["api", "production"]
},
"actions": [
{
"type": "datadog_metric",
"metric_name": "uptime.response_time.degraded",
"tags": ["service:api", "env:production"]
},
{
"type": "notification",
"notification_id": 2
}
]
}
],
"escalation_policies": [
{
"name": "Critical Escalation",
"levels": [
{
"delay_minutes": 0,
"targets": ["on-call-primary"]
},
{
"delay_minutes": 15,
"targets": ["on-call-secondary", "team-lead"]
},
{
"delay_minutes": 30,
"targets": ["engineering-manager"]
}
]
}
]
}
Create monitoring dashboard integration
Build custom dashboards that combine Uptime Kuma data with other monitoring systems.
#!/usr/bin/env python3
import requests
import json
import time
from datetime import datetime, timedelta
from prometheus_client import start_http_server, Gauge, Counter
class UptimeKumaDashboard:
def __init__(self, config_file='/etc/uptime-kuma/api-config.json'):
with open(config_file) as f:
self.config = json.load(f)
self.base_url = self.config['api_base_url']
self.headers = {
'Authorization': f"Bearer {self.config['auth_token']}",
'Content-Type': 'application/json'
}
# Prometheus metrics
self.monitor_up = Gauge('uptime_kuma_monitor_up', 'Monitor status', ['monitor_name', 'monitor_id', 'tags'])
self.monitor_response_time = Gauge('uptime_kuma_response_time_ms', 'Response time in milliseconds', ['monitor_name', 'monitor_id'])
self.monitor_uptime = Gauge('uptime_kuma_uptime_percent', 'Monitor uptime percentage', ['monitor_name', 'monitor_id', 'period'])
self.alert_count = Counter('uptime_kuma_alerts_total', 'Total alerts sent', ['monitor_name', 'alert_type', 'severity'])
def get_monitor_stats(self):
"""Fetch comprehensive monitor statistics"""
response = requests.get(
f"{self.base_url}/monitors",
headers=self.headers
)
response.raise_for_status()
return response.json()
def update_prometheus_metrics(self):
"""Update Prometheus metrics with current monitor data"""
monitors = self.get_monitor_stats()
for monitor in monitors:
monitor_name = monitor.get('name', 'unknown')
monitor_id = str(monitor.get('id', 0))
tags = ','.join(monitor.get('tags', []))
# Update status metric
status_value = 1 if monitor.get('status') == 'up' else 0
self.monitor_up.labels(
monitor_name=monitor_name,
monitor_id=monitor_id,
tags=tags
).set(status_value)
# Update response time
if 'avgResponseTime' in monitor:
self.monitor_response_time.labels(
monitor_name=monitor_name,
monitor_id=monitor_id
).set(monitor['avgResponseTime'])
# Update uptime percentages
for period in ['24h', '7d', '30d']:
uptime_key = f'uptime_{period}'
if uptime_key in monitor:
self.monitor_uptime.labels(
monitor_name=monitor_name,
monitor_id=monitor_id,
period=period
).set(monitor[uptime_key])
def generate_status_report(self, output_file='/var/log/uptime-kuma/status-report.json'):
"""Generate comprehensive status report"""
monitors = self.get_monitor_stats()
report = {
'generated_at': datetime.utcnow().isoformat(),
'summary': {
'total_monitors': len(monitors),
'monitors_up': sum(1 for m in monitors if m.get('status') == 'up'),
'monitors_down': sum(1 for m in monitors if m.get('status') == 'down'),
'average_uptime_24h': sum(m.get('uptime_24h', 0) for m in monitors) / len(monitors) if monitors else 0
},
'by_tag': {},
'by_type': {},
'incidents_last_24h': self.get_recent_incidents()
}
# Group by tags
for monitor in monitors:
for tag in monitor.get('tags', ['untagged']):
if tag not in report['by_tag']:
report['by_tag'][tag] = {'total': 0, 'up': 0, 'down': 0}
report['by_tag'][tag]['total'] += 1
if monitor.get('status') == 'up':
report['by_tag'][tag]['up'] += 1
else:
report['by_tag'][tag]['down'] += 1
# Group by monitor type
for monitor in monitors:
monitor_type = monitor.get('type', 'unknown')
if monitor_type not in report['by_type']:
report['by_type'][monitor_type] = {'total': 0, 'up': 0, 'down': 0}
report['by_type'][monitor_type]['total'] += 1
if monitor.get('status') == 'up':
report['by_type'][monitor_type]['up'] += 1
else:
report['by_type'][monitor_type]['down'] += 1
with open(output_file, 'w') as f:
json.dump(report, f, indent=2)
return report
def get_recent_incidents(self, hours=24):
"""Get incidents from the last N hours"""
since = (datetime.utcnow() - timedelta(hours=hours)).isoformat()
try:
response = requests.get(
f"{self.base_url}/incidents",
headers=self.headers,
params={'since': since}
)
response.raise_for_status()
return response.json()
except Exception as e:
print(f"Failed to fetch incidents: {e}")
return []
def main():
dashboard = UptimeKumaDashboard()
# Start Prometheus metrics server
start_http_server(8000)
print("Prometheus metrics server started on port 8000")
while True:
try:
dashboard.update_prometheus_metrics()
dashboard.generate_status_report()
print(f"Updated metrics at {datetime.now().isoformat()}")
except Exception as e:
print(f"Error updating metrics: {e}")
time.sleep(60) # Update every minute
if __name__ == '__main__':
main()
Install required Python packages and create service:
sudo apt install -y python3-pip
sudo pip3 install requests prometheus_client
sudo chmod 755 /usr/local/bin/uk-dashboard-exporter.py
Create systemd service for the dashboard exporter
sudo tee /etc/systemd/system/uk-dashboard.service << 'EOF'
[Unit]
Description=Uptime Kuma Dashboard Exporter
After=network.target uptime-kuma.service
Requires=uptime-kuma.service
[Service]
Type=simple
User=uptime-kuma
Group=uptime-kuma
ExecStart=/usr/local/bin/uk-dashboard-exporter.py
Restart=always
RestartSec=10
TimeoutStopSec=5
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now uk-dashboard.service
Verify your setup
Test your advanced Uptime Kuma configuration with these verification commands:
# Test API connectivity
curl -H "Authorization: Bearer YOUR_TOKEN" \
http://localhost:3001/api/monitors
Verify auto-discovery service
sudo systemctl status uk-auto-discovery.timer
sudo journalctl -u uk-auto-discovery.service -n 20
Check dashboard exporter
curl http://localhost:8000/metrics | grep uptime_kuma
Test notification integrations
python3 -c "
import requests
import json
with open('/etc/uptime-kuma/api-config.json') as f: config = json.load(f)
print('API config loaded successfully')
"
Verify scheduled tasks
sudo systemctl list-timers | grep uk-auto-discovery
Check status report generation
sudo ls -la /var/log/uptime-kuma/status-report.json
http://localhost:3001/api. The Prometheus metrics are available at http://localhost:8000/metrics for integration with existing monitoring stacks like our Prometheus and Grafana setup.Common issues
| Symptom | Cause | Fix |
|---|---|---|
| API returns 401 Unauthorized | Invalid or expired token | Regenerate API token in Uptime Kuma settings and update config files |
| Auto-discovery script fails | Missing Docker or systemctl permissions | Add uptime-kuma user to docker group: sudo usermod -a -G docker uptime-kuma |
| Prometheus metrics not updating | Dashboard exporter service crashed | Check service logs: sudo journalctl -u uk-dashboard.service -f |
| Notification webhooks failing | Network connectivity or auth issues | Test webhook URLs manually with curl and verify credentials |
| Status page not accessible | Domain configuration or proxy issues | Verify domain DNS and reverse proxy configuration |
| High API rate limit errors | Too many concurrent requests | Increase rate limits in api-config.json or add request throttling |
Next steps
- Set up reverse proxy with SSL for your Uptime Kuma instance
- Integrate with Prometheus and Grafana for advanced dashboards
- Configure Uptime Kuma in high availability mode
- Set up automated backup and disaster recovery
- Develop custom plugins for specialized monitoring
Running this in production?
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Configuration
UPTIME_KUMA_USER="uptime-kuma"
UPTIME_KUMA_CONFIG_DIR="/etc/uptime-kuma"
SCRIPT_DIR="/usr/local/bin"
API_CONFIG_FILE="$UPTIME_KUMA_CONFIG_DIR/api-config.json"
MONITOR_MANAGER_SCRIPT="$SCRIPT_DIR/uk-monitor-manager.py"
# Usage message
usage() {
echo "Usage: $0 [admin_password] [api_user_password]"
echo " admin_password: Password for Uptime Kuma admin user (default: generated)"
echo " api_user_password: Password for API user (default: generated)"
exit 1
}
# Cleanup function
cleanup() {
echo -e "${RED}[ERROR]${NC} Script failed. Check logs above for details."
}
trap cleanup ERR
# Generate random password
generate_password() {
openssl rand -base64 32 | tr -d "=+/" | cut -c1-25
}
# Progress functions
print_step() {
echo -e "${GREEN}[$1]${NC} $2"
}
print_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Check prerequisites
check_prerequisites() {
print_step "1/8" "Checking prerequisites..."
if [[ $EUID -ne 0 ]]; then
print_error "This script must be run as root"
exit 1
fi
# Check if Uptime Kuma is running
if ! systemctl is-active --quiet uptime-kuma 2>/dev/null; then
print_error "Uptime Kuma service is not running. Please install and start Uptime Kuma first."
exit 1
fi
# Check if port 3001 is listening
if ! netstat -tuln 2>/dev/null | grep -q ":3001 " && ! ss -tuln 2>/dev/null | grep -q ":3001 "; then
print_error "Uptime Kuma is not listening on port 3001"
exit 1
fi
}
# Detect distribution and set package manager
detect_distro() {
print_step "2/8" "Detecting distribution..."
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_INSTALL="apt install -y"
PKG_UPDATE="apt update"
PYTHON_PKG="python3 python3-pip python3-requests"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_INSTALL="dnf install -y"
PKG_UPDATE="dnf update -y --refresh"
PYTHON_PKG="python3 python3-pip python3-requests"
;;
amzn)
PKG_MGR="yum"
PKG_INSTALL="yum install -y"
PKG_UPDATE="yum update -y"
PYTHON_PKG="python3 python3-pip"
;;
*)
print_error "Unsupported distribution: $ID"
exit 1
;;
esac
echo "Detected: $PRETTY_NAME (using $PKG_MGR)"
else
print_error "Cannot detect distribution - /etc/os-release not found"
exit 1
fi
}
# Install dependencies
install_dependencies() {
print_step "3/8" "Installing dependencies..."
$PKG_UPDATE
$PKG_INSTALL curl jq $PYTHON_PKG
# Install requests module if not available via package
if [ "$ID" = "amzn" ]; then
pip3 install requests --user
fi
}
# Setup configuration directory
setup_config_directory() {
print_step "4/8" "Setting up configuration directory..."
# Create uptime-kuma user if it doesn't exist
if ! id "$UPTIME_KUMA_USER" &>/dev/null; then
useradd --system --no-create-home --shell /bin/false "$UPTIME_KUMA_USER"
fi
# Create configuration directory
mkdir -p "$UPTIME_KUMA_CONFIG_DIR"
chown root:$UPTIME_KUMA_USER "$UPTIME_KUMA_CONFIG_DIR"
chmod 750 "$UPTIME_KUMA_CONFIG_DIR"
}
# Configure API access
configure_api_access() {
print_step "5/8" "Configuring API access..."
# Set passwords
ADMIN_PASSWORD="${1:-$(generate_password)}"
API_USER_PASSWORD="${2:-$(generate_password)}"
# Wait for Uptime Kuma to be fully ready
sleep 5
# Login as admin and get token
echo "Attempting to authenticate with Uptime Kuma..."
local token_response
token_response=$(curl -s -X POST http://localhost:3001/api/login \
-H "Content-Type: application/json" \
-d "{\"username\": \"admin\", \"password\": \"$ADMIN_PASSWORD\"}" || true)
if [ -z "$token_response" ] || ! echo "$token_response" | jq -r '.token' &>/dev/null; then
print_warning "Could not authenticate with provided admin password. API setup may need manual configuration."
API_TOKEN="CONFIGURE_MANUALLY"
else
API_TOKEN=$(echo "$token_response" | jq -r '.token')
echo "Successfully authenticated with Uptime Kuma API"
fi
# Create API configuration file
cat > "$API_CONFIG_FILE" << EOF
{
"api_base_url": "http://localhost:3001/api",
"auth_token": "$API_TOKEN",
"timeout": 30,
"retry_attempts": 3,
"rate_limit": {
"requests_per_minute": 60,
"burst_limit": 10
}
}
EOF
# Set proper permissions
chown root:$UPTIME_KUMA_USER "$API_CONFIG_FILE"
chmod 640 "$API_CONFIG_FILE"
echo "Admin password: $ADMIN_PASSWORD"
echo "API user password: $API_USER_PASSWORD"
}
# Create monitor management script
create_monitor_manager() {
print_step "6/8" "Creating monitor management script..."
cat > "$MONITOR_MANAGER_SCRIPT" << 'EOF'
#!/usr/bin/env python3
import requests
import json
import sys
import os
from datetime import datetime
class UptimeKumaAPI:
def __init__(self, config_file='/etc/uptime-kuma/api-config.json'):
try:
with open(config_file) as f:
self.config = json.load(f)
except FileNotFoundError:
print(f"Error: Config file {config_file} not found")
sys.exit(1)
except json.JSONDecodeError:
print(f"Error: Invalid JSON in {config_file}")
sys.exit(1)
self.base_url = self.config['api_base_url']
self.headers = {
'Authorization': f"Bearer {self.config['auth_token']}",
'Content-Type': 'application/json'
}
def create_monitor(self, monitor_config):
"""Create a new monitor with advanced configuration"""
response = requests.post(
f"{self.base_url}/monitor",
headers=self.headers,
json=monitor_config,
timeout=self.config['timeout']
)
response.raise_for_status()
return response.json()
def list_monitors(self):
"""List all monitors"""
response = requests.get(
f"{self.base_url}/monitor",
headers=self.headers,
timeout=self.config['timeout']
)
response.raise_for_status()
return response.json()
def delete_monitor(self, monitor_id):
"""Delete a monitor"""
response = requests.delete(
f"{self.base_url}/monitor/{monitor_id}",
headers=self.headers,
timeout=self.config['timeout']
)
response.raise_for_status()
return response.json()
def main():
if len(sys.argv) < 2:
print("Usage: uk-monitor-manager.py <command> [options]")
print("Commands:")
print(" list - List all monitors")
print(" create <config.json> - Create monitor from config")
print(" delete <monitor_id> - Delete monitor by ID")
sys.exit(1)
try:
api = UptimeKumaAPI()
command = sys.argv[1]
if command == 'list':
monitors = api.list_monitors()
print(json.dumps(monitors, indent=2))
elif command == 'create':
if len(sys.argv) != 3:
print("Usage: uk-monitor-manager.py create <config.json>")
sys.exit(1)
with open(sys.argv[2]) as f:
monitor_config = json.load(f)
result = api.create_monitor(monitor_config)
print(f"Created monitor: {json.dumps(result, indent=2)}")
elif command == 'delete':
if len(sys.argv) != 3:
print("Usage: uk-monitor-manager.py delete <monitor_id>")
sys.exit(1)
result = api.delete_monitor(sys.argv[2])
print(f"Deleted monitor: {json.dumps(result, indent=2)}")
else:
print(f"Unknown command: {command}")
sys.exit(1)
except requests.exceptions.RequestException as e:
print(f"API Error: {e}")
sys.exit(1)
except Exception as e:
print(f"Error: {e}")
sys.exit(1)
if __name__ == '__main__':
main()
EOF
chmod 755 "$MONITOR_MANAGER_SCRIPT"
chown root:root "$MONITOR_MANAGER_SCRIPT"
}
# Create sample monitor configuration
create_sample_configs() {
print_step "7/8" "Creating sample configuration files..."
# Sample monitor configuration
cat > "$UPTIME_KUMA_CONFIG_DIR/sample-monitor.json" << 'EOF'
{
"name": "Example Website",
"type": "http",
"url": "https://example.com",
"interval": 300,
"maxretries": 3,
"timeout": 30,
"method": "GET",
"headers": {},
"body": "",
"tags": ["production", "web"],
"description": "Sample website monitor"
}
EOF
chown root:$UPTIME_KUMA_USER "$UPTIME_KUMA_CONFIG_DIR/sample-monitor.json"
chmod 644 "$UPTIME_KUMA_CONFIG_DIR/sample-monitor.json"
}
# Verify installation
verify_installation() {
print_step "8/8" "Verifying installation..."
# Check files exist and have correct permissions
local files=(
"$API_CONFIG_FILE:640"
"$MONITOR_MANAGER_SCRIPT:755"
"$UPTIME_KUMA_CONFIG_DIR/sample-monitor.json:644"
)
for file_perm in "${files[@]}"; do
local file="${file_perm%:*}"
local expected_perm="${file_perm#*:}"
if [ ! -f "$file" ]; then
print_error "File $file does not exist"
exit 1
fi
local actual_perm
actual_perm=$(stat -c "%a" "$file")
if [ "$actual_perm" != "$expected_perm" ]; then
print_warning "File $file has permissions $actual_perm, expected $expected_perm"
fi
done
# Test the monitor manager script
if python3 -c "import requests, json" 2>/dev/null; then
echo "Python dependencies verified"
else
print_warning "Python dependencies may not be properly installed"
fi
echo -e "${GREEN}Installation completed successfully!${NC}"
echo
echo "Next steps:"
echo "1. Review and update the API configuration in: $API_CONFIG_FILE"
echo "2. Use the monitor manager script: $MONITOR_MANAGER_SCRIPT"
echo "3. Example usage: $MONITOR_MANAGER_SCRIPT list"
echo "4. Sample monitor config available at: $UPTIME_KUMA_CONFIG_DIR/sample-monitor.json"
}
# Main execution
main() {
echo "Uptime Kuma Advanced API Configuration Setup"
echo "=============================================="
check_prerequisites
detect_distro
install_dependencies
setup_config_directory
configure_api_access "$@"
create_monitor_manager
create_sample_configs
verify_installation
}
# Handle arguments
if [[ "${1:-}" == "--help" ]] || [[ "${1:-}" == "-h" ]]; then
usage
fi
main "$@"
Review the script before running. Execute with: bash install.sh