Deployment guide

Uptime Kuma with ntfy 2.5.8

Overview

Uptime Kuma is a self-hosted uptime monitor. It checks HTTP and HTTPS endpoints, keywords, TCP ports, ping, DNS records, certificate expiry, databases and more, with a dashboard, history and status pages. ntfy is a self-hosted push-notification server: anything that can make an HTTP request can publish to a topic, and the ntfy app for Android and iOS, a browser or a script can subscribe to it.

This image runs Uptime Kuma with ntfy 2.5.8 on Ubuntu 24.04 from SecureAnyCloud on Amazon EC2. It is one version of the SecureAnyCloud Hardened Uptime Kuma, Gatus & Uptime and Status Pages AMIs listing on AWS Marketplace. You pick it as the software version when you subscribe and launch. The listing's guide hub describes the other products in the listing.

The two products work as one alert pipeline, not two programs installed side by side. First boot creates Uptime Kuma's default notification channel, ntfy (this instance). It points at the ntfy server on the same instance and uses the instance's own access token, so every monitor you create alerts through it with nothing to configure. You subscribe your phone, browser or scripts to the instance's own topic. Alerts never depend on an outside notification service, and both the monitoring data and the alert history stay on your instance.

What you get

  • Uptime Kuma 2.5.8 (uptime-kuma.service) from the official 2.5.8 release, running as the unprivileged kuma user on 127.0.0.1:3001 only. Its production dependencies are updated to releases that fix every known advisory reachable at run time, and Node.js 22.23.4 runs it.
  • ntfy 2.34.0 (ntfy.service), compiled by SecureAnyCloud from the official 2.34.0 source with Go 1.27.3 and running as the unprivileged ntfy user on 127.0.0.1:8088 only. Building from source pins the Go toolchain, ntfy's build tags and its link against the system C library. govulncheck finds no vulnerability reachable in this build.
  • nginx publishing Uptime Kuma over HTTPS on port 443 and ntfy over HTTPS on port 8443, with a certificate created on your instance's first boot. Port 80 redirects to HTTPS.
  • An Uptime Kuma admin account, an ntfy SecureAnyCloud user, an ntfy access token and an ntfy topic, all unique to your instance and created on first boot.
  • The default ntfy (this instance) notification channel and a self-check monitor of the ntfy server.
  • uptime-kuma-ntfy-set-hostname, a helper to serve both under your own DNS name, and sac-uptime-kuma-e2e-probe, an end-to-end test of the alert pipeline.
  • The build record (BUILD-INFO.txt), the dependency lockfiles, the npm audit and govulncheck results and the licences in /usr/share/doc/sac-uptime-kuma-ntfy/.
  • A fully patched Ubuntu 24.04 LTS base, with unattended security upgrades left on for your instance.
  • 24/7 SecureAnyCloud support.

Default user: ubuntu · Architecture: x86_64 · Root volume: 8 GiB gp3

Security posture

  • No setup wizard for strangers. A fresh Uptime Kuma 2.x install shows a database chooser, then lets the first visitor create the admin account. On a public address, that is a race you can lose. On this image, first boot creates the database and the admin account before the web server is allowed to start, so both first-run pages are already closed when the instance first answers on 443. A check before every start refuses to run Uptime Kuma, ntfy or nginx until first boot has finished.
  • ntfy denies anonymous access. ntfy's upstream default lets anyone publish to and read any topic. This image runs with auth-default-access: deny-all. Only the SecureAnyCloud user and its access token can publish to or read your instance's topic, and only that topic. Self-registration and topic reservations are off, and the web app requires a login.
  • Per-instance secrets. The Uptime Kuma admin password, Uptime Kuma's session-signing (JWT) secret, the ntfy password, the ntfy access token, the ntfy topic and the TLS key are all generated on your instance's first boot. No database, password, token or key ships in the image. Your credentials are in /root/uptime-kuma-ntfy-credentials.txt (mode 0600, root only). The applications store passwords only as bcrypt hashes.
  • Loopback only. Uptime Kuma and ntfy listen on 127.0.0.1. nginx on 443 and 8443 is the only way in.
  • HTTPS on first boot. nginx serves both with a TLS key and self-signed certificate created on your instance (TLS 1.2 and 1.3 only). Port 80 only redirects to HTTPS.
  • Fixed host name. Both are served under a name taken from the instance metadata at first boot (or one you set), never from the request. nginx drops requests for any other host name. nginx, and Uptime Kuma's own origin check, refuse cross-site form posts and WebSocket connections.
  • Real client addresses. nginx passes the connecting address to Uptime Kuma and ntfy and ignores any X-Forwarded-For header a client sends. Their logs and ntfy's rate limits therefore see who really connected.
  • Nothing leaves the instance unless you configure it. Uptime Kuma's update check, which polls uptime.kuma.pet and is on by default upstream, is off. ntfy has no upstream-base-url (the ntfy.sh relay used for instant iOS delivery), no firebase-key-file (Firebase Cloud Messaging), no web-push keys and no SMTP server configured, so alerts are delivered only to subscribers of this instance. The monitors you create are, of course, the outbound checks you ask for.
  • No metadata access. Uptime Kuma checks whatever URLs and hosts you enter, so uptime-kuma.service, ntfy.service and nginx.service are blocked from reaching the instance metadata service (169.254.169.254 and fd00:ec2::254). Amazon Time Sync keeps working.
  • Least privilege. Both services run with no Linux capabilities, a read-only system (ProtectSystem=strict) except their own data directory, and private /tmp. Uptime Kuma's ping monitors use unprivileged ICMP sockets that the image allows for the kuma group only.
  • No scheduled firmware-metadata refresh. The fwupd firmware updater stays installed, but its LVFS metadata refresh (fwupd-refresh.timer and .service) is masked, so an LVFS outage never marks your instance unhealthy at boot. If you use it, run sudo fwupdmgr refresh yourself.
  • IMDSv2 required. The AMI is registered with ImdsSupport v2.0, so instances launched from it refuse token-less (IMDSv1) metadata requests.
  • Per-instance identity. SSH host keys and the machine ID are generated fresh on every instance.

Known advisories and how the build handles them

  • Uptime Kuma dependencies. npm audit on the upstream 2.5.8 lockfile lists 25 advisories in the production tree. Within their own major release lines, this build updates every affected library that Uptime Kuma uses at run time: axios, nodemailer (to the 10.x line that upstream's next release already uses), ws, protobufjs, @grpc/grpc-js, liquidjs, mysql2, lodash, glob, body-parser, undici and ip-address. Two items remain:
    1. The SQLite driver's install-time build tooling (tar, node-gyp and their helpers). It runs only when the driver is compiled from source. At run time, the driver loads its prebuilt binary and never loads that code, which the build verifies.
    2. @azure/msal-node (GHSA-xcx6-jx8p-x3h5), used through @azure/identity by the SQL Server monitor's Azure sign-in options. Its fix is only in a later major release that no @azure/identity release uses yet. The advisory affects the OAuth authorization-code sign-in flow. Neither Uptime Kuma nor its SQL Server driver ever uses that flow (they use client-secret, managed-identity, username/password and default credentials only), and the build verifies that too.
    The full result ships in kuma-npm-audit-production.json. No vite (a development tool) is installed.
  • ntfy. govulncheck reports no vulnerability reachable from ntfy. It lists one advisory at module level only, GO-2026-5932: the golang.org/x/crypto/openpgp package is deprecated and has no fixed version. That package is not compiled into ntfy, and the build fails if it ever is. The full output ships in ntfy-govulncheck-binary.txt and ntfy-govulncheck-source.txt. ntfy's web app is built from its own lockfile (npm audit: 0 vulnerabilities). The ntfy binary links the system C library, so Ubuntu's security updates to it apply.
  • ntfy documentation. Upstream's binary embeds a copy of the ntfy documentation at /docs. Its build installs unpinned Python packages, so this image's /docs page links to the documentation at docs.ntfy.sh instead.

Prerequisites

Before you deploy, make sure you have:

  • An AWS account and permission to launch EC2 instances.
  • An EC2 key pair in the Region you launch in.
  • A subnet that gives the instance a public IPv4 address, or private connectivity from where you will use the dashboard.
  • Network access from the instance to the endpoints you want to monitor.

Recommended instance type: m5.large. Uptime Kuma is a single Node.js process with SQLite storage, and ntfy is a single Go process. A smaller burstable type also works for a few dozen monitors.

Connecting to your instance

For the Uptime Kuma with ntfy 2.5.8 on Ubuntu 24.04 version, the operating system is Ubuntu 24.04 LTS and the SSH user is ubuntu.

1

Launch the instance

Option A: AWS Marketplace console

  • Open the SecureAnyCloud Hardened Uptime Kuma, Gatus & Uptime and Status Pages AMIs listing on AWS Marketplace. Choose View purchase options, then Subscribe. One subscription covers every version in the listing.
  • When the subscription is active, choose Launch your software.
  • Choose One-click launch from AWS Marketplace, or Launch from EC2 Console for the full launch wizard. In Version, choose Uptime Kuma with ntfy 2.5.8 on Ubuntu 24.04, then choose your Region.
  • Pick an instance type and your key pair. m5.large is recommended, and the software charge is $0.04 per vCPU per hour.
  • Configure the security group to allow SSH (22), HTTP (80), HTTPS (443) and 8443 (ntfy, where your phone, browser or scripts subscribe). Restrict SSH to your own IP address, 80 and 443 to the people who use the dashboard, and 8443 to the devices that subscribe.
  • Choose your VPC and a subnet that gives the instance a public IP. Leave the metadata defaults, because the image already requires IMDSv2. Then choose Launch.

Option B: AWS CLI

Run this on your own workstation. It creates a security group that allows SSH, the dashboard and ntfy from your management address only, then launches the instance. Replace the AMI ID with the one shown for your Region on the Marketplace launch page. Replace the VPC, subnet, key pair and CIDR with your own values:

SG=$(aws ec2 create-security-group --group-name uptime-kuma-ntfy \
  --description "Uptime Kuma with ntfy" --vpc-id vpc-0123456789abcdef0 \
  --query GroupId --output text) for p in 22 80 443 8443; do aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port "$p" --cidr <your-mgmt-cidr> done aws ec2 run-instances \
  --image-id ami-0123456789abcdef0 \
  --instance-type m5.large \
  --key-name my-key-pair \
  --security-group-ids "$SG" \
  --subnet-id subnet-0123456789abcdef0 \
  --associate-public-ip-address \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=uptime-kuma-ntfy}]'

You do not need --metadata-options, because the AMI already requires IMDSv2.

2

Connect and read your credentials

Connect as ubuntu with the key pair you chose:

ssh -i ~/.ssh/my-key-pair.pem ubuntu@<public-ip>

First boot finishes within a minute of launch. It creates the certificate, both applications' databases and accounts, and the ntfy token and topic, then lets the services start. Read your credentials from the root-only file:

