<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Benachrichtigungen – Serverküche</title><link>https://serverkueche.de/tags/benachrichtigungen/</link><description>Benachrichtigungen – Neueste Beiträge von Serverküche</description><generator>Hugo</generator><language>de-DE</language><managingEditor>feedback@serverkueche.de (Serverküche)</managingEditor><webMaster>feedback@serverkueche.de (Serverküche)</webMaster><copyright>2026 Serverküche</copyright><lastBuildDate>Fri, 07 Aug 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://serverkueche.de/tags/benachrichtigungen/index.xml" rel="self" type="application/rss+xml"/><item><title>ntfy: Push-Benachrichtigungen vom eigenen Server aufs Handy</title><link>https://serverkueche.de/tutorials/ntfy-push-benachrichtigungen/</link><pubDate>Fri, 07 Aug 2026 00:00:00 +0000</pubDate><author>feedback@serverkueche.de (Serverküche)</author><guid>https://serverkueche.de/tutorials/ntfy-push-benachrichtigungen/</guid><description>ntfy mit Docker &amp; Traefik selbst hosten: Push-Nachrichten aufs Handy per einfachem curl – ideal für Backup-Meldungen, Monitoring-Alerts und Skripte.</description><content:encoded><![CDATA[<p>„Backup fehlgeschlagen&quot;, „Festplatte fast voll&quot;, „neuer SSH-Login&quot; – solche Meldungen willst du sofort aufs Handy bekommen, ohne sie an einen fremden Push-Dienst zu geben. Mit ntfy baust du dir in wenigen Minuten deinen eigenen Push-Server: Eine Nachricht ist nur ein <code>curl</code>-Aufruf entfernt.</p>
<h2 id="was-bauen-wir">Was bauen wir?</h2>
<p>Am Ende läuft <strong>ntfy 2.26</strong> in Docker hinter deinem Traefik-Reverse-Proxy, erreichbar unter deiner eigenen (Sub-)Domain mit HTTPS. Du kannst dann aus jedem Skript, Cronjob oder Monitoring-Tool eine Push-Nachricht verschicken – mit einem simplen HTTP-Request – und bekommst sie sofort in der ntfy-App auf dem Handy oder im Browser angezeigt, inklusive Titel, Priorität, Emojis und optionalen Aktionen.</p>
<p>Der Clou: ntfy ist extrem leichtgewichtig (läuft locker auf dem kleinsten VPS) und die Daten bleiben bei dir. Wir richten den Server gleich <strong>privat</strong> ein – nur mit Zugangsdaten darf jemand Nachrichten senden oder lesen.</p>
<p>Warum ntfy und nicht ein fertiger Dienst wie Pushover oder ein Telegram-Bot? Weil du hier keinen Account bei Dritten brauchst, keine Nachrichteninhalte an fremde Server gibst und die Schnittstelle denkbar simpel ist: Alles, was einen HTTP-Request absetzen kann – ein Shell-Skript, ein Cronjob, ein Monitoring-Tool – kann dich benachrichtigen, ganz ohne SDK oder API-Bibliothek. Genau diese Reduktion auf „POST an eine URL&quot; macht ntfy so anschlussfähig an ein selbstgehostetes Setup.</p>
<h2 id="voraussetzungen">Voraussetzungen</h2>
<ul>
<li>Ein <a href="/tutorials/ssh-absichern/">abgesicherter Server</a> mit Debian 13 und Docker</li>
<li>Ein <a href="/tutorials/reverse-proxy-traefik/">laufender Traefik-Reverse-Proxy</a> mit dem externen Netzwerk <code>proxy</code> und dem Resolver <code>le</code></li>
<li>Eine (Sub-)Domain, deren A-/AAAA-Record <a href="/tutorials/domain-mit-server-verbinden/">auf deinen Server zeigt</a>, z. B. <code>ntfy.DEINE-DOMAIN.de</code></li>
<li>Optional, aber empfohlen: die <strong>ntfy-App</strong> (Android/F-Droid/iOS), um Push wirklich aufs Handy zu bekommen</li>
</ul>
<p>ntfy ist so sparsam, dass es problemlos neben vielen anderen Diensten auf einem VPS 1000 läuft – der <a href="/serverempfehlung/">Server-Rechner</a> zeigt dir, wie wenig es braucht.</p>
<div class="not-prose my-6 overflow-hidden rounded-xl border border-paprika-200 bg-paprika-50 dark:border-paprika-800 dark:bg-paprika-900/20"
     data-track-content data-content-name="Affiliate-Box · /tutorials/ntfy-push-benachrichtigungen/" data-content-piece="VPS 1000 G12">
  <div class="flex items-center justify-between border-b border-paprika-200 bg-paprika-100 px-4 py-1.5 text-xs font-semibold uppercase tracking-wide text-paprika-700 dark:border-paprika-800 dark:bg-paprika-900/40 dark:text-paprika-300">
    <span>🍳 Empfehlung</span>
    <span title="Mit * markierte Links sind Affiliate-Links.">Anzeige</span>
  </div>
  <div class="flex flex-col gap-4 p-4 sm:flex-row sm:items-center sm:justify-between">
    <div>
      <p class="text-lg font-bold text-slate-900 dark:text-white">VPS 1000 G12</p>
      <p class="mt-1 text-sm text-slate-600 dark:text-slate-300">4 vCore · 8 GB RAM · 256 GB NVMe</p>
      <p class="mt-1 text-sm font-semibold text-paprika-700 dark:text-paprika-400">ab 10,36 €/Monat</p>
      <p class="mt-2 text-sm text-slate-600 dark:text-slate-400">Reicht für ntfy locker – der Dienst braucht kaum Ressourcen.</p>
    </div>
    <a href="https://www.netcup.com/de/server/vps/vps-1000-g12-12m?ref=44083" rel="sponsored noopener" target="_blank"
   data-track-event="Affiliate|netcup: Affiliate-Box|VPS 1000 G12 · {page}"
   class="inline-flex shrink-0 items-center justify-center rounded-lg bg-paprika-600 px-5 py-2.5 font-semibold text-white transition-colors hover:bg-paprika-700">
  Zu netcup →
