Taking Control of Your Own Notifications
Push notifications are everywhere, but the infrastructure behind them almost always belongs to someone else. Google’s Firebase Cloud Messaging, Apple’s APNs, and various third-party services handle the routing, storage, and delivery of messages that pass through your apps and services – and by extension, they have visibility into that traffic. For anyone running a homelab, a private server, or just a collection of self-hosted tools, that dependency on external notification infrastructure is a gap worth closing. Gotify fills that gap cleanly.
Gotify is an open-source, self-hosted notification server that lets you send and receive real-time push messages through your own infrastructure. It runs as a single lightweight binary or Docker container, exposes a REST API for sending messages, and includes a web interface plus an Android client for receiving them. You define the apps, you generate the tokens, and your notifications never leave your network unless you want them to. This guide walks through a complete Docker-based setup, from installation to sending your first message.

What You Need Before Starting
The setup assumes a Linux server – a VPS, a dedicated machine, or even a Raspberry Pi running at home. Docker and Docker Compose should already be installed. You will also want a domain name or subdomain pointing to your server if you plan to expose Gotify over HTTPS, which is strongly recommended for any setup where notifications leave your local network. A reverse proxy like Nginx or Caddy handles the TLS termination. If you’re only running Gotify locally and accessing it from within the same network, a plain HTTP setup over an internal IP is workable to start.
Port 80 and 443 should be open on your firewall if you’re going with a public-facing deployment. If you’re using UFW, make sure those rules are active before proceeding. The Gotify container itself only needs to expose a single port internally – by default 80 inside the container, which you map to whatever external port you choose. No database setup is required separately; Gotify uses SQLite by default and manages its own data directory. The entire stack is deliberately minimal.
Installing Gotify with Docker Compose
Create a directory for your Gotify setup, then write a docker-compose.yml file inside it. The configuration is short. You define the image as gotify/server, map the container port to a host port, set a data volume so your messages and configuration persist across container restarts, and pass a few environment variables. The most important variable at this stage is GOTIFY_DEFAULTUSER_PASS, which sets the password for the built-in admin account created on first run. Choose something strong here because this is the account with full API access.
A working compose file looks like this: set the image to gotify/server:latest, map host port 8080 to container port 80, mount a local ./gotify-data directory to /app/data inside the container, and set the environment variables GOTIFY_DEFAULTUSER_NAME and GOTIFY_DEFAULTUSER_PASS to your chosen credentials. Add restart: unless-stopped so the service comes back up automatically after a server reboot. Once the file is saved, run docker compose up -d from that directory. Docker pulls the image and starts the container in the background.
Open a browser and navigate to http://your-server-ip:8080. You should see the Gotify login page. Sign in with the admin credentials you set in the compose file. The dashboard is sparse by design – a navigation sidebar with sections for messages, apps, clients, and users. That directness is useful; there is nothing to configure before the service is usable. The first thing to do after logging in is create an application, which Gotify uses to namespace messages and issue API tokens.
Under the Apps section, click the plus icon and give your application a name – something descriptive like “Server Alerts” or “Backup Monitor.” Gotify generates a token for that app immediately. This token is what any external script or service will use to authenticate when sending a message. Treat it like a password. You can create as many apps as you need, each with its own token, which makes it easy to route different types of notifications through separate channels without mixing them together in the message feed.

Putting Gotify Behind a Reverse Proxy
Running Gotify on a raw port without TLS is fine for local testing but not for production use, especially if you are sending notifications from external services or accessing the server from a mobile device outside your home network. Caddy is the simplest option here because it handles certificate provisioning automatically through Let’s Encrypt with almost no manual configuration.
In your Caddyfile, add a block for your Gotify subdomain – something like gotify.yourdomain.com – and set it to reverse proxy to localhost:8080. Caddy negotiates the TLS certificate on its own when you start or reload it. For Nginx, the configuration is slightly more involved: you define a server block, add the SSL certificate paths after you’ve obtained them via Certbot, and proxy pass to the same localhost address. One detail specific to Gotify is WebSocket support – the real-time message delivery relies on a WebSocket connection, so your proxy config must include the appropriate upgrade headers. With Nginx, that means adding proxy_http_version 1.1, proxy_set_header Upgrade $http_upgrade, and proxy_set_header Connection “upgrade” inside the location block.
Sending Your First Notification
With the server running and the proxy configured, sending a message is a single HTTP POST request. Using curl, the command targets your Gotify URL at the /message endpoint with the app token passed as a query parameter. The request body is JSON containing a title, a message string, and a priority integer between 1 and 10. Priority affects how urgently the Android app surfaces the notification – low priority messages arrive quietly while high priority ones trigger standard push alerts.
A practical curl example: curl -X POST “https://gotify.yourdomain.com/message?token=YOUR_APP_TOKEN” -F “title=Test” -F “message=Gotify is working” -F “priority=5”. If everything is configured correctly, the message appears in the web dashboard immediately. From there you can start wiring Gotify into your actual workflows – shell scripts that report on cron job completions, monitoring tools that fire on service failures, backup utilities that confirm successful runs, or any application that supports custom webhook endpoints.
The Android app, available on F-Droid and as a direct APK download from the Gotify GitHub releases page, connects to your server URL and authenticates with a client token generated from the Clients section of the web UI. App tokens and client tokens serve different purposes: app tokens are for sending messages, client tokens are for receiving them. Once the Android app is connected, messages sent to any application on your server arrive as standard push notifications on your phone – routed entirely through your own server, with no third-party relay in the path. There is no iOS client maintained by the core project, though the REST API is open and community-built integrations exist for various platforms.





