Communication beginner ⏱ 20 minutes

ntfy: Simple Push Notifications for Your Homelab

Send notifications to your phone from scripts and services. Simple HTTP/pub-sub interface.

By homelabbing.io • 2025-12-17
#ntfy#notifications#push#alerts#docker

Introduction

Every homelab administrator faces the same challenge: how do you get notified when something important happens? Your server reboots, a backup fails, disk space runs low, or your home automation system detects unusual activity. You need instant, reliable notifications without depending on commercial services or complex setups.

ntfy (pronounced “notify”) is the elegant solution: a simple HTTP-based pub-sub notification service that sends push notifications to your phone, desktop, or browser in seconds. No API keys, no complicated authentication, and no monthly fees. Just pure, straightforward notifications.

What you’ll learn:

  • Deploy ntfy server with Docker Compose
  • Configure topics and subscriptions
  • Set up authentication and access control
  • Install mobile apps (iOS/Android) and web client
  • Integrate with monitoring tools (Uptime Kuma, Grafana, scripts)
  • Use advanced features (priorities, attachments, actions)
  • Implement rate limiting and security
  • Troubleshoot common notification issues

Prerequisites:

  • Docker and Docker Compose installed (v24.0+ and v2.0+)
  • Reverse proxy with HTTPS (optional but recommended)
  • Domain name (optional, can use IP address)
  • Basic understanding of HTTP requests
  • 256+ MB RAM, 1+ GB storage (minimal requirements)

Why ntfy?

The Notification Problem

Traditional notification solutions present challenges:

  • Cloud Services (Pushover, Pushbullet): Monthly fees, API limits, privacy concerns
  • Email: Slow, unreliable, often filtered to spam
  • SMS: Expensive, carrier-dependent, no rich media
  • Custom Apps: Development overhead, platform-specific
  • IFTTT/Zapier: Requires internet, adds complexity

How ntfy Solves This

ntfy provides dead-simple notifications with zero configuration:

FeaturentfyPushoverEmail
CostFree$5 one-timeFree
Setup Time5 minutes10 minutes30+ minutes
Delivery SpeedInstantInstantSeconds to minutes
PrivacySelf-hostedCloud serviceEmail provider
API ComplexityHTTP POSTAPI key requiredSMTP configuration
File AttachmentsYesNoYes
Rate LimitsYour choice10,000/monthProvider-dependent

Key Features

  • Zero Configuration: Use public ntfy.sh or self-host in 2 minutes
  • Simple API: Send notifications with curl or any HTTP client
  • Topics: Subscribe to specific notification channels
  • Priority Levels: Urgent, high, default, low, min
  • Attachments: Send images, files up to 150 MB
  • Actions: Add clickable buttons to notifications
  • Scheduled Delivery: Delay notifications or send at specific times
  • Email Publishing: Send notifications via email
  • Authentication: Protect topics with passwords or access tokens
  • Web Push: Browser notifications without mobile app

Architecture Overview

Your Scripts/Services → ntfy Server → Mobile Apps
         ↓                  ↓              ↓
    HTTP POST          Topics         Push Notifications
                          ↓
                   Subscribers

How it works:

  1. Publisher sends HTTP POST to ntfy server: curl -d "Backup completed" ntfy.sh/backups
  2. ntfy server stores message in topic: backups
  3. All subscribers to backups topic receive instant push notification
  4. Delivery via WebSocket, Server-Sent Events (SSE), or polling

Resource Requirements:

UsersMessages/DayRAMStorage
1-5Under 1,000256 MB1 GB
5-201,000-10,000512 MB5 GB
20-10010,000+1 GB10+ GB

Installation: Docker Compose Method

Step 1: Create Directory Structure

mkdir -p /opt/ntfy/{cache,etc}
cd /opt/ntfy

Step 2: Create server.yml Configuration

Create /opt/ntfy/etc/server.yml:

# Base configuration
base-url: "https://ntfy.example.com"

# Listen address (internal to container)
listen-http: ":80"

# Cache configuration
cache-file: "/var/cache/ntfy/cache.db"
cache-duration: "12h"
cache-startup-queries: |
  pragma journal_mode = WAL;
  pragma synchronous = normal;
  pragma temp_store = memory;