</a>

  </div><div class="px-4 pb-4"><p class="not-prose my-3 flex flex-wrap items-center gap-x-2 gap-y-1 rounded-lg border border-herb-500/40 bg-herb-50 px-3 py-2 text-sm text-slate-700 dark:bg-herb-900/20 dark:text-slate-200">
  <span>💶 <strong>5 € Gutschein</strong> für netcup-Neukunden:</span><code data-track-voucher="36nc17844976032"
        class="rounded bg-white px-2 py-0.5 font-mono text-sm font-semibold text-herb-800 dark:bg-slate-800 dark:text-herb-400">36nc17844976032</code>
  <span class="text-xs text-slate-500 dark:text-slate-400">(nur Neukunden, keine Domains)</span>
</p></div>
</div>

<h2 id="schritt-für-schritt">Schritt für Schritt</h2>
<h3 id="schritt-1-die-composeyaml-schreiben">Schritt 1: Die <code>compose.yaml</code> schreiben</h3>
<p>Leg den Projektordner an:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">mkdir -p /opt/ntfy <span class="o">&amp;&amp;</span> <span class="nb">cd</span> /opt/ntfy</span></span></code></pre></div>
</div>
<p>Erstelle <code>/opt/ntfy/compose.yaml</code>. Ersetze <strong><code>ntfy.DEINE-DOMAIN.de</code> durch deine echte (Sub-)Domain</strong> – sie steht sowohl in der <code>NTFY_BASE_URL</code> als auch im Traefik-Label:</p>
<div class="sk-code">
  <span class="sk-code-head">YAML</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">services</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">ntfy</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">binwiederhier/ntfy:v2.26</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">container_name</span><span class="p">:</span><span class="w"> </span><span class="l">ntfy</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">command</span><span class="p">:</span><span class="w"> </span><span class="l">serve</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">environment</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">NTFY_BASE_URL</span><span class="p">:</span><span class="w"> </span><span class="l">https://ntfy.DEINE-DOMAIN.de</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">NTFY_LISTEN_HTTP</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;:80&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">NTFY_BEHIND_PROXY</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;true&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">NTFY_ENABLE_LOGIN</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;true&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">NTFY_REQUIRE_LOGIN</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;true&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">NTFY_CACHE_FILE</span><span class="p">:</span><span class="w"> </span><span class="l">/var/lib/ntfy/cache.db</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">NTFY_AUTH_FILE</span><span class="p">:</span><span class="w"> </span><span class="l">/var/lib/ntfy/auth.db</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">NTFY_AUTH_DEFAULT_ACCESS</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;deny-all&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">NTFY_ATTACHMENT_CACHE_DIR</span><span class="p">:</span><span class="w"> </span><span class="l">/var/lib/ntfy/attachments</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">volumes</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">data:/var/lib/ntfy</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">networks</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">proxy]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">restart</span><span class="p">:</span><span class="w"> </span><span class="l">unless-stopped</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">labels</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;traefik.enable=true&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;traefik.http.routers.ntfy.rule=Host(`ntfy.DEINE-DOMAIN.de`)&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;traefik.http.routers.ntfy.entrypoints=websecure&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;traefik.http.routers.ntfy.tls.certresolver=le&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;traefik.http.services.ntfy.loadbalancer.server.port=80&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">networks</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">proxy</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">external</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">volumes</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="l">data:</span></span></span></code></pre></div>
