Every self-hosted setup eventually needs notifications. Watchtower updated a container? You want to know. Backup failed? Alert me. Server disk at 90%? Send a push notification to my phone.
Most people use Pushover ($5 one-time), ntfy (hosted service), or Discord webhooks. But if you’re self-hosting everything else, why not self-host your notifications too?
Gotify is a simple, self-hosted push notification server with a clean web UI, Android app, and dead-simple REST API. One curl command sends a notification to your phone.
Why Gotify?
- Simple REST API — one HTTP call sends a notification
- Android app — real push notifications (not polling)
- Web UI — see all notifications in the browser
- Priority levels — from silent to urgent
- Applications — separate notification streams per service
- Clients — subscribe to messages programmatically
- Plugins — extend with webhooks and custom logic
- Tiny footprint — runs on anything, ~10MB RAM
Limitations (Be Honest)
- No iOS app — Apple requires push notification services that Gotify can’t self-host. Use ntfy if you need iOS.
- No end-to-end encryption — messages are stored in plaintext on your server
- Basic UI — functional but not fancy
If you’re on Android (or just use the web UI), Gotify is perfect. iPhone users should look at ntfy instead.
Installation
Step 1: Create the directory
mkdir -p ~/gotify && cd ~/gotify
Step 2: Docker Compose
services:
gotify:
image: gotify/server:latest
container_name: gotify
ports:
- "127.0.0.1:8070:80"
environment:
GOTIFY_DEFAULTUSER_NAME: admin
GOTIFY_DEFAULTUSER_PASS: "${GOTIFY_ADMIN_PASS}"
volumes:
- ./data:/app/data
restart: unless-stopped
Step 3: Create .env
echo "GOTIFY_ADMIN_PASS=$(openssl rand -base64 16)" > .env
cat .env # Note the password!
Step 4: Start
docker compose up -d
Step 5: Access
Open http://your-server:8070. Log in with admin credentials.
Setting Up HTTPS
Essential for sending notifications over the internet:
See our reverse proxy guide for details.
Creating Applications
Each service that sends notifications gets its own Application with a unique token:
- Log into the web UI
- Go to Apps tab
- Click Create Application
- Name it (e.g., “Watchtower”, “Backup Script”, “Uptime Kuma”)
- Copy the token — you’ll need this to send messages
Create separate apps for each service so you can manage and mute them independently.
Sending Notifications
Basic curl
curl "https://gotify.yourdomain.com/message?token=YOUR_APP_TOKEN" \
-F "title=Backup Complete" \
-F "message=Daily backup finished successfully at $(date)" \
-F "priority=5"
That’s it. One line. Your phone buzzes.
Priority Levels
| Priority | Behavior (Android) | Use Case |
|---|---|---|
| 0 | Silent, no notification | Debug/verbose logs |
| 1-3 | Notification, no sound | Info messages |
| 4-7 | Notification with sound | Important alerts |
| 8-10 | Notification, sound, wake screen | Critical alerts |
With Markdown
curl "https://gotify.yourdomain.com/message?token=YOUR_APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"title": "Disk Alert",
"message": "## Warning\n\nDisk usage on **server1** is at **92%**.\n\nClean up `/var/log` or expand the volume.",
"priority": 8,
"extras": {
"client::display": {
"contentType": "text/markdown"
}
}
}'
Integration Examples
Watchtower (Container Updates)
Add to your Watchtower environment:
services:
watchtower:
image: containrrr/watchtower
environment:
WATCHTOWER_NOTIFICATION_URL: "gotify://gotify.yourdomain.com/YOUR_APP_TOKEN"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
Uptime Kuma
- In Uptime Kuma, go to Settings → Notifications
- Select Gotify as the notification type
- Enter your Gotify URL and application token
- Test and save
Now you get push notifications when services go down. See our Uptime Kuma guide for the full setup.
Bash Script Wrapper
Create a reusable notification function:
#!/bin/bash
# notify.sh - source this in your scripts
GOTIFY_URL="https://gotify.yourdomain.com"
GOTIFY_TOKEN="YOUR_APP_TOKEN"
notify() {
local title="$1"
local message="$2"
local priority="${3:-5}"
curl -sf "$GOTIFY_URL/message?token=$GOTIFY_TOKEN" \
-F "title=$title" \
-F "message=$message" \
-F "priority=$priority" \
>/dev/null 2>&1
}
# Usage:
# source ~/notify.sh
# notify "Backup" "Completed successfully" 3
# notify "CRITICAL" "Database is down!" 10
Cron Job Monitoring
#!/bin/bash
# backup.sh with notifications
source ~/notify.sh
if restic backup /data --repo /mnt/backup 2>&1; then
notify "Backup" "✅ Daily backup completed" 3
else
notify "Backup FAILED" "❌ Daily backup failed! Check logs." 10
fi
Disk Space Alert
#!/bin/bash
# disk-alert.sh — run via cron every hour
source ~/notify.sh
THRESHOLD=85
USAGE=$(df / | tail -1 | awk '{print $5}' | tr -d '%')
if [ "$USAGE" -gt "$THRESHOLD" ]; then
notify "Disk Alert" "⚠️ Root partition at ${USAGE}% (threshold: ${THRESHOLD}%)" 8
fi
Docker Container Health
#!/bin/bash
# container-check.sh
source ~/notify.sh
CONTAINERS=("nextcloud" "immich" "traefik" "postgres")
for c in "${CONTAINERS[@]}"; do
STATUS=$(docker inspect --format='{{.State.Status}}' "$c" 2>/dev/null)
if [ "$STATUS" != "running" ]; then
notify "Container Down" "🔴 $c is $STATUS" 9
fi
done
Android App Setup
- Install Gotify Android from Play Store (or download the APK from GitHub)
- Enter your Gotify URL:
https://gotify.yourdomain.com - Log in with your user credentials
- Notifications will appear in real-time
Battery tip: Gotify uses a WebSocket connection, not polling. Battery impact is minimal, but add it to your battery optimization whitelist to prevent Android from killing it.
Web Client
The web UI at https://gotify.yourdomain.com shows all messages with:
- Filtering by application
- Delete individual or all messages
- Real-time updates via WebSocket
No app installation needed — works in any browser.
Multi-User Setup
Create separate users for family members or team members:
- Admin → Users → Create User
- Each user gets their own message stream
- Users can create their own applications
- Admin sees everything
Resource Usage
Gotify is incredibly lightweight:
| Metric | Value |
|---|---|
| RAM | ~10-15MB |
| CPU | Negligible |
| Storage | ~50MB + messages |
| Docker image | ~15MB |
It’ll run on literally anything — Raspberry Pi Zero, old phone, any VPS.
Gotify vs Alternatives
| Feature | Gotify | ntfy | Pushover | Discord Webhook |
|---|---|---|---|---|
| Self-hosted | ✅ | ✅ | ❌ | ❌ |
| iOS support | ❌ | ✅ | ✅ | ✅ |
| Android app | ✅ | ✅ | ✅ | N/A |
| REST API | ✅ | ✅ | ✅ | ✅ |
| Priority levels | ✅ | ✅ | ✅ | ❌ |
| Markdown | ✅ | ⚠️ Limited | ❌ | ✅ |
| Free | ✅ | ✅ (hosted) | $5 once | ✅ |
| E2E encryption | ❌ | ❌ | ❌ | ❌ |
| Resource usage | ~10MB | ~10MB | N/A | N/A |
Pick Gotify if you’re on Android and want full self-hosting. Pick ntfy if you need iOS. Pick Pushover if you don’t care about self-hosting and want the easiest setup.
Troubleshooting
Android app not receiving notifications: Check battery optimization settings. Android aggressively kills background apps. Whitelist Gotify in battery settings and disable “adaptive battery” for it.
Messages delayed: Verify WebSocket connection isn’t being terminated by your reverse proxy. For Nginx, add:
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400s;
Can’t log in:
Reset admin password by deleting ./data/gotify.db and restarting (this deletes all data). Or use the API to change it.
Conclusion
Gotify does one thing perfectly: gets notifications from your server to your phone. The API is dead simple, the Android app works great, and it runs on ~10MB of RAM.
Add it to your homelab and never miss a failed backup, downed container, or full disk again.
Related guides: