Notifications sort of fixed

This commit is contained in:
Aner Zakobar
2026-05-10 23:56:01 +03:00
parent 09052e8aec
commit d2793904f4
4 changed files with 119 additions and 45 deletions
+74 -33
View File
@@ -11,11 +11,17 @@
# - Caddy does NOT put forward_auth here; ntfy has native token/password auth
# so the mobile app can connect without Authelia SSO complications.
#
# Web Push (PWA via Safari "Add to Home Screen"):
# Generate VAPID keys on the Pi:
# sudo ntfy webpush keys
# Set homey.ntfy.webPushPublicKey and homey.ntfy.webPushEmail in default.nix.
# Add the private key to sops: ntfy/web_push_private_key
#
# Setup after first deploy:
# 1. Visit https://ntfy.zakobar.com — log in with the admin password from sops.
# 2. Create an access token for your phone (Admin → Users & Tokens).
# 3. In the Ntfy app: server = https://ntfy.zakobar.com, token = <your-token>.
# 4. Subscribe to the "alerts" topic.
# 3. PWA: open https://ntfy.zakobar.com in Safari → Share → Add to Home Screen,
# then open from Home Screen and subscribe to "alerts".
#
# Volume layout:
# <dataDir>/ntfy/auth.db ← user/token database
@@ -24,11 +30,35 @@
#
# Secrets consumed from sops:
# ntfy/admin_password
# ntfy/web_push_private_key
let
cfg = config.homey.ntfy;
dataDir = config.homey.storage.mountPoint;
domain = homeyConfig.domain;
# All ntfy settings in one place. The private key is NOT here — it is
# injected at runtime via ExecStartPre so it never lands in the nix store.
ntfySettings = {
listen-http = "127.0.0.1:${toString cfg.port}";
base-url = "https://ntfy.${domain}";
auth-default-access = "deny-all";
auth-file = "${dataDir}/ntfy/auth.db";
cache-file = "${dataDir}/ntfy/cache.db";
attachment-root = "${dataDir}/ntfy/attachments";
upstream-base-url = "https://ntfy.sh";
cache-duration = "12h";
attachment-total-size-limit = "5G";
attachment-file-size-limit = "15M";
attachment-expiry-duration = "3h";
web-push-public-key = cfg.webPushPublicKey;
web-push-email-address = cfg.webPushEmail;
web-push-file = "${dataDir}/ntfy/webpush.db";
};
# Build-time base config (no private key). ExecStartPre copies this to
# /run/ntfy-sh/server.yml and appends web-push-private-key from the credential.
baseConfigFile = (pkgs.formats.yaml {}).generate "ntfy-server-base.yml" ntfySettings;
in
{
options.homey.ntfy = {
@@ -39,40 +69,31 @@ in
default = 2586;
description = "Host port ntfy listens on (bound to 127.0.0.1).";
};
webPushPublicKey = lib.mkOption {
type = lib.types.str;
description = "VAPID public key for Web Push (generate with: sudo ntfy webpush keys).";
};
webPushEmail = lib.mkOption {
type = lib.types.str;
description = "Contact e-mail sent in VAPID headers (e.g. mailto:you@example.com).";
};
};
config = lib.mkIf cfg.enable {
# -----------------------------------------------------------------------
# Secrets
# -----------------------------------------------------------------------
sops.secrets."ntfy/admin_password" = { owner = "root"; };
sops.secrets."ntfy/admin_password" = { owner = "root"; };
sops.secrets."ntfy/web_push_private_key" = { owner = "root"; };
# -----------------------------------------------------------------------
# ntfy-sh native NixOS service
# -----------------------------------------------------------------------
services.ntfy-sh = {
enable = true;
settings = {
# Bind to localhost; Caddy reverse-proxies it
listen-http = "127.0.0.1:${toString cfg.port}";
base-url = "https://ntfy.${domain}";
# Require auth on all topics — deny unauthenticated access entirely
auth-default-access = "deny-all";
# Persistent state on external HD
auth-file = "${dataDir}/ntfy/auth.db";
cache-file = "${dataDir}/ntfy/cache.db";
attachment-root = "${dataDir}/ntfy/attachments";
# Keep messages for 12 hours so the app catches up if offline
cache-duration = "12h";
# Attachment limits
attachment-total-size-limit = "5G";
attachment-file-size-limit = "15M";
attachment-expiry-duration = "3h";
};
enable = true;
settings = ntfySettings;
};
# Minimal config for the `ntfy user` CLI — the NixOS module puts its
@@ -107,12 +128,30 @@ in
};
# Ensure ntfy-sh starts after the HD is mounted and dirs are ready.
# Also widen ReadWritePaths so ntfy-sh can write to the external HD path
# (the NixOS module restricts writes to /var/lib/ntfy-sh by default).
# Widen ReadWritePaths so ntfy-sh can write to the external HD.
# Inject the VAPID private key at runtime: ExecStartPre copies the
# build-time base config to /run/ntfy-sh/server.yml and appends the key,
# then we override ExecStart to use that runtime config file.
systemd.services.ntfy-sh = {
after = lib.mkAfter [ "mnt-data.mount" "ntfy-sh-mkdir.service" ];
requires = lib.mkAfter [ "mnt-data.mount" "ntfy-sh-mkdir.service" ];
serviceConfig.ReadWritePaths = lib.mkAfter [ "${dataDir}/ntfy" ];
serviceConfig = {
ReadWritePaths = lib.mkAfter [ "${dataDir}/ntfy" ];
RuntimeDirectory = "ntfy-sh"; # creates /run/ntfy-sh, owned by ntfy-sh user
# Run as root (+) so the module's sandbox hardening can't block the write.
# Read the sops secret directly — no LoadCredential needed.
ExecStartPre = "+" + toString (pkgs.writeShellScript "ntfy-write-config" ''
set -euo pipefail
mkdir -p /run/ntfy-sh
cp ${baseConfigFile} /run/ntfy-sh/server.yml
printf 'web-push-private-key: %s\n' \
"$(cat ${config.sops.secrets."ntfy/web_push_private_key".path})" \
>> /run/ntfy-sh/server.yml
chown ntfy-sh:ntfy-sh /run/ntfy-sh/server.yml
chmod 600 /run/ntfy-sh/server.yml
'');
ExecStart = lib.mkForce "${pkgs.ntfy-sh}/bin/ntfy serve -c /run/ntfy-sh/server.yml";
};
};
# -----------------------------------------------------------------------
@@ -145,13 +184,15 @@ in
# Use the minimal CLI config (just has auth-file path).
NTFY="${pkgs.ntfy-sh}/bin/ntfy user --config /etc/ntfy-sh/user-cli.yml"
# ntfy user list outputs a Unicode table; grep for admin in it.
# ntfy user add reads password + confirmation from stdin (two lines).
if $NTFY list 2>/dev/null | grep -qE "admin"; then
echo "ntfy-sh-setup: admin user already exists"
else
printf '%s\n%s\n' "$PASS" "$PASS" | $NTFY add --role=admin admin
# If the user already exists ntfy exits 1 with "already exists" treat that as success.
if out=$(printf '%s\n%s\n' "$PASS" "$PASS" | $NTFY add --role=admin admin 2>&1); then
echo "ntfy-sh-setup: admin user created"
elif echo "$out" | grep -q "already exists"; then
echo "ntfy-sh-setup: admin user already exists (ok)"
else
echo "$out" >&2
exit 1
fi
'';
};