How to Use Gotify: The Beginner's Guide (First Install, First App, First Token, First Push, and the Token-You-Never-Commit Rule)

CodexFuse Team · 2026-10-31T11:20:11.706Z · 17 min read

Learn how to use Gotify: install the free, self-hosted push server on Docker, create your first app token, push from a script, and connect the Android app.

How to Use Gotify: The Beginner's Guide (First Install, First App, First Token, First Push, and the Token-You-Never-Commit Rule)

Learning how to use Gotify is the answer to one very specific frustration: your scripts and monitors know things, and your phone does not. Gotify is a free, open-source, self-hosted push notification server written in Go (gotify/server on GitHub, v3.1.1 at the time of writing) that sends real-time messages from anything you run — backup scripts, cron jobs, Uptime Kuma, Home Assistant — straight to your phone, with no Google or Apple push service in the middle. The core idea is the app-token model: you create an application in the web UI for each notification source, and that app gets its own token you push messages with. This gotify tutorial walks the complete beginner arc in one sitting: install on Docker, log in and lock down the admin account, create your first app and token, send your first push from a shell script, connect the official Android app, and wire a real monitor to it. If containers are new to you, start with our Docker beginner guide first; if you want the fastest possible path from a script to a phone buzz with no accounts at all, read our ntfy beginner guide instead — ntfy is the topic-based sibling, and this guide draws the token-vs-topic line so you only have to pick once.

How to use Gotify for the first time: the 7-step arc

The fastest beginner path is: run the Docker container, log in and change the default admin password, create one test application and copy its token immediately, push one message with curl, connect the Android app and disable battery optimization, wire Uptime Kuma or a shell script to its own token, and put the server behind a reverse proxy with WebSocket support. That is the whole journey — everything else is scale and polish.

  1. Install it. One container, one volume, one admin password in the environment — the compose file below takes two minutes.
  2. Log in and change the admin password. The default login is admin, and it is the first thing you fix.
  3. Create a test application and copy the token now. Gotify 3 shows a token only at creation or rotation — close that screen without saving it and the token is gone forever.
  4. Send your first push. One curl command with the X-Gotify-Key header; the message appears in the WebUI instantly.
  5. Connect the Android app. Official app from F-Droid or the Play Store, log in with your server URL — then disable battery optimization or pushes die silently.
  6. Give every service its own app and token. Uptime Kuma gets an app, the backup script gets an app; a leaked token then burns only one lane.
  7. Put it behind a reverse proxy and back it up. The proxy must pass WebSocket upgrades, and the /app/data volume holds everything worth saving.

What is Gotify, exactly? (the app-token model)

Gotify is a small self-hosted server for sending and receiving real-time notifications, and its model is deliberately simple. A Gotify user owns clients and applications: an application sends messages and receives its own application token, while a client receives and manages messages. A server, script, or website sends an HTTPS request with that token, Gotify stores the message, and delivers it to connected clients through WebSockets. There are no channels to create and no bot accounts to invite — you make an app called "Uptime Kuma", use its token only in Uptime Kuma, and make another app called "Backups" with a different token for your scripts.

That separation is the whole point. If one token leaks, you rotate only that application's token instead of replacing one universal secret in every service you own. Application tokens send messages; user and client credentials read them — treat those as different roles, and never place a client credential into a server-side script when an application token is all you need.

The one comparison worth making early is with ntfy, the other lane in the self-hosted-notifications cluster. ntfy is topic-based and stateless: you pick a topic name, POST a message to it, and every subscriber gets it — no accounts, no tokens, and the fastest path from "I want a notification" to a buzzing phone. Gotify is application-based and persistent: you log into a web UI, create applications, each gets a token, messages are stored in a database, and you get a full dashboard with a plugin system. Pick the topic lane when the notification is fire-and-forget from scripts; pick Gotify when you want organized, categorized alert management with per-source tokens. The sibling ntfy lane covers that path in the same beginner depth.

Gotify install: Docker or binary?

Install Gotify with Docker if your server already runs containers, or run the standalone Go binary if it does not. The official container images are the easiest route when the rest of a server already uses Docker Compose; on a plain VPS, installing all of Docker's machinery to run one small Go binary is overkill, and the standalone binary with a systemd unit is the honest choice. Gotify 3.x is configured entirely through environment variables — there is no YAML config file anymore, and the server binary exposes serve, version, and migrate-config commands. The default database is SQLite, with MySQL and PostgreSQL supported when you outgrow it.

