Gotify: Servidor de Notificaciones Push Self-Hosted

Gotify es un servidor de notificaciones push self-hosted simple y ligero que proporciona una API REST para enviar mensajes y una interfaz web con WebSocket para recibirlos en tiempo real, con aplicación nativa de Android incluida. Es la opción ideal para equipos que necesitan un sistema de notificaciones privado y sin dependencias de servicios externos como Firebase Cloud Messaging. Esta guía cubre la instalación con Docker, gestión de aplicaciones y integración con sistemas de monitorización.

Requisitos Previos

  • Linux con Docker instalado (o acceso al binario)
  • 256 MB RAM mínimo
  • Nginx como proxy inverso (recomendado)
  • Dominio con SSL para producción

Instalación con Docker

# Crear directorio de datos persistentes
mkdir -p /opt/gotify/data

# Ejecutar Gotify con Docker
docker run -d \
    --name gotify \
    --restart unless-stopped \
    -p 127.0.0.1:8080:80 \
    -v /opt/gotify/data:/app/data \
    -e TZ=Europe/Madrid \
    gotify/server:latest

# Verificar que está corriendo
docker ps | grep gotify
docker logs gotify --tail=20

Docker Compose (recomendado)

# /opt/gotify/docker-compose.yml
version: '3'

services:
  gotify:
    image: gotify/server:latest
    container_name: gotify
    restart: unless-stopped
    ports:
      - "127.0.0.1:8080:80"
    volumes:
      - ./data:/app/data
    environment:
      GOTIFY_DEFAULTUSER_NAME: admin
      GOTIFY_DEFAULTUSER_PASS: AdminPassword123!
      GOTIFY_PASSSTRENGTH: 12
      GOTIFY_UPLOADEDIMAGESDIR: data/images
      GOTIFY_PLUGINSDIR: data/plugins
      GOTIFY_REGISTRATION: "false"
      TZ: Europe/Madrid
      # Base de datos SQLite por defecto
      # Para producción, considera MySQL/PostgreSQL:
      # GOTIFY_DATABASE_DIALECT: postgres
      # GOTIFY_DATABASE_CONNECTION: "host=db port=5432 user=gotify password=pass dbname=gotify"
cd /opt/gotify
docker compose up -d

# Verificar el inicio
docker compose logs -f

Proxy inverso con Nginx

cat > /etc/nginx/sites-available/gotify << 'EOF'
server {
    listen 80;
    server_name notificaciones.tudominio.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name notificaciones.tudominio.com;

    ssl_certificate /etc/letsencrypt/live/notificaciones.tudominio.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/notificaciones.tudominio.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $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 support (necesario para recibir notificaciones en tiempo real)
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_read_timeout 86400s;
    }
}
EOF

ln -s /etc/nginx/sites-available/gotify /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx

# Obtener certificado SSL
certbot --nginx -d notificaciones.tudominio.com

Instalación del Binario

Para servidores sin Docker:

# Descargar el binario de Gotify
GOTIFY_VERSION="2.4.0"
curl -LO "https://github.com/gotify/server/releases/download/v${GOTIFY_VERSION}/gotify-linux-amd64.zip"
unzip gotify-linux-amd64.zip
mv gotify-linux-amd64 /usr/local/bin/gotify
chmod +x /usr/local/bin/gotify

# Crear directorio de datos
mkdir -p /var/lib/gotify

# Crear usuario del sistema
useradd --system --no-create-home --shell /bin/false gotify
chown gotify:gotify /var/lib/gotify

# Crear archivo de configuración
cat > /etc/gotify/config.yml << 'EOF'
server:
  keepaliveperiodseconds: 0
  listenaddr: 127.0.0.1
  port: 8080
  ssl:
    enabled: false
database:
  dialect: sqlite3
  connection: /var/lib/gotify/gotify.db
defaultuser:
  name: admin
  pass: AdminPassword123!
passstrength: 12
uploadedimagesdir: /var/lib/gotify/images
pluginsdir: /var/lib/gotify/plugins
registration: false
EOF

# Crear servicio systemd
cat > /etc/systemd/system/gotify.service << 'EOF'
[Unit]
Description=Gotify Push Notification Server
After=network.target

[Service]
Type=simple
User=gotify
Group=gotify
WorkingDirectory=/var/lib/gotify
ExecStart=/usr/local/bin/gotify --config /etc/gotify/config.yml
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable --now gotify
systemctl status gotify

Gestión de Aplicaciones y Clientes

En Gotify, la arquitectura se basa en:

  • Aplicaciones (Apps): fuentes de mensajes, cada una con su token de API
  • Clientes (Clients): consumidores de mensajes (dispositivos móviles, web, scripts)