# Attachment storage
attachment-cache-dir: "/var/cache/ntfy/attachments"
attachment-total-size-limit: "5G"
attachment-file-size-limit: "150M"
attachment-expiry-duration: "3h"

# Keepalive settings
keepalive-interval: "45s"

# Authentication and access control
auth-default-access: "deny-all"  # Require authentication for all topics
auth-file: "/var/cache/ntfy/user.db"

# Rate limiting (prevent abuse)
visitor-subscription-limit: 30
visitor-request-limit-burst: 60
visitor-request-limit-replenish: "5s"
visitor-email-limit-burst: 16
visitor-email-limit-replenish: "1h"
visitor-attachment-total-size-limit: "100M"
visitor-attachment-daily-bandwidth-limit: "500M"

# Message limits
message-size-limit: "4096"  # 4 KB max message size

# Enable web app
enable-web-ui: true

# Metrics (Prometheus)
enable-metrics: true
metrics-listen-http: ":9090"

# SMTP for email notifications (optional)
# smtp-server-listen: ":25"
# smtp-server-domain: "ntfy.example.com"
# smtp-server-addr-prefix: "ntfy-"

# Logging
log-level: "info"
log-format: "text"

Key settings explained:

  • auth-default-access: "deny-all" - Require authentication (change to "read-write" for open server)
  • cache-duration: "12h" - Keep messages for 12 hours
  • attachment-file-size-limit: "150M" - Max 150 MB per attachment
  • visitor-request-limit-burst: 60 - Allow 60 requests per burst

Step 3: Create docker-compose.yml

version: '3.8'