DecisionDocker pathBinary path
Best forServers already running Docker ComposePlain VPS with no container tooling
Install effortOne compose file, minutesDownload, verify, systemd unit — ~30 minutes
ConfigEnvironment variables in composeEnv file at /etc/gotify/server.env
Data/app/data volumeDirectory like /var/lib/gotify
UpdatesRe-tag and recreate the containerReplace the binary, restart the service
Image size~20 MB, sub-second startupOne static binary

How do you install Gotify with Docker?

Pin the image to a release and set the default admin password before the first start — the container creates the admin user admin on a fresh database, and the GOTIFY_DEFAULTUSER_PASS environment variable is what changes its password from the default. The compose file is deliberately small, which is the point: one service, one data volume, one exposed port.

services:
  gotify:
    image: gotify/server:3.1.1
    container_name: gotify
    environment:
      TZ: UTC
      GOTIFY_DEFAULTUSER_PASS: "pick-a-long-random-password"
    volumes:
      - gotify-data:/app/data
    ports:
      - "127.0.0.1:8094:80"
    restart: unless-stopped

volumes:
  gotify-data:

Bring it up with docker compose up -d and open http://localhost:8094. Log in as admin with the password you set, then change that password in the WebUI — the bootstrap value is only used while creating a new database, so rotating it in the interface is the real protection. Bind the port to localhost on purpose: Gotify itself listens on plain HTTP inside the container, and the reverse proxy on the host takes the public TLS connection. If you are running this on a rented box, see our what is VPS hosting explainer for how the machine underneath works.

What is the token-you-never-commit rule?

Open the Apps tab, click Create application, and give it a name like "Test" and a description — then copy the token immediately. Gotify 3 displays a token only during creation or rotation; close the window without saving it and the only fix is rotating it. Store every production token in a password manager or a protected secret file before you leave that screen. Never paste tokens into screenshots, tickets, chat messages, or a public repository — GitHub receives secrets every day, and yours does not need to be one of them.

When testing from a shell, keep the token out of your shell history. Read it into a temporary variable with silent input, use it, then unset it:

read -rsp "Paste the Test application token: " GOTIFY_TOKEN
echo
curl -fsS "https://notify.example.com/message" \
  -H "X-Gotify-Key: ${GOTIFY_TOKEN}" \
  -F "title=Gotify Test" \
  -F "message=My self-hosted notification server works." \
  -F "priority=5"
unset GOTIFY_TOKEN

The message should appear in the WebUI immediately. Two details matter here: only message is required by the API — a title and priority just make alerts usable — and prefer the X-Gotify-Key header over the ?token= query parameter, because query strings end up in proxy and server logs while headers do not. The token must never be committed to a repository or included in a release archive: the moment a token touches git history, rotate it.

What do Gotify priorities 0–10 actually mean?

Gotify accepts message priorities from 0 to 10, and the number decides how the receiving client presents the alert. On Android, the priority maps to sound and vibration behavior: 0 is silent, low priorities show an icon only, the middle band adds sound, and 8 and above add sound plus vibration. A community-managed hosted FAQ notes that priority 8 and above can even override Do Not Disturb on Android, which is exactly the semantics you want for "the disk is almost full" versus "a download finished". The exact numbers matter less than using them consistently — everything becomes critical when there is no policy, and when everything is critical, nothing is critical.

PriorityMeaningTypical alert
0–2Silent / informationalBackup completed after a previous failure; a service recovered
3–4Notice, no interruptionMaintenance finished; new user registered
5–7Warning, action needed laterDisk usage crossed a warning threshold; unattended upgrades pending
8–9Important failureUptime Kuma detected a service outage; a critical service stopped
10Critical, immediate attentionFilesystem almost full; database unavailable; repeated backup failures

How do you connect the Android app?

The official Gotify Android app is on both F-Droid and the Google Play Store — install it, enter your server URL, and log in with your Gotify user account. That is the whole setup; there is no topic name to guess and no channel to subscribe to, because applications you created are automatically visible to the user who owns them. Incoming messages appear in the WebUI and the Android client at the same time.

Then do the one step everyone misses: disable battery optimization for Gotify. Android kills long-running background apps to save battery, and Gotify keeps a persistent WebSocket connection open — with optimization enabled, Android will kill the app and your pushes die silently. On stock Android: Settings, search "Battery Optimization", find Gotify, and set it to unrestricted (the menu names vary by manufacturer, but the "don't optimize" choice is what you are after). One more reassurance: Gotify does not use Google's push services at all, so delivery works on degoogled phones — at the cost of that one always-on connection, which is far cheaper than polling.

