- name: Setup ntfy as Uptime Kuma Notification Channel hosts: watchtower become: no vars_files: - ../../infra_vars.yml - ../../services_config.yml - ../../infra_secrets.yml - ./ntfy_vars.yml vars: ntfy_subdomain: "{{ subdomains.ntfy }}" ntfy_topic: "{{ service_settings.ntfy.topic }}" uptime_kuma_subdomain: "{{ subdomains.uptime_kuma }}" ntfy_domain: "{{ ntfy_subdomain }}.{{ root_domain }}" ntfy_server_url: "https://{{ ntfy_domain }}" ntfy_priority: 4 # 1=min, 2=low, 3=default, 4=high, 5=max uptime_kuma_api_url: "https://{{ uptime_kuma_subdomain }}.{{ root_domain }}" tasks: - name: Validate Uptime Kuma configuration assert: that: - uptime_kuma_api_url is defined - uptime_kuma_api_url != "" - uptime_kuma_username is defined - uptime_kuma_username != "" - uptime_kuma_password is defined - uptime_kuma_password != "" fail_msg: "uptime_kuma_api_url, uptime_kuma_username and uptime_kuma_password must be set" - name: Validate ntfy configuration assert: that: - ntfy_domain is defined - ntfy_domain != "" - ntfy_topic is defined - ntfy_topic != "" - ntfy_username is defined - ntfy_username != "" - ntfy_password is defined - ntfy_password != "" fail_msg: "ntfy_domain, ntfy_topic, ntfy_username and ntfy_password must be set" - name: Create Uptime Kuma ntfy notification setup script copy: dest: /tmp/setup_uptime_kuma_ntfy_notification.py content: | #!/usr/bin/env python3 import sys import json from uptime_kuma_api import UptimeKumaApi def main(): api_url = sys.argv[1] username = sys.argv[2] password = sys.argv[3] notification_name = sys.argv[4] ntfy_server_url = sys.argv[5] ntfy_topic = sys.argv[6] ntfy_username = sys.argv[7] ntfy_password = sys.argv[8] ntfy_priority = int(sys.argv[9]) api = UptimeKumaApi(api_url, timeout=60, wait_events=2.0) api.login(username, password) # Get all notifications notifications = api.get_notifications() # Find existing ntfy notification by name existing_notification = next((n for n in notifications if n.get('name') == notification_name), None) notification_data = { 'name': notification_name, 'type': 'ntfy', 'isDefault': True, # Apply to all monitors by default 'applyExisting': True, # Apply to existing monitors 'ntfyserverurl': ntfy_server_url, 'ntfytopic': ntfy_topic, 'ntfyusername': ntfy_username, 'ntfypassword': ntfy_password, 'ntfyPriority': ntfy_priority } if existing_notification: notification = api.edit_notification(existing_notification['id'], **notification_data) action = "updated" else: notification = api.add_notification(**notification_data) action = "created" # Output result as JSON result = { 'notification_id': notification['id'], 'notification_name': notification_name, 'ntfy_server': ntfy_server_url, 'ntfy_topic': ntfy_topic, 'action': action } print(json.dumps(result)) api.disconnect() if __name__ == '__main__': main() mode: '0755' delegate_to: localhost become: no - name: Run Uptime Kuma ntfy notification setup script command: > {{ ansible_playbook_python }} /tmp/setup_uptime_kuma_ntfy_notification.py "{{ uptime_kuma_api_url }}" "{{ uptime_kuma_username }}" "{{ uptime_kuma_password }}" "ntfy ({{ ntfy_topic }})" "{{ ntfy_server_url }}" "{{ ntfy_topic }}" "{{ ntfy_username }}" "{{ ntfy_password }}" "{{ ntfy_priority }}" register: notification_setup_result delegate_to: localhost become: no changed_when: false - name: Parse notification setup result set_fact: notification_info_parsed: "{{ notification_setup_result.stdout | from_json }}" - name: Display notification information debug: msg: | ✓ ntfy notification channel {{ notification_info_parsed.action }} successfully! Notification Name: ntfy ({{ ntfy_topic }}) ntfy Server: {{ ntfy_server_url }} ntfy Topic: {{ ntfy_topic }} Priority: {{ ntfy_priority }} (4=high) Default for all monitors: Yes Applied to existing monitors: Yes All Uptime Kuma monitors will now send alerts to your ntfy server on the "{{ ntfy_topic }}" topic. You can subscribe to alerts at: {{ ntfy_server_url }}/{{ ntfy_topic }} - name: Clean up temporary Uptime Kuma setup script file: path: /tmp/setup_uptime_kuma_ntfy_notification.py state: absent delegate_to: localhost become: no