services:
  ntfy:
    image: binwiederhier/ntfy:latest
    container_name: ntfy
    restart: always
    command:
      - serve
    environment:
      - TZ=America/New_York
    volumes:
      - ./cache:/var/cache/ntfy
      - ./etc/server.yml:/etc/ntfy/server.yml:ro
    ports:
      - "8080:80"      # HTTP (client API)
      - "9090:9090"    # Metrics (Prometheus)
    networks:
      - ntfy
    healthcheck:
      test: ["CMD-SHELL", "wget -q --tries=1 http://localhost:80/v1/health -O - | grep -Eo '"healthy"\s*:\s*true' || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

networks:
  ntfy:
    driver: bridge

Caddy Configuration:

ntfy.example.com {
    reverse_proxy ntfy:80

    # WebSocket support
    header {
        X-Forwarded-Proto {scheme}
    }

    # Security headers
    header {
        X-Content-Type-Options "nosniff"
        X-Frame-Options "SAMEORIGIN"
        Strict-Transport-Security "max-age=31536000;"
    }
}

Nginx Configuration:

server {
    server_name ntfy.example.com;

    location / {
        proxy_pass http://localhost:8080;
        proxy_http_version 1.1;

        # WebSocket support
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # Standard proxy headers
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # Buffering settings
        proxy_buffering off;
        proxy_read_timeout 86400s;
    }

    listen 443 ssl http2;
    ssl_certificate /etc/letsencrypt/live/ntfy.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/ntfy.example.com/privkey.pem;
}

Step 5: Start ntfy

# Start service
docker compose up -d

# Monitor logs
docker compose logs -f ntfy

# Check health
docker compose ps
curl http://localhost:8080/v1/health

Expected output:

{"healthy":true}

Step 6: Access Web Interface

Navigate to https://ntfy.example.com (or http://YOUR-SERVER-IP:8080)

You should see the ntfy web interface with:

  • Subscribe to topic input
  • Example commands
  • Recent notifications (if any)

User Management and Authentication

Creating Users

If you enabled auth-default-access: "deny-all", create users:

# Create admin user
docker exec -it ntfy ntfy user add --role=admin admin

# Create regular user
docker exec -it ntfy ntfy user add alice

# Follow prompts to set passwords

User roles:

  • admin - Can manage all topics and users
  • user - Standard access to allowed topics
  • Anonymous - No authentication (if enabled)

Managing User Access

Grant user access to specific topic:

# Allow alice to read and write to "alerts" topic
docker exec -it ntfy ntfy access alice alerts rw

# Allow bob to read-only on "status" topic
docker exec -it ntfy ntfy access bob status ro

# Grant alice wildcard access to all "backup-*" topics
docker exec -it ntfy ntfy access alice 'backup-*' rw

List user permissions:

docker exec -it ntfy ntfy user list

Access Tokens

Generate tokens for scripts and automation:

# Create access token for alice
docker exec -it ntfy ntfy token add alice

# Output example:
# tk_AgQdq7mVBoFD37zQVN29RhuMzNIz

Use token in requests:

curl -H "Authorization: Bearer tk_AgQdq7mVBoFD37zQVN29RhuMzNIz"     -d "Backup completed successfully"     https://ntfy.example.com/backups

Revoke token:

docker exec -it ntfy ntfy token remove tk_AgQdq7mVBoFD37zQVN29RhuMzNIz

Using ntfy: Publishing Notifications

Basic Publishing

Simplest notification:

curl -d "Hello, World!" ntfy.example.com/test

With title:

curl -H "Title: Server Alert"     -d "CPU usage exceeded 90%"     ntfy.example.com/alerts

From stdin:

echo "Backup completed" | curl -T- ntfy.example.com/backups

Priority Levels

Control notification urgency:

# Max priority (bypass Do Not Disturb)
curl -H "Priority: max"     -d "CRITICAL: Database offline!"     ntfy.example.com/alerts

# High priority (default sound)
curl -H "Priority: high"     -d "Disk space low: 95%"     ntfy.example.com/monitoring

# Default priority (normal)
curl -d "Deployment successful" ntfy.example.com/ci-cd

# Low priority (no sound)
curl -H "Priority: low"     -d "Daily backup completed"     ntfy.example.com/backups

# Min priority (no notification, stored only)
curl -H "Priority: min"     -d "Debug log entry"     ntfy.example.com/logs

Priority levels:

  • max (5) - Critical alerts, bypass DND
  • high (4) - Important notifications
  • default (3) - Normal priority
  • low (2) - Low priority, quiet
  • min (1) - Lowest, often silent

Tags and Emojis

Add visual indicators:

# Warning tag
curl -H "Tags: warning"     -d "Unusual login detected"     ntfy.example.com/security

# Multiple tags with emojis
curl -H "Tags: rotating_light,skull"     -d "System critical error"     ntfy.example.com/alerts

# Custom emoji
curl -H "Tags: +1,partying_face"     -d "Deployment successful!"     ntfy.example.com/ci-cd

Common tags: warning, skull, rotating_light, tada, rocket, +1, checkmark

Clickable Actions

Add buttons to notifications:

# View action (opens URL)
curl -H "Actions: view, Open Dashboard, https://dashboard.example.com"     -d "Server CPU high"     ntfy.example.com/alerts

# HTTP action (trigger webhook)
curl -H "Actions: http, Restart Service, https://api.example.com/restart, method=POST, headers.Authorization=Bearer token123"     -d "Service crashed"     ntfy.example.com/monitoring

# Broadcast action (Android intent)
curl -H "Actions: broadcast, Trigger Automation, com.example.ACTION_TRIGGER"     -d "Home automation event"     ntfy.example.com/home

File Attachments

Send images, logs, or documents:

# Attach file from URL
curl -H "Attach: https://example.com/screenshot.png"     -d "Check this error screenshot"     ntfy.example.com/support

# Upload file directly
curl -T backup.log     -H "Filename: backup.log"     https://ntfy.example.com/backups

# Attach with custom filename
curl -H "Attach: https://example.com/report.pdf"     -H "Filename: daily-report.pdf"     -d "Daily report attached"     ntfy.example.com/reports

Attachment limits: 150 MB per file (configurable in server.yml)

Delayed and Scheduled Delivery

Send notification in 30 minutes:

curl -H "Delay: 30m"     -d "Meeting reminder"     ntfy.example.com/reminders

Send at specific time:

# Send at 9 AM tomorrow
curl -H "At: tomorrow, 9am"     -d "Daily standup meeting"     ntfy.example.com/team

# Send at specific timestamp
curl -H "At: 2025-12-25T08:00:00"     -d "Merry Christmas!"     ntfy.example.com/personal

Email to ntfy

Send notifications via email:

# Configure in server.yml
smtp-server-listen: ":25"
smtp-server-domain: "ntfy.example.com"
smtp-server-addr-prefix: "ntfy-"

Send email to: [email protected]

Subject becomes title, body becomes message.


Mobile App Setup

Android App

  1. Install “ntfy” from Google Play Store
  2. Open app → Add subscription
  3. Configure:
    • Topic: alerts
    • Server: https://ntfy.example.com
    • Username: alice (if auth enabled)
    • Password: [your password]
  4. Tap Subscribe

Features:

  • Background service keeps connection alive
  • Instant push notifications
  • Share to ntfy from other apps
  • Backup/restore subscriptions
  • Custom notification sounds per topic

Notification Settings:

Per-topic configuration:

  • Priority: Max, High, Default, Low, Min
  • Sound: Custom ringtone
  • Vibrate: On/Off
  • LED color: Custom

iOS App

  1. Install “ntfy” from App Store
  2. Open app → Add subscription
  3. Configure:
    • Topic URL: https://ntfy.example.com/alerts
    • Username: alice
    • Password: [your password]
  4. Tap Add

iOS Limitations:

  • Background refresh limited by iOS
  • Notifications may be slightly delayed (30-60s)
  • No custom sounds (iOS restriction)

Workaround for instant notifications: Enable polling or use Apple Push Notification service (requires ntfy.sh or custom setup).

Desktop App

Linux (AppImage):

wget https://github.com/binwiederhier/ntfy/releases/latest/download/ntfy_linux_x86_64.AppImage
chmod +x ntfy_linux_x86_64.AppImage
./ntfy_linux_x86_64.AppImage

macOS (Homebrew):

brew install ntfy
ntfy subscribe alerts

Windows:

Download from GitHub Releases

Web Client

Access web interface directly:

  • Navigate to https://ntfy.example.com
  • Click Subscribe to topic
  • Enter topic name (e.g., alerts)
  • Allow browser notifications when prompted

Browser notifications work in:

  • Chrome/Chromium (all platforms)
  • Firefox (all platforms)
  • Safari (macOS/iOS)
  • Edge (Windows/macOS)

Integration with Monitoring Tools

Uptime Kuma Integration

Send ntfy notifications from Uptime Kuma:

  1. Uptime Kuma → Settings → Notifications
  2. Click “Add Notification”
  3. Notification Type: Webhook
  4. Configure:
    • Friendly Name: ntfy Alerts
    • URL: https://ntfy.example.com/monitoring?priority=high&tags=warning
    • Method: POST
    • Body: {"message": "[UP/DOWN]"}
  5. Test and Save

Custom payload for better formatting:

{
  "topic": "monitoring",
  "message": "[status]: [msg]",
  "title": "Uptime Kuma Alert",
  "priority": "high",
  "tags": ["warning"]
}

Grafana Integration

Send alerts from Grafana:

  1. Grafana → Alerting → Contact points

  2. Add contact point:

    • Name: ntfy
    • Integration: Webhook
    • URL: https://ntfy.example.com/grafana
    • HTTP Method: POST
  3. Optional: Add template for better formatting

Alert template:

{
  "title": "{{ .CommonLabels.alertname }}",
  "message": "{{ .CommonAnnotations.summary }}\n\n{{ .CommonAnnotations.description }}",
  "priority": "{{ if eq .Status "firing" }}high{{ else }}default{{ end }}",
  "tags": ["grafana", "{{ .Status }}"]
}

Bash Script Monitoring

Example: Disk space monitor

#!/bin/bash
# disk-monitor.sh

NTFY_URL="https://ntfy.example.com/monitoring"
THRESHOLD=90

USAGE=$(df -h / | awk 'NR==2 {print $5}' | sed 's/%//')

if [ "$USAGE" -gt "$THRESHOLD" ]; then
    curl -H "Title: Disk Space Alert"         -H "Priority: high"         -H "Tags: warning,cd"         -d "Disk usage at ${USAGE}% (threshold: ${THRESHOLD}%)"         "$NTFY_URL"
fi

Schedule with cron:

*/15 * * * * /opt/scripts/disk-monitor.sh

Docker Container Health Checks

Monitor Docker container health:

#!/bin/bash
# docker-health-monitor.sh

NTFY_URL="https://ntfy.example.com/docker"
CONTAINERS=("nginx" "postgres" "redis")

for container in "${CONTAINERS[@]}"; do
    if ! docker ps | grep -q "$container"; then
        curl -H "Title: Container Down"             -H "Priority: max"             -H "Tags: rotating_light,skull"             -d "Container $container is not running!"             "$NTFY_URL"
    fi
done

Home Assistant Integration

Add to configuration.yaml:

notify:
  - name: ntfy
    platform: rest
    resource: https://ntfy.example.com/homeassistant
    method: POST_JSON
    data:
      priority: "{{ priority }}"
      title: "{{ title }}"
    message_param_name: message

Use in automations:

automation:
  - alias: "Front door opened"
    trigger:
      platform: state
      entity_id: binary_sensor.front_door
      to: 'on'
    action:
      service: notify.ntfy
      data:
        message: "Front door opened"
        data:
          priority: high
          tags: ["door", "warning"]

n8n Workflow

Create n8n workflow node:

  1. Add “HTTP Request” node
  2. Configure:
    • Method: POST
    • URL: https://ntfy.example.com/n8n
    • Body: JSON
    • JSON body:
      {
        "message": "{{ $json.message }}",
        "title": "n8n Workflow",
        "priority": "default"
      }

Advanced Features

Email Publishing

Enable SMTP to send notifications via email:

Update server.yml:

smtp-server-listen: ":25"
smtp-server-domain: "ntfy.example.com"
smtp-server-addr-prefix: "ntfy-"

Send email to create notification:

To: [email protected]
Subject: Server Alert
Body: CPU usage critical

Phone Calls (via ntfy.sh)

Use ntfy.sh cloud service for phone call notifications:

curl -H "Call: yes"     -d "Critical server failure - call immediately"     https://ntfy.sh/your-topic

Note: Phone calls only available on ntfy.sh hosted service.

WebSocket Subscriptions

Subscribe via WebSocket for real-time updates:

// JavaScript example
const ws = new WebSocket('wss://ntfy.example.com/alerts/ws');

ws.onmessage = (event) => {
    const notification = JSON.parse(event.data);
    console.log('Received:', notification.message);
    // Display notification in your app
};

ws.onerror = (error) => {
    console.error('WebSocket error:', error);
};

Server-Sent Events (SSE)

Subscribe using Server-Sent Events:

# Command-line subscription
curl -s https://ntfy.example.com/alerts/sse

# Or with ntfy CLI
ntfy subscribe alerts

Security Best Practices

Enable Authentication

Require authentication for all topics:

# server.yml
auth-default-access: "deny-all"

Create users and grant specific access:

docker exec -it ntfy ntfy user add alice
docker exec -it ntfy ntfy access alice alerts rw

Rate Limiting

Prevent abuse with rate limits:

# server.yml
visitor-subscription-limit: 30
visitor-request-limit-burst: 60
visitor-request-limit-replenish: "5s"
visitor-attachment-total-size-limit: "100M"
visitor-attachment-daily-bandwidth-limit: "500M"

What these limits do:

  • Max 30 active subscriptions per IP
  • 60 requests per burst, then 1 per 5 seconds
  • 100 MB total attachment storage per visitor
  • 500 MB attachment bandwidth per day per visitor

HTTPS Only

Always use HTTPS in production:

  • Prevents message interception
  • Protects authentication credentials
  • Required for web push notifications

Configure reverse proxy with valid SSL certificate.

Topic Naming Best Practices

Use private, unpredictable topic names:

Good:

alerts-dk83jf92kd
backup-monitoring-x7k2p
server-status-private-8xm2

Bad (easily guessable):

alerts
backups
my-topic

Access Control Lists

Fine-grained permissions:

# Alice can read and write to all backup topics
docker exec -it ntfy ntfy access alice 'backup-*' rw

# Bob can only read alerts
docker exec -it ntfy ntfy access bob alerts ro

# Charlie has admin access
docker exec -it ntfy ntfy user change-role charlie admin

Monitoring and Troubleshooting

Health Checks

# Check service health
curl https://ntfy.example.com/v1/health

# Check server stats
curl https://ntfy.example.com/v1/stats

# Prometheus metrics
curl https://ntfy.example.com:9090/metrics

Common Issues

Issue 1: Notifications Not Received

Symptoms: Published messages don’t appear on mobile app

Solutions:

# Check topic subscription
# Ensure exact topic name match (case-sensitive)

# Test with curl
curl -d "Test notification" https://ntfy.example.com/test

# Check mobile app settings:
# - Background refresh enabled (iOS)
# - Battery optimization disabled (Android)
# - Notifications enabled in OS settings

# Verify authentication
curl -u alice:password     -d "Auth test"     https://ntfy.example.com/protected-topic

Issue 2: High Memory Usage

Symptoms: Container consumes excessive RAM

Solutions:

# Add resource limits to docker-compose.yml
    deploy:
      resources:
        limits:
          memory: 512M
        reservations:
          memory: 256M

# Reduce cache duration in server.yml
cache-duration: "6h"  # Reduce from 12h

Issue 3: Attachments Not Working

Symptoms: Cannot upload or download files

Solutions:

# Check attachment limits
docker exec -it ntfy cat /etc/ntfy/server.yml | grep attachment

# Verify disk space
df -h /opt/ntfy/cache/attachments

# Check file permissions
docker exec -it ntfy ls -la /var/cache/ntfy/attachments

Issue 4: WebSocket Connection Fails

Symptoms: Real-time notifications delayed or not working

Solutions:

# Ensure reverse proxy has WebSocket support
# Nginx:
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

# Caddy (automatic WebSocket support):
reverse_proxy ntfy:80

Logging

Enable debug logging:

# server.yml
log-level: "debug"
log-format: "json"

View logs:

docker compose logs -f ntfy

# Filter errors
docker compose logs ntfy | grep -i error

# Export logs
docker compose logs ntfy > /opt/ntfy/debug.log

Backup and Maintenance

Backup Script

#!/bin/bash
# ntfy-backup.sh

BACKUP_DIR="/opt/backups/ntfy"
DATE=$(date +%Y%m%d_%H%M%S)

mkdir -p "$BACKUP_DIR"

# Backup cache database and user database
tar czf "$BACKUP_DIR/ntfy-${DATE}.tar.gz"     /opt/ntfy/cache/cache.db     /opt/ntfy/cache/user.db     /opt/ntfy/etc/server.yml

# Optional: Backup attachments (can be large)
# tar czf "$BACKUP_DIR/ntfy-attachments-${DATE}.tar.gz" #     /opt/ntfy/cache/attachments

# Cleanup old backups (keep 30 days)
find "$BACKUP_DIR" -name "ntfy-*.tar.gz" -mtime +30 -delete

echo "Backup completed: $DATE"

Schedule:

0 3 * * * /opt/ntfy/ntfy-backup.sh

Restore

# Stop service
docker compose down

# Restore backup
tar xzf /opt/backups/ntfy/ntfy-YYYYMMDD.tar.gz -C /

# Restart service
docker compose up -d

Database Maintenance

# Check cache database size
docker exec -it ntfy sqlite3 /var/cache/ntfy/cache.db "SELECT pg_size_pretty(pg_database_size('cache'));"

# Vacuum database (reclaim space)
docker exec -it ntfy sqlite3 /var/cache/ntfy/cache.db "VACUUM;"

# Purge old messages
# Automatically handled by cache-duration setting

Conclusion

You now have a fully functional ntfy notification server with:

  • Docker-based deployment for easy management
  • Topic-based subscriptions for organized notifications
  • Authentication and access control for security
  • Mobile app support for iOS and Android
  • Integration with monitoring tools and automation
  • Advanced features like attachments and actions
  • Rate limiting and security hardening
  • Automated backups

Next steps:

  1. Subscribe to topics from mobile apps
  2. Integrate with existing monitoring tools
  3. Create custom scripts for homelab automation
  4. Set up Prometheus metrics monitoring
  5. Explore advanced features (scheduled delivery, email publishing)

ntfy provides the simplest path to reliable push notifications for your homelab. No complexity, no monthly fees, just instant notifications when you need them.


Additional Resources

Official:

Community:

Examples:


Last Updated: December 2025 Version Covered: ntfy 2.11.0+ Word Count: 3,287 words