Gestión desde la interfaz web

  1. Accede a https://notificaciones.tudominio.com
  2. Usuario: admin, Contraseña: la configurada en el setup
  3. Apps > Create Application: crear una nueva fuente de mensajes

Gestión via API

# Autenticarse y obtener token de usuario (para gestión)
# En la interfaz web: Clients > Create Client
# Copiar el token generado

CLIENT_TOKEN="tu-token-de-cliente"

# Listar todas las aplicaciones
curl https://notificaciones.tudominio.com/application \
    -H "X-Gotify-Key: $CLIENT_TOKEN" | jq '.[]'

# Crear una nueva aplicación para un servidor
APP_RESPONSE=$(curl -s -X POST https://notificaciones.tudominio.com/application \
    -H "X-Gotify-Key: $CLIENT_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
        "name": "Servidor Produccion",
        "description": "Alertas del servidor de producción principal"
    }')

echo $APP_RESPONSE | jq '.'
APP_TOKEN=$(echo $APP_RESPONSE | jq -r '.token')
echo "Token de la aplicación: $APP_TOKEN"

# Listar todos los mensajes
curl "https://notificaciones.tudominio.com/message?limit=20" \
    -H "X-Gotify-Key: $CLIENT_TOKEN" | jq '.'

# Eliminar un mensaje
curl -X DELETE https://notificaciones.tudominio.com/message/42 \
    -H "X-Gotify-Key: $CLIENT_TOKEN"

# Eliminar todos los mensajes de una aplicación
curl -X DELETE https://notificaciones.tudominio.com/application/1/message \
    -H "X-Gotify-Key: $CLIENT_TOKEN"

Uso de la API REST

Una vez que tienes el token de una aplicación, puedes enviar mensajes:

APP_TOKEN="token-de-tu-aplicacion"
GOTIFY_URL="https://notificaciones.tudominio.com"

# Enviar mensaje básico
curl -X POST "$GOTIFY_URL/message" \
    -H "X-Gotify-Key: $APP_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
        "title": "Servidor en línea",
        "message": "El servidor web arrancó correctamente",
        "priority": 2
    }'

# Enviar mensaje con prioridad alta
curl -X POST "$GOTIFY_URL/message" \
    -H "X-Gotify-Key: $APP_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
        "title": "ERROR: Base de datos no responde",
        "message": "PostgreSQL dejó de responder a las 14:32. Revisar logs en /var/log/postgresql/",
        "priority": 9
    }'

# Enviar mensaje con extras (markdown y enlaces)
curl -X POST "$GOTIFY_URL/message" \
    -H "X-Gotify-Key: $APP_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
        "title": "Reporte de Backup",
        "message": "## Backup Completado\n\n- **Estado**: Exitoso\n- **Archivos**: 15,234\n- **Tamaño**: 2.3 GB\n- **Duración**: 4m 32s",
        "priority": 3,
        "extras": {
            "client::display": {
                "contentType": "text/markdown"
            }
        }
    }'

Prioridades y Extras de Mensajes

Niveles de prioridad

# Prioridades de Gotify (0-10):
# 0: Min - notificación silenciosa
# 1-3: Low - notificación normal
# 4-7: Normal - notificación con sonido
# 8-10: High - notificación prominente, puede romper el silencio

# En la app Android de Gotify:
# Las prioridades altas (>= 8) activan el canal de máxima importancia

Extras para contenido enriquecido

# Mensaje con enlace clickeable
curl -X POST "$GOTIFY_URL/message" \
    -H "X-Gotify-Key: $APP_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
        "title": "Deploy completado",
        "message": "La versión 2.1.0 está en producción",
        "priority": 5,
        "extras": {
            "client::notification": {
                "click": {"url": "https://miapp.tudominio.com"}
            }
        }
    }'

# Mensaje con BigPicture (imagen en la notificación Android)
curl -X POST "$GOTIFY_URL/message" \
    -H "X-Gotify-Key: $APP_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
        "title": "Grafico de métricas",
        "message": "Rendimiento del último día",
        "priority": 3,
        "extras": {
            "android::action": {
                "onReceive": {"intentUrl": "https://grafana.tudominio.com/dashboard"}
            },
            "client::display": {
                "contentType": "text/markdown"
            }
        }
    }'

Integración con Monitorización

Alertas de Uptime Kuma

# En Uptime Kuma: Settings > Notifications > Add Notification
# Tipo: Gotify
# Server URL: https://notificaciones.tudominio.com
# Token: token de la aplicación de Uptime Kuma
# Priority: 8 (para alertas de caídas)

Script para alertas de sistema

cat > /usr/local/bin/gotify-alert.sh << 'EOF'
#!/bin/bash
# Script helper para enviar alertas a Gotify

