Communication beginner ⏱ 20 minutes

Gotify: Self-Hosted Push Notification Server

Simple server for sending and receiving push notifications. REST API and Android app.

By homelabbing.io • 2025-12-17
#gotify#notifications#push#api#docker

Introduction

In the homelab ecosystem, staying informed about your infrastructure’s health is critical. You need to know immediately when a backup fails, a service goes down, or a security event occurs. Gotify is a simple, self-hosted push notification server that sends real-time alerts to your Android device (or web browser) with minimal configuration and zero ongoing costs.

Unlike cloud-based notification services that charge per message or require subscriptions, Gotify runs entirely on your infrastructure, giving you complete control over your notification pipeline.

What you’ll learn:

  • Deploy Gotify server with Docker Compose
  • Configure applications and authentication tokens
  • Manage messages and priorities
  • Set up the Android mobile app
  • Use the web UI for message management
  • Integrate with monitoring tools via API
  • Implement security and access control
  • Create custom notification scripts
  • Troubleshoot delivery issues

Prerequisites:

  • Docker and Docker Compose installed (v24.0+ and v2.0+)
  • Reverse proxy with HTTPS (recommended for external access)
  • Domain name or accessible IP address
  • Android device (for mobile app) or web browser
  • Basic understanding of REST APIs
  • 128+ MB RAM, 1+ GB storage (minimal requirements)

Why Gotify?

The Push Notification Landscape

Modern homelab operators have several notification options:

Commercial Services:

  • Pushover: $5 one-time fee, 10,000 messages/month
  • Pushbullet: Free tier limited, $5/month for pro
  • Telegram Bots: Free but requires Telegram account

Self-Hosted:

  • ntfy: HTTP-based, cross-platform, newer
  • Gotify: WebSocket-based, Android-focused, mature
  • Apprise: Aggregator supporting multiple services

Gotify’s Unique Strengths

FeatureGotifyntfyPushover
CostFreeFree$5 one-time
Android AppOfficialOfficialOfficial
iOS AppNoYesYes
Web UIFull-featuredBasicLimited
WebSocketNativeNativePolling
Message StorageSQLite databaseCache-basedCloud
Setup5 minutes5 minutesInstant
Privacy100% self-hosted100% self-hostedCloud service

When to choose Gotify:

  • Android-only environment (no iOS requirement)
  • Need message history and management via web UI
  • Want application-based organization
  • Prefer WebSocket real-time delivery
  • Require fine-grained access control per application

Key Features

  • Applications: Organize notifications by source (monitoring, backups, security)
  • Priorities: 10 priority levels for granular control
  • Web UI: Manage applications, view messages, configure settings
  • Android App: Native push notifications with background service
  • WebSocket: Real-time message delivery without polling
  • Message Persistence: SQLite database stores all messages
  • User Management: Multiple users with independent applications
  • Plugin Support: Extend functionality with custom plugins
  • REST API: Simple HTTP API for sending messages
  • Markdown Support: Rich formatting in messages

Architecture Overview

Your Scripts/Services → Gotify Server → Android App / Web UI
         ↓                   ↓                ↓
    HTTP POST          Applications    Push Notifications
    (API Token)         (Messages)      (WebSocket)
                            ↓
                       SQLite Database

How it works:

  1. Create application in Gotify (e.g., “Monitoring”)
  2. Get application token (e.g., Axxxxxxxxxxxxxxxxx)
  3. Send HTTP POST with token: curl -X POST "https://gotify.example.com/message?token=Axxxxxxxxxxxxxxxxx" -F "message=Server offline"
  4. Gotify stores message in database
  5. Connected clients receive instant push via WebSocket
  6. Android app displays notification with sound/vibration

Components:

  • Gotify Server: Go application serving API and WebSocket
  • SQLite Database: Stores messages, applications, users, tokens
  • Web UI: Browser-based interface for management
  • Android App: Native mobile app for notifications

Resource Requirements:

UsersMessages/DayRAMStorage
1-5Under 1,000128 MB1 GB
5-201,000-10,000256 MB5 GB
20+10,000+512 MB10+ GB

Installation: Docker Compose Method

Step 1: Create Directory Structure

mkdir -p /opt/gotify/data
cd /opt/gotify

Step 2: Create docker-compose.yml