What about iOS? (set the expectation honestly)

There is no official Gotify iOS app. The maintainers cite the Apple Developer account requirement as the blocker, and as of the time of writing that gap has not closed. Community workarounds exist — an iOS Shortcut that polls the server rather than receiving real push — and third-party UnifiedPush-style clients can connect, but nothing on iPhone delivers the instant push experience the Android app gives. If your household is iOS-first, that is a genuine reason to pick ntfy instead: it ships an iOS app that delivers through Apple's relay. Do not install Gotify expecting an iOS notification — set the expectation before you deploy.

How do you put Gotify behind a reverse proxy?

Gotify delivers messages to clients through WebSockets, so the reverse proxy must support the WebSocket upgrade and preserve the original Host header — Gotify verifies the host against the request origin. Break that rule and the WebUI loads while live message streaming silently stops. For nginx, that means HTTP 1.1 to the backend plus the Upgrade and Connection headers:

location / {
    proxy_pass http://127.0.0.1:8094;
    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-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_buffering off;
}

Two more rules ride along. First, the Android app's WebSocket connection requires HTTPS — mobile WebSocket libraries refuse plain HTTP — so get a real certificate on the proxy before touching the phone app. Second, keep Gotify itself bound to localhost and never expose its port in the firewall; only ports 80 and 443 should be publicly reachable. Caddy passes the WebSocket upgrade by default, which is why it is the shortest proxy route for Gotify — our Caddy beginner guide covers the HTTPS front end end to end.

How do you wire Uptime Kuma to Gotify?

Uptime Kuma ships a native Gotify notification provider, which makes this the ideal first real integration. Create a separate application in Gotify called "Uptime Kuma" and copy its new token immediately — one app per integration is the rule, remember. Then in Uptime Kuma open Settings, open Notifications, create a new notification, select Gotify, and enter the application token, the public Gotify server URL, and a priority from 0 to 10. Use the built-in test button, then attach the notification provider to the monitors that should use it. Our Uptime Kuma beginner guide covers the monitoring side in full.

One honest limitation: if Uptime Kuma and Gotify live on the same VPS, the notification path dies with the machine it is supposed to report on. When the whole box disappears, Gotify cannot send a message explaining that Gotify disappeared. The fix is another monitor with another notification path — infrastructure turns into a nesting doll fast — so for a small setup, understanding the limitation and adding one external check of the status endpoint is enough.

Gotify vs ntfy: which should you pick?

The two solve the same problem — server-driven pushes to your phone — with opposite philosophies, and the March-2026 comparison data makes the tradeoffs concrete. Neither approach is wrong; they optimize for different workflows. ntfy optimizes for fire-and-forget notifications from scripts. Gotify optimizes for organized, categorized alert management through a dashboard.

FeatureGotifyntfy
ModelApplication-based, per-app tokensTopic-based pub/sub, no accounts for basic use
UnifiedPushNoYes — the reference implementation
iOS appNo official appYes, via the ntfy.sh relay
Web UIFull dashboard: apps, users, clients, plugins, token managementFunctional message viewer, not a dashboard
Plugin systemYes (Go plugins: webhook receivers, RSS pollers)No
AuthRequired, user and passwordOptional, open by default
End-to-end encryptionNoYes, client-side
Scheduled deliveryNoYes
Priorities0–10 scale5 levels: min, low, default, high, urgent
DatabaseSQLite default; MySQL and PostgreSQL supportedSQLite cache with a TTL — not long-term archival
Public cloud fallbackNoYes, ntfy.sh
Idle RAM / image size~20 MB / ~20 MB~15 MB / ~15 MB
Rate limitingNo built-in rate limitingBuilt in, configurable

Pick Gotify when you want a web dashboard to view and organize all notifications, a plugin system for custom webhook receivers, per-source rotatable tokens, or long-term message storage in MySQL or PostgreSQL. Pick ntfy when you run a degoogled phone, need iOS support, want UnifiedPush, need a public fallback if your server goes down, or send notifications from dozens of scripts and refuse to manage tokens. A managed Gotify also exists for people who want the dashboard without the server, and pairing both is fine — many homelabs run Gotify for infrastructure alerts and ntfy for everything else.

Can you push from the terminal?

Yes — the official gotify/cli tool on GitHub is a command-line client for pushing messages to a Gotify server. It stores the server URL and token once, after which pushing is one command:

