What Ntfy Does Differently
Most self-hosted notification servers require a dedicated app, an account, or a token system that adds friction every time you want to wire up a new service. Ntfy strips that down to a single concept: publish to a topic, subscribe to a topic, receive a push notification. No accounts required on the receiving end, no registration flow, no API key handshake for basic use.

Installing Ntfy with Docker
Ntfy runs cleanly inside a Docker container, which makes it the fastest path to a working setup on any Linux server or VPS. Before starting, make sure Docker and Docker Compose are installed on your host machine. You will also want a domain name pointed at your server if you plan to receive notifications outside your local network, because the Android and iOS apps connect over HTTPS by default.
Create a directory for your Ntfy configuration and a docker-compose.yml file inside it. A minimal compose file looks like this:
- Image: binwiederhier/ntfy – the official image maintained by the project author
- Command: serve – starts the HTTP server
- Port mapping: 80:80 or your preferred host port bound to container port 80
- Volume: map a local directory to /var/cache/ntfy for message cache persistence
- Volume: map your config file to /etc/ntfy/server.yml
- Restart policy: unless-stopped so the container survives reboots
Your server.yml configuration file controls nearly every behavior worth tuning. At minimum, set the base-url field to your full domain, including the scheme, such as https://ntfy.example.com. This value is what the server uses when generating web push payloads and subscription links. Without it, web push will not function correctly and the self-generated URLs in the web interface will be wrong. Set cache-duration to something like 12h or 24h so that messages are held server-side for devices that were offline when a notification arrived.
Run docker compose up -d to bring the container up in detached mode. If the port is open and the image pulled correctly, visiting your server’s IP or domain in a browser should load the Ntfy web interface. From there you can send a test notification directly through the UI to confirm the server is alive before touching any external services.
Configuring Authentication, HTTPS, and Access Control
Running Ntfy without authentication means anyone who can reach your server can publish to any topic and read any message. That is acceptable on a locked-down home network, but it is a real exposure problem on a public VPS. Ntfy includes a built-in user management system that lets you restrict who can publish and who can subscribe on a per-topic basis.
Enable authentication by adding auth-default-access: deny-all to your server.yml. This setting blocks all unauthenticated requests. From there, use the Ntfy CLI to create users: run ntfy user add username inside the container with docker exec -it ntfy-container-name ntfy user add username. You will be prompted for a password. To give that user publish access to a specific topic, run ntfy access username topicname rw, where rw grants both read and write. Use ro for read-only subscribers and wo for write-only publishers like scripts or monitoring tools.

HTTPS is non-negotiable for anything leaving your local network. The cleanest approach is to put Ntfy behind a reverse proxy like Nginx or Caddy. Caddy handles certificate provisioning automatically via Let’s Encrypt, which removes the manual renewal step entirely. A minimal Caddyfile entry points your domain to the Ntfy container’s internal port and Caddy takes care of the rest. If you are already running Uptime Kuma or another self-hosted tool behind a reverse proxy on the same host, you can add Ntfy as another block in the same proxy configuration without spinning up separate infrastructure.
Web push – the mechanism that delivers notifications to Chrome and Firefox browser tabs even when the Ntfy web UI is not open – requires an additional configuration step. Generate a VAPID key pair using the command ntfy webpush keys, then add the web-push-public-key, web-push-private-key, and web-push-file values to your server.yml. The web-push-file path should point to a location inside your persistent volume so subscriptions survive container restarts. Without this, browser-based push will silently fail and users will only receive notifications while the tab is actively open.
For mobile, install the Ntfy app on Android or iOS, open settings, and point it at your server URL. If you enabled authentication, enter your credentials there. Subscribe to a topic by name and the app will maintain a persistent connection in the background. Android users on non-Google builds or those running GrapheneOS can use the UnifiedPush integration, which routes notifications through Ntfy itself rather than Firebase Cloud Messaging, keeping the entire notification path off Google’s infrastructure.
Sending Notifications from Scripts and Services
Publishing a notification requires nothing more than an HTTP POST request to your server. A basic curl command looks like this: curl -d “Backup completed” https://ntfy.example.com/my-topic. For authenticated servers, add -u username:password to the command. You can attach a title with the Title header, set a priority level from 1 to 5 with the Priority header, tag messages for filtering with the Tags header, and even attach a click-through URL using the Click header. This makes Ntfy a practical drop-in for alerting from cron jobs, backup scripts, server monitoring pipelines, or any webhook-capable application.
Ntfy also supports a JSON payload format for more complex notification shapes, and it exposes a simple PUT endpoint for attaching files to messages. If your use case involves alerting from a home automation platform like Home Assistant, Ntfy has a native integration available in the community store. The real question for most self-hosters is not whether Ntfy can handle the use case, but whether the topic naming scheme they start with will still make sense six months and forty scripts later.