version: '3.8'

services:
  gotify:
    image: gotify/server:latest
    container_name: gotify
    restart: always
    environment:
      # Timezone
      - TZ=America/New_York

      # Server configuration
      - GOTIFY_SERVER_PORT=80
      - GOTIFY_SERVER_KEEPALIVEPERIODECONDS=0
      - GOTIFY_SERVER_LISTENADDR=
      - GOTIFY_SERVER_SSL_ENABLED=false  # SSL handled by reverse proxy

      # Database
      - GOTIFY_DATABASE_DIALECT=sqlite3
      - GOTIFY_DATABASE_CONNECTION=data/gotify.db

      # Default admin credentials (CHANGE THESE!)
      - GOTIFY_DEFAULTUSER_NAME=admin
      - GOTIFY_DEFAULTUSER_PASS=CHANGE_THIS_PASSWORD

      # Registration settings
      - GOTIFY_REGISTRATION=false  # Disable public registration

      # Message limits
      - GOTIFY_UPLOADEDIMAGESDIR=data/images
      - GOTIFY_PLUGINSDIR=data/plugins

    volumes:
      - ./data:/app/data
    ports:
      - "8080:80"
    networks:
      - gotify
    healthcheck:
      test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:80/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 10s

networks:
  gotify:
    driver: bridge

Important: Change GOTIFY_DEFAULTUSER_PASS to a strong password!

Caddy Configuration:

gotify.example.com {
    reverse_proxy gotify:80 {
        # WebSocket support (automatic with Caddy)
        header_up X-Forwarded-Proto {scheme}
    }

    # Security headers
    header {
        X-Content-Type-Options "nosniff"
        X-Frame-Options "SAMEORIGIN"
        Referrer-Policy "no-referrer-when-downgrade"
        Strict-Transport-Security "max-age=31536000;"
    }
}

Nginx Configuration:

server {
    server_name gotify.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;

        # WebSocket specific settings
        proxy_read_timeout 86400;
        proxy_buffering off;
    }

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

Step 4: Start Gotify

# Start service
docker compose up -d

# Monitor logs
docker compose logs -f gotify

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

Expected output:

{"health":"green","database":"green"}

Step 5: Access Web Interface

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

First login:

  • Username: admin
  • Password: [password from docker-compose.yml]

You should see the Gotify web interface with:

  • Messages tab (empty initially)
  • Applications tab (for creating notification sources)
  • Clients tab (connected devices)
  • Users tab (user management)

Step 6: Change Default Password

  1. Click profile icon (top-right) → Change Password
  2. Current Password: [default password]
  3. New Password: [strong password]
  4. Confirm Password: [strong password]
  5. Click Change

Security Note: Always change the default admin password immediately after first login.


Application and Token Management

Understanding Applications

Applications represent notification sources (e.g., “Monitoring”, “Backups”, “Security”). Each application has:

  • Name: Descriptive identifier
  • Description: Purpose of the application
  • Token: API key for sending messages
  • Priority: Default message priority (1-10)
  • Image: Optional icon

Creating Your First Application

  1. Navigate to Apps tab
  2. Click Create Application
  3. Configure:
    • Name: Monitoring
    • Description: Server monitoring alerts
    • Default Priority: 8 (high)
  4. Click Create

You’ll receive an application token like: Axxxxxxxxxxxxxxxxx

Save this token securely - you’ll need it to send messages.

Sending Messages via API

Basic message:

curl -X POST "https://gotify.example.com/message?token=Axxxxxxxxxxxxxxxxx"     -F "message=Server CPU usage high: 95%"

With title:

curl -X POST "https://gotify.example.com/message?token=Axxxxxxxxxxxxxxxxx"     -F "title=CPU Alert"     -F "message=Server CPU usage high: 95%"

With priority:

curl -X POST "https://gotify.example.com/message?token=Axxxxxxxxxxxxxxxxx"     -F "title=Critical Alert"     -F "message=Database server offline"     -F "priority=10"

Priority levels:

  • 10 - Highest (critical alerts, loud notification)
  • 8 - High (important, default sound)
  • 5 - Normal (standard notification)
  • 2 - Low (quiet notification)
  • 0 - Lowest (silent, stored only)

Message Formatting

Markdown support:

