Gotify Push Notification Server
Gotify is a self-hosted push notification server that provides a simple REST API for sending messages to Android and web clients via WebSocket. Unlike ntfy, Gotify uses an application-based model where senders use per-application tokens, making it well-suited for alerting from multiple services with centralized management.
Prerequisites
- Linux VPS with Docker installed
- A domain name with DNS pointing to your server
- Nginx or Traefik for HTTPS termination
- Port 80 or a custom port open
Installing Gotify with Docker
# Create data directory
sudo mkdir -p /opt/gotify/data
# Run Gotify with Docker
docker run -d \
--name gotify \
--restart unless-stopped \
-p 8080:80 \
-v /opt/gotify/data:/app/data \
-e GOTIFY_DEFAULTUSER_PASS="ChangeThisPassword!" \
gotify/server:latest
# Verify it's running
docker ps | grep gotify
docker logs gotify --tail 20
Docker Compose Setup
# docker-compose.yml
version: '3'
services:
gotify:
image: gotify/server:latest
container_name: gotify
restart: unless-stopped
ports:
- "8080:80"
environment:
GOTIFY_DEFAULTUSER_PASS: "ChangeThisSecurePassword!"
GOTIFY_SERVER_PORT: 80
GOTIFY_DATABASE_DIALECT: sqlite3
GOTIFY_DATABASE_CONNECTION: data/gotify.db
GOTIFY_DEFAULTUSER_NAME: admin
volumes:
- gotify_data:/app/data
volumes:
gotify_data:
docker compose up -d
# Access the web UI at http://your-server-ip:8080
# Default credentials: admin / ChangeThisSecurePassword!
Binary Installation (Non-Docker)
# Download latest binary
GOTIFY_VERSION=$(curl -s https://api.github.com/repos/gotify/server/releases/latest | grep -o '"tag_name":"[^"]*"' | cut -d'"' -f4)
wget "https://github.com/gotify/server/releases/download/${GOTIFY_VERSION}/gotify-linux-amd64.zip"
unzip gotify-linux-amd64.zip
sudo mv gotify-linux-amd64 /usr/local/bin/gotify
chmod +x /usr/local/bin/gotify
# Create data directory
sudo mkdir -p /var/lib/gotify
# Create systemd service
sudo tee /etc/systemd/system/gotify.service << 'EOF'
[Unit]
Description=Gotify Push Notification Server
After=network.target
[Service]
Type=simple
User=nobody
WorkingDirectory=/var/lib/gotify
ExecStart=/usr/local/bin/gotify
Environment=GOTIFY_DEFAULTUSER_PASS=SecurePassword
Environment=GOTIFY_DATABASE_DIALECT=sqlite3
Environment=GOTIFY_DATABASE_CONNECTION=gotify.db
Restart=always
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable --now gotify
Application Management
Gotify uses "applications" as namespaced senders, each with its own token:
Via Web UI
- Log in at
http://your-server:8080 - Click Apps → Create Application
- Name:
Server Monitoring, Description:Alerts from monitoring scripts - Click Create — save the returned token
Via REST API
# Create an application
curl -X POST "http://localhost:8080/application" \
-u "admin:ChangeThisPassword!" \
-H "Content-Type: application/json" \
-d '{"name": "Server Monitoring", "description": "Monitoring alerts"}'
# Returns: {"id": 1, "token": "Axxxxxxxxxxxxxxxx", ...}
# List all applications
curl "http://localhost:8080/application" \
-u "admin:ChangeThisPassword!"
# Delete an application
curl -X DELETE "http://localhost:8080/application/1" \
-u "admin:ChangeThisPassword!"
# Create a second application for deployments
curl -X POST "http://localhost:8080/application" \
-u "admin:ChangeThisPassword!" \
-H "Content-Type: application/json" \
-d '{"name": "CI/CD Pipeline", "description": "Deployment notifications"}'
Message Priorities and Formatting
# Send a basic message using an application token
curl -X POST "http://localhost:8080/message" \
-H "X-Gotify-Key: Axxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"title": "Deployment Complete",
"message": "Version 1.2.3 deployed successfully",
"priority": 5
}'
# Priority levels:
# 1-3: Low (informational)
# 4-7: Normal
# 8-10: High (urgent alerts)
# Send with extras (clickable URL)
curl -X POST "http://localhost:8080/message" \
-H "X-Gotify-Key: Axxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"title": "Disk Warning",
"message": "Disk usage at 90% on web-01",
"priority": 8,
"extras": {
"client::notification": {
"click": {"url": "https://grafana.yourdomain.com/d/server-metrics"}
}
}
}'
# Send Markdown formatted message
curl -X POST "http://localhost:8080/message" \
-H "X-Gotify-Key: Axxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"title": "Weekly Report",
"message": "## Summary\n\n- **Uptime**: 99.9%\n- **Requests**: 1.2M\n- **Errors**: 42",
"priority": 3,
"extras": {
"client::display": {
"contentType": "text/markdown"
}
}
}'
Client Plugins
Android App
- Install Gotify from F-Droid or Google Play
- Settings → Add Server
- Server URL:
https://gotify.yourdomain.com - Username:
admin, Password: your password - Subscribe to applications to receive push notifications
Web UI / Browser Notifications
The built-in Gotify web UI supports Web Push notifications. Enable in browser settings when visiting https://gotify.yourdomain.com.
REST API Usage
# Get all messages
curl "http://localhost:8080/message" \
-u "admin:password"
# Get messages with pagination
curl "http://localhost:8080/message?limit=20&since=100" \
-u "admin:password"
# Delete all messages for an application
curl -X DELETE "http://localhost:8080/application/1/message" \
-u "admin:password"
# Delete a specific message
curl -X DELETE "http://localhost:8080/message/42" \
-u "admin:password"
# Get all clients (connected WebSocket sessions)
curl "http://localhost:8080/client" \
-u "admin:password"
# Create additional users
curl -X POST "http://localhost:8080/user" \
-u "admin:password" \
-H "Content-Type: application/json" \
-d '{"name": "alice", "pass": "AlicePassword123", "admin": false}'
WebSocket Subscription
// Listen for messages via WebSocket
const ws = new WebSocket('wss://gotify.yourdomain.com/stream?token=Cxxxxxxxxxxxxxxxx')
ws.onmessage = (event) => {
const msg = JSON.parse(event.data)
console.log(`[${msg.appid}] ${msg.title}: ${msg.message}`)
}
ws.onclose = () => {
console.log('Connection closed - reconnecting in 5s')
setTimeout(connect, 5000)
}
Monitoring Integration
Uptime Kuma
- Go to a monitor → Edit → Notifications
- Add notification → type: Gotify
- Server URL:
https://gotify.yourdomain.com - Application Token: your app token
- Priority: 8
Grafana
# Grafana → Alerting → Contact Points → New
# Type: Webhook
# URL: http://localhost:8080/message
# HTTP Method: POST
# Content-Type header: application/json
# Authorization header: Bearer Axxxxxxxxxxxxxxxx
# Template (message body):
{
"title": "{{ .Status }}: {{ .GroupLabels.alertname }}",
"message": "{{ range .Alerts }}{{ .Annotations.description }}{{ end }}",
"priority": 8
}
Backup Script Notifications
#!/bin/bash
# /usr/local/bin/backup-with-notify.sh
GOTIFY_URL="http://localhost:8080"
GOTIFY_TOKEN="Axxxxxxxxxxxxxxxx"
HOSTNAME=$(hostname)
notify() {
local title="$1"
local message="$2"
local priority="${3:-5}"
curl -s -X POST "$GOTIFY_URL/message" \
-H "X-Gotify-Key: $GOTIFY_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"title\":\"$title\",\"message\":\"$message\",\"priority\":$priority}" \
> /dev/null
}
# Send start notification
notify "Backup Started" "Backup started on $HOSTNAME at $(date)" 3
# Run backup
if /usr/local/bin/borg-backup.sh; then
notify "Backup Complete" "Backup completed successfully on $HOSTNAME" 3
else
notify "BACKUP FAILED" "Backup FAILED on $HOSTNAME at $(date). Check logs!" 10
fi
Nginx Reverse Proxy
# /etc/nginx/sites-available/gotify
server {
server_name gotify.yourdomain.com;
location / {
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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;
# Disable buffering for WebSocket and stream
proxy_buffering off;
proxy_read_timeout 3600s;
}
}
sudo ln -s /etc/nginx/sites-available/gotify /etc/nginx/sites-enabled/
sudo certbot --nginx -d gotify.yourdomain.com
sudo systemctl reload nginx
Troubleshooting
Android app not receiving push notifications:
# Verify token is correct in the app
# Check Gotify server is accessible from the internet
curl -I https://gotify.yourdomain.com
# Check WebSocket connectivity
curl --include \
--no-buffer \
--header "Upgrade: websocket" \
--header "Connection: Upgrade" \
https://gotify.yourdomain.com/stream?token=Cxxxxxxxxxxxxxxxx
Messages not appearing in web UI:
# Check message was created
curl "http://localhost:8080/message" -u "admin:password" | python3 -m json.tool
# Check database permissions
ls -la /opt/gotify/data/
docker exec gotify ls /app/data/
Gotify container keeps restarting:
# Check container logs
docker logs gotify --tail 50
# Verify data directory permissions
sudo chown -R nobody:nobody /opt/gotify/data
# Or check what user the container runs as
docker exec gotify id
Conclusion
Gotify provides a clean, application-scoped push notification service that works well as a centralized alerting hub for Linux infrastructure. Its simple REST API and WebSocket-based delivery make integration with monitoring tools, backup scripts, and CI/CD pipelines straightforward. The F-Droid Android client avoids Google Play dependencies, making it suitable for privacy-conscious environments.