</div>
<p>Die wichtigsten Zeilen:</p>
<ul>
<li><strong><code>NTFY_BASE_URL</code></strong> muss exakt deine öffentliche HTTPS-Adresse sein – die App und der Web-Client verweigern sonst die Verbindung.</li>
<li><strong><code>NTFY_BEHIND_PROXY: &quot;true&quot;</code></strong> sagt ntfy, dass es hinter Traefik läuft, damit es die echte Besucher-IP aus den Proxy-Headern liest (wichtig fürs Rate-Limiting).</li>
<li><strong><code>NTFY_AUTH_DEFAULT_ACCESS: &quot;deny-all&quot;</code></strong> ist die Sicherheitsschraube: Standardmäßig darf <strong>niemand</strong> lesen oder schreiben. Zugriff bekommt nur, wen wir gleich explizit anlegen. Ohne diese Zeile wäre dein Server ein offenes Push-Relay für die ganze Welt.</li>
<li><strong><code>NTFY_ENABLE_LOGIN</code> / <code>NTFY_REQUIRE_LOGIN</code></strong> schalten die Anmeldung im Web-Client frei und machen sie zur Pflicht. Mit <code>NTFY_REQUIRE_LOGIN</code> empfängt ein nicht angemeldeter Besucher direkt einen Login-Screen statt einer leeren Oberfläche.</li>
</ul>
<h3 id="schritt-2-den-server-starten">Schritt 2: Den Server starten</h3>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker compose up -d</span></span></code></pre></div>
</div>
<p>Prüfe, dass der Container läuft:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker compose ps</span></span></code></pre></div>
</div>
<div class="sk-code">
  <span class="sk-code-head">Ausgabe</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">NAME   IMAGE                       COMMAND         SERVICE   STATUS
</span></span><span class="line"><span class="cl">ntfy   binwiederhier/ntfy:v2.26    &#34;ntfy serve&#34;    ntfy      Up 4 seconds</span></span></code></pre></div>
</div>
<p>(Zur besseren Lesbarkeit sind die Spalten <code>CREATED</code> und <code>PORTS</code> hier ausgeblendet.)</p>
<p>Traefik holt automatisch ein Zertifikat. Prüfe von deinem Rechner aus den Health-Endpunkt:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl -s https://ntfy.DEINE-DOMAIN.de/v1/health</span></span></code></pre></div>
</div>
<div class="sk-code">
  <span class="sk-code-head">Ausgabe</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">{&#34;healthy&#34;:true}</span></span></code></pre></div>
</div>
<p>Antwortet der Server mit <code>{&quot;healthy&quot;:true}</code>, steht die Kette aus DNS, Traefik, TLS und ntfy.</p>
<h3 id="schritt-3-einen-benutzer-anlegen">Schritt 3: Einen Benutzer anlegen</h3>
<p>Weil wir <code>deny-all</code> gesetzt haben, brauchst du mindestens einen Benutzer. Lege einen Administrator an (er darf auf alle Themen schreiben und lesen):</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker <span class="nb">exec</span> -it ntfy ntfy user add --role<span class="o">=</span>admin admin</span></span></code></pre></div>
</div>
<p>ntfy fragt zweimal nach einem Passwort und bestätigt dann:</p>
<div class="sk-code">
  <span class="sk-code-head">Ausgabe</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">user admin added with role admin</span></span></code></pre></div>
</div>
<p>Kontrolliere das Ergebnis:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker <span class="nb">exec</span> ntfy ntfy user list</span></span></code></pre></div>
</div>
<div class="sk-code">
  <span class="sk-code-head">Ausgabe</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">user admin (role: admin, tier: none)