curl -X POST "https://gotify.example.com/message?token=Axxxxxxxxxxxxxxxxx"     -F "title=Backup Report"     -F "message=## Daily Backup Status

**Completed:**
- Database: ✓
- Files: ✓
- Logs: ✓

**Failed:**
- None

**Next backup:** Tomorrow 2 AM"     -F "priority=5"

Supported Markdown:

  • Headers: # H1, ## H2
  • Bold: **bold**
  • Italic: *italic*
  • Lists: - item or * item
  • Links: [text](url)
  • Code: `code`

Extras (Additional Fields)

Send structured data:

curl -X POST "https://gotify.example.com/message?token=Axxxxxxxxxxxxxxxxx"     -F "title=Server Status"     -F "message=All systems operational"     -F 'extras={"server": {"name": "web01", "uptime": "30 days", "cpu": "45%"}}'

Extras appear in Android app as structured data.


User Management

Creating Additional Users

  1. Navigate to Users tab
  2. Click Create User
  3. Configure:
    • Name: alice
    • Password: [secure password]
    • Admin: unchecked (for regular user)
  4. Click Create

User permissions:

  • Admin: Full access to all applications, users, settings
  • Regular User: Access only to their own applications

User Applications

Each user has independent applications and messages. Messages sent to Alice’s applications only appear in her account.

Use cases:

  • Team members with separate notification channels
  • Different departments (IT, DevOps, Security)
  • Isolation between projects or clients

Android App Setup

Installing the App

  1. Install “Gotify” from F-Droid or Google Play Store
  2. Open app
  3. Click Add Server (+ button)
  4. Configure:
    • Server URL: https://gotify.example.com
    • Username: admin
    • Password: [your password]
  5. Tap Connect

Client Token

After connecting, app generates a client token automatically. View in web UI:

  1. Web UI → Clients tab
  2. See your Android device listed
  3. Token displayed (starts with C)

Client token vs. Application token:

  • Application token (A...): Send messages TO Gotify
  • Client token (C...): Receive messages FROM Gotify (auto-generated by app)

Notification Settings

Per-application settings:

  1. Android app → Long-press application
  2. Tap settings icon
  3. Configure:
    • Priority: Max, High, Default, Low, Min
    • Sound: Select ringtone
    • Vibrate: On/Off
    • Notification channel importance
  4. Save

Global settings:

  1. Android app → Menu → Settings
  2. Configure:
    • Connection timeout
    • Image preview in notifications
    • Background service behavior
    • Battery optimization exemption

Battery Optimization: For reliable notifications, disable battery optimization:

  1. Android Settings → Apps → Gotify
  2. Battery → Optimize battery usage
  3. Select “All apps”
  4. Find Gotify → Disable

Testing Notifications

Send test message:

curl -X POST "https://gotify.example.com/message?token=YOUR_APP_TOKEN"     -F "title=Test Notification"     -F "message=This is a test from your Gotify server"     -F "priority=8"

You should receive instant notification on your Android device.


Web UI Features

Message Management

Viewing messages:

  1. Navigate to Messages tab
  2. Select application from sidebar
  3. View message list with timestamps
  4. Click message to expand and see full content

Filtering:

  • Search messages by content
  • Filter by application
  • Sort by date or priority

Deleting messages:

  • Click trash icon on individual message
  • Click “Delete All” to clear application messages
  • Messages deleted from all connected clients

Application Management

Edit application:

  1. Apps tab → Click application
  2. Click Edit (pencil icon)
  3. Modify name, description, or priority
  4. Click Update

Delete application:

  1. Apps tab → Click application
  2. Click Delete (trash icon)
  3. Confirm deletion
  4. All messages for this application are deleted

View application token:

  1. Apps tab → Click application
  2. Token displayed at top
  3. Click to copy to clipboard

Statistics

View message statistics:

  1. Web UI → Messages tab
  2. See message counts per application
  3. Monitor notification delivery success

Integration Examples

Bash Script Monitoring

Disk space monitor:

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

GOTIFY_URL="https://gotify.example.com/message"
GOTIFY_TOKEN="Axxxxxxxxxxxxxxxxx"
THRESHOLD=90

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

