How to Self-Host ntfy in 2026: Topics, Access Control and Delivery
A practical ntfy self-hosting guide covering Docker, ports, persistent data, TLS, security, backups and the failures that block production use. Step by step.
Most ntfy installation notes end at the first page load. That is too early: the cache is ephemeral or WebSocket/SSE connections time out at the proxy. A useful production test is more demanding — publish a message with curl, receive it through HTTP and WebSocket subscriptions, attach a file and test one authenticated topic.
ntfy's role is straightforward: push notifications sent with a simple HTTP request. Its operational boundary includes more than the web process, so the dependency, stored state and public route all have to be named explicitly before real data arrives.
The production shape of ntfy
The ntfy HTTP process listens on 80; keep that port on the application network and publish only the platform route. The local runtime requirement is a config volume and optional auth database. Test that boundary before publication and again after a container replacement.
Write the boundary down as a short contract: who owns the requirement, which credential is used, what timeout is acceptable and how failure appears. Then run this transaction: publish a message with curl, receive it through HTTP and WebSocket subscriptions, attach a file and test one authenticated topic. Observe long-lived subscriber connections, attachment size, cache retention and outbound push relays during the run, because that workload gives a more useful starting size than an idle container.
Start ntfy without hiding the moving parts
Use the container as a replaceable runtime, not as the location of truth.
docker run -d \
--name ntfy \
--restart unless-stopped \
-p 127.0.0.1:80:80 \
-v ntfy-data:/var/cache/ntfy \
-e NTFY_BASE_URL=https://app.example.com \
binwiederhier/ntfy:latest serve
Confirm the local requirement before exposure: a config volume and optional auth database. Inspect the container user, writable paths and bound listener before exposing it. Run the complete action — publish a message with curl, receive it through HTTP and WebSocket subscriptions, attach a file and test one authenticated topic — and save the exact image reference that produced the result.
Give ntfy one canonical address
Set base-url to the public HTTPS origin used by publishers and subscribers. Send the chosen hostname to container port 80, forward the original host and HTTPS scheme, and avoid publishing a second direct origin.
Test ntfy from a clean external client. Separate ingress failure from the known application boundary — the cache is ephemeral or WebSocket/SSE connections time out at the proxy. A certificate, DNS or 502 error belongs to routing; a request that reaches ntfy and fails later belongs to application state, capacity or its supporting requirement. The custom-domain TLS guide covers the first group.
Prove ntfy survives replacement
Protect ntfy's state before optimizing its container. The required set is configuration, auth database and attachments that must survive. Mount /var/cache/ntfy before bootstrap, write harmless sample data and replace the container to prove that path is actually persistent. If multiple stores must agree, document the order in which writes are paused and backups are taken.
Keep copies outside the deployment server and encrypt material containing credentials or private content. Recovery succeeds when users, ACLs, configuration and retained attachments return and an authenticated subscriber receives a new message. The distinction between a persistent mount and an independent copy is covered in persistent storage and snapshots.
Do not give ntfy the whole host
For ntfy, the valuable surface is not necessarily the landing page. The main mistake is allowing public topic guessing when messages contain operational details. Counter it deliberately: use topic ACLs because unguessable topic names are not strong authorization for operational messages.
NTFY_BASE_URL is configuration rather than a secret; keep its value explicit while protecting the separate credentials used by ntfy. Use an unprivileged container user when the image supports it and mount no unrelated credentials. Apply rate or size limits at ingress where untrusted work can consume long-lived subscriber connections, attachment size, cache retention and outbound push relays.
Upgrade ntfy without guessing
Use publish a message with curl, receive it through HTTP and WebSocket subscriptions, attach a file and test one authenticated topic as the ntfy smoke test after every deployment. Its supporting metrics are long-lived subscriber connections, attachment size, cache retention and outbound push relays; alert where those resources approach a point that degrades the user action.
The main change risk is that configuration keys, auth database migrations and client expectations should be checked before updating ntfy. A safe release starts from a restorable snapshot and validates any one-way state change before traffic moves. When the cache is ephemeral or WebSocket/SSE connections time out at the proxy, keep the failed container long enough to read its configuration and first error.
The ntfy release gate
A release candidate for ntfy earns traffic by completing a fixed scenario: publish a message with curl, receive it through HTTP and WebSocket subscriptions, attach a file and test one authenticated topic. Capture the image digest, effective non-secret configuration, public origin and timestamps for that scenario. The test data should be disposable but realistic enough to exercise the same path as users.
Run it after replacing the runtime, then rebuild the service from configuration, auth database and attachments that must survive. Recovery passes when users, ACLs, configuration and retained attachments return and an authenticated subscriber receives a new message. Compare resource measurements for long-lived subscriber connections, attachment size, cache retention and outbound push relays with the prior release and investigate meaningful drift before promotion.
Finally, exercise this controlled failure: submit harmless input near the resource or format limit associated with this boundary: the cache is ephemeral or WebSocket/SSE connections time out at the proxy. Verify that ntfy explains the failure, does not damage existing state and resumes after the valid condition returns. Save a redacted log excerpt and the recovery time. Together these checks cover behavior, durability and operability rather than just process uptime.
Keep ntfy explicit while Dockup handles routing
Routing, certificates, service replacement and attached storage are reasonable automation targets. Dockup handles those for ntfy and can provision the related managed database or connect to services on a customer's own server.
What it should not invent is the ntfy trust policy. After deployment, set base-url to the public HTTPS origin used by publishers and subscribers, enforce this boundary — use topic ACLs because unguessable topic names are not strong authorization for operational messages — and verify the result of this scenario: publish a message with curl, receive it through HTTP and WebSocket subscriptions, attach a file and test one authenticated topic. The outcome is one-click infrastructure with an application-specific acceptance test.
Frequently asked questions
What does ntfy need for a production deployment?
Route the ntfy container on port 80 through one HTTPS origin. The local runtime requirement is a config volume and optional auth database. Do not call ntfy ready until you can publish a message with curl, receive it through HTTP and WebSocket subscriptions, attach a file and test one authenticated topic.
Which ntfy data belongs in a backup?
Persist /var/cache/ntfy and include configuration, auth database and attachments that must survive in the same recovery manifest. A clean ntfy restore passes only when users, ACLs, configuration and retained attachments return and an authenticated subscriber receives a new message.
Does ntfy require HTTPS behind a reverse proxy?
Use HTTPS for the public ntfy origin and keep port 80 on the internal route. Apply the ntfy setting correctly: set base-url to the public HTTPS origin used by publishers and subscribers. For ntfy, HTTPS protects credentials or user content in transit and keeps origin-sensitive client behavior consistent.
How should a ntfy upgrade be tested?
Restore current ntfy state into an isolated deployment, apply the candidate version and repeat its acceptance transaction. Pay particular attention because configuration keys, auth database migrations and client expectations should be checked before updating ntfy. Keep the previous ntfy image until its data-migration and rollback boundary are understood.