</span></span><span class="line"><span class="cl">- read-write access to all topics (admin role)</span></span></code></pre></div>
</div>
<div class="not-prose my-6 rounded-lg border-l-4 p-4 border-herb-400 bg-herb-50 dark:border-herb-700 dark:bg-herb-900/20">
  <p class="mb-1 flex items-center gap-2 font-semibold text-slate-900 dark:text-white">
    <span aria-hidden="true">🧑‍🍳</span>Tipp
  </p>
  <div class="prose-kitchen text-sm">Für einzelne Personen oder Geräte, die nur bestimmte Themen nutzen sollen, legst du normale Benutzer (<code>--role=user</code>) an und vergibst gezielt Rechte. Lege den Benutzer zuerst an (<code>docker exec -it ntfy ntfy user add --role=user handy</code>) und weise ihm dann das Recht zu, z. B. <code>docker exec ntfy ntfy access handy &quot;serverkueche-alerts&quot; read-only</code>. So darf das Handy mitlesen, aber nichts senden.</div>
</div>
<h3 id="schritt-4-ein-thema-abonnieren">Schritt 4: Ein Thema abonnieren</h3>
<p>In ntfy läuft alles über <strong>Themen</strong> (englisch „topics&quot;) – frei wählbare Namen, unter denen Nachrichten laufen. Öffne <code>https://ntfy.DEINE-DOMAIN.de</code> im Browser. Dank <code>NTFY_REQUIRE_LOGIN</code> empfängt dich der Web-Client direkt mit einem <strong>Login-Screen</strong> – melde dich dort mit deinem angelegten <code>admin</code>-Konto an (ohne Login blockt <code>deny-all</code> jeden Lese- und Abo-Versuch mit <code>HTTP 403</code>). Danach klickst du links auf <strong>Thema abonnieren</strong> und wählst einen <strong>schwer zu erratenden Namen</strong> (z. B. <code>serverkueche-alerts</code>):</p>
<p><figure class="my-6"><img src="/tutorials/ntfy-push-benachrichtigungen/ntfy-abonnieren_hu_630bf72059626d02.webp" srcset="/tutorials/ntfy-push-benachrichtigungen/ntfy-abonnieren_hu_3461bb382fbdc25b.webp 480w, /tutorials/ntfy-push-benachrichtigungen/ntfy-abonnieren_hu_630bf72059626d02.webp 768w, /tutorials/ntfy-push-benachrichtigungen/ntfy-abonnieren_hu_50a00ebf5efd6267.webp 1200w, /tutorials/ntfy-push-benachrichtigungen/ntfy-abonnieren_hu_e8cf55e3a5c4ab34.webp 1920w" sizes="(min-width: 768px) 768px, 100vw"
    width="768" height="432"
    data-full="/tutorials/ntfy-push-benachrichtigungen/ntfy-abonnieren_hu_2194bf6e2f932c0d.webp"
    alt="ntfy-Web-Oberfläche mit dem Dialog zum Abonnieren eines neuen Themas" title="Ein Thema abonnieren – der Name sollte nicht zu erraten sein"
    loading="lazy" decoding="async" class="rounded-lg"><figcaption class="mt-2 text-sm text-center text-slate-500 italic">Ein Thema abonnieren – der Name sollte nicht zu erraten sein</figcaption></figure></p>
<p>Auf dem Handy richtest du deinen eigenen Server einmalig in der ntfy-App ein: Öffne <strong>Einstellungen → Standard-Server</strong> und trage <code>https://ntfy.DEINE-DOMAIN.de</code> ein. Danach hinterlegst du unter <strong>Benutzerverwaltung</strong> deine Zugangsdaten für diesen Server. Jetzt kannst du wie im Browser ein Thema hinzufügen – die App fragt dabei nicht mehr nach dem großen ntfy.sh-Server, sondern nutzt deinen. Ab sofort landet jede Nachricht an dieses Thema als echte Push-Benachrichtigung auf dem Gerät, auch bei geschlossener App. Auf iOS läuft der Empfang über Apples Push-Dienst; die App erklärt beim ersten Start, was dafür einmalig nötig ist.</p>
<div class="not-prose my-6 rounded-lg border-l-4 p-4 border-sky-300 bg-sky-50 dark:border-sky-800 dark:bg-sky-900/20">
  <p class="mb-1 flex items-center gap-2 font-semibold text-slate-900 dark:text-white">
    <span aria-hidden="true">ℹ️</span>Browser-Benachrichtigungen erlauben
  </p>
  <div class="prose-kitchen text-sm">Zeigt der Web-Client oben links „Benachrichtigungen sind blockiert&quot;, musst du sie in deinem Browser für diese Seite noch erlauben – sonst siehst du die Nachrichten nur, solange der Tab offen ist. Für zuverlässige Push-Nachrichten unterwegs ist die Handy-App ohnehin die bessere Wahl.</div>
