How to Install Gotify on Ubuntu 24.04 — Self-Hosted Push Notifications on Your VPS
If you run servers, you need notifications. Cron jobs fail, disks fill up, SSL certificates expire, backups break, and containers restart — and you want to know immediately without paying per-message fees to a SaaS vendor or granting a third party access to your alert stream. Gotify is a tiny, self-hosted push notification server written in Go that delivers messages over WebSocket to a web UI and a native Android app. This guide takes you from a fresh Ubuntu 24.04 VPS to a TLS-secured Gotify instance wired into your monitoring stack.
Prefer the managed route? Spin up a CloudCore Starter VPS in 60 seconds and follow along. At EUR 7.99/month, it is more than enough to run Gotify plus a reverse proxy.
Table of Contents
What is Gotify?
Gotify is an open-source, self-hosted push notification service. The entire server ships as a single static Go binary (roughly 15 MB) with an embedded React web UI. You send messages to Gotify via a simple HTTP POST using an application token, and Gotify fans those messages out to every connected client over a persistent WebSocket connection. The source code lives at github.com/gotify/server under the MIT license.
The architecture has three core concepts:
- Applications — Senders. Each application has its own token. A
backupapp, aprometheusapp, and ahome-assistantapp would each have distinct tokens, so you can revoke one without breaking the others. - Clients — Receivers. Your phone, your browser, a desktop client, or a custom script. Each client has its own token and sees every message for every app the user owns.
- Users — The owner of apps and clients. A single-user install is the common case. Multi-user mode lets you share one server across a team.
Typical use cases include monitoring alerts (Prometheus Alertmanager, Grafana, Uptime Kuma), cron job status reports, CI/CD pipeline notifications, home automation events (Home Assistant, Node-RED), security alerts from intrusion detection systems, and personal workflows ("notify me when my rsync backup finishes"). Anything that can curl a URL can push to Gotify in one line.
Why Self-Host a Push Notification Server?
Hosted notification services like Pushover, PushBullet, and Pushcut work well, but they come with trade-offs that matter for technical users:
- Zero per-message cost — Gotify is free forever. Pushover limits you to 10,000 messages per app per month on the USD 5 one-time license. Gotify has no caps.
- No third-party message inspection — Your alert text never leaves infrastructure you control. For security-sensitive alerts (failed login attempts, IDS triggers, leaked-credential warnings), that matters.
- Low latency — Messages travel directly from your VPS to your phone over your own domain. No central broker round-trips.
- No vendor lock-in — The API is a handful of HTTP endpoints. If Gotify ever stops development, swapping to Ntfy or a custom service takes hours, not weeks.
- Works offline-ish — If your monitoring runs on the same VPS as Gotify, alerts still flow even when upstream providers are down.
- Arbitrary payload control — Priorities, custom extras, Markdown rendering, click actions — all defined by you, not capped by a SaaS tier.
CloudCore Plan Recommendations for Gotify
Gotify is tiny. The hard floor is about 30 MB of RAM for the server itself. Most of your resource budget goes to the reverse proxy, the OS, and any co-located services.
| Workload | Recommended Plan | Specs | Price |
|---|---|---|---|
| Gotify only / Gotify + Nginx + small stack | CloudCore Starter (recommended) | 1 vCPU, 2 GB RAM, 40 GB NVMe | EUR 7.99/mo |
| Gotify + full monitoring (Prometheus, Grafana, Uptime Kuma) | CloudCore Professional | 6 vCPU, 12 GB RAM, 100 GB NVMe | EUR 19.99/mo |
| Team deployment, 50+ users, plugins | CloudCore Business | 8 vCPU, 24 GB RAM, 200 GB NVMe | EUR 29.99/mo |
Gotify vs. Ntfy vs. Pushover vs. Apprise
Before you install anything, it is worth understanding where Gotify sits in the ecosystem.
| Feature | Gotify | Ntfy | Pushover | Apprise |
|---|---|---|---|---|
| License | MIT (server), GPLv3 (Android app) | Apache 2.0 | Proprietary | MIT |
| Self-hostable | Yes | Yes | No | N/A (library) |
| Official iOS app | No | Yes | Yes | N/A |
| Official Android app | Yes | Yes | Yes | N/A |
| Web UI | Yes (built-in) | Yes (built-in) | Yes (hosted) | No |
| User accounts | Yes | Optional | Yes | N/A |
| Persistence | Yes (SQLite/MySQL/PostgreSQL) | Yes (SQLite) | Yes (cloud) | No |
| Pricing model | Free, self-hosted | Free, self-hosted or paid cloud | USD 5 one-time per platform | Free, self-hosted |
| Message cap | Unlimited | Unlimited (self-hosted) | 10,000/app/month | N/A |
| Plugin system | Yes (Go plugins) | Limited | No | N/A (library, fans out to 80+ services) |
| Best for | Single-VPS alerting, power users | iOS users, topic-based pub/sub | Non-technical users, iOS/Android | Scripts that need to fan out to many services |
- Choose Gotify if you want a self-hosted server with a web UI, user accounts, and persistent history — the classic "personal alerting server."
- Choose Ntfy if you need iOS support or prefer topic-based pub/sub without accounts.
- Choose Pushover if you are not technical and just want it to work with a one-time fee.
- Use Apprise inside your scripts when you need to push the same alert to Gotify, Ntfy, Telegram, and Slack simultaneously.
Prerequisites
Before you begin, make sure you have:
- A VPS running Ubuntu 24.04 LTS with root or sudo access — we recommend a CloudCore Starter
- SSH access to the server
- A domain name pointed to the VPS (for example,
gotify.yourdomain.com) with an A record in place - Ports 80 and 443 open in your firewall (for Let's Encrypt and HTTPS)
- 512 MB of RAM minimum, 2 GB recommended for comfortable co-located services
- An Android device (optional, but highly recommended for the full push experience)
ssh root@your-server-ipStep 1: Update and Harden Ubuntu 24.04
Bring the system up to date and install the packages we will need:
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl wget unzip ufw ca-certificatesIf a new kernel was installed, reboot:
sudo rebootConfigure the firewall. Gotify itself listens on port 80 by default, but we will front it with Nginx on 443, so we only need to expose HTTP and HTTPS:
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw --force enable
sudo ufw statusCreate a dedicated system user so Gotify does not run as root:
sudo useradd --system --home /var/lib/gotify --shell /usr/sbin/nologin gotify
sudo mkdir -p /var/lib/gotify /etc/gotify
sudo chown -R gotify:gotify /var/lib/gotify /etc/gotifyYou now have a minimal hardened base. Pick one of the two install paths below.
Step 2a: Install Gotify from the Official Binary
The binary install is lighter than Docker and integrates natively with systemd and journald. It is the recommended option for single-purpose VPSs.
Find the latest release version at github.com/gotify/server/releases. At time of writing, Gotify 2.6.x is current. We will download the Linux amd64 build:
GOTIFY_VERSION="2.6.1"
cd /tmp
wget "https://github.com/gotify/server/releases/download/v${GOTIFY_VERSION}/gotify-linux-amd64.zip"
unzip gotify-linux-amd64.zip
sudo mv gotify-linux-amd64 /usr/local/bin/gotify
sudo chmod +x /usr/local/bin/gotifyFor ARM servers (Ampere, Raspberry Pi, Oracle A1), replace amd64 with arm64.
Verify the install:
/usr/local/bin/gotify versionExpected output:
Version: 2.6.1
Commit: abcdef1234567890
BuildDate: 2026-03-10-12:00:00
ModuleMode: on
Go: go1.22.5
OS: linux
Arch: amd64Skip to Step 3.
Step 2b: Install Gotify with Docker Compose
If you prefer containerized services, Gotify publishes official images at gotify/server.
Install Docker Engine if it is not already present:
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USERLog out and back in for the group change to apply.
Create a working directory and compose file:
sudo mkdir -p /opt/gotify
cd /opt/gotifyWrite /opt/gotify/docker-compose.yml:
services:
gotify:
image: gotify/server:2.6.1
container_name: gotify
restart: unless-stopped
ports:
- "127.0.0.1:8080:80"
environment:
- TZ=Europe/Berlin
- GOTIFY_DEFAULTUSER_NAME=admin
- GOTIFY_DEFAULTUSER_PASS=change-me-now
- GOTIFY_PASSSTRENGTH=10
- GOTIFY_UPLOADEDIMAGESDIR=data/images
- GOTIFY_PLUGINSDIR=data/plugins
- GOTIFY_SERVER_SSL_ENABLED=false
volumes:
- ./data:/app/dataNotice the port binding 127.0.0.1:8080:80 — this keeps Gotify accessible only from localhost so Nginx can proxy to it. We never expose the container directly to the internet.
Launch the stack:
docker compose up -d
docker compose logs -fYou should see Gotify bind to :80 inside the container and be reachable on http://127.0.0.1:8080 on the host.
Step 3: Configure config.yml
For binary installs, Gotify reads /etc/gotify/config.yml. For Docker installs, environment variables (as shown above) cover most of what you need, but you can also mount a config.yml into /app/data/config.yml.
Create /etc/gotify/config.yml (binary installs):
server: keepaliveperiodseconds: 0 listenaddr: "127.0.0.1" port: 8080 ssl: enabled: false responseheaders: X-Content-Type-Options: nosniff X-Frame-Options: DENY Referrer-Policy: no-referrer cors: alloworigins: - ".+.yourdomain.com" allowmethods: - "GET" - "POST" allowheaders: - "Authorization" - "content-type" stream: pingperiodseconds: 45 allowedorigins: - ".+.yourdomain.com"database: dialect: sqlite3 connection: /var/lib/gotify/gotify.db
defaultuser: name: admin pass: change-me-now
passstrength: 10
uploadedimagesdir: /var/lib/gotify/images pluginsdir: /var/lib/gotify/plugins registration: false
Key settings explained:
server.listenaddr: "127.0.0.1"— Bind only to localhost. Nginx will handle public traffic on 443.server.port: 8080— Internal port. Does not need to match the public port.server.ssl.enabled: false— TLS is terminated by Nginx, not Gotify. Simpler cert renewal with Certbot.database.dialect: sqlite3— Default. For MySQL, usedialect: mysqland a DSN connection string. For PostgreSQL, usepostgres.defaultuser— The admin account created on first boot. Change the password immediately in the web UI.passstrength: 10— bcrypt cost factor. 10 is the sweet spot.registration: false— Disables public sign-up. You add users manually from the admin UI.cors.alloworigins— Restricts which origins may hit the REST API from a browser. Lock this down.
sudo chown -R gotify:gotify /etc/gotify /var/lib/gotifyUsing MySQL instead of SQLite looks like this:
database:
dialect: mysql
connection: gotify:s3cret@tcp(127.0.0.1:3306)/gotify?charset=utf8&parseTime=True&loc=LocalSwitch only if you expect tens of thousands of messages per day or need multi-node HA. For everyone else, SQLite handles millions of rows without noticeable slowdown.
Step 4: Create a systemd Service (Binary Install)
Write /etc/systemd/system/gotify.service:
[Unit] Description=Gotify Server Documentation=https://gotify.net After=network-online.target Wants=network-online.target[Service] Type=simple User=gotify Group=gotify WorkingDirectory=/var/lib/gotify Environment=GOTIFY_CONFIG=/etc/gotify/config.yml ExecStart=/usr/local/bin/gotify Restart=on-failure RestartSec=5
Hardening
NoNewPrivileges=true PrivateTmp=true ProtectSystem=strict ReadWritePaths=/var/lib/gotify ProtectHome=true ProtectKernelTunables=true ProtectKernelModules=true ProtectControlGroups=true RestrictSUIDSGID=true LockPersonality=true
[Install] WantedBy=multi-user.target
Enable and start:
sudo systemctl daemon-reload
sudo systemctl enable --now gotify
sudo systemctl status gotifyExpected status output:
● gotify.service - Gotify Server
Loaded: loaded (/etc/systemd/system/gotify.service; enabled; preset: enabled)
Active: active (running) since Thu 2026-04-16 12:05:00 UTC; 3s ago
Main PID: 4215 (gotify)
Tasks: 8 (limit: 4631)
Memory: 28.4MConfirm the local endpoint answers:
curl -s http://127.0.0.1:8080/healthExpected output:
{"health":"green","database":"green"}Step 5: Reverse Proxy with Nginx and TLS
Gotify must sit behind a TLS-terminating proxy because the Android app requires HTTPS and because WebSocket traffic should never traverse the public internet unencrypted. We will use Nginx with Let's Encrypt. For a deeper dive, see our Nginx install guide.
Install Nginx and Certbot:
sudo apt install -y nginx certbot python3-certbot-nginxObtain a certificate (replace the domain):
sudo certbot certonly --nginx -d gotify.yourdomain.com --agree-tos --email [email protected] --no-eff-emailWrite /etc/nginx/sites-available/gotify:
map $http_upgrade $connection_upgrade { default upgrade; '' close; }server { listen 80; server_name gotify.yourdomain.com; return 301 https://$host$request_uri; }
server { listen 443 ssl http2; server_name gotify.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/gotify.yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/gotify.yourdomain.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on;
add_header Strict-Transport-Security "max-age=63072000" always; add_header X-Content-Type-Options nosniff always; add_header X-Frame-Options DENY always; add_header Referrer-Policy no-referrer always;
client_max_body_size 32m;
location / { proxy_pass http://127.0.0.1:8080; proxy_http_version 1.1;
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 for /stream proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 3600s; proxy_send_timeout 3600s; proxy_connect_timeout 60s; proxy_buffering off; } }
The map block and proxy_set_header Upgrade/Connection lines are critical — without them, the WebSocket connection used by clients to receive push messages silently fails and messages only arrive after an HTTP refresh.
Enable and reload:
sudo ln -s /etc/nginx/sites-available/gotify /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginxVisit https://gotify.yourdomain.com in your browser. You should see the Gotify login screen.
Step 6: Create Apps, Clients, and Users
Log in with admin and the password you set in config.yml (or the Docker env). Change the password immediately under Users -> admin -> Edit password.
Create an Application (Sender)
Navigate to Apps -> Create Application:
- Name —
backups - Description —
rsync + restic nightly backups - Default priority —
5
A0Abc123def456. Copy this token. Every alert from your backup script will include it as the authentication credential.Repeat for each sender you plan to integrate: prometheus, uptime-kuma, home-assistant, ci-cd, etc.
Create Clients (Receivers)
A client token represents one subscriber. Your phone is one client. Your second phone is another. A desktop browser bookmark can be yet another.
Navigate to Clients -> Create Client:
- Name —
Pixel 8
Create Additional Users (Optional)
If your team shares one Gotify instance, create a user per team member. Navigate to Users -> Create User and set a role of user (normal) or admin (full access). Each user has their own apps and clients and cannot see other users' messages.
Step 7: Install the Gotify Android App
Install the Gotify Android client from F-Droid or the Google Play Store.
On first launch:
https://gotify.yourdomain.com.Once connected, the app shows a list of received messages grouped by application. Tapping a message opens the full body with Markdown rendered.
A critical detail on Android 12+: grant the app the Alarms & reminders permission and, if available on your device, Autostart. These keep the WebSocket alive across deep-sleep windows. Without them, you may miss notifications for a few minutes after the phone sleeps.
Step 8: Send Your First Notification with curl
Test end to end. Replace APP_TOKEN with the token from the backups app you created:
curl -X POST "https://gotify.yourdomain.com/message?token=APP_TOKEN" \
-F "title=Backup Completed" \
-F "message=Nightly restic backup finished in 4m12s (2.3 GB transferred)." \
-F "priority=5"Within a second or two, the message appears in the web UI and on your phone.
Priority Levels
Gotify uses a numeric priority scale. The Android app maps these to Android notification channels so you can silence low-priority alerts without missing critical ones.
| Priority | Android Behavior |
|---|---|
| 0-3 | Min importance, no sound |
| 4-7 | Default importance, silent by default depending on channel |
| 8+ | High importance, sound and vibration, bypasses Do Not Disturb (if user allows) |
Markdown and Extras
Gotify supports Markdown rendering via the content_type extra:
curl -X POST "https://gotify.yourdomain.com/message?token=APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"title": "Disk Usage Alert",
"message": "/var/log is at 92%.\n\n- /var/log/journal — 4.1 GB\n- /var/log/nginx — 1.8 GB\n\nRun journalctl --vacuum-time=7d.",
"priority": 8,
"extras": {
"client::display": {
"contentType": "text/markdown"
},
"client::notification": {
"click": { "url": "https://grafana.yourdomain.com/d/disk-dashboard" }
}
}
}'The client::notification.click.url extra makes the Android notification open a URL when tapped — useful for linking straight to the Grafana dashboard that triggered the alert.
Send from Python
import requests
requests.post( "https://gotify.yourdomain.com/message", params={"token": "APP_TOKEN"}, json={ "title": "CI Pipeline Passed", "message": "Commit abc1234 passed all checks in 2m17s.", "priority": 4, }, timeout=5, )
Send from Go
http.PostForm("https://gotify.yourdomain.com/message?token=APP_TOKEN",
url.Values{
"title": {"Deploy OK"},
"message": {"Release v2.4.1 is live."},
"priority": {"5"},
})Step 9: Plugins and Extensions
Gotify has a Go-based plugin system that lets you extend the server with custom message sources. Popular community plugins include:
- gotify/cmd-plugin — Runs shell commands on incoming messages.
- gotify/plugin-template — Scaffolding for building your own.
- RSS plugins — Poll a feed and push new items as notifications.
.so files) against the exact Gotify version you are running. Drop them into /var/lib/gotify/plugins/ and restart:sudo systemctl restart gotifyThe web UI exposes plugin config under Plugins once they are loaded. For most users, the REST API plus a reverse proxy is enough — plugins are advanced territory.
Integrations: Monitoring Stack Examples
Prometheus Alertmanager
Add Gotify as a webhook receiver in alertmanager.yml. See our deep dive in the Alertmanager install guide:
receivers:
- name: gotify
webhook_configs:
- url: "https://gotify.yourdomain.com/message?token=PROM_APP_TOKEN"
send_resolved: true
http_config:
follow_redirects: trueGotify accepts Alertmanager's JSON payload if you wrap it with a small adapter, or you can use the community alertmanager-gotify-bridge sidecar which translates the schema.
Uptime Kuma
Uptime Kuma has native Gotify support. In Notifications -> Setup Notification -> Gotify:
- Gotify Application Token — paste your
uptime-kumaapp token - Gotify Server URL —
https://gotify.yourdomain.com - Priority —
8for outages,4for recovery
Home Assistant
In configuration.yaml:
notify:
- name: gotify
platform: rest
resource: https://gotify.yourdomain.com/message
method: POST_JSON
headers:
X-Gotify-Key: HA_APP_TOKEN
data:
priority: 5
title_param_name: title
message_param_name: messageAny automation can now call notify.gotify to push a message.
Shell Script One-Liner
Define a helper in ~/.bashrc:
gotify() {
local title="${1:-Notification}"
local message="${2:-(no body)}"
local priority="${3:-5}"
curl -s -X POST "https://gotify.yourdomain.com/message?token=$GOTIFY_TOKEN" \
-F "title=$title" \
-F "message=$message" \
-F "priority=$priority" > /dev/null
}Then sprinkle gotify "Backup done" "$(du -sh /backups | cut -f1)" 4 throughout your cron jobs and scripts.
Performance and Scaling
Gotify is built on Gin (HTTP) and Gorilla WebSocket. Single-node performance is remarkable:
- Idle RAM — ~30 MB
- RAM per 1,000 concurrent WebSocket clients — ~60 MB
- Messages per second — 5,000+ on a 1 vCPU VPS with SQLite, limited mostly by fsync
- Message latency — 5-50 ms local network, 50-200 ms across continents
- Switch SQLite to PostgreSQL for concurrent writes.
- Set
server.keepaliveperiodsecondsto 30 for mobile clients behind NATs with short idle timeouts. - Put Gotify behind HAProxy or Cloudflare for TLS offload at higher volume.
- Run multiple Gotify replicas sharing a PostgreSQL backend if you exceed 10,000 concurrent clients per node.
Backups
The entire state lives in one SQLite file plus the plugins directory. Back it up nightly:
sudo install -m 0750 -o gotify -g gotify -d /var/backups/gotify
sudo -u gotify sqlite3 /var/lib/gotify/gotify.db ".backup /var/backups/gotify/gotify-$(date +%F).db"Pipe the backup file into your offsite backup job (restic, rclone, etc.).
Troubleshooting
| Problem | Cause | Solution |
|---|---|---|
502 Bad Gateway from Nginx | Gotify not running or wrong upstream port | sudo systemctl status gotify, confirm listenaddr/port in config.yml match proxy_pass |
| Web UI loads but messages do not arrive in real time | Nginx missing WebSocket headers | Verify proxy_set_header Upgrade $http_upgrade and the map block in your Nginx config |
| Android app shows "Connection failed" | TLS cert invalid or mixed HTTP/HTTPS | Use https:// only, confirm Let's Encrypt renewal with sudo certbot renew --dry-run |
| Notifications delayed on Android | Aggressive battery optimization | Disable battery optimization for the Gotify app; grant autostart permission |
curl: (22) The requested URL returned error: 401 | Wrong or missing app token | Check the token exactly; tokens are case-sensitive and include leading capital letter |
| Gotify fails to start after upgrade | Database schema migration failed | Stop service, back up gotify.db, then start with journalctl -u gotify -f to see exact error |
| High memory use after weeks of uptime | Old messages accumulating | Gotify auto-prunes per-app message history; lower per-app message limits in the admin UI |
| Messages missing after reboot | Docker volume not mounted | Confirm ./data:/app/data in docker-compose.yml and that ./data/gotify.db exists |
Useful Debug Commands
Stream logs in real time:
sudo journalctl -u gotify -fCheck the public endpoint with verbose output:
curl -vk https://gotify.yourdomain.com/healthTail Nginx error log during a failed connection:
sudo tail -f /var/log/nginx/error.logTest the WebSocket endpoint directly (requires websocat):
sudo apt install -y websocat
websocat -H="X-Gotify-Key: CLIENT_TOKEN" wss://gotify.yourdomain.com/streamYou should see a JSON frame per incoming message.
FAQ
What are the minimum hardware requirements for Gotify?
Gotify is one of the lightest self-hosted services you can run. The server binary uses about 30 MB of RAM at idle and tens of MB under load. A 1 vCPU, 512 MB RAM VPS is enough for a personal instance. For production alongside Nginx, Let's Encrypt, and a small monitoring stack, the CloudCore Starter plan at EUR 7.99/month (1 vCPU, 2 GB RAM, 40 GB NVMe) is the recommended sweet spot. Teams running dozens of apps and hundreds of clients are fine on CloudCore Professional.
Is Gotify free and open source?
Yes. The Gotify server is MIT-licensed and fully open source. Source code is at github.com/gotify/server. The Android app is GPLv3. There are no paid tiers, no telemetry, no license keys, and no usage caps when you self-host. The project is maintained by volunteers and accepts contributions on GitHub.
How is Gotify different from Ntfy, Pushover, and Apprise?
Gotify is a self-hosted server with a web UI, user accounts, persistent SQLite/MySQL storage, and a plugin system. Ntfy is also self-hostable but uses topic-based pub/sub with no built-in accounts — anyone who knows your topic can listen. Pushover is a paid managed service (one-time USD 5 per platform, with a 10,000 messages-per-app-per-month cap). Apprise is a Python library that fans out notifications to 80+ services — it is not a server, so you typically combine Apprise inside your scripts with Gotify as one of its destinations.
Does Gotify support iOS?
There is no official Gotify iOS app. Apple Push Notification Service requires a paid Apple Developer account and a central relay server — a model that conflicts with Gotify's "everything self-hosted" philosophy. Third-party iOS clients (like Gomify) exist but vary in quality. If iOS is your primary mobile platform, Ntfy is the better choice — it has an official iOS app that polls through an open relay.
Can I use Gotify without the Android app?
Absolutely. The built-in web UI shows all messages in real time via WebSocket and works on any desktop browser. You can also write custom clients that authenticate with a client token and subscribe to the /stream WebSocket endpoint — a dozen lines of JavaScript, Go, or Python is enough. Some users run a permanent browser tab or a desktop Electron wrapper for work hours and skip mobile entirely.
What database does Gotify use?
Gotify defaults to SQLite, stored in /var/lib/gotify/gotify.db. SQLite is more than sufficient for almost any deployment — it handles millions of messages per day on modest hardware. For high-volume or multi-node setups, switch to MySQL or PostgreSQL by editing the database.dialect and database.connection fields in config.yml. Most users never need to switch.
Will Gotify messages survive a server reboot?
Yes. Messages are persisted to the database when Gotify receives them. After a reboot, all messages that were not yet delivered to a client remain queued, and connected clients see their full history on reconnect. You can also configure per-app message retention caps from the admin UI to prevent unbounded growth.
How do I migrate from a hosted service like Pushover?
For most integrations, you only change the URL and token. Scripts that POST to https://api.pushover.net/1/messages.json can be updated to POST to https://gotify.yourdomain.com/message?token=... with minimal field renaming (title and message are the same, priority uses a different scale). Write a small wrapper function and drop it in place of the Pushover client. Migrations typically take an afternoon.
Next Steps
Now that Gotify is live on your VPS, here is how to build out the surrounding stack:
- Wire up Uptime Kuma — Deploy Uptime Kuma and add Gotify as a notification channel. Within minutes you will get real push alerts every time a monitored endpoint goes down.
- Bring in Prometheus + Alertmanager — Follow our Alertmanager install guide and forward critical infrastructure alerts to Gotify with priority 8 so they bypass Do Not Disturb.
- Harden the Nginx front-end further — Our Nginx install and hardening guide covers fail2ban, rate limiting, and HTTP/3 for Gotify's public endpoint.
- Compare with Ntfy — If you need iOS support or topic-based pub/sub, read the Ntfy install guide. Many teams run both.
- Wrap it with Apprise — Install Apprise in your scripts so a single notification call fans out to Gotify, Slack, Telegram, and email. Great for cross-team visibility.
- Back up the database offsite — Schedule nightly SQLite snapshots and sync them with restic or rclone to an S3-compatible bucket. Losing
gotify.dbis losing your notification history.
- Build a dashboard tile — Expose
/healthand/metricon an internal Grafana dashboard alongside your other services. Treat Gotify like any other production service.
Ready to deploy? Grab a CloudCore Starter VPS for EUR 7.99/month and you will have Gotify running with TLS, an Android client, and monitoring integrations in under 30 minutes. No per-message fees, no vendor lock-in, no third party in your alert path — just a tiny Go binary doing exactly one job extremely well.