sudo cat /root/uptime-kuma-ntfy-credentials.txt
# Uptime Kuma with ntfy - generated on this instance's first boot by uptime-kuma-ntfy-firstboot.service. # Unique to this instance; nothing here shipped in the image. Store it somewhere safe. KUMA_URL=https://ec2-35-174-111-13.compute-1.amazonaws.com/ KUMA_ADMIN_USERNAME=admin KUMA_ADMIN_PASSWORD=<KUMA_ADMIN_PASSWORD> NTFY_URL=https://ec2-35-174-111-13.compute-1.amazonaws.com:8443/ NTFY_USERNAME=sac NTFY_PASSWORD=<NTFY_PASSWORD> NTFY_TOKEN=<NTFY_TOKEN> NTFY_TOPIC=<NTFY_TOPIC> NTFY_SUBSCRIBE_URL=https://ec2-35-174-111-13.compute-1.amazonaws.com:8443/<NTFY_TOPIC> # # Uptime Kuma: open KUMA_URL and sign in as admin (self-signed certificate minted on this instance; port 80 redirects). # Every monitor you create alerts through the default "ntfy (this instance)" channel to NTFY_TOPIC. # ntfy: subscribe to NTFY_SUBSCRIBE_URL in the ntfy app or a browser as NTFY_USERNAME / NTFY_PASSWORD, or with # curl -H "Authorization: Bearer <NTFY_TOKEN>" https://<host>:8443/<NTFY_TOPIC>/json # Change the name both are served as:
sudo uptime-kuma-ntfy-set-hostname <your-dns-name>
# Restrict 80/443/8443 in the security group to the people and devices that need them.
# Guide: https://secureanycloud.com/stacks/uptime-kuma-with-ntfy-2-5-8/

KUMA_ADMIN_PASSWORD, NTFY_PASSWORD, NTFY_TOKEN and NTFY_TOPIC hold your instance's own values. The topic name is long and random, so it cannot be guessed. ntfy also refuses access to the topic for anyone without your credentials.

3

Confirm the services are running

Run the following checks. They confirm that first boot, Uptime Kuma, ntfy and nginx are active. They also confirm that the two applications run as their own unprivileged users, that ntfy reports healthy, and that the start guard passes. The guard runs before every start of the three services.

systemctl is-active uptime-kuma-ntfy-firstboot.service uptime-kuma.service ntfy.service nginx.service ps -o user=,comm= -p "$(systemctl show -p MainPID --value uptime-kuma.service),$(systemctl show -p MainPID --value ntfy.service)" curl -sf http://127.0.0.1:8088/v1/health | jq -e '.healthy == true'
sudo /usr/local/sbin/uptime-kuma-ntfy-guard
active active active active ntfy ntfy kuma uptime-kuma true GUARD_OK

If a service ever refuses to start, run the guard. It names the exact reason.

List the TCP ports the instance listens on:

sudo ss -Hltn | awk '{print $4}' | sort -u
0.0.0.0:22 0.0.0.0:443 0.0.0.0:80 0.0.0.0:8443 127.0.0.1:3001 127.0.0.1:8088 127.0.0.53%lo:53 127.0.0.54:53 [::]:22 [::]:443 [::]:80 [::]:8443

Uptime Kuma (3001) and ntfy (8088) listen on loopback only, and nginx publishes them on 443 and 8443. The loopback port 53 entries are Ubuntu's local stub resolver (systemd-resolved).

Check the versions and the build record:

/opt/ntfy/bin/ntfy --version node --version grep -E '^(Uptime Kuma|ntfy|Node.js| source| binary sha256| govulncheck)' /usr/share/doc/sac-uptime-kuma-ntfy/BUILD-INFO.txt
ntfy version 2.34.0 v22.23.4 Uptime Kuma 2.5.8 with ntfy 2.34.0 - sac build (d-320, d-304, d-094) Uptime Kuma 2.5.8 (MIT, uptime-kuma-LICENSE) source https://github.com/louislam/uptime-kuma/archive/refs/tags/2.5.8.tar.gz ntfy 2.34.0 (Apache-2.0 / GPL-2.0 dual licence, ntfy-LICENSE + ntfy-LICENSE.GPLv2) source https://github.com/binwiederhier/ntfy/archive/refs/tags/v2.34.0.tar.gz binary sha256 5c690348535ad120b9db1de895dcf0815c659b16a7686991f76cb2a8754c8fad govulncheck v1.9.0 -mode=binary and source mode: 0 reachable vulnerabilities (DB updated: 2026-10-21 00:27:29 +0000 UTC) Node.js v22.23.4 (MIT, nodejs-LICENSE)
4