</div>
<h3 id="schritt-5-eine-nachricht-senden">Schritt 5: Eine Nachricht senden</h3>
<p>Jetzt der eigentliche Zweck – eine Nachricht per <code>curl</code> verschicken. Weil der Server privat ist, gibst du deine Zugangsdaten mit (<code>-u BENUTZER:PASSWORT</code>):</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl -u admin:DEIN_PASSWORT -d <span class="s2">&#34;Backup erfolgreich abgeschlossen&#34;</span> https://ntfy.DEINE-DOMAIN.de/serverkueche-alerts</span></span></code></pre></div>
</div>
<p>Das war&rsquo;s – die Nachricht ist sofort auf allen abonnierten Geräten. Mit ein paar zusätzlichen Headern wird sie aussagekräftiger: Titel, Priorität (1–5) und Tags (die auch als Emojis erscheinen):</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl -u admin:DEIN_PASSWORT <span class="se">\
</span></span></span><span class="line"><span class="cl">  -H <span class="s2">&#34;Title: Warnung vom Monitoring&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  -H <span class="s2">&#34;Priority: 4&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  -H <span class="s2">&#34;Tags: warning&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  -d <span class="s2">&#34;Hohe CPU-Last auf dem VPS&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  https://ntfy.DEINE-DOMAIN.de/serverkueche-alerts</span></span></code></pre></div>
</div>
<p>Die <strong>Priorität</strong> steuert, wie aufdringlich die Meldung ankommt: <code>5</code> (max) lässt das Handy klingeln und vibrieren, <code>4</code> (high) meldet sich deutlich, <code>3</code> ist der Standard, <code>2</code> und <code>1</code> (low/min) landen leise in der Liste. Für „Server nicht erreichbar&quot; nimmst du 5, für „Backup ok&quot; eher 2 – so stumpfst du dich nicht gegen die wichtigen Alarme ab.</p>
<p><strong>Tags</strong> werden zu Emojis, wenn sie einem bekannten Namen entsprechen: <code>warning</code> → ⚠️, <code>white_check_mark</code> → ✅, <code>rotating_light</code> → 🚨. Mehrere Tags gibst du kommagetrennt an (<code>-H &quot;Tags: rotating_light,skull&quot;</code>). Und mit dem Header <code>Click</code> öffnet ein Tippen auf die Nachricht direkt eine URL – praktisch, um vom Alarm sofort ins Dashboard zu springen:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl -u admin:DEIN_PASSWORT <span class="se">\
</span></span></span><span class="line"><span class="cl">  -H <span class="s2">&#34;Title: Uptime Kuma: Dienst down&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  -H <span class="s2">&#34;Priority: 5&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  -H <span class="s2">&#34;Tags: rotating_light&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  -H <span class="s2">&#34;Click: https://status.DEINE-DOMAIN.de&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  -d <span class="s2">&#34;Nextcloud antwortet nicht mehr&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  https://ntfy.DEINE-DOMAIN.de/serverkueche-alerts</span></span></code></pre></div>
</div>
<p>Richtig mächtig wird es mit <strong>Aktions-Buttons</strong>: Über den Header <code>Actions</code> blendest du direkt in der Benachrichtigung Schaltflächen ein, die eine URL öffnen oder einen HTTP-Request auslösen – so quittierst du einen Alarm mit einem Fingertipp, ohne die App überhaupt zu öffnen:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl -u admin:DEIN_PASSWORT <span class="se">\
</span></span></span><span class="line"><span class="cl">  -H <span class="s2">&#34;Title: Server neu starten?&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  -H <span class="s2">&#34;Actions: view, Status öffnen, https://status.DEINE-DOMAIN.de&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  -d <span class="s2">&#34;Ein Dienst hängt – im Statusboard nachsehen.&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  https://ntfy.DEINE-DOMAIN.de/serverkueche-alerts</span></span></code></pre></div>
</div>
<p>Dieselbe Nachricht kannst du auch bequem über den Web-Client zusammenklicken – praktisch zum Ausprobieren aller Optionen:</p>
<p><figure class="my-6"><img src="/tutorials/ntfy-push-benachrichtigungen/ntfy-senden_hu_20dc0a373997177a.webp" srcset="/tutorials/ntfy-push-benachrichtigungen/ntfy-senden_hu_2d836d1860ec48bd.webp 480w, /tutorials/ntfy-push-benachrichtigungen/ntfy-senden_hu_20dc0a373997177a.webp 768w, /tutorials/ntfy-push-benachrichtigungen/ntfy-senden_hu_46a0e4cadaa6c52e.webp 1200w, /tutorials/ntfy-push-benachrichtigungen/ntfy-senden_hu_f1b0f91f0f7e824.webp 1920w" sizes="(min-width: 768px) 768px, 100vw"
    width="768" height="432"
    data-full="/tutorials/ntfy-push-benachrichtigungen/ntfy-senden_hu_4cfeedc53d2a359f.webp"
    alt="ntfy-Dialog zum Senden einer Nachricht mit Feldern für Thema, Titel, Priorität und Tags" title="Der Sende-Dialog im Web-Client zeigt alle Optionen: Titel, Priorität, Tags, Anhänge"
    loading="lazy" decoding="async" class="rounded-lg"><figcaption class="mt-2 text-sm text-center text-slate-500 italic">Der Sende-Dialog im Web-Client zeigt alle Optionen: Titel, Priorität, Tags, Anhänge</figcaption></figure></p>
