diff --git a/dns-monitor/monitor.sh b/dns-monitor/monitor.sh new file mode 100644 index 00000000..a1f0f8fd --- /dev/null +++ b/dns-monitor/monitor.sh @@ -0,0 +1,44 @@ +#!/bin/sh + +# Install curl and ping if not present (Alpine) +if ! command -v curl >/dev/null 2>&1; then + apk add --no-cache curl +fi + +echo "[DNS-MONITOR] Service started. Monitoring $SUBDOMAINS every 5 minutes..." + +while true; do + # Fetch Public IP + PUBLIC_IP=$(curl -s -m 10 https://api.ipify.org) + + if [ -z "$PUBLIC_IP" ]; then + PUBLIC_IP="Error: Could not fetch IP" + fi + + # Get the first subdomain to check + FIRST_SUB=$(echo $SUBDOMAINS | cut -d',' -f1) + + if [ -z "$FIRST_SUB" ]; then + echo "[DNS-MONITOR] No subdomain found in env var SUBDOMAINS" + else + FULL_DOMAIN="${FIRST_SUB}.duckdns.org" + + # Resolve IP using ping + DOMAIN_IP=$(ping -c 1 -W 5 "$FULL_DOMAIN" 2>/dev/null | head -n 1 | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -n 1) + + if [ -z "$DOMAIN_IP" ]; then + DOMAIN_IP="Error: Could not resolve" + fi + + TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S') + + if [ "$PUBLIC_IP" == "$DOMAIN_IP" ]; then + echo "[$TIMESTAMP] [DNS-MONITOR] OK | Domain: $FULL_DOMAIN ($DOMAIN_IP) == Public: $PUBLIC_IP" + else + echo "[$TIMESTAMP] [DNS-MONITOR] ALERT | Domain: $FULL_DOMAIN ($DOMAIN_IP) != Public: $PUBLIC_IP" + fi + fi + + # Check every 5 minutes + sleep 300 +done diff --git a/docker-compose.yml b/docker-compose.yml index 8094ff25..297d7425 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -106,4 +106,29 @@ services: - ./serpapikey.txt:/app/serpapikey.txt environment: - PYTHONUNBUFFERED=1 - - DB_PATH=/app/gtm_projects.db \ No newline at end of file + - DB_PATH=/app/gtm_projects.db + + # --- DUCKDNS UPDATER --- + duckdns: + image: lscr.io/linuxserver/duckdns:latest + container_name: duckdns + environment: + - PUID=1000 # User ID (anpassen falls nötig) + - PGID=1000 # Group ID (anpassen falls nötig) + - TZ=Europe/Berlin + - SUBDOMAINS=floke,floke-ai,floke-gitea,floke-ha,floke-n8n + - TOKEN=af8f6d8b-5a83-4251-9c15-d3b3e82eeef1 + restart: unless-stopped + + # --- DNS MONITOR (Sidecar) --- + dns-monitor: + image: alpine + container_name: dns-monitor + environment: + - SUBDOMAINS=floke,floke-ai,floke-gitea,floke-ha,floke-n8n + - TZ=Europe/Berlin + volumes: + - ./dns-monitor:/app + command: /app/monitor.sh + restart: unless-stopped + \ No newline at end of file diff --git a/duckdns_setup.md b/duckdns_setup.md new file mode 100644 index 00000000..331933cc --- /dev/null +++ b/duckdns_setup.md @@ -0,0 +1,82 @@ +# DuckDNS & DNS Monitor Setup + +**Erstellt am:** 05.01.2026 +**Status:** Aktiv +**Architektur:** Sidecar-Pattern + +Dieses Dokument beschreibt die Docker-basierte Lösung zur DynDNS-Aktualisierung und Überwachung, die eingeführt wurde, um DNS-Caching-Probleme und Verbindungsabbrüche auf der Synology Diskstation zu beheben. + +## Problembeschreibung +Das ursprüngliche Synology-Skript im Aufgabenplaner führte zu unzuverlässigen DNS-Updates. Oft war die IP bei DuckDNS zwar aktuell, aber die Dienste waren von außen nicht erreichbar. Erst ein manuelles Ändern der IP auf einen falschen Wert und zurück (Toggle) löste das Problem. Dies deutete auf DNS-Propagation- oder Caching-Probleme hin. + +## Lösung +Wir haben eine robuste **Zwei-Container-Lösung** (Sidecar-Pattern) implementiert: + +1. **Updater (`duckdns`):** Aktualisiert zuverlässig die IP bei DuckDNS (Image: `linuxserver/duckdns`). +2. **Monitor (`dns-monitor`):** Überwacht unabhängig, ob die Domain tatsächlich auf die aktuelle öffentliche IP auflöst. + +## Konfiguration (`docker-compose.yml`) + +### 1. Der Updater +Dieser Container sorgt dafür, dass DuckDNS immer die aktuelle IP kennt. + +```yaml + duckdns: + image: lscr.io/linuxserver/duckdns:latest + container_name: duckdns + environment: + - PUID=1000 + - PGID=1000 + - TZ=Europe/Berlin + - SUBDOMAINS=deine-subdomains # (ohne .duckdns.org, kommasepariert) + - TOKEN=dein-duckdns-token + restart: unless-stopped +``` + +### 2. Der Monitor (Sidecar) +Dieser Container prüft alle 5 Minuten die DNS-Auflösung und schreibt das Ergebnis ins Log. + +```yaml + dns-monitor: + image: alpine + container_name: dns-monitor + environment: + - SUBDOMAINS=deine-subdomains + - TZ=Europe/Berlin + volumes: + - ./dns-monitor:/app + command: /app/monitor.sh + restart: unless-stopped +``` + +**Wichtig:** Das Skript `monitor.sh` liegt im Host-Verzeichnis `/app/dns-monitor/`. + +## Logs & Monitoring + +### Update-Status prüfen +```bash +docker logs duckdns +``` +*Erwartet:* `Your IP was updated at ...` oder `IP(s) unchanged`. + +### DNS-Konsistenz prüfen (WICHTIG!) +Hier sehen wir, ob die Welt (bzw. der Container) die Domain korrekt auflöst. + +```bash +docker logs dns-monitor +``` + +**Szenario OK:** +```text +[2026-01-05 21:26:26] [DNS-MONITOR] OK | Domain: floke.duckdns.org (87.x.x.x) == Public: 87.x.x.x +``` + +**Szenario FEHLER (Alarm):** +```text +[2026-01-05 21:30:00] [DNS-MONITOR] ALERT | Domain: floke.duckdns.org (Error) != Public: 87.x.x.x +``` +Dies deutet darauf hin, dass DuckDNS zwar vielleicht aktualisiert wurde, aber die DNS-Server die Änderung noch nicht propagiert haben. + +## Dateien +- `/app/docker-compose.yml`: Definition der Services. +- `/app/dns-monitor/monitor.sh`: Das Shell-Skript für den Monitor-Container. \ No newline at end of file diff --git a/readme.md b/readme.md index 07d14ee9..4c25eeff 100644 --- a/readme.md +++ b/readme.md @@ -852,3 +852,12 @@ Das "Market Intelligence Tool" wurde in Version 2.2 massiv überarbeitet, um rob * **Modern User-Agent:** Der Scraper gibt sich als moderner Chrome-Browser aus, um Blockaden zu minimieren. * **Frontend-Integration:** Die neuen Datenfelder werden nahtlos im React-Frontend und im Markdown-Export angezeigt. +--- + +## 12. Infrastructure & Operations + +### DNS & Connectivity +Um eine stabile Erreichbarkeit der Dienste zu gewährleisten, wurde eine Docker-basierte DynDNS-Lösung implementiert. + +* **[DuckDNS & Monitoring Setup](duckdns_setup.md):** Dokumentation zur Einrichtung des `duckdns` Updaters und des `dns-monitor` Sidecars, um Verbindungsprobleme und Caching-Fehler zu beheben. +