Sign in to Uptime Kuma

Browse to the KUMA_URL from Step 2, for example https://ec2-35-174-111-13.compute-1.amazonaws.com/. The certificate is self-signed, so your browser warns once. Accept the warning, or install your own certificate (Step 9). Because the administrator already exists, Uptime Kuma asks you to sign in rather than to create an account.

Sign in as admin with KUMA_ADMIN_PASSWORD. The dashboard lists your monitors. A new instance has one, a self-check of the local ntfy server. The dashboard screenshot is from an instance with two more monitors added, one of them pointing at a closed port so that it is down.

You can also confirm from the command line that the first-run pages are closed. The command checks that:

  • Port 80 only redirects to HTTPS.
  • Uptime Kuma reports that neither the database setup nor the account setup is needed.
  • The account table holds only your admin.
  • Uptime Kuma's update check is off, it reads client addresses from the header nginx writes, and its public URL is your instance's name.

The block stops with an error if any answer is not the expected one:

H=$(sudo sed -n 's/^set $ukn_host "\(.*\)";$/\1/p' /etc/nginx/sac-ukn-host.conf)
R=$(curl -s -o /dev/null -w '%{http_code} %{redirect_url}' --resolve "$H:80:127.0.0.1" "http://$H/"); echo "$R"
S=$(curl -s --cacert /etc/ssl/sac/uptime-kuma-ntfy.crt --resolve "$H:443:127.0.0.1" "https://$H/setup-database-info"); echo "$S"
U=$(sudo sqlite3 "file:/var/lib/uptime-kuma/kuma.db?mode=ro" "SELECT username FROM user;"); echo "$U"
sudo sqlite3 "file:/var/lib/uptime-kuma/kuma.db?mode=ro" "SELECT key, value FROM setting WHERE key IN ('checkUpdate','trustProxy','primaryBaseURL') ORDER BY key;" [ "$R" = "301 https://$H/" ] && [ "$S" = '{"runningSetup":false,"needSetup":false}' ] && [ "$U" = admin ]
301 https://ec2-35-174-111-13.compute-1.amazonaws.com/ {"runningSetup":false,"needSetup":false} admin checkUpdate|false primaryBaseURL|"https://ec2-35-174-111-13.compute-1.amazonaws.com" trustProxy|true
5

The alert channel is already wired up

In Uptime Kuma, open the profile menu, then choose Settings, then Notifications. The channel ntfy (this instance) is already there.

It publishes to the ntfy server on this instance with your access token. It is marked as the default, so it is pre-selected on every new monitor. Confirm this from the command line:

CH=$(sudo sqlite3 "file:/var/lib/uptime-kuma/kuma.db?mode=ro" \
  "SELECT name, is_default, json_extract(config,'$.ntfyserverurl'), json_extract(config,'$.ntfyAuthenticationMethod') FROM notification;")
echo "$CH" [ "$CH" = 'ntfy (this instance)|1|http://127.0.0.1:8088|accessToken' ]
ntfy (this instance)|1|http://127.0.0.1:8088|accessToken
6

Create a monitor

Choose Add New Monitor and pick a monitor type, such as HTTP(s), keyword, TCP port, ping or DNS. Give the monitor a name and a target, then save it. Leave ntfy (this instance) ticked under Notifications.

When a monitor cannot reach its target, it goes red and fires an alert. Its page shows the check history.

Uptime Kuma checks your endpoints from this instance, so the instance needs a network path to them. Monitoring requires no inbound rules in the security group.

7

Subscribe to your alerts

Alerts land on your instance's ntfy topic on port 8443, and anything that speaks HTTP can subscribe.

From a browser: open NTFY_URL, sign in with NTFY_USERNAME and NTFY_PASSWORD, then subscribe to NTFY_TOPIC.

