-
Notifications
You must be signed in to change notification settings - Fork 71
Add unified notifications stack with ntfy and Gotify (Bounty #13) #397
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| # ntfy server configuration | ||
| # Documentation: https://docs.ntfy.sh/config/ | ||
|
|
||
| # Base URL for external access - configure via NTFY_BASE_URL environment variable | ||
| # Leave unset here and configure via NTFY_BASE_URL environment variable. | ||
| # base-url: "https://ntfy.example.com" | ||
|
|
||
| # Authentication settings | ||
| auth-default-access: "deny-all" | ||
| auth-file: "/var/lib/ntfy/user.db" | ||
|
|
||
| # Cache settings | ||
| cache-file: "/var/cache/ntfy/cache.db" | ||
| cache-duration: "12h" | ||
|
|
||
| # Behind reverse proxy | ||
| behind-proxy: true | ||
|
|
||
| # Rate limiting | ||
| global-rate-limit: "200 burst=50" | ||
| visitor-rate-limit: "30 burst=10" | ||
|
|
||
| # Message limits | ||
| message-size-limit: 4096 | ||
| message-total-size-limit: "5120MB" | ||
| message-delay-max: "3h" | ||
|
|
||
| # Topics | ||
| topic-list-allowed: false | ||
| topic-publish-unauthorized: ["homelab-alerts", "homelab-updates", "homelab-test"] | ||
|
|
||
| # Attachments | ||
| attachment-cache-dir: "/var/lib/ntfy/attachments" | ||
| attachment-size-limit: "15MB" | ||
| attachment-total-size-limit: "5120MB" | ||
| attachment-expiry-duration: "3h" | ||
|
|
||
| # Logging | ||
| log-level: "info" | ||
|
|
||
| # Web UI | ||
| enable-login: true | ||
| enable-signup: false | ||
|
|
||
| # SMTP for email notifications (optional) | ||
| # smtp-sender-addr: "smtp.gmail.com:587" | ||
| # smtp-sender-user: "your-email@gmail.com" | ||
| # smtp-sender-pass: "your-password" | ||
|
|
||
| # Firebase Cloud Messaging (optional, for iOS/Android push) | ||
| # firebase-key-file: "/etc/ntfy/firebase.json" |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,236 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #!/usr/bin/env bash | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Unified notification script for homelab-stack | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Supports ntfy and Gotify notification services | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Usage: notify.sh <topic> <title> <message> [priority] [tags] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set -euo pipefail | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Default configuration | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| NTFY_BASE_URL="${NTFY_BASE_URL:-https://ntfy.${DOMAIN:-example.com}}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GOTIFY_URL="${GOTIFY_URL:-http://gotify:8080}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GOTIFY_TOKEN="${GOTIFY_TOKEN:-}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Priority mapping (1=min, 5=max, default=3) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| declare -A PRIORITY_MAP=( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ["min"]=1 ["1"]=1 ["low"]=2 ["2"]=2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ["default"]=3 ["3"]=3 ["normal"]=3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ["high"]=4 ["4"]=4 ["urgent"]=5 ["5"]=5 ["max"]=5 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Color codes for output | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RED='\033[0;31m' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GREEN='\033[0;32m' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| YELLOW='\033[1;33m' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| NC='\033[0m' # No Color | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Log function | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| log() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')]${NC} $1" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| error() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo -e "${RED}[$(date '+%Y-%m-%d %H:%M:%S')] ERROR:${NC} $1" >&2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Help function | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| show_help() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cat << EOF | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Unified Notification Script for Homelab Stack | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Usage: notify.sh <topic> <title> <message> [priority] [tags] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Arguments: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| topic Notification topic/channel (e.g., homelab-alerts, homelab-updates) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| title Notification title | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message Notification message body | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| priority Priority level (default: 3) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Options: min(1), low(2), default(3), high(4), max(5) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tags Comma-separated tags (e.g., warning,error,success) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Environment Variables: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| NTFY_BASE_URL Ntfy server URL (default: https://ntfy.\${DOMAIN}) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GOTIFY_URL Gotify server URL (default: http://gotify:8080) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GOTIFY_TOKEN Gotify application token (optional) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| DOMAIN Your domain for ntfy (default: example.com) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Examples: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Basic notification | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| notify.sh homelab-test "Test" "Hello World" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # High priority alert | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| notify.sh homelab-alerts "Alert" "Service down" high error | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # With tags | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| notify.sh homelab-updates "Update" "Container updated" normal success,docker | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Using environment variables | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| DOMAIN=mydomain.com notify.sh test "Test" "Message" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| EOF | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Send notification via ntfy | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| send_ntfy() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| local topic="$1" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| local title="$2" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| local message="$3" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| local priority="$4" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| local tags="$5" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| local json_payload="{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| \"topic\": \"${topic}\", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| \"title\": \"${title}\", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| \"message\": \"${message}\", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| \"priority\": ${priority}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if [[ -n "$tags" ]]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Convert comma-separated tags to array | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IFS=',' read -ra TAG_ARRAY <<< "$tags" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| local tags_json="[" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for tag in "${TAG_ARRAY[@]}"; do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tags_json+="\"${tag}\"," | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| done | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tags_json="${tags_json%,}]" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| json_payload+=", \"tags\": ${tags_json}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| json_payload+="}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+79
to
+97
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| local json_payload="{ | |
| \"topic\": \"${topic}\", | |
| \"title\": \"${title}\", | |
| \"message\": \"${message}\", | |
| \"priority\": ${priority}" | |
| if [[ -n "$tags" ]]; then | |
| # Convert comma-separated tags to array | |
| IFS=',' read -ra TAG_ARRAY <<< "$tags" | |
| local tags_json="[" | |
| for tag in "${TAG_ARRAY[@]}"; do | |
| tags_json+="\"${tag}\"," | |
| done | |
| tags_json="${tags_json%,}]" | |
| json_payload+=", \"tags\": ${tags_json}" | |
| fi | |
| json_payload+="}" | |
| local json_payload | |
| if [[ -n "$tags" ]]; then | |
| # Build JSON with tags, safely escaped via jq | |
| json_payload="$(jq -n \ | |
| --arg topic "$topic" \ | |
| --arg title "$title" \ | |
| --arg message "$message" \ | |
| --argjson priority "$priority" \ | |
| --arg tags "$tags" \ | |
| '{topic: $topic, | |
| title: $title, | |
| message: $message, | |
| priority: $priority, | |
| tags: ($tags | split(",") | map(select(length > 0)))}')" | |
| else | |
| # Build JSON without tags, safely escaped via jq | |
| json_payload="$(jq -n \ | |
| --arg topic "$topic" \ | |
| --arg title "$title" \ | |
| --arg message "$message" \ | |
| --argjson priority "$priority" \ | |
| '{topic: $topic, | |
| title: $title, | |
| message: $message, | |
| priority: $priority}')" | |
| fi |
Copilot
AI
Mar 31, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
curl -s does not fail on HTTP 4xx/5xx, so the script may log βsent successfullyβ even when the server rejected the request. Use curl -f (and ideally capture/print response body on failure) so HTTP errors are treated as failures.
Copilot
AI
Mar 31, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as ntfy: Gotify requests use curl -s which wonβt fail on HTTP 4xx/5xx. This can report success when the token is invalid or the server returns an error. Use -f and handle non-2xx responses as failures.
Copilot
AI
Mar 31, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After sanitizing the topic, the script doesnβt validate that itβs still non-empty. Inputs like --- or only invalid characters will produce an empty topic and result in a broken publish request. Add a post-sanitization check and fail with a clear error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The script always sends an
Authorization: Bearer ...header even whenNTFY_TOKENis unset/empty, andNTFY_TOKENisnβt documented in the help text. Only include the header when a token is set, and document the variable (or support basic auth) to avoid confusing auth failures.