<h3 id="schritt-6-nachrichten-kommen-an">Schritt 6: Nachrichten kommen an</h3>
<p>Im Web-Client (sofern du dort wie in Schritt 4 mit deinem <code>admin</code>-Konto angemeldet bist) und parallel in der App tauchen die Nachrichten sofort auf – mit Titel, Zeitstempel und farblich hervorgehobener Priorität:</p>
<p><figure class="my-6"><img src="/tutorials/ntfy-push-benachrichtigungen/ntfy-dashboard_hu_2ef0838eba6f8800.webp" srcset="/tutorials/ntfy-push-benachrichtigungen/ntfy-dashboard_hu_e0117b28a7b72124.webp 480w, /tutorials/ntfy-push-benachrichtigungen/ntfy-dashboard_hu_2ef0838eba6f8800.webp 768w, /tutorials/ntfy-push-benachrichtigungen/ntfy-dashboard_hu_cdb9f8d2e6ba283a.webp 1200w, /tutorials/ntfy-push-benachrichtigungen/ntfy-dashboard_hu_a6e5b8cdce028242.webp 1920w" sizes="(min-width: 768px) 768px, 100vw"
    width="768" height="432"
    data-full="/tutorials/ntfy-push-benachrichtigungen/ntfy-dashboard_hu_f346e48ed6939dd4.webp"
    alt="ntfy-Web-Oberfläche mit drei empfangenen Benachrichtigungen im abonnierten Thema" title="Empfangene Nachrichten im Thema – mit Titel, Priorität und Emoji-Tags"
    loading="lazy" decoding="async" class="rounded-lg"><figcaption class="mt-2 text-sm text-center text-slate-500 italic">Empfangene Nachrichten im Thema – mit Titel, Priorität und Emoji-Tags</figcaption></figure></p>
