#!/bin/bash ############################################################# #### ntfy Desktop Client Setup for Linux #### #### Subscribe to ntfy push notifications with desktop #### #### alerts via systemd user service #### #### #### #### Author: Phil Connor #### #### Contact: contact@mylinux.work #### #### License: MIT #### #### Version: 1.0 #### #### #### #### Usage: ./ntfy-client-setup-linux.sh #### ############################################################# set -euo pipefail NTFY_VERSION="2.11.0" # ── Detect the actual desktop user ───────────────────────── # Handles both sudo and non-sudo execution if [ -n "${SUDO_USER:-}" ]; then DESKTOP_USER="$SUDO_USER" DESKTOP_HOME=$(getent passwd "$SUDO_USER" | cut -d: -f6) else DESKTOP_USER="$USER" DESKTOP_HOME="$HOME" fi CONFIG_DIR="$DESKTOP_HOME/.config/ntfy" SYSTEMD_DIR="$DESKTOP_HOME/.config/systemd/user" # ── Helper functions ─────────────────────────────────────── info() { echo -e " ✓ $*"; } warn() { echo -e " ⚠ $*"; } error() { echo -e " ✗ $*" >&2; } run_as_user() { # Run a command as the desktop user (handles sudo case) if [ "$(id -u)" -eq 0 ] && [ "$DESKTOP_USER" != "root" ]; then sudo -u "$DESKTOP_USER" "$@" else "$@" fi } install_package() { local pkg_apt="$1" local pkg_dnf="${2:-$1}" local pkg_pacman="${3:-$1}" if command -v apt &> /dev/null; then sudo apt install -y "$pkg_apt" elif command -v dnf &> /dev/null; then sudo dnf install -y "$pkg_dnf" elif command -v pacman &> /dev/null; then sudo pacman -S --noconfirm "$pkg_pacman" else error "Could not detect package manager. Please install '$pkg_apt' manually." return 1 fi } # ── Banner ───────────────────────────────────────────────── echo "" echo "===========================================" echo " ntfy Desktop Client Setup for Linux" echo "===========================================" echo "" echo " User: $DESKTOP_USER" echo " Home: $DESKTOP_HOME" echo "" # ── Step 1: Install dependencies ─────────────────────────── echo "── Checking dependencies ──────────────────" echo "" if ! command -v notify-send &> /dev/null; then echo " Installing libnotify for desktop notifications..." install_package libnotify-bin libnotify libnotify info "libnotify installed" else info "notify-send already available" fi if ! command -v curl &> /dev/null; then echo " Installing curl..." install_package curl curl curl info "curl installed" else info "curl already available" fi echo "" # ── Step 2: Install ntfy binary ──────────────────────────── echo "── Installing ntfy client ─────────────────" echo "" # Determine install location based on privileges if [ "$(id -u)" -eq 0 ] || sudo -n true 2>/dev/null; then NTFY_BIN="/usr/local/bin/ntfy" INSTALL_SYSTEM=true else NTFY_BIN="$DESKTOP_HOME/.local/bin/ntfy" INSTALL_SYSTEM=false fi if [ -x "$NTFY_BIN" ]; then info "ntfy already installed at $NTFY_BIN" else # Detect architecture ARCH=$(uname -m) case "$ARCH" in x86_64) NTFY_ARCH="amd64" ;; aarch64) NTFY_ARCH="arm64" ;; armv7l) NTFY_ARCH="armv7" ;; *) error "Unsupported architecture: $ARCH" exit 1 ;; esac DOWNLOAD_URL="https://github.com/binwiederhier/ntfy/releases/download/v${NTFY_VERSION}/ntfy_${NTFY_VERSION}_linux_${NTFY_ARCH}.tar.gz" echo " Downloading ntfy v${NTFY_VERSION} (${NTFY_ARCH})..." TEMP_DIR=$(mktemp -d) trap 'rm -rf "$TEMP_DIR"' EXIT curl -sL -o "$TEMP_DIR/ntfy.tar.gz" "$DOWNLOAD_URL" tar -xzf "$TEMP_DIR/ntfy.tar.gz" -C "$TEMP_DIR" if [ "$INSTALL_SYSTEM" = true ]; then sudo find "$TEMP_DIR" -name "ntfy" -type f -exec mv {} "$NTFY_BIN" \; sudo chmod +x "$NTFY_BIN" else mkdir -p "$(dirname "$NTFY_BIN")" find "$TEMP_DIR" -name "ntfy" -type f -exec mv {} "$NTFY_BIN" \; chmod +x "$NTFY_BIN" fi rm -rf "$TEMP_DIR" trap - EXIT info "ntfy installed to $NTFY_BIN" fi echo "" # ── Step 3: Interactive configuration ────────────────────── echo "── Configuration ──────────────────────────" echo "" read -rp " Server URL [https://ntfy.example.com]: " INPUT_SERVER SERVER_URL="${INPUT_SERVER:-https://ntfy.example.com}" echo "" read -rp " Access token (leave empty for public topics): " ACCESS_TOKEN echo "" echo " Enter topics to subscribe to (space-separated)." echo " Examples: alerts monitoring backup-status" read -rp " Topics: " TOPICS if [ -z "$TOPICS" ]; then error "At least one topic is required." exit 1 fi echo "" echo " Server: $SERVER_URL" echo " Topics: $TOPICS" echo " Token: ${ACCESS_TOKEN:+(set)}${ACCESS_TOKEN:-(none)}" echo "" # ── Step 4: Create client config ─────────────────────────── echo "── Creating configuration files ────────────" echo "" run_as_user mkdir -p "$CONFIG_DIR" run_as_user mkdir -p "$SYSTEMD_DIR" # Build the subscribe section for client.yml SUBSCRIBE_BLOCK="" for topic in $TOPICS; do SUBSCRIBE_BLOCK+=" - topic: ${SERVER_URL}/${topic}"$'\n' if [ -n "$ACCESS_TOKEN" ]; then SUBSCRIBE_BLOCK+=" token: ${ACCESS_TOKEN}"$'\n' fi done # Write client.yml cat > "$CONFIG_DIR/client.yml" << EOF # ntfy client configuration # Documentation: https://docs.ntfy.sh/subscribe/cli/ subscribe: ${SUBSCRIBE_BLOCK}EOF # Fix ownership if running as root if [ "$(id -u)" -eq 0 ] && [ "$DESKTOP_USER" != "root" ]; then chown -R "$DESKTOP_USER:$DESKTOP_USER" "$CONFIG_DIR" fi info "Config saved to $CONFIG_DIR/client.yml" # ── Step 5: Create systemd user service ──────────────────── cat > "$SYSTEMD_DIR/ntfy-subscribe.service" << EOF [Unit] Description=ntfy desktop notification subscriber After=network-online.target Wants=network-online.target [Service] Type=simple ExecStart=${NTFY_BIN} subscribe --from-config Restart=on-failure RestartSec=10 [Install] WantedBy=default.target EOF # Fix ownership if running as root if [ "$(id -u)" -eq 0 ] && [ "$DESKTOP_USER" != "root" ]; then chown -R "$DESKTOP_USER:$DESKTOP_USER" "$SYSTEMD_DIR" fi info "Systemd user service created" echo "" # ── Done ─────────────────────────────────────────────────── echo "===========================================" echo " Setup Complete" echo "===========================================" echo "" echo " To start receiving notifications, run as $DESKTOP_USER" echo " from a graphical desktop session:" echo "" echo " systemctl --user daemon-reload" echo " systemctl --user enable --now ntfy-subscribe" echo "" echo " Useful commands:" echo "" echo " Status: systemctl --user status ntfy-subscribe" echo " Logs: journalctl --user -u ntfy-subscribe -f" echo " Restart: systemctl --user restart ntfy-subscribe" echo " Stop: systemctl --user stop ntfy-subscribe" echo " Disable: systemctl --user disable --now ntfy-subscribe" echo "" echo " Test with:" echo "" echo " curl -d 'Hello from ntfy!' ${SERVER_URL}/${TOPICS%% *}" echo ""