Monitoring primarily
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
{ config, lib, pkgs, homeyConfig, ... }:
|
||||
|
||||
# Ntfy — self-hosted push notification server.
|
||||
#
|
||||
# Mobile app (Android/iOS) connects to https://ntfy.zakobar.com with a token
|
||||
# and subscribes to the "alerts" topic. Uptime Kuma and Grafana send alerts
|
||||
# to that topic when services go down.
|
||||
#
|
||||
# Auth model:
|
||||
# - Web UI: public-facing but ntfy enforces its own auth (deny-all by default)
|
||||
# - Caddy does NOT put forward_auth here; ntfy has native token/password auth
|
||||
# so the mobile app can connect without Authelia SSO complications.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# Volume layout:
|
||||
# <dataDir>/ntfy/auth.db ← user/token database
|
||||
# <dataDir>/ntfy/cache.db ← message cache (for missed messages)
|
||||
# <dataDir>/ntfy/attachments/ ← file attachments
|
||||
#
|
||||
# Secrets consumed from sops:
|
||||
# ntfy/admin_password
|
||||
|
||||
let
|
||||
cfg = config.homey.ntfy;
|
||||
dataDir = config.homey.storage.mountPoint;
|
||||
domain = homeyConfig.domain;
|
||||
in
|
||||
{
|
||||
options.homey.ntfy = {
|
||||
enable = lib.mkEnableOption "Ntfy push notification server";
|
||||
|
||||
port = lib.mkOption {
|
||||
type = lib.types.port;
|
||||
default = 2586;
|
||||
description = "Host port ntfy listens on (bound to 127.0.0.1).";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
# -----------------------------------------------------------------------
|
||||
# Secrets
|
||||
# -----------------------------------------------------------------------
|
||||
sops.secrets."ntfy/admin_password" = { 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";
|
||||
};
|
||||
};
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Create the admin user on first start (idempotent)
|
||||
# -----------------------------------------------------------------------
|
||||
systemd.services.ntfy-sh-setup = {
|
||||
description = "Create Ntfy admin user";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "ntfy-sh.service" "mnt-data.mount" ];
|
||||
requires = [ "ntfy-sh.service" ];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
LoadCredential = "ntfy_admin_password:${config.sops.secrets."ntfy/admin_password".path}";
|
||||
|
||||
ExecStart = pkgs.writeShellScript "ntfy-create-admin" ''
|
||||
set -euo pipefail
|
||||
|
||||
# Wait until ntfy HTTP endpoint is ready (max 60 s)
|
||||
for i in $(seq 1 30); do
|
||||
if ${pkgs.curl}/bin/curl -sf http://127.0.0.1:${toString cfg.port}/v1/health > /dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
|
||||
PASS=$(cat "$CREDENTIALS_DIRECTORY/ntfy_admin_password")
|
||||
|
||||
# ntfy user commands need the config file to find the auth database.
|
||||
# The NixOS ntfy-sh module writes config to /etc/ntfy-sh/server.yml.
|
||||
NTFY="${pkgs.ntfy-sh}/bin/ntfy user --config /etc/ntfy-sh/server.yml"
|
||||
|
||||
# ntfy user list exits non-zero if the user DB is empty/doesn't exist;
|
||||
# grep exits non-zero if the pattern is missing. Either means no admin.
|
||||
if $NTFY list 2>/dev/null | grep -qE "^admin\b"; then
|
||||
echo "ntfy-sh-setup: admin user already exists"
|
||||
else
|
||||
echo "$PASS" | $NTFY add --role=admin admin
|
||||
echo "ntfy-sh-setup: admin user created"
|
||||
fi
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
# Ensure ntfy-sh starts after the external HD is mounted
|
||||
systemd.services.ntfy-sh = {
|
||||
after = lib.mkAfter [ "mnt-data.mount" ];
|
||||
requires = lib.mkAfter [ "mnt-data.mount" ];
|
||||
};
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Uptime Kuma monitor for this service
|
||||
# -----------------------------------------------------------------------
|
||||
homey.monitoring.monitors = [{
|
||||
name = "Ntfy";
|
||||
url = "https://ntfy.${domain}/v1/health";
|
||||
interval = 60;
|
||||
}];
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user