<p>Den Web-Client kannst du in Chrome oder Edge übrigens als <strong>App installieren</strong> (PWA): Dann bekommst du auch am Desktop Push-Benachrichtigungen, ohne einen Tab offen halten zu müssen – praktisch, wenn der Rechner ohnehin läuft und du Alarme direkt auf dem Bildschirm sehen willst.</p>
<h3 id="schritt-7-access-tokens-für-skripte-statt-passwort">Schritt 7: Access-Tokens für Skripte statt Passwort</h3>
<p>Ein Passwort in jedem Cronjob und Backup-Skript zu hinterlegen ist unschön. Besser ist ein <strong>Access-Token</strong>, den du jederzeit einzeln widerrufen kannst:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker <span class="nb">exec</span> ntfy ntfy token add admin</span></span></code></pre></div>
</div>
<p>ntfy gibt einen Token zurück, der mit <code>tk_</code> beginnt. Den nutzt du dann statt <code>-u</code> als Bearer-Token:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl -H <span class="s2">&#34;Authorization: Bearer tk_DEIN_TOKEN&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  -H <span class="s2">&#34;Title: Nächtliches Backup&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  -d <span class="s2">&#34;Restic-Backup ohne Fehler durchgelaufen&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  https://ntfy.DEINE-DOMAIN.de/serverkueche-alerts</span></span></code></pre></div>
</div>
<p>So kannst du ntfy sauber in deine <a href="/tutorials/backups-mit-restic/">Restic-Backups</a> einbauen (Meldung am Ende des Backup-Skripts) oder von <a href="/tutorials/uptime-kuma-monitoring/">Uptime Kuma</a> als Benachrichtigungskanal ansprechen lassen – Uptime Kuma kennt ntfy als eingebauten Notification-Typ.</p>
<h3 id="schritt-8-praxisbeispiel--ein-backup-skript-das-sich-meldet">Schritt 8: Praxisbeispiel – ein Backup-Skript, das sich meldet</h3>
<p>Am nützlichsten wird ntfy, wenn ein Skript automatisch Bescheid gibt. Das folgende Muster wickelt einen beliebigen Befehl ein und schickt je nach Ausgang eine leise Erfolgs- oder eine laute Fehlermeldung. Leg es als <code>/opt/scripts/backup-notify.sh</code> an und passe Domain, Token und den eigentlichen Backup-Befehl an:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="cp">#!/usr/bin/env bash
</span></span></span><span class="line"><span class="cl"><span class="nb">set</span> -uo pipefail
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">NTFY_URL</span><span class="o">=</span><span class="s2">&#34;https://ntfy.DEINE-DOMAIN.de/serverkueche-alerts&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">NTFY_TOKEN</span><span class="o">=</span><span class="s2">&#34;tk_DEIN_TOKEN&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Hier steht dein echter Backup-Befehl – Exit-Code entscheidet über die Meldung:</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> restic backup /opt --tag nightly<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">  curl -s -H <span class="s2">&#34;Authorization: Bearer </span><span class="nv">$NTFY_TOKEN</span><span class="s2">&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">    -H <span class="s2">&#34;Title: Backup ok&#34;</span> -H <span class="s2">&#34;Tags: white_check_mark&#34;</span> -H <span class="s2">&#34;Priority: 2&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">    -d <span class="s2">&#34;Nächtliches Backup ohne Fehler durchgelaufen.&#34;</span> <span class="s2">&#34;</span><span class="nv">$NTFY_URL</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">else</span>
</span></span><span class="line"><span class="cl">  curl -s -H <span class="s2">&#34;Authorization: Bearer </span><span class="nv">$NTFY_TOKEN</span><span class="s2">&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">    -H <span class="s2">&#34;Title: BACKUP FEHLGESCHLAGEN&#34;</span> -H <span class="s2">&#34;Tags: rotating_light&#34;</span> -H <span class="s2">&#34;Priority: 5&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">    -d <span class="s2">&#34;Das Backup ist mit einem Fehler abgebrochen – bitte sofort prüfen.&#34;</span> <span class="s2">&#34;</span><span class="nv">$NTFY_URL</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">fi</span></span></span></code></pre></div>
</div>
<p>Mach es ausführbar und teste es einmal von Hand:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">chmod +x /opt/scripts/backup-notify.sh
</span></span><span class="line"><span class="cl">/opt/scripts/backup-notify.sh</span></span></code></pre></div>
</div>
<p>Läuft es sauber, hängst du es in einen Cronjob – so bekommst du jede Nacht eine kurze Bestätigung und wirst bei einem Fehler mit voller Priorität geweckt:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">crontab -e</span></span></code></pre></div>
</div>
<div class="sk-code">
  <span class="sk-code-head">Ausgabe</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">30 3 * * * /opt/scripts/backup-notify.sh</span></span></code></pre></div>
