ntfy
A simple HTTP-based pub/sub push notification service.
ntfy is an open-source service for sending push notifications to phones and desktops via HTTP PUT/POST requests from any script or application. It requires no sign-up, works with a simple topic-based subscription model, and has mobile apps for iOS and Android. Self-hosting ensures privacy and no rate limits.
Alternatives considered
Cloud Hosted
| Tool | Open Source | Free Tier | Monthly Cost |
|---|---|---|---|
| Pushover | No | No | $4.99 one-time/platform |
| Pushbullet | No | Limited | $4.99/mo |
Self Hosted
| Tool | Open Source | Full Features | Notes |
|---|---|---|---|
| Gotify | Yes | Yes | No iOS app |
Installation
Architecture
- Deployment: Single
ntfydeployment in thentfynamespace - Image:
binwiederhier/ntfy:v2.21.0(digest-pinned) - Storage: Longhorn PVC (
ntfy, annotatedk8up.io/backup: "true") for message cache and auth database - Networking: ClusterIP service on port 80, HTTPRoute via public gateway
Security
- Runs as
runAsUser: 0,runAsNonRoot: false— no privilege drop configured - Longhorn PVC encrypted at rest via SOPS-managed keys
Updates
Managed by Renovate. Image is digest-pinned.
Data Management
- PVC:
ntfy(Longhorn-encrypted,k8up.io/backup: "true") for message cache and auth database - Backups: k8up
Schedulebacks up the Longhorn PVC to Hetzner S3 via restic.
User Management
Login enabled with file-based auth (NTFY_AUTH_FILE). NTFY_AUTH_DEFAULT_ACCESS controls default topic access. No OIDC configured.
Configuration Management
NTFY_ENABLE_LOGIN,NTFY_AUTH_DEFAULT_ACCESS,NTFY_BEHIND_PROXY,NTFY_BASE_URL,NTFY_AUTH_FILE,NTFY_CACHE_FILEfrom ConfigMap- Longhorn encryption key from SOPS-encrypted secret
Administration
Usage
Subscribe to a topic in the ntfy mobile app or web UI. Send notifications via curl -d "message" Grafana alerts and other monitoring tools use ntfy as a notification channel. The ntfy-authsecret in the monitoring namespace contains credentials for thegrafana-to-ntfy` proxy.
Cluster-specific deviations from the above live in the per-cluster README — see k8s/apps/talos/ntfy/README.md.
Cluster Deployment
ntfy — Talos cluster
Cluster-specific notes only. General product info, "why we use it", and alternatives live in docusaurus/docs/apps/ntfy.mdx.
Deviations from defaults
Defaults live in docusaurus/docs/apps/ntfy.mdx — document anything this cluster does differently here, with a one-line reason.
- Image:
binwiederhier/ntfy:v2.24.0@sha256:f8a9b104313b87cc24ae4f775f39e6328205b57dff6ede3eaf098a91e5d79f59
Rendered manifests (kustomize build)
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
kustomize.toolkit.fluxcd.io/force: enabled
labels:
app: ntfy
name: ntfy
namespace: ntfy
spec:
replicas: 1
revisionHistoryLimit: 1
selector:
matchLabels:
app: ntfy
ingress: public
strategy:
type: Recreate
template:
metadata:
labels:
app: ntfy
ingress: public
spec:
containers:
- args:
- serve
env:
- name: NTFY_ENABLE_LOGIN
value: 'true'
- name: NTFY_AUTH_DEFAULT_ACCESS
value: deny-all
- name: NTFY_BEHIND_PROXY
value: 'true'
- name: NTFY_AUTH_FILE
value: /var/lib/ntfy/auth.db
- name: NTFY_CACHE_FILE
value: /var/lib/ntfy/cache.db
- name: TZ
value: CET
- name: NTFY_DEBUG
value: 'false'
- name: NTFY_LOG_LEVEL
value: INFO
- name: NTFY_BASE_URL
value: http://ntfy.web.kueber.eu
image: binwiederhier/ntfy:v2.24.0@sha256:f8a9b104313b87cc24ae4f775f39e6328205b57dff6ede3eaf098a91e5d79f59
name: ntfy
ports:
- containerPort: 80
name: web
volumeMounts:
- mountPath: /var/lib/ntfy/
name: cache-volume
- mountPath: /etc/ntfy/server.yml
name: config-volume
subPath: server-config.yaml
securityContext:
seccompProfile:
type: RuntimeDefault
volumes:
- name: cache-volume
persistentVolumeClaim:
claimName: ntfy
- configMap:
name: server-config-52bbc48m5c
name: config-volume