gotify push -t "Backup failed" "The daily backup did not complete." --priority 10

The CLI is the pragmatic choice inside scripts that already run on the box: no curl flags to get wrong, and the token lives in the CLI's stored config rather than inline in every script. For remote or multi-language senders, the one-HTTP-request REST API from the earlier section is the universal fallback.

How do you back up and update Gotify?

With SQLite, everything that matters lives in the data volume: the database holds users, applications, clients, messages, and the protected token data. Back up the volume and the configuration together. For a simple consistent copy, stop the container briefly and archive the volume — the interruption lasts only a moment on a small instance. Protect the backup like the server itself: anyone who can read it can read your notification history and your tokens.

docker compose stop gotify
docker run --rm -v gotify_gotify-data:/data -v /var/backups:/backup \
  alpine tar -czf /backup/gotify-$(date +%F).tar.gz -C /data .
docker compose start gotify

Updates are manual: Gotify is not updated by a package manager. Read the release notes first — Gotify 3 removed the old YAML configuration format and changed token handling, which is exactly the kind of detail that turns a blind image replacement into an educational outage — then re-tag the compose file to the new release, recreate the container, and send a test notification after the upgrade. A green container status confirms a process is running; it does not confirm that tokens, WebSockets, and the Android client still work, so the test push is the real check.

Beginner mistakes to avoid

MistakeWhat happensThe fix
Pasting the token into the shell directlyToken lands in shell history, visible to anyone with your userRead it with read -rsp, then unset it
Leaving Android battery optimization onAndroid kills Gotify; pushes die silentlySettings → Battery Optimization → Gotify → unrestricted
Closing the app-creation screen without savingToken shown once, then gone — you must rotateStore it in a password manager before leaving the screen
One universal token for every serviceOne leak burns every integrationOne application — one token — per notification source
Proxy without the WebSocket upgradeWebUI loads but live messages never streamPass Upgrade + Connection headers and preserve Host
Committing tokens to gitSecret in history foreverRotate immediately; read tokens from protected files
Gotify and its monitors on the same VPSAn outage kills the alerter with the alertedKnow the blind spot; add one external check
Expecting iOS pushDisappointmentAndroid-only for real push; ntfy if iOS matters

Sources

Release and version data from the GitHub gotify/server releases API (v3.1.1, published 2026-09-15); the full self-host walkthrough — app-token model, Gotify 3 env config, token-only-at-creation rule, shell-history hygiene, WebSocket proxy requirements, priority model, and backup flow — from the July 2026 Gotify 3 deployment guide at 0ut3r.space; configuration reference from gotify.net/docs/config (env-based config, _FILE secret variants, subcommand list); Docker install pattern and priority semantics from Jannis Mattheis's REST-API send guide; the token-vs-topic architecture, UnifiedPush, iOS, plugin, and resource comparisons from the March-2026 selfhosting.sh ntfy-vs-gotify comparison; the Android battery-optimization requirement and token format notes from the same send guide's Android section; the HTTPS-for-WebSocket rule and the "per-app rotatable token" pattern from the ElfHosted Gotify product FAQ; the gotify/cli command-line client from the GitHub gotify/cli repository.

Frequently asked questions

Is Gotify really free?

Yes. Gotify is open-source and self-hosted — the only cost is the server it runs on, and a ~20 MB Go binary runs fine on the smallest VPS. Managed hosting exists for people who do not want the server, but the software itself has no paid tier.

Does Gotify work on iPhone?

Not with real push. There is no official iOS app; community workarounds poll the server instead of receiving instant notifications. If iOS matters in your household, ntfy is the honest pick.

How is Gotify different from ntfy?

Gotify is application-based: each notification source is an app with its own token, managed in a full web dashboard. ntfy is topic-based: you POST to a topic name with no accounts and no tokens. Gotify is the dashboard lane; ntfy is the fire-and-forget lane.

Is my app token safe in a script?

Only if you treat it like a password: read it from a protected file with 0600 permissions, never put it in process arguments or source code, never commit it to a repository, and rotate the token the moment you suspect a leak. Gotify makes rotation cheap — one click per app.

How much server do I need for Gotify?

Almost none. The Docker image is about 20 MB and idle RAM is about the same; it starts in under a second. A single SQLite file handles a private instance comfortably, and MySQL or PostgreSQL are there only when you need them.

Featured on Twelve Tools Launch Llama Tools Launch your MCP