From the ntfy app for Android or iOS: add a subscription with Use another server, enter NTFY_URL and your topic, and sign in with the same user. Your phone must trust the instance's certificate, so install your own certificate first (Step 9). Without an upstream relay, the iOS app delivers notifications when it polls rather than instantly (see Step 10).

From a script: use the access token. The block below publishes a test message with the token and reads it back from the topic. It then shows that a request without credentials is refused. The token is passed to curl as a header file, never on the command line:

H=$(sudo sed -n 's/^set $ukn_host "\(.*\)";$/\1/p' /etc/nginx/sac-ukn-host.conf)
T=$(sudo sed -n 's/^NTFY_TOPIC=//p' /root/uptime-kuma-ntfy-credentials.txt) C=(--cacert /etc/ssl/sac/uptime-kuma-ntfy.crt --resolve "$H:8443:127.0.0.1") M="test from $(hostname) at $(date -u +%H:%M:%S)"
P=$(curl -s "${C[@]}" -H @<(sudo sed -n 's/^NTFY_TOKEN=/Authorization: Bearer /p' /root/uptime-kuma-ntfy-credentials.txt) -d "$M" "https://$H:8443/$T" | jq -r .event)
G=$(curl -s "${C[@]}" -H @<(sudo sed -n 's/^NTFY_TOKEN=/Authorization: Bearer /p' /root/uptime-kuma-ntfy-credentials.txt) "https://$H:8443/$T/json?poll=1" | jq -r 'select(.event == "message") | .message' | grep -cxF "$M")
A=$(curl -s "${C[@]}" -o /dev/null -w '%{http_code}' "https://$H:8443/$T/json?poll=1")
N=$(curl -s "${C[@]}" -o /dev/null -w '%{http_code}' -d 'anonymous publish' "https://$H:8443/$T")
echo "publish with token : $P";
echo "read back with token : $G message";
echo "anonymous subscribe : $A";
echo "anonymous publish : $N" [ "$P" = message ] && [ "$G" = 1 ] && [ "$A" = 403 ] && [ "$N" = 403 ]
publish with token : message read back with token : 1 message anonymous subscribe : 403 anonymous publish : 403

