Files
Homelab--Bratonein-Kontroll…/Kapitel 10/Free Rhohtext.md

1345 lines
54 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Kapitel 10 n8n (Free)
## Einleitung
Mit dem Tool **n8n** (gesprochen: „nn“) führst du eine zentrale Komponente für Automatisierungen in dein UCC-System ein. Das Ziel ist, wiederkehrende Aufgaben wie Erinnerungen, Uploads oder Social-Media-Posts nicht manuell erledigen zu müssen sondern automatisiert, nachvollziehbar und kontrolliert im Hintergrund ablaufen zu lassen.
n8n ist eine sogenannte Low-Code-Automatisierungsplattform. Du erstellst Abläufe („Workflows“) visuell, indem du vordefinierte Funktionen sogenannte „Nodes“ miteinander verbindest. Es gibt Nodes für Zeitpläne, HTTP-Requests, Datenbanken, Social Media, Kalender, E-Mail, Twitch, Discord und viele weitere Dienste. Gleichzeitig kannst du eigene JavaScript-Logik ergänzen, wenn du mehr Kontrolle brauchst.
Im Gegensatz zu externen Diensten wie Zapier, Make oder IFTTT läuft n8n vollständig lokal in einem eigenen Container auf deinem Server. Das bedeutet:
- keine Daten verlassen dein Netzwerk,
- keine Anmeldung oder Drittanbieter-Abhängigkeit,
- keine Einschränkungen bei der Anpassung.
[!NOTE]
Wir verwenden in diesem Tutorial ausschließlich die kostenfreie **Community Edition** von n8n. Diese wird lokal installiert, läuft dauerhaft im eigenen Container und stellt alle für den Einstieg relevanten Funktionen bereit.
Dieses Kapitel behandelt ausschließlich die Grundlagen:
- Installation von n8n auf einem dedizierten Ubuntu-Container,
- Konfiguration und Start als systemweiter Dienst,
- Integration über Nginx Proxy Manager mit Subdomain und HTTPS,
- Erstellung eines ersten produktiven Workflows (Stream-Reminder + Social Post).
Das hier erstellte Setup bildet die technische Basis für spätere Erweiterungen, z.B. das automatische Auslesen von Twitch-Kalenderdaten (ICS-Dateien), das Erzeugen und Planen von Social-Media-Inhalten oder automatisierte Uploads in deine Nextcloud. Diese folgen im Premium-Kapitel.
Wie immer setzen wir kein technisches Vorwissen voraus. Alles, was du für dieses Kapitel brauchst, hast du in den vorherigen Schritten bereits eingerichtet: Proxmox, LXC, Proxy, Domain und grundlegende Netzwerkstruktur. Wenn du diesen Abschnitt erfolgreich abgeschlossen hast, kannst du erste Automatisierungen vollständig eigenständig umsetzen mit deinem eigenen System und ohne Drittanbieter.
---
## Voraussetzungen & Ressourcen
Bevor du mit der Installation von n8n beginnst, solltest du sicherstellen, dass dein System korrekt vorbereitet ist. In diesem Abschnitt definieren wir die nötigen Ressourcen für den LXC-Container und klären, welche technischen Voraussetzungen erfüllt sein müssen, damit alle späteren Schritte funktionieren.
### Container-Ressourcen
Für den n8n-Container legen wir folgende Ausstattung fest:
* **CPU: 2 vCPUs**
Zwei virtuelle Prozessoren reichen für die Ausführung typischer n8nWorkflows im Hintergrund.
Falls du später viele parallele Abläufe oder aufwendige API-Abfragen nutzen möchtest, kannst du die CPU-Zahl bei Bedarf erhöhen.
* **RAM: 2 GB**
Der Node.js-Prozess von n8n benötigt vergleichsweise wenig Arbeitsspeicher.
Mit 2 GB läuft das System auch bei mehreren gleichzeitig aktiven Workflows stabil.
Nur bei sehr großen Datenverarbeitungen (z.B. viele gleichzeitige Uploads oder komplexe Datenmanipulationen) kann mehr RAM sinnvoll sein.
* **Speicherplatz: 10 GB**
Dieser Platz reicht für die Grundinstallation, Logdateien und temporäre Workflow-Daten.
Da n8n keine großen Medien speichert, ist der Speicherbedarf überschaubar.
Wenn du viele eigene Skripte oder große JSON-Daten verarbeitest, kannst du den Container später vergrößern.
* **Betriebssystem: Ubuntu 24.04 LTS (64Bit)**
Wir setzen hier auf Ubuntu, da es moderne Pakete für Node.js bereitstellt und sich gut für die manuelle Installation eignet.
Zudem verwenden wir Node.js ≥ 18.x, was unter Ubuntu besonders gut unterstützt wird.
* **Netzwerk: Feste IP-Adresse per DHCP-Reservierung**
Wie in Kapitel 1 beschrieben, richtest du im Router eine DHCP-Reservierung für den Container ein.
So bleibt er immer unter derselben Adresse erreichbar und kann später korrekt im Proxy Manager eingebunden werden.
[!TIP]
Plane beim Erstellen des Containers genug Reserven ein auch wenn n8n anfangs wenig verbraucht.
Gerade wenn du das System später für Uploads, VOD-Verarbeitung oder komplexe Kalenderanalysen nutzt, steigen RAM- und CPU-Anforderungen deutlich.
### Technische Voraussetzungen
Dieses Kapitel baut auf der bestehenden UCC-Grundstruktur auf. Folgende Komponenten solltest du bereits eingerichtet haben:
* **Proxmox läuft stabil** (Kapitel 1)
Der LXC-Container für n8n wird direkt dort erstellt und verwaltet.
* **Nginx Proxy Manager ist eingerichtet** (Kapitel 3)
Darüber wird n8n später mit Subdomain, HTTPS und Zertifikat erreichbar gemacht.
* **Domain oder DynDNS-Adresse ist vorhanden** (Kapitel 4)
Für die öffentliche Erreichbarkeit und Let's Encrypt brauchst du eine gültige Subdomain, z.B. `n8n.deinprojekt.de`.
* **Zugriff auf das Container-Terminal**
Du benötigst entweder direkten Zugriff über die Proxmox-Konsole oder per SSH auf den Container.
[!IMPORTANT]
Wenn du n8n nur im lokalen Netzwerk einsetzen möchtest, kannst du den Container auch ohne Domain und HTTPS betreiben. Die Anleitung funktioniert in diesem Fall ebenfalls du musst später lediglich eigene Proxy-Regeln anpassen.
### Software und Versionen
In diesem Kapitel installierst du alle benötigten Komponenten manuell ohne Docker, vollständig nachvollziehbar:
* **Node.js** ab Version 18.x (erforderlich für aktuelle n8n-Releases)
* **npm** Node Package Manager, wird automatisch mit Node.js installiert
* **n8n** Automatisierungstool, wird systemweit per `npm install -g` eingerichtet
* **PM2** Prozessmanager, sorgt für dauerhaften Hintergrundbetrieb und Autostart
Alle Schritte erfolgen in der richtigen Reihenfolge und mit ausführlichen Erklärungen du brauchst keine Vorkenntnisse im Umgang mit Node.js oder JavaScript.
[!TIP]
Die direkte Installation ohne Docker erhöht die Transparenz. Du behältst volle Kontrolle über die Dateien, Logs und Prozesse und kannst das System bei Bedarf gezielt sichern oder migrieren.
---
## Schritt 1 Grundsystem aktualisieren
Bevor wir mit der Installation von n8n beginnen, sorgen wir dafür, dass das Betriebssystem im Container auf dem neuesten Stand ist.
Das ist wichtig, um Fehler durch veraltete Pakete zu vermeiden und eine stabile Grundlage für die weiteren Schritte zu schaffen.
Öffne dazu in Proxmox die **Shell** des n8n-Containers.
Wähle in der linken Seitenleiste den Container aus und klicke auf **Shell**.
👉 Screenshot geeignet: Proxmox Container ausgewählt und Konsole geöffnet
Gib anschließend den folgenden Befehl ein, um alle Paketlisten zu aktualisieren und die verfügbaren Updates zu installieren.
Starte danach den Container neu, damit die Aktualisierungen aktiv werden:
```bash
apt update && apt upgrade -y
reboot
```
[!NOTE]
Führe diesen Schritt auch dann durch, wenn der Container gerade erst erstellt wurde.
Ein aktuelles Grundsystem verhindert spätere Konflikte bei der Installation von Node.js und n8n.
## Schritt 2 Node.js & n8n installieren
Nach dem Update ist das System bereit für die Installation der benötigten Software.
n8n basiert auf Node.js, daher müssen wir zunächst Node.js und den zugehörigen Paketmanager **npm** einrichten.
Anschließend installieren wir n8n selbst sowie den Prozessmanager **PM2**, damit n8n dauerhaft im Hintergrund laufen kann.
### Benutzer wechseln
Wir installieren n8n nicht mit Administrator-Rechten, sondern unter einem eigenen Benutzerkonto.
Melde dich daher mit dem Benutzer an, den du in Schritt 1 erstellt hast:
```bash
su - n8nuser
```
👉 Screenshot geeignet: Konsole Anmeldung als Benutzer `n8nuser`
### Node.js installieren
Zuerst fügen wir das offizielle NodeSource-Repository hinzu, um die aktuelle Version (mindestens 18.x) zu erhalten, und installieren dann Node.js und npm:
```bash
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt install -y nodejs
```
Prüfe nach der Installation die Versionen:
```bash
node -v
npm -v
```
Die angezeigten Versionsnummern sollten mindestens `v18.x` für Node.js und eine aktuelle npm-Version zeigen.
[!NOTE]
Falls eine deutlich ältere Version angezeigt wird, wiederhole die Installation oder kontrolliere die Repository-Adresse.
### n8n und PM2 installieren
Installiere nun n8n und den Prozessmanager PM2 global über npm:
```bash
sudo npm install -g n8n pm2
```
Mit PM2 stellst du sicher, dass n8n auch nach einem Neustart automatisch startet.
Überprüfe anschließend, ob n8n korrekt installiert wurde:
```bash
n8n --version
```
Die Ausgabe zeigt die aktuell installierte n8n-Version an.
[!TIP]
PM2 sorgt dafür, dass n8n später automatisch als Hintergrunddienst läuft.
Die Konfiguration dafür nehmen wir im nächsten Schritt vor.
## Schritt 3 n8n als Dienst einrichten und starten
Damit n8n nicht nur manuell über die Konsole gestartet werden kann, richten wir den automatischen Start mit **PM2** ein.
So läuft n8n dauerhaft im Hintergrund und wird bei jedem Neustart des Containers automatisch geladen.
### n8n erstmals starten
Starte n8n zunächst einmalig, um sicherzustellen, dass es fehlerfrei läuft:
```bash
n8n
```
Die Konsole zeigt nun Startmeldungen von n8n an und wartet anschließend auf Anfragen.
Beende den Prozess wieder mit der Tastenkombination `Strg + C`.
👉 Screenshot geeignet: Konsole n8n erfolgreich gestartet und wartet auf Anfragen
### PM2 einrichten
Mit PM2 starten wir n8n als Hintergrundprozess:
```bash
pm2 start n8n
```
Damit n8n automatisch beim Systemstart geladen wird, registriere den PM2-Startdienst:
```bash
pm2 startup
sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u n8nuser --hp /home/n8nuser
pm2 save
```
* `pm2 startup` zeigt den notwendigen Befehl für den Autostart an.
* Mit `pm2 save` speicherst du die aktuelle PM2-Prozessliste.
### Dienststatus prüfen
Überprüfe, ob n8n nun im Hintergrund läuft:
```bash
pm2 list
```
Die Ausgabe sollte den Prozess `n8n` mit dem Status **online** anzeigen.
[!NOTE]
Ab diesem Punkt läuft n8n automatisch im Hintergrund und wird bei jedem Neustart des Containers selbstständig gestartet.
## Schritt 4 n8n im Nginx Proxy Manager einbinden
Öffne den **Nginx Proxy Manager** und lege einen neuen Proxy-Host für n8n an.
1) **Anmelden** im NPM-Dashboard
👉 Screenshot geeignet: NPM Dashboard nach Login
2) Klicke auf **Add Proxy Host**
3) Trage im Reiter **Details** folgende Werte ein:
| Feld | Wert / Auswahl |
|--------------------------------|------------------------------------------|
| **Domain Names** | `n8n.deinedomain.tld` |
| **Scheme** | `http` |
| **Forward Hostname / IP** | IP-Adresse des n8n-Containers |
| **Forward Port** | `5678` |
| **Block Common Exploits** | aktivieren |
| **Websockets Support** | aktivieren |
👉 Screenshot geeignet: Formular „Add Proxy Host“ mit IP des n8n-Containers und Port 5678
4) Wechsle zu **SSL** und setze:
| Feld | Einstellung |
|-----------------------------------|----------------------------|
| **Request a new SSL Certificate** | aktivieren |
| **Force SSL** | aktivieren |
| **HTTP/2 Support** | aktivieren |
👉 Screenshot geeignet: SSL-Tab mit aktivierter Option „Force SSL“
5) Klicke **Save**, um den Proxy-Host anzulegen.
Nach wenigen Sekunden ist n8n über die gewählte Subdomain erreichbar, z. B.:
`https://n8n.deinedomain.tld`
👉 Screenshot geeignet: Browser n8n-Anmeldeseite über die Subdomain aufgerufen
[!TIP]
Falls der Zugriff auch von außen möglich sein soll, muss im Router Port 443 auf den NPM-Host weitergeleitet werden.
## Schritt 5 Vorbereitung: X-App und Credentials anlegen
In diesem Schritt richten wir die Verbindung zwischen **n8n** und **X (ehemals Twitter)** ein, damit später automatisch Beiträge gepostet werden können.
### 5.1 X-Entwicklerkonto erstellen und Free-Plan aktivieren
1) Gehe zu [https://developer.x.com/](https://developer.x.com/) und melde dich mit deinem normalen X-Account an.
2) Öffne im linken Menü **Products → X API**.
3) Scrolle zu **API Tiers & Pricing** und wähle **Free**.
4) Klicke auf **„Sign Up for Free Account“** (der Button ist etwas unscheinbar).
5) Im Formular die **Use Cases** eintragen mindestens 250 Zeichen.
Beispiel (englisch, ausreichend allgemein):
> We use the API to read and write posts programmatically in order to build community engagement and automate simple posting flows for our streams.
6) Alle Häkchen für die Bedingungen setzen und die Anmeldung abschließen.
👉 Screenshot geeignet: Developer-Portal mit ausgewähltem Free-Plan
[!NOTE]
Mit dem Free-Plan steht genau **eine App** zur Verfügung.
Dieser Plan erlaubt bis zu **500 Posts (Write) und 100 gelesene Posts (Read) pro Monat** für Streaming-Ankündigungen reicht das in der Regel völlig aus.
### 5.2 Überblick im Developer-Dashboard
Nach der Anmeldung erscheint im **Dashboard → Projects & Apps** automatisch ein erstes Projekt mit einer App.
👉 Screenshot geeignet: Dashboard mit Projekt-Kachel und Post-Limit-Anzeige
### 5.3 Keys und Tokens vorbereiten
1) Klicke in der App-Kachel auf das **Zahnrad-Symbol → Keys and Tokens**.
2) Hier später **API Key & Secret** sowie **Bearer Token** generieren diese brauchen wir gleich in n8n.
👉 Screenshot geeignet: Bereich „Keys and Tokens“ vor dem Generieren der Keys
[!WARNING]
Diese Schlüssel sind vertraulich und dürfen nicht öffentlich geteilt oder im Code abgelegt werden.
Speichere sie sicher ab.
### 5.4 n8n-Credentials anlegen
1) Öffne in **n8n** das linke Menü **Credentials → + Neu**.
2) Wähle **„X OAuth 2.0 API“** als Typ.
3) Kopiere im geöffneten Fenster die angezeigte **OAuth Redirect URL** diese wird gleich im Developer-Portal benötigt.
4) Lasse dieses Credentials-Fenster in n8n geöffnet.
👉 Screenshot geeignet: n8n neues Credentials-Fenster mit sichtbarer Redirect-URL
[!TIP]
Die Redirect-URL immer aus dem geöffneten n8n-Fenster kopieren, nicht manuell eintippen.
### 5.5 User-Authentication in X einrichten
1) Zurück im **Developer-Portal → Projects & Apps → App Details** wechseln.
2) Bei **User Authentication Settings** auf **„Set Up“** klicken.
3) **App Permissions:** „Read and Write“ auswählen.
4) **Type of App:** „Web App, Automated App or Bot“ auswählen.
5) Bei **Callback URL** die zuvor aus n8n kopierte Redirect-URL einfügen.
6) Bei **Homepage URL** die eigene Domain (z. B. `https://deinedomain.tld`) angeben.
7) **Save** klicken und die folgende Warnung bestätigen.
👉 Screenshot geeignet: Formular „User Authentication Settings“ mit ausgewählter Berechtigung „Read and Write“ und Callback-URL
[!IMPORTANT]
Falls die Berechtigung nicht auf „Read and Write“ steht, können später keine Posts veröffentlicht werden.
### 5.6 Client-Daten in n8n eintragen und Account verknüpfen
1) Nach dem Speichern erscheinen im Developer-Portal **Client ID** und **Client Secret**.
2) Zurück in das noch geöffnete Credentials-Fenster in n8n wechseln.
3) **Client ID** und **Client Secret** dort eintragen.
4) Auf **„Account verknüpfen“** klicken.
5) Es öffnet sich ein Pop-up-Fenster mit der X-Login-Seite.
6) Mit dem normalen X-Konto anmelden und die App **autorisieren**.
[!WARNING]
Falls statt „Authorize App“ das X-Dashboard erscheint, das Fenster schließen und den Schritt „Account verknüpfen“ in n8n erneut ausführen.
👉 Screenshot geeignet: Pop-up mit X-Login und „Authorize App“
Damit sind die **X-Credentials** in n8n eingerichtet und einsatzbereit.
### 5.7 Twitch-Auth-Credentials anlegen
Damit n8n die geplanten Streams abrufen kann, brauchen wir eine eigene **Twitch-Anwendung** mit User-Token (Authorization-Code-Flow).
Die benötigte **OAuth-Redirect-URL** kommt direkt aus n8n, deshalb beginnen wir dort.
#### 5.7.1 Redirect-URL aus n8n kopieren
1) n8n öffnen → links **Credentials → + Neu**.
2) **„Twitch OAuth2 API“** als Typ auswählen.
3) Im sich öffnenden Fenster die angezeigte **OAuth Redirect URL** vollständig kopieren.
4) Fenster offenlassen, da wir gleich hierher zurückkehren.
👉 Screenshot geeignet: n8n neues Twitch-Credential mit sichtbarer Redirect-URL
[!TIP]
Die Redirect-URL immer direkt aus n8n kopieren, nicht manuell eintippen sonst schlägt die Authentifizierung fehl.
#### 5.7.2 Neue Anwendung in der Twitch-Developer-Console anlegen
1) Twitch-Developer-Console öffnen: [https://dev.twitch.tv/console/apps](https://dev.twitch.tv/console/apps).
2) Mit dem Twitch-Konto anmelden, das später für die Streams genutzt wird.
3) Auf **„Register Your Application“** klicken
*(in der deutschen Oberfläche: **„Deine Anwendung registrieren“**).*
4) Einen aussagekräftigen Namen vergeben, z. B. `n8n-stream-schedule`.
5) Unter **OAuth Redirect URLs** die zuvor aus n8n kopierte URL einfügen.
6) Unter **Category** „Application Integration“ auswählen.
7) Bei **Public / Öffentlich** die Option **„Öffentlich“** aktivieren.
8) Auf **Create** klicken.
👉 Screenshot geeignet: Twitch-Developer-Console Formular „Register Your Application / Deine Anwendung registrieren“ mit eingetragener Redirect-URL und aktivierter Option „Öffentlich“
[!IMPORTANT]
Die Redirect-URL muss exakt der aus n8n entsprechen, sonst schlägt die spätere Verknüpfung fehl.
#### 5.7.3 Client-ID und Secret sichern
1) Nach dem Erstellen erscheint die Anwendung in der Übersicht.
2) Auf **Manage** klicken.
3) Die **Client ID** kopieren.
4) Über **New Secret** einen neuen **Client Secret** erzeugen und kopieren.
5) Beide Werte sicher speichern.
👉 Screenshot geeignet: Twitch-Developer-Console App-Details mit sichtbarer Client ID und Button „New Secret“
[!WARNING]
Der Client Secret ist nur einmal sichtbar. Nicht öffentlich teilen und sicher aufbewahren.
#### 5.7.4 Credential in n8n fertigstellen
1) Zurück zu n8n in das noch geöffnete Credential-Fenster wechseln.
2) Folgende Felder ausfüllen:
* **Client ID:** Wert aus der Twitch-Anwendung einfügen
* **Client Secret:** Wert aus der Twitch-Anwendung einfügen
* **Auth URL:** `https://id.twitch.tv/oauth2/authorize`
* **Access Token URL:** `https://id.twitch.tv/oauth2/token`
* **Grant Type:** `Authorization Code`
* **Scope:** `user:read:broadcast`
* **Auth URI Query Parameters:** leer lassen
* **Authentication:** `Body`
3) Auf **„Account verknüpfen“** klicken.
4) Im neuen Fenster mit dem Twitch-Konto anmelden und die Anwendung **autorisieren**.
5) Falls statt „Authorize App“ das Twitch-Dashboard erscheint, Fenster schließen und den Vorgang **„Account verknüpfen“** erneut ausführen.
👉 Screenshot geeignet: Twitch OAuth-Freigabeseite mit „Authorize App“
[!NOTE]
Der Scope `user:read:broadcast` erlaubt n8n, die geplanten Streams des angegebenen Kanals über die Helix-API abzurufen.
### 5.8 Hinweis zu Access Tokens
Mit den bisher eingerichteten **Credentials** für X und Twitch sind zwar die Schnittstellen verbunden, aber das reicht für den geplanten Workflow noch nicht aus.
Viele API-Endpunkte insbesondere bei Twitch benötigen zusätzlich einen **Access Token** (Bearer-Token) für jeden Abruf.
Zwar kann dieser Token theoretisch auch manuell über die Developer-Seiten erzeugt und in n8n eingetragen werden, doch solche Tokens laufen nach kurzer Zeit ab (bei Twitch z. B. meist nach 60 Tagen oder früher).
Ein händisches Nachtragen würde bedeuten, dass der Workflow regelmäßig ausfällt und manuell nachgepflegt werden muss.
[!IMPORTANT]
Wir werden deshalb im **Verlauf des Workflows** einen eigenen Node hinzufügen, der den Access Token automatisch anfordert und bei Bedarf erneuert.
So bleibt der Workflow stabil und benötigt keine manuelle Pflege.
### 5.9 Nextcloud-Credentials anlegen
**Zweck:**
Damit n8n automatisch auf Dateien in deiner Nextcloud zugreifen kann (z. B. für vorbereitete Posts oder temporäre Daten), benötigen wir ein eigenes App-Passwort und ein passendes Credential in n8n.
#### In Nextcloud: App-Passwort erstellen
1) Melde dich in deiner **Nextcloud** an.
2) Öffne oben rechts das **Benutzermenü → Einstellungen**.
3) Wähle im linken Menü den Punkt **Sicherheit** (engl. „Security“).
4) Scrolle nach unten bis zum Bereich **App-Passwörter**.
5) Vergib unter „Neues App-Passwort“ einen Namen, z. B. `n8n`.
6) Klicke auf **App-Passwort erstellen**.
7) Kopiere den angezeigten Schlüssel sofort er wird nur einmal angezeigt.
👉 Screenshot geeignet: Nextcloud Bereich *Sicherheit / App-Passwörter*
[!IMPORTANT]
Nur dieses **App-Passwort** wird in n8n verwendet, **nicht** dein normales Login-Passwort.
Das App-Passwort kann bei Bedarf jederzeit widerrufen oder neu erstellt werden.
#### In n8n: Credential hinzufügen
1) Öffne in n8n oben links **+ → Credentials → Nextcloud**.
2) Trage folgende Werte ein:
| Feld | Wert / Beschreibung |
|------|---------------------|
| **Name** | `Nextcloud` |
| **Base URL** | `https://deine-domain.tld` *(ohne `/remote.php/...`)* |
| **Username** | dein Nextcloud-Benutzername |
| **Password** | das zuvor erstellte App-Passwort |
3) Klicke auf **Save**.
👉 Screenshot geeignet: n8n Nextcloud-Credential mit Base URL und App-Passwort
[!NOTE]
Das Credential „Nextcloud“ wird später in Schritt **6.13** verwendet, um Dateien wie `posts.txt` automatisiert aus der Cloud zu laden und lokal zu verarbeiten.
## Schritt 6 Workflow in n8n aufbauen
In diesem Schritt erstellen wir den eigentlichen Workflow in **n8n**.
Wir fügen die benötigten Nodes hinzu und konfigurieren sie so, dass der Workflow regelmäßig die geplanten Twitch-Streams prüft und bei Bedarf automatisch Ankündigungen auf X erstellt.
### 6.1 Cron Trigger (Workflow alle 30 Minuten starten)
**Zweck:**
Der Cron-Trigger ist der Startpunkt des Workflows.
Er sorgt dafür, dass alle 30 Minuten geprüft wird, ob ein geplanter Stream in Kürze startet.
**Node-Typ:** `Schedule Trigger`
**Name:** `Cron Workflow alle 30 Minuten starten`
**Einstellungen im Node:**
- **Trigger Interval:** `Minutes`
- **Minutes Between Triggers:** `30`
👉 Screenshot geeignet: n8n Schedule Trigger mit „Trigger Interval: Minutes“ und Wert „30“
[!NOTE]
Die Zeitzone wird nicht im Node eingestellt.
Sie richtet sich nach der **Workflow-Zeitzone** (oben rechts im Workflow → *Settings → Time Zone*).
Ist dort nichts gesetzt, gilt die Zeitzone des Servers, auf dem n8n läuft.
[!TIP]
Die Intervalldauer (hier 30 Minuten) kann bei Bedarf angepasst werden. Für Ankündigungen kurz vor dem Stream reicht ein Intervall von 30 Minuten in der Regel aus.
### 6.2 Code Node: Access Token prüfen
**Zweck:**
Dieser Node prüft bei jedem Durchlauf, ob bereits ein gültiger Twitch-Access-Token vorhanden ist und wie lange er noch gültig ist.
Wenn kein Token existiert oder die Restlaufzeit unter 24 Stunden liegt, markieren wir das für die nächste Stufe (Token erneuern).
**Node-Typ:** `Code`
**Programmiersprache:** `JavaScript`
**Name:** `Code Access Token prüfen`
**Einstellungen:**
- **Language:** `JavaScript`
- Den folgenden Code einfügen:
```javascript
// Liest gespeicherten Token aus den globalen Workflow-Daten
const sd = $getWorkflowStaticData('global');
const token = sd.twitch_token || '';
const expISO = sd.twitch_expires_at || '';
const expMs = expISO ? new Date(expISO).getTime() : 0;
const now = Date.now();
const msLeft = expMs ? (expMs - now) : 0;
const hoursLeft = msLeft > 0 ? (msLeft / (1000*60*60)) : 0;
// true, wenn kein Token vorhanden ist oder wenn er in <24h abläuft
const needsRefresh = !token || !expMs || hoursLeft < 24;
return [{
json: {
needsRefresh,
token,
expires_at: expISO,
hoursLeft: Number(hoursLeft.toFixed(2))
}
}];
```
👉 Screenshot geeignet: n8n Code-Node mit eingefügtem JavaScript-Code
[!NOTE]
Dieser Node speichert nichts, sondern liefert nur Statusdaten (`needsRefresh`, `hoursLeft`, `expires_at`).
Die tatsächliche Erneuerung des Tokens erfolgt später im Workflow.
### 6.3 IF Node: Access Token erneuern?
**Zweck:**
Dieser Node prüft, ob aus dem vorherigen Code-Node das Flag `needsRefresh` auf **true** steht.
Nur in diesem Fall wird im nächsten Schritt ein neuer Access-Token angefordert.
**Node-Typ:** `IF`
**Name:** `IF Access Token erneuern?`
**Einstellungen:**
- **Conditions:**
- `{{$json.needsRefresh}}`
- `is true` *(Type: Boolean)*
👉 Screenshot geeignet: n8n IF-Node mit Bedingung `{{$json.needsRefresh}}``is true (Boolean)`
[!IMPORTANT]
Stelle sicher, dass der Vergleichs-Typ auf **Boolean** gesetzt ist, sonst wird der Wert eventuell als Text interpretiert und die Abfrage funktioniert nicht korrekt.
[!NOTE]
- **TRUE-Pfad:** Token wird im nächsten Schritt erneuert.
- **FALSE-Pfad:** Es wird mit dem bestehenden Token fortgefahren.
### 6.4 HTTP Request: Neuen Twitch-Access-Token anfordern *(TRUE-Pfad)*
**Zweck:**
Fordert über die Twitch-API einen neuen Access-Token an, wenn der IF-Node festgestellt hat, dass keiner vorhanden ist oder der aktuelle bald abläuft.
**Node-Typ:** `HTTP Request`
**Name:** `HTTP Access Token anfordern`
**Einstellungen:**
- **Method:** `POST`
- **URL:** `https://id.twitch.tv/oauth2/token`
- **Send Body:** aktivieren
- **Content Type:** `Form-URL-Encoded`
- **Body Parameters:**
- `client_id` → Wert aus den in n8n hinterlegten Twitch-Credentials
- `client_secret` → Wert aus den Twitch-Credentials
- `grant_type``client_credentials`
👉 Screenshot geeignet: n8n HTTP-Request-Node mit konfigurierten Body-Parametern
[!NOTE]
Der Node gibt als Antwort ein JSON-Objekt mit `access_token` und `expires_in` zurück.
Diese Werte werden im nächsten Node gespeichert.
### 6.5 Code Node: Neuen Access-Token speichern *(TRUE-Pfad)*
**Zweck:**
Speichert den vom HTTP-Request erhaltenen Twitch-Access-Token und dessen Ablaufzeitpunkt in den globalen Workflow-Daten.
So bleibt der Token auch für spätere Workflow-Durchläufe verfügbar.
**Node-Typ:** `Code`
**Programmiersprache:** `JavaScript`
**Name:** `Code Access Token speichern`
**Einstellungen:**
- **Language:** `JavaScript`
- Den folgenden Code einfügen:
```javascript
// Speichert neuen Token + Ablaufzeit in Workflow-Static-Data
const sd = $getWorkflowStaticData('global');
const access = $json.access_token;
const ttlSec = Number($json.expires_in || 0);
// Ablaufzeitpunkt berechnen und speichern
const expISO = new Date(Date.now() + ttlSec * 1000).toISOString();
sd.twitch_token = access;
sd.twitch_expires_at = expISO;
// Optional: verbleibende Stunden ausgeben
const msLeft = (new Date(expISO).getTime() - Date.now());
const hoursLeft = msLeft / (1000 * 60 * 60);
return [{
json: {
token: access,
expires_at: expISO,
hoursLeft: Number(hoursLeft.toFixed(2))
}
}];
```
👉 Screenshot geeignet: n8n Code-Node mit eingefügtem JavaScript-Code
[!NOTE]
Dieser Node speichert den neuen Token und gibt ihn zusätzlich mit seiner Restlaufzeit (`hoursLeft`) aus, sodass nachfolgende Nodes die Werte sofort verwenden können.
### 6.6 Set Node: Token aus Cache bereitstellen *(FALSE-Pfad)*
**Zweck:**
Wenn der IF-Node feststellt, dass der vorhandene Token noch gültig ist, brauchen wir keinen neuen anzufordern.
Dieser Node liest die bereits gespeicherten Token-Daten aus den globalen Workflow-Daten und stellt sie den nachfolgenden Nodes zur Verfügung.
**Node-Typ:** `Set`
**Name:** `Set Token aus Cache bereitstellen`
**Einstellungen:**
- **Mode:** `Add Field`
- **Felder hinzufügen:**
- `token``{{$json.token}}`
- `expires_at``{{$json.expires_at}}`
- `hoursLeft``{{$json.hoursLeft}}`
👉 Screenshot geeignet: n8n Set-Node mit eingetragenen drei Feldern (token, expires_at, hoursLeft)
[!NOTE]
Der Set-Node wird nur im **FALSE-Pfad** des IF-Nodes ausgeführt.
Er sorgt dafür, dass auch ohne Erneuerung dieselben Felder (`token`, `expires_at`, `hoursLeft`) für die nächsten Schritte bereitstehen.
### 6.7 Merge Node: Token-Ströme zusammenführen
**Zweck:**
Führt die beiden möglichen Pfade aus dem IF-Node wieder zusammen:
- TRUE-Pfad: liefert den **neu angeforderten Token** aus dem Code-Node „Access Token speichern“.
- FALSE-Pfad: liefert den **bereits vorhandenen Token** aus dem Set-Node „Token aus Cache bereitstellen“.
So steht dem Workflow anschließend unabhängig vom Pfad derselbe Datensatz für die weiteren Schritte zur Verfügung.
**Node-Typ:** `Merge`
**Name:** `Merge Token zusammenführen`
**Einstellungen:**
- **Mode:** `Append`
- **Number of Inputs:** `2`
👉 Screenshot geeignet: n8n Merge-Node mit „Mode: Append“ und „Number of Inputs: 2“
[!NOTE]
Da jeweils nur einer der beiden Pfade aktiv ist, genügt der Append-Modus, um den ausgegebenen Datensatz an den Hauptfluss zurückzugeben.
### 6.8 HTTP Request: Twitch-Termine laden
**Zweck:**
Dieser Node ruft über die Twitch-Helix-API den aktuellen Stream-Zeitplan des Kanals ab, um zu prüfen, ob innerhalb der nächsten 30 Minuten ein Stream startet.
**Node-Typ:** `HTTP Request`
**Name:** `HTTP Twitch-Termine laden`
#### Twitch-User-ID ermitteln (ohne Programmierung)
Die `broadcaster_id` ist eine **numerische ID**, die jedem Twitch-Kanal zugeordnet ist.
Du brauchst diese Zahl (nicht den Kanalnamen), um die API-Abfrage auszuführen.
**So findest du sie leicht:**
1) Öffne im Browser die Seite
[https://streamscharts.com/tools/convert-username](https://streamscharts.com/tools/convert-username)
2) Gib deinen Twitch-Kanalnamen ein (z. B. `bratonien_tv`).
3) Klicke auf **Convert**.
4) Die angezeigte Zahl unter „Channel ID“ ist deine `broadcaster_id`.
5) Kopiere diese Zahl und trage sie später im HTTP-Request-Node in das Feld **broadcaster_id** ein.
👉 Screenshot geeignet: StreamsCharts-Tool mit eingegebenem Kanalnamen und angezeigter Channel-ID
[!TIP]
Dieses Tool verwendet offiziell die Twitch-API, du brauchst dort keine eigenen Entwickler-Anmeldungen.
#### Einstellungen im Node
- **Method:** `GET`
- **URL:** `https://api.twitch.tv/helix/schedule`
- **Send Query:** aktivieren
- **Query Parameters:**
- `broadcaster_id``<Twitch-User-ID>` des Kanals
- `start_time``{{$now.toUTC().startOf('day').toISO()}}`
- **Send Headers:** aktivieren
- **Header Parameters:**
- `Authorization``Bearer {{$json.token}}`
- `Client-ID``<deine Client-ID aus Twitch-Credentials>`
👉 Screenshot geeignet: n8n HTTP-Request-Node mit eingetragenen Query- und Header-Parametern
[!NOTE]
Die `broadcaster_id` ist die eindeutige numerische ID des Kanals.
Der Header **Authorization** enthält den Access-Token aus dem Merge-Node.
Der Header **Client-ID** ist zwingend erforderlich, sonst verweigert die Helix-API den Zugriff.
### 6.8 HTTP Request: Twitch-Termine laden
**Zweck:**
Dieser Node ruft über die Twitch-Helix-API den aktuellen Stream-Zeitplan des Kanals ab, um zu prüfen, ob innerhalb der nächsten 30 Minuten ein Stream startet.
**Node-Typ:** `HTTP Request`
**Name:** `HTTP Twitch-Termine laden`
#### Twitch-User-ID ermitteln (ohne Programmierung)
Die `broadcaster_id` ist eine **numerische ID**, die jedem Twitch-Kanal zugeordnet ist.
Du brauchst diese Zahl (nicht den Kanalnamen), um die API-Abfrage auszuführen.
**So findest du sie leicht:**
1) Öffne im Browser die Seite
[https://streamscharts.com/tools/convert-username](https://streamscharts.com/tools/convert-username)
2) Gib deinen Twitch-Kanalnamen ein (z. B. `bratonien_tv`).
3) Klicke auf **Convert**.
4) Die angezeigte Zahl unter „Channel ID“ ist deine `broadcaster_id`.
5) Kopiere diese Zahl und trage sie später im HTTP-Request-Node in das Feld **broadcaster_id** ein.
👉 Screenshot geeignet: StreamsCharts-Tool mit eingegebenem Kanalnamen und angezeigter Channel-ID
[!TIP]
Dieses Tool verwendet offiziell die Twitch-API und erfordert keine eigenen Entwickler-Anmeldungen.
#### Einstellungen im Node
- **Method:** `GET`
- **URL:** `https://api.twitch.tv/helix/schedule`
- **Authentication:** `Generic Credential Type`
- **Generic Auth Type:** `OAuth2 API` → wähle hier die zuvor in n8n angelegten **Twitch-Credentials** aus
- **Send Query Parameters:** aktivieren
- **Query Parameters:**
- **Name:** `broadcaster_id``<deine Twitch-User-ID>`
- **Name:** `start_time``{{ $now.toUTC().startOf('day').toISO() }}`
- **Send Headers:** aktivieren
- **Header Parameters:**
- **Name:** `Client-ID``<deine Client-ID aus den Twitch-Credentials>`
👉 Screenshot geeignet: n8n HTTP-Request-Node mit allen sichtbaren Parametern wie auf den beiden Referenz-Screenshots
[!NOTE]
Der Access-Token wird über die ausgewählte OAuth2-Credential automatisch mitgesendet.
Zusätzlich ist nur der **Client-ID**-Header notwendig.
Die Option **Never Error** bleibt deaktiviert, da sie hier nicht benötigt wird.
### 6.9 Code-Node: „Parse ICS“
**Zweck:**
Dieser Node verarbeitet die Antwort des Nodes **„Twitch-Termine laden“**.
Er liest das JSON aus der Helix-API und erzeugt für jedes Stream-Segment ein einheitliches Objekt mit Start- und Endzeit, Titel, Beschreibung und einer Hash-ID.
So können wir die Termine später leichter filtern und weiterverarbeiten.
**Node-Typ:** `Code`
**Name:** `Parse ICS`
👉 Screenshot geeignet: n8n geöffneter Code-Node mit eingefügtem Skript
#### Node-Einstellungen
- **Programming Language:** `JavaScript`
- Weitere Einstellungen bleiben auf Standard.
#### Eingabe
Der Node erwartet die Antwort des HTTP-Requests **„Twitch-Termine laden“**.
Der Inhalt liegt meist als Text-String in `items[0].json.body` vor.
#### Code-Inhalt
Kopiere den folgenden Code komplett in das Editorfeld des Code-Nodes:
```
/**
* INPUT: items[0].json ODER items[0].json.body (String) vom HTTP Request /helix/schedule
* OUTPUT: pro Segment ein Item in folgendem Schema:
* { uid, cancelled, title, description, startIso, endIso, tz, hash }
*/
const input = items[0]?.json ?? {};
let payload;
if (typeof input.body === 'string') {
// HTTP-Node hat "Response Format: Text" -> JSON-String in body
try { payload = JSON.parse(input.body); }
catch (e) { throw new Error('HTTP body ist kein gültiges JSON'); }
} else if (input.data) {
// HTTP-Node hat "Response Format: JSON"
payload = input;
} else if (typeof input === 'string') {
payload = JSON.parse(input);
} else {
throw new Error('Unerwartete Eingabeform. Erwartet JSON oder body-String.');
}
const segments = Array.isArray(payload.data?.segments) ? payload.data.segments : [];
// Hash für eindeutige Segmentkennung
function hashHex(s) {
let h = 5381;
for (let i = 0; i < s.length; i++) h = ((h << 5) + h) ^ s.charCodeAt(i);
return (h >>> 0).toString(16).padStart(8, '0');
}
function buildTitle() { return 'Streamtime'; }
function buildDesc(seg) {
const lines = [];
if (seg.title) lines.push(`Originaltitel: ${seg.title}`);
if (seg.category?.name) lines.push(`Kategorie/Game: ${seg.category.name}`);
return lines.join('\n');
}
const tz = 'Europe/Berlin';
const out = segments.map(seg => {
const startIso = seg.start_time; // ISO-UTC laut Twitch
const endIso = seg.end_time;
const title = buildTitle();
const description = buildDesc(seg);
const hash = hashHex(`${title}|${startIso}|${endIso}|${description}`);
return {
json: {
uid: seg.id,
cancelled: Boolean(seg.canceled_until),
title, description,
startIso, endIso, tz,
hash
}
};
});
return out;
```
[!NOTE]
- `tz` ist fest auf `Europe/Berlin` gesetzt, kann aber bei Bedarf angepasst werden.
- Das Feld `cancelled` wird genutzt, um abgesagte Streams zu kennzeichnen.
- Jeder Stream-Eintrag erhält einen Hash, der später als eindeutiger Schlüssel dient.
### 6.10 Code-Node: „Nächstes Event finden“
**Zweck:**
Dieser Node wählt aus allen vom **„Parse ICS“**-Node gelieferten Terminen den **nächsten bevorstehenden Stream** aus.
Er liefert das Start-Datum und die relevanten Infos des nächsten Events als einzelnes Item.
**Node-Typ:** `Code`
**Name:** `Nächstes Event finden`
👉 Screenshot geeignet: n8n geöffneter Code-Node mit dem folgenden Script
#### Node-Einstellungen
- **Programming Language:** `JavaScript`
- Alle weiteren Optionen bleiben auf Standard.
#### Eingabe
Dieser Node erwartet als Input die komplette Liste der Stream-Segmente aus dem Node **„Parse ICS“**.
#### Code-Inhalt
Kopiere den folgenden Code vollständig in das Code-Feld:
```
/**
* INPUT: Array von Items aus "Parse ICS"
* OUTPUT: nur das nächste bevorstehende Event
*/
const now = Date.now();
const upcoming = items
.map(i => i.json)
.filter(e => !e.cancelled && new Date(e.startIso).getTime() > now)
.sort((a, b) => new Date(a.startIso) - new Date(b.startIso));
if (upcoming.length === 0) {
return [{ json: { message: 'Kein bevorstehender Stream gefunden' } }];
}
const next = upcoming[0];
return [{
json: {
uid: next.uid,
title: next.title,
kategroie: next.kategorie,
description: next.description,
startIso: next.startIso,
endIso: next.endIso,
tz: next.tz,
hash: next.hash
}
}];
```
[!TIP]
Dieser Node gibt **genau ein Item** mit dem nächsten Stream zurück.
Fehlt ein Termin, wird eine kurze Meldung im Feld `message` ausgegeben.
### 6.11 Code-Node: „Stream prüfen“
**Zweck:**
Dieser Node überprüft, ob der nächste geplante Stream in den kommenden **30 Minuten** beginnt und ob für diesen Stream bereits ein Post veröffentlicht wurde.
Nur wenn beide Bedingungen erfüllt sind, wird der Workflow fortgesetzt.
**Node-Typ:** `Code`
**Name:** `Stream prüfen`
👉 Screenshot geeignet: n8n geöffneter Code-Node mit folgendem Script
#### Node-Einstellungen
- **Programmiersprache:** `JavaScript`
- Keine weiteren Optionen ändern
#### Eingabe
Der Node erhält den Output aus **„Nächstes Event finden“** also einen einzelnen Stream-Eintrag mit `uid`, `title`, `startIso` und weiteren Feldern.
#### Code-Inhalt
Kopiere den folgenden Code:
```
/**
* Prüft:
* 1. Startet der Stream in ≤ 30 Minuten?
* 2. Wurde bereits ein Post erstellt?
*
* Zeitumwandlung: Twitch liefert UTC ("2025-10-15T16:00:00Z").
* Wir rechnen in lokale Zeit (Europe/Berlin), um MEZ/MESZ korrekt zu berücksichtigen.
*/
const event = items[0]?.json ?? {};
if (!event.startIso) {
return [{
json: {
postAllowed: false,
reason: 'Kein Termin gefunden'
}
}];
}
// Aktuelle Zeit + Startzeit in lokale Zeitzone überführen
const tz = 'Europe/Berlin';
const now = new Date(); // lokale Zeit des n8n-Servers
const startUtc = new Date(event.startIso);
// Startzeit in lokales Format (inkl. Sommer-/Winterzeit)
const startLocal = new Date(startUtc.toLocaleString('en-US', { timeZone: tz }));
// Differenz in Minuten
const diffMin = (startLocal - now) / 60000;
const within30 = diffMin > 0 && diffMin <= 30;
// Zugriff auf global gespeicherte IDs
const sd = $getWorkflowStaticData('global');
sd.postedIds = sd.postedIds || [];
const alreadyPosted = sd.postedIds.includes(event.uid);
// Wenn innerhalb von 30 Minuten und noch kein Post → erlauben
if (within30 && !alreadyPosted) {
sd.postedIds.push(event.uid);
return [{
json: {
...event,
postAllowed: true,
reason: 'Stream startet bald, noch kein Post vorhanden',
localStart: startLocal.toISOString(),
diffMinutes: Math.round(diffMin)
}
}];
}
// Keine Aktion notwendig
return [{
json: {
...event,
postAllowed: false,
reason: alreadyPosted
? 'Für diesen Stream wurde bereits gepostet'
: 'Stream liegt außerhalb des 30-Minuten-Fensters',
localStart: startLocal.toISOString(),
diffMinutes: Math.round(diffMin)
}
}];
```
[!NOTE]
Dieser Node speichert die **UID jedes angekündigten Streams** im Workflow-Speicher (`global static data`).
So wird sichergestellt, dass kein Termin doppelt angekündigt wird auch nicht nach einem Neustart des Systems.
Der Zeitvergleich erfolgt in **MEZ/MESZ (Europe/Berlin)**, damit lokale Streamzeiten korrekt erkannt werden.
### 6.12 IF-Node: „Post ausführen?“
**Zweck:**
Der IF-Node entscheidet, ob tatsächlich ein Social-Post (z. B. auf X) ausgelöst werden soll.
Er prüft das Feld `postAllowed`, das aus dem vorherigen Code-Node stammt.
**Node-Typ:** `IF`
**Name:** `Post ausführen?`
👉 Screenshot geeignet: n8n geöffneter IF-Node mit konfigurierter Bedingung
#### Node-Einstellungen
**Conditions**
| Feld | Einstellung |
|------|--------------|
| **Left Value** | `{{$json.postAllowed}}` |
| **Operator** | `is true` |
| **Type** | `Boolean` |
[!NOTE]
- Der *True*-Pfad wird nur ausgeführt, wenn der Stream innerhalb der nächsten 30 Minuten startet **und** noch kein Post gesendet wurde.
- Der *False*-Pfad kann später genutzt werden, um Debug-Logs oder Benachrichtigungen zu schreiben (z. B. „Kein Post nötig“).
👉 Screenshot geeignet: n8n IF-Node mit `{{$json.postAllowed}} is true (Boolean)`
### 6.13 Nextcloud-Node: Datei herunterladen
**Zweck:**
Dieser Node lädt die Datei `posts.txt` aus deiner Nextcloud in n8n, damit sie anschließend lokal verarbeitet werden kann.
**Node-Typ:** `Nextcloud`
**Name:** `posts.txt herunterladen`
👉 Screenshot geeignet: n8n Nextcloud-Node mit ausgefüllten Feldern
#### Einstellungen
| Feld | Eingabe |
|------|----------|
| **Credential to connect with** | `Nextcloud` *(aus Schritt 5.9)* |
| **Resource** | `File` |
| **Operation** | `Download` |
| **File Path** | `/n8n/posts.txt` *(Pfad in deiner Nextcloud anpassen)* |
| **Put Output File in Field** | `data` |
[!NOTE]
Die Datei `posts.txt` sollte in deiner Nextcloud vorhanden sein und **eine Textzeile pro Post** enthalten, z. B.:
```
Gleich gehts los der Stream startet in Kürze!
Heute wieder live seid dabei!
Stream incoming! Noch ein paar Minuten bis Start.
```
👉 Screenshot geeignet: Beispielansicht der Datei `posts.txt` in Nextcloud
Nach der Ausführung enthält der Node die Datei als **binäre Ausgabe** im Feld `data`.
Diese wird im nächsten Schritt lokal gespeichert, damit sie gelesen werden kann.
### 6.14 Code-Node: Zufälligen Post auswählen
**Zweck:**
Dieser Node liest die Datei `posts.txt` (aus dem Binary-Feld des Nextcloud-Nodes) und wählt zufällig eine Zeile als Posting-Text.
Wenn die Datei fehlt oder leer ist, nutzt der Workflow eine kleine Standardliste mit vorbereiteten Posts als Fallback.
**Node-Typ:** `Code`
**Name:** `Posttext auswählen`
👉 Screenshot geeignet: n8n geöffneter Code-Node mit Script
#### Code-Inhalt
```
/**
* Liest posts.txt direkt aus dem Binary-Feld "data" (vom Nextcloud-Node)
* und wählt zufällig eine Zeile aus.
* Wenn keine Datei oder kein Inhalt vorhanden ist, wird ein Fallback-Text aus einer Liste genutzt.
* Zusätzlich wird der Startzeitpunkt des Streams in lokaler Zeit (MEZ/MESZ) angehängt.
*/
let content = '';
try {
const buffer = items[0].binary?.data?.data;
if (buffer) {
content = Buffer.from(buffer, 'base64').toString('utf8');
}
} catch (err) {
content = '';
}
// Inhalt in Zeilen aufteilen
const lines = content.split('\n').map(l => l.trim()).filter(Boolean);
// Fallback-Texte
const fallbackPosts = [
'Der Stream startet gleich holt euch Snacks und seid dabei! 🎮',
'Bald gehts los heute wird wieder gezockt! 🔥',
'Noch kurz durchatmen gleich gehts live auf Sendung! 🚀',
'In wenigen Minuten live Kaffee bereit? ☕',
'Los gehts der Chat wartet schon auf euch! 💬',
'Heute gibts wieder gute Laune und Gaming pur! 💜'
];
// Textauswahl
let postText;
if (lines.length > 0) {
const randomIndex = Math.floor(Math.random() * lines.length);
postText = lines[randomIndex];
} else {
const randomIndex = Math.floor(Math.random() * fallbackPosts.length);
postText = fallbackPosts[randomIndex];
}
// Startzeitpunkt des Streams aus vorherigem Node lesen (startIso)
let startIso = items[0].json?.startIso || null;
let startLocal = '';
if (startIso) {
try {
const date = new Date(startIso);
const formatter = new Intl.DateTimeFormat('de-DE', {
weekday: 'short',
hour: '2-digit',
minute: '2-digit',
timeZone: 'Europe/Berlin',
hour12: false
});
startLocal = formatter.format(date);
} catch (err) {
startLocal = '';
}
}
if (startLocal) {
postText = `${postText} 🎬 Start: ${startLocal}`;
}
// Weitergabe an nächste Nodes
return [{
json: {
...items[0].json,
postText
}
}];
```
👉 Screenshot geeignet: Node-Ausgabe mit Feld `postText` und zufälligem Text
[!NOTE]
Wenn die Datei `posts.txt` fehlt oder leer ist, sorgt die integrierte Fallback-Liste dafür, dass trotzdem ein sinnvoller Post generiert wird.
Damit ist der Workflow robust und funktioniert zuverlässig auch ohne manuelle Pflege der Datei.
### 6.15 X-Post veröffentlichen
**Zweck:**
Dieser Node sendet den zuvor generierten Text (`postText`) automatisch als Tweet über das verknüpfte X-Konto.
**Node-Typ:** `X`
**Name:** `X Post veröffentlichen`
👉 Screenshot geeignet: n8n X-Node mit ausgefülltem Formular für Tweet-Erstellung
#### Einstellungen
| Feld | Eingabe |
|------|----------|
| **Credential to connect with** | `X account` *(aus Schritt 5.8)* |
| **Resource** | `Tweet` |
| **Operation** | `Create` |
| **Text** | `{{ $json.postText }}` |
Beispielausgabe:
```
Stream incoming! Noch ein paar Minuten bis Start 🎬 Start: Mi., 18:00
```
👉 Screenshot geeignet: n8n Erfolgreicher Tweet-Node mit grünem Ausgabestatus
[!NOTE]
Dieser Node nutzt direkt die X-Integration von n8n und benötigt keine manuelle API-Konfiguration.
Im **Free-Plan** sind bis zu **17 Posts pro 24 Stunden** erlaubt.
[!TIP]
Wenn der Node mit `401 Unauthorized` fehlschlägt:
- Öffne die X-Credentials in n8n und **verbinde den Account erneut**,
- prüfe, ob die App im X Developer Dashboard **„Read and Write“** aktiviert hat.
Danach sollte der Node wieder erfolgreich posten.
### 6.16 Lokale Datei löschen (Workflow-Speicher bereinigen)
**Zweck:**
Dieser Node entfernt die lokal zwischengespeicherte Datei `posts.txt` aus dem Workflow-Speicher.
Damit wird verhindert, dass beim nächsten Lauf alte Daten erneut verwendet werden.
**Node-Typ:** `Code`
**Name:** `Temporäre Datei entfernen`
👉 Screenshot geeignet: n8n Code Node mit Löschskript
#### Einstellungen
**Code:**
```
return items.map(item => {
if (item.binary && item.binary.data) {
delete item.binary.data; // Entfernt die heruntergeladene Datei aus dem Speicher
}
return item;
});
```
[!NOTE]
- Dieser Node löscht **nicht die Datei auf der Festplatte oder in Nextcloud**,
sondern nur die temporäre Kopie, die n8n im Speicher hält.
- Beim nächsten Workflow-Lauf wird die Datei automatisch neu aus Nextcloud geladen.
- Diese Methode funktioniert stabil in jeder n8n-Version, ohne zusätzliche Module.
### 6.17 Gesamter Workflow als JSON-Import
Zum Abschluss stellen wir den gesamten Workflow als **importierbare JSON-Datei** bereit.
Diese Datei enthält alle Nodes, Verbindungen und Einstellungen fertig vorbereitet für den direkten Import in n8n.
👉 Screenshot geeignet: n8n Menüpunkt „Import from File“
1) Öffne n8n im Browser.
2) Klicke oben rechts auf das **Drei-Punkte-Menü****Import from File**.
3) Wähle die bereitgestellte JSON-Datei (`stream_schedule_workflow.json`) aus.
4) Nach dem Import prüfe, ob alle **Credentials** korrekt zugewiesen sind:
- Twitch
- X (Twitter)
- Nextcloud
[!TIP]
Sollten Credentials fehlen oder fehlerhaft sein, öffne den jeweiligen Node, wähle in der Liste das passende Credential neu aus und speichere den Node anschließend.
Nach erfolgreichem Import ist der Workflow sofort einsatzbereit und kann manuell gestartet oder automatisch durch den Cron-Trigger ausgelöst werden.
---
## Troubleshooting & Tipps
Auch ein gut eingerichteter Workflow kann gelegentlich aus dem Takt geraten.
Vielleicht erscheint kein Beitrag, vielleicht bleibt eine Verbindung hängen das ist normal.
n8n arbeitet mit mehreren Diensten gleichzeitig, und schon kleine Änderungen bei Twitch, X oder Nextcloud können eine neue Anmeldung nötig machen.
Mit etwas Geduld lässt sich das schnell wieder beheben.
### Verbindungen prüfen und aktualisieren
n8n speichert die Zugänge zu deinen Diensten unter **Credentials**.
Diese Zugänge sind wie kleine Schlüssel, mit denen der Workflow auf Twitch, X und Nextcloud zugreifen darf.
Wenn du dich bei einem dieser Dienste neu anmeldest, das Passwort änderst oder der Zugang zu lange ungenutzt bleibt, verliert n8n die Berechtigung.
Das erkennst du daran, dass der Workflow plötzlich keine Daten mehr abruft oder beim Start eine Fehlermeldung anzeigt.
So stellst du die Verbindung wieder her:
1. Öffne in n8n die linke Seitenleiste und wähle **Credentials**.
2. Dort erscheinen alle gespeicherten Zugänge.
Schaue dir besonders **Twitch**, **X** und **Nextcloud** an.
3. Ist ein Eintrag rot markiert oder als *disconnected* gekennzeichnet, öffne ihn.
4. Klicke auf **Reconnect**. Es öffnet sich das gewohnte Anmeldefenster des Dienstes.
5. Melde dich mit deinem Konto an und bestätige die Freigabe für n8n.
6. Danach auf **Save** klicken.
Nach der Bestätigung prüft n8n automatisch, ob alles wieder funktioniert.
Du musst nichts neu anlegen der Workflow arbeitet beim nächsten Lauf wie gewohnt weiter.
### Wenn kein Beitrag erscheint
Dass kein Post veröffentlicht wird, ist nicht immer ein Fehler.
Der Workflow reagiert nur, wenn im Twitch-Zeitplan ein Stream bevorsteht.
Ist aktuell keiner geplant, passiert auch nichts so soll es sein.
Wenn aber ein Stream eingetragen ist und trotzdem kein Post kommt, gehe folgendermaßen vor:
1. Öffne den Workflow in n8n.
Oben rechts sollte der Statuspunkt **grün** sein.
Wenn er grau ist, klicke auf **Activate**, damit der automatische Start wieder aktiv ist.
2. Schaue unten links in den Bereich **Executions**.
Wird dort ein rotes Symbol oder der Hinweis „Unauthorized“ angezeigt, ist eine Verbindung abgelaufen.
In diesem Fall einmal die Credentials prüfen und gegebenenfalls neu verbinden (siehe oben).
3. Starte den Workflow testweise manuell über **Execute Workflow**.
Wenn danach ein Post ausgelöst wird, war die Verbindung die Ursache.
Nach dieser Kontrolle läuft der Ablauf in der Regel wieder zuverlässig.
### Posts-Datei kontrollieren
Die Textvorschläge für deine Beiträge stammen aus der Datei **posts.txt** in deiner Nextcloud.
Wenn n8n keine Beiträge mehr findet oder immer denselben Text verwendet, liegt das meist an dieser Datei.
Prüfe Folgendes:
- **Ort:** Die Datei muss im Ordner liegen, der im Workflow beim Download-Node angegeben wurde.
- **Inhalt:** Jede Zeile steht für einen Textvorschlag.
Beispiel:
```
Gleich gehts los wir sind live!
Heute wieder mit neuen Highlights im Stream!
Noch 15 Minuten, dann gehts los!
```
- **Name:** Der Dateiname muss exakt `posts.txt` lauten.
- **Fehlerfall:** Ist die Datei leer oder fehlt, nutzt n8n automatisch eigene Standardtexte, damit der Ablauf nicht unterbrochen wird.
Wenn du neue Posts ergänzen möchtest, öffne die Datei direkt in Nextcloud, schreibe die Texte hinein und speichere sie.
n8n lädt beim nächsten Lauf automatisch die aktualisierte Version.
### Wenn der Workflow hängt
Manchmal reagiert n8n träge, zum Beispiel nach einem Update oder wenn der Container längere Zeit pausiert war.
Dann hilft ein kurzer Neustart:
1. Öffne den Workflow.
2. Klicke oben auf **Stop**.
3. Danach auf **Start**.
Dadurch wird nur der Ablauf neu geladen alle Einstellungen und Verbindungen bleiben erhalten.
Beim nächsten geplanten Zeitpunkt arbeitet der Cron-Trigger wieder normal.
[!TIP]
Wenn du nachvollziehen möchtest, was beim letzten Durchlauf passiert ist, öffne unten links **Executions** und wähle den neuesten Eintrag.
n8n zeigt dort Schritt für Schritt, welche Aktionen erfolgreich waren und wo ein Fehler aufgetreten ist.
So findest du die Ursache gezielt, ohne den Workflow neu einrichten zu müssen.
---
## Abschluss
Mit dem hier eingerichteten Workflow ist dein System erstmals in der Lage, eigenständig auf zukünftige Streams zu reagieren.
Sobald auf Twitch ein neuer Termin im Zeitplan auftaucht, prüft n8n automatisch, ob dieser in Kürze startet, und erstellt einen vorbereiteten Beitrag.
Damit hast du den ersten Baustein für automatisierte Kommunikation gelegt einfach, nachvollziehbar und ohne externe Dienste.
Der Ablauf läuft vollständig im eigenen Container und arbeitet stabil, solange die Verbindungen zu Twitch, X und Nextcloud aktiv bleiben.
Neue Ideen oder kleine Änderungen lassen sich jederzeit direkt in n8n testen, ohne etwas am Grundsystem zu verändern.
Wenn du möchtest, kannst du so nach und nach weitere Dienste einbinden oder bestehende Abläufe verfeinern.
Im weiteren Verlauf werden wir auf dieser Grundlage aufbauen und die Automatisierung Schritt für Schritt erweitern bis hin zu intelligenten Workflows, die eigenständig Inhalte analysieren, kombinieren und veröffentlichen.
Doch selbst in dieser Basisform zeigt sich, wie viel Zeit sich mit etwas Vorbereitung einsparen lässt.
[!TIP]
Wenn dein Workflow zuverlässig läuft, sichere ihn regelmäßig über **Export > Download Workflow File**.
So kannst du jederzeit eine funktionierende Version wiederherstellen, falls n8n oder ein Container neu aufgesetzt werden muss.