if [ "$USAGE" -gt "$THRESHOLD" ]; then
    curl -X POST "$GOTIFY_URL?token=$GOTIFY_TOKEN"         -F "title=Disk Space Alert"         -F "message=Root partition at ${USAGE}% (threshold: ${THRESHOLD}%)"         -F "priority=9"
fi

Schedule with cron:

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

Docker Container Monitor

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

GOTIFY_URL="https://gotify.example.com/message"
GOTIFY_TOKEN="Axxxxxxxxxxxxxxxxx"
CONTAINERS=("nginx" "postgres" "redis")

for container in "${CONTAINERS[@]}"; do
    if ! docker ps --format '{{.Names}}' | grep -q "^${container}$"; then
        curl -X POST "$GOTIFY_URL?token=$GOTIFY_TOKEN"             -F "title=Container Down"             -F "message=Container $container is not running!"             -F "priority=10"
    fi
done

Python Integration

#!/usr/bin/env python3
# gotify_notify.py

import requests

def send_notification(title, message, priority=5):
    """Send notification to Gotify server."""
    url = "https://gotify.example.com/message"
    token = "Axxxxxxxxxxxxxxxxx"

    data = {
        "title": title,
        "message": message,
        "priority": priority
    }

    params = {"token": token}

    try:
        response = requests.post(url, params=params, data=data)
        response.raise_for_status()
        print(f"Notification sent: {response.json()['id']}")
    except requests.exceptions.RequestException as e:
        print(f"Failed to send notification: {e}")

# Usage
if __name__ == "__main__":
    send_notification(
        title="Backup Complete",
        message="Daily backup completed successfully at 2 AM",
        priority=5
    )

Home Assistant Integration

Add to configuration.yaml:

notify:
  - name: gotify
    platform: rest
    resource: https://gotify.example.com/message
    method: POST_JSON
    authentication: basic
    headers:
      X-Gotify-Key: "Axxxxxxxxxxxxxxxxx"
    data:
      title: "{{ title }}"
      priority: "{{ priority }}"
    message_param_name: message

Use in automations:

automation:
  - alias: "Motion detected"
    trigger:
      platform: state
      entity_id: binary_sensor.motion_sensor
      to: 'on'
    action:
      service: notify.gotify
      data:
        message: "Motion detected in living room"
        data:
          title: "Security Alert"
          priority: 8

Uptime Kuma Integration

  1. Uptime Kuma → Settings → Notifications
  2. Add Notification → Gotify
  3. Configure:
    • Server URL: https://gotify.example.com
    • Application Token: Axxxxxxxxxxxxxxxxx
    • Priority: 8
  4. Test and Save

Grafana Webhook

Configure Grafana contact point:

  1. Grafana → Alerting → Contact points

  2. Add contact point:

    • Name: Gotify
    • Integration: Webhook
    • URL: https://gotify.example.com/message?token=Axxxxxxxxxxxxxxxxx
    • HTTP Method: POST
    • Content-Type: application/x-www-form-urlencoded
  3. Body template:

title={{ .CommonLabels.alertname }}&message={{ .CommonAnnotations.summary }}&priority=9

n8n Workflow

  1. Add HTTP Request node
  2. Configure:
    • Method: POST
    • URL: https://gotify.example.com/message?token=Axxxxxxxxxxxxxxxxx
    • Body Content Type: Form-Data
    • Body parameters:
      • title: {{ $json.title }}
      • message: {{ $json.message }}
      • priority: {{ $json.priority }}

Advanced Configuration

Environment Variables

Full list of configuration options:

# Server
- GOTIFY_SERVER_PORT=80
- GOTIFY_SERVER_KEEPALIVEPERIODECONDS=0
- GOTIFY_SERVER_LISTENADDR=
- GOTIFY_SERVER_SSL_ENABLED=false
- GOTIFY_SERVER_SSL_CERTFILE=
- GOTIFY_SERVER_SSL_CERTKEY=
- GOTIFY_SERVER_SSL_LETSENCRYPT_ENABLED=false
- GOTIFY_SERVER_SSL_LETSENCRYPT_ACCEPTTOS=false
- GOTIFY_SERVER_SSL_LETSENCRYPT_CACHE=certs
- GOTIFY_SERVER_SSL_LETSENCRYPT_HOSTS=
- GOTIFY_SERVER_RESPONSEHEADERS=