To stream alerts as they arrive, drop ?poll=1 and keep the connection open (https://<host>:8443/<topic>/json), or use /<topic>/sse or /<topic>/ws. From another machine, use your instance's address and the same Authorization: Bearer header.

8

Prove the whole pipeline end to end

The image ships a self-test of the real alert path. It does the following:

  • Signs in to Uptime Kuma through nginx with your administrator credentials.
  • Creates a temporary monitor that points at a closed port, so the monitor must go down.
  • Waits for the alert, then reads it back from your ntfy topic through nginx on 8443 with your access token, as a subscriber would.
  • Deletes the temporary monitor.

Run it:

OUT=$(sudo /usr/local/sbin/sac-uptime-kuma-e2e-probe 2>&1) || { echo "$OUT"; exit 1; } echo "$OUT" | grep -E '^(probe: (signed in|default ntfy channel|ALERT| title| message)|E2E_PIPELINE_OK)' grep -qx 'E2E_PIPELINE_OK' <<<"$OUT"
probe: signed in to Uptime Kuma as admin (JWT issued) probe: default ntfy channel present (id 1) -> topic <NTFY_TOPIC> probe: ALERT DELIVERED to an authenticated subscriber of https://ec2-35-174-111-13.compute-1.amazonaws.com:8443/<NTFY_TOPIC> probe: title = sac e2e probe 1792610335769 Down [Uptime-Kuma] probe: message = connect ECONNREFUSED 127.0.0.1:1 E2E_PIPELINE_OK

Run the self-test after any change to the instance. If it fails, alerts are not reaching your subscribers.

9

HTTPS certificate and host name

First boot creates the certificate for the instance's public DNS name, public IP, private IP and localhost. The key, the credentials file and both data directories are readable only by their owners. Verify the certificate and the permissions:

sudo openssl x509 -in /etc/ssl/sac/uptime-kuma-ntfy.crt -noout -subject -ext subjectAltName
sudo stat -c '%a %U:%G %n' /etc/ssl/sac/uptime-kuma-ntfy.key /root/uptime-kuma-ntfy-credentials.txt /var/lib/uptime-kuma /var/lib/ntfy /etc/ntfy/server.yml
subject=CN = ec2-35-174-111-13.compute-1.amazonaws.com, O = sac X509v3 Subject Alternative Name: DNS:ec2-35-174-111-13.compute-1.amazonaws.com, IP Address:35.174.111.13, IP Address:172.31.91.150, IP Address:127.0.0.1, DNS:localhost 600 root:root /etc/ssl/sac/uptime-kuma-ntfy.key 600 root:root /root/uptime-kuma-ntfy-credentials.txt 750 kuma:kuma /var/lib/uptime-kuma 750 ntfy:ntfy /var/lib/ntfy 640 root:ntfy /etc/ntfy/server.yml

To serve both under your own DNS name, for example status.example.com pointed at this instance, run the helper. It does the following:

  • Records the name and creates a new self-signed certificate for it.
  • Updates nginx, ntfy's base URL and Uptime Kuma's Primary Base URL, which is used in alert links.
  • Restarts what is running and rewrites the URLs in the credentials file.
sudo uptime-kuma-ntfy-set-hostname status.example.com

If the instance's public address changes after a stop and start, run the helper again.

To use a certificate from your own certificate authority, replace /etc/ssl/sac/uptime-kuma-ntfy.key (keep it 0600 root) and /etc/ssl/sac/uptime-kuma-ntfy.crt, then run sudo systemctl reload nginx. This is recommended before you subscribe phones.

10

Outbound connections and metadata

ntfy listens on loopback, denies anonymous access, allows no self-registration, and has no relay, push service or mail server configured. The three services cannot reach the instance metadata service, while the Amazon Time Sync Service at 169.254.169.123 keeps working. The firmware-metadata refresh is masked. The commands below check all of this. The count of upstream-base-url, firebase-key-file, web-push-public-key and smtp-sender-addr entries is none:

sudo grep -E '^(listen-http|auth-default-access|enable-signup|enable-reservations|require-login|behind-proxy)' /etc/ntfy/server.yml
OUTBOUND=$(sudo grep -cE '^(upstream-base-url|firebase-key-file|web-push-public-key|smtp-sender-addr):' /etc/ntfy/server.yml || true); echo "$OUTBOUND" systemctl show -p IPAddressDeny uptime-kuma.service ntfy.service nginx.service chronyc -n sources | grep 169.254
FW=$(systemctl is-enabled fwupd-refresh.timer fwupd-refresh.service || true); echo "$FW" [ "$OUTBOUND" = 0 ] && [ "$(sort -u <<<"$FW")" = masked ] && [ "$(systemctl show -p IPAddressDeny --value uptime-kuma.service ntfy.service nginx.service | grep -c 169.254.169.254)" = 3 ]
listen-http: "127.0.0.1:8088" auth-default-access: "deny-all" enable-signup: false require-login: true enable-reservations: false behind-proxy: true 0 IPAddressDeny=168.63.129.16/32 fd00:ec2::254/128 169.254.169.254/32 IPAddressDeny=168.63.129.16/32 fd00:ec2::254/128 169.254.169.254/32 IPAddressDeny=168.63.129.16/32 fd00:ec2::254/128 169.254.169.254/32 ^* 169.254.169.123 3 4 377 7 +373ns[ +410ns] +/- 482us masked masked

Features that need an outside service are off by default. To use them, configure them yourself in /etc/ntfy/server.yml and restart ntfy (sudo systemctl restart ntfy):

  • Instant delivery to the iOS app needs upstream-base-url: "https://ntfy.sh". It forwards a poll request, not the message, to ntfy.sh for each notification.
  • Email notifications need an smtp-sender-* mail server.
  • Firebase (firebase-key-file) and web push (web-push-* keys) need their own credentials.

You can add Uptime Kuma's own notification providers (email, Slack, Teams, Telegram and around 90 others) in Settings → Notifications, next to the ntfy channel. To turn Uptime Kuma's update check back on, use Settings → About.

Maintenance

  • Uptime Kuma password: change it in Settings → Security, then update /root/uptime-kuma-ntfy-credentials.txt or delete it. If you lose the password, reset it from a shell on the instance with Uptime Kuma's own tool, which asks for the new password interactively:
sudo systemctl stop uptime-kuma cd /opt/uptime-kuma && sudo -u kuma env DATA_DIR=/var/lib/uptime-kuma/ /opt/node/bin/node extra/reset-password.js
sudo systemctl start uptime-kuma
  • ntfy password and users: the ntfy command reads passwords from standard input, so they never appear on a command line. To change the SecureAnyCloud password, or to give a colleague read-only access to the topic, run:
sudo ntfy user change-pass sac
sudo ntfy user add --role=user colleague
sudo ntfy access colleague <your-topic> read-only
sudo ntfy token add --label=my-script sac
  • Backups: Uptime Kuma's database is in /var/lib/uptime-kuma, and ntfy's users, tokens and message cache are in /var/lib/ntfy. Back up both directories with the services stopped. Keep the backup as safe as the credentials, because the databases hold your monitors' secrets and the ntfy tokens.
  • Message retention: ntfy keeps messages for 12 hours (cache-duration in /etc/ntfy/server.yml).
  • Upgrades: to move to a newer release, launch the newer version from the listing when it is published, then restore your backups.
  • Logs: run sudo journalctl -u uptime-kuma -u ntfy -n 100 --no-pager.
  • Security patches: unattended-upgrades remains enabled, so the OS, including the C library ntfy uses, keeps receiving security updates.

Security recommendations

  • Keep the security group tight. Open 22 only to your management address, 80 and 443 only to the people who use the dashboard, and 8443 only to the devices and scripts that subscribe.
  • Use your own certificate before you subscribe phones or other people sign in, so that they trust it without exceptions.
  • Keep both applications on loopback. Reach them through nginx, which keeps forwarded headers honest and refuses cross-site requests.
  • Give each subscriber its own access. Create a separate ntfy user or token with only the access it needs, rather than sharing the SecureAnyCloud password.

Support and licensing

SecureAnyCloud provides the packaging, the hardening, first-boot HTTPS and per-instance credentials, and 24/7 support. For help with deployment or configuration, email sales@secureanycloud.com or visit SecureAnyCloud support.

Licensing

  • Uptime Kuma is developed by Louis Lam and contributors and distributed under the MIT License.
  • ntfy is developed by Philipp C. Heckel and contributors and dual-licensed under the Apache License 2.0 and the GPLv2. This image distributes it under the Apache License 2.0, and both texts ship with it.
  • ntfy's web app includes notification sounds under the Mixkit Free License and Creative Commons Attribution terms, as in every upstream build.
  • Node.js is distributed under the MIT License.
  • This image ships Uptime Kuma 2.5.8 with updated dependencies, and an ntfy binary that SecureAnyCloud compiled from the unmodified 2.34.0 source with Go 1.27.3. The build record and licences are in /usr/share/doc/sac-uptime-kuma-ntfy/.

SecureAnyCloud is not affiliated with or endorsed by the Uptime Kuma or ntfy projects or their authors. Product names are marks of their owners and are used here only to identify the software.

Deploy on AWS

Launch Uptime Kuma with ntfy 2.5.8 on Ubuntu 24.04 on AWS with 24/7 support from SecureAnyCloud.

View on Marketplace

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on AWS