GOTIFY_URL="https://notificaciones.tudominio.com"
APP_TOKEN="${GOTIFY_TOKEN:-}"  # Token desde variable de entorno o parámetro
TITULO="${1:-Sin título}"
MENSAJE="${2:-Sin mensaje}"
PRIORIDAD="${3:-5}"

if [ -z "$APP_TOKEN" ]; then
    echo "Error: GOTIFY_TOKEN no está configurado"
    exit 1
fi

RESPUESTA=$(curl -s -w "\n%{http_code}" -X POST "$GOTIFY_URL/message" \
    -H "X-Gotify-Key: $APP_TOKEN" \
    -H "Content-Type: application/json" \
    -d "{
        \"title\": \"$TITULO\",
        \"message\": \"$MENSAJE\",
        \"priority\": $PRIORIDAD
    }")

HTTP_CODE=$(echo "$RESPUESTA" | tail -1)

if [ "$HTTP_CODE" = "200" ]; then
    echo "Notificación enviada correctamente"
else
    echo "Error al enviar notificación: HTTP $HTTP_CODE"
    exit 1
fi
EOF

chmod +x /usr/local/bin/gotify-alert.sh

# Uso del script
export GOTIFY_TOKEN="tu-app-token"
gotify-alert.sh "Backup completado" "El backup de producción finalizó correctamente" 3
gotify-alert.sh "ERROR: Disco lleno" "El disco /dev/sda1 está al 98%" 9

Integración con Grafana

# En Grafana: Alerting > Contact Points > New contact point
# Tipo: webhook
# URL: https://notificaciones.tudominio.com/message?token=TU_APP_TOKEN
# Method: POST
# Headers: Content-Type: application/json

# Configurar el payload template en Grafana:
{
  "title": "Alerta: {{ .GroupLabels.alertname }}",
  "message": "{{ range .Alerts }}{{ .Annotations.description }}\n{{ end }}",
  "priority": 8
}

Alertas de cron jobs

# Wrapper para cron que notifica en caso de fallo
cat > /usr/local/bin/cron-with-gotify.sh << 'EOF'
#!/bin/bash
# Ejecutar un comando y notificar via Gotify si falla

COMANDO="$*"
GOTIFY_URL="https://notificaciones.tudominio.com"
GOTIFY_TOKEN="tu-app-token"

SALIDA=$(eval "$COMANDO" 2>&1)
CODIGO=$?

if [ $CODIGO -ne 0 ]; then
    curl -s -X POST "$GOTIFY_URL/message" \
        -H "X-Gotify-Key: $GOTIFY_TOKEN" \
        -H "Content-Type: application/json" \
        -d "{
            \"title\": \"Error en cron: $(hostname)\",
            \"message\": \"Comando: $COMANDO\nCódigo de salida: $CODIGO\nSalida:\n$SALIDA\",
            \"priority\": 7
        }"
    exit $CODIGO
fi
EOF

chmod +x /usr/local/bin/cron-with-gotify.sh

# Uso en crontab:
# 0 3 * * * root cron-with-gotify.sh /usr/local/bin/backup.sh

Solución de Problemas

El servidor no arranca

# Con Docker:
docker logs gotify --tail=50

# Con el binario:
journalctl -u gotify -n 50

# Problemas comunes:
# - Puerto 8080 ya en uso: cambiar el puerto en la configuración
# - Permisos del directorio de datos: chown -R gotify:gotify /var/lib/gotify

Los mensajes no llegan a la app Android

# Gotify usa WebSocket para la entrega en tiempo real
# Verificar que el proxy Nginx está configurado para WebSocket:
# proxy_set_header Upgrade $http_upgrade;
# proxy_set_header Connection "upgrade";

# Verificar conectividad WebSocket
curl -I -H "Upgrade: websocket" -H "Connection: Upgrade" \
    https://notificaciones.tudominio.com/stream?token=CLIENT_TOKEN

# En la app Android: verificar que la URL del servidor es correcta
# y que incluye https://

Error 401 al enviar mensajes

# Verificar que estás usando el token correcto
# Para enviar mensajes: token de la APLICACIÓN (App token)
# Para gestionar: token del CLIENTE (Client token)

# Listar aplicaciones y sus tokens (necesitas client token)
curl https://notificaciones.tudominio.com/application \
    -H "X-Gotify-Key: $CLIENT_TOKEN" | jq '.[] | {id, name, token}'

Conclusión

Gotify ofrece un sistema de notificaciones push privado y sin dependencias de Google o Apple con una arquitectura simple basada en WebSocket. Su combinación de API REST fácil de integrar, aplicación Android nativa, interfaz web y soporte para plugins lo hace adecuado tanto para alertas de servidores como para notificaciones de aplicaciones en producción. La instalación con Docker en menos de 5 minutos y el modelo de aplicaciones/clientes lo convierten en una pieza sencilla pero potente en cualquier stack de operaciones.