# Database
- GOTIFY_DATABASE_DIALECT=sqlite3
- GOTIFY_DATABASE_CONNECTION=data/gotify.db

# For PostgreSQL (optional):
# - GOTIFY_DATABASE_DIALECT=postgres
# - GOTIFY_DATABASE_CONNECTION=host=postgres port=5432 user=gotify dbname=gotify password=secret

# Uploads
- GOTIFY_UPLOADEDIMAGESDIR=data/images
- GOTIFY_PLUGINSDIR=data/plugins

# Registration
- GOTIFY_REGISTRATION=false

# Passphrase for encryption
- GOTIFY_PASSPHRASE=

PostgreSQL Backend (Optional)

For high-traffic deployments:

# docker-compose.yml
services:
  postgres:
    image: postgres:16-alpine
    container_name: gotify-postgres
    restart: always
    environment:
      POSTGRES_DB: gotify
      POSTGRES_USER: gotify
      POSTGRES_PASSWORD: SECURE_PASSWORD
    volumes:
      - ./postgres_data:/var/lib/postgresql/data
    networks:
      - gotify

  gotify:
    image: gotify/server:latest
    container_name: gotify
    restart: always
    environment:
      - GOTIFY_DATABASE_DIALECT=postgres
      - GOTIFY_DATABASE_CONNECTION=host=postgres port=5432 user=gotify dbname=gotify password=SECURE_PASSWORD sslmode=disable
    depends_on:
      - postgres
    # ... rest of configuration

Plugin System

Gotify supports plugins for extended functionality:

Installing plugins:

  1. Download plugin .so file for your architecture
  2. Place in ./data/plugins/ directory
  3. Restart Gotify
  4. Web UI → Plugins tab → Configure

Popular plugins:

  • broadcast: Broadcast messages to multiple applications
  • example: Template for creating custom plugins

Custom Styling

Customize web UI appearance:

  1. Create custom CSS file
  2. Mount in docker-compose.yml:
    volumes:
      - ./custom.css:/app/ui/custom.css:ro

Security Best Practices

Disable Public Registration

# docker-compose.yml
- GOTIFY_REGISTRATION=false

Only admins can create users via web UI.

Use HTTPS

Always access Gotify via HTTPS:

  • Protects API tokens in transit
  • Prevents message interception
  • Required for secure WebSocket connections

Token Management

Best practices:

  • Create separate application for each service
  • Rotate tokens periodically
  • Delete unused applications
  • Never commit tokens to source control

Regenerate application token:

  1. Web UI → Apps → Select application
  2. Click Regenerate Token
  3. Confirm regeneration
  4. Update all services using old token

Rate Limiting

Implement rate limiting in reverse proxy:

Nginx example:

limit_req_zone $binary_remote_addr zone=gotify:10m rate=10r/s;

location / {
    limit_req zone=gotify burst=20 nodelay;
    proxy_pass http://localhost:8080;
    # ... rest of configuration
}

Firewall Rules

Restrict access to Gotify server:

# Allow only from specific IP ranges
ufw allow from 192.168.1.0/24 to any port 8080

# Or use reverse proxy with authentication

Monitoring and Troubleshooting

Health Checks

# Check service health
curl https://gotify.example.com/health

# Expected output:
# {"health":"green","database":"green"}

# Check version
curl https://gotify.example.com/version

# View current messages
curl -H "X-Gotify-Key: CLIENT_TOKEN"     https://gotify.example.com/message

Common Issues

Issue 1: Android App Not Receiving Notifications

Symptoms: Messages appear in web UI but not on Android

Solutions:

# Check Android app connection
# Web UI → Clients tab → Verify device is connected

# Ensure WebSocket connection is active
# Android app → Menu → Check connection status (green = connected)

# Verify battery optimization is disabled
# Android Settings → Apps → Gotify → Battery → Disable optimization

# Test with high-priority message
curl -X POST "https://gotify.example.com/message?token=TOKEN"     -F "title=Test"     -F "message=High priority test"     -F "priority=10"

Issue 2: Messages Not Stored

Symptoms: Messages sent successfully but don’t appear in web UI

Solutions:

# Check database file permissions
docker exec gotify ls -la /app/data/gotify.db

# Verify database is writable
docker exec gotify sqlite3 /app/data/gotify.db "PRAGMA integrity_check;"

# Check disk space
df -h /opt/gotify/data

