Skip to content

Self-host ntfy

updated Sep 2026prices checked · Jul 2026Install verified on Ubuntu 26.04 · Aug 2026 · how we test
We earn commissions when you shop through the links below. Full disclosure →

Send push notifications to your phone or desktop from any script with a simple HTTP PUT or POST — no accounts, no cloud. A tiny Go binary that turns `curl` into a notification pipeline for your servers and cron jobs.

Key facts

CategoryPush notifications
LicenseApache-2.0
StackGo
Min RAM256 MB
Official imageyes
Measured idle RAM13 MB
Difficulty
Our recommendation

Pick ntfy when you want push notifications that reach every device you own — it has first-party Android, iOS, web and CLI clients — from a single Go binary or container with no external database. Publishing is an HTTP PUT or POST to a topic URL — `curl -d "Backup successful" ntfy.example.com/mytopic` — and topics are created on the fly, which is why the docs say the topic name is essentially a password. The repository ships both an Apache-2.0 `LICENSE` and `LICENSE.GPLv2`; the README calls the project dual-licensed. Just do not skip the config step: a fresh ntfy server is open to the world by default.

Follow the ntfy deploy guide →

What you need

  • Any VPS with at least 256 MB of RAM
  • A domain you control — most self-hosted setups need HTTPS in front of them
  • Under an hour if you've used Docker before
Where to host itaffiliate disclosure
Hetzner Cloudrun it on
From $23.59/mo · 2 vCPU / 4 GB / 80 GB · EU + US
Get Hetzner Cloud (opens in new tab)
Kamaterafree trial
From $4/mo · 1 vCPU / 1 GB / 20 GB · US + EU + Asia
Start free on Kamatera → (opens in new tab)
DigitalOceanalso works on
From $6/mo · 1 vCPU / 1 GB / 25 GB · US + EU + Asia
Deploy on DigitalOcean → (opens in new tab)

Paid link — we earn a commission if you shop through it.

Install with Docker Compose

Save this as compose.yml and run docker compose up -d:

# ntfy — pub/sub push notifications
services:
  ntfy:
    image: binwiederhier/ntfy:latest
    command: serve
    ports: ["80:80"]
    environment:
      NTFY_BASE_URL: http://SERVER_IP
      NTFY_BEHIND_PROXY: "true"
    volumes:
      - ./cache:/var/cache/ntfy
      - ./etc:/etc/ntfy
    restart: unless-stopped
# docker compose up -d  →  http://SERVER_IP
# as written anyone can publish and subscribe: before exposing it, set NTFY_AUTH_FILE=/var/lib/ntfy/user.db and NTFY_AUTH_DEFAULT_ACCESS=deny-all (mount a volume there), then add a user with: docker compose exec ntfy ntfy user add --role=admin NAME
# add NTFY_CACHE_FILE=/var/cache/ntfy/cache.db to keep undelivered messages across restarts

What you take on

ntfy's defaults are tuned for the public ntfy.sh service, not for a private server, and its own docs flag each of these:

non-negotiable"By default, the ntfy server is open for everyone, meaning everyone can read and write to any topic." For a private instance set auth-file and auth-default-access: deny-all, then create users — before you publish the URL.
non-negotiableInstant iOS notifications on a self-hosted server require upstream-base-url: "https://ntfy.sh" so poll requests are forwarded through the public server; the docs state that iOS restrictions make instant push impossible without a central server. If that relay is unacceptable, iOS users get delayed delivery.
non-negotiableMessages are kept in memory for 12 hours by default and attachments for 3 hours. Our snippet mounts /var/cache/ntfy but you still have to set cache-file (e.g. NTFY_CACHE_FILE: /var/cache/ntfy/cache.db) or messages vanish on restart; attachments additionally need base-url and attachment-cache-dir.
non-negotiableBehind a proxy you must set behind-proxy (our snippet does), or the docs warn that every visitor is rate-limited as if they were one client.

Head-to-head

More self-hosted tools

We use analytics cookies (Google Analytics, PostHog) to see which guides are useful. No ad networks, no cross-site tracking. See our privacy policy.