</div>
<p>Das Prinzip lässt sich auf alles übertragen: ein Zertifikat läuft ab, eine Platte wird voll (<code>df</code> im Skript prüfen), ein Deployment ist durch. Immer derselbe Einzeiler – ein <code>curl</code> an dein Thema. Genau das macht ntfy so praktisch: Du musst nichts integrieren, was HTTP kann, kann dich benachrichtigen.</p>
<h2 id="wenn-es-nicht-funktioniert">Wenn es nicht funktioniert</h2>
<div class="troubleshoot not-prose">
<p><strong>Die App meldet „Cannot connect&quot; oder der Web-Client bleibt leer.</strong> Die <code>NTFY_BASE_URL</code> passt nicht
zur aufgerufenen Adresse. Sie muss exakt deine öffentliche HTTPS-URL sein
(<code>https://ntfy.DEINE-DOMAIN.de</code>, ohne Slash am Ende). Nach einer Änderung <code>docker compose up -d</code>
erneut ausführen.</p>
<p><strong><code>curl</code> liefert <code>HTTP 401</code> oder <code>403</code>.</strong> Bei <code>deny-all</code> sind fehlende oder falsche Zugangsdaten der
häufigste Fehler. Benutzer/Passwort prüfen (<code>docker exec ntfy ntfy user list</code>) und beim Senden <code>-u BENUTZER:PASSWORT</code> bzw. den Bearer-Token mitgeben. Ein <code>403</code> bedeutet, dass der Benutzer existiert,
aber keine Rechte auf dieses Thema hat – dann mit <code>ntfy access</code> Rechte vergeben.</p>
<p><strong>Nachrichten kommen im Browser an, aber nicht als Push aufs Handy, wenn der Tab zu ist.</strong>
Browser-Push braucht erteilte Benachrichtigungsrechte und einen aktiven Service Worker; das ist
unzuverlässig, sobald der Tab geschlossen ist. Für echtes „unterwegs&quot;-Push die ntfy-App verwenden –
sie hält die Verbindung im Hintergrund.</p>
<p><strong><code>502 Bad Gateway</code> von Traefik.</strong> Der Container ist noch nicht bereit oder hört auf dem falschen
Port. Prüfe <code>docker compose logs ntfy</code> und dass das Label <code>loadbalancer.server.port=80</code> gesetzt ist
– ntfy lauscht im Container auf Port 80 (<code>NTFY_LISTEN_HTTP=&quot;:80&quot;</code>).</p>
<p><strong><code>429 Too Many Requests</code> bei vielen Nachrichten kurz hintereinander.</strong> ntfy begrenzt standardmäßig
die Rate pro Absender, um Missbrauch zu verhindern. Bei einem privaten Server mit eigenen Skripten
stößt du selten daran – ein Schleifen-Skript ohne Pause aber schon. Nachrichten bündeln statt im
Sekundentakt zu feuern, oder die Limits gezielt über die <code>NTFY_VISITOR_*</code>-Umgebungsvariablen anheben
(in der ntfy-Doku unter „Rate limiting&quot; beschrieben). <code>NTFY_BEHIND_PROXY: &quot;true&quot;</code> ist Voraussetzung,
damit das Limit pro echter IP statt pro Traefik-Container greift.</p>

</div>

<h2 id="wartung--backups">Wartung &amp; Backups</h2>
<p><strong>Updates</strong> ziehst du innerhalb der gepinnten Version so:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">cd</span> /opt/ntfy <span class="o">&amp;&amp;</span> docker compose pull <span class="o">&amp;&amp;</span> docker compose up -d</span></span></code></pre></div>
</div>
<p>Für einen Sprung auf eine neue Hauptversion vorher die Release-Notes lesen und den Image-Tag anheben.</p>
<p><strong>Backups:</strong> ntfy speichert Benutzer, Zugriffsrechte und den Nachrichten-Cache in seinen SQLite-Dateien im Volume (<code>cache.db</code>, <code>auth.db</code>). Sichere den Inhalt regelmäßig, indem du das Volume in ein Archiv packst …</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker run --rm -v ntfy_data:/data -v /opt/backups:/backup alpine:3 <span class="se">\
</span></span></span><span class="line"><span class="cl">  tar czf /backup/ntfy-data.tar.gz -C /data .</span></span></code></pre></div>
</div>
<p>… und dieses Archiv in dein <a href="/tutorials/backups-mit-restic/">verschlüsseltes Off-Site-Backup mit Restic</a> aufnimmst. Der Nachrichten-Cache ist zwar verzichtbar (Push-Nachrichten sind flüchtig), aber die Benutzer- und Rechte-Datenbank willst du nach einem Ausfall nicht neu aufbauen müssen.</p>
<p><strong>Im Alltag</strong> ist ntfy nahezu wartungsfrei. Kontrolliere gelegentlich mit <code>docker exec ntfy ntfy user list</code>, wer Zugriff hat, und widerrufe nicht mehr genutzte Tokens mit <code>ntfy token remove BENUTZER TOKEN-ID</code> (die IDs zeigt dir <code>ntfy token list BENUTZER</code>) – so bleibt dein Push-Server dein eigener.</p>
]]></content:encoded></item></channel></rss>