Issue 3: WebSocket Connection Fails

Symptoms: Web UI shows “Disconnected” status

Solutions:

# Verify reverse proxy WebSocket headers
# Nginx:
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

# Test WebSocket directly
wscat -c wss://gotify.example.com/stream?token=CLIENT_TOKEN

Issue 4: High Memory Usage

Symptoms: Container consumes excessive RAM

Solutions:

# Add resource limits
    deploy:
      resources:
        limits:
          memory: 256M
        reservations:
          memory: 128M

# Clean up old messages
# Web UI → Messages → Delete old messages

Logging

Enable debug logging:

# Add to docker-compose.yml
    environment:
      - GOTIFY_SERVER_LOGLEVEL=debug

View logs:

# Real-time logs
docker compose logs -f gotify

# Search for errors
docker compose logs gotify | grep -i error

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

Backup and Recovery

Backup Script

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

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

mkdir -p "$BACKUP_DIR"

echo "Starting Gotify backup: $DATE"

# Backup SQLite database
cp /opt/gotify/data/gotify.db "$BACKUP_DIR/gotify-${DATE}.db"

if [ $? -eq 0 ]; then
    echo "Database backup successful"

    # Compress backup
    gzip "$BACKUP_DIR/gotify-${DATE}.db"
else
    echo "Database backup FAILED!" >&2
    exit 1
fi

# Backup uploaded images (optional)
if [ -d /opt/gotify/data/images ]; then
    tar czf "$BACKUP_DIR/gotify-images-${DATE}.tar.gz"         /opt/gotify/data/images
fi

# Cleanup old backups
find "$BACKUP_DIR" -name "gotify-*.gz" -mtime +$RETENTION_DAYS -delete

echo "Backup completed: $DATE"

Schedule daily:

chmod +x /opt/gotify/gotify-backup.sh
crontab -e
# Add: 0 3 * * * /opt/gotify/gotify-backup.sh >> /var/log/gotify-backup.log 2>&1

Disaster Recovery

# Stop service
docker compose down

# Restore database
gunzip -c /opt/backups/gotify/gotify-YYYYMMDD.db.gz >     /opt/gotify/data/gotify.db

# Restore images (if backed up)
tar xzf /opt/backups/gotify/gotify-images-YYYYMMDD.tar.gz -C /

# Restart service
docker compose up -d

# Verify
docker compose logs -f gotify

Database Maintenance

# Check database size
docker exec gotify ls -lh /app/data/gotify.db

# Vacuum database (reclaim space)
docker exec gotify sqlite3 /app/data/gotify.db "VACUUM;"

# Check database integrity
docker exec gotify sqlite3 /app/data/gotify.db "PRAGMA integrity_check;"

Comparison: Gotify vs. ntfy

Both are excellent self-hosted notification servers. Choose based on your needs:

FeatureGotifyntfy
Mobile SupportAndroid onlyAndroid + iOS
Message StoragePersistent SQLiteCache-based
Web UIFull-featuredBasic
OrganizationApplicationsTopics
AuthenticationUser accountsToken-based
APIREST + WebSocketHTTP-based
Best ForAndroid users, message historyCross-platform, simplicity

Use Gotify if:

  • All users have Android devices
  • Need comprehensive web UI for message management
  • Want persistent message storage
  • Prefer application-based organization

Use ntfy if:

  • Need iOS support
  • Want simpler setup
  • Prefer topic-based organization
  • Don’t require long-term message storage

Conclusion

You now have a fully functional Gotify notification server with:

  • Docker-based deployment for reliability
  • Application-based message organization
  • Web UI for comprehensive management
  • Android app for instant push notifications
  • REST API for easy integration
  • User management and access control
  • WebSocket real-time delivery
  • Automated backups

Next steps:

  1. Install Android app and connect to your server
  2. Create applications for different notification sources
  3. Integrate with monitoring tools and scripts
  4. Set up automated backups
  5. Configure notification priorities per application
  6. Explore plugin ecosystem

Gotify provides reliable, self-hosted push notifications with zero ongoing costs and complete privacy. Your notifications, your control, your infrastructure.


Additional Resources

Official:

Community:

API:


Last Updated: December 2025 Version Covered: Gotify 2.5.0+ Word Count: 3,619 words