<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
	<id>https://wiki.tuxi.ddnss.de/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Admin</id>
	<title>Tuxipedia - Benutzerbeiträge [de]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.tuxi.ddnss.de/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Admin"/>
	<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/wiki/Spezial:Beitr%C3%A4ge/Admin"/>
	<updated>2026-10-18T19:53:04Z</updated>
	<subtitle>Benutzerbeiträge</subtitle>
	<generator>MediaWiki 1.46.0</generator>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=326</id>
		<title>Belegversand</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=326"/>
		<updated>2026-08-19T14:53:58Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* 2. Repository klonen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Belegversand =&lt;br /&gt;
&lt;br /&gt;
== Übersicht ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Belegversand&#039;&#039;&#039; ist eine automatisierte AppleScript-Lösung zur Verwaltung von Dokumenten-Versand in DEVONthink. Das System ermöglicht es, Belege aus einer DEVONthink-Datenbank auszuwählen, diese in ZIP-Archive zu packen (optional mit Passwort) und automatische Mail-Drafts mit konfigurierbaren Empfängern zu erstellen. Zusätzlich erfolgt strukturierte Protokollierung über Logging und Tagging-Mechanismen.&lt;br /&gt;
&lt;br /&gt;
== Sicherheitstechnischer Hinweis! ==&lt;br /&gt;
&lt;br /&gt;
Ich bitte zu beachten, dass die Software allenfalls minimale Sicherheitsanforderungen erfüllt.&lt;br /&gt;
&lt;br /&gt;
    Insbesondere liegt das Passwort für&#039;s ZIP-Archiv unverschlüsselt, im Klartext, in /_config/belegversand.conf. Wer das Passwort schützen möchte, kann das über die DB-Crypto von DEVONthink selbst tun. DEVONthink hat eine Datenbank-Verschlüsselung in den Bordmitteln.&lt;br /&gt;
    Dann bleibt trotzdem der zweite Schwachpunkt: Die ZIP-Verschlüsselung wird in dieser Version 1.4 über das Shell-Tool zip -P auf der Konsolenzeile realisiert. Dahinter steckt das veraltete und kryptographisch schwache ZipCrypto-Verfahren.&lt;br /&gt;
&lt;br /&gt;
Ganz deutlich: Diese Belegversand-Automatisation hab&#039; ich mir gebaut, um Tankbelege, Einkaufszettel und Restaurant-Quittungen an die Steuerberatung zu verschicken! Dafür sind sie prima! Falls es eine Version 1.5 geben sollte, ersetze ich zip -P vermutlich durch eine starke AES-Verschlüsselung, und das Passwort kommt als Hash-Wert in die Config-Datei.&lt;br /&gt;
&lt;br /&gt;
Bis dahin jedoch gilt ganz klar: Wer mit diesen Skripten, in dieser Version 1.4, sicherheitsrelevante Dokumente verschickt, tut das auf eigene Gefahr und handelt potentiell fahrlässig!&lt;br /&gt;
&lt;br /&gt;
== Aktuelle Softwareversion (August 2026) ==&lt;br /&gt;
&lt;br /&gt;
; Version: 1.4&lt;br /&gt;
; Plattform: macOS 10.13+&lt;br /&gt;
; Abhängigkeiten: DEVONthink 4.x, Apple Mail&lt;br /&gt;
; Lizenz: MIT-License&lt;br /&gt;
; Repository: https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Voraussetzungen ===&lt;br /&gt;
&lt;br /&gt;
* macOS 10.13 oder neuer&lt;br /&gt;
* DEVONthink 4.x&lt;br /&gt;
* Apple Mail&lt;br /&gt;
* AppleScript-Zugriff in Systemeinstellungen aktiviert&lt;br /&gt;
* Git (zum Klonen des Repositories)&lt;br /&gt;
&lt;br /&gt;
=== Schritt-für-Schritt Anleitung ===&lt;br /&gt;
&lt;br /&gt;
==== 1. Verzeichnisstruktur anlegen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&lt;br /&gt;
cd ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 2. Repository klonen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation.git Belegversand&lt;br /&gt;
&lt;br /&gt;
cd Belegversand&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 3. Scripts kompilieren ====&lt;br /&gt;
&lt;br /&gt;
Dies ist ein &#039;&#039;&#039;wichtiger Schritt&#039;&#039;&#039; und darf nicht übersprungen werden!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chmod +x compile.sh&lt;br /&gt;
./compile.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erwartete Ausgabe:&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Compiliere Belegversand AppleScripts...&lt;br /&gt;
✓ Fertig!&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 4. Erste Ausführung ====&lt;br /&gt;
&lt;br /&gt;
# DEVONthink öffnen&lt;br /&gt;
# Ein Objekt in der gewünschten Datenbank auswählen&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog folgen → Setup wird durchgeführt&lt;br /&gt;
&lt;br /&gt;
Das Setup-Script erstellt automatisch alle notwendigen Ordnerstrukturen und Konfigurationsdateien in DEVONthink.&lt;br /&gt;
&lt;br /&gt;
== Wichtig: .applescript vs. .scpt Dateien ==&lt;br /&gt;
&lt;br /&gt;
Im Repository gibt es zwei Arten von AppleScript-Dateien:&lt;br /&gt;
&lt;br /&gt;
; .applescript: Quelldateien (lesbar, nur für Entwicklung)&lt;br /&gt;
; .scpt: Kompilierte Skripte (binär, werden von DEVONthink ausgeführt)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Kritisch:&#039;&#039;&#039; Die `.applescript`-Quelldateien funktionieren &#039;&#039;&#039;nicht&#039;&#039;&#039; direkt in DEVONthink. Sie enthalten relative Pfade, die zur Laufzeit expandiert werden müssen.&lt;br /&gt;
&lt;br /&gt;
Das `compile.sh`-Script:&lt;br /&gt;
# Kompiliert alle `.applescript` zu `.scpt`&lt;br /&gt;
# Löscht anschließend die `.applescript`-Dateien&lt;br /&gt;
# Hinterlässt nur funktionsfähige `.scpt`-Dateien&lt;br /&gt;
&lt;br /&gt;
Falls nach dem Clone noch `.applescript`-Dateien vorhanden sind, war `compile.sh` nicht erfolgreich. In diesem Fall erneut ausführen und auf Fehlermeldungen achten.&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
=== Automatische Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Nach der ersten Ausführung erstellt das System automatisch folgende Struktur in DEVONthink:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
_config/&lt;br /&gt;
├── belegversand.conf              # Konfigurationsdatei&lt;br /&gt;
├── mail_vorlagen/                 # Mail-Templates&lt;br /&gt;
│   └── belegversand               # Standard-Template&lt;br /&gt;
├── README-Belegversand            # Interne Hilfe&lt;br /&gt;
└── [weitere Dateien nach Versand]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Konfigurationsdatei ===&lt;br /&gt;
&lt;br /&gt;
Die Datei `belegversand.conf` befindet sich in DEVONthink unter `_config → belegversand.conf`.&lt;br /&gt;
&lt;br /&gt;
==== Wichtigste Parameter ====&lt;br /&gt;
&lt;br /&gt;
; MAIL_TO_DEFAULT: Standard-Empfänger (z.B. steuer@example.com)&lt;br /&gt;
&lt;br /&gt;
; MAIL_CC_TO_DEFAULT: Standard-CC-Empfänger (optional)&lt;br /&gt;
&lt;br /&gt;
; MAIL_SUBJECT_PREFIX: Präfix für den Mail-Betreff (z.B. &amp;quot;Belegversand&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
; ZIP_PASSWORD_DEFAULT: Standard-Passwort für ZIP-Archive (optional, keine Sonderzeichen)&lt;br /&gt;
&lt;br /&gt;
; LOG_SENT_GROUP_NAME: Name der Ordnergruppe für Versandprotokolle (Standard: &amp;quot;Versendet&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
; SENT_TAG_FOR_DOCS: Tag für versendete Belege (Standard: &amp;quot;gesendet&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
; WRITE_DEBUG_LOG: Debug-Logging aktivieren (true/false)&lt;br /&gt;
&lt;br /&gt;
; SHOW_README: Willkommensdialog beim Start anzeigen (true/false)&lt;br /&gt;
&lt;br /&gt;
; MAILBODY_FOLDER_NAME: Ordner für Mail-Templates (Standard: &amp;quot;mail_vorlagen&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
; MAILBODY_RECORD_NAME: Name des Standard-Templates (Standard: &amp;quot;belegversand&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
; PATH_TO_DRYRUN_PREVIEW: Speicherort der Dry-Run Vorschau-Datei&lt;br /&gt;
&lt;br /&gt;
==== Multiple Empfänger (CSV-Format) ====&lt;br /&gt;
&lt;br /&gt;
Mehrere E-Mail-Adressen können durch Kommas getrennt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
MAIL_TO_DEFAULT=recipient1@example.com, recipient2@example.com&lt;br /&gt;
MAIL_CC_TO_DEFAULT=cc1@example.com, cc2@example.com&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Adressen werden automatisch geparst und in Apple Mail einzeln eingefügt.&lt;br /&gt;
&lt;br /&gt;
== Verwendung ==&lt;br /&gt;
&lt;br /&gt;
=== Grundablauf ===&lt;br /&gt;
&lt;br /&gt;
# Belege in DEVONthink auswählen (Mehrfachauswahl möglich)&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog beantwortet (Empfänger, ZIP-Passwort, Dry-Run?)&lt;br /&gt;
# Dry-Run Vorschau anschauen (optional)&lt;br /&gt;
# Echtlauf → ZIP-Archive erstellt, Mail-Draft geöffnet, Logging durchgeführt&lt;br /&gt;
&lt;br /&gt;
=== Menü-Befehle ===&lt;br /&gt;
&lt;br /&gt;
; START: Haupteinstiegspunkt — startet Setup oder Versand&lt;br /&gt;
; About...: About-Dialog mit Versionsinformation und Links&lt;br /&gt;
&lt;br /&gt;
=== Booking-Jahr Enforcement ===&lt;br /&gt;
&lt;br /&gt;
Das System verhindert Versandvermischung über mehrere Jahre:&lt;br /&gt;
&lt;br /&gt;
; Mixed-Year Selection: Werden Belege aus verschiedenen Jahren auswählt, wird ein Fehler zurückgewiesen&lt;br /&gt;
; Separate Protokolle: Jedes Buchungsjahr hat eigene Versendet-Ordner mit separaten Logs&lt;br /&gt;
; Outsider-Belege: Dokumente außerhalb der Jahresstruktur werden separat gehandhabt&lt;br /&gt;
&lt;br /&gt;
Beispiel-Struktur:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Belege/&lt;br /&gt;
├── 2026/&lt;br /&gt;
│   ├── 01_Januar/&lt;br /&gt;
    ├── 02_Februar/&lt;br /&gt;
    ├── .../&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
├── 2027/&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
└── Provisionsabrechnungen/&lt;br /&gt;
    └── [← Separate Outsider-Logs]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dry-Run Modus ===&lt;br /&gt;
&lt;br /&gt;
Vor jedem echten Versand kann ein Dry-Run durchgeführt werden:&lt;br /&gt;
&lt;br /&gt;
# Simuliert den kompletten Versandprozess&lt;br /&gt;
# Erstellt Vorschau-Datei mit allen Details&lt;br /&gt;
# Zeigt Dialog mit Zusammenfassung&lt;br /&gt;
# User kann bestätigen oder abbrechen&lt;br /&gt;
&lt;br /&gt;
Die Vorschau-Datei wird auf der lokalen Festplatte gespeichert (Pfad konfigurierbar).&lt;br /&gt;
&lt;br /&gt;
=== Mail-Drafts ===&lt;br /&gt;
&lt;br /&gt;
Das System erstellt keinen automatischen Versand, sondern Mail-Drafts:&lt;br /&gt;
&lt;br /&gt;
# ZIP-Archive werden erzeugt&lt;br /&gt;
# Apple Mail öffnet mit neuem Draft (nicht gesendet!)&lt;br /&gt;
# User kann Template prüfen, weitere Empfänger hinzufügen&lt;br /&gt;
# Benutzerdefinierter Versand per Knopfdruck in Mail&lt;br /&gt;
&lt;br /&gt;
Dies ermöglicht volle Kontrolle über den Versand.&lt;br /&gt;
&lt;br /&gt;
=== Mail-Templates ===&lt;br /&gt;
&lt;br /&gt;
Templates werden aus DEVONthink geladen (`_config/mail_vorlagen/`).&lt;br /&gt;
&lt;br /&gt;
Das System zeigt einen Dialog zur Template-Auswahl, wenn mehrere Vorlagen vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Beispiel-Template:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Sehr geehrte/r Frau/Herr,&lt;br /&gt;
&lt;br /&gt;
beiliegend erhalten Sie die angeforderten Unterlagen.&lt;br /&gt;
&lt;br /&gt;
Mit freundlichen Grüßen&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Protokollierung ==&lt;br /&gt;
&lt;br /&gt;
Die Versandvorgänge werden jeweils doppelt protokolliert:&lt;br /&gt;
&lt;br /&gt;
1. Zum einen im maschinenlesbaren json-Format, für technische Weiterverarbeitung.&lt;br /&gt;
&lt;br /&gt;
2. Zum anderen im menschlich lesbaren Mark-Down-Textformat, mit Übersichten nach Versandlauf.&lt;br /&gt;
&lt;br /&gt;
Die Protokolle liegen entweder in der DEVONthink-Gruppe /Versendet des aktuellen Buchungsjahres. Das gilt, wenn Dokumente innerhalb eines Jahresordners liegen und einem Monat zugeordnet sind (siehe oben, Abschnitt &#039;&#039;Booking-Jahr Enforcement&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
Dokumente, die nicht Teil eines Buchungsjahres sind, werden in der Gruppe /Versendet_Outsider abgelegt. Diese Gruppe liegt neben /_config unmittel an der Datenbankwurzel.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
=== Scripts funktionieren nicht ===&lt;br /&gt;
&lt;br /&gt;
==== Problem: &amp;quot;Script nicht gefunden&amp;quot; ====&lt;br /&gt;
&lt;br /&gt;
Häufigste Ursache: `compile.sh` wurde nicht ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# Prüfen ob `.scpt`-Dateien vorhanden sind: &amp;lt;code&amp;gt;ls ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/Belegversand/Helpers/scripts/&amp;lt;/code&amp;gt;&lt;br /&gt;
# Falls nur `.applescript`-Dateien vorhanden → &amp;lt;code&amp;gt;./compile.sh&amp;lt;/code&amp;gt; erneut ausführen&lt;br /&gt;
# Auf Fehlermeldungen achten&lt;br /&gt;
&lt;br /&gt;
==== Problem: Script-Zugriff verweigert ====&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# System Settings → Privacy &amp;amp; Security → Automation&lt;br /&gt;
# DEVONthink sollte mit entsprechenden Rechten gelistet sein&lt;br /&gt;
# Script Editor öffnen und START.scpt öffnen&lt;br /&gt;
# Compile (⌘K) — sollte ohne Fehler durchlaufen&lt;br /&gt;
&lt;br /&gt;
=== ZIP wird nicht erstellt ===&lt;br /&gt;
&lt;br /&gt;
* ZIP-Passwort in Config überprüfen (keine Sonderzeichen!)&lt;br /&gt;
* Ausreichend Festplatte vorhanden?&lt;br /&gt;
* Staging-Ordner in DEVONthink beschreibbar?&lt;br /&gt;
&lt;br /&gt;
=== Mail-Draft öffnet sich nicht ===&lt;br /&gt;
&lt;br /&gt;
* Apple Mail ist geöffnet?&lt;br /&gt;
* Script-Zugriff für Mail aktiviert?&lt;br /&gt;
* Mail-Templates-Ordner vorhanden?&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Mixed-Year-Selection&amp;quot;-Fehler ===&lt;br /&gt;
&lt;br /&gt;
Dies ist kein Fehler, sondern Schutz vor Versandvermischung:&lt;br /&gt;
&lt;br /&gt;
- Lösung 1: Nur Belege aus einem Buchungsjahr auswählen&lt;br /&gt;
&lt;br /&gt;
- Lösung 2: Belege in mehreren Versänden verteilen&lt;br /&gt;
&lt;br /&gt;
=== Debug-Informationen aktivieren ===&lt;br /&gt;
&lt;br /&gt;
In `belegversand.conf`:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
WRITE_DEBUG_LOG=true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Debug-Logs erscheinen dann in `/tmp/DT-Belegversand-debug.log`.&lt;br /&gt;
&lt;br /&gt;
== Versionshistorie ==&lt;br /&gt;
&lt;br /&gt;
* 1.4: Booking-Jahr Enforcement, Kompilierungs-Automation, About-Dialog, Wiki-Integration&lt;br /&gt;
&lt;br /&gt;
* 1.3: Dry-Run Verbesserungen, Markdown-Logs&lt;br /&gt;
&lt;br /&gt;
* 1.2: Mail-Templates in DEVONthink, interne README&lt;br /&gt;
&lt;br /&gt;
* 1.1: Konfigurationssystem&lt;br /&gt;
&lt;br /&gt;
* 1.0: Erste funktionale Version&lt;br /&gt;
&lt;br /&gt;
== Entwicklung ==&lt;br /&gt;
&lt;br /&gt;
Quellcode liegt als `.applescript`-Dateien vor (lesbar, git-freundlich).&lt;br /&gt;
&lt;br /&gt;
Zur lokalen Entwicklung:&lt;br /&gt;
# Quelldateien (`.applescript`) editieren&lt;br /&gt;
# `./compile.sh` ausführen&lt;br /&gt;
# In DEVONthink testen&lt;br /&gt;
# Bei Änderungen: `./compile.sh` erneut ausführen&lt;br /&gt;
&lt;br /&gt;
== Support ==&lt;br /&gt;
&lt;br /&gt;
Für technische Fragen oder Probleme:&lt;br /&gt;
* Wiki-Dokumentation durchlesen (diese Seite)&lt;br /&gt;
* Debug-Log aktivieren und analysieren&lt;br /&gt;
* Im Gitea-Repository ein Issue erstellen (falls Zugriff vorhanden)&lt;br /&gt;
&lt;br /&gt;
== Externe Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation Repository]&lt;br /&gt;
* [https://www.devontechnologies.com DEVONthink Homepage]&lt;br /&gt;
* [https://support.apple.com/mail Apple Mail Documentation]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=325</id>
		<title>Belegversand</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=325"/>
		<updated>2026-08-18T17:25:41Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Belegversand =&lt;br /&gt;
&lt;br /&gt;
== Übersicht ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Belegversand&#039;&#039;&#039; ist eine automatisierte AppleScript-Lösung zur Verwaltung von Dokumenten-Versand in DEVONthink. Das System ermöglicht es, Belege aus einer DEVONthink-Datenbank auszuwählen, diese in ZIP-Archive zu packen (optional mit Passwort) und automatische Mail-Drafts mit konfigurierbaren Empfängern zu erstellen. Zusätzlich erfolgt strukturierte Protokollierung über Logging und Tagging-Mechanismen.&lt;br /&gt;
&lt;br /&gt;
== Sicherheitstechnischer Hinweis! ==&lt;br /&gt;
&lt;br /&gt;
Ich bitte zu beachten, dass die Software allenfalls minimale Sicherheitsanforderungen erfüllt.&lt;br /&gt;
&lt;br /&gt;
    Insbesondere liegt das Passwort für&#039;s ZIP-Archiv unverschlüsselt, im Klartext, in /_config/belegversand.conf. Wer das Passwort schützen möchte, kann das über die DB-Crypto von DEVONthink selbst tun. DEVONthink hat eine Datenbank-Verschlüsselung in den Bordmitteln.&lt;br /&gt;
    Dann bleibt trotzdem der zweite Schwachpunkt: Die ZIP-Verschlüsselung wird in dieser Version 1.4 über das Shell-Tool zip -P auf der Konsolenzeile realisiert. Dahinter steckt das veraltete und kryptographisch schwache ZipCrypto-Verfahren.&lt;br /&gt;
&lt;br /&gt;
Ganz deutlich: Diese Belegversand-Automatisation hab&#039; ich mir gebaut, um Tankbelege, Einkaufszettel und Restaurant-Quittungen an die Steuerberatung zu verschicken! Dafür sind sie prima! Falls es eine Version 1.5 geben sollte, ersetze ich zip -P vermutlich durch eine starke AES-Verschlüsselung, und das Passwort kommt als Hash-Wert in die Config-Datei.&lt;br /&gt;
&lt;br /&gt;
Bis dahin jedoch gilt ganz klar: Wer mit diesen Skripten, in dieser Version 1.4, sicherheitsrelevante Dokumente verschickt, tut das auf eigene Gefahr und handelt potentiell fahrlässig!&lt;br /&gt;
&lt;br /&gt;
== Aktuelle Softwareversion (August 2026) ==&lt;br /&gt;
&lt;br /&gt;
; Version: 1.4&lt;br /&gt;
; Plattform: macOS 10.13+&lt;br /&gt;
; Abhängigkeiten: DEVONthink 4.x, Apple Mail&lt;br /&gt;
; Lizenz: MIT-License&lt;br /&gt;
; Repository: https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Voraussetzungen ===&lt;br /&gt;
&lt;br /&gt;
* macOS 10.13 oder neuer&lt;br /&gt;
* DEVONthink 4.x&lt;br /&gt;
* Apple Mail&lt;br /&gt;
* AppleScript-Zugriff in Systemeinstellungen aktiviert&lt;br /&gt;
* Git (zum Klonen des Repositories)&lt;br /&gt;
&lt;br /&gt;
=== Schritt-für-Schritt Anleitung ===&lt;br /&gt;
&lt;br /&gt;
==== 1. Verzeichnisstruktur anlegen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&lt;br /&gt;
cd ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 2. Repository klonen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation.git Belegversand&lt;br /&gt;
cd Belegversand&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 3. Scripts kompilieren ====&lt;br /&gt;
&lt;br /&gt;
Dies ist ein &#039;&#039;&#039;wichtiger Schritt&#039;&#039;&#039; und darf nicht übersprungen werden!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chmod +x compile.sh&lt;br /&gt;
./compile.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erwartete Ausgabe:&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Compiliere Belegversand AppleScripts...&lt;br /&gt;
✓ Fertig!&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 4. Erste Ausführung ====&lt;br /&gt;
&lt;br /&gt;
# DEVONthink öffnen&lt;br /&gt;
# Ein Objekt in der gewünschten Datenbank auswählen&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog folgen → Setup wird durchgeführt&lt;br /&gt;
&lt;br /&gt;
Das Setup-Script erstellt automatisch alle notwendigen Ordnerstrukturen und Konfigurationsdateien in DEVONthink.&lt;br /&gt;
&lt;br /&gt;
== Wichtig: .applescript vs. .scpt Dateien ==&lt;br /&gt;
&lt;br /&gt;
Im Repository gibt es zwei Arten von AppleScript-Dateien:&lt;br /&gt;
&lt;br /&gt;
; .applescript: Quelldateien (lesbar, nur für Entwicklung)&lt;br /&gt;
; .scpt: Kompilierte Skripte (binär, werden von DEVONthink ausgeführt)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Kritisch:&#039;&#039;&#039; Die `.applescript`-Quelldateien funktionieren &#039;&#039;&#039;nicht&#039;&#039;&#039; direkt in DEVONthink. Sie enthalten relative Pfade, die zur Laufzeit expandiert werden müssen.&lt;br /&gt;
&lt;br /&gt;
Das `compile.sh`-Script:&lt;br /&gt;
# Kompiliert alle `.applescript` zu `.scpt`&lt;br /&gt;
# Löscht anschließend die `.applescript`-Dateien&lt;br /&gt;
# Hinterlässt nur funktionsfähige `.scpt`-Dateien&lt;br /&gt;
&lt;br /&gt;
Falls nach dem Clone noch `.applescript`-Dateien vorhanden sind, war `compile.sh` nicht erfolgreich. In diesem Fall erneut ausführen und auf Fehlermeldungen achten.&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
=== Automatische Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Nach der ersten Ausführung erstellt das System automatisch folgende Struktur in DEVONthink:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
_config/&lt;br /&gt;
├── belegversand.conf              # Konfigurationsdatei&lt;br /&gt;
├── mail_vorlagen/                 # Mail-Templates&lt;br /&gt;
│   └── belegversand               # Standard-Template&lt;br /&gt;
├── README-Belegversand            # Interne Hilfe&lt;br /&gt;
└── [weitere Dateien nach Versand]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Konfigurationsdatei ===&lt;br /&gt;
&lt;br /&gt;
Die Datei `belegversand.conf` befindet sich in DEVONthink unter `_config → belegversand.conf`.&lt;br /&gt;
&lt;br /&gt;
==== Wichtigste Parameter ====&lt;br /&gt;
&lt;br /&gt;
; MAIL_TO_DEFAULT: Standard-Empfänger (z.B. steuer@example.com)&lt;br /&gt;
&lt;br /&gt;
; MAIL_CC_TO_DEFAULT: Standard-CC-Empfänger (optional)&lt;br /&gt;
&lt;br /&gt;
; MAIL_SUBJECT_PREFIX: Präfix für den Mail-Betreff (z.B. &amp;quot;Belegversand&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
; ZIP_PASSWORD_DEFAULT: Standard-Passwort für ZIP-Archive (optional, keine Sonderzeichen)&lt;br /&gt;
&lt;br /&gt;
; LOG_SENT_GROUP_NAME: Name der Ordnergruppe für Versandprotokolle (Standard: &amp;quot;Versendet&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
; SENT_TAG_FOR_DOCS: Tag für versendete Belege (Standard: &amp;quot;gesendet&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
; WRITE_DEBUG_LOG: Debug-Logging aktivieren (true/false)&lt;br /&gt;
&lt;br /&gt;
; SHOW_README: Willkommensdialog beim Start anzeigen (true/false)&lt;br /&gt;
&lt;br /&gt;
; MAILBODY_FOLDER_NAME: Ordner für Mail-Templates (Standard: &amp;quot;mail_vorlagen&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
; MAILBODY_RECORD_NAME: Name des Standard-Templates (Standard: &amp;quot;belegversand&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
; PATH_TO_DRYRUN_PREVIEW: Speicherort der Dry-Run Vorschau-Datei&lt;br /&gt;
&lt;br /&gt;
==== Multiple Empfänger (CSV-Format) ====&lt;br /&gt;
&lt;br /&gt;
Mehrere E-Mail-Adressen können durch Kommas getrennt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
MAIL_TO_DEFAULT=recipient1@example.com, recipient2@example.com&lt;br /&gt;
MAIL_CC_TO_DEFAULT=cc1@example.com, cc2@example.com&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Adressen werden automatisch geparst und in Apple Mail einzeln eingefügt.&lt;br /&gt;
&lt;br /&gt;
== Verwendung ==&lt;br /&gt;
&lt;br /&gt;
=== Grundablauf ===&lt;br /&gt;
&lt;br /&gt;
# Belege in DEVONthink auswählen (Mehrfachauswahl möglich)&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog beantwortet (Empfänger, ZIP-Passwort, Dry-Run?)&lt;br /&gt;
# Dry-Run Vorschau anschauen (optional)&lt;br /&gt;
# Echtlauf → ZIP-Archive erstellt, Mail-Draft geöffnet, Logging durchgeführt&lt;br /&gt;
&lt;br /&gt;
=== Menü-Befehle ===&lt;br /&gt;
&lt;br /&gt;
; START: Haupteinstiegspunkt — startet Setup oder Versand&lt;br /&gt;
; About...: About-Dialog mit Versionsinformation und Links&lt;br /&gt;
&lt;br /&gt;
=== Booking-Jahr Enforcement ===&lt;br /&gt;
&lt;br /&gt;
Das System verhindert Versandvermischung über mehrere Jahre:&lt;br /&gt;
&lt;br /&gt;
; Mixed-Year Selection: Werden Belege aus verschiedenen Jahren auswählt, wird ein Fehler zurückgewiesen&lt;br /&gt;
; Separate Protokolle: Jedes Buchungsjahr hat eigene Versendet-Ordner mit separaten Logs&lt;br /&gt;
; Outsider-Belege: Dokumente außerhalb der Jahresstruktur werden separat gehandhabt&lt;br /&gt;
&lt;br /&gt;
Beispiel-Struktur:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Belege/&lt;br /&gt;
├── 2026/&lt;br /&gt;
│   ├── 01_Januar/&lt;br /&gt;
    ├── 02_Februar/&lt;br /&gt;
    ├── .../&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
├── 2027/&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
└── Provisionsabrechnungen/&lt;br /&gt;
    └── [← Separate Outsider-Logs]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dry-Run Modus ===&lt;br /&gt;
&lt;br /&gt;
Vor jedem echten Versand kann ein Dry-Run durchgeführt werden:&lt;br /&gt;
&lt;br /&gt;
# Simuliert den kompletten Versandprozess&lt;br /&gt;
# Erstellt Vorschau-Datei mit allen Details&lt;br /&gt;
# Zeigt Dialog mit Zusammenfassung&lt;br /&gt;
# User kann bestätigen oder abbrechen&lt;br /&gt;
&lt;br /&gt;
Die Vorschau-Datei wird auf der lokalen Festplatte gespeichert (Pfad konfigurierbar).&lt;br /&gt;
&lt;br /&gt;
=== Mail-Drafts ===&lt;br /&gt;
&lt;br /&gt;
Das System erstellt keinen automatischen Versand, sondern Mail-Drafts:&lt;br /&gt;
&lt;br /&gt;
# ZIP-Archive werden erzeugt&lt;br /&gt;
# Apple Mail öffnet mit neuem Draft (nicht gesendet!)&lt;br /&gt;
# User kann Template prüfen, weitere Empfänger hinzufügen&lt;br /&gt;
# Benutzerdefinierter Versand per Knopfdruck in Mail&lt;br /&gt;
&lt;br /&gt;
Dies ermöglicht volle Kontrolle über den Versand.&lt;br /&gt;
&lt;br /&gt;
=== Mail-Templates ===&lt;br /&gt;
&lt;br /&gt;
Templates werden aus DEVONthink geladen (`_config/mail_vorlagen/`).&lt;br /&gt;
&lt;br /&gt;
Das System zeigt einen Dialog zur Template-Auswahl, wenn mehrere Vorlagen vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Beispiel-Template:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Sehr geehrte/r Frau/Herr,&lt;br /&gt;
&lt;br /&gt;
beiliegend erhalten Sie die angeforderten Unterlagen.&lt;br /&gt;
&lt;br /&gt;
Mit freundlichen Grüßen&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Protokollierung ==&lt;br /&gt;
&lt;br /&gt;
Die Versandvorgänge werden jeweils doppelt protokolliert:&lt;br /&gt;
&lt;br /&gt;
1. Zum einen im maschinenlesbaren json-Format, für technische Weiterverarbeitung.&lt;br /&gt;
&lt;br /&gt;
2. Zum anderen im menschlich lesbaren Mark-Down-Textformat, mit Übersichten nach Versandlauf.&lt;br /&gt;
&lt;br /&gt;
Die Protokolle liegen entweder in der DEVONthink-Gruppe /Versendet des aktuellen Buchungsjahres. Das gilt, wenn Dokumente innerhalb eines Jahresordners liegen und einem Monat zugeordnet sind (siehe oben, Abschnitt &#039;&#039;Booking-Jahr Enforcement&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
Dokumente, die nicht Teil eines Buchungsjahres sind, werden in der Gruppe /Versendet_Outsider abgelegt. Diese Gruppe liegt neben /_config unmittel an der Datenbankwurzel.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
=== Scripts funktionieren nicht ===&lt;br /&gt;
&lt;br /&gt;
==== Problem: &amp;quot;Script nicht gefunden&amp;quot; ====&lt;br /&gt;
&lt;br /&gt;
Häufigste Ursache: `compile.sh` wurde nicht ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# Prüfen ob `.scpt`-Dateien vorhanden sind: &amp;lt;code&amp;gt;ls ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/Belegversand/Helpers/scripts/&amp;lt;/code&amp;gt;&lt;br /&gt;
# Falls nur `.applescript`-Dateien vorhanden → &amp;lt;code&amp;gt;./compile.sh&amp;lt;/code&amp;gt; erneut ausführen&lt;br /&gt;
# Auf Fehlermeldungen achten&lt;br /&gt;
&lt;br /&gt;
==== Problem: Script-Zugriff verweigert ====&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# System Settings → Privacy &amp;amp; Security → Automation&lt;br /&gt;
# DEVONthink sollte mit entsprechenden Rechten gelistet sein&lt;br /&gt;
# Script Editor öffnen und START.scpt öffnen&lt;br /&gt;
# Compile (⌘K) — sollte ohne Fehler durchlaufen&lt;br /&gt;
&lt;br /&gt;
=== ZIP wird nicht erstellt ===&lt;br /&gt;
&lt;br /&gt;
* ZIP-Passwort in Config überprüfen (keine Sonderzeichen!)&lt;br /&gt;
* Ausreichend Festplatte vorhanden?&lt;br /&gt;
* Staging-Ordner in DEVONthink beschreibbar?&lt;br /&gt;
&lt;br /&gt;
=== Mail-Draft öffnet sich nicht ===&lt;br /&gt;
&lt;br /&gt;
* Apple Mail ist geöffnet?&lt;br /&gt;
* Script-Zugriff für Mail aktiviert?&lt;br /&gt;
* Mail-Templates-Ordner vorhanden?&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Mixed-Year-Selection&amp;quot;-Fehler ===&lt;br /&gt;
&lt;br /&gt;
Dies ist kein Fehler, sondern Schutz vor Versandvermischung:&lt;br /&gt;
&lt;br /&gt;
- Lösung 1: Nur Belege aus einem Buchungsjahr auswählen&lt;br /&gt;
&lt;br /&gt;
- Lösung 2: Belege in mehreren Versänden verteilen&lt;br /&gt;
&lt;br /&gt;
=== Debug-Informationen aktivieren ===&lt;br /&gt;
&lt;br /&gt;
In `belegversand.conf`:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
WRITE_DEBUG_LOG=true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Debug-Logs erscheinen dann in `/tmp/DT-Belegversand-debug.log`.&lt;br /&gt;
&lt;br /&gt;
== Versionshistorie ==&lt;br /&gt;
&lt;br /&gt;
* 1.4: Booking-Jahr Enforcement, Kompilierungs-Automation, About-Dialog, Wiki-Integration&lt;br /&gt;
&lt;br /&gt;
* 1.3: Dry-Run Verbesserungen, Markdown-Logs&lt;br /&gt;
&lt;br /&gt;
* 1.2: Mail-Templates in DEVONthink, interne README&lt;br /&gt;
&lt;br /&gt;
* 1.1: Konfigurationssystem&lt;br /&gt;
&lt;br /&gt;
* 1.0: Erste funktionale Version&lt;br /&gt;
&lt;br /&gt;
== Entwicklung ==&lt;br /&gt;
&lt;br /&gt;
Quellcode liegt als `.applescript`-Dateien vor (lesbar, git-freundlich).&lt;br /&gt;
&lt;br /&gt;
Zur lokalen Entwicklung:&lt;br /&gt;
# Quelldateien (`.applescript`) editieren&lt;br /&gt;
# `./compile.sh` ausführen&lt;br /&gt;
# In DEVONthink testen&lt;br /&gt;
# Bei Änderungen: `./compile.sh` erneut ausführen&lt;br /&gt;
&lt;br /&gt;
== Support ==&lt;br /&gt;
&lt;br /&gt;
Für technische Fragen oder Probleme:&lt;br /&gt;
* Wiki-Dokumentation durchlesen (diese Seite)&lt;br /&gt;
* Debug-Log aktivieren und analysieren&lt;br /&gt;
* Im Gitea-Repository ein Issue erstellen (falls Zugriff vorhanden)&lt;br /&gt;
&lt;br /&gt;
== Externe Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation Repository]&lt;br /&gt;
* [https://www.devontechnologies.com DEVONthink Homepage]&lt;br /&gt;
* [https://support.apple.com/mail Apple Mail Documentation]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=324</id>
		<title>Belegversand</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=324"/>
		<updated>2026-08-18T17:21:36Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Sicherheitstechnischer Hinweis! */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Belegversand =&lt;br /&gt;
&lt;br /&gt;
== Übersicht ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Belegversand&#039;&#039;&#039; ist eine automatisierte AppleScript-Lösung zur Verwaltung von Dokumenten-Versand in DEVONthink. Das System ermöglicht es, Belege aus einer DEVONthink-Datenbank auszuwählen, diese in ZIP-Archive zu packen (optional mit Passwort) und automatische Mail-Drafts mit konfigurierbaren Empfängern zu erstellen. Zusätzlich erfolgt strukturierte Protokollierung über Logging und Tagging-Mechanismen.&lt;br /&gt;
&lt;br /&gt;
== Sicherheitstechnischer Hinweis! ==&lt;br /&gt;
&lt;br /&gt;
Ich bitte zu beachten, dass die Software allenfalls minimale Sicherheitsanforderungen erfüllt.&lt;br /&gt;
&lt;br /&gt;
    Insbesondere liegt das Passwort für&#039;s ZIP-Archiv unverschlüsselt, im Klartext, in /_config/belegversand.conf. Wer das Passwort schützen möchte, kann das über die DB-Crypto von DEVONthink selbst tun. DEVONthink hat eine Datenbank-Verschlüsselung in den Bordmitteln.&lt;br /&gt;
    Dann bleibt trotzdem der zweite Schwachpunkt: Die ZIP-Verschlüsselung wird in dieser Version 1.4 über das Shell-Tool zip -P auf der Konsolenzeile realisiert. Dahinter steckt das veraltete und kryptographisch schwache ZipCrypto-Verfahren.&lt;br /&gt;
&lt;br /&gt;
Ganz deutlich: Diese Belegversand-Automatisation hab&#039; ich mir gebaut, um Tankbelege, Einkaufszettel und Restaurant-Quittungen an die Steuerberatung zu verschicken! Dafür sind sie prima! Falls es eine Version 1.5 geben sollte, ersetze ich zip -P vermutlich durch eine starke AES-Verschlüsselung, und das Passwort kommt als Hash-Wert in die Config-Datei.&lt;br /&gt;
&lt;br /&gt;
Bis dahin jedoch gilt ganz klar: Wer mit diesen Skripten, in dieser Version 1.4, sicherheitsrelevante Dokumente verschickt, tut das auf eigene Gefahr und handelt potentiell fahrlässig!&lt;br /&gt;
&lt;br /&gt;
; Version: 1.4&lt;br /&gt;
; Plattform: macOS 10.13+&lt;br /&gt;
; Abhängigkeiten: DEVONthink 3.x, Apple Mail&lt;br /&gt;
; Lizenz: Privatgebrauch&lt;br /&gt;
; Repository: https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Voraussetzungen ===&lt;br /&gt;
&lt;br /&gt;
* macOS 10.13 oder neuer&lt;br /&gt;
* DEVONthink 3.x&lt;br /&gt;
* Apple Mail&lt;br /&gt;
* AppleScript-Zugriff in Systemeinstellungen aktiviert&lt;br /&gt;
* Git (zum Klonen des Repositories)&lt;br /&gt;
&lt;br /&gt;
=== Schritt-für-Schritt Anleitung ===&lt;br /&gt;
&lt;br /&gt;
==== 1. Verzeichnisstruktur anlegen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&lt;br /&gt;
cd ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 2. Repository klonen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation.git Belegversand&lt;br /&gt;
cd Belegversand&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 3. Scripts kompilieren ====&lt;br /&gt;
&lt;br /&gt;
Dies ist ein &#039;&#039;&#039;wichtiger Schritt&#039;&#039;&#039; und darf nicht übersprungen werden!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chmod +x compile.sh&lt;br /&gt;
./compile.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erwartete Ausgabe:&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Compiliere Belegversand AppleScripts...&lt;br /&gt;
✓ Fertig!&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 4. Erste Ausführung ====&lt;br /&gt;
&lt;br /&gt;
# DEVONthink öffnen&lt;br /&gt;
# Ein Objekt in der gewünschten Datenbank auswählen&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog folgen → Setup wird durchgeführt&lt;br /&gt;
&lt;br /&gt;
Das Setup-Script erstellt automatisch alle notwendigen Ordnerstrukturen und Konfigurationsdateien in DEVONthink.&lt;br /&gt;
&lt;br /&gt;
== Wichtig: .applescript vs. .scpt Dateien ==&lt;br /&gt;
&lt;br /&gt;
Im Repository gibt es zwei Arten von AppleScript-Dateien:&lt;br /&gt;
&lt;br /&gt;
; .applescript: Quelldateien (lesbar, nur für Entwicklung)&lt;br /&gt;
; .scpt: Kompilierte Skripte (binär, werden von DEVONthink ausgeführt)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Kritisch:&#039;&#039;&#039; Die `.applescript`-Quelldateien funktionieren &#039;&#039;&#039;nicht&#039;&#039;&#039; direkt in DEVONthink. Sie enthalten relative Pfade, die zur Laufzeit expandiert werden müssen.&lt;br /&gt;
&lt;br /&gt;
Das `compile.sh`-Script:&lt;br /&gt;
# Kompiliert alle `.applescript` zu `.scpt`&lt;br /&gt;
# Löscht anschließend die `.applescript`-Dateien&lt;br /&gt;
# Hinterlässt nur funktionsfähige `.scpt`-Dateien&lt;br /&gt;
&lt;br /&gt;
Falls nach dem Clone noch `.applescript`-Dateien vorhanden sind, war `compile.sh` nicht erfolgreich. In diesem Fall erneut ausführen und auf Fehlermeldungen achten.&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
=== Automatische Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Nach der ersten Ausführung erstellt das System automatisch folgende Struktur in DEVONthink:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
_config/&lt;br /&gt;
├── belegversand.conf              # Konfigurationsdatei&lt;br /&gt;
├── mail_vorlagen/                 # Mail-Templates&lt;br /&gt;
│   └── belegversand               # Standard-Template&lt;br /&gt;
├── README-Belegversand            # Interne Hilfe&lt;br /&gt;
└── [weitere Dateien nach Versand]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Konfigurationsdatei ===&lt;br /&gt;
&lt;br /&gt;
Die Datei `belegversand.conf` befindet sich in DEVONthink unter `_config → belegversand.conf`.&lt;br /&gt;
&lt;br /&gt;
==== Wichtigste Parameter ====&lt;br /&gt;
&lt;br /&gt;
; MAIL_TO_DEFAULT: Standard-Empfänger (z.B. steuer@example.com)&lt;br /&gt;
&lt;br /&gt;
; MAIL_CC_TO_DEFAULT: Standard-CC-Empfänger (optional)&lt;br /&gt;
&lt;br /&gt;
; MAIL_SUBJECT_PREFIX: Präfix für den Mail-Betreff (z.B. &amp;quot;Belegversand&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
; ZIP_PASSWORD_DEFAULT: Standard-Passwort für ZIP-Archive (optional, keine Sonderzeichen)&lt;br /&gt;
&lt;br /&gt;
; LOG_SENT_GROUP_NAME: Name der Ordnergruppe für Versandprotokolle (Standard: &amp;quot;Versendet&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
; SENT_TAG_FOR_DOCS: Tag für versendete Belege (Standard: &amp;quot;gesendet&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
; WRITE_DEBUG_LOG: Debug-Logging aktivieren (true/false)&lt;br /&gt;
&lt;br /&gt;
; SHOW_README: Willkommensdialog beim Start anzeigen (true/false)&lt;br /&gt;
&lt;br /&gt;
; MAILBODY_FOLDER_NAME: Ordner für Mail-Templates (Standard: &amp;quot;mail_vorlagen&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
; MAILBODY_RECORD_NAME: Name des Standard-Templates (Standard: &amp;quot;belegversand&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
; PATH_TO_DRYRUN_PREVIEW: Speicherort der Dry-Run Vorschau-Datei&lt;br /&gt;
&lt;br /&gt;
==== Multiple Empfänger (CSV-Format) ====&lt;br /&gt;
&lt;br /&gt;
Mehrere E-Mail-Adressen können durch Kommas getrennt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
MAIL_TO_DEFAULT=recipient1@example.com, recipient2@example.com&lt;br /&gt;
MAIL_CC_TO_DEFAULT=cc1@example.com, cc2@example.com&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Adressen werden automatisch geparst und in Apple Mail einzeln eingefügt.&lt;br /&gt;
&lt;br /&gt;
== Verwendung ==&lt;br /&gt;
&lt;br /&gt;
=== Grundablauf ===&lt;br /&gt;
&lt;br /&gt;
# Belege in DEVONthink auswählen (Mehrfachauswahl möglich)&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog beantwortet (Empfänger, ZIP-Passwort, Dry-Run?)&lt;br /&gt;
# Dry-Run Vorschau anschauen (optional)&lt;br /&gt;
# Echtlauf → ZIP-Archive erstellt, Mail-Draft geöffnet, Logging durchgeführt&lt;br /&gt;
&lt;br /&gt;
=== Menü-Befehle ===&lt;br /&gt;
&lt;br /&gt;
; START: Haupteinstiegspunkt — startet Setup oder Versand&lt;br /&gt;
; About...: About-Dialog mit Versionsinformation und Links&lt;br /&gt;
&lt;br /&gt;
=== Booking-Jahr Enforcement ===&lt;br /&gt;
&lt;br /&gt;
Das System verhindert Versandvermischung über mehrere Jahre:&lt;br /&gt;
&lt;br /&gt;
; Mixed-Year Selection: Werden Belege aus verschiedenen Jahren auswählt, wird ein Fehler zurückgewiesen&lt;br /&gt;
; Separate Protokolle: Jedes Buchungsjahr hat eigene Versendet-Ordner mit separaten Logs&lt;br /&gt;
; Outsider-Belege: Dokumente außerhalb der Jahresstruktur werden separat gehandhabt&lt;br /&gt;
&lt;br /&gt;
Beispiel-Struktur:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Belege/&lt;br /&gt;
├── 2026/&lt;br /&gt;
│   ├── 01_Januar/&lt;br /&gt;
    ├── 02_Februar/&lt;br /&gt;
    ├── .../&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
├── 2027/&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
└── Provisionsabrechnungen/&lt;br /&gt;
    └── [← Separate Outsider-Logs]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dry-Run Modus ===&lt;br /&gt;
&lt;br /&gt;
Vor jedem echten Versand kann ein Dry-Run durchgeführt werden:&lt;br /&gt;
&lt;br /&gt;
# Simuliert den kompletten Versandprozess&lt;br /&gt;
# Erstellt Vorschau-Datei mit allen Details&lt;br /&gt;
# Zeigt Dialog mit Zusammenfassung&lt;br /&gt;
# User kann bestätigen oder abbrechen&lt;br /&gt;
&lt;br /&gt;
Die Vorschau-Datei wird auf der lokalen Festplatte gespeichert (Pfad konfigurierbar).&lt;br /&gt;
&lt;br /&gt;
=== Mail-Drafts ===&lt;br /&gt;
&lt;br /&gt;
Das System erstellt keinen automatischen Versand, sondern Mail-Drafts:&lt;br /&gt;
&lt;br /&gt;
# ZIP-Archive werden erzeugt&lt;br /&gt;
# Apple Mail öffnet mit neuem Draft (nicht gesendet!)&lt;br /&gt;
# User kann Template prüfen, weitere Empfänger hinzufügen&lt;br /&gt;
# Benutzerdefinierter Versand per Knopfdruck in Mail&lt;br /&gt;
&lt;br /&gt;
Dies ermöglicht volle Kontrolle über den Versand.&lt;br /&gt;
&lt;br /&gt;
=== Mail-Templates ===&lt;br /&gt;
&lt;br /&gt;
Templates werden aus DEVONthink geladen (`_config/mail_vorlagen/`).&lt;br /&gt;
&lt;br /&gt;
Das System zeigt einen Dialog zur Template-Auswahl, wenn mehrere Vorlagen vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Beispiel-Template:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Sehr geehrte/r Frau/Herr,&lt;br /&gt;
&lt;br /&gt;
beiliegend erhalten Sie die angeforderten Unterlagen.&lt;br /&gt;
&lt;br /&gt;
Mit freundlichen Grüßen&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Protokollierung ==&lt;br /&gt;
&lt;br /&gt;
Die Versandvorgänge werden jeweils doppelt protokolliert:&lt;br /&gt;
&lt;br /&gt;
1. Zum einen im maschinenlesbaren json-Format, für technische Weiterverarbeitung.&lt;br /&gt;
&lt;br /&gt;
2. Zum anderen im menschlich lesbaren Mark-Down-Textformat, mit Übersichten nach Versandlauf.&lt;br /&gt;
&lt;br /&gt;
Die Protokolle liegen entweder in der DEVONthink-Gruppe /Versendet des aktuellen Buchungsjahres. Das gilt, wenn Dokumente innerhalb eines Jahresordners liegen und einem Monat zugeordnet sind (siehe oben, Abschnitt &#039;&#039;Booking-Jahr Enforcement&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
Dokumente, die nicht Teil eines Buchungsjahres sind, werden in der Gruppe /Versendet_Outsider abgelegt. Diese Gruppe liegt neben /_config unmittel an der Datenbankwurzel.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
=== Scripts funktionieren nicht ===&lt;br /&gt;
&lt;br /&gt;
==== Problem: &amp;quot;Script nicht gefunden&amp;quot; ====&lt;br /&gt;
&lt;br /&gt;
Häufigste Ursache: `compile.sh` wurde nicht ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# Prüfen ob `.scpt`-Dateien vorhanden sind: &amp;lt;code&amp;gt;ls ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/Belegversand/Helpers/scripts/&amp;lt;/code&amp;gt;&lt;br /&gt;
# Falls nur `.applescript`-Dateien vorhanden → &amp;lt;code&amp;gt;./compile.sh&amp;lt;/code&amp;gt; erneut ausführen&lt;br /&gt;
# Auf Fehlermeldungen achten&lt;br /&gt;
&lt;br /&gt;
==== Problem: Script-Zugriff verweigert ====&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# System Settings → Privacy &amp;amp; Security → Automation&lt;br /&gt;
# DEVONthink sollte mit entsprechenden Rechten gelistet sein&lt;br /&gt;
# Script Editor öffnen und START.scpt öffnen&lt;br /&gt;
# Compile (⌘K) — sollte ohne Fehler durchlaufen&lt;br /&gt;
&lt;br /&gt;
=== ZIP wird nicht erstellt ===&lt;br /&gt;
&lt;br /&gt;
* ZIP-Passwort in Config überprüfen (keine Sonderzeichen!)&lt;br /&gt;
* Ausreichend Festplatte vorhanden?&lt;br /&gt;
* Staging-Ordner in DEVONthink beschreibbar?&lt;br /&gt;
&lt;br /&gt;
=== Mail-Draft öffnet sich nicht ===&lt;br /&gt;
&lt;br /&gt;
* Apple Mail ist geöffnet?&lt;br /&gt;
* Script-Zugriff für Mail aktiviert?&lt;br /&gt;
* Mail-Templates-Ordner vorhanden?&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Mixed-Year-Selection&amp;quot;-Fehler ===&lt;br /&gt;
&lt;br /&gt;
Dies ist kein Fehler, sondern Schutz vor Versandvermischung:&lt;br /&gt;
&lt;br /&gt;
- Lösung 1: Nur Belege aus einem Buchungsjahr auswählen&lt;br /&gt;
&lt;br /&gt;
- Lösung 2: Belege in mehreren Versänden verteilen&lt;br /&gt;
&lt;br /&gt;
=== Debug-Informationen aktivieren ===&lt;br /&gt;
&lt;br /&gt;
In `belegversand.conf`:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
WRITE_DEBUG_LOG=true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Debug-Logs erscheinen dann in `/tmp/DT-Belegversand-debug.log`.&lt;br /&gt;
&lt;br /&gt;
== Versionshistorie ==&lt;br /&gt;
&lt;br /&gt;
* 1.4: Booking-Jahr Enforcement, Kompilierungs-Automation, About-Dialog, Wiki-Integration&lt;br /&gt;
&lt;br /&gt;
* 1.3: Dry-Run Verbesserungen, Markdown-Logs&lt;br /&gt;
&lt;br /&gt;
* 1.2: Mail-Templates in DEVONthink, interne README&lt;br /&gt;
&lt;br /&gt;
* 1.1: Konfigurationssystem&lt;br /&gt;
&lt;br /&gt;
* 1.0: Erste funktionale Version&lt;br /&gt;
&lt;br /&gt;
== Entwicklung ==&lt;br /&gt;
&lt;br /&gt;
Quellcode liegt als `.applescript`-Dateien vor (lesbar, git-freundlich).&lt;br /&gt;
&lt;br /&gt;
Zur lokalen Entwicklung:&lt;br /&gt;
# Quelldateien (`.applescript`) editieren&lt;br /&gt;
# `./compile.sh` ausführen&lt;br /&gt;
# In DEVONthink testen&lt;br /&gt;
# Bei Änderungen: `./compile.sh` erneut ausführen&lt;br /&gt;
&lt;br /&gt;
== Support ==&lt;br /&gt;
&lt;br /&gt;
Für technische Fragen oder Probleme:&lt;br /&gt;
* Wiki-Dokumentation durchlesen (diese Seite)&lt;br /&gt;
* Debug-Log aktivieren und analysieren&lt;br /&gt;
* Im Gitea-Repository ein Issue erstellen (falls Zugriff vorhanden)&lt;br /&gt;
&lt;br /&gt;
== Externe Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation Repository]&lt;br /&gt;
* [https://www.devontechnologies.com DEVONthink Homepage]&lt;br /&gt;
* [https://support.apple.com/mail Apple Mail Documentation]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=323</id>
		<title>Belegversand</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=323"/>
		<updated>2026-08-18T16:47:22Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Booking-Jahr Enforcement */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Belegversand =&lt;br /&gt;
&lt;br /&gt;
== Übersicht ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Belegversand&#039;&#039;&#039; ist eine automatisierte AppleScript-Lösung zur Verwaltung von Dokumenten-Versand in DEVONthink. Das System ermöglicht es, Belege aus einer DEVONthink-Datenbank auszuwählen, diese in ZIP-Archive zu packen (optional mit Passwort) und automatische Mail-Drafts mit konfigurierbaren Empfängern zu erstellen. Zusätzlich erfolgt strukturierte Protokollierung über Logging und Tagging-Mechanismen.&lt;br /&gt;
&lt;br /&gt;
== Sicherheitstechnischer Hinweis! ==&lt;br /&gt;
&lt;br /&gt;
Ich bitte zu beachten, dass die Software allenfalls minimale Sicherheitsanforderungen erfüllt.&lt;br /&gt;
&lt;br /&gt;
    Insbesondere liegt das Passwort für&#039;s ZIP-Archiv unverschlüsselt, im Klartext, in /_config/belegversand.conf. Wer das Passwort schützen möchte, kann das über die DB-Crypto von DEVONthink selbst tun. DEVONthink hat eine Datenbank-Verschlüsselung in den Bordmitteln.&lt;br /&gt;
    Dann bleibt trotzdem der zweite Schwachpunkt: Die ZIP-Verschlüsselung wird in dieser Version 1.4 über das Shell-Tool zip -P auf der Konsolenzeile realisiert. Dahinter steckt das veraltete und kryptographisch schwache ZipCrypto-Verfahren.&lt;br /&gt;
&lt;br /&gt;
Ganz deutlich: Diese Belegversand-Automatisation hab&#039; ich mir gebaut, um Tankbelege, Einkaufszettel und Restaurant-Quittungen an die Steuerberatung zu verschicken! Dafür sind sie prima! Falls es eine Version 1.5 geben sollte, ersetze ich zip -P vermutlich durch eine starke AES-Verschlüsselung, und das Passwort kommt als Hash-Wert in die Config-Datei.&lt;br /&gt;
&lt;br /&gt;
Bis dahin jedoch gilt ganz klar: Wer mit diesen Skripten, in dieser Version 1.4, sicherheitsrelevante Dokumente verschickt, tut das auf eigene Gefahr und handelt fahrlässig!&lt;br /&gt;
&lt;br /&gt;
; Version: 1.4&lt;br /&gt;
; Plattform: macOS 10.13+&lt;br /&gt;
; Abhängigkeiten: DEVONthink 3.x, Apple Mail&lt;br /&gt;
; Lizenz: Privatgebrauch&lt;br /&gt;
; Repository: https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Voraussetzungen ===&lt;br /&gt;
&lt;br /&gt;
* macOS 10.13 oder neuer&lt;br /&gt;
* DEVONthink 3.x&lt;br /&gt;
* Apple Mail&lt;br /&gt;
* AppleScript-Zugriff in Systemeinstellungen aktiviert&lt;br /&gt;
* Git (zum Klonen des Repositories)&lt;br /&gt;
&lt;br /&gt;
=== Schritt-für-Schritt Anleitung ===&lt;br /&gt;
&lt;br /&gt;
==== 1. Verzeichnisstruktur anlegen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&lt;br /&gt;
cd ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 2. Repository klonen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation.git Belegversand&lt;br /&gt;
cd Belegversand&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 3. Scripts kompilieren ====&lt;br /&gt;
&lt;br /&gt;
Dies ist ein &#039;&#039;&#039;wichtiger Schritt&#039;&#039;&#039; und darf nicht übersprungen werden!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chmod +x compile.sh&lt;br /&gt;
./compile.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erwartete Ausgabe:&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Compiliere Belegversand AppleScripts...&lt;br /&gt;
✓ Fertig!&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 4. Erste Ausführung ====&lt;br /&gt;
&lt;br /&gt;
# DEVONthink öffnen&lt;br /&gt;
# Ein Objekt in der gewünschten Datenbank auswählen&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog folgen → Setup wird durchgeführt&lt;br /&gt;
&lt;br /&gt;
Das Setup-Script erstellt automatisch alle notwendigen Ordnerstrukturen und Konfigurationsdateien in DEVONthink.&lt;br /&gt;
&lt;br /&gt;
== Wichtig: .applescript vs. .scpt Dateien ==&lt;br /&gt;
&lt;br /&gt;
Im Repository gibt es zwei Arten von AppleScript-Dateien:&lt;br /&gt;
&lt;br /&gt;
; .applescript: Quelldateien (lesbar, nur für Entwicklung)&lt;br /&gt;
; .scpt: Kompilierte Skripte (binär, werden von DEVONthink ausgeführt)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Kritisch:&#039;&#039;&#039; Die `.applescript`-Quelldateien funktionieren &#039;&#039;&#039;nicht&#039;&#039;&#039; direkt in DEVONthink. Sie enthalten relative Pfade, die zur Laufzeit expandiert werden müssen.&lt;br /&gt;
&lt;br /&gt;
Das `compile.sh`-Script:&lt;br /&gt;
# Kompiliert alle `.applescript` zu `.scpt`&lt;br /&gt;
# Löscht anschließend die `.applescript`-Dateien&lt;br /&gt;
# Hinterlässt nur funktionsfähige `.scpt`-Dateien&lt;br /&gt;
&lt;br /&gt;
Falls nach dem Clone noch `.applescript`-Dateien vorhanden sind, war `compile.sh` nicht erfolgreich. In diesem Fall erneut ausführen und auf Fehlermeldungen achten.&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
=== Automatische Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Nach der ersten Ausführung erstellt das System automatisch folgende Struktur in DEVONthink:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
_config/&lt;br /&gt;
├── belegversand.conf              # Konfigurationsdatei&lt;br /&gt;
├── mail_vorlagen/                 # Mail-Templates&lt;br /&gt;
│   └── belegversand               # Standard-Template&lt;br /&gt;
├── README-Belegversand            # Interne Hilfe&lt;br /&gt;
└── [weitere Dateien nach Versand]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Konfigurationsdatei ===&lt;br /&gt;
&lt;br /&gt;
Die Datei `belegversand.conf` befindet sich in DEVONthink unter `_config → belegversand.conf`.&lt;br /&gt;
&lt;br /&gt;
==== Wichtigste Parameter ====&lt;br /&gt;
&lt;br /&gt;
; MAIL_TO_DEFAULT: Standard-Empfänger (z.B. steuer@example.com)&lt;br /&gt;
&lt;br /&gt;
; MAIL_CC_TO_DEFAULT: Standard-CC-Empfänger (optional)&lt;br /&gt;
&lt;br /&gt;
; MAIL_SUBJECT_PREFIX: Präfix für den Mail-Betreff (z.B. &amp;quot;Belegversand&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
; ZIP_PASSWORD_DEFAULT: Standard-Passwort für ZIP-Archive (optional, keine Sonderzeichen)&lt;br /&gt;
&lt;br /&gt;
; LOG_SENT_GROUP_NAME: Name der Ordnergruppe für Versandprotokolle (Standard: &amp;quot;Versendet&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
; SENT_TAG_FOR_DOCS: Tag für versendete Belege (Standard: &amp;quot;gesendet&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
; WRITE_DEBUG_LOG: Debug-Logging aktivieren (true/false)&lt;br /&gt;
&lt;br /&gt;
; SHOW_README: Willkommensdialog beim Start anzeigen (true/false)&lt;br /&gt;
&lt;br /&gt;
; MAILBODY_FOLDER_NAME: Ordner für Mail-Templates (Standard: &amp;quot;mail_vorlagen&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
; MAILBODY_RECORD_NAME: Name des Standard-Templates (Standard: &amp;quot;belegversand&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
; PATH_TO_DRYRUN_PREVIEW: Speicherort der Dry-Run Vorschau-Datei&lt;br /&gt;
&lt;br /&gt;
==== Multiple Empfänger (CSV-Format) ====&lt;br /&gt;
&lt;br /&gt;
Mehrere E-Mail-Adressen können durch Kommas getrennt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
MAIL_TO_DEFAULT=recipient1@example.com, recipient2@example.com&lt;br /&gt;
MAIL_CC_TO_DEFAULT=cc1@example.com, cc2@example.com&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Adressen werden automatisch geparst und in Apple Mail einzeln eingefügt.&lt;br /&gt;
&lt;br /&gt;
== Verwendung ==&lt;br /&gt;
&lt;br /&gt;
=== Grundablauf ===&lt;br /&gt;
&lt;br /&gt;
# Belege in DEVONthink auswählen (Mehrfachauswahl möglich)&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog beantwortet (Empfänger, ZIP-Passwort, Dry-Run?)&lt;br /&gt;
# Dry-Run Vorschau anschauen (optional)&lt;br /&gt;
# Echtlauf → ZIP-Archive erstellt, Mail-Draft geöffnet, Logging durchgeführt&lt;br /&gt;
&lt;br /&gt;
=== Menü-Befehle ===&lt;br /&gt;
&lt;br /&gt;
; START: Haupteinstiegspunkt — startet Setup oder Versand&lt;br /&gt;
; About...: About-Dialog mit Versionsinformation und Links&lt;br /&gt;
&lt;br /&gt;
=== Booking-Jahr Enforcement ===&lt;br /&gt;
&lt;br /&gt;
Das System verhindert Versandvermischung über mehrere Jahre:&lt;br /&gt;
&lt;br /&gt;
; Mixed-Year Selection: Werden Belege aus verschiedenen Jahren auswählt, wird ein Fehler zurückgewiesen&lt;br /&gt;
; Separate Protokolle: Jedes Buchungsjahr hat eigene Versendet-Ordner mit separaten Logs&lt;br /&gt;
; Outsider-Belege: Dokumente außerhalb der Jahresstruktur werden separat gehandhabt&lt;br /&gt;
&lt;br /&gt;
Beispiel-Struktur:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Belege/&lt;br /&gt;
├── 2026/&lt;br /&gt;
│   ├── 01_Januar/&lt;br /&gt;
    ├── 02_Februar/&lt;br /&gt;
    ├── .../&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
├── 2027/&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
└── Provisionsabrechnungen/&lt;br /&gt;
    └── [← Separate Outsider-Logs]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dry-Run Modus ===&lt;br /&gt;
&lt;br /&gt;
Vor jedem echten Versand kann ein Dry-Run durchgeführt werden:&lt;br /&gt;
&lt;br /&gt;
# Simuliert den kompletten Versandprozess&lt;br /&gt;
# Erstellt Vorschau-Datei mit allen Details&lt;br /&gt;
# Zeigt Dialog mit Zusammenfassung&lt;br /&gt;
# User kann bestätigen oder abbrechen&lt;br /&gt;
&lt;br /&gt;
Die Vorschau-Datei wird auf der lokalen Festplatte gespeichert (Pfad konfigurierbar).&lt;br /&gt;
&lt;br /&gt;
=== Mail-Drafts ===&lt;br /&gt;
&lt;br /&gt;
Das System erstellt keinen automatischen Versand, sondern Mail-Drafts:&lt;br /&gt;
&lt;br /&gt;
# ZIP-Archive werden erzeugt&lt;br /&gt;
# Apple Mail öffnet mit neuem Draft (nicht gesendet!)&lt;br /&gt;
# User kann Template prüfen, weitere Empfänger hinzufügen&lt;br /&gt;
# Benutzerdefinierter Versand per Knopfdruck in Mail&lt;br /&gt;
&lt;br /&gt;
Dies ermöglicht volle Kontrolle über den Versand.&lt;br /&gt;
&lt;br /&gt;
=== Mail-Templates ===&lt;br /&gt;
&lt;br /&gt;
Templates werden aus DEVONthink geladen (`_config/mail_vorlagen/`).&lt;br /&gt;
&lt;br /&gt;
Das System zeigt einen Dialog zur Template-Auswahl, wenn mehrere Vorlagen vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Beispiel-Template:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Sehr geehrte/r Frau/Herr,&lt;br /&gt;
&lt;br /&gt;
beiliegend erhalten Sie die angeforderten Unterlagen.&lt;br /&gt;
&lt;br /&gt;
Mit freundlichen Grüßen&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Protokollierung ==&lt;br /&gt;
&lt;br /&gt;
Die Versandvorgänge werden jeweils doppelt protokolliert:&lt;br /&gt;
&lt;br /&gt;
1. Zum einen im maschinenlesbaren json-Format, für technische Weiterverarbeitung.&lt;br /&gt;
&lt;br /&gt;
2. Zum anderen im menschlich lesbaren Mark-Down-Textformat, mit Übersichten nach Versandlauf.&lt;br /&gt;
&lt;br /&gt;
Die Protokolle liegen entweder in der DEVONthink-Gruppe /Versendet des aktuellen Buchungsjahres. Das gilt, wenn Dokumente innerhalb eines Jahresordners liegen und einem Monat zugeordnet sind (siehe oben, Abschnitt &#039;&#039;Booking-Jahr Enforcement&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
Dokumente, die nicht Teil eines Buchungsjahres sind, werden in der Gruppe /Versendet_Outsider abgelegt. Diese Gruppe liegt neben /_config unmittel an der Datenbankwurzel.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
=== Scripts funktionieren nicht ===&lt;br /&gt;
&lt;br /&gt;
==== Problem: &amp;quot;Script nicht gefunden&amp;quot; ====&lt;br /&gt;
&lt;br /&gt;
Häufigste Ursache: `compile.sh` wurde nicht ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# Prüfen ob `.scpt`-Dateien vorhanden sind: &amp;lt;code&amp;gt;ls ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/Belegversand/Helpers/scripts/&amp;lt;/code&amp;gt;&lt;br /&gt;
# Falls nur `.applescript`-Dateien vorhanden → &amp;lt;code&amp;gt;./compile.sh&amp;lt;/code&amp;gt; erneut ausführen&lt;br /&gt;
# Auf Fehlermeldungen achten&lt;br /&gt;
&lt;br /&gt;
==== Problem: Script-Zugriff verweigert ====&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# System Settings → Privacy &amp;amp; Security → Automation&lt;br /&gt;
# DEVONthink sollte mit entsprechenden Rechten gelistet sein&lt;br /&gt;
# Script Editor öffnen und START.scpt öffnen&lt;br /&gt;
# Compile (⌘K) — sollte ohne Fehler durchlaufen&lt;br /&gt;
&lt;br /&gt;
=== ZIP wird nicht erstellt ===&lt;br /&gt;
&lt;br /&gt;
* ZIP-Passwort in Config überprüfen (keine Sonderzeichen!)&lt;br /&gt;
* Ausreichend Festplatte vorhanden?&lt;br /&gt;
* Staging-Ordner in DEVONthink beschreibbar?&lt;br /&gt;
&lt;br /&gt;
=== Mail-Draft öffnet sich nicht ===&lt;br /&gt;
&lt;br /&gt;
* Apple Mail ist geöffnet?&lt;br /&gt;
* Script-Zugriff für Mail aktiviert?&lt;br /&gt;
* Mail-Templates-Ordner vorhanden?&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Mixed-Year-Selection&amp;quot;-Fehler ===&lt;br /&gt;
&lt;br /&gt;
Dies ist kein Fehler, sondern Schutz vor Versandvermischung:&lt;br /&gt;
&lt;br /&gt;
- Lösung 1: Nur Belege aus einem Buchungsjahr auswählen&lt;br /&gt;
&lt;br /&gt;
- Lösung 2: Belege in mehreren Versänden verteilen&lt;br /&gt;
&lt;br /&gt;
=== Debug-Informationen aktivieren ===&lt;br /&gt;
&lt;br /&gt;
In `belegversand.conf`:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
WRITE_DEBUG_LOG=true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Debug-Logs erscheinen dann in `/tmp/DT-Belegversand-debug.log`.&lt;br /&gt;
&lt;br /&gt;
== Versionshistorie ==&lt;br /&gt;
&lt;br /&gt;
* 1.4: Booking-Jahr Enforcement, Kompilierungs-Automation, About-Dialog, Wiki-Integration&lt;br /&gt;
&lt;br /&gt;
* 1.3: Dry-Run Verbesserungen, Markdown-Logs&lt;br /&gt;
&lt;br /&gt;
* 1.2: Mail-Templates in DEVONthink, interne README&lt;br /&gt;
&lt;br /&gt;
* 1.1: Konfigurationssystem&lt;br /&gt;
&lt;br /&gt;
* 1.0: Erste funktionale Version&lt;br /&gt;
&lt;br /&gt;
== Entwicklung ==&lt;br /&gt;
&lt;br /&gt;
Quellcode liegt als `.applescript`-Dateien vor (lesbar, git-freundlich).&lt;br /&gt;
&lt;br /&gt;
Zur lokalen Entwicklung:&lt;br /&gt;
# Quelldateien (`.applescript`) editieren&lt;br /&gt;
# `./compile.sh` ausführen&lt;br /&gt;
# In DEVONthink testen&lt;br /&gt;
# Bei Änderungen: `./compile.sh` erneut ausführen&lt;br /&gt;
&lt;br /&gt;
== Support ==&lt;br /&gt;
&lt;br /&gt;
Für technische Fragen oder Probleme:&lt;br /&gt;
* Wiki-Dokumentation durchlesen (diese Seite)&lt;br /&gt;
* Debug-Log aktivieren und analysieren&lt;br /&gt;
* Im Gitea-Repository ein Issue erstellen (falls Zugriff vorhanden)&lt;br /&gt;
&lt;br /&gt;
== Externe Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation Repository]&lt;br /&gt;
* [https://www.devontechnologies.com DEVONthink Homepage]&lt;br /&gt;
* [https://support.apple.com/mail Apple Mail Documentation]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=322</id>
		<title>Belegversand</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=322"/>
		<updated>2026-08-18T16:45:49Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Wichtigste Parameter */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Belegversand =&lt;br /&gt;
&lt;br /&gt;
== Übersicht ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Belegversand&#039;&#039;&#039; ist eine automatisierte AppleScript-Lösung zur Verwaltung von Dokumenten-Versand in DEVONthink. Das System ermöglicht es, Belege aus einer DEVONthink-Datenbank auszuwählen, diese in ZIP-Archive zu packen (optional mit Passwort) und automatische Mail-Drafts mit konfigurierbaren Empfängern zu erstellen. Zusätzlich erfolgt strukturierte Protokollierung über Logging und Tagging-Mechanismen.&lt;br /&gt;
&lt;br /&gt;
== Sicherheitstechnischer Hinweis! ==&lt;br /&gt;
&lt;br /&gt;
Ich bitte zu beachten, dass die Software allenfalls minimale Sicherheitsanforderungen erfüllt.&lt;br /&gt;
&lt;br /&gt;
    Insbesondere liegt das Passwort für&#039;s ZIP-Archiv unverschlüsselt, im Klartext, in /_config/belegversand.conf. Wer das Passwort schützen möchte, kann das über die DB-Crypto von DEVONthink selbst tun. DEVONthink hat eine Datenbank-Verschlüsselung in den Bordmitteln.&lt;br /&gt;
    Dann bleibt trotzdem der zweite Schwachpunkt: Die ZIP-Verschlüsselung wird in dieser Version 1.4 über das Shell-Tool zip -P auf der Konsolenzeile realisiert. Dahinter steckt das veraltete und kryptographisch schwache ZipCrypto-Verfahren.&lt;br /&gt;
&lt;br /&gt;
Ganz deutlich: Diese Belegversand-Automatisation hab&#039; ich mir gebaut, um Tankbelege, Einkaufszettel und Restaurant-Quittungen an die Steuerberatung zu verschicken! Dafür sind sie prima! Falls es eine Version 1.5 geben sollte, ersetze ich zip -P vermutlich durch eine starke AES-Verschlüsselung, und das Passwort kommt als Hash-Wert in die Config-Datei.&lt;br /&gt;
&lt;br /&gt;
Bis dahin jedoch gilt ganz klar: Wer mit diesen Skripten, in dieser Version 1.4, sicherheitsrelevante Dokumente verschickt, tut das auf eigene Gefahr und handelt fahrlässig!&lt;br /&gt;
&lt;br /&gt;
; Version: 1.4&lt;br /&gt;
; Plattform: macOS 10.13+&lt;br /&gt;
; Abhängigkeiten: DEVONthink 3.x, Apple Mail&lt;br /&gt;
; Lizenz: Privatgebrauch&lt;br /&gt;
; Repository: https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Voraussetzungen ===&lt;br /&gt;
&lt;br /&gt;
* macOS 10.13 oder neuer&lt;br /&gt;
* DEVONthink 3.x&lt;br /&gt;
* Apple Mail&lt;br /&gt;
* AppleScript-Zugriff in Systemeinstellungen aktiviert&lt;br /&gt;
* Git (zum Klonen des Repositories)&lt;br /&gt;
&lt;br /&gt;
=== Schritt-für-Schritt Anleitung ===&lt;br /&gt;
&lt;br /&gt;
==== 1. Verzeichnisstruktur anlegen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&lt;br /&gt;
cd ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 2. Repository klonen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation.git Belegversand&lt;br /&gt;
cd Belegversand&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 3. Scripts kompilieren ====&lt;br /&gt;
&lt;br /&gt;
Dies ist ein &#039;&#039;&#039;wichtiger Schritt&#039;&#039;&#039; und darf nicht übersprungen werden!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chmod +x compile.sh&lt;br /&gt;
./compile.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erwartete Ausgabe:&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Compiliere Belegversand AppleScripts...&lt;br /&gt;
✓ Fertig!&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 4. Erste Ausführung ====&lt;br /&gt;
&lt;br /&gt;
# DEVONthink öffnen&lt;br /&gt;
# Ein Objekt in der gewünschten Datenbank auswählen&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog folgen → Setup wird durchgeführt&lt;br /&gt;
&lt;br /&gt;
Das Setup-Script erstellt automatisch alle notwendigen Ordnerstrukturen und Konfigurationsdateien in DEVONthink.&lt;br /&gt;
&lt;br /&gt;
== Wichtig: .applescript vs. .scpt Dateien ==&lt;br /&gt;
&lt;br /&gt;
Im Repository gibt es zwei Arten von AppleScript-Dateien:&lt;br /&gt;
&lt;br /&gt;
; .applescript: Quelldateien (lesbar, nur für Entwicklung)&lt;br /&gt;
; .scpt: Kompilierte Skripte (binär, werden von DEVONthink ausgeführt)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Kritisch:&#039;&#039;&#039; Die `.applescript`-Quelldateien funktionieren &#039;&#039;&#039;nicht&#039;&#039;&#039; direkt in DEVONthink. Sie enthalten relative Pfade, die zur Laufzeit expandiert werden müssen.&lt;br /&gt;
&lt;br /&gt;
Das `compile.sh`-Script:&lt;br /&gt;
# Kompiliert alle `.applescript` zu `.scpt`&lt;br /&gt;
# Löscht anschließend die `.applescript`-Dateien&lt;br /&gt;
# Hinterlässt nur funktionsfähige `.scpt`-Dateien&lt;br /&gt;
&lt;br /&gt;
Falls nach dem Clone noch `.applescript`-Dateien vorhanden sind, war `compile.sh` nicht erfolgreich. In diesem Fall erneut ausführen und auf Fehlermeldungen achten.&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
=== Automatische Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Nach der ersten Ausführung erstellt das System automatisch folgende Struktur in DEVONthink:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
_config/&lt;br /&gt;
├── belegversand.conf              # Konfigurationsdatei&lt;br /&gt;
├── mail_vorlagen/                 # Mail-Templates&lt;br /&gt;
│   └── belegversand               # Standard-Template&lt;br /&gt;
├── README-Belegversand            # Interne Hilfe&lt;br /&gt;
└── [weitere Dateien nach Versand]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Konfigurationsdatei ===&lt;br /&gt;
&lt;br /&gt;
Die Datei `belegversand.conf` befindet sich in DEVONthink unter `_config → belegversand.conf`.&lt;br /&gt;
&lt;br /&gt;
==== Wichtigste Parameter ====&lt;br /&gt;
&lt;br /&gt;
; MAIL_TO_DEFAULT: Standard-Empfänger (z.B. steuer@example.com)&lt;br /&gt;
&lt;br /&gt;
; MAIL_CC_TO_DEFAULT: Standard-CC-Empfänger (optional)&lt;br /&gt;
&lt;br /&gt;
; MAIL_SUBJECT_PREFIX: Präfix für den Mail-Betreff (z.B. &amp;quot;Belegversand&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
; ZIP_PASSWORD_DEFAULT: Standard-Passwort für ZIP-Archive (optional, keine Sonderzeichen)&lt;br /&gt;
&lt;br /&gt;
; LOG_SENT_GROUP_NAME: Name der Ordnergruppe für Versandprotokolle (Standard: &amp;quot;Versendet&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
; SENT_TAG_FOR_DOCS: Tag für versendete Belege (Standard: &amp;quot;gesendet&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
; WRITE_DEBUG_LOG: Debug-Logging aktivieren (true/false)&lt;br /&gt;
&lt;br /&gt;
; SHOW_README: Willkommensdialog beim Start anzeigen (true/false)&lt;br /&gt;
&lt;br /&gt;
; MAILBODY_FOLDER_NAME: Ordner für Mail-Templates (Standard: &amp;quot;mail_vorlagen&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
; MAILBODY_RECORD_NAME: Name des Standard-Templates (Standard: &amp;quot;belegversand&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
; PATH_TO_DRYRUN_PREVIEW: Speicherort der Dry-Run Vorschau-Datei&lt;br /&gt;
&lt;br /&gt;
==== Multiple Empfänger (CSV-Format) ====&lt;br /&gt;
&lt;br /&gt;
Mehrere E-Mail-Adressen können durch Kommas getrennt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
MAIL_TO_DEFAULT=recipient1@example.com, recipient2@example.com&lt;br /&gt;
MAIL_CC_TO_DEFAULT=cc1@example.com, cc2@example.com&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Adressen werden automatisch geparst und in Apple Mail einzeln eingefügt.&lt;br /&gt;
&lt;br /&gt;
== Verwendung ==&lt;br /&gt;
&lt;br /&gt;
=== Grundablauf ===&lt;br /&gt;
&lt;br /&gt;
# Belege in DEVONthink auswählen (Mehrfachauswahl möglich)&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog beantwortet (Empfänger, ZIP-Passwort, Dry-Run?)&lt;br /&gt;
# Dry-Run Vorschau anschauen (optional)&lt;br /&gt;
# Echtlauf → ZIP-Archive erstellt, Mail-Draft geöffnet, Logging durchgeführt&lt;br /&gt;
&lt;br /&gt;
=== Menü-Befehle ===&lt;br /&gt;
&lt;br /&gt;
; START: Haupteinstiegspunkt — startet Setup oder Versand&lt;br /&gt;
; About...: About-Dialog mit Versionsinformation und Links&lt;br /&gt;
&lt;br /&gt;
=== Booking-Jahr Enforcement ===&lt;br /&gt;
&lt;br /&gt;
Das System verhindert Versandvermischung über mehrere Jahre:&lt;br /&gt;
&lt;br /&gt;
; Mixed-Year Selection: Werden Belege aus verschiedenen Jahren auswählt, wird ein Fehler zurückgewiesen&lt;br /&gt;
; Separate Protokolle: Jedes Buchungsjahr hat eigene Versendet-Ordner mit separaten Logs&lt;br /&gt;
; Outsider-Belege: Dokumente außerhalb der Jahresstruktur werden separat gehandhabt&lt;br /&gt;
&lt;br /&gt;
Beispiel-Struktur:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Belege/&lt;br /&gt;
├── 2026/&lt;br /&gt;
│   ├── 01_Januar/&lt;br /&gt;
    ├── 02_Februar/&lt;br /&gt;
    ├── .../&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
├── 2027/&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
└── Provisionsabrechnungen/&lt;br /&gt;
    └── [← Separate Outsider-Logs]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dry-Run Modus ===&lt;br /&gt;
&lt;br /&gt;
Vor jedem echten Versand kann ein Dry-Run durchgeführt werden:&lt;br /&gt;
&lt;br /&gt;
# Simuliert den kompletten Versandprozess&lt;br /&gt;
# Erstellt Vorschau-Datei mit allen Details&lt;br /&gt;
# Zeigt Dialog mit Zusammenfassung&lt;br /&gt;
# User kann bestätigen oder abbrechen&lt;br /&gt;
&lt;br /&gt;
Die Vorschau-Datei wird auf der lokalen Festplatte gespeichert (Pfad konfigurierbar).&lt;br /&gt;
&lt;br /&gt;
=== Mail-Drafts ===&lt;br /&gt;
&lt;br /&gt;
Das System erstellt keinen automatischen Versand, sondern Mail-Drafts:&lt;br /&gt;
&lt;br /&gt;
# ZIP-Archive werden erzeugt&lt;br /&gt;
# Apple Mail öffnet mit neuem Draft (nicht gesendet!)&lt;br /&gt;
# User kann Template prüfen, weitere Empfänger hinzufügen&lt;br /&gt;
# Benutzerdefinierter Versand per Knopfdruck in Mail&lt;br /&gt;
&lt;br /&gt;
Dies ermöglicht volle Kontrolle über den Versand.&lt;br /&gt;
&lt;br /&gt;
=== Mail-Templates ===&lt;br /&gt;
&lt;br /&gt;
Templates werden aus DEVONthink geladen (`_config/mail_vorlagen/`).&lt;br /&gt;
&lt;br /&gt;
Das System zeigt einen Dialog zur Template-Auswahl, wenn mehrere Vorlagen vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Beispiel-Template:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Sehr geehrte/r Frau/Herr,&lt;br /&gt;
&lt;br /&gt;
beiliegend erhalten Sie die angeforderten Unterlagen.&lt;br /&gt;
&lt;br /&gt;
Mit freundlichen Grüßen&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Protokollierung ==&lt;br /&gt;
&lt;br /&gt;
Die Versandvorgänge werden jeweils doppelt protokolliert:&lt;br /&gt;
&lt;br /&gt;
1. Zum einen im maschinenlesbaren json-Format, für technische Weiterverarbeitung.&lt;br /&gt;
&lt;br /&gt;
2. Zum anderen im menschlich lesbaren Mark-Down-Textformat, mit Übersichten nach Versandlauf.&lt;br /&gt;
&lt;br /&gt;
Die Protokolle liegen entweder in der DEVONthink-Gruppe /Versendet des aktuellen Buchungsjahres. Das gilt, wenn Dokumente innerhalb eines Jahresordners liegen und einem Monat zugeordnet sind (siehe oben, Abschnitt &#039;&#039;Booking-Jahr Enforcement&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
Dokumente, die nicht Teil eines Buchungsjahres sind, werden in der Gruppe /Versendet_Outsider abgelegt. Diese Gruppe liegt neben /_config unmittel an der Datenbankwurzel.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
=== Scripts funktionieren nicht ===&lt;br /&gt;
&lt;br /&gt;
==== Problem: &amp;quot;Script nicht gefunden&amp;quot; ====&lt;br /&gt;
&lt;br /&gt;
Häufigste Ursache: `compile.sh` wurde nicht ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# Prüfen ob `.scpt`-Dateien vorhanden sind: &amp;lt;code&amp;gt;ls ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/Belegversand/Helpers/scripts/&amp;lt;/code&amp;gt;&lt;br /&gt;
# Falls nur `.applescript`-Dateien vorhanden → &amp;lt;code&amp;gt;./compile.sh&amp;lt;/code&amp;gt; erneut ausführen&lt;br /&gt;
# Auf Fehlermeldungen achten&lt;br /&gt;
&lt;br /&gt;
==== Problem: Script-Zugriff verweigert ====&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# System Settings → Privacy &amp;amp; Security → Automation&lt;br /&gt;
# DEVONthink sollte mit entsprechenden Rechten gelistet sein&lt;br /&gt;
# Script Editor öffnen und START.scpt öffnen&lt;br /&gt;
# Compile (⌘K) — sollte ohne Fehler durchlaufen&lt;br /&gt;
&lt;br /&gt;
=== ZIP wird nicht erstellt ===&lt;br /&gt;
&lt;br /&gt;
* ZIP-Passwort in Config überprüfen (keine Sonderzeichen!)&lt;br /&gt;
* Ausreichend Festplatte vorhanden?&lt;br /&gt;
* Staging-Ordner in DEVONthink beschreibbar?&lt;br /&gt;
&lt;br /&gt;
=== Mail-Draft öffnet sich nicht ===&lt;br /&gt;
&lt;br /&gt;
* Apple Mail ist geöffnet?&lt;br /&gt;
* Script-Zugriff für Mail aktiviert?&lt;br /&gt;
* Mail-Templates-Ordner vorhanden?&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Mixed-Year-Selection&amp;quot;-Fehler ===&lt;br /&gt;
&lt;br /&gt;
Dies ist kein Fehler, sondern Schutz vor Versandvermischung:&lt;br /&gt;
&lt;br /&gt;
- Lösung 1: Nur Belege aus einem Buchungsjahr auswählen&lt;br /&gt;
&lt;br /&gt;
- Lösung 2: Belege in mehreren Versänden verteilen&lt;br /&gt;
&lt;br /&gt;
=== Debug-Informationen aktivieren ===&lt;br /&gt;
&lt;br /&gt;
In `belegversand.conf`:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
WRITE_DEBUG_LOG=true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Debug-Logs erscheinen dann in `/tmp/DT-Belegversand-debug.log`.&lt;br /&gt;
&lt;br /&gt;
== Versionshistorie ==&lt;br /&gt;
&lt;br /&gt;
* 1.4: Booking-Jahr Enforcement, Kompilierungs-Automation, About-Dialog, Wiki-Integration&lt;br /&gt;
&lt;br /&gt;
* 1.3: Dry-Run Verbesserungen, Markdown-Logs&lt;br /&gt;
&lt;br /&gt;
* 1.2: Mail-Templates in DEVONthink, interne README&lt;br /&gt;
&lt;br /&gt;
* 1.1: Konfigurationssystem&lt;br /&gt;
&lt;br /&gt;
* 1.0: Erste funktionale Version&lt;br /&gt;
&lt;br /&gt;
== Entwicklung ==&lt;br /&gt;
&lt;br /&gt;
Quellcode liegt als `.applescript`-Dateien vor (lesbar, git-freundlich).&lt;br /&gt;
&lt;br /&gt;
Zur lokalen Entwicklung:&lt;br /&gt;
# Quelldateien (`.applescript`) editieren&lt;br /&gt;
# `./compile.sh` ausführen&lt;br /&gt;
# In DEVONthink testen&lt;br /&gt;
# Bei Änderungen: `./compile.sh` erneut ausführen&lt;br /&gt;
&lt;br /&gt;
== Support ==&lt;br /&gt;
&lt;br /&gt;
Für technische Fragen oder Probleme:&lt;br /&gt;
* Wiki-Dokumentation durchlesen (diese Seite)&lt;br /&gt;
* Debug-Log aktivieren und analysieren&lt;br /&gt;
* Im Gitea-Repository ein Issue erstellen (falls Zugriff vorhanden)&lt;br /&gt;
&lt;br /&gt;
== Externe Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation Repository]&lt;br /&gt;
* [https://www.devontechnologies.com DEVONthink Homepage]&lt;br /&gt;
* [https://support.apple.com/mail Apple Mail Documentation]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=321</id>
		<title>Belegversand</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=321"/>
		<updated>2026-08-18T16:44:38Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Versionshistorie */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Belegversand =&lt;br /&gt;
&lt;br /&gt;
== Übersicht ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Belegversand&#039;&#039;&#039; ist eine automatisierte AppleScript-Lösung zur Verwaltung von Dokumenten-Versand in DEVONthink. Das System ermöglicht es, Belege aus einer DEVONthink-Datenbank auszuwählen, diese in ZIP-Archive zu packen (optional mit Passwort) und automatische Mail-Drafts mit konfigurierbaren Empfängern zu erstellen. Zusätzlich erfolgt strukturierte Protokollierung über Logging und Tagging-Mechanismen.&lt;br /&gt;
&lt;br /&gt;
== Sicherheitstechnischer Hinweis! ==&lt;br /&gt;
&lt;br /&gt;
Ich bitte zu beachten, dass die Software allenfalls minimale Sicherheitsanforderungen erfüllt.&lt;br /&gt;
&lt;br /&gt;
    Insbesondere liegt das Passwort für&#039;s ZIP-Archiv unverschlüsselt, im Klartext, in /_config/belegversand.conf. Wer das Passwort schützen möchte, kann das über die DB-Crypto von DEVONthink selbst tun. DEVONthink hat eine Datenbank-Verschlüsselung in den Bordmitteln.&lt;br /&gt;
    Dann bleibt trotzdem der zweite Schwachpunkt: Die ZIP-Verschlüsselung wird in dieser Version 1.4 über das Shell-Tool zip -P auf der Konsolenzeile realisiert. Dahinter steckt das veraltete und kryptographisch schwache ZipCrypto-Verfahren.&lt;br /&gt;
&lt;br /&gt;
Ganz deutlich: Diese Belegversand-Automatisation hab&#039; ich mir gebaut, um Tankbelege, Einkaufszettel und Restaurant-Quittungen an die Steuerberatung zu verschicken! Dafür sind sie prima! Falls es eine Version 1.5 geben sollte, ersetze ich zip -P vermutlich durch eine starke AES-Verschlüsselung, und das Passwort kommt als Hash-Wert in die Config-Datei.&lt;br /&gt;
&lt;br /&gt;
Bis dahin jedoch gilt ganz klar: Wer mit diesen Skripten, in dieser Version 1.4, sicherheitsrelevante Dokumente verschickt, tut das auf eigene Gefahr und handelt fahrlässig!&lt;br /&gt;
&lt;br /&gt;
; Version: 1.4&lt;br /&gt;
; Plattform: macOS 10.13+&lt;br /&gt;
; Abhängigkeiten: DEVONthink 3.x, Apple Mail&lt;br /&gt;
; Lizenz: Privatgebrauch&lt;br /&gt;
; Repository: https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Voraussetzungen ===&lt;br /&gt;
&lt;br /&gt;
* macOS 10.13 oder neuer&lt;br /&gt;
* DEVONthink 3.x&lt;br /&gt;
* Apple Mail&lt;br /&gt;
* AppleScript-Zugriff in Systemeinstellungen aktiviert&lt;br /&gt;
* Git (zum Klonen des Repositories)&lt;br /&gt;
&lt;br /&gt;
=== Schritt-für-Schritt Anleitung ===&lt;br /&gt;
&lt;br /&gt;
==== 1. Verzeichnisstruktur anlegen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&lt;br /&gt;
cd ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 2. Repository klonen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation.git Belegversand&lt;br /&gt;
cd Belegversand&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 3. Scripts kompilieren ====&lt;br /&gt;
&lt;br /&gt;
Dies ist ein &#039;&#039;&#039;wichtiger Schritt&#039;&#039;&#039; und darf nicht übersprungen werden!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chmod +x compile.sh&lt;br /&gt;
./compile.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erwartete Ausgabe:&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Compiliere Belegversand AppleScripts...&lt;br /&gt;
✓ Fertig!&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 4. Erste Ausführung ====&lt;br /&gt;
&lt;br /&gt;
# DEVONthink öffnen&lt;br /&gt;
# Ein Objekt in der gewünschten Datenbank auswählen&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog folgen → Setup wird durchgeführt&lt;br /&gt;
&lt;br /&gt;
Das Setup-Script erstellt automatisch alle notwendigen Ordnerstrukturen und Konfigurationsdateien in DEVONthink.&lt;br /&gt;
&lt;br /&gt;
== Wichtig: .applescript vs. .scpt Dateien ==&lt;br /&gt;
&lt;br /&gt;
Im Repository gibt es zwei Arten von AppleScript-Dateien:&lt;br /&gt;
&lt;br /&gt;
; .applescript: Quelldateien (lesbar, nur für Entwicklung)&lt;br /&gt;
; .scpt: Kompilierte Skripte (binär, werden von DEVONthink ausgeführt)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Kritisch:&#039;&#039;&#039; Die `.applescript`-Quelldateien funktionieren &#039;&#039;&#039;nicht&#039;&#039;&#039; direkt in DEVONthink. Sie enthalten relative Pfade, die zur Laufzeit expandiert werden müssen.&lt;br /&gt;
&lt;br /&gt;
Das `compile.sh`-Script:&lt;br /&gt;
# Kompiliert alle `.applescript` zu `.scpt`&lt;br /&gt;
# Löscht anschließend die `.applescript`-Dateien&lt;br /&gt;
# Hinterlässt nur funktionsfähige `.scpt`-Dateien&lt;br /&gt;
&lt;br /&gt;
Falls nach dem Clone noch `.applescript`-Dateien vorhanden sind, war `compile.sh` nicht erfolgreich. In diesem Fall erneut ausführen und auf Fehlermeldungen achten.&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
=== Automatische Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Nach der ersten Ausführung erstellt das System automatisch folgende Struktur in DEVONthink:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
_config/&lt;br /&gt;
├── belegversand.conf              # Konfigurationsdatei&lt;br /&gt;
├── mail_vorlagen/                 # Mail-Templates&lt;br /&gt;
│   └── belegversand               # Standard-Template&lt;br /&gt;
├── README-Belegversand            # Interne Hilfe&lt;br /&gt;
└── [weitere Dateien nach Versand]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Konfigurationsdatei ===&lt;br /&gt;
&lt;br /&gt;
Die Datei `belegversand.conf` befindet sich in DEVONthink unter `_config → belegversand.conf`.&lt;br /&gt;
&lt;br /&gt;
==== Wichtigste Parameter ====&lt;br /&gt;
&lt;br /&gt;
; MAIL_TO_DEFAULT: Standard-Empfänger (z.B. steuer@example.com)&lt;br /&gt;
; MAIL_CC_TO_DEFAULT: Standard-CC-Empfänger (optional)&lt;br /&gt;
; MAIL_SUBJECT_PREFIX: Präfix für den Mail-Betreff (z.B. &amp;quot;Belegversand&amp;quot;)&lt;br /&gt;
; ZIP_PASSWORD_DEFAULT: Standard-Passwort für ZIP-Archive (optional, keine Sonderzeichen)&lt;br /&gt;
; LOG_SENT_GROUP_NAME: Name der Ordnergruppe für Versandprotokolle (Standard: &amp;quot;Versendet&amp;quot;)&lt;br /&gt;
; SENT_TAG_FOR_DOCS: Tag für versendete Belege (Standard: &amp;quot;gesendet&amp;quot;)&lt;br /&gt;
; WRITE_DEBUG_LOG: Debug-Logging aktivieren (true/false)&lt;br /&gt;
; SHOW_README: Willkommensdialog beim Start anzeigen (true/false)&lt;br /&gt;
; MAILBODY_FOLDER_NAME: Ordner für Mail-Templates (Standard: &amp;quot;mail_vorlagen&amp;quot;)&lt;br /&gt;
; MAILBODY_RECORD_NAME: Name des Standard-Templates (Standard: &amp;quot;belegversand&amp;quot;)&lt;br /&gt;
; PATH_TO_DRYRUN_PREVIEW: Speicherort der Dry-Run Vorschau-Datei&lt;br /&gt;
&lt;br /&gt;
==== Multiple Empfänger (CSV-Format) ====&lt;br /&gt;
&lt;br /&gt;
Mehrere E-Mail-Adressen können durch Kommas getrennt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
MAIL_TO_DEFAULT=recipient1@example.com, recipient2@example.com&lt;br /&gt;
MAIL_CC_TO_DEFAULT=cc1@example.com, cc2@example.com&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Adressen werden automatisch geparst und in Apple Mail einzeln eingefügt.&lt;br /&gt;
&lt;br /&gt;
== Verwendung ==&lt;br /&gt;
&lt;br /&gt;
=== Grundablauf ===&lt;br /&gt;
&lt;br /&gt;
# Belege in DEVONthink auswählen (Mehrfachauswahl möglich)&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog beantwortet (Empfänger, ZIP-Passwort, Dry-Run?)&lt;br /&gt;
# Dry-Run Vorschau anschauen (optional)&lt;br /&gt;
# Echtlauf → ZIP-Archive erstellt, Mail-Draft geöffnet, Logging durchgeführt&lt;br /&gt;
&lt;br /&gt;
=== Menü-Befehle ===&lt;br /&gt;
&lt;br /&gt;
; START: Haupteinstiegspunkt — startet Setup oder Versand&lt;br /&gt;
; About...: About-Dialog mit Versionsinformation und Links&lt;br /&gt;
&lt;br /&gt;
=== Booking-Jahr Enforcement ===&lt;br /&gt;
&lt;br /&gt;
Das System verhindert Versandvermischung über mehrere Jahre:&lt;br /&gt;
&lt;br /&gt;
; Mixed-Year Selection: Werden Belege aus verschiedenen Jahren auswählt, wird ein Fehler zurückgewiesen&lt;br /&gt;
; Separate Protokolle: Jedes Buchungsjahr hat eigene Versendet-Ordner mit separaten Logs&lt;br /&gt;
; Outsider-Belege: Dokumente außerhalb der Jahresstruktur werden separat gehandhabt&lt;br /&gt;
&lt;br /&gt;
Beispiel-Struktur:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Belege/&lt;br /&gt;
├── 2026/&lt;br /&gt;
│   ├── 01_Januar/&lt;br /&gt;
    ├── 02_Februar/&lt;br /&gt;
    ├── .../&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
├── 2027/&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
└── Provisionsabrechnungen/&lt;br /&gt;
    └── [← Separate Outsider-Logs]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dry-Run Modus ===&lt;br /&gt;
&lt;br /&gt;
Vor jedem echten Versand kann ein Dry-Run durchgeführt werden:&lt;br /&gt;
&lt;br /&gt;
# Simuliert den kompletten Versandprozess&lt;br /&gt;
# Erstellt Vorschau-Datei mit allen Details&lt;br /&gt;
# Zeigt Dialog mit Zusammenfassung&lt;br /&gt;
# User kann bestätigen oder abbrechen&lt;br /&gt;
&lt;br /&gt;
Die Vorschau-Datei wird auf der lokalen Festplatte gespeichert (Pfad konfigurierbar).&lt;br /&gt;
&lt;br /&gt;
=== Mail-Drafts ===&lt;br /&gt;
&lt;br /&gt;
Das System erstellt keinen automatischen Versand, sondern Mail-Drafts:&lt;br /&gt;
&lt;br /&gt;
# ZIP-Archive werden erzeugt&lt;br /&gt;
# Apple Mail öffnet mit neuem Draft (nicht gesendet!)&lt;br /&gt;
# User kann Template prüfen, weitere Empfänger hinzufügen&lt;br /&gt;
# Benutzerdefinierter Versand per Knopfdruck in Mail&lt;br /&gt;
&lt;br /&gt;
Dies ermöglicht volle Kontrolle über den Versand.&lt;br /&gt;
&lt;br /&gt;
=== Mail-Templates ===&lt;br /&gt;
&lt;br /&gt;
Templates werden aus DEVONthink geladen (`_config/mail_vorlagen/`).&lt;br /&gt;
&lt;br /&gt;
Das System zeigt einen Dialog zur Template-Auswahl, wenn mehrere Vorlagen vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Beispiel-Template:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Sehr geehrte/r Frau/Herr,&lt;br /&gt;
&lt;br /&gt;
beiliegend erhalten Sie die angeforderten Unterlagen.&lt;br /&gt;
&lt;br /&gt;
Mit freundlichen Grüßen&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Protokollierung ==&lt;br /&gt;
&lt;br /&gt;
Die Versandvorgänge werden jeweils doppelt protokolliert:&lt;br /&gt;
&lt;br /&gt;
1. Zum einen im maschinenlesbaren json-Format, für technische Weiterverarbeitung.&lt;br /&gt;
&lt;br /&gt;
2. Zum anderen im menschlich lesbaren Mark-Down-Textformat, mit Übersichten nach Versandlauf.&lt;br /&gt;
&lt;br /&gt;
Die Protokolle liegen entweder in der DEVONthink-Gruppe /Versendet des aktuellen Buchungsjahres. Das gilt, wenn Dokumente innerhalb eines Jahresordners liegen und einem Monat zugeordnet sind (siehe oben, Abschnitt &#039;&#039;Booking-Jahr Enforcement&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
Dokumente, die nicht Teil eines Buchungsjahres sind, werden in der Gruppe /Versendet_Outsider abgelegt. Diese Gruppe liegt neben /_config unmittel an der Datenbankwurzel.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
=== Scripts funktionieren nicht ===&lt;br /&gt;
&lt;br /&gt;
==== Problem: &amp;quot;Script nicht gefunden&amp;quot; ====&lt;br /&gt;
&lt;br /&gt;
Häufigste Ursache: `compile.sh` wurde nicht ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# Prüfen ob `.scpt`-Dateien vorhanden sind: &amp;lt;code&amp;gt;ls ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/Belegversand/Helpers/scripts/&amp;lt;/code&amp;gt;&lt;br /&gt;
# Falls nur `.applescript`-Dateien vorhanden → &amp;lt;code&amp;gt;./compile.sh&amp;lt;/code&amp;gt; erneut ausführen&lt;br /&gt;
# Auf Fehlermeldungen achten&lt;br /&gt;
&lt;br /&gt;
==== Problem: Script-Zugriff verweigert ====&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# System Settings → Privacy &amp;amp; Security → Automation&lt;br /&gt;
# DEVONthink sollte mit entsprechenden Rechten gelistet sein&lt;br /&gt;
# Script Editor öffnen und START.scpt öffnen&lt;br /&gt;
# Compile (⌘K) — sollte ohne Fehler durchlaufen&lt;br /&gt;
&lt;br /&gt;
=== ZIP wird nicht erstellt ===&lt;br /&gt;
&lt;br /&gt;
* ZIP-Passwort in Config überprüfen (keine Sonderzeichen!)&lt;br /&gt;
* Ausreichend Festplatte vorhanden?&lt;br /&gt;
* Staging-Ordner in DEVONthink beschreibbar?&lt;br /&gt;
&lt;br /&gt;
=== Mail-Draft öffnet sich nicht ===&lt;br /&gt;
&lt;br /&gt;
* Apple Mail ist geöffnet?&lt;br /&gt;
* Script-Zugriff für Mail aktiviert?&lt;br /&gt;
* Mail-Templates-Ordner vorhanden?&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Mixed-Year-Selection&amp;quot;-Fehler ===&lt;br /&gt;
&lt;br /&gt;
Dies ist kein Fehler, sondern Schutz vor Versandvermischung:&lt;br /&gt;
&lt;br /&gt;
- Lösung 1: Nur Belege aus einem Buchungsjahr auswählen&lt;br /&gt;
&lt;br /&gt;
- Lösung 2: Belege in mehreren Versänden verteilen&lt;br /&gt;
&lt;br /&gt;
=== Debug-Informationen aktivieren ===&lt;br /&gt;
&lt;br /&gt;
In `belegversand.conf`:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
WRITE_DEBUG_LOG=true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Debug-Logs erscheinen dann in `/tmp/DT-Belegversand-debug.log`.&lt;br /&gt;
&lt;br /&gt;
== Versionshistorie ==&lt;br /&gt;
&lt;br /&gt;
* 1.4: Booking-Jahr Enforcement, Kompilierungs-Automation, About-Dialog, Wiki-Integration&lt;br /&gt;
&lt;br /&gt;
* 1.3: Dry-Run Verbesserungen, Markdown-Logs&lt;br /&gt;
&lt;br /&gt;
* 1.2: Mail-Templates in DEVONthink, interne README&lt;br /&gt;
&lt;br /&gt;
* 1.1: Konfigurationssystem&lt;br /&gt;
&lt;br /&gt;
* 1.0: Erste funktionale Version&lt;br /&gt;
&lt;br /&gt;
== Entwicklung ==&lt;br /&gt;
&lt;br /&gt;
Quellcode liegt als `.applescript`-Dateien vor (lesbar, git-freundlich).&lt;br /&gt;
&lt;br /&gt;
Zur lokalen Entwicklung:&lt;br /&gt;
# Quelldateien (`.applescript`) editieren&lt;br /&gt;
# `./compile.sh` ausführen&lt;br /&gt;
# In DEVONthink testen&lt;br /&gt;
# Bei Änderungen: `./compile.sh` erneut ausführen&lt;br /&gt;
&lt;br /&gt;
== Support ==&lt;br /&gt;
&lt;br /&gt;
Für technische Fragen oder Probleme:&lt;br /&gt;
* Wiki-Dokumentation durchlesen (diese Seite)&lt;br /&gt;
* Debug-Log aktivieren und analysieren&lt;br /&gt;
* Im Gitea-Repository ein Issue erstellen (falls Zugriff vorhanden)&lt;br /&gt;
&lt;br /&gt;
== Externe Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation Repository]&lt;br /&gt;
* [https://www.devontechnologies.com DEVONthink Homepage]&lt;br /&gt;
* [https://support.apple.com/mail Apple Mail Documentation]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=320</id>
		<title>Belegversand</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=320"/>
		<updated>2026-08-18T16:44:12Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Externe Links */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Belegversand =&lt;br /&gt;
&lt;br /&gt;
== Übersicht ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Belegversand&#039;&#039;&#039; ist eine automatisierte AppleScript-Lösung zur Verwaltung von Dokumenten-Versand in DEVONthink. Das System ermöglicht es, Belege aus einer DEVONthink-Datenbank auszuwählen, diese in ZIP-Archive zu packen (optional mit Passwort) und automatische Mail-Drafts mit konfigurierbaren Empfängern zu erstellen. Zusätzlich erfolgt strukturierte Protokollierung über Logging und Tagging-Mechanismen.&lt;br /&gt;
&lt;br /&gt;
== Sicherheitstechnischer Hinweis! ==&lt;br /&gt;
&lt;br /&gt;
Ich bitte zu beachten, dass die Software allenfalls minimale Sicherheitsanforderungen erfüllt.&lt;br /&gt;
&lt;br /&gt;
    Insbesondere liegt das Passwort für&#039;s ZIP-Archiv unverschlüsselt, im Klartext, in /_config/belegversand.conf. Wer das Passwort schützen möchte, kann das über die DB-Crypto von DEVONthink selbst tun. DEVONthink hat eine Datenbank-Verschlüsselung in den Bordmitteln.&lt;br /&gt;
    Dann bleibt trotzdem der zweite Schwachpunkt: Die ZIP-Verschlüsselung wird in dieser Version 1.4 über das Shell-Tool zip -P auf der Konsolenzeile realisiert. Dahinter steckt das veraltete und kryptographisch schwache ZipCrypto-Verfahren.&lt;br /&gt;
&lt;br /&gt;
Ganz deutlich: Diese Belegversand-Automatisation hab&#039; ich mir gebaut, um Tankbelege, Einkaufszettel und Restaurant-Quittungen an die Steuerberatung zu verschicken! Dafür sind sie prima! Falls es eine Version 1.5 geben sollte, ersetze ich zip -P vermutlich durch eine starke AES-Verschlüsselung, und das Passwort kommt als Hash-Wert in die Config-Datei.&lt;br /&gt;
&lt;br /&gt;
Bis dahin jedoch gilt ganz klar: Wer mit diesen Skripten, in dieser Version 1.4, sicherheitsrelevante Dokumente verschickt, tut das auf eigene Gefahr und handelt fahrlässig!&lt;br /&gt;
&lt;br /&gt;
; Version: 1.4&lt;br /&gt;
; Plattform: macOS 10.13+&lt;br /&gt;
; Abhängigkeiten: DEVONthink 3.x, Apple Mail&lt;br /&gt;
; Lizenz: Privatgebrauch&lt;br /&gt;
; Repository: https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Voraussetzungen ===&lt;br /&gt;
&lt;br /&gt;
* macOS 10.13 oder neuer&lt;br /&gt;
* DEVONthink 3.x&lt;br /&gt;
* Apple Mail&lt;br /&gt;
* AppleScript-Zugriff in Systemeinstellungen aktiviert&lt;br /&gt;
* Git (zum Klonen des Repositories)&lt;br /&gt;
&lt;br /&gt;
=== Schritt-für-Schritt Anleitung ===&lt;br /&gt;
&lt;br /&gt;
==== 1. Verzeichnisstruktur anlegen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&lt;br /&gt;
cd ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 2. Repository klonen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation.git Belegversand&lt;br /&gt;
cd Belegversand&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 3. Scripts kompilieren ====&lt;br /&gt;
&lt;br /&gt;
Dies ist ein &#039;&#039;&#039;wichtiger Schritt&#039;&#039;&#039; und darf nicht übersprungen werden!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chmod +x compile.sh&lt;br /&gt;
./compile.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erwartete Ausgabe:&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Compiliere Belegversand AppleScripts...&lt;br /&gt;
✓ Fertig!&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 4. Erste Ausführung ====&lt;br /&gt;
&lt;br /&gt;
# DEVONthink öffnen&lt;br /&gt;
# Ein Objekt in der gewünschten Datenbank auswählen&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog folgen → Setup wird durchgeführt&lt;br /&gt;
&lt;br /&gt;
Das Setup-Script erstellt automatisch alle notwendigen Ordnerstrukturen und Konfigurationsdateien in DEVONthink.&lt;br /&gt;
&lt;br /&gt;
== Wichtig: .applescript vs. .scpt Dateien ==&lt;br /&gt;
&lt;br /&gt;
Im Repository gibt es zwei Arten von AppleScript-Dateien:&lt;br /&gt;
&lt;br /&gt;
; .applescript: Quelldateien (lesbar, nur für Entwicklung)&lt;br /&gt;
; .scpt: Kompilierte Skripte (binär, werden von DEVONthink ausgeführt)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Kritisch:&#039;&#039;&#039; Die `.applescript`-Quelldateien funktionieren &#039;&#039;&#039;nicht&#039;&#039;&#039; direkt in DEVONthink. Sie enthalten relative Pfade, die zur Laufzeit expandiert werden müssen.&lt;br /&gt;
&lt;br /&gt;
Das `compile.sh`-Script:&lt;br /&gt;
# Kompiliert alle `.applescript` zu `.scpt`&lt;br /&gt;
# Löscht anschließend die `.applescript`-Dateien&lt;br /&gt;
# Hinterlässt nur funktionsfähige `.scpt`-Dateien&lt;br /&gt;
&lt;br /&gt;
Falls nach dem Clone noch `.applescript`-Dateien vorhanden sind, war `compile.sh` nicht erfolgreich. In diesem Fall erneut ausführen und auf Fehlermeldungen achten.&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
=== Automatische Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Nach der ersten Ausführung erstellt das System automatisch folgende Struktur in DEVONthink:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
_config/&lt;br /&gt;
├── belegversand.conf              # Konfigurationsdatei&lt;br /&gt;
├── mail_vorlagen/                 # Mail-Templates&lt;br /&gt;
│   └── belegversand               # Standard-Template&lt;br /&gt;
├── README-Belegversand            # Interne Hilfe&lt;br /&gt;
└── [weitere Dateien nach Versand]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Konfigurationsdatei ===&lt;br /&gt;
&lt;br /&gt;
Die Datei `belegversand.conf` befindet sich in DEVONthink unter `_config → belegversand.conf`.&lt;br /&gt;
&lt;br /&gt;
==== Wichtigste Parameter ====&lt;br /&gt;
&lt;br /&gt;
; MAIL_TO_DEFAULT: Standard-Empfänger (z.B. steuer@example.com)&lt;br /&gt;
; MAIL_CC_TO_DEFAULT: Standard-CC-Empfänger (optional)&lt;br /&gt;
; MAIL_SUBJECT_PREFIX: Präfix für den Mail-Betreff (z.B. &amp;quot;Belegversand&amp;quot;)&lt;br /&gt;
; ZIP_PASSWORD_DEFAULT: Standard-Passwort für ZIP-Archive (optional, keine Sonderzeichen)&lt;br /&gt;
; LOG_SENT_GROUP_NAME: Name der Ordnergruppe für Versandprotokolle (Standard: &amp;quot;Versendet&amp;quot;)&lt;br /&gt;
; SENT_TAG_FOR_DOCS: Tag für versendete Belege (Standard: &amp;quot;gesendet&amp;quot;)&lt;br /&gt;
; WRITE_DEBUG_LOG: Debug-Logging aktivieren (true/false)&lt;br /&gt;
; SHOW_README: Willkommensdialog beim Start anzeigen (true/false)&lt;br /&gt;
; MAILBODY_FOLDER_NAME: Ordner für Mail-Templates (Standard: &amp;quot;mail_vorlagen&amp;quot;)&lt;br /&gt;
; MAILBODY_RECORD_NAME: Name des Standard-Templates (Standard: &amp;quot;belegversand&amp;quot;)&lt;br /&gt;
; PATH_TO_DRYRUN_PREVIEW: Speicherort der Dry-Run Vorschau-Datei&lt;br /&gt;
&lt;br /&gt;
==== Multiple Empfänger (CSV-Format) ====&lt;br /&gt;
&lt;br /&gt;
Mehrere E-Mail-Adressen können durch Kommas getrennt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
MAIL_TO_DEFAULT=recipient1@example.com, recipient2@example.com&lt;br /&gt;
MAIL_CC_TO_DEFAULT=cc1@example.com, cc2@example.com&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Adressen werden automatisch geparst und in Apple Mail einzeln eingefügt.&lt;br /&gt;
&lt;br /&gt;
== Verwendung ==&lt;br /&gt;
&lt;br /&gt;
=== Grundablauf ===&lt;br /&gt;
&lt;br /&gt;
# Belege in DEVONthink auswählen (Mehrfachauswahl möglich)&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog beantwortet (Empfänger, ZIP-Passwort, Dry-Run?)&lt;br /&gt;
# Dry-Run Vorschau anschauen (optional)&lt;br /&gt;
# Echtlauf → ZIP-Archive erstellt, Mail-Draft geöffnet, Logging durchgeführt&lt;br /&gt;
&lt;br /&gt;
=== Menü-Befehle ===&lt;br /&gt;
&lt;br /&gt;
; START: Haupteinstiegspunkt — startet Setup oder Versand&lt;br /&gt;
; About...: About-Dialog mit Versionsinformation und Links&lt;br /&gt;
&lt;br /&gt;
=== Booking-Jahr Enforcement ===&lt;br /&gt;
&lt;br /&gt;
Das System verhindert Versandvermischung über mehrere Jahre:&lt;br /&gt;
&lt;br /&gt;
; Mixed-Year Selection: Werden Belege aus verschiedenen Jahren auswählt, wird ein Fehler zurückgewiesen&lt;br /&gt;
; Separate Protokolle: Jedes Buchungsjahr hat eigene Versendet-Ordner mit separaten Logs&lt;br /&gt;
; Outsider-Belege: Dokumente außerhalb der Jahresstruktur werden separat gehandhabt&lt;br /&gt;
&lt;br /&gt;
Beispiel-Struktur:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Belege/&lt;br /&gt;
├── 2026/&lt;br /&gt;
│   ├── 01_Januar/&lt;br /&gt;
    ├── 02_Februar/&lt;br /&gt;
    ├── .../&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
├── 2027/&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
└── Provisionsabrechnungen/&lt;br /&gt;
    └── [← Separate Outsider-Logs]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dry-Run Modus ===&lt;br /&gt;
&lt;br /&gt;
Vor jedem echten Versand kann ein Dry-Run durchgeführt werden:&lt;br /&gt;
&lt;br /&gt;
# Simuliert den kompletten Versandprozess&lt;br /&gt;
# Erstellt Vorschau-Datei mit allen Details&lt;br /&gt;
# Zeigt Dialog mit Zusammenfassung&lt;br /&gt;
# User kann bestätigen oder abbrechen&lt;br /&gt;
&lt;br /&gt;
Die Vorschau-Datei wird auf der lokalen Festplatte gespeichert (Pfad konfigurierbar).&lt;br /&gt;
&lt;br /&gt;
=== Mail-Drafts ===&lt;br /&gt;
&lt;br /&gt;
Das System erstellt keinen automatischen Versand, sondern Mail-Drafts:&lt;br /&gt;
&lt;br /&gt;
# ZIP-Archive werden erzeugt&lt;br /&gt;
# Apple Mail öffnet mit neuem Draft (nicht gesendet!)&lt;br /&gt;
# User kann Template prüfen, weitere Empfänger hinzufügen&lt;br /&gt;
# Benutzerdefinierter Versand per Knopfdruck in Mail&lt;br /&gt;
&lt;br /&gt;
Dies ermöglicht volle Kontrolle über den Versand.&lt;br /&gt;
&lt;br /&gt;
=== Mail-Templates ===&lt;br /&gt;
&lt;br /&gt;
Templates werden aus DEVONthink geladen (`_config/mail_vorlagen/`).&lt;br /&gt;
&lt;br /&gt;
Das System zeigt einen Dialog zur Template-Auswahl, wenn mehrere Vorlagen vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Beispiel-Template:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Sehr geehrte/r Frau/Herr,&lt;br /&gt;
&lt;br /&gt;
beiliegend erhalten Sie die angeforderten Unterlagen.&lt;br /&gt;
&lt;br /&gt;
Mit freundlichen Grüßen&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Protokollierung ==&lt;br /&gt;
&lt;br /&gt;
Die Versandvorgänge werden jeweils doppelt protokolliert:&lt;br /&gt;
&lt;br /&gt;
1. Zum einen im maschinenlesbaren json-Format, für technische Weiterverarbeitung.&lt;br /&gt;
&lt;br /&gt;
2. Zum anderen im menschlich lesbaren Mark-Down-Textformat, mit Übersichten nach Versandlauf.&lt;br /&gt;
&lt;br /&gt;
Die Protokolle liegen entweder in der DEVONthink-Gruppe /Versendet des aktuellen Buchungsjahres. Das gilt, wenn Dokumente innerhalb eines Jahresordners liegen und einem Monat zugeordnet sind (siehe oben, Abschnitt &#039;&#039;Booking-Jahr Enforcement&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
Dokumente, die nicht Teil eines Buchungsjahres sind, werden in der Gruppe /Versendet_Outsider abgelegt. Diese Gruppe liegt neben /_config unmittel an der Datenbankwurzel.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
=== Scripts funktionieren nicht ===&lt;br /&gt;
&lt;br /&gt;
==== Problem: &amp;quot;Script nicht gefunden&amp;quot; ====&lt;br /&gt;
&lt;br /&gt;
Häufigste Ursache: `compile.sh` wurde nicht ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# Prüfen ob `.scpt`-Dateien vorhanden sind: &amp;lt;code&amp;gt;ls ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/Belegversand/Helpers/scripts/&amp;lt;/code&amp;gt;&lt;br /&gt;
# Falls nur `.applescript`-Dateien vorhanden → &amp;lt;code&amp;gt;./compile.sh&amp;lt;/code&amp;gt; erneut ausführen&lt;br /&gt;
# Auf Fehlermeldungen achten&lt;br /&gt;
&lt;br /&gt;
==== Problem: Script-Zugriff verweigert ====&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# System Settings → Privacy &amp;amp; Security → Automation&lt;br /&gt;
# DEVONthink sollte mit entsprechenden Rechten gelistet sein&lt;br /&gt;
# Script Editor öffnen und START.scpt öffnen&lt;br /&gt;
# Compile (⌘K) — sollte ohne Fehler durchlaufen&lt;br /&gt;
&lt;br /&gt;
=== ZIP wird nicht erstellt ===&lt;br /&gt;
&lt;br /&gt;
* ZIP-Passwort in Config überprüfen (keine Sonderzeichen!)&lt;br /&gt;
* Ausreichend Festplatte vorhanden?&lt;br /&gt;
* Staging-Ordner in DEVONthink beschreibbar?&lt;br /&gt;
&lt;br /&gt;
=== Mail-Draft öffnet sich nicht ===&lt;br /&gt;
&lt;br /&gt;
* Apple Mail ist geöffnet?&lt;br /&gt;
* Script-Zugriff für Mail aktiviert?&lt;br /&gt;
* Mail-Templates-Ordner vorhanden?&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Mixed-Year-Selection&amp;quot;-Fehler ===&lt;br /&gt;
&lt;br /&gt;
Dies ist kein Fehler, sondern Schutz vor Versandvermischung:&lt;br /&gt;
&lt;br /&gt;
- Lösung 1: Nur Belege aus einem Buchungsjahr auswählen&lt;br /&gt;
&lt;br /&gt;
- Lösung 2: Belege in mehreren Versänden verteilen&lt;br /&gt;
&lt;br /&gt;
=== Debug-Informationen aktivieren ===&lt;br /&gt;
&lt;br /&gt;
In `belegversand.conf`:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
WRITE_DEBUG_LOG=true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Debug-Logs erscheinen dann in `/tmp/DT-Belegversand-debug.log`.&lt;br /&gt;
&lt;br /&gt;
== Versionshistorie ==&lt;br /&gt;
&lt;br /&gt;
- 1.4: Booking-Jahr Enforcement, Kompilierungs-Automation, About-Dialog, Wiki-Integration&lt;br /&gt;
&lt;br /&gt;
- 1.3: Dry-Run Verbesserungen, Markdown-Logs&lt;br /&gt;
&lt;br /&gt;
- 1.2: Mail-Templates in DEVONthink, interne README&lt;br /&gt;
&lt;br /&gt;
- 1.1: Konfigurationssystem&lt;br /&gt;
&lt;br /&gt;
- 1.0: Erste funktionale Version&lt;br /&gt;
&lt;br /&gt;
== Entwicklung ==&lt;br /&gt;
&lt;br /&gt;
Quellcode liegt als `.applescript`-Dateien vor (lesbar, git-freundlich).&lt;br /&gt;
&lt;br /&gt;
Zur lokalen Entwicklung:&lt;br /&gt;
# Quelldateien (`.applescript`) editieren&lt;br /&gt;
# `./compile.sh` ausführen&lt;br /&gt;
# In DEVONthink testen&lt;br /&gt;
# Bei Änderungen: `./compile.sh` erneut ausführen&lt;br /&gt;
&lt;br /&gt;
== Support ==&lt;br /&gt;
&lt;br /&gt;
Für technische Fragen oder Probleme:&lt;br /&gt;
* Wiki-Dokumentation durchlesen (diese Seite)&lt;br /&gt;
* Debug-Log aktivieren und analysieren&lt;br /&gt;
* Im Gitea-Repository ein Issue erstellen (falls Zugriff vorhanden)&lt;br /&gt;
&lt;br /&gt;
== Externe Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation Repository]&lt;br /&gt;
* [https://www.devontechnologies.com DEVONthink Homepage]&lt;br /&gt;
* [https://support.apple.com/mail Apple Mail Documentation]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=319</id>
		<title>Belegversand</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=319"/>
		<updated>2026-08-18T16:43:46Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* &amp;quot;Mixed-Year-Selection&amp;quot;-Fehler */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Belegversand =&lt;br /&gt;
&lt;br /&gt;
== Übersicht ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Belegversand&#039;&#039;&#039; ist eine automatisierte AppleScript-Lösung zur Verwaltung von Dokumenten-Versand in DEVONthink. Das System ermöglicht es, Belege aus einer DEVONthink-Datenbank auszuwählen, diese in ZIP-Archive zu packen (optional mit Passwort) und automatische Mail-Drafts mit konfigurierbaren Empfängern zu erstellen. Zusätzlich erfolgt strukturierte Protokollierung über Logging und Tagging-Mechanismen.&lt;br /&gt;
&lt;br /&gt;
== Sicherheitstechnischer Hinweis! ==&lt;br /&gt;
&lt;br /&gt;
Ich bitte zu beachten, dass die Software allenfalls minimale Sicherheitsanforderungen erfüllt.&lt;br /&gt;
&lt;br /&gt;
    Insbesondere liegt das Passwort für&#039;s ZIP-Archiv unverschlüsselt, im Klartext, in /_config/belegversand.conf. Wer das Passwort schützen möchte, kann das über die DB-Crypto von DEVONthink selbst tun. DEVONthink hat eine Datenbank-Verschlüsselung in den Bordmitteln.&lt;br /&gt;
    Dann bleibt trotzdem der zweite Schwachpunkt: Die ZIP-Verschlüsselung wird in dieser Version 1.4 über das Shell-Tool zip -P auf der Konsolenzeile realisiert. Dahinter steckt das veraltete und kryptographisch schwache ZipCrypto-Verfahren.&lt;br /&gt;
&lt;br /&gt;
Ganz deutlich: Diese Belegversand-Automatisation hab&#039; ich mir gebaut, um Tankbelege, Einkaufszettel und Restaurant-Quittungen an die Steuerberatung zu verschicken! Dafür sind sie prima! Falls es eine Version 1.5 geben sollte, ersetze ich zip -P vermutlich durch eine starke AES-Verschlüsselung, und das Passwort kommt als Hash-Wert in die Config-Datei.&lt;br /&gt;
&lt;br /&gt;
Bis dahin jedoch gilt ganz klar: Wer mit diesen Skripten, in dieser Version 1.4, sicherheitsrelevante Dokumente verschickt, tut das auf eigene Gefahr und handelt fahrlässig!&lt;br /&gt;
&lt;br /&gt;
; Version: 1.4&lt;br /&gt;
; Plattform: macOS 10.13+&lt;br /&gt;
; Abhängigkeiten: DEVONthink 3.x, Apple Mail&lt;br /&gt;
; Lizenz: Privatgebrauch&lt;br /&gt;
; Repository: https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Voraussetzungen ===&lt;br /&gt;
&lt;br /&gt;
* macOS 10.13 oder neuer&lt;br /&gt;
* DEVONthink 3.x&lt;br /&gt;
* Apple Mail&lt;br /&gt;
* AppleScript-Zugriff in Systemeinstellungen aktiviert&lt;br /&gt;
* Git (zum Klonen des Repositories)&lt;br /&gt;
&lt;br /&gt;
=== Schritt-für-Schritt Anleitung ===&lt;br /&gt;
&lt;br /&gt;
==== 1. Verzeichnisstruktur anlegen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&lt;br /&gt;
cd ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 2. Repository klonen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation.git Belegversand&lt;br /&gt;
cd Belegversand&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 3. Scripts kompilieren ====&lt;br /&gt;
&lt;br /&gt;
Dies ist ein &#039;&#039;&#039;wichtiger Schritt&#039;&#039;&#039; und darf nicht übersprungen werden!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chmod +x compile.sh&lt;br /&gt;
./compile.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erwartete Ausgabe:&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Compiliere Belegversand AppleScripts...&lt;br /&gt;
✓ Fertig!&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 4. Erste Ausführung ====&lt;br /&gt;
&lt;br /&gt;
# DEVONthink öffnen&lt;br /&gt;
# Ein Objekt in der gewünschten Datenbank auswählen&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog folgen → Setup wird durchgeführt&lt;br /&gt;
&lt;br /&gt;
Das Setup-Script erstellt automatisch alle notwendigen Ordnerstrukturen und Konfigurationsdateien in DEVONthink.&lt;br /&gt;
&lt;br /&gt;
== Wichtig: .applescript vs. .scpt Dateien ==&lt;br /&gt;
&lt;br /&gt;
Im Repository gibt es zwei Arten von AppleScript-Dateien:&lt;br /&gt;
&lt;br /&gt;
; .applescript: Quelldateien (lesbar, nur für Entwicklung)&lt;br /&gt;
; .scpt: Kompilierte Skripte (binär, werden von DEVONthink ausgeführt)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Kritisch:&#039;&#039;&#039; Die `.applescript`-Quelldateien funktionieren &#039;&#039;&#039;nicht&#039;&#039;&#039; direkt in DEVONthink. Sie enthalten relative Pfade, die zur Laufzeit expandiert werden müssen.&lt;br /&gt;
&lt;br /&gt;
Das `compile.sh`-Script:&lt;br /&gt;
# Kompiliert alle `.applescript` zu `.scpt`&lt;br /&gt;
# Löscht anschließend die `.applescript`-Dateien&lt;br /&gt;
# Hinterlässt nur funktionsfähige `.scpt`-Dateien&lt;br /&gt;
&lt;br /&gt;
Falls nach dem Clone noch `.applescript`-Dateien vorhanden sind, war `compile.sh` nicht erfolgreich. In diesem Fall erneut ausführen und auf Fehlermeldungen achten.&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
=== Automatische Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Nach der ersten Ausführung erstellt das System automatisch folgende Struktur in DEVONthink:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
_config/&lt;br /&gt;
├── belegversand.conf              # Konfigurationsdatei&lt;br /&gt;
├── mail_vorlagen/                 # Mail-Templates&lt;br /&gt;
│   └── belegversand               # Standard-Template&lt;br /&gt;
├── README-Belegversand            # Interne Hilfe&lt;br /&gt;
└── [weitere Dateien nach Versand]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Konfigurationsdatei ===&lt;br /&gt;
&lt;br /&gt;
Die Datei `belegversand.conf` befindet sich in DEVONthink unter `_config → belegversand.conf`.&lt;br /&gt;
&lt;br /&gt;
==== Wichtigste Parameter ====&lt;br /&gt;
&lt;br /&gt;
; MAIL_TO_DEFAULT: Standard-Empfänger (z.B. steuer@example.com)&lt;br /&gt;
; MAIL_CC_TO_DEFAULT: Standard-CC-Empfänger (optional)&lt;br /&gt;
; MAIL_SUBJECT_PREFIX: Präfix für den Mail-Betreff (z.B. &amp;quot;Belegversand&amp;quot;)&lt;br /&gt;
; ZIP_PASSWORD_DEFAULT: Standard-Passwort für ZIP-Archive (optional, keine Sonderzeichen)&lt;br /&gt;
; LOG_SENT_GROUP_NAME: Name der Ordnergruppe für Versandprotokolle (Standard: &amp;quot;Versendet&amp;quot;)&lt;br /&gt;
; SENT_TAG_FOR_DOCS: Tag für versendete Belege (Standard: &amp;quot;gesendet&amp;quot;)&lt;br /&gt;
; WRITE_DEBUG_LOG: Debug-Logging aktivieren (true/false)&lt;br /&gt;
; SHOW_README: Willkommensdialog beim Start anzeigen (true/false)&lt;br /&gt;
; MAILBODY_FOLDER_NAME: Ordner für Mail-Templates (Standard: &amp;quot;mail_vorlagen&amp;quot;)&lt;br /&gt;
; MAILBODY_RECORD_NAME: Name des Standard-Templates (Standard: &amp;quot;belegversand&amp;quot;)&lt;br /&gt;
; PATH_TO_DRYRUN_PREVIEW: Speicherort der Dry-Run Vorschau-Datei&lt;br /&gt;
&lt;br /&gt;
==== Multiple Empfänger (CSV-Format) ====&lt;br /&gt;
&lt;br /&gt;
Mehrere E-Mail-Adressen können durch Kommas getrennt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
MAIL_TO_DEFAULT=recipient1@example.com, recipient2@example.com&lt;br /&gt;
MAIL_CC_TO_DEFAULT=cc1@example.com, cc2@example.com&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Adressen werden automatisch geparst und in Apple Mail einzeln eingefügt.&lt;br /&gt;
&lt;br /&gt;
== Verwendung ==&lt;br /&gt;
&lt;br /&gt;
=== Grundablauf ===&lt;br /&gt;
&lt;br /&gt;
# Belege in DEVONthink auswählen (Mehrfachauswahl möglich)&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog beantwortet (Empfänger, ZIP-Passwort, Dry-Run?)&lt;br /&gt;
# Dry-Run Vorschau anschauen (optional)&lt;br /&gt;
# Echtlauf → ZIP-Archive erstellt, Mail-Draft geöffnet, Logging durchgeführt&lt;br /&gt;
&lt;br /&gt;
=== Menü-Befehle ===&lt;br /&gt;
&lt;br /&gt;
; START: Haupteinstiegspunkt — startet Setup oder Versand&lt;br /&gt;
; About...: About-Dialog mit Versionsinformation und Links&lt;br /&gt;
&lt;br /&gt;
=== Booking-Jahr Enforcement ===&lt;br /&gt;
&lt;br /&gt;
Das System verhindert Versandvermischung über mehrere Jahre:&lt;br /&gt;
&lt;br /&gt;
; Mixed-Year Selection: Werden Belege aus verschiedenen Jahren auswählt, wird ein Fehler zurückgewiesen&lt;br /&gt;
; Separate Protokolle: Jedes Buchungsjahr hat eigene Versendet-Ordner mit separaten Logs&lt;br /&gt;
; Outsider-Belege: Dokumente außerhalb der Jahresstruktur werden separat gehandhabt&lt;br /&gt;
&lt;br /&gt;
Beispiel-Struktur:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Belege/&lt;br /&gt;
├── 2026/&lt;br /&gt;
│   ├── 01_Januar/&lt;br /&gt;
    ├── 02_Februar/&lt;br /&gt;
    ├── .../&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
├── 2027/&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
└── Provisionsabrechnungen/&lt;br /&gt;
    └── [← Separate Outsider-Logs]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dry-Run Modus ===&lt;br /&gt;
&lt;br /&gt;
Vor jedem echten Versand kann ein Dry-Run durchgeführt werden:&lt;br /&gt;
&lt;br /&gt;
# Simuliert den kompletten Versandprozess&lt;br /&gt;
# Erstellt Vorschau-Datei mit allen Details&lt;br /&gt;
# Zeigt Dialog mit Zusammenfassung&lt;br /&gt;
# User kann bestätigen oder abbrechen&lt;br /&gt;
&lt;br /&gt;
Die Vorschau-Datei wird auf der lokalen Festplatte gespeichert (Pfad konfigurierbar).&lt;br /&gt;
&lt;br /&gt;
=== Mail-Drafts ===&lt;br /&gt;
&lt;br /&gt;
Das System erstellt keinen automatischen Versand, sondern Mail-Drafts:&lt;br /&gt;
&lt;br /&gt;
# ZIP-Archive werden erzeugt&lt;br /&gt;
# Apple Mail öffnet mit neuem Draft (nicht gesendet!)&lt;br /&gt;
# User kann Template prüfen, weitere Empfänger hinzufügen&lt;br /&gt;
# Benutzerdefinierter Versand per Knopfdruck in Mail&lt;br /&gt;
&lt;br /&gt;
Dies ermöglicht volle Kontrolle über den Versand.&lt;br /&gt;
&lt;br /&gt;
=== Mail-Templates ===&lt;br /&gt;
&lt;br /&gt;
Templates werden aus DEVONthink geladen (`_config/mail_vorlagen/`).&lt;br /&gt;
&lt;br /&gt;
Das System zeigt einen Dialog zur Template-Auswahl, wenn mehrere Vorlagen vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Beispiel-Template:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Sehr geehrte/r Frau/Herr,&lt;br /&gt;
&lt;br /&gt;
beiliegend erhalten Sie die angeforderten Unterlagen.&lt;br /&gt;
&lt;br /&gt;
Mit freundlichen Grüßen&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Protokollierung ==&lt;br /&gt;
&lt;br /&gt;
Die Versandvorgänge werden jeweils doppelt protokolliert:&lt;br /&gt;
&lt;br /&gt;
1. Zum einen im maschinenlesbaren json-Format, für technische Weiterverarbeitung.&lt;br /&gt;
&lt;br /&gt;
2. Zum anderen im menschlich lesbaren Mark-Down-Textformat, mit Übersichten nach Versandlauf.&lt;br /&gt;
&lt;br /&gt;
Die Protokolle liegen entweder in der DEVONthink-Gruppe /Versendet des aktuellen Buchungsjahres. Das gilt, wenn Dokumente innerhalb eines Jahresordners liegen und einem Monat zugeordnet sind (siehe oben, Abschnitt &#039;&#039;Booking-Jahr Enforcement&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
Dokumente, die nicht Teil eines Buchungsjahres sind, werden in der Gruppe /Versendet_Outsider abgelegt. Diese Gruppe liegt neben /_config unmittel an der Datenbankwurzel.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
=== Scripts funktionieren nicht ===&lt;br /&gt;
&lt;br /&gt;
==== Problem: &amp;quot;Script nicht gefunden&amp;quot; ====&lt;br /&gt;
&lt;br /&gt;
Häufigste Ursache: `compile.sh` wurde nicht ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# Prüfen ob `.scpt`-Dateien vorhanden sind: &amp;lt;code&amp;gt;ls ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/Belegversand/Helpers/scripts/&amp;lt;/code&amp;gt;&lt;br /&gt;
# Falls nur `.applescript`-Dateien vorhanden → &amp;lt;code&amp;gt;./compile.sh&amp;lt;/code&amp;gt; erneut ausführen&lt;br /&gt;
# Auf Fehlermeldungen achten&lt;br /&gt;
&lt;br /&gt;
==== Problem: Script-Zugriff verweigert ====&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# System Settings → Privacy &amp;amp; Security → Automation&lt;br /&gt;
# DEVONthink sollte mit entsprechenden Rechten gelistet sein&lt;br /&gt;
# Script Editor öffnen und START.scpt öffnen&lt;br /&gt;
# Compile (⌘K) — sollte ohne Fehler durchlaufen&lt;br /&gt;
&lt;br /&gt;
=== ZIP wird nicht erstellt ===&lt;br /&gt;
&lt;br /&gt;
* ZIP-Passwort in Config überprüfen (keine Sonderzeichen!)&lt;br /&gt;
* Ausreichend Festplatte vorhanden?&lt;br /&gt;
* Staging-Ordner in DEVONthink beschreibbar?&lt;br /&gt;
&lt;br /&gt;
=== Mail-Draft öffnet sich nicht ===&lt;br /&gt;
&lt;br /&gt;
* Apple Mail ist geöffnet?&lt;br /&gt;
* Script-Zugriff für Mail aktiviert?&lt;br /&gt;
* Mail-Templates-Ordner vorhanden?&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Mixed-Year-Selection&amp;quot;-Fehler ===&lt;br /&gt;
&lt;br /&gt;
Dies ist kein Fehler, sondern Schutz vor Versandvermischung:&lt;br /&gt;
&lt;br /&gt;
- Lösung 1: Nur Belege aus einem Buchungsjahr auswählen&lt;br /&gt;
&lt;br /&gt;
- Lösung 2: Belege in mehreren Versänden verteilen&lt;br /&gt;
&lt;br /&gt;
=== Debug-Informationen aktivieren ===&lt;br /&gt;
&lt;br /&gt;
In `belegversand.conf`:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
WRITE_DEBUG_LOG=true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Debug-Logs erscheinen dann in `/tmp/DT-Belegversand-debug.log`.&lt;br /&gt;
&lt;br /&gt;
== Versionshistorie ==&lt;br /&gt;
&lt;br /&gt;
- 1.4: Booking-Jahr Enforcement, Kompilierungs-Automation, About-Dialog, Wiki-Integration&lt;br /&gt;
&lt;br /&gt;
- 1.3: Dry-Run Verbesserungen, Markdown-Logs&lt;br /&gt;
&lt;br /&gt;
- 1.2: Mail-Templates in DEVONthink, interne README&lt;br /&gt;
&lt;br /&gt;
- 1.1: Konfigurationssystem&lt;br /&gt;
&lt;br /&gt;
- 1.0: Erste funktionale Version&lt;br /&gt;
&lt;br /&gt;
== Entwicklung ==&lt;br /&gt;
&lt;br /&gt;
Quellcode liegt als `.applescript`-Dateien vor (lesbar, git-freundlich).&lt;br /&gt;
&lt;br /&gt;
Zur lokalen Entwicklung:&lt;br /&gt;
# Quelldateien (`.applescript`) editieren&lt;br /&gt;
# `./compile.sh` ausführen&lt;br /&gt;
# In DEVONthink testen&lt;br /&gt;
# Bei Änderungen: `./compile.sh` erneut ausführen&lt;br /&gt;
&lt;br /&gt;
== Support ==&lt;br /&gt;
&lt;br /&gt;
Für technische Fragen oder Probleme:&lt;br /&gt;
* Wiki-Dokumentation durchlesen (diese Seite)&lt;br /&gt;
* Debug-Log aktivieren und analysieren&lt;br /&gt;
* Im Gitea-Repository ein Issue erstellen (falls Zugriff vorhanden)&lt;br /&gt;
&lt;br /&gt;
== Externe Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation Repository] (privat, erfordert Zugriff)&lt;br /&gt;
* [https://www.devontechnologies.com DEVONthink Homepage]&lt;br /&gt;
* [https://support.apple.com/mail Apple Mail Documentation]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=318</id>
		<title>Belegversand</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=318"/>
		<updated>2026-08-18T16:43:14Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Versionshistorie */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Belegversand =&lt;br /&gt;
&lt;br /&gt;
== Übersicht ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Belegversand&#039;&#039;&#039; ist eine automatisierte AppleScript-Lösung zur Verwaltung von Dokumenten-Versand in DEVONthink. Das System ermöglicht es, Belege aus einer DEVONthink-Datenbank auszuwählen, diese in ZIP-Archive zu packen (optional mit Passwort) und automatische Mail-Drafts mit konfigurierbaren Empfängern zu erstellen. Zusätzlich erfolgt strukturierte Protokollierung über Logging und Tagging-Mechanismen.&lt;br /&gt;
&lt;br /&gt;
== Sicherheitstechnischer Hinweis! ==&lt;br /&gt;
&lt;br /&gt;
Ich bitte zu beachten, dass die Software allenfalls minimale Sicherheitsanforderungen erfüllt.&lt;br /&gt;
&lt;br /&gt;
    Insbesondere liegt das Passwort für&#039;s ZIP-Archiv unverschlüsselt, im Klartext, in /_config/belegversand.conf. Wer das Passwort schützen möchte, kann das über die DB-Crypto von DEVONthink selbst tun. DEVONthink hat eine Datenbank-Verschlüsselung in den Bordmitteln.&lt;br /&gt;
    Dann bleibt trotzdem der zweite Schwachpunkt: Die ZIP-Verschlüsselung wird in dieser Version 1.4 über das Shell-Tool zip -P auf der Konsolenzeile realisiert. Dahinter steckt das veraltete und kryptographisch schwache ZipCrypto-Verfahren.&lt;br /&gt;
&lt;br /&gt;
Ganz deutlich: Diese Belegversand-Automatisation hab&#039; ich mir gebaut, um Tankbelege, Einkaufszettel und Restaurant-Quittungen an die Steuerberatung zu verschicken! Dafür sind sie prima! Falls es eine Version 1.5 geben sollte, ersetze ich zip -P vermutlich durch eine starke AES-Verschlüsselung, und das Passwort kommt als Hash-Wert in die Config-Datei.&lt;br /&gt;
&lt;br /&gt;
Bis dahin jedoch gilt ganz klar: Wer mit diesen Skripten, in dieser Version 1.4, sicherheitsrelevante Dokumente verschickt, tut das auf eigene Gefahr und handelt fahrlässig!&lt;br /&gt;
&lt;br /&gt;
; Version: 1.4&lt;br /&gt;
; Plattform: macOS 10.13+&lt;br /&gt;
; Abhängigkeiten: DEVONthink 3.x, Apple Mail&lt;br /&gt;
; Lizenz: Privatgebrauch&lt;br /&gt;
; Repository: https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Voraussetzungen ===&lt;br /&gt;
&lt;br /&gt;
* macOS 10.13 oder neuer&lt;br /&gt;
* DEVONthink 3.x&lt;br /&gt;
* Apple Mail&lt;br /&gt;
* AppleScript-Zugriff in Systemeinstellungen aktiviert&lt;br /&gt;
* Git (zum Klonen des Repositories)&lt;br /&gt;
&lt;br /&gt;
=== Schritt-für-Schritt Anleitung ===&lt;br /&gt;
&lt;br /&gt;
==== 1. Verzeichnisstruktur anlegen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&lt;br /&gt;
cd ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 2. Repository klonen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation.git Belegversand&lt;br /&gt;
cd Belegversand&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 3. Scripts kompilieren ====&lt;br /&gt;
&lt;br /&gt;
Dies ist ein &#039;&#039;&#039;wichtiger Schritt&#039;&#039;&#039; und darf nicht übersprungen werden!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chmod +x compile.sh&lt;br /&gt;
./compile.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erwartete Ausgabe:&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Compiliere Belegversand AppleScripts...&lt;br /&gt;
✓ Fertig!&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 4. Erste Ausführung ====&lt;br /&gt;
&lt;br /&gt;
# DEVONthink öffnen&lt;br /&gt;
# Ein Objekt in der gewünschten Datenbank auswählen&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog folgen → Setup wird durchgeführt&lt;br /&gt;
&lt;br /&gt;
Das Setup-Script erstellt automatisch alle notwendigen Ordnerstrukturen und Konfigurationsdateien in DEVONthink.&lt;br /&gt;
&lt;br /&gt;
== Wichtig: .applescript vs. .scpt Dateien ==&lt;br /&gt;
&lt;br /&gt;
Im Repository gibt es zwei Arten von AppleScript-Dateien:&lt;br /&gt;
&lt;br /&gt;
; .applescript: Quelldateien (lesbar, nur für Entwicklung)&lt;br /&gt;
; .scpt: Kompilierte Skripte (binär, werden von DEVONthink ausgeführt)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Kritisch:&#039;&#039;&#039; Die `.applescript`-Quelldateien funktionieren &#039;&#039;&#039;nicht&#039;&#039;&#039; direkt in DEVONthink. Sie enthalten relative Pfade, die zur Laufzeit expandiert werden müssen.&lt;br /&gt;
&lt;br /&gt;
Das `compile.sh`-Script:&lt;br /&gt;
# Kompiliert alle `.applescript` zu `.scpt`&lt;br /&gt;
# Löscht anschließend die `.applescript`-Dateien&lt;br /&gt;
# Hinterlässt nur funktionsfähige `.scpt`-Dateien&lt;br /&gt;
&lt;br /&gt;
Falls nach dem Clone noch `.applescript`-Dateien vorhanden sind, war `compile.sh` nicht erfolgreich. In diesem Fall erneut ausführen und auf Fehlermeldungen achten.&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
=== Automatische Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Nach der ersten Ausführung erstellt das System automatisch folgende Struktur in DEVONthink:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
_config/&lt;br /&gt;
├── belegversand.conf              # Konfigurationsdatei&lt;br /&gt;
├── mail_vorlagen/                 # Mail-Templates&lt;br /&gt;
│   └── belegversand               # Standard-Template&lt;br /&gt;
├── README-Belegversand            # Interne Hilfe&lt;br /&gt;
└── [weitere Dateien nach Versand]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Konfigurationsdatei ===&lt;br /&gt;
&lt;br /&gt;
Die Datei `belegversand.conf` befindet sich in DEVONthink unter `_config → belegversand.conf`.&lt;br /&gt;
&lt;br /&gt;
==== Wichtigste Parameter ====&lt;br /&gt;
&lt;br /&gt;
; MAIL_TO_DEFAULT: Standard-Empfänger (z.B. steuer@example.com)&lt;br /&gt;
; MAIL_CC_TO_DEFAULT: Standard-CC-Empfänger (optional)&lt;br /&gt;
; MAIL_SUBJECT_PREFIX: Präfix für den Mail-Betreff (z.B. &amp;quot;Belegversand&amp;quot;)&lt;br /&gt;
; ZIP_PASSWORD_DEFAULT: Standard-Passwort für ZIP-Archive (optional, keine Sonderzeichen)&lt;br /&gt;
; LOG_SENT_GROUP_NAME: Name der Ordnergruppe für Versandprotokolle (Standard: &amp;quot;Versendet&amp;quot;)&lt;br /&gt;
; SENT_TAG_FOR_DOCS: Tag für versendete Belege (Standard: &amp;quot;gesendet&amp;quot;)&lt;br /&gt;
; WRITE_DEBUG_LOG: Debug-Logging aktivieren (true/false)&lt;br /&gt;
; SHOW_README: Willkommensdialog beim Start anzeigen (true/false)&lt;br /&gt;
; MAILBODY_FOLDER_NAME: Ordner für Mail-Templates (Standard: &amp;quot;mail_vorlagen&amp;quot;)&lt;br /&gt;
; MAILBODY_RECORD_NAME: Name des Standard-Templates (Standard: &amp;quot;belegversand&amp;quot;)&lt;br /&gt;
; PATH_TO_DRYRUN_PREVIEW: Speicherort der Dry-Run Vorschau-Datei&lt;br /&gt;
&lt;br /&gt;
==== Multiple Empfänger (CSV-Format) ====&lt;br /&gt;
&lt;br /&gt;
Mehrere E-Mail-Adressen können durch Kommas getrennt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
MAIL_TO_DEFAULT=recipient1@example.com, recipient2@example.com&lt;br /&gt;
MAIL_CC_TO_DEFAULT=cc1@example.com, cc2@example.com&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Adressen werden automatisch geparst und in Apple Mail einzeln eingefügt.&lt;br /&gt;
&lt;br /&gt;
== Verwendung ==&lt;br /&gt;
&lt;br /&gt;
=== Grundablauf ===&lt;br /&gt;
&lt;br /&gt;
# Belege in DEVONthink auswählen (Mehrfachauswahl möglich)&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog beantwortet (Empfänger, ZIP-Passwort, Dry-Run?)&lt;br /&gt;
# Dry-Run Vorschau anschauen (optional)&lt;br /&gt;
# Echtlauf → ZIP-Archive erstellt, Mail-Draft geöffnet, Logging durchgeführt&lt;br /&gt;
&lt;br /&gt;
=== Menü-Befehle ===&lt;br /&gt;
&lt;br /&gt;
; START: Haupteinstiegspunkt — startet Setup oder Versand&lt;br /&gt;
; About...: About-Dialog mit Versionsinformation und Links&lt;br /&gt;
&lt;br /&gt;
=== Booking-Jahr Enforcement ===&lt;br /&gt;
&lt;br /&gt;
Das System verhindert Versandvermischung über mehrere Jahre:&lt;br /&gt;
&lt;br /&gt;
; Mixed-Year Selection: Werden Belege aus verschiedenen Jahren auswählt, wird ein Fehler zurückgewiesen&lt;br /&gt;
; Separate Protokolle: Jedes Buchungsjahr hat eigene Versendet-Ordner mit separaten Logs&lt;br /&gt;
; Outsider-Belege: Dokumente außerhalb der Jahresstruktur werden separat gehandhabt&lt;br /&gt;
&lt;br /&gt;
Beispiel-Struktur:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Belege/&lt;br /&gt;
├── 2026/&lt;br /&gt;
│   ├── 01_Januar/&lt;br /&gt;
    ├── 02_Februar/&lt;br /&gt;
    ├── .../&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
├── 2027/&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
└── Provisionsabrechnungen/&lt;br /&gt;
    └── [← Separate Outsider-Logs]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dry-Run Modus ===&lt;br /&gt;
&lt;br /&gt;
Vor jedem echten Versand kann ein Dry-Run durchgeführt werden:&lt;br /&gt;
&lt;br /&gt;
# Simuliert den kompletten Versandprozess&lt;br /&gt;
# Erstellt Vorschau-Datei mit allen Details&lt;br /&gt;
# Zeigt Dialog mit Zusammenfassung&lt;br /&gt;
# User kann bestätigen oder abbrechen&lt;br /&gt;
&lt;br /&gt;
Die Vorschau-Datei wird auf der lokalen Festplatte gespeichert (Pfad konfigurierbar).&lt;br /&gt;
&lt;br /&gt;
=== Mail-Drafts ===&lt;br /&gt;
&lt;br /&gt;
Das System erstellt keinen automatischen Versand, sondern Mail-Drafts:&lt;br /&gt;
&lt;br /&gt;
# ZIP-Archive werden erzeugt&lt;br /&gt;
# Apple Mail öffnet mit neuem Draft (nicht gesendet!)&lt;br /&gt;
# User kann Template prüfen, weitere Empfänger hinzufügen&lt;br /&gt;
# Benutzerdefinierter Versand per Knopfdruck in Mail&lt;br /&gt;
&lt;br /&gt;
Dies ermöglicht volle Kontrolle über den Versand.&lt;br /&gt;
&lt;br /&gt;
=== Mail-Templates ===&lt;br /&gt;
&lt;br /&gt;
Templates werden aus DEVONthink geladen (`_config/mail_vorlagen/`).&lt;br /&gt;
&lt;br /&gt;
Das System zeigt einen Dialog zur Template-Auswahl, wenn mehrere Vorlagen vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Beispiel-Template:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Sehr geehrte/r Frau/Herr,&lt;br /&gt;
&lt;br /&gt;
beiliegend erhalten Sie die angeforderten Unterlagen.&lt;br /&gt;
&lt;br /&gt;
Mit freundlichen Grüßen&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Protokollierung ==&lt;br /&gt;
&lt;br /&gt;
Die Versandvorgänge werden jeweils doppelt protokolliert:&lt;br /&gt;
&lt;br /&gt;
1. Zum einen im maschinenlesbaren json-Format, für technische Weiterverarbeitung.&lt;br /&gt;
&lt;br /&gt;
2. Zum anderen im menschlich lesbaren Mark-Down-Textformat, mit Übersichten nach Versandlauf.&lt;br /&gt;
&lt;br /&gt;
Die Protokolle liegen entweder in der DEVONthink-Gruppe /Versendet des aktuellen Buchungsjahres. Das gilt, wenn Dokumente innerhalb eines Jahresordners liegen und einem Monat zugeordnet sind (siehe oben, Abschnitt &#039;&#039;Booking-Jahr Enforcement&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
Dokumente, die nicht Teil eines Buchungsjahres sind, werden in der Gruppe /Versendet_Outsider abgelegt. Diese Gruppe liegt neben /_config unmittel an der Datenbankwurzel.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
=== Scripts funktionieren nicht ===&lt;br /&gt;
&lt;br /&gt;
==== Problem: &amp;quot;Script nicht gefunden&amp;quot; ====&lt;br /&gt;
&lt;br /&gt;
Häufigste Ursache: `compile.sh` wurde nicht ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# Prüfen ob `.scpt`-Dateien vorhanden sind: &amp;lt;code&amp;gt;ls ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/Belegversand/Helpers/scripts/&amp;lt;/code&amp;gt;&lt;br /&gt;
# Falls nur `.applescript`-Dateien vorhanden → &amp;lt;code&amp;gt;./compile.sh&amp;lt;/code&amp;gt; erneut ausführen&lt;br /&gt;
# Auf Fehlermeldungen achten&lt;br /&gt;
&lt;br /&gt;
==== Problem: Script-Zugriff verweigert ====&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# System Settings → Privacy &amp;amp; Security → Automation&lt;br /&gt;
# DEVONthink sollte mit entsprechenden Rechten gelistet sein&lt;br /&gt;
# Script Editor öffnen und START.scpt öffnen&lt;br /&gt;
# Compile (⌘K) — sollte ohne Fehler durchlaufen&lt;br /&gt;
&lt;br /&gt;
=== ZIP wird nicht erstellt ===&lt;br /&gt;
&lt;br /&gt;
* ZIP-Passwort in Config überprüfen (keine Sonderzeichen!)&lt;br /&gt;
* Ausreichend Festplatte vorhanden?&lt;br /&gt;
* Staging-Ordner in DEVONthink beschreibbar?&lt;br /&gt;
&lt;br /&gt;
=== Mail-Draft öffnet sich nicht ===&lt;br /&gt;
&lt;br /&gt;
* Apple Mail ist geöffnet?&lt;br /&gt;
* Script-Zugriff für Mail aktiviert?&lt;br /&gt;
* Mail-Templates-Ordner vorhanden?&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Mixed-Year-Selection&amp;quot;-Fehler ===&lt;br /&gt;
&lt;br /&gt;
Dies ist kein Fehler, sondern Schutz vor Versandvermischung:&lt;br /&gt;
&lt;br /&gt;
; Lösung 1: Nur Belege aus einem Buchungsjahr auswählen&lt;br /&gt;
; Lösung 2: Belege in mehreren Versänden verteilen&lt;br /&gt;
&lt;br /&gt;
=== Debug-Informationen aktivieren ===&lt;br /&gt;
&lt;br /&gt;
In `belegversand.conf`:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
WRITE_DEBUG_LOG=true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Debug-Logs erscheinen dann in `/tmp/DT-Belegversand-debug.log`.&lt;br /&gt;
&lt;br /&gt;
== Versionshistorie ==&lt;br /&gt;
&lt;br /&gt;
- 1.4: Booking-Jahr Enforcement, Kompilierungs-Automation, About-Dialog, Wiki-Integration&lt;br /&gt;
&lt;br /&gt;
- 1.3: Dry-Run Verbesserungen, Markdown-Logs&lt;br /&gt;
&lt;br /&gt;
- 1.2: Mail-Templates in DEVONthink, interne README&lt;br /&gt;
&lt;br /&gt;
- 1.1: Konfigurationssystem&lt;br /&gt;
&lt;br /&gt;
- 1.0: Erste funktionale Version&lt;br /&gt;
&lt;br /&gt;
== Entwicklung ==&lt;br /&gt;
&lt;br /&gt;
Quellcode liegt als `.applescript`-Dateien vor (lesbar, git-freundlich).&lt;br /&gt;
&lt;br /&gt;
Zur lokalen Entwicklung:&lt;br /&gt;
# Quelldateien (`.applescript`) editieren&lt;br /&gt;
# `./compile.sh` ausführen&lt;br /&gt;
# In DEVONthink testen&lt;br /&gt;
# Bei Änderungen: `./compile.sh` erneut ausführen&lt;br /&gt;
&lt;br /&gt;
== Support ==&lt;br /&gt;
&lt;br /&gt;
Für technische Fragen oder Probleme:&lt;br /&gt;
* Wiki-Dokumentation durchlesen (diese Seite)&lt;br /&gt;
* Debug-Log aktivieren und analysieren&lt;br /&gt;
* Im Gitea-Repository ein Issue erstellen (falls Zugriff vorhanden)&lt;br /&gt;
&lt;br /&gt;
== Externe Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation Repository] (privat, erfordert Zugriff)&lt;br /&gt;
* [https://www.devontechnologies.com DEVONthink Homepage]&lt;br /&gt;
* [https://support.apple.com/mail Apple Mail Documentation]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=317</id>
		<title>Belegversand</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=317"/>
		<updated>2026-08-18T16:42:50Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Versionshistorie */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Belegversand =&lt;br /&gt;
&lt;br /&gt;
== Übersicht ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Belegversand&#039;&#039;&#039; ist eine automatisierte AppleScript-Lösung zur Verwaltung von Dokumenten-Versand in DEVONthink. Das System ermöglicht es, Belege aus einer DEVONthink-Datenbank auszuwählen, diese in ZIP-Archive zu packen (optional mit Passwort) und automatische Mail-Drafts mit konfigurierbaren Empfängern zu erstellen. Zusätzlich erfolgt strukturierte Protokollierung über Logging und Tagging-Mechanismen.&lt;br /&gt;
&lt;br /&gt;
== Sicherheitstechnischer Hinweis! ==&lt;br /&gt;
&lt;br /&gt;
Ich bitte zu beachten, dass die Software allenfalls minimale Sicherheitsanforderungen erfüllt.&lt;br /&gt;
&lt;br /&gt;
    Insbesondere liegt das Passwort für&#039;s ZIP-Archiv unverschlüsselt, im Klartext, in /_config/belegversand.conf. Wer das Passwort schützen möchte, kann das über die DB-Crypto von DEVONthink selbst tun. DEVONthink hat eine Datenbank-Verschlüsselung in den Bordmitteln.&lt;br /&gt;
    Dann bleibt trotzdem der zweite Schwachpunkt: Die ZIP-Verschlüsselung wird in dieser Version 1.4 über das Shell-Tool zip -P auf der Konsolenzeile realisiert. Dahinter steckt das veraltete und kryptographisch schwache ZipCrypto-Verfahren.&lt;br /&gt;
&lt;br /&gt;
Ganz deutlich: Diese Belegversand-Automatisation hab&#039; ich mir gebaut, um Tankbelege, Einkaufszettel und Restaurant-Quittungen an die Steuerberatung zu verschicken! Dafür sind sie prima! Falls es eine Version 1.5 geben sollte, ersetze ich zip -P vermutlich durch eine starke AES-Verschlüsselung, und das Passwort kommt als Hash-Wert in die Config-Datei.&lt;br /&gt;
&lt;br /&gt;
Bis dahin jedoch gilt ganz klar: Wer mit diesen Skripten, in dieser Version 1.4, sicherheitsrelevante Dokumente verschickt, tut das auf eigene Gefahr und handelt fahrlässig!&lt;br /&gt;
&lt;br /&gt;
; Version: 1.4&lt;br /&gt;
; Plattform: macOS 10.13+&lt;br /&gt;
; Abhängigkeiten: DEVONthink 3.x, Apple Mail&lt;br /&gt;
; Lizenz: Privatgebrauch&lt;br /&gt;
; Repository: https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Voraussetzungen ===&lt;br /&gt;
&lt;br /&gt;
* macOS 10.13 oder neuer&lt;br /&gt;
* DEVONthink 3.x&lt;br /&gt;
* Apple Mail&lt;br /&gt;
* AppleScript-Zugriff in Systemeinstellungen aktiviert&lt;br /&gt;
* Git (zum Klonen des Repositories)&lt;br /&gt;
&lt;br /&gt;
=== Schritt-für-Schritt Anleitung ===&lt;br /&gt;
&lt;br /&gt;
==== 1. Verzeichnisstruktur anlegen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&lt;br /&gt;
cd ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 2. Repository klonen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation.git Belegversand&lt;br /&gt;
cd Belegversand&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 3. Scripts kompilieren ====&lt;br /&gt;
&lt;br /&gt;
Dies ist ein &#039;&#039;&#039;wichtiger Schritt&#039;&#039;&#039; und darf nicht übersprungen werden!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chmod +x compile.sh&lt;br /&gt;
./compile.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erwartete Ausgabe:&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Compiliere Belegversand AppleScripts...&lt;br /&gt;
✓ Fertig!&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 4. Erste Ausführung ====&lt;br /&gt;
&lt;br /&gt;
# DEVONthink öffnen&lt;br /&gt;
# Ein Objekt in der gewünschten Datenbank auswählen&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog folgen → Setup wird durchgeführt&lt;br /&gt;
&lt;br /&gt;
Das Setup-Script erstellt automatisch alle notwendigen Ordnerstrukturen und Konfigurationsdateien in DEVONthink.&lt;br /&gt;
&lt;br /&gt;
== Wichtig: .applescript vs. .scpt Dateien ==&lt;br /&gt;
&lt;br /&gt;
Im Repository gibt es zwei Arten von AppleScript-Dateien:&lt;br /&gt;
&lt;br /&gt;
; .applescript: Quelldateien (lesbar, nur für Entwicklung)&lt;br /&gt;
; .scpt: Kompilierte Skripte (binär, werden von DEVONthink ausgeführt)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Kritisch:&#039;&#039;&#039; Die `.applescript`-Quelldateien funktionieren &#039;&#039;&#039;nicht&#039;&#039;&#039; direkt in DEVONthink. Sie enthalten relative Pfade, die zur Laufzeit expandiert werden müssen.&lt;br /&gt;
&lt;br /&gt;
Das `compile.sh`-Script:&lt;br /&gt;
# Kompiliert alle `.applescript` zu `.scpt`&lt;br /&gt;
# Löscht anschließend die `.applescript`-Dateien&lt;br /&gt;
# Hinterlässt nur funktionsfähige `.scpt`-Dateien&lt;br /&gt;
&lt;br /&gt;
Falls nach dem Clone noch `.applescript`-Dateien vorhanden sind, war `compile.sh` nicht erfolgreich. In diesem Fall erneut ausführen und auf Fehlermeldungen achten.&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
=== Automatische Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Nach der ersten Ausführung erstellt das System automatisch folgende Struktur in DEVONthink:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
_config/&lt;br /&gt;
├── belegversand.conf              # Konfigurationsdatei&lt;br /&gt;
├── mail_vorlagen/                 # Mail-Templates&lt;br /&gt;
│   └── belegversand               # Standard-Template&lt;br /&gt;
├── README-Belegversand            # Interne Hilfe&lt;br /&gt;
└── [weitere Dateien nach Versand]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Konfigurationsdatei ===&lt;br /&gt;
&lt;br /&gt;
Die Datei `belegversand.conf` befindet sich in DEVONthink unter `_config → belegversand.conf`.&lt;br /&gt;
&lt;br /&gt;
==== Wichtigste Parameter ====&lt;br /&gt;
&lt;br /&gt;
; MAIL_TO_DEFAULT: Standard-Empfänger (z.B. steuer@example.com)&lt;br /&gt;
; MAIL_CC_TO_DEFAULT: Standard-CC-Empfänger (optional)&lt;br /&gt;
; MAIL_SUBJECT_PREFIX: Präfix für den Mail-Betreff (z.B. &amp;quot;Belegversand&amp;quot;)&lt;br /&gt;
; ZIP_PASSWORD_DEFAULT: Standard-Passwort für ZIP-Archive (optional, keine Sonderzeichen)&lt;br /&gt;
; LOG_SENT_GROUP_NAME: Name der Ordnergruppe für Versandprotokolle (Standard: &amp;quot;Versendet&amp;quot;)&lt;br /&gt;
; SENT_TAG_FOR_DOCS: Tag für versendete Belege (Standard: &amp;quot;gesendet&amp;quot;)&lt;br /&gt;
; WRITE_DEBUG_LOG: Debug-Logging aktivieren (true/false)&lt;br /&gt;
; SHOW_README: Willkommensdialog beim Start anzeigen (true/false)&lt;br /&gt;
; MAILBODY_FOLDER_NAME: Ordner für Mail-Templates (Standard: &amp;quot;mail_vorlagen&amp;quot;)&lt;br /&gt;
; MAILBODY_RECORD_NAME: Name des Standard-Templates (Standard: &amp;quot;belegversand&amp;quot;)&lt;br /&gt;
; PATH_TO_DRYRUN_PREVIEW: Speicherort der Dry-Run Vorschau-Datei&lt;br /&gt;
&lt;br /&gt;
==== Multiple Empfänger (CSV-Format) ====&lt;br /&gt;
&lt;br /&gt;
Mehrere E-Mail-Adressen können durch Kommas getrennt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
MAIL_TO_DEFAULT=recipient1@example.com, recipient2@example.com&lt;br /&gt;
MAIL_CC_TO_DEFAULT=cc1@example.com, cc2@example.com&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Adressen werden automatisch geparst und in Apple Mail einzeln eingefügt.&lt;br /&gt;
&lt;br /&gt;
== Verwendung ==&lt;br /&gt;
&lt;br /&gt;
=== Grundablauf ===&lt;br /&gt;
&lt;br /&gt;
# Belege in DEVONthink auswählen (Mehrfachauswahl möglich)&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog beantwortet (Empfänger, ZIP-Passwort, Dry-Run?)&lt;br /&gt;
# Dry-Run Vorschau anschauen (optional)&lt;br /&gt;
# Echtlauf → ZIP-Archive erstellt, Mail-Draft geöffnet, Logging durchgeführt&lt;br /&gt;
&lt;br /&gt;
=== Menü-Befehle ===&lt;br /&gt;
&lt;br /&gt;
; START: Haupteinstiegspunkt — startet Setup oder Versand&lt;br /&gt;
; About...: About-Dialog mit Versionsinformation und Links&lt;br /&gt;
&lt;br /&gt;
=== Booking-Jahr Enforcement ===&lt;br /&gt;
&lt;br /&gt;
Das System verhindert Versandvermischung über mehrere Jahre:&lt;br /&gt;
&lt;br /&gt;
; Mixed-Year Selection: Werden Belege aus verschiedenen Jahren auswählt, wird ein Fehler zurückgewiesen&lt;br /&gt;
; Separate Protokolle: Jedes Buchungsjahr hat eigene Versendet-Ordner mit separaten Logs&lt;br /&gt;
; Outsider-Belege: Dokumente außerhalb der Jahresstruktur werden separat gehandhabt&lt;br /&gt;
&lt;br /&gt;
Beispiel-Struktur:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Belege/&lt;br /&gt;
├── 2026/&lt;br /&gt;
│   ├── 01_Januar/&lt;br /&gt;
    ├── 02_Februar/&lt;br /&gt;
    ├── .../&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
├── 2027/&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
└── Provisionsabrechnungen/&lt;br /&gt;
    └── [← Separate Outsider-Logs]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dry-Run Modus ===&lt;br /&gt;
&lt;br /&gt;
Vor jedem echten Versand kann ein Dry-Run durchgeführt werden:&lt;br /&gt;
&lt;br /&gt;
# Simuliert den kompletten Versandprozess&lt;br /&gt;
# Erstellt Vorschau-Datei mit allen Details&lt;br /&gt;
# Zeigt Dialog mit Zusammenfassung&lt;br /&gt;
# User kann bestätigen oder abbrechen&lt;br /&gt;
&lt;br /&gt;
Die Vorschau-Datei wird auf der lokalen Festplatte gespeichert (Pfad konfigurierbar).&lt;br /&gt;
&lt;br /&gt;
=== Mail-Drafts ===&lt;br /&gt;
&lt;br /&gt;
Das System erstellt keinen automatischen Versand, sondern Mail-Drafts:&lt;br /&gt;
&lt;br /&gt;
# ZIP-Archive werden erzeugt&lt;br /&gt;
# Apple Mail öffnet mit neuem Draft (nicht gesendet!)&lt;br /&gt;
# User kann Template prüfen, weitere Empfänger hinzufügen&lt;br /&gt;
# Benutzerdefinierter Versand per Knopfdruck in Mail&lt;br /&gt;
&lt;br /&gt;
Dies ermöglicht volle Kontrolle über den Versand.&lt;br /&gt;
&lt;br /&gt;
=== Mail-Templates ===&lt;br /&gt;
&lt;br /&gt;
Templates werden aus DEVONthink geladen (`_config/mail_vorlagen/`).&lt;br /&gt;
&lt;br /&gt;
Das System zeigt einen Dialog zur Template-Auswahl, wenn mehrere Vorlagen vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Beispiel-Template:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Sehr geehrte/r Frau/Herr,&lt;br /&gt;
&lt;br /&gt;
beiliegend erhalten Sie die angeforderten Unterlagen.&lt;br /&gt;
&lt;br /&gt;
Mit freundlichen Grüßen&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Protokollierung ==&lt;br /&gt;
&lt;br /&gt;
Die Versandvorgänge werden jeweils doppelt protokolliert:&lt;br /&gt;
&lt;br /&gt;
1. Zum einen im maschinenlesbaren json-Format, für technische Weiterverarbeitung.&lt;br /&gt;
&lt;br /&gt;
2. Zum anderen im menschlich lesbaren Mark-Down-Textformat, mit Übersichten nach Versandlauf.&lt;br /&gt;
&lt;br /&gt;
Die Protokolle liegen entweder in der DEVONthink-Gruppe /Versendet des aktuellen Buchungsjahres. Das gilt, wenn Dokumente innerhalb eines Jahresordners liegen und einem Monat zugeordnet sind (siehe oben, Abschnitt &#039;&#039;Booking-Jahr Enforcement&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
Dokumente, die nicht Teil eines Buchungsjahres sind, werden in der Gruppe /Versendet_Outsider abgelegt. Diese Gruppe liegt neben /_config unmittel an der Datenbankwurzel.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
=== Scripts funktionieren nicht ===&lt;br /&gt;
&lt;br /&gt;
==== Problem: &amp;quot;Script nicht gefunden&amp;quot; ====&lt;br /&gt;
&lt;br /&gt;
Häufigste Ursache: `compile.sh` wurde nicht ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# Prüfen ob `.scpt`-Dateien vorhanden sind: &amp;lt;code&amp;gt;ls ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/Belegversand/Helpers/scripts/&amp;lt;/code&amp;gt;&lt;br /&gt;
# Falls nur `.applescript`-Dateien vorhanden → &amp;lt;code&amp;gt;./compile.sh&amp;lt;/code&amp;gt; erneut ausführen&lt;br /&gt;
# Auf Fehlermeldungen achten&lt;br /&gt;
&lt;br /&gt;
==== Problem: Script-Zugriff verweigert ====&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# System Settings → Privacy &amp;amp; Security → Automation&lt;br /&gt;
# DEVONthink sollte mit entsprechenden Rechten gelistet sein&lt;br /&gt;
# Script Editor öffnen und START.scpt öffnen&lt;br /&gt;
# Compile (⌘K) — sollte ohne Fehler durchlaufen&lt;br /&gt;
&lt;br /&gt;
=== ZIP wird nicht erstellt ===&lt;br /&gt;
&lt;br /&gt;
* ZIP-Passwort in Config überprüfen (keine Sonderzeichen!)&lt;br /&gt;
* Ausreichend Festplatte vorhanden?&lt;br /&gt;
* Staging-Ordner in DEVONthink beschreibbar?&lt;br /&gt;
&lt;br /&gt;
=== Mail-Draft öffnet sich nicht ===&lt;br /&gt;
&lt;br /&gt;
* Apple Mail ist geöffnet?&lt;br /&gt;
* Script-Zugriff für Mail aktiviert?&lt;br /&gt;
* Mail-Templates-Ordner vorhanden?&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Mixed-Year-Selection&amp;quot;-Fehler ===&lt;br /&gt;
&lt;br /&gt;
Dies ist kein Fehler, sondern Schutz vor Versandvermischung:&lt;br /&gt;
&lt;br /&gt;
; Lösung 1: Nur Belege aus einem Buchungsjahr auswählen&lt;br /&gt;
; Lösung 2: Belege in mehreren Versänden verteilen&lt;br /&gt;
&lt;br /&gt;
=== Debug-Informationen aktivieren ===&lt;br /&gt;
&lt;br /&gt;
In `belegversand.conf`:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
WRITE_DEBUG_LOG=true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Debug-Logs erscheinen dann in `/tmp/DT-Belegversand-debug.log`.&lt;br /&gt;
&lt;br /&gt;
== Versionshistorie ==&lt;br /&gt;
&lt;br /&gt;
- 1.4: Booking-Jahr Enforcement, Kompilierungs-Automation, About-Dialog, Wiki-Integration&lt;br /&gt;
- 1.3: Dry-Run Verbesserungen, Markdown-Logs&lt;br /&gt;
- 1.2: Mail-Templates in DEVONthink, interne README&lt;br /&gt;
- 1.1: Konfigurationssystem&lt;br /&gt;
- 1.0: Erste funktionale Version&lt;br /&gt;
&lt;br /&gt;
== Entwicklung ==&lt;br /&gt;
&lt;br /&gt;
Quellcode liegt als `.applescript`-Dateien vor (lesbar, git-freundlich).&lt;br /&gt;
&lt;br /&gt;
Zur lokalen Entwicklung:&lt;br /&gt;
# Quelldateien (`.applescript`) editieren&lt;br /&gt;
# `./compile.sh` ausführen&lt;br /&gt;
# In DEVONthink testen&lt;br /&gt;
# Bei Änderungen: `./compile.sh` erneut ausführen&lt;br /&gt;
&lt;br /&gt;
== Support ==&lt;br /&gt;
&lt;br /&gt;
Für technische Fragen oder Probleme:&lt;br /&gt;
* Wiki-Dokumentation durchlesen (diese Seite)&lt;br /&gt;
* Debug-Log aktivieren und analysieren&lt;br /&gt;
* Im Gitea-Repository ein Issue erstellen (falls Zugriff vorhanden)&lt;br /&gt;
&lt;br /&gt;
== Externe Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation Repository] (privat, erfordert Zugriff)&lt;br /&gt;
* [https://www.devontechnologies.com DEVONthink Homepage]&lt;br /&gt;
* [https://support.apple.com/mail Apple Mail Documentation]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=316</id>
		<title>Belegversand</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=316"/>
		<updated>2026-08-18T16:42:24Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Protokollierung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Belegversand =&lt;br /&gt;
&lt;br /&gt;
== Übersicht ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Belegversand&#039;&#039;&#039; ist eine automatisierte AppleScript-Lösung zur Verwaltung von Dokumenten-Versand in DEVONthink. Das System ermöglicht es, Belege aus einer DEVONthink-Datenbank auszuwählen, diese in ZIP-Archive zu packen (optional mit Passwort) und automatische Mail-Drafts mit konfigurierbaren Empfängern zu erstellen. Zusätzlich erfolgt strukturierte Protokollierung über Logging und Tagging-Mechanismen.&lt;br /&gt;
&lt;br /&gt;
== Sicherheitstechnischer Hinweis! ==&lt;br /&gt;
&lt;br /&gt;
Ich bitte zu beachten, dass die Software allenfalls minimale Sicherheitsanforderungen erfüllt.&lt;br /&gt;
&lt;br /&gt;
    Insbesondere liegt das Passwort für&#039;s ZIP-Archiv unverschlüsselt, im Klartext, in /_config/belegversand.conf. Wer das Passwort schützen möchte, kann das über die DB-Crypto von DEVONthink selbst tun. DEVONthink hat eine Datenbank-Verschlüsselung in den Bordmitteln.&lt;br /&gt;
    Dann bleibt trotzdem der zweite Schwachpunkt: Die ZIP-Verschlüsselung wird in dieser Version 1.4 über das Shell-Tool zip -P auf der Konsolenzeile realisiert. Dahinter steckt das veraltete und kryptographisch schwache ZipCrypto-Verfahren.&lt;br /&gt;
&lt;br /&gt;
Ganz deutlich: Diese Belegversand-Automatisation hab&#039; ich mir gebaut, um Tankbelege, Einkaufszettel und Restaurant-Quittungen an die Steuerberatung zu verschicken! Dafür sind sie prima! Falls es eine Version 1.5 geben sollte, ersetze ich zip -P vermutlich durch eine starke AES-Verschlüsselung, und das Passwort kommt als Hash-Wert in die Config-Datei.&lt;br /&gt;
&lt;br /&gt;
Bis dahin jedoch gilt ganz klar: Wer mit diesen Skripten, in dieser Version 1.4, sicherheitsrelevante Dokumente verschickt, tut das auf eigene Gefahr und handelt fahrlässig!&lt;br /&gt;
&lt;br /&gt;
; Version: 1.4&lt;br /&gt;
; Plattform: macOS 10.13+&lt;br /&gt;
; Abhängigkeiten: DEVONthink 3.x, Apple Mail&lt;br /&gt;
; Lizenz: Privatgebrauch&lt;br /&gt;
; Repository: https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Voraussetzungen ===&lt;br /&gt;
&lt;br /&gt;
* macOS 10.13 oder neuer&lt;br /&gt;
* DEVONthink 3.x&lt;br /&gt;
* Apple Mail&lt;br /&gt;
* AppleScript-Zugriff in Systemeinstellungen aktiviert&lt;br /&gt;
* Git (zum Klonen des Repositories)&lt;br /&gt;
&lt;br /&gt;
=== Schritt-für-Schritt Anleitung ===&lt;br /&gt;
&lt;br /&gt;
==== 1. Verzeichnisstruktur anlegen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&lt;br /&gt;
cd ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 2. Repository klonen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation.git Belegversand&lt;br /&gt;
cd Belegversand&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 3. Scripts kompilieren ====&lt;br /&gt;
&lt;br /&gt;
Dies ist ein &#039;&#039;&#039;wichtiger Schritt&#039;&#039;&#039; und darf nicht übersprungen werden!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chmod +x compile.sh&lt;br /&gt;
./compile.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erwartete Ausgabe:&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Compiliere Belegversand AppleScripts...&lt;br /&gt;
✓ Fertig!&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 4. Erste Ausführung ====&lt;br /&gt;
&lt;br /&gt;
# DEVONthink öffnen&lt;br /&gt;
# Ein Objekt in der gewünschten Datenbank auswählen&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog folgen → Setup wird durchgeführt&lt;br /&gt;
&lt;br /&gt;
Das Setup-Script erstellt automatisch alle notwendigen Ordnerstrukturen und Konfigurationsdateien in DEVONthink.&lt;br /&gt;
&lt;br /&gt;
== Wichtig: .applescript vs. .scpt Dateien ==&lt;br /&gt;
&lt;br /&gt;
Im Repository gibt es zwei Arten von AppleScript-Dateien:&lt;br /&gt;
&lt;br /&gt;
; .applescript: Quelldateien (lesbar, nur für Entwicklung)&lt;br /&gt;
; .scpt: Kompilierte Skripte (binär, werden von DEVONthink ausgeführt)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Kritisch:&#039;&#039;&#039; Die `.applescript`-Quelldateien funktionieren &#039;&#039;&#039;nicht&#039;&#039;&#039; direkt in DEVONthink. Sie enthalten relative Pfade, die zur Laufzeit expandiert werden müssen.&lt;br /&gt;
&lt;br /&gt;
Das `compile.sh`-Script:&lt;br /&gt;
# Kompiliert alle `.applescript` zu `.scpt`&lt;br /&gt;
# Löscht anschließend die `.applescript`-Dateien&lt;br /&gt;
# Hinterlässt nur funktionsfähige `.scpt`-Dateien&lt;br /&gt;
&lt;br /&gt;
Falls nach dem Clone noch `.applescript`-Dateien vorhanden sind, war `compile.sh` nicht erfolgreich. In diesem Fall erneut ausführen und auf Fehlermeldungen achten.&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
=== Automatische Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Nach der ersten Ausführung erstellt das System automatisch folgende Struktur in DEVONthink:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
_config/&lt;br /&gt;
├── belegversand.conf              # Konfigurationsdatei&lt;br /&gt;
├── mail_vorlagen/                 # Mail-Templates&lt;br /&gt;
│   └── belegversand               # Standard-Template&lt;br /&gt;
├── README-Belegversand            # Interne Hilfe&lt;br /&gt;
└── [weitere Dateien nach Versand]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Konfigurationsdatei ===&lt;br /&gt;
&lt;br /&gt;
Die Datei `belegversand.conf` befindet sich in DEVONthink unter `_config → belegversand.conf`.&lt;br /&gt;
&lt;br /&gt;
==== Wichtigste Parameter ====&lt;br /&gt;
&lt;br /&gt;
; MAIL_TO_DEFAULT: Standard-Empfänger (z.B. steuer@example.com)&lt;br /&gt;
; MAIL_CC_TO_DEFAULT: Standard-CC-Empfänger (optional)&lt;br /&gt;
; MAIL_SUBJECT_PREFIX: Präfix für den Mail-Betreff (z.B. &amp;quot;Belegversand&amp;quot;)&lt;br /&gt;
; ZIP_PASSWORD_DEFAULT: Standard-Passwort für ZIP-Archive (optional, keine Sonderzeichen)&lt;br /&gt;
; LOG_SENT_GROUP_NAME: Name der Ordnergruppe für Versandprotokolle (Standard: &amp;quot;Versendet&amp;quot;)&lt;br /&gt;
; SENT_TAG_FOR_DOCS: Tag für versendete Belege (Standard: &amp;quot;gesendet&amp;quot;)&lt;br /&gt;
; WRITE_DEBUG_LOG: Debug-Logging aktivieren (true/false)&lt;br /&gt;
; SHOW_README: Willkommensdialog beim Start anzeigen (true/false)&lt;br /&gt;
; MAILBODY_FOLDER_NAME: Ordner für Mail-Templates (Standard: &amp;quot;mail_vorlagen&amp;quot;)&lt;br /&gt;
; MAILBODY_RECORD_NAME: Name des Standard-Templates (Standard: &amp;quot;belegversand&amp;quot;)&lt;br /&gt;
; PATH_TO_DRYRUN_PREVIEW: Speicherort der Dry-Run Vorschau-Datei&lt;br /&gt;
&lt;br /&gt;
==== Multiple Empfänger (CSV-Format) ====&lt;br /&gt;
&lt;br /&gt;
Mehrere E-Mail-Adressen können durch Kommas getrennt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
MAIL_TO_DEFAULT=recipient1@example.com, recipient2@example.com&lt;br /&gt;
MAIL_CC_TO_DEFAULT=cc1@example.com, cc2@example.com&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Adressen werden automatisch geparst und in Apple Mail einzeln eingefügt.&lt;br /&gt;
&lt;br /&gt;
== Verwendung ==&lt;br /&gt;
&lt;br /&gt;
=== Grundablauf ===&lt;br /&gt;
&lt;br /&gt;
# Belege in DEVONthink auswählen (Mehrfachauswahl möglich)&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog beantwortet (Empfänger, ZIP-Passwort, Dry-Run?)&lt;br /&gt;
# Dry-Run Vorschau anschauen (optional)&lt;br /&gt;
# Echtlauf → ZIP-Archive erstellt, Mail-Draft geöffnet, Logging durchgeführt&lt;br /&gt;
&lt;br /&gt;
=== Menü-Befehle ===&lt;br /&gt;
&lt;br /&gt;
; START: Haupteinstiegspunkt — startet Setup oder Versand&lt;br /&gt;
; About...: About-Dialog mit Versionsinformation und Links&lt;br /&gt;
&lt;br /&gt;
=== Booking-Jahr Enforcement ===&lt;br /&gt;
&lt;br /&gt;
Das System verhindert Versandvermischung über mehrere Jahre:&lt;br /&gt;
&lt;br /&gt;
; Mixed-Year Selection: Werden Belege aus verschiedenen Jahren auswählt, wird ein Fehler zurückgewiesen&lt;br /&gt;
; Separate Protokolle: Jedes Buchungsjahr hat eigene Versendet-Ordner mit separaten Logs&lt;br /&gt;
; Outsider-Belege: Dokumente außerhalb der Jahresstruktur werden separat gehandhabt&lt;br /&gt;
&lt;br /&gt;
Beispiel-Struktur:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Belege/&lt;br /&gt;
├── 2026/&lt;br /&gt;
│   ├── 01_Januar/&lt;br /&gt;
    ├── 02_Februar/&lt;br /&gt;
    ├── .../&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
├── 2027/&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
└── Provisionsabrechnungen/&lt;br /&gt;
    └── [← Separate Outsider-Logs]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dry-Run Modus ===&lt;br /&gt;
&lt;br /&gt;
Vor jedem echten Versand kann ein Dry-Run durchgeführt werden:&lt;br /&gt;
&lt;br /&gt;
# Simuliert den kompletten Versandprozess&lt;br /&gt;
# Erstellt Vorschau-Datei mit allen Details&lt;br /&gt;
# Zeigt Dialog mit Zusammenfassung&lt;br /&gt;
# User kann bestätigen oder abbrechen&lt;br /&gt;
&lt;br /&gt;
Die Vorschau-Datei wird auf der lokalen Festplatte gespeichert (Pfad konfigurierbar).&lt;br /&gt;
&lt;br /&gt;
=== Mail-Drafts ===&lt;br /&gt;
&lt;br /&gt;
Das System erstellt keinen automatischen Versand, sondern Mail-Drafts:&lt;br /&gt;
&lt;br /&gt;
# ZIP-Archive werden erzeugt&lt;br /&gt;
# Apple Mail öffnet mit neuem Draft (nicht gesendet!)&lt;br /&gt;
# User kann Template prüfen, weitere Empfänger hinzufügen&lt;br /&gt;
# Benutzerdefinierter Versand per Knopfdruck in Mail&lt;br /&gt;
&lt;br /&gt;
Dies ermöglicht volle Kontrolle über den Versand.&lt;br /&gt;
&lt;br /&gt;
=== Mail-Templates ===&lt;br /&gt;
&lt;br /&gt;
Templates werden aus DEVONthink geladen (`_config/mail_vorlagen/`).&lt;br /&gt;
&lt;br /&gt;
Das System zeigt einen Dialog zur Template-Auswahl, wenn mehrere Vorlagen vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Beispiel-Template:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Sehr geehrte/r Frau/Herr,&lt;br /&gt;
&lt;br /&gt;
beiliegend erhalten Sie die angeforderten Unterlagen.&lt;br /&gt;
&lt;br /&gt;
Mit freundlichen Grüßen&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Protokollierung ==&lt;br /&gt;
&lt;br /&gt;
Die Versandvorgänge werden jeweils doppelt protokolliert:&lt;br /&gt;
&lt;br /&gt;
1. Zum einen im maschinenlesbaren json-Format, für technische Weiterverarbeitung.&lt;br /&gt;
&lt;br /&gt;
2. Zum anderen im menschlich lesbaren Mark-Down-Textformat, mit Übersichten nach Versandlauf.&lt;br /&gt;
&lt;br /&gt;
Die Protokolle liegen entweder in der DEVONthink-Gruppe /Versendet des aktuellen Buchungsjahres. Das gilt, wenn Dokumente innerhalb eines Jahresordners liegen und einem Monat zugeordnet sind (siehe oben, Abschnitt &#039;&#039;Booking-Jahr Enforcement&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
Dokumente, die nicht Teil eines Buchungsjahres sind, werden in der Gruppe /Versendet_Outsider abgelegt. Diese Gruppe liegt neben /_config unmittel an der Datenbankwurzel.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
=== Scripts funktionieren nicht ===&lt;br /&gt;
&lt;br /&gt;
==== Problem: &amp;quot;Script nicht gefunden&amp;quot; ====&lt;br /&gt;
&lt;br /&gt;
Häufigste Ursache: `compile.sh` wurde nicht ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# Prüfen ob `.scpt`-Dateien vorhanden sind: &amp;lt;code&amp;gt;ls ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/Belegversand/Helpers/scripts/&amp;lt;/code&amp;gt;&lt;br /&gt;
# Falls nur `.applescript`-Dateien vorhanden → &amp;lt;code&amp;gt;./compile.sh&amp;lt;/code&amp;gt; erneut ausführen&lt;br /&gt;
# Auf Fehlermeldungen achten&lt;br /&gt;
&lt;br /&gt;
==== Problem: Script-Zugriff verweigert ====&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# System Settings → Privacy &amp;amp; Security → Automation&lt;br /&gt;
# DEVONthink sollte mit entsprechenden Rechten gelistet sein&lt;br /&gt;
# Script Editor öffnen und START.scpt öffnen&lt;br /&gt;
# Compile (⌘K) — sollte ohne Fehler durchlaufen&lt;br /&gt;
&lt;br /&gt;
=== ZIP wird nicht erstellt ===&lt;br /&gt;
&lt;br /&gt;
* ZIP-Passwort in Config überprüfen (keine Sonderzeichen!)&lt;br /&gt;
* Ausreichend Festplatte vorhanden?&lt;br /&gt;
* Staging-Ordner in DEVONthink beschreibbar?&lt;br /&gt;
&lt;br /&gt;
=== Mail-Draft öffnet sich nicht ===&lt;br /&gt;
&lt;br /&gt;
* Apple Mail ist geöffnet?&lt;br /&gt;
* Script-Zugriff für Mail aktiviert?&lt;br /&gt;
* Mail-Templates-Ordner vorhanden?&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Mixed-Year-Selection&amp;quot;-Fehler ===&lt;br /&gt;
&lt;br /&gt;
Dies ist kein Fehler, sondern Schutz vor Versandvermischung:&lt;br /&gt;
&lt;br /&gt;
; Lösung 1: Nur Belege aus einem Buchungsjahr auswählen&lt;br /&gt;
; Lösung 2: Belege in mehreren Versänden verteilen&lt;br /&gt;
&lt;br /&gt;
=== Debug-Informationen aktivieren ===&lt;br /&gt;
&lt;br /&gt;
In `belegversand.conf`:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
WRITE_DEBUG_LOG=true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Debug-Logs erscheinen dann in `/tmp/DT-Belegversand-debug.log`.&lt;br /&gt;
&lt;br /&gt;
== Versionshistorie ==&lt;br /&gt;
&lt;br /&gt;
; 1.4: Booking-Jahr Enforcement, Kompilierungs-Automation, About-Dialog, Wiki-Integration&lt;br /&gt;
; 1.3: Dry-Run Verbesserungen, Markdown-Logs&lt;br /&gt;
; 1.2: Mail-Templates in DEVONthink, interne README&lt;br /&gt;
; 1.1: Konfigurationssystem&lt;br /&gt;
; 1.0: Erste funktionale Version&lt;br /&gt;
&lt;br /&gt;
== Entwicklung ==&lt;br /&gt;
&lt;br /&gt;
Quellcode liegt als `.applescript`-Dateien vor (lesbar, git-freundlich).&lt;br /&gt;
&lt;br /&gt;
Zur lokalen Entwicklung:&lt;br /&gt;
# Quelldateien (`.applescript`) editieren&lt;br /&gt;
# `./compile.sh` ausführen&lt;br /&gt;
# In DEVONthink testen&lt;br /&gt;
# Bei Änderungen: `./compile.sh` erneut ausführen&lt;br /&gt;
&lt;br /&gt;
== Support ==&lt;br /&gt;
&lt;br /&gt;
Für technische Fragen oder Probleme:&lt;br /&gt;
* Wiki-Dokumentation durchlesen (diese Seite)&lt;br /&gt;
* Debug-Log aktivieren und analysieren&lt;br /&gt;
* Im Gitea-Repository ein Issue erstellen (falls Zugriff vorhanden)&lt;br /&gt;
&lt;br /&gt;
== Externe Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation Repository] (privat, erfordert Zugriff)&lt;br /&gt;
* [https://www.devontechnologies.com DEVONthink Homepage]&lt;br /&gt;
* [https://support.apple.com/mail Apple Mail Documentation]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=315</id>
		<title>Belegversand</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=315"/>
		<updated>2026-08-18T16:41:26Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Booking-Jahr Enforcement */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Belegversand =&lt;br /&gt;
&lt;br /&gt;
== Übersicht ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Belegversand&#039;&#039;&#039; ist eine automatisierte AppleScript-Lösung zur Verwaltung von Dokumenten-Versand in DEVONthink. Das System ermöglicht es, Belege aus einer DEVONthink-Datenbank auszuwählen, diese in ZIP-Archive zu packen (optional mit Passwort) und automatische Mail-Drafts mit konfigurierbaren Empfängern zu erstellen. Zusätzlich erfolgt strukturierte Protokollierung über Logging und Tagging-Mechanismen.&lt;br /&gt;
&lt;br /&gt;
== Sicherheitstechnischer Hinweis! ==&lt;br /&gt;
&lt;br /&gt;
Ich bitte zu beachten, dass die Software allenfalls minimale Sicherheitsanforderungen erfüllt.&lt;br /&gt;
&lt;br /&gt;
    Insbesondere liegt das Passwort für&#039;s ZIP-Archiv unverschlüsselt, im Klartext, in /_config/belegversand.conf. Wer das Passwort schützen möchte, kann das über die DB-Crypto von DEVONthink selbst tun. DEVONthink hat eine Datenbank-Verschlüsselung in den Bordmitteln.&lt;br /&gt;
    Dann bleibt trotzdem der zweite Schwachpunkt: Die ZIP-Verschlüsselung wird in dieser Version 1.4 über das Shell-Tool zip -P auf der Konsolenzeile realisiert. Dahinter steckt das veraltete und kryptographisch schwache ZipCrypto-Verfahren.&lt;br /&gt;
&lt;br /&gt;
Ganz deutlich: Diese Belegversand-Automatisation hab&#039; ich mir gebaut, um Tankbelege, Einkaufszettel und Restaurant-Quittungen an die Steuerberatung zu verschicken! Dafür sind sie prima! Falls es eine Version 1.5 geben sollte, ersetze ich zip -P vermutlich durch eine starke AES-Verschlüsselung, und das Passwort kommt als Hash-Wert in die Config-Datei.&lt;br /&gt;
&lt;br /&gt;
Bis dahin jedoch gilt ganz klar: Wer mit diesen Skripten, in dieser Version 1.4, sicherheitsrelevante Dokumente verschickt, tut das auf eigene Gefahr und handelt fahrlässig!&lt;br /&gt;
&lt;br /&gt;
; Version: 1.4&lt;br /&gt;
; Plattform: macOS 10.13+&lt;br /&gt;
; Abhängigkeiten: DEVONthink 3.x, Apple Mail&lt;br /&gt;
; Lizenz: Privatgebrauch&lt;br /&gt;
; Repository: https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Voraussetzungen ===&lt;br /&gt;
&lt;br /&gt;
* macOS 10.13 oder neuer&lt;br /&gt;
* DEVONthink 3.x&lt;br /&gt;
* Apple Mail&lt;br /&gt;
* AppleScript-Zugriff in Systemeinstellungen aktiviert&lt;br /&gt;
* Git (zum Klonen des Repositories)&lt;br /&gt;
&lt;br /&gt;
=== Schritt-für-Schritt Anleitung ===&lt;br /&gt;
&lt;br /&gt;
==== 1. Verzeichnisstruktur anlegen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&lt;br /&gt;
cd ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 2. Repository klonen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation.git Belegversand&lt;br /&gt;
cd Belegversand&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 3. Scripts kompilieren ====&lt;br /&gt;
&lt;br /&gt;
Dies ist ein &#039;&#039;&#039;wichtiger Schritt&#039;&#039;&#039; und darf nicht übersprungen werden!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chmod +x compile.sh&lt;br /&gt;
./compile.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erwartete Ausgabe:&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Compiliere Belegversand AppleScripts...&lt;br /&gt;
✓ Fertig!&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 4. Erste Ausführung ====&lt;br /&gt;
&lt;br /&gt;
# DEVONthink öffnen&lt;br /&gt;
# Ein Objekt in der gewünschten Datenbank auswählen&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog folgen → Setup wird durchgeführt&lt;br /&gt;
&lt;br /&gt;
Das Setup-Script erstellt automatisch alle notwendigen Ordnerstrukturen und Konfigurationsdateien in DEVONthink.&lt;br /&gt;
&lt;br /&gt;
== Wichtig: .applescript vs. .scpt Dateien ==&lt;br /&gt;
&lt;br /&gt;
Im Repository gibt es zwei Arten von AppleScript-Dateien:&lt;br /&gt;
&lt;br /&gt;
; .applescript: Quelldateien (lesbar, nur für Entwicklung)&lt;br /&gt;
; .scpt: Kompilierte Skripte (binär, werden von DEVONthink ausgeführt)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Kritisch:&#039;&#039;&#039; Die `.applescript`-Quelldateien funktionieren &#039;&#039;&#039;nicht&#039;&#039;&#039; direkt in DEVONthink. Sie enthalten relative Pfade, die zur Laufzeit expandiert werden müssen.&lt;br /&gt;
&lt;br /&gt;
Das `compile.sh`-Script:&lt;br /&gt;
# Kompiliert alle `.applescript` zu `.scpt`&lt;br /&gt;
# Löscht anschließend die `.applescript`-Dateien&lt;br /&gt;
# Hinterlässt nur funktionsfähige `.scpt`-Dateien&lt;br /&gt;
&lt;br /&gt;
Falls nach dem Clone noch `.applescript`-Dateien vorhanden sind, war `compile.sh` nicht erfolgreich. In diesem Fall erneut ausführen und auf Fehlermeldungen achten.&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
=== Automatische Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Nach der ersten Ausführung erstellt das System automatisch folgende Struktur in DEVONthink:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
_config/&lt;br /&gt;
├── belegversand.conf              # Konfigurationsdatei&lt;br /&gt;
├── mail_vorlagen/                 # Mail-Templates&lt;br /&gt;
│   └── belegversand               # Standard-Template&lt;br /&gt;
├── README-Belegversand            # Interne Hilfe&lt;br /&gt;
└── [weitere Dateien nach Versand]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Konfigurationsdatei ===&lt;br /&gt;
&lt;br /&gt;
Die Datei `belegversand.conf` befindet sich in DEVONthink unter `_config → belegversand.conf`.&lt;br /&gt;
&lt;br /&gt;
==== Wichtigste Parameter ====&lt;br /&gt;
&lt;br /&gt;
; MAIL_TO_DEFAULT: Standard-Empfänger (z.B. steuer@example.com)&lt;br /&gt;
; MAIL_CC_TO_DEFAULT: Standard-CC-Empfänger (optional)&lt;br /&gt;
; MAIL_SUBJECT_PREFIX: Präfix für den Mail-Betreff (z.B. &amp;quot;Belegversand&amp;quot;)&lt;br /&gt;
; ZIP_PASSWORD_DEFAULT: Standard-Passwort für ZIP-Archive (optional, keine Sonderzeichen)&lt;br /&gt;
; LOG_SENT_GROUP_NAME: Name der Ordnergruppe für Versandprotokolle (Standard: &amp;quot;Versendet&amp;quot;)&lt;br /&gt;
; SENT_TAG_FOR_DOCS: Tag für versendete Belege (Standard: &amp;quot;gesendet&amp;quot;)&lt;br /&gt;
; WRITE_DEBUG_LOG: Debug-Logging aktivieren (true/false)&lt;br /&gt;
; SHOW_README: Willkommensdialog beim Start anzeigen (true/false)&lt;br /&gt;
; MAILBODY_FOLDER_NAME: Ordner für Mail-Templates (Standard: &amp;quot;mail_vorlagen&amp;quot;)&lt;br /&gt;
; MAILBODY_RECORD_NAME: Name des Standard-Templates (Standard: &amp;quot;belegversand&amp;quot;)&lt;br /&gt;
; PATH_TO_DRYRUN_PREVIEW: Speicherort der Dry-Run Vorschau-Datei&lt;br /&gt;
&lt;br /&gt;
==== Multiple Empfänger (CSV-Format) ====&lt;br /&gt;
&lt;br /&gt;
Mehrere E-Mail-Adressen können durch Kommas getrennt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
MAIL_TO_DEFAULT=recipient1@example.com, recipient2@example.com&lt;br /&gt;
MAIL_CC_TO_DEFAULT=cc1@example.com, cc2@example.com&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Adressen werden automatisch geparst und in Apple Mail einzeln eingefügt.&lt;br /&gt;
&lt;br /&gt;
== Verwendung ==&lt;br /&gt;
&lt;br /&gt;
=== Grundablauf ===&lt;br /&gt;
&lt;br /&gt;
# Belege in DEVONthink auswählen (Mehrfachauswahl möglich)&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog beantwortet (Empfänger, ZIP-Passwort, Dry-Run?)&lt;br /&gt;
# Dry-Run Vorschau anschauen (optional)&lt;br /&gt;
# Echtlauf → ZIP-Archive erstellt, Mail-Draft geöffnet, Logging durchgeführt&lt;br /&gt;
&lt;br /&gt;
=== Menü-Befehle ===&lt;br /&gt;
&lt;br /&gt;
; START: Haupteinstiegspunkt — startet Setup oder Versand&lt;br /&gt;
; About...: About-Dialog mit Versionsinformation und Links&lt;br /&gt;
&lt;br /&gt;
=== Booking-Jahr Enforcement ===&lt;br /&gt;
&lt;br /&gt;
Das System verhindert Versandvermischung über mehrere Jahre:&lt;br /&gt;
&lt;br /&gt;
; Mixed-Year Selection: Werden Belege aus verschiedenen Jahren auswählt, wird ein Fehler zurückgewiesen&lt;br /&gt;
; Separate Protokolle: Jedes Buchungsjahr hat eigene Versendet-Ordner mit separaten Logs&lt;br /&gt;
; Outsider-Belege: Dokumente außerhalb der Jahresstruktur werden separat gehandhabt&lt;br /&gt;
&lt;br /&gt;
Beispiel-Struktur:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Belege/&lt;br /&gt;
├── 2026/&lt;br /&gt;
│   ├── 01_Januar/&lt;br /&gt;
    ├── 02_Februar/&lt;br /&gt;
    ├── .../&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
├── 2027/&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
└── Provisionsabrechnungen/&lt;br /&gt;
    └── [← Separate Outsider-Logs]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dry-Run Modus ===&lt;br /&gt;
&lt;br /&gt;
Vor jedem echten Versand kann ein Dry-Run durchgeführt werden:&lt;br /&gt;
&lt;br /&gt;
# Simuliert den kompletten Versandprozess&lt;br /&gt;
# Erstellt Vorschau-Datei mit allen Details&lt;br /&gt;
# Zeigt Dialog mit Zusammenfassung&lt;br /&gt;
# User kann bestätigen oder abbrechen&lt;br /&gt;
&lt;br /&gt;
Die Vorschau-Datei wird auf der lokalen Festplatte gespeichert (Pfad konfigurierbar).&lt;br /&gt;
&lt;br /&gt;
=== Mail-Drafts ===&lt;br /&gt;
&lt;br /&gt;
Das System erstellt keinen automatischen Versand, sondern Mail-Drafts:&lt;br /&gt;
&lt;br /&gt;
# ZIP-Archive werden erzeugt&lt;br /&gt;
# Apple Mail öffnet mit neuem Draft (nicht gesendet!)&lt;br /&gt;
# User kann Template prüfen, weitere Empfänger hinzufügen&lt;br /&gt;
# Benutzerdefinierter Versand per Knopfdruck in Mail&lt;br /&gt;
&lt;br /&gt;
Dies ermöglicht volle Kontrolle über den Versand.&lt;br /&gt;
&lt;br /&gt;
=== Mail-Templates ===&lt;br /&gt;
&lt;br /&gt;
Templates werden aus DEVONthink geladen (`_config/mail_vorlagen/`).&lt;br /&gt;
&lt;br /&gt;
Das System zeigt einen Dialog zur Template-Auswahl, wenn mehrere Vorlagen vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Beispiel-Template:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Sehr geehrte/r Frau/Herr,&lt;br /&gt;
&lt;br /&gt;
beiliegend erhalten Sie die angeforderten Unterlagen.&lt;br /&gt;
&lt;br /&gt;
Mit freundlichen Grüßen&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Protokollierung ==&lt;br /&gt;
&lt;br /&gt;
Die Versandvorgänge werden jeweils doppelt protokolliert:&lt;br /&gt;
&lt;br /&gt;
1. Zum einen im maschinenlesbaren json-Format, für technische Weiterverarbeitung.&lt;br /&gt;
&lt;br /&gt;
2. Zum anderen im menschlich lesbaren Mark-Down-Textformat, mit Übersichten nach Versandlauf.&lt;br /&gt;
&lt;br /&gt;
Die Protokolle liegen entweder in der DEVONthink-Gruppe /Versendet des aktuellen Buchungsjahres. Das gilt, wenn Dokumente innerhalb eines Jahresordners liegen und einem Monat zugeordnet sind.&lt;br /&gt;
Dokumente, die nicht Teil eines Buchungsjahres sind, werden in der Gruppe /Versendet_Outsider abgelegt. Diese Gruppe liegt neben /_config unmittel an der Datenbankwurzel.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
=== Scripts funktionieren nicht ===&lt;br /&gt;
&lt;br /&gt;
==== Problem: &amp;quot;Script nicht gefunden&amp;quot; ====&lt;br /&gt;
&lt;br /&gt;
Häufigste Ursache: `compile.sh` wurde nicht ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# Prüfen ob `.scpt`-Dateien vorhanden sind: &amp;lt;code&amp;gt;ls ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/Belegversand/Helpers/scripts/&amp;lt;/code&amp;gt;&lt;br /&gt;
# Falls nur `.applescript`-Dateien vorhanden → &amp;lt;code&amp;gt;./compile.sh&amp;lt;/code&amp;gt; erneut ausführen&lt;br /&gt;
# Auf Fehlermeldungen achten&lt;br /&gt;
&lt;br /&gt;
==== Problem: Script-Zugriff verweigert ====&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# System Settings → Privacy &amp;amp; Security → Automation&lt;br /&gt;
# DEVONthink sollte mit entsprechenden Rechten gelistet sein&lt;br /&gt;
# Script Editor öffnen und START.scpt öffnen&lt;br /&gt;
# Compile (⌘K) — sollte ohne Fehler durchlaufen&lt;br /&gt;
&lt;br /&gt;
=== ZIP wird nicht erstellt ===&lt;br /&gt;
&lt;br /&gt;
* ZIP-Passwort in Config überprüfen (keine Sonderzeichen!)&lt;br /&gt;
* Ausreichend Festplatte vorhanden?&lt;br /&gt;
* Staging-Ordner in DEVONthink beschreibbar?&lt;br /&gt;
&lt;br /&gt;
=== Mail-Draft öffnet sich nicht ===&lt;br /&gt;
&lt;br /&gt;
* Apple Mail ist geöffnet?&lt;br /&gt;
* Script-Zugriff für Mail aktiviert?&lt;br /&gt;
* Mail-Templates-Ordner vorhanden?&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Mixed-Year-Selection&amp;quot;-Fehler ===&lt;br /&gt;
&lt;br /&gt;
Dies ist kein Fehler, sondern Schutz vor Versandvermischung:&lt;br /&gt;
&lt;br /&gt;
; Lösung 1: Nur Belege aus einem Buchungsjahr auswählen&lt;br /&gt;
; Lösung 2: Belege in mehreren Versänden verteilen&lt;br /&gt;
&lt;br /&gt;
=== Debug-Informationen aktivieren ===&lt;br /&gt;
&lt;br /&gt;
In `belegversand.conf`:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
WRITE_DEBUG_LOG=true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Debug-Logs erscheinen dann in `/tmp/DT-Belegversand-debug.log`.&lt;br /&gt;
&lt;br /&gt;
== Versionshistorie ==&lt;br /&gt;
&lt;br /&gt;
; 1.4: Booking-Jahr Enforcement, Kompilierungs-Automation, About-Dialog, Wiki-Integration&lt;br /&gt;
; 1.3: Dry-Run Verbesserungen, Markdown-Logs&lt;br /&gt;
; 1.2: Mail-Templates in DEVONthink, interne README&lt;br /&gt;
; 1.1: Konfigurationssystem&lt;br /&gt;
; 1.0: Erste funktionale Version&lt;br /&gt;
&lt;br /&gt;
== Entwicklung ==&lt;br /&gt;
&lt;br /&gt;
Quellcode liegt als `.applescript`-Dateien vor (lesbar, git-freundlich).&lt;br /&gt;
&lt;br /&gt;
Zur lokalen Entwicklung:&lt;br /&gt;
# Quelldateien (`.applescript`) editieren&lt;br /&gt;
# `./compile.sh` ausführen&lt;br /&gt;
# In DEVONthink testen&lt;br /&gt;
# Bei Änderungen: `./compile.sh` erneut ausführen&lt;br /&gt;
&lt;br /&gt;
== Support ==&lt;br /&gt;
&lt;br /&gt;
Für technische Fragen oder Probleme:&lt;br /&gt;
* Wiki-Dokumentation durchlesen (diese Seite)&lt;br /&gt;
* Debug-Log aktivieren und analysieren&lt;br /&gt;
* Im Gitea-Repository ein Issue erstellen (falls Zugriff vorhanden)&lt;br /&gt;
&lt;br /&gt;
== Externe Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation Repository] (privat, erfordert Zugriff)&lt;br /&gt;
* [https://www.devontechnologies.com DEVONthink Homepage]&lt;br /&gt;
* [https://support.apple.com/mail Apple Mail Documentation]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=314</id>
		<title>Belegversand</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=314"/>
		<updated>2026-08-18T16:40:06Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Protokollierung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Belegversand =&lt;br /&gt;
&lt;br /&gt;
== Übersicht ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Belegversand&#039;&#039;&#039; ist eine automatisierte AppleScript-Lösung zur Verwaltung von Dokumenten-Versand in DEVONthink. Das System ermöglicht es, Belege aus einer DEVONthink-Datenbank auszuwählen, diese in ZIP-Archive zu packen (optional mit Passwort) und automatische Mail-Drafts mit konfigurierbaren Empfängern zu erstellen. Zusätzlich erfolgt strukturierte Protokollierung über Logging und Tagging-Mechanismen.&lt;br /&gt;
&lt;br /&gt;
== Sicherheitstechnischer Hinweis! ==&lt;br /&gt;
&lt;br /&gt;
Ich bitte zu beachten, dass die Software allenfalls minimale Sicherheitsanforderungen erfüllt.&lt;br /&gt;
&lt;br /&gt;
    Insbesondere liegt das Passwort für&#039;s ZIP-Archiv unverschlüsselt, im Klartext, in /_config/belegversand.conf. Wer das Passwort schützen möchte, kann das über die DB-Crypto von DEVONthink selbst tun. DEVONthink hat eine Datenbank-Verschlüsselung in den Bordmitteln.&lt;br /&gt;
    Dann bleibt trotzdem der zweite Schwachpunkt: Die ZIP-Verschlüsselung wird in dieser Version 1.4 über das Shell-Tool zip -P auf der Konsolenzeile realisiert. Dahinter steckt das veraltete und kryptographisch schwache ZipCrypto-Verfahren.&lt;br /&gt;
&lt;br /&gt;
Ganz deutlich: Diese Belegversand-Automatisation hab&#039; ich mir gebaut, um Tankbelege, Einkaufszettel und Restaurant-Quittungen an die Steuerberatung zu verschicken! Dafür sind sie prima! Falls es eine Version 1.5 geben sollte, ersetze ich zip -P vermutlich durch eine starke AES-Verschlüsselung, und das Passwort kommt als Hash-Wert in die Config-Datei.&lt;br /&gt;
&lt;br /&gt;
Bis dahin jedoch gilt ganz klar: Wer mit diesen Skripten, in dieser Version 1.4, sicherheitsrelevante Dokumente verschickt, tut das auf eigene Gefahr und handelt fahrlässig!&lt;br /&gt;
&lt;br /&gt;
; Version: 1.4&lt;br /&gt;
; Plattform: macOS 10.13+&lt;br /&gt;
; Abhängigkeiten: DEVONthink 3.x, Apple Mail&lt;br /&gt;
; Lizenz: Privatgebrauch&lt;br /&gt;
; Repository: https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Voraussetzungen ===&lt;br /&gt;
&lt;br /&gt;
* macOS 10.13 oder neuer&lt;br /&gt;
* DEVONthink 3.x&lt;br /&gt;
* Apple Mail&lt;br /&gt;
* AppleScript-Zugriff in Systemeinstellungen aktiviert&lt;br /&gt;
* Git (zum Klonen des Repositories)&lt;br /&gt;
&lt;br /&gt;
=== Schritt-für-Schritt Anleitung ===&lt;br /&gt;
&lt;br /&gt;
==== 1. Verzeichnisstruktur anlegen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&lt;br /&gt;
cd ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 2. Repository klonen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation.git Belegversand&lt;br /&gt;
cd Belegversand&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 3. Scripts kompilieren ====&lt;br /&gt;
&lt;br /&gt;
Dies ist ein &#039;&#039;&#039;wichtiger Schritt&#039;&#039;&#039; und darf nicht übersprungen werden!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chmod +x compile.sh&lt;br /&gt;
./compile.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erwartete Ausgabe:&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Compiliere Belegversand AppleScripts...&lt;br /&gt;
✓ Fertig!&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 4. Erste Ausführung ====&lt;br /&gt;
&lt;br /&gt;
# DEVONthink öffnen&lt;br /&gt;
# Ein Objekt in der gewünschten Datenbank auswählen&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog folgen → Setup wird durchgeführt&lt;br /&gt;
&lt;br /&gt;
Das Setup-Script erstellt automatisch alle notwendigen Ordnerstrukturen und Konfigurationsdateien in DEVONthink.&lt;br /&gt;
&lt;br /&gt;
== Wichtig: .applescript vs. .scpt Dateien ==&lt;br /&gt;
&lt;br /&gt;
Im Repository gibt es zwei Arten von AppleScript-Dateien:&lt;br /&gt;
&lt;br /&gt;
; .applescript: Quelldateien (lesbar, nur für Entwicklung)&lt;br /&gt;
; .scpt: Kompilierte Skripte (binär, werden von DEVONthink ausgeführt)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Kritisch:&#039;&#039;&#039; Die `.applescript`-Quelldateien funktionieren &#039;&#039;&#039;nicht&#039;&#039;&#039; direkt in DEVONthink. Sie enthalten relative Pfade, die zur Laufzeit expandiert werden müssen.&lt;br /&gt;
&lt;br /&gt;
Das `compile.sh`-Script:&lt;br /&gt;
# Kompiliert alle `.applescript` zu `.scpt`&lt;br /&gt;
# Löscht anschließend die `.applescript`-Dateien&lt;br /&gt;
# Hinterlässt nur funktionsfähige `.scpt`-Dateien&lt;br /&gt;
&lt;br /&gt;
Falls nach dem Clone noch `.applescript`-Dateien vorhanden sind, war `compile.sh` nicht erfolgreich. In diesem Fall erneut ausführen und auf Fehlermeldungen achten.&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
=== Automatische Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Nach der ersten Ausführung erstellt das System automatisch folgende Struktur in DEVONthink:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
_config/&lt;br /&gt;
├── belegversand.conf              # Konfigurationsdatei&lt;br /&gt;
├── mail_vorlagen/                 # Mail-Templates&lt;br /&gt;
│   └── belegversand               # Standard-Template&lt;br /&gt;
├── README-Belegversand            # Interne Hilfe&lt;br /&gt;
└── [weitere Dateien nach Versand]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Konfigurationsdatei ===&lt;br /&gt;
&lt;br /&gt;
Die Datei `belegversand.conf` befindet sich in DEVONthink unter `_config → belegversand.conf`.&lt;br /&gt;
&lt;br /&gt;
==== Wichtigste Parameter ====&lt;br /&gt;
&lt;br /&gt;
; MAIL_TO_DEFAULT: Standard-Empfänger (z.B. steuer@example.com)&lt;br /&gt;
; MAIL_CC_TO_DEFAULT: Standard-CC-Empfänger (optional)&lt;br /&gt;
; MAIL_SUBJECT_PREFIX: Präfix für den Mail-Betreff (z.B. &amp;quot;Belegversand&amp;quot;)&lt;br /&gt;
; ZIP_PASSWORD_DEFAULT: Standard-Passwort für ZIP-Archive (optional, keine Sonderzeichen)&lt;br /&gt;
; LOG_SENT_GROUP_NAME: Name der Ordnergruppe für Versandprotokolle (Standard: &amp;quot;Versendet&amp;quot;)&lt;br /&gt;
; SENT_TAG_FOR_DOCS: Tag für versendete Belege (Standard: &amp;quot;gesendet&amp;quot;)&lt;br /&gt;
; WRITE_DEBUG_LOG: Debug-Logging aktivieren (true/false)&lt;br /&gt;
; SHOW_README: Willkommensdialog beim Start anzeigen (true/false)&lt;br /&gt;
; MAILBODY_FOLDER_NAME: Ordner für Mail-Templates (Standard: &amp;quot;mail_vorlagen&amp;quot;)&lt;br /&gt;
; MAILBODY_RECORD_NAME: Name des Standard-Templates (Standard: &amp;quot;belegversand&amp;quot;)&lt;br /&gt;
; PATH_TO_DRYRUN_PREVIEW: Speicherort der Dry-Run Vorschau-Datei&lt;br /&gt;
&lt;br /&gt;
==== Multiple Empfänger (CSV-Format) ====&lt;br /&gt;
&lt;br /&gt;
Mehrere E-Mail-Adressen können durch Kommas getrennt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
MAIL_TO_DEFAULT=recipient1@example.com, recipient2@example.com&lt;br /&gt;
MAIL_CC_TO_DEFAULT=cc1@example.com, cc2@example.com&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Adressen werden automatisch geparst und in Apple Mail einzeln eingefügt.&lt;br /&gt;
&lt;br /&gt;
== Verwendung ==&lt;br /&gt;
&lt;br /&gt;
=== Grundablauf ===&lt;br /&gt;
&lt;br /&gt;
# Belege in DEVONthink auswählen (Mehrfachauswahl möglich)&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog beantwortet (Empfänger, ZIP-Passwort, Dry-Run?)&lt;br /&gt;
# Dry-Run Vorschau anschauen (optional)&lt;br /&gt;
# Echtlauf → ZIP-Archive erstellt, Mail-Draft geöffnet, Logging durchgeführt&lt;br /&gt;
&lt;br /&gt;
=== Menü-Befehle ===&lt;br /&gt;
&lt;br /&gt;
; START: Haupteinstiegspunkt — startet Setup oder Versand&lt;br /&gt;
; About...: About-Dialog mit Versionsinformation und Links&lt;br /&gt;
&lt;br /&gt;
=== Booking-Jahr Enforcement ===&lt;br /&gt;
&lt;br /&gt;
Das System verhindert Versandvermischung über mehrere Jahre:&lt;br /&gt;
&lt;br /&gt;
; Mixed-Year Selection: Werden Belege aus verschiedenen Jahren auswählt, wird ein Fehler zurückgewiesen&lt;br /&gt;
; Separate Protokolle: Jedes Buchungsjahr hat eigene Versendet-Ordner mit separaten Logs&lt;br /&gt;
; Outsider-Belege: Dokumente außerhalb der Jahresstruktur werden separat gehandhabt&lt;br /&gt;
&lt;br /&gt;
Beispiel-Struktur:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Belege/&lt;br /&gt;
├── 2026/&lt;br /&gt;
│   ├── 01_Januar/&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
├── 2027/&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
└── Provisionsabrechnungen/&lt;br /&gt;
    └── [← Separate Outsider-Logs]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dry-Run Modus ===&lt;br /&gt;
&lt;br /&gt;
Vor jedem echten Versand kann ein Dry-Run durchgeführt werden:&lt;br /&gt;
&lt;br /&gt;
# Simuliert den kompletten Versandprozess&lt;br /&gt;
# Erstellt Vorschau-Datei mit allen Details&lt;br /&gt;
# Zeigt Dialog mit Zusammenfassung&lt;br /&gt;
# User kann bestätigen oder abbrechen&lt;br /&gt;
&lt;br /&gt;
Die Vorschau-Datei wird auf der lokalen Festplatte gespeichert (Pfad konfigurierbar).&lt;br /&gt;
&lt;br /&gt;
=== Mail-Drafts ===&lt;br /&gt;
&lt;br /&gt;
Das System erstellt keinen automatischen Versand, sondern Mail-Drafts:&lt;br /&gt;
&lt;br /&gt;
# ZIP-Archive werden erzeugt&lt;br /&gt;
# Apple Mail öffnet mit neuem Draft (nicht gesendet!)&lt;br /&gt;
# User kann Template prüfen, weitere Empfänger hinzufügen&lt;br /&gt;
# Benutzerdefinierter Versand per Knopfdruck in Mail&lt;br /&gt;
&lt;br /&gt;
Dies ermöglicht volle Kontrolle über den Versand.&lt;br /&gt;
&lt;br /&gt;
=== Mail-Templates ===&lt;br /&gt;
&lt;br /&gt;
Templates werden aus DEVONthink geladen (`_config/mail_vorlagen/`).&lt;br /&gt;
&lt;br /&gt;
Das System zeigt einen Dialog zur Template-Auswahl, wenn mehrere Vorlagen vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Beispiel-Template:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Sehr geehrte/r Frau/Herr,&lt;br /&gt;
&lt;br /&gt;
beiliegend erhalten Sie die angeforderten Unterlagen.&lt;br /&gt;
&lt;br /&gt;
Mit freundlichen Grüßen&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Protokollierung ==&lt;br /&gt;
&lt;br /&gt;
Die Versandvorgänge werden jeweils doppelt protokolliert:&lt;br /&gt;
&lt;br /&gt;
1. Zum einen im maschinenlesbaren json-Format, für technische Weiterverarbeitung.&lt;br /&gt;
&lt;br /&gt;
2. Zum anderen im menschlich lesbaren Mark-Down-Textformat, mit Übersichten nach Versandlauf.&lt;br /&gt;
&lt;br /&gt;
Die Protokolle liegen entweder in der DEVONthink-Gruppe /Versendet des aktuellen Buchungsjahres. Das gilt, wenn Dokumente innerhalb eines Jahresordners liegen und einem Monat zugeordnet sind.&lt;br /&gt;
Dokumente, die nicht Teil eines Buchungsjahres sind, werden in der Gruppe /Versendet_Outsider abgelegt. Diese Gruppe liegt neben /_config unmittel an der Datenbankwurzel.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
=== Scripts funktionieren nicht ===&lt;br /&gt;
&lt;br /&gt;
==== Problem: &amp;quot;Script nicht gefunden&amp;quot; ====&lt;br /&gt;
&lt;br /&gt;
Häufigste Ursache: `compile.sh` wurde nicht ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# Prüfen ob `.scpt`-Dateien vorhanden sind: &amp;lt;code&amp;gt;ls ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/Belegversand/Helpers/scripts/&amp;lt;/code&amp;gt;&lt;br /&gt;
# Falls nur `.applescript`-Dateien vorhanden → &amp;lt;code&amp;gt;./compile.sh&amp;lt;/code&amp;gt; erneut ausführen&lt;br /&gt;
# Auf Fehlermeldungen achten&lt;br /&gt;
&lt;br /&gt;
==== Problem: Script-Zugriff verweigert ====&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# System Settings → Privacy &amp;amp; Security → Automation&lt;br /&gt;
# DEVONthink sollte mit entsprechenden Rechten gelistet sein&lt;br /&gt;
# Script Editor öffnen und START.scpt öffnen&lt;br /&gt;
# Compile (⌘K) — sollte ohne Fehler durchlaufen&lt;br /&gt;
&lt;br /&gt;
=== ZIP wird nicht erstellt ===&lt;br /&gt;
&lt;br /&gt;
* ZIP-Passwort in Config überprüfen (keine Sonderzeichen!)&lt;br /&gt;
* Ausreichend Festplatte vorhanden?&lt;br /&gt;
* Staging-Ordner in DEVONthink beschreibbar?&lt;br /&gt;
&lt;br /&gt;
=== Mail-Draft öffnet sich nicht ===&lt;br /&gt;
&lt;br /&gt;
* Apple Mail ist geöffnet?&lt;br /&gt;
* Script-Zugriff für Mail aktiviert?&lt;br /&gt;
* Mail-Templates-Ordner vorhanden?&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Mixed-Year-Selection&amp;quot;-Fehler ===&lt;br /&gt;
&lt;br /&gt;
Dies ist kein Fehler, sondern Schutz vor Versandvermischung:&lt;br /&gt;
&lt;br /&gt;
; Lösung 1: Nur Belege aus einem Buchungsjahr auswählen&lt;br /&gt;
; Lösung 2: Belege in mehreren Versänden verteilen&lt;br /&gt;
&lt;br /&gt;
=== Debug-Informationen aktivieren ===&lt;br /&gt;
&lt;br /&gt;
In `belegversand.conf`:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
WRITE_DEBUG_LOG=true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Debug-Logs erscheinen dann in `/tmp/DT-Belegversand-debug.log`.&lt;br /&gt;
&lt;br /&gt;
== Versionshistorie ==&lt;br /&gt;
&lt;br /&gt;
; 1.4: Booking-Jahr Enforcement, Kompilierungs-Automation, About-Dialog, Wiki-Integration&lt;br /&gt;
; 1.3: Dry-Run Verbesserungen, Markdown-Logs&lt;br /&gt;
; 1.2: Mail-Templates in DEVONthink, interne README&lt;br /&gt;
; 1.1: Konfigurationssystem&lt;br /&gt;
; 1.0: Erste funktionale Version&lt;br /&gt;
&lt;br /&gt;
== Entwicklung ==&lt;br /&gt;
&lt;br /&gt;
Quellcode liegt als `.applescript`-Dateien vor (lesbar, git-freundlich).&lt;br /&gt;
&lt;br /&gt;
Zur lokalen Entwicklung:&lt;br /&gt;
# Quelldateien (`.applescript`) editieren&lt;br /&gt;
# `./compile.sh` ausführen&lt;br /&gt;
# In DEVONthink testen&lt;br /&gt;
# Bei Änderungen: `./compile.sh` erneut ausführen&lt;br /&gt;
&lt;br /&gt;
== Support ==&lt;br /&gt;
&lt;br /&gt;
Für technische Fragen oder Probleme:&lt;br /&gt;
* Wiki-Dokumentation durchlesen (diese Seite)&lt;br /&gt;
* Debug-Log aktivieren und analysieren&lt;br /&gt;
* Im Gitea-Repository ein Issue erstellen (falls Zugriff vorhanden)&lt;br /&gt;
&lt;br /&gt;
== Externe Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation Repository] (privat, erfordert Zugriff)&lt;br /&gt;
* [https://www.devontechnologies.com DEVONthink Homepage]&lt;br /&gt;
* [https://support.apple.com/mail Apple Mail Documentation]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=313</id>
		<title>Belegversand</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=313"/>
		<updated>2026-08-18T16:37:15Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Belegversand =&lt;br /&gt;
&lt;br /&gt;
== Übersicht ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Belegversand&#039;&#039;&#039; ist eine automatisierte AppleScript-Lösung zur Verwaltung von Dokumenten-Versand in DEVONthink. Das System ermöglicht es, Belege aus einer DEVONthink-Datenbank auszuwählen, diese in ZIP-Archive zu packen (optional mit Passwort) und automatische Mail-Drafts mit konfigurierbaren Empfängern zu erstellen. Zusätzlich erfolgt strukturierte Protokollierung über Logging und Tagging-Mechanismen.&lt;br /&gt;
&lt;br /&gt;
== Sicherheitstechnischer Hinweis! ==&lt;br /&gt;
&lt;br /&gt;
Ich bitte zu beachten, dass die Software allenfalls minimale Sicherheitsanforderungen erfüllt.&lt;br /&gt;
&lt;br /&gt;
    Insbesondere liegt das Passwort für&#039;s ZIP-Archiv unverschlüsselt, im Klartext, in /_config/belegversand.conf. Wer das Passwort schützen möchte, kann das über die DB-Crypto von DEVONthink selbst tun. DEVONthink hat eine Datenbank-Verschlüsselung in den Bordmitteln.&lt;br /&gt;
    Dann bleibt trotzdem der zweite Schwachpunkt: Die ZIP-Verschlüsselung wird in dieser Version 1.4 über das Shell-Tool zip -P auf der Konsolenzeile realisiert. Dahinter steckt das veraltete und kryptographisch schwache ZipCrypto-Verfahren.&lt;br /&gt;
&lt;br /&gt;
Ganz deutlich: Diese Belegversand-Automatisation hab&#039; ich mir gebaut, um Tankbelege, Einkaufszettel und Restaurant-Quittungen an die Steuerberatung zu verschicken! Dafür sind sie prima! Falls es eine Version 1.5 geben sollte, ersetze ich zip -P vermutlich durch eine starke AES-Verschlüsselung, und das Passwort kommt als Hash-Wert in die Config-Datei.&lt;br /&gt;
&lt;br /&gt;
Bis dahin jedoch gilt ganz klar: Wer mit diesen Skripten, in dieser Version 1.4, sicherheitsrelevante Dokumente verschickt, tut das auf eigene Gefahr und handelt fahrlässig!&lt;br /&gt;
&lt;br /&gt;
; Version: 1.4&lt;br /&gt;
; Plattform: macOS 10.13+&lt;br /&gt;
; Abhängigkeiten: DEVONthink 3.x, Apple Mail&lt;br /&gt;
; Lizenz: Privatgebrauch&lt;br /&gt;
; Repository: https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Voraussetzungen ===&lt;br /&gt;
&lt;br /&gt;
* macOS 10.13 oder neuer&lt;br /&gt;
* DEVONthink 3.x&lt;br /&gt;
* Apple Mail&lt;br /&gt;
* AppleScript-Zugriff in Systemeinstellungen aktiviert&lt;br /&gt;
* Git (zum Klonen des Repositories)&lt;br /&gt;
&lt;br /&gt;
=== Schritt-für-Schritt Anleitung ===&lt;br /&gt;
&lt;br /&gt;
==== 1. Verzeichnisstruktur anlegen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&lt;br /&gt;
cd ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 2. Repository klonen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation.git Belegversand&lt;br /&gt;
cd Belegversand&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 3. Scripts kompilieren ====&lt;br /&gt;
&lt;br /&gt;
Dies ist ein &#039;&#039;&#039;wichtiger Schritt&#039;&#039;&#039; und darf nicht übersprungen werden!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chmod +x compile.sh&lt;br /&gt;
./compile.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erwartete Ausgabe:&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Compiliere Belegversand AppleScripts...&lt;br /&gt;
✓ Fertig!&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 4. Erste Ausführung ====&lt;br /&gt;
&lt;br /&gt;
# DEVONthink öffnen&lt;br /&gt;
# Ein Objekt in der gewünschten Datenbank auswählen&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog folgen → Setup wird durchgeführt&lt;br /&gt;
&lt;br /&gt;
Das Setup-Script erstellt automatisch alle notwendigen Ordnerstrukturen und Konfigurationsdateien in DEVONthink.&lt;br /&gt;
&lt;br /&gt;
== Wichtig: .applescript vs. .scpt Dateien ==&lt;br /&gt;
&lt;br /&gt;
Im Repository gibt es zwei Arten von AppleScript-Dateien:&lt;br /&gt;
&lt;br /&gt;
; .applescript: Quelldateien (lesbar, nur für Entwicklung)&lt;br /&gt;
; .scpt: Kompilierte Skripte (binär, werden von DEVONthink ausgeführt)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Kritisch:&#039;&#039;&#039; Die `.applescript`-Quelldateien funktionieren &#039;&#039;&#039;nicht&#039;&#039;&#039; direkt in DEVONthink. Sie enthalten relative Pfade, die zur Laufzeit expandiert werden müssen.&lt;br /&gt;
&lt;br /&gt;
Das `compile.sh`-Script:&lt;br /&gt;
# Kompiliert alle `.applescript` zu `.scpt`&lt;br /&gt;
# Löscht anschließend die `.applescript`-Dateien&lt;br /&gt;
# Hinterlässt nur funktionsfähige `.scpt`-Dateien&lt;br /&gt;
&lt;br /&gt;
Falls nach dem Clone noch `.applescript`-Dateien vorhanden sind, war `compile.sh` nicht erfolgreich. In diesem Fall erneut ausführen und auf Fehlermeldungen achten.&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
=== Automatische Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Nach der ersten Ausführung erstellt das System automatisch folgende Struktur in DEVONthink:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
_config/&lt;br /&gt;
├── belegversand.conf              # Konfigurationsdatei&lt;br /&gt;
├── mail_vorlagen/                 # Mail-Templates&lt;br /&gt;
│   └── belegversand               # Standard-Template&lt;br /&gt;
├── README-Belegversand            # Interne Hilfe&lt;br /&gt;
└── [weitere Dateien nach Versand]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Konfigurationsdatei ===&lt;br /&gt;
&lt;br /&gt;
Die Datei `belegversand.conf` befindet sich in DEVONthink unter `_config → belegversand.conf`.&lt;br /&gt;
&lt;br /&gt;
==== Wichtigste Parameter ====&lt;br /&gt;
&lt;br /&gt;
; MAIL_TO_DEFAULT: Standard-Empfänger (z.B. steuer@example.com)&lt;br /&gt;
; MAIL_CC_TO_DEFAULT: Standard-CC-Empfänger (optional)&lt;br /&gt;
; MAIL_SUBJECT_PREFIX: Präfix für den Mail-Betreff (z.B. &amp;quot;Belegversand&amp;quot;)&lt;br /&gt;
; ZIP_PASSWORD_DEFAULT: Standard-Passwort für ZIP-Archive (optional, keine Sonderzeichen)&lt;br /&gt;
; LOG_SENT_GROUP_NAME: Name der Ordnergruppe für Versandprotokolle (Standard: &amp;quot;Versendet&amp;quot;)&lt;br /&gt;
; SENT_TAG_FOR_DOCS: Tag für versendete Belege (Standard: &amp;quot;gesendet&amp;quot;)&lt;br /&gt;
; WRITE_DEBUG_LOG: Debug-Logging aktivieren (true/false)&lt;br /&gt;
; SHOW_README: Willkommensdialog beim Start anzeigen (true/false)&lt;br /&gt;
; MAILBODY_FOLDER_NAME: Ordner für Mail-Templates (Standard: &amp;quot;mail_vorlagen&amp;quot;)&lt;br /&gt;
; MAILBODY_RECORD_NAME: Name des Standard-Templates (Standard: &amp;quot;belegversand&amp;quot;)&lt;br /&gt;
; PATH_TO_DRYRUN_PREVIEW: Speicherort der Dry-Run Vorschau-Datei&lt;br /&gt;
&lt;br /&gt;
==== Multiple Empfänger (CSV-Format) ====&lt;br /&gt;
&lt;br /&gt;
Mehrere E-Mail-Adressen können durch Kommas getrennt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
MAIL_TO_DEFAULT=recipient1@example.com, recipient2@example.com&lt;br /&gt;
MAIL_CC_TO_DEFAULT=cc1@example.com, cc2@example.com&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Adressen werden automatisch geparst und in Apple Mail einzeln eingefügt.&lt;br /&gt;
&lt;br /&gt;
== Verwendung ==&lt;br /&gt;
&lt;br /&gt;
=== Grundablauf ===&lt;br /&gt;
&lt;br /&gt;
# Belege in DEVONthink auswählen (Mehrfachauswahl möglich)&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog beantwortet (Empfänger, ZIP-Passwort, Dry-Run?)&lt;br /&gt;
# Dry-Run Vorschau anschauen (optional)&lt;br /&gt;
# Echtlauf → ZIP-Archive erstellt, Mail-Draft geöffnet, Logging durchgeführt&lt;br /&gt;
&lt;br /&gt;
=== Menü-Befehle ===&lt;br /&gt;
&lt;br /&gt;
; START: Haupteinstiegspunkt — startet Setup oder Versand&lt;br /&gt;
; About...: About-Dialog mit Versionsinformation und Links&lt;br /&gt;
&lt;br /&gt;
=== Booking-Jahr Enforcement ===&lt;br /&gt;
&lt;br /&gt;
Das System verhindert Versandvermischung über mehrere Jahre:&lt;br /&gt;
&lt;br /&gt;
; Mixed-Year Selection: Werden Belege aus verschiedenen Jahren auswählt, wird ein Fehler zurückgewiesen&lt;br /&gt;
; Separate Protokolle: Jedes Buchungsjahr hat eigene Versendet-Ordner mit separaten Logs&lt;br /&gt;
; Outsider-Belege: Dokumente außerhalb der Jahresstruktur werden separat gehandhabt&lt;br /&gt;
&lt;br /&gt;
Beispiel-Struktur:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Belege/&lt;br /&gt;
├── 2026/&lt;br /&gt;
│   ├── 01_Januar/&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
├── 2027/&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
└── Provisionsabrechnungen/&lt;br /&gt;
    └── [← Separate Outsider-Logs]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dry-Run Modus ===&lt;br /&gt;
&lt;br /&gt;
Vor jedem echten Versand kann ein Dry-Run durchgeführt werden:&lt;br /&gt;
&lt;br /&gt;
# Simuliert den kompletten Versandprozess&lt;br /&gt;
# Erstellt Vorschau-Datei mit allen Details&lt;br /&gt;
# Zeigt Dialog mit Zusammenfassung&lt;br /&gt;
# User kann bestätigen oder abbrechen&lt;br /&gt;
&lt;br /&gt;
Die Vorschau-Datei wird auf der lokalen Festplatte gespeichert (Pfad konfigurierbar).&lt;br /&gt;
&lt;br /&gt;
=== Mail-Drafts ===&lt;br /&gt;
&lt;br /&gt;
Das System erstellt keinen automatischen Versand, sondern Mail-Drafts:&lt;br /&gt;
&lt;br /&gt;
# ZIP-Archive werden erzeugt&lt;br /&gt;
# Apple Mail öffnet mit neuem Draft (nicht gesendet!)&lt;br /&gt;
# User kann Template prüfen, weitere Empfänger hinzufügen&lt;br /&gt;
# Benutzerdefinierter Versand per Knopfdruck in Mail&lt;br /&gt;
&lt;br /&gt;
Dies ermöglicht volle Kontrolle über den Versand.&lt;br /&gt;
&lt;br /&gt;
=== Mail-Templates ===&lt;br /&gt;
&lt;br /&gt;
Templates werden aus DEVONthink geladen (`_config/mail_vorlagen/`).&lt;br /&gt;
&lt;br /&gt;
Das System zeigt einen Dialog zur Template-Auswahl, wenn mehrere Vorlagen vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Beispiel-Template:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Sehr geehrte/r Frau/Herr,&lt;br /&gt;
&lt;br /&gt;
beiliegend erhalten Sie die angeforderten Unterlagen.&lt;br /&gt;
&lt;br /&gt;
Mit freundlichen Grüßen&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Protokollierung ==&lt;br /&gt;
&lt;br /&gt;
- Die Versandvorgänge werden jeweils doppelt protokolliert. Zum einen im maschinenlesbaren json-Format, für technische Weiterverarbeitung.&lt;br /&gt;
- Zum anderen im menschlich lesbaren Mark-Down-Textformatm mit Übersichten nach Versandlauf.&lt;br /&gt;
&lt;br /&gt;
Die Protokolle liegen entweder in der DEVONthink-Gruppe /Versendet des aktuellen Buchungsjahres, wenn innerhalb dieses Jahres Dokumente versendet wurden.&lt;br /&gt;
Dokumente, die nicht Teil eines Buchungsjahres sind, werden in der Gruppe /Versendet_Outsider abgelegt. Diese Gruppe liegt neben /_config unmittel an der Datenbankwurzel.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
=== Scripts funktionieren nicht ===&lt;br /&gt;
&lt;br /&gt;
==== Problem: &amp;quot;Script nicht gefunden&amp;quot; ====&lt;br /&gt;
&lt;br /&gt;
Häufigste Ursache: `compile.sh` wurde nicht ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# Prüfen ob `.scpt`-Dateien vorhanden sind: &amp;lt;code&amp;gt;ls ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/Belegversand/Helpers/scripts/&amp;lt;/code&amp;gt;&lt;br /&gt;
# Falls nur `.applescript`-Dateien vorhanden → &amp;lt;code&amp;gt;./compile.sh&amp;lt;/code&amp;gt; erneut ausführen&lt;br /&gt;
# Auf Fehlermeldungen achten&lt;br /&gt;
&lt;br /&gt;
==== Problem: Script-Zugriff verweigert ====&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# System Settings → Privacy &amp;amp; Security → Automation&lt;br /&gt;
# DEVONthink sollte mit entsprechenden Rechten gelistet sein&lt;br /&gt;
# Script Editor öffnen und START.scpt öffnen&lt;br /&gt;
# Compile (⌘K) — sollte ohne Fehler durchlaufen&lt;br /&gt;
&lt;br /&gt;
=== ZIP wird nicht erstellt ===&lt;br /&gt;
&lt;br /&gt;
* ZIP-Passwort in Config überprüfen (keine Sonderzeichen!)&lt;br /&gt;
* Ausreichend Festplatte vorhanden?&lt;br /&gt;
* Staging-Ordner in DEVONthink beschreibbar?&lt;br /&gt;
&lt;br /&gt;
=== Mail-Draft öffnet sich nicht ===&lt;br /&gt;
&lt;br /&gt;
* Apple Mail ist geöffnet?&lt;br /&gt;
* Script-Zugriff für Mail aktiviert?&lt;br /&gt;
* Mail-Templates-Ordner vorhanden?&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Mixed-Year-Selection&amp;quot;-Fehler ===&lt;br /&gt;
&lt;br /&gt;
Dies ist kein Fehler, sondern Schutz vor Versandvermischung:&lt;br /&gt;
&lt;br /&gt;
; Lösung 1: Nur Belege aus einem Buchungsjahr auswählen&lt;br /&gt;
; Lösung 2: Belege in mehreren Versänden verteilen&lt;br /&gt;
&lt;br /&gt;
=== Debug-Informationen aktivieren ===&lt;br /&gt;
&lt;br /&gt;
In `belegversand.conf`:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
WRITE_DEBUG_LOG=true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Debug-Logs erscheinen dann in `/tmp/DT-Belegversand-debug.log`.&lt;br /&gt;
&lt;br /&gt;
== Versionshistorie ==&lt;br /&gt;
&lt;br /&gt;
; 1.4: Booking-Jahr Enforcement, Kompilierungs-Automation, About-Dialog, Wiki-Integration&lt;br /&gt;
; 1.3: Dry-Run Verbesserungen, Markdown-Logs&lt;br /&gt;
; 1.2: Mail-Templates in DEVONthink, interne README&lt;br /&gt;
; 1.1: Konfigurationssystem&lt;br /&gt;
; 1.0: Erste funktionale Version&lt;br /&gt;
&lt;br /&gt;
== Entwicklung ==&lt;br /&gt;
&lt;br /&gt;
Quellcode liegt als `.applescript`-Dateien vor (lesbar, git-freundlich).&lt;br /&gt;
&lt;br /&gt;
Zur lokalen Entwicklung:&lt;br /&gt;
# Quelldateien (`.applescript`) editieren&lt;br /&gt;
# `./compile.sh` ausführen&lt;br /&gt;
# In DEVONthink testen&lt;br /&gt;
# Bei Änderungen: `./compile.sh` erneut ausführen&lt;br /&gt;
&lt;br /&gt;
== Support ==&lt;br /&gt;
&lt;br /&gt;
Für technische Fragen oder Probleme:&lt;br /&gt;
* Wiki-Dokumentation durchlesen (diese Seite)&lt;br /&gt;
* Debug-Log aktivieren und analysieren&lt;br /&gt;
* Im Gitea-Repository ein Issue erstellen (falls Zugriff vorhanden)&lt;br /&gt;
&lt;br /&gt;
== Externe Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation Repository] (privat, erfordert Zugriff)&lt;br /&gt;
* [https://www.devontechnologies.com DEVONthink Homepage]&lt;br /&gt;
* [https://support.apple.com/mail Apple Mail Documentation]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=312</id>
		<title>Belegversand</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=312"/>
		<updated>2026-08-18T16:30:42Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Markdown-Logs */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Belegversand =&lt;br /&gt;
&lt;br /&gt;
== Übersicht ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Belegversand&#039;&#039;&#039; ist eine automatisierte AppleScript-Lösung zur Verwaltung von Dokumenten-Versand in DEVONthink. Das System ermöglicht es, Belege aus einer DEVONthink-Datenbank auszuwählen, diese in ZIP-Archive zu packen (optional mit Passwort) und automatische Mail-Drafts mit konfigurierbaren Empfängern zu erstellen. Zusätzlich erfolgt strukturierte Protokollierung über Logging und Tagging-Mechanismen.&lt;br /&gt;
&lt;br /&gt;
== Sicherheitstechnischer Hinweis! ==&lt;br /&gt;
&lt;br /&gt;
Ich bitte zu beachten, dass die Software allenfalls minimale Sicherheitsanforderungen erfüllt.&lt;br /&gt;
&lt;br /&gt;
    Insbesondere liegt das Passwort für&#039;s ZIP-Archiv unverschlüsselt, im Klartext, in /_config/belegversand.conf. Wer das Passwort schützen möchte, kann das über die DB-Crypto von DEVONthink selbst tun. DEVONthink hat eine Datenbank-Verschlüsselung in den Bordmitteln.&lt;br /&gt;
    Dann bleibt trotzdem der zweite Schwachpunkt: Die ZIP-Verschlüsselung wird in dieser Version 1.4 über das Shell-Tool zip -P auf der Konsolenzeile realisiert. Dahinter steckt das veraltete und kryptographisch schwache ZipCrypto-Verfahren.&lt;br /&gt;
&lt;br /&gt;
Ganz deutlich: Diese Belegversand-Automatisation hab&#039; ich mir gebaut, um Tankbelege, Einkaufszettel und Restaurant-Quittungen an die Steuerberatung zu verschicken! Dafür sind sie prima! Falls es eine Version 1.5 geben sollte, ersetze ich zip -P vermutlich durch eine starke AES-Verschlüsselung, und das Passwort kommt als Hash-Wert in die Config-Datei.&lt;br /&gt;
&lt;br /&gt;
Bis dahin jedoch gilt ganz klar: Wer mit diesen Skripten, in dieser Version 1.4, sicherheitsrelevante Dokumente verschickt, tut das auf eigene Gefahr und handelt fahrlässig!&lt;br /&gt;
&lt;br /&gt;
; Version: 1.4&lt;br /&gt;
; Plattform: macOS 10.13+&lt;br /&gt;
; Abhängigkeiten: DEVONthink 3.x, Apple Mail&lt;br /&gt;
; Lizenz: Privatgebrauch&lt;br /&gt;
; Repository: https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Voraussetzungen ===&lt;br /&gt;
&lt;br /&gt;
* macOS 10.13 oder neuer&lt;br /&gt;
* DEVONthink 3.x&lt;br /&gt;
* Apple Mail&lt;br /&gt;
* AppleScript-Zugriff in Systemeinstellungen aktiviert&lt;br /&gt;
* Git (zum Klonen des Repositories)&lt;br /&gt;
&lt;br /&gt;
=== Schritt-für-Schritt Anleitung ===&lt;br /&gt;
&lt;br /&gt;
==== 1. Verzeichnisstruktur anlegen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&lt;br /&gt;
cd ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 2. Repository klonen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation.git Belegversand&lt;br /&gt;
cd Belegversand&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 3. Scripts kompilieren ====&lt;br /&gt;
&lt;br /&gt;
Dies ist ein &#039;&#039;&#039;wichtiger Schritt&#039;&#039;&#039; und darf nicht übersprungen werden!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chmod +x compile.sh&lt;br /&gt;
./compile.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erwartete Ausgabe:&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Compiliere Belegversand AppleScripts...&lt;br /&gt;
✓ Fertig!&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 4. Erste Ausführung ====&lt;br /&gt;
&lt;br /&gt;
# DEVONthink öffnen&lt;br /&gt;
# Ein Objekt in der gewünschten Datenbank auswählen&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog folgen → Setup wird durchgeführt&lt;br /&gt;
&lt;br /&gt;
Das Setup-Script erstellt automatisch alle notwendigen Ordnerstrukturen und Konfigurationsdateien in DEVONthink.&lt;br /&gt;
&lt;br /&gt;
== Wichtig: .applescript vs. .scpt Dateien ==&lt;br /&gt;
&lt;br /&gt;
Im Repository gibt es zwei Arten von AppleScript-Dateien:&lt;br /&gt;
&lt;br /&gt;
; .applescript: Quelldateien (lesbar, nur für Entwicklung)&lt;br /&gt;
; .scpt: Kompilierte Skripte (binär, werden von DEVONthink ausgeführt)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Kritisch:&#039;&#039;&#039; Die `.applescript`-Quelldateien funktionieren &#039;&#039;&#039;nicht&#039;&#039;&#039; direkt in DEVONthink. Sie enthalten relative Pfade, die zur Laufzeit expandiert werden müssen.&lt;br /&gt;
&lt;br /&gt;
Das `compile.sh`-Script:&lt;br /&gt;
# Kompiliert alle `.applescript` zu `.scpt`&lt;br /&gt;
# Löscht anschließend die `.applescript`-Dateien&lt;br /&gt;
# Hinterlässt nur funktionsfähige `.scpt`-Dateien&lt;br /&gt;
&lt;br /&gt;
Falls nach dem Clone noch `.applescript`-Dateien vorhanden sind, war `compile.sh` nicht erfolgreich. In diesem Fall erneut ausführen und auf Fehlermeldungen achten.&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
=== Automatische Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Nach der ersten Ausführung erstellt das System automatisch folgende Struktur in DEVONthink:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
_config/&lt;br /&gt;
├── belegversand.conf              # Konfigurationsdatei&lt;br /&gt;
├── mail_vorlagen/                 # Mail-Templates&lt;br /&gt;
│   └── belegversand               # Standard-Template&lt;br /&gt;
├── README-Belegversand            # Interne Hilfe&lt;br /&gt;
└── [weitere Dateien nach Versand]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Konfigurationsdatei ===&lt;br /&gt;
&lt;br /&gt;
Die Datei `belegversand.conf` befindet sich in DEVONthink unter `_config → belegversand.conf`.&lt;br /&gt;
&lt;br /&gt;
==== Wichtigste Parameter ====&lt;br /&gt;
&lt;br /&gt;
; MAIL_TO_DEFAULT: Standard-Empfänger (z.B. steuer@example.com)&lt;br /&gt;
; MAIL_CC_TO_DEFAULT: Standard-CC-Empfänger (optional)&lt;br /&gt;
; MAIL_SUBJECT_PREFIX: Präfix für den Mail-Betreff (z.B. &amp;quot;Belegversand&amp;quot;)&lt;br /&gt;
; ZIP_PASSWORD_DEFAULT: Standard-Passwort für ZIP-Archive (optional, keine Sonderzeichen)&lt;br /&gt;
; LOG_SENT_GROUP_NAME: Name der Ordnergruppe für Versandprotokolle (Standard: &amp;quot;Versendet&amp;quot;)&lt;br /&gt;
; SENT_TAG_FOR_DOCS: Tag für versendete Belege (Standard: &amp;quot;gesendet&amp;quot;)&lt;br /&gt;
; WRITE_DEBUG_LOG: Debug-Logging aktivieren (true/false)&lt;br /&gt;
; SHOW_README: Willkommensdialog beim Start anzeigen (true/false)&lt;br /&gt;
; MAILBODY_FOLDER_NAME: Ordner für Mail-Templates (Standard: &amp;quot;mail_vorlagen&amp;quot;)&lt;br /&gt;
; MAILBODY_RECORD_NAME: Name des Standard-Templates (Standard: &amp;quot;belegversand&amp;quot;)&lt;br /&gt;
; PATH_TO_DRYRUN_PREVIEW: Speicherort der Dry-Run Vorschau-Datei&lt;br /&gt;
&lt;br /&gt;
==== Multiple Empfänger (CSV-Format) ====&lt;br /&gt;
&lt;br /&gt;
Mehrere E-Mail-Adressen können durch Kommas getrennt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
MAIL_TO_DEFAULT=recipient1@example.com, recipient2@example.com&lt;br /&gt;
MAIL_CC_TO_DEFAULT=cc1@example.com, cc2@example.com&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Adressen werden automatisch geparst und in Apple Mail einzeln eingefügt.&lt;br /&gt;
&lt;br /&gt;
== Verwendung ==&lt;br /&gt;
&lt;br /&gt;
=== Grundablauf ===&lt;br /&gt;
&lt;br /&gt;
# Belege in DEVONthink auswählen (Mehrfachauswahl möglich)&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog beantwortet (Empfänger, ZIP-Passwort, Dry-Run?)&lt;br /&gt;
# Dry-Run Vorschau anschauen (optional)&lt;br /&gt;
# Echtlauf → ZIP-Archive erstellt, Mail-Draft geöffnet, Logging durchgeführt&lt;br /&gt;
&lt;br /&gt;
=== Menü-Befehle ===&lt;br /&gt;
&lt;br /&gt;
; START: Haupteinstiegspunkt — startet Setup oder Versand&lt;br /&gt;
; About...: About-Dialog mit Versionsinformation und Links&lt;br /&gt;
&lt;br /&gt;
=== Booking-Jahr Enforcement ===&lt;br /&gt;
&lt;br /&gt;
Das System verhindert Versandvermischung über mehrere Jahre:&lt;br /&gt;
&lt;br /&gt;
; Mixed-Year Selection: Werden Belege aus verschiedenen Jahren auswählt, wird ein Fehler zurückgewiesen&lt;br /&gt;
; Separate Protokolle: Jedes Buchungsjahr hat eigene Versendet-Ordner mit separaten Logs&lt;br /&gt;
; Outsider-Belege: Dokumente außerhalb der Jahresstruktur werden separat gehandhabt&lt;br /&gt;
&lt;br /&gt;
Beispiel-Struktur:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Belege/&lt;br /&gt;
├── 2026/&lt;br /&gt;
│   ├── 01_Januar/&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
├── 2027/&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
└── Provisionsabrechnungen/&lt;br /&gt;
    └── [← Separate Outsider-Logs]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dry-Run Modus ===&lt;br /&gt;
&lt;br /&gt;
Vor jedem echten Versand kann ein Dry-Run durchgeführt werden:&lt;br /&gt;
&lt;br /&gt;
# Simuliert den kompletten Versandprozess&lt;br /&gt;
# Erstellt Vorschau-Datei mit allen Details&lt;br /&gt;
# Zeigt Dialog mit Zusammenfassung&lt;br /&gt;
# User kann bestätigen oder abbrechen&lt;br /&gt;
&lt;br /&gt;
Die Vorschau-Datei wird auf der lokalen Festplatte gespeichert (Pfad konfigurierbar).&lt;br /&gt;
&lt;br /&gt;
=== Mail-Drafts ===&lt;br /&gt;
&lt;br /&gt;
Das System erstellt keinen automatischen Versand, sondern Mail-Drafts:&lt;br /&gt;
&lt;br /&gt;
# ZIP-Archive werden erzeugt&lt;br /&gt;
# Apple Mail öffnet mit neuem Draft (nicht gesendet!)&lt;br /&gt;
# User kann Template prüfen, weitere Empfänger hinzufügen&lt;br /&gt;
# Benutzerdefinierter Versand per Knopfdruck in Mail&lt;br /&gt;
&lt;br /&gt;
Dies ermöglicht volle Kontrolle über den Versand.&lt;br /&gt;
&lt;br /&gt;
=== Mail-Templates ===&lt;br /&gt;
&lt;br /&gt;
Templates werden aus DEVONthink geladen (`_config/mail_vorlagen/`).&lt;br /&gt;
&lt;br /&gt;
Das System zeigt einen Dialog zur Template-Auswahl, wenn mehrere Vorlagen vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Beispiel-Template:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Sehr geehrte/r Frau/Herr,&lt;br /&gt;
&lt;br /&gt;
beiliegend erhalten Sie die angeforderten Unterlagen.&lt;br /&gt;
&lt;br /&gt;
Mit freundlichen Grüßen&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Protokollierung ==&lt;br /&gt;
&lt;br /&gt;
=== NDJSON-Logs ===&lt;br /&gt;
&lt;br /&gt;
Maschinell lesbar im JSON-Lines Format für technische Weiterverarbeitung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&amp;quot;timestamp&amp;quot;:&amp;quot;2026-01-15T10:30:45Z&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;record&amp;quot;,&amp;quot;record_uuid&amp;quot;:&amp;quot;abc123&amp;quot;,&amp;quot;record_name&amp;quot;:&amp;quot;Invoice-001&amp;quot;,&amp;quot;status&amp;quot;:&amp;quot;sent&amp;quot;}&lt;br /&gt;
{&amp;quot;timestamp&amp;quot;:&amp;quot;2026-01-15T10:30:46Z&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;email&amp;quot;,&amp;quot;to&amp;quot;:&amp;quot;recipient@example.com&amp;quot;,&amp;quot;zip_file&amp;quot;:&amp;quot;archive.zip&amp;quot;,&amp;quot;status&amp;quot;:&amp;quot;created&amp;quot;}&lt;br /&gt;
{&amp;quot;timestamp&amp;quot;:&amp;quot;2026-01-15T10:30:47Z&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;tag&amp;quot;,&amp;quot;record_uuid&amp;quot;:&amp;quot;abc123&amp;quot;,&amp;quot;tag&amp;quot;:&amp;quot;gesendet&amp;quot;,&amp;quot;status&amp;quot;:&amp;quot;applied&amp;quot;}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Markdown-Logs ===&lt;br /&gt;
&lt;br /&gt;
Menschlich lesbar mit Übersichten nach Versandlauf:&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
=== Scripts funktionieren nicht ===&lt;br /&gt;
&lt;br /&gt;
==== Problem: &amp;quot;Script nicht gefunden&amp;quot; ====&lt;br /&gt;
&lt;br /&gt;
Häufigste Ursache: `compile.sh` wurde nicht ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# Prüfen ob `.scpt`-Dateien vorhanden sind: &amp;lt;code&amp;gt;ls ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/Belegversand/Helpers/scripts/&amp;lt;/code&amp;gt;&lt;br /&gt;
# Falls nur `.applescript`-Dateien vorhanden → &amp;lt;code&amp;gt;./compile.sh&amp;lt;/code&amp;gt; erneut ausführen&lt;br /&gt;
# Auf Fehlermeldungen achten&lt;br /&gt;
&lt;br /&gt;
==== Problem: Script-Zugriff verweigert ====&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# System Settings → Privacy &amp;amp; Security → Automation&lt;br /&gt;
# DEVONthink sollte mit entsprechenden Rechten gelistet sein&lt;br /&gt;
# Script Editor öffnen und START.scpt öffnen&lt;br /&gt;
# Compile (⌘K) — sollte ohne Fehler durchlaufen&lt;br /&gt;
&lt;br /&gt;
=== ZIP wird nicht erstellt ===&lt;br /&gt;
&lt;br /&gt;
* ZIP-Passwort in Config überprüfen (keine Sonderzeichen!)&lt;br /&gt;
* Ausreichend Festplatte vorhanden?&lt;br /&gt;
* Staging-Ordner in DEVONthink beschreibbar?&lt;br /&gt;
&lt;br /&gt;
=== Mail-Draft öffnet sich nicht ===&lt;br /&gt;
&lt;br /&gt;
* Apple Mail ist geöffnet?&lt;br /&gt;
* Script-Zugriff für Mail aktiviert?&lt;br /&gt;
* Mail-Templates-Ordner vorhanden?&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Mixed-Year-Selection&amp;quot;-Fehler ===&lt;br /&gt;
&lt;br /&gt;
Dies ist kein Fehler, sondern Schutz vor Versandvermischung:&lt;br /&gt;
&lt;br /&gt;
; Lösung 1: Nur Belege aus einem Buchungsjahr auswählen&lt;br /&gt;
; Lösung 2: Belege in mehreren Versänden verteilen&lt;br /&gt;
&lt;br /&gt;
=== Debug-Informationen aktivieren ===&lt;br /&gt;
&lt;br /&gt;
In `belegversand.conf`:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
WRITE_DEBUG_LOG=true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Debug-Logs erscheinen dann in `/tmp/DT-Belegversand-debug.log`.&lt;br /&gt;
&lt;br /&gt;
== Versionshistorie ==&lt;br /&gt;
&lt;br /&gt;
; 1.4: Booking-Jahr Enforcement, Kompilierungs-Automation, About-Dialog, Wiki-Integration&lt;br /&gt;
; 1.3: Dry-Run Verbesserungen, Markdown-Logs&lt;br /&gt;
; 1.2: Mail-Templates in DEVONthink, interne README&lt;br /&gt;
; 1.1: Konfigurationssystem&lt;br /&gt;
; 1.0: Erste funktionale Version&lt;br /&gt;
&lt;br /&gt;
== Entwicklung ==&lt;br /&gt;
&lt;br /&gt;
Quellcode liegt als `.applescript`-Dateien vor (lesbar, git-freundlich).&lt;br /&gt;
&lt;br /&gt;
Zur lokalen Entwicklung:&lt;br /&gt;
# Quelldateien (`.applescript`) editieren&lt;br /&gt;
# `./compile.sh` ausführen&lt;br /&gt;
# In DEVONthink testen&lt;br /&gt;
# Bei Änderungen: `./compile.sh` erneut ausführen&lt;br /&gt;
&lt;br /&gt;
== Support ==&lt;br /&gt;
&lt;br /&gt;
Für technische Fragen oder Probleme:&lt;br /&gt;
* Wiki-Dokumentation durchlesen (diese Seite)&lt;br /&gt;
* Debug-Log aktivieren und analysieren&lt;br /&gt;
* Im Gitea-Repository ein Issue erstellen (falls Zugriff vorhanden)&lt;br /&gt;
&lt;br /&gt;
== Externe Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation Repository] (privat, erfordert Zugriff)&lt;br /&gt;
* [https://www.devontechnologies.com DEVONthink Homepage]&lt;br /&gt;
* [https://support.apple.com/mail Apple Mail Documentation]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=311</id>
		<title>Belegversand</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=311"/>
		<updated>2026-08-18T16:25:37Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Markdown-Logs */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Belegversand =&lt;br /&gt;
&lt;br /&gt;
== Übersicht ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Belegversand&#039;&#039;&#039; ist eine automatisierte AppleScript-Lösung zur Verwaltung von Dokumenten-Versand in DEVONthink. Das System ermöglicht es, Belege aus einer DEVONthink-Datenbank auszuwählen, diese in ZIP-Archive zu packen (optional mit Passwort) und automatische Mail-Drafts mit konfigurierbaren Empfängern zu erstellen. Zusätzlich erfolgt strukturierte Protokollierung über Logging und Tagging-Mechanismen.&lt;br /&gt;
&lt;br /&gt;
== Sicherheitstechnischer Hinweis! ==&lt;br /&gt;
&lt;br /&gt;
Ich bitte zu beachten, dass die Software allenfalls minimale Sicherheitsanforderungen erfüllt.&lt;br /&gt;
&lt;br /&gt;
    Insbesondere liegt das Passwort für&#039;s ZIP-Archiv unverschlüsselt, im Klartext, in /_config/belegversand.conf. Wer das Passwort schützen möchte, kann das über die DB-Crypto von DEVONthink selbst tun. DEVONthink hat eine Datenbank-Verschlüsselung in den Bordmitteln.&lt;br /&gt;
    Dann bleibt trotzdem der zweite Schwachpunkt: Die ZIP-Verschlüsselung wird in dieser Version 1.4 über das Shell-Tool zip -P auf der Konsolenzeile realisiert. Dahinter steckt das veraltete und kryptographisch schwache ZipCrypto-Verfahren.&lt;br /&gt;
&lt;br /&gt;
Ganz deutlich: Diese Belegversand-Automatisation hab&#039; ich mir gebaut, um Tankbelege, Einkaufszettel und Restaurant-Quittungen an die Steuerberatung zu verschicken! Dafür sind sie prima! Falls es eine Version 1.5 geben sollte, ersetze ich zip -P vermutlich durch eine starke AES-Verschlüsselung, und das Passwort kommt als Hash-Wert in die Config-Datei.&lt;br /&gt;
&lt;br /&gt;
Bis dahin jedoch gilt ganz klar: Wer mit diesen Skripten, in dieser Version 1.4, sicherheitsrelevante Dokumente verschickt, tut das auf eigene Gefahr und handelt fahrlässig!&lt;br /&gt;
&lt;br /&gt;
; Version: 1.4&lt;br /&gt;
; Plattform: macOS 10.13+&lt;br /&gt;
; Abhängigkeiten: DEVONthink 3.x, Apple Mail&lt;br /&gt;
; Lizenz: Privatgebrauch&lt;br /&gt;
; Repository: https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Voraussetzungen ===&lt;br /&gt;
&lt;br /&gt;
* macOS 10.13 oder neuer&lt;br /&gt;
* DEVONthink 3.x&lt;br /&gt;
* Apple Mail&lt;br /&gt;
* AppleScript-Zugriff in Systemeinstellungen aktiviert&lt;br /&gt;
* Git (zum Klonen des Repositories)&lt;br /&gt;
&lt;br /&gt;
=== Schritt-für-Schritt Anleitung ===&lt;br /&gt;
&lt;br /&gt;
==== 1. Verzeichnisstruktur anlegen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&lt;br /&gt;
cd ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 2. Repository klonen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation.git Belegversand&lt;br /&gt;
cd Belegversand&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 3. Scripts kompilieren ====&lt;br /&gt;
&lt;br /&gt;
Dies ist ein &#039;&#039;&#039;wichtiger Schritt&#039;&#039;&#039; und darf nicht übersprungen werden!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chmod +x compile.sh&lt;br /&gt;
./compile.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erwartete Ausgabe:&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Compiliere Belegversand AppleScripts...&lt;br /&gt;
✓ Fertig!&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 4. Erste Ausführung ====&lt;br /&gt;
&lt;br /&gt;
# DEVONthink öffnen&lt;br /&gt;
# Ein Objekt in der gewünschten Datenbank auswählen&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog folgen → Setup wird durchgeführt&lt;br /&gt;
&lt;br /&gt;
Das Setup-Script erstellt automatisch alle notwendigen Ordnerstrukturen und Konfigurationsdateien in DEVONthink.&lt;br /&gt;
&lt;br /&gt;
== Wichtig: .applescript vs. .scpt Dateien ==&lt;br /&gt;
&lt;br /&gt;
Im Repository gibt es zwei Arten von AppleScript-Dateien:&lt;br /&gt;
&lt;br /&gt;
; .applescript: Quelldateien (lesbar, nur für Entwicklung)&lt;br /&gt;
; .scpt: Kompilierte Skripte (binär, werden von DEVONthink ausgeführt)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Kritisch:&#039;&#039;&#039; Die `.applescript`-Quelldateien funktionieren &#039;&#039;&#039;nicht&#039;&#039;&#039; direkt in DEVONthink. Sie enthalten relative Pfade, die zur Laufzeit expandiert werden müssen.&lt;br /&gt;
&lt;br /&gt;
Das `compile.sh`-Script:&lt;br /&gt;
# Kompiliert alle `.applescript` zu `.scpt`&lt;br /&gt;
# Löscht anschließend die `.applescript`-Dateien&lt;br /&gt;
# Hinterlässt nur funktionsfähige `.scpt`-Dateien&lt;br /&gt;
&lt;br /&gt;
Falls nach dem Clone noch `.applescript`-Dateien vorhanden sind, war `compile.sh` nicht erfolgreich. In diesem Fall erneut ausführen und auf Fehlermeldungen achten.&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
=== Automatische Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Nach der ersten Ausführung erstellt das System automatisch folgende Struktur in DEVONthink:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
_config/&lt;br /&gt;
├── belegversand.conf              # Konfigurationsdatei&lt;br /&gt;
├── mail_vorlagen/                 # Mail-Templates&lt;br /&gt;
│   └── belegversand               # Standard-Template&lt;br /&gt;
├── README-Belegversand            # Interne Hilfe&lt;br /&gt;
└── [weitere Dateien nach Versand]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Konfigurationsdatei ===&lt;br /&gt;
&lt;br /&gt;
Die Datei `belegversand.conf` befindet sich in DEVONthink unter `_config → belegversand.conf`.&lt;br /&gt;
&lt;br /&gt;
==== Wichtigste Parameter ====&lt;br /&gt;
&lt;br /&gt;
; MAIL_TO_DEFAULT: Standard-Empfänger (z.B. steuer@example.com)&lt;br /&gt;
; MAIL_CC_TO_DEFAULT: Standard-CC-Empfänger (optional)&lt;br /&gt;
; MAIL_SUBJECT_PREFIX: Präfix für den Mail-Betreff (z.B. &amp;quot;Belegversand&amp;quot;)&lt;br /&gt;
; ZIP_PASSWORD_DEFAULT: Standard-Passwort für ZIP-Archive (optional, keine Sonderzeichen)&lt;br /&gt;
; LOG_SENT_GROUP_NAME: Name der Ordnergruppe für Versandprotokolle (Standard: &amp;quot;Versendet&amp;quot;)&lt;br /&gt;
; SENT_TAG_FOR_DOCS: Tag für versendete Belege (Standard: &amp;quot;gesendet&amp;quot;)&lt;br /&gt;
; WRITE_DEBUG_LOG: Debug-Logging aktivieren (true/false)&lt;br /&gt;
; SHOW_README: Willkommensdialog beim Start anzeigen (true/false)&lt;br /&gt;
; MAILBODY_FOLDER_NAME: Ordner für Mail-Templates (Standard: &amp;quot;mail_vorlagen&amp;quot;)&lt;br /&gt;
; MAILBODY_RECORD_NAME: Name des Standard-Templates (Standard: &amp;quot;belegversand&amp;quot;)&lt;br /&gt;
; PATH_TO_DRYRUN_PREVIEW: Speicherort der Dry-Run Vorschau-Datei&lt;br /&gt;
&lt;br /&gt;
==== Multiple Empfänger (CSV-Format) ====&lt;br /&gt;
&lt;br /&gt;
Mehrere E-Mail-Adressen können durch Kommas getrennt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
MAIL_TO_DEFAULT=recipient1@example.com, recipient2@example.com&lt;br /&gt;
MAIL_CC_TO_DEFAULT=cc1@example.com, cc2@example.com&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Adressen werden automatisch geparst und in Apple Mail einzeln eingefügt.&lt;br /&gt;
&lt;br /&gt;
== Verwendung ==&lt;br /&gt;
&lt;br /&gt;
=== Grundablauf ===&lt;br /&gt;
&lt;br /&gt;
# Belege in DEVONthink auswählen (Mehrfachauswahl möglich)&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog beantwortet (Empfänger, ZIP-Passwort, Dry-Run?)&lt;br /&gt;
# Dry-Run Vorschau anschauen (optional)&lt;br /&gt;
# Echtlauf → ZIP-Archive erstellt, Mail-Draft geöffnet, Logging durchgeführt&lt;br /&gt;
&lt;br /&gt;
=== Menü-Befehle ===&lt;br /&gt;
&lt;br /&gt;
; START: Haupteinstiegspunkt — startet Setup oder Versand&lt;br /&gt;
; About...: About-Dialog mit Versionsinformation und Links&lt;br /&gt;
&lt;br /&gt;
=== Booking-Jahr Enforcement ===&lt;br /&gt;
&lt;br /&gt;
Das System verhindert Versandvermischung über mehrere Jahre:&lt;br /&gt;
&lt;br /&gt;
; Mixed-Year Selection: Werden Belege aus verschiedenen Jahren auswählt, wird ein Fehler zurückgewiesen&lt;br /&gt;
; Separate Protokolle: Jedes Buchungsjahr hat eigene Versendet-Ordner mit separaten Logs&lt;br /&gt;
; Outsider-Belege: Dokumente außerhalb der Jahresstruktur werden separat gehandhabt&lt;br /&gt;
&lt;br /&gt;
Beispiel-Struktur:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Belege/&lt;br /&gt;
├── 2026/&lt;br /&gt;
│   ├── 01_Januar/&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
├── 2027/&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
└── Provisionsabrechnungen/&lt;br /&gt;
    └── [← Separate Outsider-Logs]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dry-Run Modus ===&lt;br /&gt;
&lt;br /&gt;
Vor jedem echten Versand kann ein Dry-Run durchgeführt werden:&lt;br /&gt;
&lt;br /&gt;
# Simuliert den kompletten Versandprozess&lt;br /&gt;
# Erstellt Vorschau-Datei mit allen Details&lt;br /&gt;
# Zeigt Dialog mit Zusammenfassung&lt;br /&gt;
# User kann bestätigen oder abbrechen&lt;br /&gt;
&lt;br /&gt;
Die Vorschau-Datei wird auf der lokalen Festplatte gespeichert (Pfad konfigurierbar).&lt;br /&gt;
&lt;br /&gt;
=== Mail-Drafts ===&lt;br /&gt;
&lt;br /&gt;
Das System erstellt keinen automatischen Versand, sondern Mail-Drafts:&lt;br /&gt;
&lt;br /&gt;
# ZIP-Archive werden erzeugt&lt;br /&gt;
# Apple Mail öffnet mit neuem Draft (nicht gesendet!)&lt;br /&gt;
# User kann Template prüfen, weitere Empfänger hinzufügen&lt;br /&gt;
# Benutzerdefinierter Versand per Knopfdruck in Mail&lt;br /&gt;
&lt;br /&gt;
Dies ermöglicht volle Kontrolle über den Versand.&lt;br /&gt;
&lt;br /&gt;
=== Mail-Templates ===&lt;br /&gt;
&lt;br /&gt;
Templates werden aus DEVONthink geladen (`_config/mail_vorlagen/`).&lt;br /&gt;
&lt;br /&gt;
Das System zeigt einen Dialog zur Template-Auswahl, wenn mehrere Vorlagen vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Beispiel-Template:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Sehr geehrte/r Frau/Herr,&lt;br /&gt;
&lt;br /&gt;
beiliegend erhalten Sie die angeforderten Unterlagen.&lt;br /&gt;
&lt;br /&gt;
Mit freundlichen Grüßen&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Protokollierung ==&lt;br /&gt;
&lt;br /&gt;
=== NDJSON-Logs ===&lt;br /&gt;
&lt;br /&gt;
Maschinell lesbar im JSON-Lines Format für technische Weiterverarbeitung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&amp;quot;timestamp&amp;quot;:&amp;quot;2026-01-15T10:30:45Z&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;record&amp;quot;,&amp;quot;record_uuid&amp;quot;:&amp;quot;abc123&amp;quot;,&amp;quot;record_name&amp;quot;:&amp;quot;Invoice-001&amp;quot;,&amp;quot;status&amp;quot;:&amp;quot;sent&amp;quot;}&lt;br /&gt;
{&amp;quot;timestamp&amp;quot;:&amp;quot;2026-01-15T10:30:46Z&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;email&amp;quot;,&amp;quot;to&amp;quot;:&amp;quot;recipient@example.com&amp;quot;,&amp;quot;zip_file&amp;quot;:&amp;quot;archive.zip&amp;quot;,&amp;quot;status&amp;quot;:&amp;quot;created&amp;quot;}&lt;br /&gt;
{&amp;quot;timestamp&amp;quot;:&amp;quot;2026-01-15T10:30:47Z&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;tag&amp;quot;,&amp;quot;record_uuid&amp;quot;:&amp;quot;abc123&amp;quot;,&amp;quot;tag&amp;quot;:&amp;quot;gesendet&amp;quot;,&amp;quot;status&amp;quot;:&amp;quot;applied&amp;quot;}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Markdown-Logs ===&lt;br /&gt;
&lt;br /&gt;
Menschlich lesbar mit Übersichten nach Versandlauf:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
# Belegversand Logs — 2026&lt;br /&gt;
&lt;br /&gt;
## Versandlauf 2026-01-15 10:30&lt;br /&gt;
**Versendete Belege:** 5 Stück&lt;br /&gt;
**Empfänger:** recipient@example.com&lt;br /&gt;
**ZIP-Datei:** belegversand_2026-01-15_103045.zip&lt;br /&gt;
**Passwort:** [konfiguriert]&lt;br /&gt;
**Status:** Erfolgreich&lt;br /&gt;
&lt;br /&gt;
### Versandte Dokumente&lt;br /&gt;
- Invoice-001 (UUID: abc123...)&lt;br /&gt;
- Invoice-002 (UUID: def456...)&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
=== Scripts funktionieren nicht ===&lt;br /&gt;
&lt;br /&gt;
==== Problem: &amp;quot;Script nicht gefunden&amp;quot; ====&lt;br /&gt;
&lt;br /&gt;
Häufigste Ursache: `compile.sh` wurde nicht ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# Prüfen ob `.scpt`-Dateien vorhanden sind: &amp;lt;code&amp;gt;ls ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/Belegversand/Helpers/scripts/&amp;lt;/code&amp;gt;&lt;br /&gt;
# Falls nur `.applescript`-Dateien vorhanden → &amp;lt;code&amp;gt;./compile.sh&amp;lt;/code&amp;gt; erneut ausführen&lt;br /&gt;
# Auf Fehlermeldungen achten&lt;br /&gt;
&lt;br /&gt;
==== Problem: Script-Zugriff verweigert ====&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# System Settings → Privacy &amp;amp; Security → Automation&lt;br /&gt;
# DEVONthink sollte mit entsprechenden Rechten gelistet sein&lt;br /&gt;
# Script Editor öffnen und START.scpt öffnen&lt;br /&gt;
# Compile (⌘K) — sollte ohne Fehler durchlaufen&lt;br /&gt;
&lt;br /&gt;
=== ZIP wird nicht erstellt ===&lt;br /&gt;
&lt;br /&gt;
* ZIP-Passwort in Config überprüfen (keine Sonderzeichen!)&lt;br /&gt;
* Ausreichend Festplatte vorhanden?&lt;br /&gt;
* Staging-Ordner in DEVONthink beschreibbar?&lt;br /&gt;
&lt;br /&gt;
=== Mail-Draft öffnet sich nicht ===&lt;br /&gt;
&lt;br /&gt;
* Apple Mail ist geöffnet?&lt;br /&gt;
* Script-Zugriff für Mail aktiviert?&lt;br /&gt;
* Mail-Templates-Ordner vorhanden?&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Mixed-Year-Selection&amp;quot;-Fehler ===&lt;br /&gt;
&lt;br /&gt;
Dies ist kein Fehler, sondern Schutz vor Versandvermischung:&lt;br /&gt;
&lt;br /&gt;
; Lösung 1: Nur Belege aus einem Buchungsjahr auswählen&lt;br /&gt;
; Lösung 2: Belege in mehreren Versänden verteilen&lt;br /&gt;
&lt;br /&gt;
=== Debug-Informationen aktivieren ===&lt;br /&gt;
&lt;br /&gt;
In `belegversand.conf`:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
WRITE_DEBUG_LOG=true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Debug-Logs erscheinen dann in `/tmp/DT-Belegversand-debug.log`.&lt;br /&gt;
&lt;br /&gt;
== Versionshistorie ==&lt;br /&gt;
&lt;br /&gt;
; 1.4: Booking-Jahr Enforcement, Kompilierungs-Automation, About-Dialog, Wiki-Integration&lt;br /&gt;
; 1.3: Dry-Run Verbesserungen, Markdown-Logs&lt;br /&gt;
; 1.2: Mail-Templates in DEVONthink, interne README&lt;br /&gt;
; 1.1: Konfigurationssystem&lt;br /&gt;
; 1.0: Erste funktionale Version&lt;br /&gt;
&lt;br /&gt;
== Entwicklung ==&lt;br /&gt;
&lt;br /&gt;
Quellcode liegt als `.applescript`-Dateien vor (lesbar, git-freundlich).&lt;br /&gt;
&lt;br /&gt;
Zur lokalen Entwicklung:&lt;br /&gt;
# Quelldateien (`.applescript`) editieren&lt;br /&gt;
# `./compile.sh` ausführen&lt;br /&gt;
# In DEVONthink testen&lt;br /&gt;
# Bei Änderungen: `./compile.sh` erneut ausführen&lt;br /&gt;
&lt;br /&gt;
== Support ==&lt;br /&gt;
&lt;br /&gt;
Für technische Fragen oder Probleme:&lt;br /&gt;
* Wiki-Dokumentation durchlesen (diese Seite)&lt;br /&gt;
* Debug-Log aktivieren und analysieren&lt;br /&gt;
* Im Gitea-Repository ein Issue erstellen (falls Zugriff vorhanden)&lt;br /&gt;
&lt;br /&gt;
== Externe Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation Repository] (privat, erfordert Zugriff)&lt;br /&gt;
* [https://www.devontechnologies.com DEVONthink Homepage]&lt;br /&gt;
* [https://support.apple.com/mail Apple Mail Documentation]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=310</id>
		<title>Belegversand</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=310"/>
		<updated>2026-08-18T16:24:40Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* 2. Repository klonen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Belegversand =&lt;br /&gt;
&lt;br /&gt;
== Übersicht ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Belegversand&#039;&#039;&#039; ist eine automatisierte AppleScript-Lösung zur Verwaltung von Dokumenten-Versand in DEVONthink. Das System ermöglicht es, Belege aus einer DEVONthink-Datenbank auszuwählen, diese in ZIP-Archive zu packen (optional mit Passwort) und automatische Mail-Drafts mit konfigurierbaren Empfängern zu erstellen. Zusätzlich erfolgt strukturierte Protokollierung über Logging und Tagging-Mechanismen.&lt;br /&gt;
&lt;br /&gt;
== Sicherheitstechnischer Hinweis! ==&lt;br /&gt;
&lt;br /&gt;
Ich bitte zu beachten, dass die Software allenfalls minimale Sicherheitsanforderungen erfüllt.&lt;br /&gt;
&lt;br /&gt;
    Insbesondere liegt das Passwort für&#039;s ZIP-Archiv unverschlüsselt, im Klartext, in /_config/belegversand.conf. Wer das Passwort schützen möchte, kann das über die DB-Crypto von DEVONthink selbst tun. DEVONthink hat eine Datenbank-Verschlüsselung in den Bordmitteln.&lt;br /&gt;
    Dann bleibt trotzdem der zweite Schwachpunkt: Die ZIP-Verschlüsselung wird in dieser Version 1.4 über das Shell-Tool zip -P auf der Konsolenzeile realisiert. Dahinter steckt das veraltete und kryptographisch schwache ZipCrypto-Verfahren.&lt;br /&gt;
&lt;br /&gt;
Ganz deutlich: Diese Belegversand-Automatisation hab&#039; ich mir gebaut, um Tankbelege, Einkaufszettel und Restaurant-Quittungen an die Steuerberatung zu verschicken! Dafür sind sie prima! Falls es eine Version 1.5 geben sollte, ersetze ich zip -P vermutlich durch eine starke AES-Verschlüsselung, und das Passwort kommt als Hash-Wert in die Config-Datei.&lt;br /&gt;
&lt;br /&gt;
Bis dahin jedoch gilt ganz klar: Wer mit diesen Skripten, in dieser Version 1.4, sicherheitsrelevante Dokumente verschickt, tut das auf eigene Gefahr und handelt fahrlässig!&lt;br /&gt;
&lt;br /&gt;
; Version: 1.4&lt;br /&gt;
; Plattform: macOS 10.13+&lt;br /&gt;
; Abhängigkeiten: DEVONthink 3.x, Apple Mail&lt;br /&gt;
; Lizenz: Privatgebrauch&lt;br /&gt;
; Repository: https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Voraussetzungen ===&lt;br /&gt;
&lt;br /&gt;
* macOS 10.13 oder neuer&lt;br /&gt;
* DEVONthink 3.x&lt;br /&gt;
* Apple Mail&lt;br /&gt;
* AppleScript-Zugriff in Systemeinstellungen aktiviert&lt;br /&gt;
* Git (zum Klonen des Repositories)&lt;br /&gt;
&lt;br /&gt;
=== Schritt-für-Schritt Anleitung ===&lt;br /&gt;
&lt;br /&gt;
==== 1. Verzeichnisstruktur anlegen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&lt;br /&gt;
cd ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 2. Repository klonen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation.git Belegversand&lt;br /&gt;
cd Belegversand&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 3. Scripts kompilieren ====&lt;br /&gt;
&lt;br /&gt;
Dies ist ein &#039;&#039;&#039;wichtiger Schritt&#039;&#039;&#039; und darf nicht übersprungen werden!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chmod +x compile.sh&lt;br /&gt;
./compile.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erwartete Ausgabe:&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Compiliere Belegversand AppleScripts...&lt;br /&gt;
✓ Fertig!&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 4. Erste Ausführung ====&lt;br /&gt;
&lt;br /&gt;
# DEVONthink öffnen&lt;br /&gt;
# Ein Objekt in der gewünschten Datenbank auswählen&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog folgen → Setup wird durchgeführt&lt;br /&gt;
&lt;br /&gt;
Das Setup-Script erstellt automatisch alle notwendigen Ordnerstrukturen und Konfigurationsdateien in DEVONthink.&lt;br /&gt;
&lt;br /&gt;
== Wichtig: .applescript vs. .scpt Dateien ==&lt;br /&gt;
&lt;br /&gt;
Im Repository gibt es zwei Arten von AppleScript-Dateien:&lt;br /&gt;
&lt;br /&gt;
; .applescript: Quelldateien (lesbar, nur für Entwicklung)&lt;br /&gt;
; .scpt: Kompilierte Skripte (binär, werden von DEVONthink ausgeführt)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Kritisch:&#039;&#039;&#039; Die `.applescript`-Quelldateien funktionieren &#039;&#039;&#039;nicht&#039;&#039;&#039; direkt in DEVONthink. Sie enthalten relative Pfade, die zur Laufzeit expandiert werden müssen.&lt;br /&gt;
&lt;br /&gt;
Das `compile.sh`-Script:&lt;br /&gt;
# Kompiliert alle `.applescript` zu `.scpt`&lt;br /&gt;
# Löscht anschließend die `.applescript`-Dateien&lt;br /&gt;
# Hinterlässt nur funktionsfähige `.scpt`-Dateien&lt;br /&gt;
&lt;br /&gt;
Falls nach dem Clone noch `.applescript`-Dateien vorhanden sind, war `compile.sh` nicht erfolgreich. In diesem Fall erneut ausführen und auf Fehlermeldungen achten.&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
=== Automatische Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Nach der ersten Ausführung erstellt das System automatisch folgende Struktur in DEVONthink:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
_config/&lt;br /&gt;
├── belegversand.conf              # Konfigurationsdatei&lt;br /&gt;
├── mail_vorlagen/                 # Mail-Templates&lt;br /&gt;
│   └── belegversand               # Standard-Template&lt;br /&gt;
├── README-Belegversand            # Interne Hilfe&lt;br /&gt;
└── [weitere Dateien nach Versand]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Konfigurationsdatei ===&lt;br /&gt;
&lt;br /&gt;
Die Datei `belegversand.conf` befindet sich in DEVONthink unter `_config → belegversand.conf`.&lt;br /&gt;
&lt;br /&gt;
==== Wichtigste Parameter ====&lt;br /&gt;
&lt;br /&gt;
; MAIL_TO_DEFAULT: Standard-Empfänger (z.B. steuer@example.com)&lt;br /&gt;
; MAIL_CC_TO_DEFAULT: Standard-CC-Empfänger (optional)&lt;br /&gt;
; MAIL_SUBJECT_PREFIX: Präfix für den Mail-Betreff (z.B. &amp;quot;Belegversand&amp;quot;)&lt;br /&gt;
; ZIP_PASSWORD_DEFAULT: Standard-Passwort für ZIP-Archive (optional, keine Sonderzeichen)&lt;br /&gt;
; LOG_SENT_GROUP_NAME: Name der Ordnergruppe für Versandprotokolle (Standard: &amp;quot;Versendet&amp;quot;)&lt;br /&gt;
; SENT_TAG_FOR_DOCS: Tag für versendete Belege (Standard: &amp;quot;gesendet&amp;quot;)&lt;br /&gt;
; WRITE_DEBUG_LOG: Debug-Logging aktivieren (true/false)&lt;br /&gt;
; SHOW_README: Willkommensdialog beim Start anzeigen (true/false)&lt;br /&gt;
; MAILBODY_FOLDER_NAME: Ordner für Mail-Templates (Standard: &amp;quot;mail_vorlagen&amp;quot;)&lt;br /&gt;
; MAILBODY_RECORD_NAME: Name des Standard-Templates (Standard: &amp;quot;belegversand&amp;quot;)&lt;br /&gt;
; PATH_TO_DRYRUN_PREVIEW: Speicherort der Dry-Run Vorschau-Datei&lt;br /&gt;
&lt;br /&gt;
==== Multiple Empfänger (CSV-Format) ====&lt;br /&gt;
&lt;br /&gt;
Mehrere E-Mail-Adressen können durch Kommas getrennt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
MAIL_TO_DEFAULT=recipient1@example.com, recipient2@example.com&lt;br /&gt;
MAIL_CC_TO_DEFAULT=cc1@example.com, cc2@example.com&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Adressen werden automatisch geparst und in Apple Mail einzeln eingefügt.&lt;br /&gt;
&lt;br /&gt;
== Verwendung ==&lt;br /&gt;
&lt;br /&gt;
=== Grundablauf ===&lt;br /&gt;
&lt;br /&gt;
# Belege in DEVONthink auswählen (Mehrfachauswahl möglich)&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog beantwortet (Empfänger, ZIP-Passwort, Dry-Run?)&lt;br /&gt;
# Dry-Run Vorschau anschauen (optional)&lt;br /&gt;
# Echtlauf → ZIP-Archive erstellt, Mail-Draft geöffnet, Logging durchgeführt&lt;br /&gt;
&lt;br /&gt;
=== Menü-Befehle ===&lt;br /&gt;
&lt;br /&gt;
; START: Haupteinstiegspunkt — startet Setup oder Versand&lt;br /&gt;
; About...: About-Dialog mit Versionsinformation und Links&lt;br /&gt;
&lt;br /&gt;
=== Booking-Jahr Enforcement ===&lt;br /&gt;
&lt;br /&gt;
Das System verhindert Versandvermischung über mehrere Jahre:&lt;br /&gt;
&lt;br /&gt;
; Mixed-Year Selection: Werden Belege aus verschiedenen Jahren auswählt, wird ein Fehler zurückgewiesen&lt;br /&gt;
; Separate Protokolle: Jedes Buchungsjahr hat eigene Versendet-Ordner mit separaten Logs&lt;br /&gt;
; Outsider-Belege: Dokumente außerhalb der Jahresstruktur werden separat gehandhabt&lt;br /&gt;
&lt;br /&gt;
Beispiel-Struktur:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Belege/&lt;br /&gt;
├── 2026/&lt;br /&gt;
│   ├── 01_Januar/&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
├── 2027/&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
└── Provisionsabrechnungen/&lt;br /&gt;
    └── [← Separate Outsider-Logs]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dry-Run Modus ===&lt;br /&gt;
&lt;br /&gt;
Vor jedem echten Versand kann ein Dry-Run durchgeführt werden:&lt;br /&gt;
&lt;br /&gt;
# Simuliert den kompletten Versandprozess&lt;br /&gt;
# Erstellt Vorschau-Datei mit allen Details&lt;br /&gt;
# Zeigt Dialog mit Zusammenfassung&lt;br /&gt;
# User kann bestätigen oder abbrechen&lt;br /&gt;
&lt;br /&gt;
Die Vorschau-Datei wird auf der lokalen Festplatte gespeichert (Pfad konfigurierbar).&lt;br /&gt;
&lt;br /&gt;
=== Mail-Drafts ===&lt;br /&gt;
&lt;br /&gt;
Das System erstellt keinen automatischen Versand, sondern Mail-Drafts:&lt;br /&gt;
&lt;br /&gt;
# ZIP-Archive werden erzeugt&lt;br /&gt;
# Apple Mail öffnet mit neuem Draft (nicht gesendet!)&lt;br /&gt;
# User kann Template prüfen, weitere Empfänger hinzufügen&lt;br /&gt;
# Benutzerdefinierter Versand per Knopfdruck in Mail&lt;br /&gt;
&lt;br /&gt;
Dies ermöglicht volle Kontrolle über den Versand.&lt;br /&gt;
&lt;br /&gt;
=== Mail-Templates ===&lt;br /&gt;
&lt;br /&gt;
Templates werden aus DEVONthink geladen (`_config/mail_vorlagen/`).&lt;br /&gt;
&lt;br /&gt;
Das System zeigt einen Dialog zur Template-Auswahl, wenn mehrere Vorlagen vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Beispiel-Template:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Sehr geehrte/r Frau/Herr,&lt;br /&gt;
&lt;br /&gt;
beiliegend erhalten Sie die angeforderten Unterlagen.&lt;br /&gt;
&lt;br /&gt;
Mit freundlichen Grüßen&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Protokollierung ==&lt;br /&gt;
&lt;br /&gt;
=== NDJSON-Logs ===&lt;br /&gt;
&lt;br /&gt;
Maschinell lesbar im JSON-Lines Format für technische Weiterverarbeitung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&amp;quot;timestamp&amp;quot;:&amp;quot;2026-01-15T10:30:45Z&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;record&amp;quot;,&amp;quot;record_uuid&amp;quot;:&amp;quot;abc123&amp;quot;,&amp;quot;record_name&amp;quot;:&amp;quot;Invoice-001&amp;quot;,&amp;quot;status&amp;quot;:&amp;quot;sent&amp;quot;}&lt;br /&gt;
{&amp;quot;timestamp&amp;quot;:&amp;quot;2026-01-15T10:30:46Z&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;email&amp;quot;,&amp;quot;to&amp;quot;:&amp;quot;recipient@example.com&amp;quot;,&amp;quot;zip_file&amp;quot;:&amp;quot;archive.zip&amp;quot;,&amp;quot;status&amp;quot;:&amp;quot;created&amp;quot;}&lt;br /&gt;
{&amp;quot;timestamp&amp;quot;:&amp;quot;2026-01-15T10:30:47Z&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;tag&amp;quot;,&amp;quot;record_uuid&amp;quot;:&amp;quot;abc123&amp;quot;,&amp;quot;tag&amp;quot;:&amp;quot;gesendet&amp;quot;,&amp;quot;status&amp;quot;:&amp;quot;applied&amp;quot;}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Markdown-Logs ===&lt;br /&gt;
&lt;br /&gt;
Menschlich lesbar mit Übersichten nach Versandlauf:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
# Belegversand Logs — 2026&lt;br /&gt;
&lt;br /&gt;
## Versandlauf 2026-01-15 10:30&lt;br /&gt;
**Versendete Belege:** 5 Stück&lt;br /&gt;
**Empfänger:** recipient@example.com&lt;br /&gt;
**ZIP-Datei:** belegversand_2026-01-15_103045.zip&lt;br /&gt;
**Passwort:** [konfiguriert]&lt;br /&gt;
**Status:** Erfolgreich&lt;br /&gt;
&lt;br /&gt;
### Versandte Dokumente&lt;br /&gt;
- Invoice-001 (UUID: abc123...)&lt;br /&gt;
- Invoice-002 (UUID: def456...)&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
=== Scripts funktionieren nicht ===&lt;br /&gt;
&lt;br /&gt;
==== Problem: &amp;quot;Script nicht gefunden&amp;quot; ====&lt;br /&gt;
&lt;br /&gt;
Häufigste Ursache: `compile.sh` wurde nicht ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# Prüfen ob `.scpt`-Dateien vorhanden sind: &amp;lt;code&amp;gt;ls ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/Belegversand/Helpers/scripts/&amp;lt;/code&amp;gt;&lt;br /&gt;
# Falls nur `.applescript`-Dateien vorhanden → &amp;lt;code&amp;gt;./compile.sh&amp;lt;/code&amp;gt; erneut ausführen&lt;br /&gt;
# Auf Fehlermeldungen achten&lt;br /&gt;
&lt;br /&gt;
==== Problem: Script-Zugriff verweigert ====&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# System Settings → Privacy &amp;amp; Security → Automation&lt;br /&gt;
# DEVONthink sollte mit entsprechenden Rechten gelistet sein&lt;br /&gt;
# Script Editor öffnen und START.scpt öffnen&lt;br /&gt;
# Compile (⌘K) — sollte ohne Fehler durchlaufen&lt;br /&gt;
&lt;br /&gt;
=== ZIP wird nicht erstellt ===&lt;br /&gt;
&lt;br /&gt;
* ZIP-Passwort in Config überprüfen (keine Sonderzeichen!)&lt;br /&gt;
* Ausreichend Festplatte vorhanden?&lt;br /&gt;
* Staging-Ordner in DEVONthink beschreibbar?&lt;br /&gt;
&lt;br /&gt;
=== Mail-Draft öffnet sich nicht ===&lt;br /&gt;
&lt;br /&gt;
* Apple Mail ist geöffnet?&lt;br /&gt;
* Script-Zugriff für Mail aktiviert?&lt;br /&gt;
* Mail-Templates-Ordner vorhanden?&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Mixed-Year-Selection&amp;quot;-Fehler ===&lt;br /&gt;
&lt;br /&gt;
Dies ist kein Fehler, sondern Schutz vor Versandvermischung:&lt;br /&gt;
&lt;br /&gt;
; Lösung 1: Nur Belege aus einem Buchungsjahr auswählen&lt;br /&gt;
; Lösung 2: Belege in mehreren Versänden verteilen&lt;br /&gt;
&lt;br /&gt;
=== Debug-Informationen aktivieren ===&lt;br /&gt;
&lt;br /&gt;
In `belegversand.conf`:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
WRITE_DEBUG_LOG=true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Debug-Logs erscheinen dann in `/tmp/DT-Belegversand-debug.log`.&lt;br /&gt;
&lt;br /&gt;
== Versionshistorie ==&lt;br /&gt;
&lt;br /&gt;
; 1.4: Booking-Jahr Enforcement, Kompilierungs-Automation, About-Dialog, Wiki-Integration&lt;br /&gt;
; 1.3: Dry-Run Verbesserungen, Markdown-Logs&lt;br /&gt;
; 1.2: Mail-Templates in DEVONthink, interne README&lt;br /&gt;
; 1.1: Konfigurationssystem&lt;br /&gt;
; 1.0: Erste funktionale Version&lt;br /&gt;
&lt;br /&gt;
== Entwicklung ==&lt;br /&gt;
&lt;br /&gt;
Quellcode liegt als `.applescript`-Dateien vor (lesbar, git-freundlich).&lt;br /&gt;
&lt;br /&gt;
Zur lokalen Entwicklung:&lt;br /&gt;
# Quelldateien (`.applescript`) editieren&lt;br /&gt;
# `./compile.sh` ausführen&lt;br /&gt;
# In DEVONthink testen&lt;br /&gt;
# Bei Änderungen: `./compile.sh` erneut ausführen&lt;br /&gt;
&lt;br /&gt;
== Support ==&lt;br /&gt;
&lt;br /&gt;
Für technische Fragen oder Probleme:&lt;br /&gt;
* Wiki-Dokumentation durchlesen (diese Seite)&lt;br /&gt;
* Debug-Log aktivieren und analysieren&lt;br /&gt;
* Im Gitea-Repository ein Issue erstellen (falls Zugriff vorhanden)&lt;br /&gt;
&lt;br /&gt;
== Externe Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation Repository] (privat, erfordert Zugriff)&lt;br /&gt;
* [https://www.devontechnologies.com DEVONthink Homepage]&lt;br /&gt;
* [https://support.apple.com/mail Apple Mail Documentation]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=309</id>
		<title>Belegversand</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=309"/>
		<updated>2026-08-18T16:23:07Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* 1. Verzeichnisstruktur anlegen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Belegversand =&lt;br /&gt;
&lt;br /&gt;
== Übersicht ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Belegversand&#039;&#039;&#039; ist eine automatisierte AppleScript-Lösung zur Verwaltung von Dokumenten-Versand in DEVONthink. Das System ermöglicht es, Belege aus einer DEVONthink-Datenbank auszuwählen, diese in ZIP-Archive zu packen (optional mit Passwort) und automatische Mail-Drafts mit konfigurierbaren Empfängern zu erstellen. Zusätzlich erfolgt strukturierte Protokollierung über Logging und Tagging-Mechanismen.&lt;br /&gt;
&lt;br /&gt;
== Sicherheitstechnischer Hinweis! ==&lt;br /&gt;
&lt;br /&gt;
Ich bitte zu beachten, dass die Software allenfalls minimale Sicherheitsanforderungen erfüllt.&lt;br /&gt;
&lt;br /&gt;
    Insbesondere liegt das Passwort für&#039;s ZIP-Archiv unverschlüsselt, im Klartext, in /_config/belegversand.conf. Wer das Passwort schützen möchte, kann das über die DB-Crypto von DEVONthink selbst tun. DEVONthink hat eine Datenbank-Verschlüsselung in den Bordmitteln.&lt;br /&gt;
    Dann bleibt trotzdem der zweite Schwachpunkt: Die ZIP-Verschlüsselung wird in dieser Version 1.4 über das Shell-Tool zip -P auf der Konsolenzeile realisiert. Dahinter steckt das veraltete und kryptographisch schwache ZipCrypto-Verfahren.&lt;br /&gt;
&lt;br /&gt;
Ganz deutlich: Diese Belegversand-Automatisation hab&#039; ich mir gebaut, um Tankbelege, Einkaufszettel und Restaurant-Quittungen an die Steuerberatung zu verschicken! Dafür sind sie prima! Falls es eine Version 1.5 geben sollte, ersetze ich zip -P vermutlich durch eine starke AES-Verschlüsselung, und das Passwort kommt als Hash-Wert in die Config-Datei.&lt;br /&gt;
&lt;br /&gt;
Bis dahin jedoch gilt ganz klar: Wer mit diesen Skripten, in dieser Version 1.4, sicherheitsrelevante Dokumente verschickt, tut das auf eigene Gefahr und handelt fahrlässig!&lt;br /&gt;
&lt;br /&gt;
; Version: 1.4&lt;br /&gt;
; Plattform: macOS 10.13+&lt;br /&gt;
; Abhängigkeiten: DEVONthink 3.x, Apple Mail&lt;br /&gt;
; Lizenz: Privatgebrauch&lt;br /&gt;
; Repository: https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Voraussetzungen ===&lt;br /&gt;
&lt;br /&gt;
* macOS 10.13 oder neuer&lt;br /&gt;
* DEVONthink 3.x&lt;br /&gt;
* Apple Mail&lt;br /&gt;
* AppleScript-Zugriff in Systemeinstellungen aktiviert&lt;br /&gt;
* Git (zum Klonen des Repositories)&lt;br /&gt;
&lt;br /&gt;
=== Schritt-für-Schritt Anleitung ===&lt;br /&gt;
&lt;br /&gt;
==== 1. Verzeichnisstruktur anlegen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&lt;br /&gt;
cd ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 2. Repository klonen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation.git Belegversand&lt;br /&gt;
cd Belegversand&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 3. Scripts kompilieren ====&lt;br /&gt;
&lt;br /&gt;
Dies ist ein &#039;&#039;&#039;wichtiger Schritt&#039;&#039;&#039; und darf nicht übersprungen werden!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chmod +x compile.sh&lt;br /&gt;
./compile.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erwartete Ausgabe:&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Compiliere Belegversand AppleScripts...&lt;br /&gt;
✓ Fertig!&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 4. Erste Ausführung ====&lt;br /&gt;
&lt;br /&gt;
# DEVONthink öffnen&lt;br /&gt;
# Ein Objekt in der gewünschten Datenbank auswählen&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog folgen → Setup wird durchgeführt&lt;br /&gt;
&lt;br /&gt;
Das Setup-Script erstellt automatisch alle notwendigen Ordnerstrukturen und Konfigurationsdateien in DEVONthink.&lt;br /&gt;
&lt;br /&gt;
== Wichtig: .applescript vs. .scpt Dateien ==&lt;br /&gt;
&lt;br /&gt;
Im Repository gibt es zwei Arten von AppleScript-Dateien:&lt;br /&gt;
&lt;br /&gt;
; .applescript: Quelldateien (lesbar, nur für Entwicklung)&lt;br /&gt;
; .scpt: Kompilierte Skripte (binär, werden von DEVONthink ausgeführt)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Kritisch:&#039;&#039;&#039; Die `.applescript`-Quelldateien funktionieren &#039;&#039;&#039;nicht&#039;&#039;&#039; direkt in DEVONthink. Sie enthalten relative Pfade, die zur Laufzeit expandiert werden müssen.&lt;br /&gt;
&lt;br /&gt;
Das `compile.sh`-Script:&lt;br /&gt;
# Kompiliert alle `.applescript` zu `.scpt`&lt;br /&gt;
# Löscht anschließend die `.applescript`-Dateien&lt;br /&gt;
# Hinterlässt nur funktionsfähige `.scpt`-Dateien&lt;br /&gt;
&lt;br /&gt;
Falls nach dem Clone noch `.applescript`-Dateien vorhanden sind, war `compile.sh` nicht erfolgreich. In diesem Fall erneut ausführen und auf Fehlermeldungen achten.&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
=== Automatische Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Nach der ersten Ausführung erstellt das System automatisch folgende Struktur in DEVONthink:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
_config/&lt;br /&gt;
├── belegversand.conf              # Konfigurationsdatei&lt;br /&gt;
├── mail_vorlagen/                 # Mail-Templates&lt;br /&gt;
│   └── belegversand               # Standard-Template&lt;br /&gt;
├── README-Belegversand            # Interne Hilfe&lt;br /&gt;
└── [weitere Dateien nach Versand]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Konfigurationsdatei ===&lt;br /&gt;
&lt;br /&gt;
Die Datei `belegversand.conf` befindet sich in DEVONthink unter `_config → belegversand.conf`.&lt;br /&gt;
&lt;br /&gt;
==== Wichtigste Parameter ====&lt;br /&gt;
&lt;br /&gt;
; MAIL_TO_DEFAULT: Standard-Empfänger (z.B. steuer@example.com)&lt;br /&gt;
; MAIL_CC_TO_DEFAULT: Standard-CC-Empfänger (optional)&lt;br /&gt;
; MAIL_SUBJECT_PREFIX: Präfix für den Mail-Betreff (z.B. &amp;quot;Belegversand&amp;quot;)&lt;br /&gt;
; ZIP_PASSWORD_DEFAULT: Standard-Passwort für ZIP-Archive (optional, keine Sonderzeichen)&lt;br /&gt;
; LOG_SENT_GROUP_NAME: Name der Ordnergruppe für Versandprotokolle (Standard: &amp;quot;Versendet&amp;quot;)&lt;br /&gt;
; SENT_TAG_FOR_DOCS: Tag für versendete Belege (Standard: &amp;quot;gesendet&amp;quot;)&lt;br /&gt;
; WRITE_DEBUG_LOG: Debug-Logging aktivieren (true/false)&lt;br /&gt;
; SHOW_README: Willkommensdialog beim Start anzeigen (true/false)&lt;br /&gt;
; MAILBODY_FOLDER_NAME: Ordner für Mail-Templates (Standard: &amp;quot;mail_vorlagen&amp;quot;)&lt;br /&gt;
; MAILBODY_RECORD_NAME: Name des Standard-Templates (Standard: &amp;quot;belegversand&amp;quot;)&lt;br /&gt;
; PATH_TO_DRYRUN_PREVIEW: Speicherort der Dry-Run Vorschau-Datei&lt;br /&gt;
&lt;br /&gt;
==== Multiple Empfänger (CSV-Format) ====&lt;br /&gt;
&lt;br /&gt;
Mehrere E-Mail-Adressen können durch Kommas getrennt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
MAIL_TO_DEFAULT=recipient1@example.com, recipient2@example.com&lt;br /&gt;
MAIL_CC_TO_DEFAULT=cc1@example.com, cc2@example.com&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Adressen werden automatisch geparst und in Apple Mail einzeln eingefügt.&lt;br /&gt;
&lt;br /&gt;
== Verwendung ==&lt;br /&gt;
&lt;br /&gt;
=== Grundablauf ===&lt;br /&gt;
&lt;br /&gt;
# Belege in DEVONthink auswählen (Mehrfachauswahl möglich)&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog beantwortet (Empfänger, ZIP-Passwort, Dry-Run?)&lt;br /&gt;
# Dry-Run Vorschau anschauen (optional)&lt;br /&gt;
# Echtlauf → ZIP-Archive erstellt, Mail-Draft geöffnet, Logging durchgeführt&lt;br /&gt;
&lt;br /&gt;
=== Menü-Befehle ===&lt;br /&gt;
&lt;br /&gt;
; START: Haupteinstiegspunkt — startet Setup oder Versand&lt;br /&gt;
; About...: About-Dialog mit Versionsinformation und Links&lt;br /&gt;
&lt;br /&gt;
=== Booking-Jahr Enforcement ===&lt;br /&gt;
&lt;br /&gt;
Das System verhindert Versandvermischung über mehrere Jahre:&lt;br /&gt;
&lt;br /&gt;
; Mixed-Year Selection: Werden Belege aus verschiedenen Jahren auswählt, wird ein Fehler zurückgewiesen&lt;br /&gt;
; Separate Protokolle: Jedes Buchungsjahr hat eigene Versendet-Ordner mit separaten Logs&lt;br /&gt;
; Outsider-Belege: Dokumente außerhalb der Jahresstruktur werden separat gehandhabt&lt;br /&gt;
&lt;br /&gt;
Beispiel-Struktur:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Belege/&lt;br /&gt;
├── 2026/&lt;br /&gt;
│   ├── 01_Januar/&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
├── 2027/&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
└── Provisionsabrechnungen/&lt;br /&gt;
    └── [← Separate Outsider-Logs]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dry-Run Modus ===&lt;br /&gt;
&lt;br /&gt;
Vor jedem echten Versand kann ein Dry-Run durchgeführt werden:&lt;br /&gt;
&lt;br /&gt;
# Simuliert den kompletten Versandprozess&lt;br /&gt;
# Erstellt Vorschau-Datei mit allen Details&lt;br /&gt;
# Zeigt Dialog mit Zusammenfassung&lt;br /&gt;
# User kann bestätigen oder abbrechen&lt;br /&gt;
&lt;br /&gt;
Die Vorschau-Datei wird auf der lokalen Festplatte gespeichert (Pfad konfigurierbar).&lt;br /&gt;
&lt;br /&gt;
=== Mail-Drafts ===&lt;br /&gt;
&lt;br /&gt;
Das System erstellt keinen automatischen Versand, sondern Mail-Drafts:&lt;br /&gt;
&lt;br /&gt;
# ZIP-Archive werden erzeugt&lt;br /&gt;
# Apple Mail öffnet mit neuem Draft (nicht gesendet!)&lt;br /&gt;
# User kann Template prüfen, weitere Empfänger hinzufügen&lt;br /&gt;
# Benutzerdefinierter Versand per Knopfdruck in Mail&lt;br /&gt;
&lt;br /&gt;
Dies ermöglicht volle Kontrolle über den Versand.&lt;br /&gt;
&lt;br /&gt;
=== Mail-Templates ===&lt;br /&gt;
&lt;br /&gt;
Templates werden aus DEVONthink geladen (`_config/mail_vorlagen/`).&lt;br /&gt;
&lt;br /&gt;
Das System zeigt einen Dialog zur Template-Auswahl, wenn mehrere Vorlagen vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Beispiel-Template:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Sehr geehrte/r Frau/Herr,&lt;br /&gt;
&lt;br /&gt;
beiliegend erhalten Sie die angeforderten Unterlagen.&lt;br /&gt;
&lt;br /&gt;
Mit freundlichen Grüßen&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Protokollierung ==&lt;br /&gt;
&lt;br /&gt;
=== NDJSON-Logs ===&lt;br /&gt;
&lt;br /&gt;
Maschinell lesbar im JSON-Lines Format für technische Weiterverarbeitung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&amp;quot;timestamp&amp;quot;:&amp;quot;2026-01-15T10:30:45Z&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;record&amp;quot;,&amp;quot;record_uuid&amp;quot;:&amp;quot;abc123&amp;quot;,&amp;quot;record_name&amp;quot;:&amp;quot;Invoice-001&amp;quot;,&amp;quot;status&amp;quot;:&amp;quot;sent&amp;quot;}&lt;br /&gt;
{&amp;quot;timestamp&amp;quot;:&amp;quot;2026-01-15T10:30:46Z&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;email&amp;quot;,&amp;quot;to&amp;quot;:&amp;quot;recipient@example.com&amp;quot;,&amp;quot;zip_file&amp;quot;:&amp;quot;archive.zip&amp;quot;,&amp;quot;status&amp;quot;:&amp;quot;created&amp;quot;}&lt;br /&gt;
{&amp;quot;timestamp&amp;quot;:&amp;quot;2026-01-15T10:30:47Z&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;tag&amp;quot;,&amp;quot;record_uuid&amp;quot;:&amp;quot;abc123&amp;quot;,&amp;quot;tag&amp;quot;:&amp;quot;gesendet&amp;quot;,&amp;quot;status&amp;quot;:&amp;quot;applied&amp;quot;}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Markdown-Logs ===&lt;br /&gt;
&lt;br /&gt;
Menschlich lesbar mit Übersichten nach Versandlauf:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
# Belegversand Logs — 2026&lt;br /&gt;
&lt;br /&gt;
## Versandlauf 2026-01-15 10:30&lt;br /&gt;
**Versendete Belege:** 5 Stück&lt;br /&gt;
**Empfänger:** recipient@example.com&lt;br /&gt;
**ZIP-Datei:** belegversand_2026-01-15_103045.zip&lt;br /&gt;
**Passwort:** [konfiguriert]&lt;br /&gt;
**Status:** Erfolgreich&lt;br /&gt;
&lt;br /&gt;
### Versandte Dokumente&lt;br /&gt;
- Invoice-001 (UUID: abc123...)&lt;br /&gt;
- Invoice-002 (UUID: def456...)&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
=== Scripts funktionieren nicht ===&lt;br /&gt;
&lt;br /&gt;
==== Problem: &amp;quot;Script nicht gefunden&amp;quot; ====&lt;br /&gt;
&lt;br /&gt;
Häufigste Ursache: `compile.sh` wurde nicht ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# Prüfen ob `.scpt`-Dateien vorhanden sind: &amp;lt;code&amp;gt;ls ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/Belegversand/Helpers/scripts/&amp;lt;/code&amp;gt;&lt;br /&gt;
# Falls nur `.applescript`-Dateien vorhanden → &amp;lt;code&amp;gt;./compile.sh&amp;lt;/code&amp;gt; erneut ausführen&lt;br /&gt;
# Auf Fehlermeldungen achten&lt;br /&gt;
&lt;br /&gt;
==== Problem: Script-Zugriff verweigert ====&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# System Settings → Privacy &amp;amp; Security → Automation&lt;br /&gt;
# DEVONthink sollte mit entsprechenden Rechten gelistet sein&lt;br /&gt;
# Script Editor öffnen und START.scpt öffnen&lt;br /&gt;
# Compile (⌘K) — sollte ohne Fehler durchlaufen&lt;br /&gt;
&lt;br /&gt;
=== ZIP wird nicht erstellt ===&lt;br /&gt;
&lt;br /&gt;
* ZIP-Passwort in Config überprüfen (keine Sonderzeichen!)&lt;br /&gt;
* Ausreichend Festplatte vorhanden?&lt;br /&gt;
* Staging-Ordner in DEVONthink beschreibbar?&lt;br /&gt;
&lt;br /&gt;
=== Mail-Draft öffnet sich nicht ===&lt;br /&gt;
&lt;br /&gt;
* Apple Mail ist geöffnet?&lt;br /&gt;
* Script-Zugriff für Mail aktiviert?&lt;br /&gt;
* Mail-Templates-Ordner vorhanden?&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Mixed-Year-Selection&amp;quot;-Fehler ===&lt;br /&gt;
&lt;br /&gt;
Dies ist kein Fehler, sondern Schutz vor Versandvermischung:&lt;br /&gt;
&lt;br /&gt;
; Lösung 1: Nur Belege aus einem Buchungsjahr auswählen&lt;br /&gt;
; Lösung 2: Belege in mehreren Versänden verteilen&lt;br /&gt;
&lt;br /&gt;
=== Debug-Informationen aktivieren ===&lt;br /&gt;
&lt;br /&gt;
In `belegversand.conf`:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
WRITE_DEBUG_LOG=true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Debug-Logs erscheinen dann in `/tmp/DT-Belegversand-debug.log`.&lt;br /&gt;
&lt;br /&gt;
== Versionshistorie ==&lt;br /&gt;
&lt;br /&gt;
; 1.4: Booking-Jahr Enforcement, Kompilierungs-Automation, About-Dialog, Wiki-Integration&lt;br /&gt;
; 1.3: Dry-Run Verbesserungen, Markdown-Logs&lt;br /&gt;
; 1.2: Mail-Templates in DEVONthink, interne README&lt;br /&gt;
; 1.1: Konfigurationssystem&lt;br /&gt;
; 1.0: Erste funktionale Version&lt;br /&gt;
&lt;br /&gt;
== Entwicklung ==&lt;br /&gt;
&lt;br /&gt;
Quellcode liegt als `.applescript`-Dateien vor (lesbar, git-freundlich).&lt;br /&gt;
&lt;br /&gt;
Zur lokalen Entwicklung:&lt;br /&gt;
# Quelldateien (`.applescript`) editieren&lt;br /&gt;
# `./compile.sh` ausführen&lt;br /&gt;
# In DEVONthink testen&lt;br /&gt;
# Bei Änderungen: `./compile.sh` erneut ausführen&lt;br /&gt;
&lt;br /&gt;
== Support ==&lt;br /&gt;
&lt;br /&gt;
Für technische Fragen oder Probleme:&lt;br /&gt;
* Wiki-Dokumentation durchlesen (diese Seite)&lt;br /&gt;
* Debug-Log aktivieren und analysieren&lt;br /&gt;
* Im Gitea-Repository ein Issue erstellen (falls Zugriff vorhanden)&lt;br /&gt;
&lt;br /&gt;
== Externe Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation Repository] (privat, erfordert Zugriff)&lt;br /&gt;
* [https://www.devontechnologies.com DEVONthink Homepage]&lt;br /&gt;
* [https://support.apple.com/mail Apple Mail Documentation]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=308</id>
		<title>Belegversand</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=308"/>
		<updated>2026-08-18T16:19:15Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Automatische Initialisierung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Belegversand =&lt;br /&gt;
&lt;br /&gt;
== Übersicht ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Belegversand&#039;&#039;&#039; ist eine automatisierte AppleScript-Lösung zur Verwaltung von Dokumenten-Versand in DEVONthink. Das System ermöglicht es, Belege aus einer DEVONthink-Datenbank auszuwählen, diese in ZIP-Archive zu packen (optional mit Passwort) und automatische Mail-Drafts mit konfigurierbaren Empfängern zu erstellen. Zusätzlich erfolgt strukturierte Protokollierung über Logging und Tagging-Mechanismen.&lt;br /&gt;
&lt;br /&gt;
== Sicherheitstechnischer Hinweis! ==&lt;br /&gt;
&lt;br /&gt;
Ich bitte zu beachten, dass die Software allenfalls minimale Sicherheitsanforderungen erfüllt.&lt;br /&gt;
&lt;br /&gt;
    Insbesondere liegt das Passwort für&#039;s ZIP-Archiv unverschlüsselt, im Klartext, in /_config/belegversand.conf. Wer das Passwort schützen möchte, kann das über die DB-Crypto von DEVONthink selbst tun. DEVONthink hat eine Datenbank-Verschlüsselung in den Bordmitteln.&lt;br /&gt;
    Dann bleibt trotzdem der zweite Schwachpunkt: Die ZIP-Verschlüsselung wird in dieser Version 1.4 über das Shell-Tool zip -P auf der Konsolenzeile realisiert. Dahinter steckt das veraltete und kryptographisch schwache ZipCrypto-Verfahren.&lt;br /&gt;
&lt;br /&gt;
Ganz deutlich: Diese Belegversand-Automatisation hab&#039; ich mir gebaut, um Tankbelege, Einkaufszettel und Restaurant-Quittungen an die Steuerberatung zu verschicken! Dafür sind sie prima! Falls es eine Version 1.5 geben sollte, ersetze ich zip -P vermutlich durch eine starke AES-Verschlüsselung, und das Passwort kommt als Hash-Wert in die Config-Datei.&lt;br /&gt;
&lt;br /&gt;
Bis dahin jedoch gilt ganz klar: Wer mit diesen Skripten, in dieser Version 1.4, sicherheitsrelevante Dokumente verschickt, tut das auf eigene Gefahr und handelt fahrlässig!&lt;br /&gt;
&lt;br /&gt;
; Version: 1.4&lt;br /&gt;
; Plattform: macOS 10.13+&lt;br /&gt;
; Abhängigkeiten: DEVONthink 3.x, Apple Mail&lt;br /&gt;
; Lizenz: Privatgebrauch&lt;br /&gt;
; Repository: https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Voraussetzungen ===&lt;br /&gt;
&lt;br /&gt;
* macOS 10.13 oder neuer&lt;br /&gt;
* DEVONthink 3.x&lt;br /&gt;
* Apple Mail&lt;br /&gt;
* AppleScript-Zugriff in Systemeinstellungen aktiviert&lt;br /&gt;
* Git (zum Klonen des Repositories)&lt;br /&gt;
&lt;br /&gt;
=== Schritt-für-Schritt Anleitung ===&lt;br /&gt;
&lt;br /&gt;
==== 1. Verzeichnisstruktur anlegen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
cd ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 2. Repository klonen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation.git Belegversand&lt;br /&gt;
cd Belegversand&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 3. Scripts kompilieren ====&lt;br /&gt;
&lt;br /&gt;
Dies ist ein &#039;&#039;&#039;wichtiger Schritt&#039;&#039;&#039; und darf nicht übersprungen werden!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chmod +x compile.sh&lt;br /&gt;
./compile.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erwartete Ausgabe:&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Compiliere Belegversand AppleScripts...&lt;br /&gt;
✓ Fertig!&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 4. Erste Ausführung ====&lt;br /&gt;
&lt;br /&gt;
# DEVONthink öffnen&lt;br /&gt;
# Ein Objekt in der gewünschten Datenbank auswählen&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog folgen → Setup wird durchgeführt&lt;br /&gt;
&lt;br /&gt;
Das Setup-Script erstellt automatisch alle notwendigen Ordnerstrukturen und Konfigurationsdateien in DEVONthink.&lt;br /&gt;
&lt;br /&gt;
== Wichtig: .applescript vs. .scpt Dateien ==&lt;br /&gt;
&lt;br /&gt;
Im Repository gibt es zwei Arten von AppleScript-Dateien:&lt;br /&gt;
&lt;br /&gt;
; .applescript: Quelldateien (lesbar, nur für Entwicklung)&lt;br /&gt;
; .scpt: Kompilierte Skripte (binär, werden von DEVONthink ausgeführt)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Kritisch:&#039;&#039;&#039; Die `.applescript`-Quelldateien funktionieren &#039;&#039;&#039;nicht&#039;&#039;&#039; direkt in DEVONthink. Sie enthalten relative Pfade, die zur Laufzeit expandiert werden müssen.&lt;br /&gt;
&lt;br /&gt;
Das `compile.sh`-Script:&lt;br /&gt;
# Kompiliert alle `.applescript` zu `.scpt`&lt;br /&gt;
# Löscht anschließend die `.applescript`-Dateien&lt;br /&gt;
# Hinterlässt nur funktionsfähige `.scpt`-Dateien&lt;br /&gt;
&lt;br /&gt;
Falls nach dem Clone noch `.applescript`-Dateien vorhanden sind, war `compile.sh` nicht erfolgreich. In diesem Fall erneut ausführen und auf Fehlermeldungen achten.&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
=== Automatische Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Nach der ersten Ausführung erstellt das System automatisch folgende Struktur in DEVONthink:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
_config/&lt;br /&gt;
├── belegversand.conf              # Konfigurationsdatei&lt;br /&gt;
├── mail_vorlagen/                 # Mail-Templates&lt;br /&gt;
│   └── belegversand               # Standard-Template&lt;br /&gt;
├── README-Belegversand            # Interne Hilfe&lt;br /&gt;
└── [weitere Dateien nach Versand]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Konfigurationsdatei ===&lt;br /&gt;
&lt;br /&gt;
Die Datei `belegversand.conf` befindet sich in DEVONthink unter `_config → belegversand.conf`.&lt;br /&gt;
&lt;br /&gt;
==== Wichtigste Parameter ====&lt;br /&gt;
&lt;br /&gt;
; MAIL_TO_DEFAULT: Standard-Empfänger (z.B. steuer@example.com)&lt;br /&gt;
; MAIL_CC_TO_DEFAULT: Standard-CC-Empfänger (optional)&lt;br /&gt;
; MAIL_SUBJECT_PREFIX: Präfix für den Mail-Betreff (z.B. &amp;quot;Belegversand&amp;quot;)&lt;br /&gt;
; ZIP_PASSWORD_DEFAULT: Standard-Passwort für ZIP-Archive (optional, keine Sonderzeichen)&lt;br /&gt;
; LOG_SENT_GROUP_NAME: Name der Ordnergruppe für Versandprotokolle (Standard: &amp;quot;Versendet&amp;quot;)&lt;br /&gt;
; SENT_TAG_FOR_DOCS: Tag für versendete Belege (Standard: &amp;quot;gesendet&amp;quot;)&lt;br /&gt;
; WRITE_DEBUG_LOG: Debug-Logging aktivieren (true/false)&lt;br /&gt;
; SHOW_README: Willkommensdialog beim Start anzeigen (true/false)&lt;br /&gt;
; MAILBODY_FOLDER_NAME: Ordner für Mail-Templates (Standard: &amp;quot;mail_vorlagen&amp;quot;)&lt;br /&gt;
; MAILBODY_RECORD_NAME: Name des Standard-Templates (Standard: &amp;quot;belegversand&amp;quot;)&lt;br /&gt;
; PATH_TO_DRYRUN_PREVIEW: Speicherort der Dry-Run Vorschau-Datei&lt;br /&gt;
&lt;br /&gt;
==== Multiple Empfänger (CSV-Format) ====&lt;br /&gt;
&lt;br /&gt;
Mehrere E-Mail-Adressen können durch Kommas getrennt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
MAIL_TO_DEFAULT=recipient1@example.com, recipient2@example.com&lt;br /&gt;
MAIL_CC_TO_DEFAULT=cc1@example.com, cc2@example.com&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Adressen werden automatisch geparst und in Apple Mail einzeln eingefügt.&lt;br /&gt;
&lt;br /&gt;
== Verwendung ==&lt;br /&gt;
&lt;br /&gt;
=== Grundablauf ===&lt;br /&gt;
&lt;br /&gt;
# Belege in DEVONthink auswählen (Mehrfachauswahl möglich)&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog beantwortet (Empfänger, ZIP-Passwort, Dry-Run?)&lt;br /&gt;
# Dry-Run Vorschau anschauen (optional)&lt;br /&gt;
# Echtlauf → ZIP-Archive erstellt, Mail-Draft geöffnet, Logging durchgeführt&lt;br /&gt;
&lt;br /&gt;
=== Menü-Befehle ===&lt;br /&gt;
&lt;br /&gt;
; START: Haupteinstiegspunkt — startet Setup oder Versand&lt;br /&gt;
; About...: About-Dialog mit Versionsinformation und Links&lt;br /&gt;
&lt;br /&gt;
=== Booking-Jahr Enforcement ===&lt;br /&gt;
&lt;br /&gt;
Das System verhindert Versandvermischung über mehrere Jahre:&lt;br /&gt;
&lt;br /&gt;
; Mixed-Year Selection: Werden Belege aus verschiedenen Jahren auswählt, wird ein Fehler zurückgewiesen&lt;br /&gt;
; Separate Protokolle: Jedes Buchungsjahr hat eigene Versendet-Ordner mit separaten Logs&lt;br /&gt;
; Outsider-Belege: Dokumente außerhalb der Jahresstruktur werden separat gehandhabt&lt;br /&gt;
&lt;br /&gt;
Beispiel-Struktur:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Belege/&lt;br /&gt;
├── 2026/&lt;br /&gt;
│   ├── 01_Januar/&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
├── 2027/&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
└── Provisionsabrechnungen/&lt;br /&gt;
    └── [← Separate Outsider-Logs]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dry-Run Modus ===&lt;br /&gt;
&lt;br /&gt;
Vor jedem echten Versand kann ein Dry-Run durchgeführt werden:&lt;br /&gt;
&lt;br /&gt;
# Simuliert den kompletten Versandprozess&lt;br /&gt;
# Erstellt Vorschau-Datei mit allen Details&lt;br /&gt;
# Zeigt Dialog mit Zusammenfassung&lt;br /&gt;
# User kann bestätigen oder abbrechen&lt;br /&gt;
&lt;br /&gt;
Die Vorschau-Datei wird auf der lokalen Festplatte gespeichert (Pfad konfigurierbar).&lt;br /&gt;
&lt;br /&gt;
=== Mail-Drafts ===&lt;br /&gt;
&lt;br /&gt;
Das System erstellt keinen automatischen Versand, sondern Mail-Drafts:&lt;br /&gt;
&lt;br /&gt;
# ZIP-Archive werden erzeugt&lt;br /&gt;
# Apple Mail öffnet mit neuem Draft (nicht gesendet!)&lt;br /&gt;
# User kann Template prüfen, weitere Empfänger hinzufügen&lt;br /&gt;
# Benutzerdefinierter Versand per Knopfdruck in Mail&lt;br /&gt;
&lt;br /&gt;
Dies ermöglicht volle Kontrolle über den Versand.&lt;br /&gt;
&lt;br /&gt;
=== Mail-Templates ===&lt;br /&gt;
&lt;br /&gt;
Templates werden aus DEVONthink geladen (`_config/mail_vorlagen/`).&lt;br /&gt;
&lt;br /&gt;
Das System zeigt einen Dialog zur Template-Auswahl, wenn mehrere Vorlagen vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Beispiel-Template:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Sehr geehrte/r Frau/Herr,&lt;br /&gt;
&lt;br /&gt;
beiliegend erhalten Sie die angeforderten Unterlagen.&lt;br /&gt;
&lt;br /&gt;
Mit freundlichen Grüßen&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Protokollierung ==&lt;br /&gt;
&lt;br /&gt;
=== NDJSON-Logs ===&lt;br /&gt;
&lt;br /&gt;
Maschinell lesbar im JSON-Lines Format für technische Weiterverarbeitung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&amp;quot;timestamp&amp;quot;:&amp;quot;2026-01-15T10:30:45Z&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;record&amp;quot;,&amp;quot;record_uuid&amp;quot;:&amp;quot;abc123&amp;quot;,&amp;quot;record_name&amp;quot;:&amp;quot;Invoice-001&amp;quot;,&amp;quot;status&amp;quot;:&amp;quot;sent&amp;quot;}&lt;br /&gt;
{&amp;quot;timestamp&amp;quot;:&amp;quot;2026-01-15T10:30:46Z&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;email&amp;quot;,&amp;quot;to&amp;quot;:&amp;quot;recipient@example.com&amp;quot;,&amp;quot;zip_file&amp;quot;:&amp;quot;archive.zip&amp;quot;,&amp;quot;status&amp;quot;:&amp;quot;created&amp;quot;}&lt;br /&gt;
{&amp;quot;timestamp&amp;quot;:&amp;quot;2026-01-15T10:30:47Z&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;tag&amp;quot;,&amp;quot;record_uuid&amp;quot;:&amp;quot;abc123&amp;quot;,&amp;quot;tag&amp;quot;:&amp;quot;gesendet&amp;quot;,&amp;quot;status&amp;quot;:&amp;quot;applied&amp;quot;}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Markdown-Logs ===&lt;br /&gt;
&lt;br /&gt;
Menschlich lesbar mit Übersichten nach Versandlauf:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
# Belegversand Logs — 2026&lt;br /&gt;
&lt;br /&gt;
## Versandlauf 2026-01-15 10:30&lt;br /&gt;
**Versendete Belege:** 5 Stück&lt;br /&gt;
**Empfänger:** recipient@example.com&lt;br /&gt;
**ZIP-Datei:** belegversand_2026-01-15_103045.zip&lt;br /&gt;
**Passwort:** [konfiguriert]&lt;br /&gt;
**Status:** Erfolgreich&lt;br /&gt;
&lt;br /&gt;
### Versandte Dokumente&lt;br /&gt;
- Invoice-001 (UUID: abc123...)&lt;br /&gt;
- Invoice-002 (UUID: def456...)&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
=== Scripts funktionieren nicht ===&lt;br /&gt;
&lt;br /&gt;
==== Problem: &amp;quot;Script nicht gefunden&amp;quot; ====&lt;br /&gt;
&lt;br /&gt;
Häufigste Ursache: `compile.sh` wurde nicht ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# Prüfen ob `.scpt`-Dateien vorhanden sind: &amp;lt;code&amp;gt;ls ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/Belegversand/Helpers/scripts/&amp;lt;/code&amp;gt;&lt;br /&gt;
# Falls nur `.applescript`-Dateien vorhanden → &amp;lt;code&amp;gt;./compile.sh&amp;lt;/code&amp;gt; erneut ausführen&lt;br /&gt;
# Auf Fehlermeldungen achten&lt;br /&gt;
&lt;br /&gt;
==== Problem: Script-Zugriff verweigert ====&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# System Settings → Privacy &amp;amp; Security → Automation&lt;br /&gt;
# DEVONthink sollte mit entsprechenden Rechten gelistet sein&lt;br /&gt;
# Script Editor öffnen und START.scpt öffnen&lt;br /&gt;
# Compile (⌘K) — sollte ohne Fehler durchlaufen&lt;br /&gt;
&lt;br /&gt;
=== ZIP wird nicht erstellt ===&lt;br /&gt;
&lt;br /&gt;
* ZIP-Passwort in Config überprüfen (keine Sonderzeichen!)&lt;br /&gt;
* Ausreichend Festplatte vorhanden?&lt;br /&gt;
* Staging-Ordner in DEVONthink beschreibbar?&lt;br /&gt;
&lt;br /&gt;
=== Mail-Draft öffnet sich nicht ===&lt;br /&gt;
&lt;br /&gt;
* Apple Mail ist geöffnet?&lt;br /&gt;
* Script-Zugriff für Mail aktiviert?&lt;br /&gt;
* Mail-Templates-Ordner vorhanden?&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Mixed-Year-Selection&amp;quot;-Fehler ===&lt;br /&gt;
&lt;br /&gt;
Dies ist kein Fehler, sondern Schutz vor Versandvermischung:&lt;br /&gt;
&lt;br /&gt;
; Lösung 1: Nur Belege aus einem Buchungsjahr auswählen&lt;br /&gt;
; Lösung 2: Belege in mehreren Versänden verteilen&lt;br /&gt;
&lt;br /&gt;
=== Debug-Informationen aktivieren ===&lt;br /&gt;
&lt;br /&gt;
In `belegversand.conf`:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
WRITE_DEBUG_LOG=true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Debug-Logs erscheinen dann in `/tmp/DT-Belegversand-debug.log`.&lt;br /&gt;
&lt;br /&gt;
== Versionshistorie ==&lt;br /&gt;
&lt;br /&gt;
; 1.4: Booking-Jahr Enforcement, Kompilierungs-Automation, About-Dialog, Wiki-Integration&lt;br /&gt;
; 1.3: Dry-Run Verbesserungen, Markdown-Logs&lt;br /&gt;
; 1.2: Mail-Templates in DEVONthink, interne README&lt;br /&gt;
; 1.1: Konfigurationssystem&lt;br /&gt;
; 1.0: Erste funktionale Version&lt;br /&gt;
&lt;br /&gt;
== Entwicklung ==&lt;br /&gt;
&lt;br /&gt;
Quellcode liegt als `.applescript`-Dateien vor (lesbar, git-freundlich).&lt;br /&gt;
&lt;br /&gt;
Zur lokalen Entwicklung:&lt;br /&gt;
# Quelldateien (`.applescript`) editieren&lt;br /&gt;
# `./compile.sh` ausführen&lt;br /&gt;
# In DEVONthink testen&lt;br /&gt;
# Bei Änderungen: `./compile.sh` erneut ausführen&lt;br /&gt;
&lt;br /&gt;
== Support ==&lt;br /&gt;
&lt;br /&gt;
Für technische Fragen oder Probleme:&lt;br /&gt;
* Wiki-Dokumentation durchlesen (diese Seite)&lt;br /&gt;
* Debug-Log aktivieren und analysieren&lt;br /&gt;
* Im Gitea-Repository ein Issue erstellen (falls Zugriff vorhanden)&lt;br /&gt;
&lt;br /&gt;
== Externe Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation Repository] (privat, erfordert Zugriff)&lt;br /&gt;
* [https://www.devontechnologies.com DEVONthink Homepage]&lt;br /&gt;
* [https://support.apple.com/mail Apple Mail Documentation]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=307</id>
		<title>Belegversand</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=307"/>
		<updated>2026-08-18T16:18:45Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Booking-Jahr Enforcement */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Belegversand =&lt;br /&gt;
&lt;br /&gt;
== Übersicht ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Belegversand&#039;&#039;&#039; ist eine automatisierte AppleScript-Lösung zur Verwaltung von Dokumenten-Versand in DEVONthink. Das System ermöglicht es, Belege aus einer DEVONthink-Datenbank auszuwählen, diese in ZIP-Archive zu packen (optional mit Passwort) und automatische Mail-Drafts mit konfigurierbaren Empfängern zu erstellen. Zusätzlich erfolgt strukturierte Protokollierung über Logging und Tagging-Mechanismen.&lt;br /&gt;
&lt;br /&gt;
== Sicherheitstechnischer Hinweis! ==&lt;br /&gt;
&lt;br /&gt;
Ich bitte zu beachten, dass die Software allenfalls minimale Sicherheitsanforderungen erfüllt.&lt;br /&gt;
&lt;br /&gt;
    Insbesondere liegt das Passwort für&#039;s ZIP-Archiv unverschlüsselt, im Klartext, in /_config/belegversand.conf. Wer das Passwort schützen möchte, kann das über die DB-Crypto von DEVONthink selbst tun. DEVONthink hat eine Datenbank-Verschlüsselung in den Bordmitteln.&lt;br /&gt;
    Dann bleibt trotzdem der zweite Schwachpunkt: Die ZIP-Verschlüsselung wird in dieser Version 1.4 über das Shell-Tool zip -P auf der Konsolenzeile realisiert. Dahinter steckt das veraltete und kryptographisch schwache ZipCrypto-Verfahren.&lt;br /&gt;
&lt;br /&gt;
Ganz deutlich: Diese Belegversand-Automatisation hab&#039; ich mir gebaut, um Tankbelege, Einkaufszettel und Restaurant-Quittungen an die Steuerberatung zu verschicken! Dafür sind sie prima! Falls es eine Version 1.5 geben sollte, ersetze ich zip -P vermutlich durch eine starke AES-Verschlüsselung, und das Passwort kommt als Hash-Wert in die Config-Datei.&lt;br /&gt;
&lt;br /&gt;
Bis dahin jedoch gilt ganz klar: Wer mit diesen Skripten, in dieser Version 1.4, sicherheitsrelevante Dokumente verschickt, tut das auf eigene Gefahr und handelt fahrlässig!&lt;br /&gt;
&lt;br /&gt;
; Version: 1.4&lt;br /&gt;
; Plattform: macOS 10.13+&lt;br /&gt;
; Abhängigkeiten: DEVONthink 3.x, Apple Mail&lt;br /&gt;
; Lizenz: Privatgebrauch&lt;br /&gt;
; Repository: https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Voraussetzungen ===&lt;br /&gt;
&lt;br /&gt;
* macOS 10.13 oder neuer&lt;br /&gt;
* DEVONthink 3.x&lt;br /&gt;
* Apple Mail&lt;br /&gt;
* AppleScript-Zugriff in Systemeinstellungen aktiviert&lt;br /&gt;
* Git (zum Klonen des Repositories)&lt;br /&gt;
&lt;br /&gt;
=== Schritt-für-Schritt Anleitung ===&lt;br /&gt;
&lt;br /&gt;
==== 1. Verzeichnisstruktur anlegen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
cd ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 2. Repository klonen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation.git Belegversand&lt;br /&gt;
cd Belegversand&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 3. Scripts kompilieren ====&lt;br /&gt;
&lt;br /&gt;
Dies ist ein &#039;&#039;&#039;wichtiger Schritt&#039;&#039;&#039; und darf nicht übersprungen werden!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chmod +x compile.sh&lt;br /&gt;
./compile.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erwartete Ausgabe:&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Compiliere Belegversand AppleScripts...&lt;br /&gt;
✓ Fertig!&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 4. Erste Ausführung ====&lt;br /&gt;
&lt;br /&gt;
# DEVONthink öffnen&lt;br /&gt;
# Ein Objekt in der gewünschten Datenbank auswählen&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog folgen → Setup wird durchgeführt&lt;br /&gt;
&lt;br /&gt;
Das Setup-Script erstellt automatisch alle notwendigen Ordnerstrukturen und Konfigurationsdateien in DEVONthink.&lt;br /&gt;
&lt;br /&gt;
== Wichtig: .applescript vs. .scpt Dateien ==&lt;br /&gt;
&lt;br /&gt;
Im Repository gibt es zwei Arten von AppleScript-Dateien:&lt;br /&gt;
&lt;br /&gt;
; .applescript: Quelldateien (lesbar, nur für Entwicklung)&lt;br /&gt;
; .scpt: Kompilierte Skripte (binär, werden von DEVONthink ausgeführt)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Kritisch:&#039;&#039;&#039; Die `.applescript`-Quelldateien funktionieren &#039;&#039;&#039;nicht&#039;&#039;&#039; direkt in DEVONthink. Sie enthalten relative Pfade, die zur Laufzeit expandiert werden müssen.&lt;br /&gt;
&lt;br /&gt;
Das `compile.sh`-Script:&lt;br /&gt;
# Kompiliert alle `.applescript` zu `.scpt`&lt;br /&gt;
# Löscht anschließend die `.applescript`-Dateien&lt;br /&gt;
# Hinterlässt nur funktionsfähige `.scpt`-Dateien&lt;br /&gt;
&lt;br /&gt;
Falls nach dem Clone noch `.applescript`-Dateien vorhanden sind, war `compile.sh` nicht erfolgreich. In diesem Fall erneut ausführen und auf Fehlermeldungen achten.&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
=== Automatische Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Nach der ersten Ausführung erstellt das System automatisch folgende Struktur in DEVONthink:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
_config/&lt;br /&gt;
├── belegversand.conf              # Konfigurationsdatei&lt;br /&gt;
├── mail_vorlagen/                 # Mail-Templates&lt;br /&gt;
│   └── belegversand               # Standard-Template&lt;br /&gt;
├── README-Belegversand            # Interne Hilfe&lt;br /&gt;
└── [weitere Dateien nach Versand]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Konfigurationsdatei ===&lt;br /&gt;
&lt;br /&gt;
Die Datei `belegversand.conf` befindet sich in DEVONthink unter `_config → belegversand.conf`.&lt;br /&gt;
&lt;br /&gt;
==== Wichtigste Parameter ====&lt;br /&gt;
&lt;br /&gt;
; MAIL_TO_DEFAULT: Standard-Empfänger (z.B. steuer@example.com)&lt;br /&gt;
; MAIL_CC_TO_DEFAULT: Standard-CC-Empfänger (optional)&lt;br /&gt;
; MAIL_SUBJECT_PREFIX: Präfix für den Mail-Betreff (z.B. &amp;quot;Belegversand&amp;quot;)&lt;br /&gt;
; ZIP_PASSWORD_DEFAULT: Standard-Passwort für ZIP-Archive (optional, keine Sonderzeichen)&lt;br /&gt;
; LOG_SENT_GROUP_NAME: Name der Ordnergruppe für Versandprotokolle (Standard: &amp;quot;Versendet&amp;quot;)&lt;br /&gt;
; SENT_TAG_FOR_DOCS: Tag für versendete Belege (Standard: &amp;quot;gesendet&amp;quot;)&lt;br /&gt;
; WRITE_DEBUG_LOG: Debug-Logging aktivieren (true/false)&lt;br /&gt;
; SHOW_README: Willkommensdialog beim Start anzeigen (true/false)&lt;br /&gt;
; MAILBODY_FOLDER_NAME: Ordner für Mail-Templates (Standard: &amp;quot;mail_vorlagen&amp;quot;)&lt;br /&gt;
; MAILBODY_RECORD_NAME: Name des Standard-Templates (Standard: &amp;quot;belegversand&amp;quot;)&lt;br /&gt;
; PATH_TO_DRYRUN_PREVIEW: Speicherort der Dry-Run Vorschau-Datei&lt;br /&gt;
&lt;br /&gt;
==== Multiple Empfänger (CSV-Format) ====&lt;br /&gt;
&lt;br /&gt;
Mehrere E-Mail-Adressen können durch Kommas getrennt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
MAIL_TO_DEFAULT=recipient1@example.com, recipient2@example.com&lt;br /&gt;
MAIL_CC_TO_DEFAULT=cc1@example.com, cc2@example.com&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Adressen werden automatisch geparst und in Apple Mail einzeln eingefügt.&lt;br /&gt;
&lt;br /&gt;
== Verwendung ==&lt;br /&gt;
&lt;br /&gt;
=== Grundablauf ===&lt;br /&gt;
&lt;br /&gt;
# Belege in DEVONthink auswählen (Mehrfachauswahl möglich)&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog beantwortet (Empfänger, ZIP-Passwort, Dry-Run?)&lt;br /&gt;
# Dry-Run Vorschau anschauen (optional)&lt;br /&gt;
# Echtlauf → ZIP-Archive erstellt, Mail-Draft geöffnet, Logging durchgeführt&lt;br /&gt;
&lt;br /&gt;
=== Menü-Befehle ===&lt;br /&gt;
&lt;br /&gt;
; START: Haupteinstiegspunkt — startet Setup oder Versand&lt;br /&gt;
; About...: About-Dialog mit Versionsinformation und Links&lt;br /&gt;
&lt;br /&gt;
=== Booking-Jahr Enforcement ===&lt;br /&gt;
&lt;br /&gt;
Das System verhindert Versandvermischung über mehrere Jahre:&lt;br /&gt;
&lt;br /&gt;
; Mixed-Year Selection: Werden Belege aus verschiedenen Jahren auswählt, wird ein Fehler zurückgewiesen&lt;br /&gt;
; Separate Protokolle: Jedes Buchungsjahr hat eigene Versendet-Ordner mit separaten Logs&lt;br /&gt;
; Outsider-Belege: Dokumente außerhalb der Jahresstruktur werden separat gehandhabt&lt;br /&gt;
&lt;br /&gt;
Beispiel-Struktur:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Belege/&lt;br /&gt;
├── 2026/&lt;br /&gt;
│   ├── 01_Januar/&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
├── 2027/&lt;br /&gt;
│   └── Versendet/ [← Logs]&lt;br /&gt;
└── Provisionsabrechnungen/&lt;br /&gt;
    └── [← Separate Outsider-Logs]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dry-Run Modus ===&lt;br /&gt;
&lt;br /&gt;
Vor jedem echten Versand kann ein Dry-Run durchgeführt werden:&lt;br /&gt;
&lt;br /&gt;
# Simuliert den kompletten Versandprozess&lt;br /&gt;
# Erstellt Vorschau-Datei mit allen Details&lt;br /&gt;
# Zeigt Dialog mit Zusammenfassung&lt;br /&gt;
# User kann bestätigen oder abbrechen&lt;br /&gt;
&lt;br /&gt;
Die Vorschau-Datei wird auf der lokalen Festplatte gespeichert (Pfad konfigurierbar).&lt;br /&gt;
&lt;br /&gt;
=== Mail-Drafts ===&lt;br /&gt;
&lt;br /&gt;
Das System erstellt keinen automatischen Versand, sondern Mail-Drafts:&lt;br /&gt;
&lt;br /&gt;
# ZIP-Archive werden erzeugt&lt;br /&gt;
# Apple Mail öffnet mit neuem Draft (nicht gesendet!)&lt;br /&gt;
# User kann Template prüfen, weitere Empfänger hinzufügen&lt;br /&gt;
# Benutzerdefinierter Versand per Knopfdruck in Mail&lt;br /&gt;
&lt;br /&gt;
Dies ermöglicht volle Kontrolle über den Versand.&lt;br /&gt;
&lt;br /&gt;
=== Mail-Templates ===&lt;br /&gt;
&lt;br /&gt;
Templates werden aus DEVONthink geladen (`_config/mail_vorlagen/`).&lt;br /&gt;
&lt;br /&gt;
Das System zeigt einen Dialog zur Template-Auswahl, wenn mehrere Vorlagen vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Beispiel-Template:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Sehr geehrte/r Frau/Herr,&lt;br /&gt;
&lt;br /&gt;
beiliegend erhalten Sie die angeforderten Unterlagen.&lt;br /&gt;
&lt;br /&gt;
Mit freundlichen Grüßen&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Protokollierung ==&lt;br /&gt;
&lt;br /&gt;
=== NDJSON-Logs ===&lt;br /&gt;
&lt;br /&gt;
Maschinell lesbar im JSON-Lines Format für technische Weiterverarbeitung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&amp;quot;timestamp&amp;quot;:&amp;quot;2026-01-15T10:30:45Z&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;record&amp;quot;,&amp;quot;record_uuid&amp;quot;:&amp;quot;abc123&amp;quot;,&amp;quot;record_name&amp;quot;:&amp;quot;Invoice-001&amp;quot;,&amp;quot;status&amp;quot;:&amp;quot;sent&amp;quot;}&lt;br /&gt;
{&amp;quot;timestamp&amp;quot;:&amp;quot;2026-01-15T10:30:46Z&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;email&amp;quot;,&amp;quot;to&amp;quot;:&amp;quot;recipient@example.com&amp;quot;,&amp;quot;zip_file&amp;quot;:&amp;quot;archive.zip&amp;quot;,&amp;quot;status&amp;quot;:&amp;quot;created&amp;quot;}&lt;br /&gt;
{&amp;quot;timestamp&amp;quot;:&amp;quot;2026-01-15T10:30:47Z&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;tag&amp;quot;,&amp;quot;record_uuid&amp;quot;:&amp;quot;abc123&amp;quot;,&amp;quot;tag&amp;quot;:&amp;quot;gesendet&amp;quot;,&amp;quot;status&amp;quot;:&amp;quot;applied&amp;quot;}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Markdown-Logs ===&lt;br /&gt;
&lt;br /&gt;
Menschlich lesbar mit Übersichten nach Versandlauf:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
# Belegversand Logs — 2026&lt;br /&gt;
&lt;br /&gt;
## Versandlauf 2026-01-15 10:30&lt;br /&gt;
**Versendete Belege:** 5 Stück&lt;br /&gt;
**Empfänger:** recipient@example.com&lt;br /&gt;
**ZIP-Datei:** belegversand_2026-01-15_103045.zip&lt;br /&gt;
**Passwort:** [konfiguriert]&lt;br /&gt;
**Status:** Erfolgreich&lt;br /&gt;
&lt;br /&gt;
### Versandte Dokumente&lt;br /&gt;
- Invoice-001 (UUID: abc123...)&lt;br /&gt;
- Invoice-002 (UUID: def456...)&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
=== Scripts funktionieren nicht ===&lt;br /&gt;
&lt;br /&gt;
==== Problem: &amp;quot;Script nicht gefunden&amp;quot; ====&lt;br /&gt;
&lt;br /&gt;
Häufigste Ursache: `compile.sh` wurde nicht ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# Prüfen ob `.scpt`-Dateien vorhanden sind: &amp;lt;code&amp;gt;ls ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/Belegversand/Helpers/scripts/&amp;lt;/code&amp;gt;&lt;br /&gt;
# Falls nur `.applescript`-Dateien vorhanden → &amp;lt;code&amp;gt;./compile.sh&amp;lt;/code&amp;gt; erneut ausführen&lt;br /&gt;
# Auf Fehlermeldungen achten&lt;br /&gt;
&lt;br /&gt;
==== Problem: Script-Zugriff verweigert ====&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# System Settings → Privacy &amp;amp; Security → Automation&lt;br /&gt;
# DEVONthink sollte mit entsprechenden Rechten gelistet sein&lt;br /&gt;
# Script Editor öffnen und START.scpt öffnen&lt;br /&gt;
# Compile (⌘K) — sollte ohne Fehler durchlaufen&lt;br /&gt;
&lt;br /&gt;
=== ZIP wird nicht erstellt ===&lt;br /&gt;
&lt;br /&gt;
* ZIP-Passwort in Config überprüfen (keine Sonderzeichen!)&lt;br /&gt;
* Ausreichend Festplatte vorhanden?&lt;br /&gt;
* Staging-Ordner in DEVONthink beschreibbar?&lt;br /&gt;
&lt;br /&gt;
=== Mail-Draft öffnet sich nicht ===&lt;br /&gt;
&lt;br /&gt;
* Apple Mail ist geöffnet?&lt;br /&gt;
* Script-Zugriff für Mail aktiviert?&lt;br /&gt;
* Mail-Templates-Ordner vorhanden?&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Mixed-Year-Selection&amp;quot;-Fehler ===&lt;br /&gt;
&lt;br /&gt;
Dies ist kein Fehler, sondern Schutz vor Versandvermischung:&lt;br /&gt;
&lt;br /&gt;
; Lösung 1: Nur Belege aus einem Buchungsjahr auswählen&lt;br /&gt;
; Lösung 2: Belege in mehreren Versänden verteilen&lt;br /&gt;
&lt;br /&gt;
=== Debug-Informationen aktivieren ===&lt;br /&gt;
&lt;br /&gt;
In `belegversand.conf`:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
WRITE_DEBUG_LOG=true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Debug-Logs erscheinen dann in `/tmp/DT-Belegversand-debug.log`.&lt;br /&gt;
&lt;br /&gt;
== Versionshistorie ==&lt;br /&gt;
&lt;br /&gt;
; 1.4: Booking-Jahr Enforcement, Kompilierungs-Automation, About-Dialog, Wiki-Integration&lt;br /&gt;
; 1.3: Dry-Run Verbesserungen, Markdown-Logs&lt;br /&gt;
; 1.2: Mail-Templates in DEVONthink, interne README&lt;br /&gt;
; 1.1: Konfigurationssystem&lt;br /&gt;
; 1.0: Erste funktionale Version&lt;br /&gt;
&lt;br /&gt;
== Entwicklung ==&lt;br /&gt;
&lt;br /&gt;
Quellcode liegt als `.applescript`-Dateien vor (lesbar, git-freundlich).&lt;br /&gt;
&lt;br /&gt;
Zur lokalen Entwicklung:&lt;br /&gt;
# Quelldateien (`.applescript`) editieren&lt;br /&gt;
# `./compile.sh` ausführen&lt;br /&gt;
# In DEVONthink testen&lt;br /&gt;
# Bei Änderungen: `./compile.sh` erneut ausführen&lt;br /&gt;
&lt;br /&gt;
== Support ==&lt;br /&gt;
&lt;br /&gt;
Für technische Fragen oder Probleme:&lt;br /&gt;
* Wiki-Dokumentation durchlesen (diese Seite)&lt;br /&gt;
* Debug-Log aktivieren und analysieren&lt;br /&gt;
* Im Gitea-Repository ein Issue erstellen (falls Zugriff vorhanden)&lt;br /&gt;
&lt;br /&gt;
== Externe Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation Repository] (privat, erfordert Zugriff)&lt;br /&gt;
* [https://www.devontechnologies.com DEVONthink Homepage]&lt;br /&gt;
* [https://support.apple.com/mail Apple Mail Documentation]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=306</id>
		<title>Belegversand</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=306"/>
		<updated>2026-08-18T15:44:14Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Sicherheitstechnischer Hinweis! */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Belegversand =&lt;br /&gt;
&lt;br /&gt;
== Übersicht ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Belegversand&#039;&#039;&#039; ist eine automatisierte AppleScript-Lösung zur Verwaltung von Dokumenten-Versand in DEVONthink. Das System ermöglicht es, Belege aus einer DEVONthink-Datenbank auszuwählen, diese in ZIP-Archive zu packen (optional mit Passwort) und automatische Mail-Drafts mit konfigurierbaren Empfängern zu erstellen. Zusätzlich erfolgt strukturierte Protokollierung über Logging und Tagging-Mechanismen.&lt;br /&gt;
&lt;br /&gt;
== Sicherheitstechnischer Hinweis! ==&lt;br /&gt;
&lt;br /&gt;
Ich bitte zu beachten, dass die Software allenfalls minimale Sicherheitsanforderungen erfüllt.&lt;br /&gt;
&lt;br /&gt;
    Insbesondere liegt das Passwort für&#039;s ZIP-Archiv unverschlüsselt, im Klartext, in /_config/belegversand.conf. Wer das Passwort schützen möchte, kann das über die DB-Crypto von DEVONthink selbst tun. DEVONthink hat eine Datenbank-Verschlüsselung in den Bordmitteln.&lt;br /&gt;
    Dann bleibt trotzdem der zweite Schwachpunkt: Die ZIP-Verschlüsselung wird in dieser Version 1.4 über das Shell-Tool zip -P auf der Konsolenzeile realisiert. Dahinter steckt das veraltete und kryptographisch schwache ZipCrypto-Verfahren.&lt;br /&gt;
&lt;br /&gt;
Ganz deutlich: Diese Belegversand-Automatisation hab&#039; ich mir gebaut, um Tankbelege, Einkaufszettel und Restaurant-Quittungen an die Steuerberatung zu verschicken! Dafür sind sie prima! Falls es eine Version 1.5 geben sollte, ersetze ich zip -P vermutlich durch eine starke AES-Verschlüsselung, und das Passwort kommt als Hash-Wert in die Config-Datei.&lt;br /&gt;
&lt;br /&gt;
Bis dahin jedoch gilt ganz klar: Wer mit diesen Skripten, in dieser Version 1.4, sicherheitsrelevante Dokumente verschickt, tut das auf eigene Gefahr und handelt fahrlässig!&lt;br /&gt;
&lt;br /&gt;
; Version: 1.4&lt;br /&gt;
; Plattform: macOS 10.13+&lt;br /&gt;
; Abhängigkeiten: DEVONthink 3.x, Apple Mail&lt;br /&gt;
; Lizenz: Privatgebrauch&lt;br /&gt;
; Repository: https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Voraussetzungen ===&lt;br /&gt;
&lt;br /&gt;
* macOS 10.13 oder neuer&lt;br /&gt;
* DEVONthink 3.x&lt;br /&gt;
* Apple Mail&lt;br /&gt;
* AppleScript-Zugriff in Systemeinstellungen aktiviert&lt;br /&gt;
* Git (zum Klonen des Repositories)&lt;br /&gt;
&lt;br /&gt;
=== Schritt-für-Schritt Anleitung ===&lt;br /&gt;
&lt;br /&gt;
==== 1. Verzeichnisstruktur anlegen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
cd ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 2. Repository klonen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation.git Belegversand&lt;br /&gt;
cd Belegversand&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 3. Scripts kompilieren ====&lt;br /&gt;
&lt;br /&gt;
Dies ist ein &#039;&#039;&#039;wichtiger Schritt&#039;&#039;&#039; und darf nicht übersprungen werden!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chmod +x compile.sh&lt;br /&gt;
./compile.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erwartete Ausgabe:&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Compiliere Belegversand AppleScripts...&lt;br /&gt;
✓ Fertig!&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 4. Erste Ausführung ====&lt;br /&gt;
&lt;br /&gt;
# DEVONthink öffnen&lt;br /&gt;
# Ein Objekt in der gewünschten Datenbank auswählen&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog folgen → Setup wird durchgeführt&lt;br /&gt;
&lt;br /&gt;
Das Setup-Script erstellt automatisch alle notwendigen Ordnerstrukturen und Konfigurationsdateien in DEVONthink.&lt;br /&gt;
&lt;br /&gt;
== Wichtig: .applescript vs. .scpt Dateien ==&lt;br /&gt;
&lt;br /&gt;
Im Repository gibt es zwei Arten von AppleScript-Dateien:&lt;br /&gt;
&lt;br /&gt;
; .applescript: Quelldateien (lesbar, nur für Entwicklung)&lt;br /&gt;
; .scpt: Kompilierte Skripte (binär, werden von DEVONthink ausgeführt)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Kritisch:&#039;&#039;&#039; Die `.applescript`-Quelldateien funktionieren &#039;&#039;&#039;nicht&#039;&#039;&#039; direkt in DEVONthink. Sie enthalten relative Pfade, die zur Laufzeit expandiert werden müssen.&lt;br /&gt;
&lt;br /&gt;
Das `compile.sh`-Script:&lt;br /&gt;
# Kompiliert alle `.applescript` zu `.scpt`&lt;br /&gt;
# Löscht anschließend die `.applescript`-Dateien&lt;br /&gt;
# Hinterlässt nur funktionsfähige `.scpt`-Dateien&lt;br /&gt;
&lt;br /&gt;
Falls nach dem Clone noch `.applescript`-Dateien vorhanden sind, war `compile.sh` nicht erfolgreich. In diesem Fall erneut ausführen und auf Fehlermeldungen achten.&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
=== Automatische Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Nach der ersten Ausführung erstellt das System automatisch folgende Struktur in DEVONthink:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
_config/&lt;br /&gt;
├── belegversand.conf              # Konfigurationsdatei&lt;br /&gt;
├── mail_vorlagen/                 # Mail-Templates&lt;br /&gt;
│   └── belegversand               # Standard-Template&lt;br /&gt;
├── README-Belegversand            # Interne Hilfe&lt;br /&gt;
└── [weitere Dateien nach Versand]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Konfigurationsdatei ===&lt;br /&gt;
&lt;br /&gt;
Die Datei `belegversand.conf` befindet sich in DEVONthink unter `_config → belegversand.conf`.&lt;br /&gt;
&lt;br /&gt;
==== Wichtigste Parameter ====&lt;br /&gt;
&lt;br /&gt;
; MAIL_TO_DEFAULT: Standard-Empfänger (z.B. steuer@example.com)&lt;br /&gt;
; MAIL_CC_TO_DEFAULT: Standard-CC-Empfänger (optional)&lt;br /&gt;
; MAIL_SUBJECT_PREFIX: Präfix für den Mail-Betreff (z.B. &amp;quot;Belegversand&amp;quot;)&lt;br /&gt;
; ZIP_PASSWORD_DEFAULT: Standard-Passwort für ZIP-Archive (optional, keine Sonderzeichen)&lt;br /&gt;
; LOG_SENT_GROUP_NAME: Name der Ordnergruppe für Versandprotokolle (Standard: &amp;quot;Versendet&amp;quot;)&lt;br /&gt;
; SENT_TAG_FOR_DOCS: Tag für versendete Belege (Standard: &amp;quot;gesendet&amp;quot;)&lt;br /&gt;
; WRITE_DEBUG_LOG: Debug-Logging aktivieren (true/false)&lt;br /&gt;
; SHOW_README: Willkommensdialog beim Start anzeigen (true/false)&lt;br /&gt;
; MAILBODY_FOLDER_NAME: Ordner für Mail-Templates (Standard: &amp;quot;mail_vorlagen&amp;quot;)&lt;br /&gt;
; MAILBODY_RECORD_NAME: Name des Standard-Templates (Standard: &amp;quot;belegversand&amp;quot;)&lt;br /&gt;
; PATH_TO_DRYRUN_PREVIEW: Speicherort der Dry-Run Vorschau-Datei&lt;br /&gt;
&lt;br /&gt;
==== Multiple Empfänger (CSV-Format) ====&lt;br /&gt;
&lt;br /&gt;
Mehrere E-Mail-Adressen können durch Kommas getrennt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
MAIL_TO_DEFAULT=recipient1@example.com, recipient2@example.com&lt;br /&gt;
MAIL_CC_TO_DEFAULT=cc1@example.com, cc2@example.com&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Adressen werden automatisch geparst und in Apple Mail einzeln eingefügt.&lt;br /&gt;
&lt;br /&gt;
== Verwendung ==&lt;br /&gt;
&lt;br /&gt;
=== Grundablauf ===&lt;br /&gt;
&lt;br /&gt;
# Belege in DEVONthink auswählen (Mehrfachauswahl möglich)&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog beantwortet (Empfänger, ZIP-Passwort, Dry-Run?)&lt;br /&gt;
# Dry-Run Vorschau anschauen (optional)&lt;br /&gt;
# Echtlauf → ZIP-Archive erstellt, Mail-Draft geöffnet, Logging durchgeführt&lt;br /&gt;
&lt;br /&gt;
=== Menü-Befehle ===&lt;br /&gt;
&lt;br /&gt;
; START: Haupteinstiegspunkt — startet Setup oder Versand&lt;br /&gt;
; About...: About-Dialog mit Versionsinformation und Links&lt;br /&gt;
&lt;br /&gt;
=== Booking-Jahr Enforcement ===&lt;br /&gt;
&lt;br /&gt;
Das System verhindert Versandvermischung über mehrere Jahre:&lt;br /&gt;
&lt;br /&gt;
; Mixed-Year Selection: Werden Belege aus verschiedenen Jahren auswählt, wird ein Fehler zurückgewiesen&lt;br /&gt;
; Separate Protokolle: Jedes Buchungsjahr hat eigene Versendet-Ordner mit separaten Logs&lt;br /&gt;
; Outsider-Belege: Dokumente außerhalb der Jahresstruktur werden separat gehandhabt&lt;br /&gt;
&lt;br /&gt;
Beispiel-Struktur:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Belege/&lt;br /&gt;
├── 2026/&lt;br /&gt;
│   ├── 01_Januar/&lt;br /&gt;
│   ├── [weitere Monate]&lt;br /&gt;
│   └── Versendet/          [← Logs für 2026-Versand]&lt;br /&gt;
├── 2027/&lt;br /&gt;
│   ├── 01_Januar/&lt;br /&gt;
│   ├── [weitere Monate]&lt;br /&gt;
│   └── Versendet/          [← Logs für 2027-Versand]&lt;br /&gt;
└── Provisionsabrechnungen/&lt;br /&gt;
    └── [← Separate Outsider-Logs]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dry-Run Modus ===&lt;br /&gt;
&lt;br /&gt;
Vor jedem echten Versand kann ein Dry-Run durchgeführt werden:&lt;br /&gt;
&lt;br /&gt;
# Simuliert den kompletten Versandprozess&lt;br /&gt;
# Erstellt Vorschau-Datei mit allen Details&lt;br /&gt;
# Zeigt Dialog mit Zusammenfassung&lt;br /&gt;
# User kann bestätigen oder abbrechen&lt;br /&gt;
&lt;br /&gt;
Die Vorschau-Datei wird auf der lokalen Festplatte gespeichert (Pfad konfigurierbar).&lt;br /&gt;
&lt;br /&gt;
=== Mail-Drafts ===&lt;br /&gt;
&lt;br /&gt;
Das System erstellt keinen automatischen Versand, sondern Mail-Drafts:&lt;br /&gt;
&lt;br /&gt;
# ZIP-Archive werden erzeugt&lt;br /&gt;
# Apple Mail öffnet mit neuem Draft (nicht gesendet!)&lt;br /&gt;
# User kann Template prüfen, weitere Empfänger hinzufügen&lt;br /&gt;
# Benutzerdefinierter Versand per Knopfdruck in Mail&lt;br /&gt;
&lt;br /&gt;
Dies ermöglicht volle Kontrolle über den Versand.&lt;br /&gt;
&lt;br /&gt;
=== Mail-Templates ===&lt;br /&gt;
&lt;br /&gt;
Templates werden aus DEVONthink geladen (`_config/mail_vorlagen/`).&lt;br /&gt;
&lt;br /&gt;
Das System zeigt einen Dialog zur Template-Auswahl, wenn mehrere Vorlagen vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Beispiel-Template:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Sehr geehrte/r Frau/Herr,&lt;br /&gt;
&lt;br /&gt;
beiliegend erhalten Sie die angeforderten Unterlagen.&lt;br /&gt;
&lt;br /&gt;
Mit freundlichen Grüßen&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Protokollierung ==&lt;br /&gt;
&lt;br /&gt;
=== NDJSON-Logs ===&lt;br /&gt;
&lt;br /&gt;
Maschinell lesbar im JSON-Lines Format für technische Weiterverarbeitung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&amp;quot;timestamp&amp;quot;:&amp;quot;2026-01-15T10:30:45Z&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;record&amp;quot;,&amp;quot;record_uuid&amp;quot;:&amp;quot;abc123&amp;quot;,&amp;quot;record_name&amp;quot;:&amp;quot;Invoice-001&amp;quot;,&amp;quot;status&amp;quot;:&amp;quot;sent&amp;quot;}&lt;br /&gt;
{&amp;quot;timestamp&amp;quot;:&amp;quot;2026-01-15T10:30:46Z&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;email&amp;quot;,&amp;quot;to&amp;quot;:&amp;quot;recipient@example.com&amp;quot;,&amp;quot;zip_file&amp;quot;:&amp;quot;archive.zip&amp;quot;,&amp;quot;status&amp;quot;:&amp;quot;created&amp;quot;}&lt;br /&gt;
{&amp;quot;timestamp&amp;quot;:&amp;quot;2026-01-15T10:30:47Z&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;tag&amp;quot;,&amp;quot;record_uuid&amp;quot;:&amp;quot;abc123&amp;quot;,&amp;quot;tag&amp;quot;:&amp;quot;gesendet&amp;quot;,&amp;quot;status&amp;quot;:&amp;quot;applied&amp;quot;}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Markdown-Logs ===&lt;br /&gt;
&lt;br /&gt;
Menschlich lesbar mit Übersichten nach Versandlauf:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
# Belegversand Logs — 2026&lt;br /&gt;
&lt;br /&gt;
## Versandlauf 2026-01-15 10:30&lt;br /&gt;
**Versendete Belege:** 5 Stück&lt;br /&gt;
**Empfänger:** recipient@example.com&lt;br /&gt;
**ZIP-Datei:** belegversand_2026-01-15_103045.zip&lt;br /&gt;
**Passwort:** [konfiguriert]&lt;br /&gt;
**Status:** Erfolgreich&lt;br /&gt;
&lt;br /&gt;
### Versandte Dokumente&lt;br /&gt;
- Invoice-001 (UUID: abc123...)&lt;br /&gt;
- Invoice-002 (UUID: def456...)&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
=== Scripts funktionieren nicht ===&lt;br /&gt;
&lt;br /&gt;
==== Problem: &amp;quot;Script nicht gefunden&amp;quot; ====&lt;br /&gt;
&lt;br /&gt;
Häufigste Ursache: `compile.sh` wurde nicht ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# Prüfen ob `.scpt`-Dateien vorhanden sind: &amp;lt;code&amp;gt;ls ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/Belegversand/Helpers/scripts/&amp;lt;/code&amp;gt;&lt;br /&gt;
# Falls nur `.applescript`-Dateien vorhanden → &amp;lt;code&amp;gt;./compile.sh&amp;lt;/code&amp;gt; erneut ausführen&lt;br /&gt;
# Auf Fehlermeldungen achten&lt;br /&gt;
&lt;br /&gt;
==== Problem: Script-Zugriff verweigert ====&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# System Settings → Privacy &amp;amp; Security → Automation&lt;br /&gt;
# DEVONthink sollte mit entsprechenden Rechten gelistet sein&lt;br /&gt;
# Script Editor öffnen und START.scpt öffnen&lt;br /&gt;
# Compile (⌘K) — sollte ohne Fehler durchlaufen&lt;br /&gt;
&lt;br /&gt;
=== ZIP wird nicht erstellt ===&lt;br /&gt;
&lt;br /&gt;
* ZIP-Passwort in Config überprüfen (keine Sonderzeichen!)&lt;br /&gt;
* Ausreichend Festplatte vorhanden?&lt;br /&gt;
* Staging-Ordner in DEVONthink beschreibbar?&lt;br /&gt;
&lt;br /&gt;
=== Mail-Draft öffnet sich nicht ===&lt;br /&gt;
&lt;br /&gt;
* Apple Mail ist geöffnet?&lt;br /&gt;
* Script-Zugriff für Mail aktiviert?&lt;br /&gt;
* Mail-Templates-Ordner vorhanden?&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Mixed-Year-Selection&amp;quot;-Fehler ===&lt;br /&gt;
&lt;br /&gt;
Dies ist kein Fehler, sondern Schutz vor Versandvermischung:&lt;br /&gt;
&lt;br /&gt;
; Lösung 1: Nur Belege aus einem Buchungsjahr auswählen&lt;br /&gt;
; Lösung 2: Belege in mehreren Versänden verteilen&lt;br /&gt;
&lt;br /&gt;
=== Debug-Informationen aktivieren ===&lt;br /&gt;
&lt;br /&gt;
In `belegversand.conf`:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
WRITE_DEBUG_LOG=true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Debug-Logs erscheinen dann in `/tmp/DT-Belegversand-debug.log`.&lt;br /&gt;
&lt;br /&gt;
== Versionshistorie ==&lt;br /&gt;
&lt;br /&gt;
; 1.4: Booking-Jahr Enforcement, Kompilierungs-Automation, About-Dialog, Wiki-Integration&lt;br /&gt;
; 1.3: Dry-Run Verbesserungen, Markdown-Logs&lt;br /&gt;
; 1.2: Mail-Templates in DEVONthink, interne README&lt;br /&gt;
; 1.1: Konfigurationssystem&lt;br /&gt;
; 1.0: Erste funktionale Version&lt;br /&gt;
&lt;br /&gt;
== Entwicklung ==&lt;br /&gt;
&lt;br /&gt;
Quellcode liegt als `.applescript`-Dateien vor (lesbar, git-freundlich).&lt;br /&gt;
&lt;br /&gt;
Zur lokalen Entwicklung:&lt;br /&gt;
# Quelldateien (`.applescript`) editieren&lt;br /&gt;
# `./compile.sh` ausführen&lt;br /&gt;
# In DEVONthink testen&lt;br /&gt;
# Bei Änderungen: `./compile.sh` erneut ausführen&lt;br /&gt;
&lt;br /&gt;
== Support ==&lt;br /&gt;
&lt;br /&gt;
Für technische Fragen oder Probleme:&lt;br /&gt;
* Wiki-Dokumentation durchlesen (diese Seite)&lt;br /&gt;
* Debug-Log aktivieren und analysieren&lt;br /&gt;
* Im Gitea-Repository ein Issue erstellen (falls Zugriff vorhanden)&lt;br /&gt;
&lt;br /&gt;
== Externe Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation Repository] (privat, erfordert Zugriff)&lt;br /&gt;
* [https://www.devontechnologies.com DEVONthink Homepage]&lt;br /&gt;
* [https://support.apple.com/mail Apple Mail Documentation]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=305</id>
		<title>Belegversand</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=305"/>
		<updated>2026-08-18T15:43:17Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Belegversand =&lt;br /&gt;
&lt;br /&gt;
== Übersicht ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Belegversand&#039;&#039;&#039; ist eine automatisierte AppleScript-Lösung zur Verwaltung von Dokumenten-Versand in DEVONthink. Das System ermöglicht es, Belege aus einer DEVONthink-Datenbank auszuwählen, diese in ZIP-Archive zu packen (optional mit Passwort) und automatische Mail-Drafts mit konfigurierbaren Empfängern zu erstellen. Zusätzlich erfolgt strukturierte Protokollierung über Logging und Tagging-Mechanismen.&lt;br /&gt;
&lt;br /&gt;
== Sicherheitstechnischer Hinweis! ==&lt;br /&gt;
&lt;br /&gt;
Ich bitte zu beachten, dass die Software allenfalls minimale Sicherheitsanforderungen erfüllt.&lt;br /&gt;
&lt;br /&gt;
    Insbesondere liegt das Passwort für&#039;s ZIP-Archiv unverschlüsselt, im Klartext, in /_config/belegversand.conf. Wer das Passwort schützen möchte, kann das über die DB-Crypto von DEVONthink selbst tun. DEVONthink hat eine Datenbank-Verschlüsselung in den Bordmitteln.&lt;br /&gt;
    Dann bleibt trotzdem der zweite Schwachpunkt: Die ZIP-Verschlüsselung wird in dieser Version 1.4 über das Shell-Tool zip -P auf der Konsolenzeile realisiert. Dahinter steckt das veraltete und kryptographisch schwache ZipCrypto-Verfahren.&lt;br /&gt;
&lt;br /&gt;
Ganz deutlich: Diese Belegversand-Automatisation hab&#039; ich mir gebaut, um Tankbelege, Einkaufszettel und Restaurant-Quittungen an die Steuerberatung zu verschicken! Dafür sind sie prima! Falls es eine Version 1.5 geben sollte, ersetze ich zip -P vermutlich durch eine starke AES-Verschlüsselung, und das Passwort kommt als Hash-Wert in die Config-Datei.&lt;br /&gt;
&lt;br /&gt;
Bis dahin gilt aber ganz klar: Wer mit diesen Skripten, in dieser Version 1.4, sicherheitsrelevante Dokumente verschickt, tut das auf eigene Gefahr und handelt fahrlässig!&lt;br /&gt;
&lt;br /&gt;
; Version: 1.4&lt;br /&gt;
; Plattform: macOS 10.13+&lt;br /&gt;
; Abhängigkeiten: DEVONthink 3.x, Apple Mail&lt;br /&gt;
; Lizenz: Privatgebrauch&lt;br /&gt;
; Repository: https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Voraussetzungen ===&lt;br /&gt;
&lt;br /&gt;
* macOS 10.13 oder neuer&lt;br /&gt;
* DEVONthink 3.x&lt;br /&gt;
* Apple Mail&lt;br /&gt;
* AppleScript-Zugriff in Systemeinstellungen aktiviert&lt;br /&gt;
* Git (zum Klonen des Repositories)&lt;br /&gt;
&lt;br /&gt;
=== Schritt-für-Schritt Anleitung ===&lt;br /&gt;
&lt;br /&gt;
==== 1. Verzeichnisstruktur anlegen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
cd ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 2. Repository klonen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation.git Belegversand&lt;br /&gt;
cd Belegversand&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 3. Scripts kompilieren ====&lt;br /&gt;
&lt;br /&gt;
Dies ist ein &#039;&#039;&#039;wichtiger Schritt&#039;&#039;&#039; und darf nicht übersprungen werden!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chmod +x compile.sh&lt;br /&gt;
./compile.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erwartete Ausgabe:&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Compiliere Belegversand AppleScripts...&lt;br /&gt;
✓ Fertig!&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 4. Erste Ausführung ====&lt;br /&gt;
&lt;br /&gt;
# DEVONthink öffnen&lt;br /&gt;
# Ein Objekt in der gewünschten Datenbank auswählen&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog folgen → Setup wird durchgeführt&lt;br /&gt;
&lt;br /&gt;
Das Setup-Script erstellt automatisch alle notwendigen Ordnerstrukturen und Konfigurationsdateien in DEVONthink.&lt;br /&gt;
&lt;br /&gt;
== Wichtig: .applescript vs. .scpt Dateien ==&lt;br /&gt;
&lt;br /&gt;
Im Repository gibt es zwei Arten von AppleScript-Dateien:&lt;br /&gt;
&lt;br /&gt;
; .applescript: Quelldateien (lesbar, nur für Entwicklung)&lt;br /&gt;
; .scpt: Kompilierte Skripte (binär, werden von DEVONthink ausgeführt)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Kritisch:&#039;&#039;&#039; Die `.applescript`-Quelldateien funktionieren &#039;&#039;&#039;nicht&#039;&#039;&#039; direkt in DEVONthink. Sie enthalten relative Pfade, die zur Laufzeit expandiert werden müssen.&lt;br /&gt;
&lt;br /&gt;
Das `compile.sh`-Script:&lt;br /&gt;
# Kompiliert alle `.applescript` zu `.scpt`&lt;br /&gt;
# Löscht anschließend die `.applescript`-Dateien&lt;br /&gt;
# Hinterlässt nur funktionsfähige `.scpt`-Dateien&lt;br /&gt;
&lt;br /&gt;
Falls nach dem Clone noch `.applescript`-Dateien vorhanden sind, war `compile.sh` nicht erfolgreich. In diesem Fall erneut ausführen und auf Fehlermeldungen achten.&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
=== Automatische Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Nach der ersten Ausführung erstellt das System automatisch folgende Struktur in DEVONthink:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
_config/&lt;br /&gt;
├── belegversand.conf              # Konfigurationsdatei&lt;br /&gt;
├── mail_vorlagen/                 # Mail-Templates&lt;br /&gt;
│   └── belegversand               # Standard-Template&lt;br /&gt;
├── README-Belegversand            # Interne Hilfe&lt;br /&gt;
└── [weitere Dateien nach Versand]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Konfigurationsdatei ===&lt;br /&gt;
&lt;br /&gt;
Die Datei `belegversand.conf` befindet sich in DEVONthink unter `_config → belegversand.conf`.&lt;br /&gt;
&lt;br /&gt;
==== Wichtigste Parameter ====&lt;br /&gt;
&lt;br /&gt;
; MAIL_TO_DEFAULT: Standard-Empfänger (z.B. steuer@example.com)&lt;br /&gt;
; MAIL_CC_TO_DEFAULT: Standard-CC-Empfänger (optional)&lt;br /&gt;
; MAIL_SUBJECT_PREFIX: Präfix für den Mail-Betreff (z.B. &amp;quot;Belegversand&amp;quot;)&lt;br /&gt;
; ZIP_PASSWORD_DEFAULT: Standard-Passwort für ZIP-Archive (optional, keine Sonderzeichen)&lt;br /&gt;
; LOG_SENT_GROUP_NAME: Name der Ordnergruppe für Versandprotokolle (Standard: &amp;quot;Versendet&amp;quot;)&lt;br /&gt;
; SENT_TAG_FOR_DOCS: Tag für versendete Belege (Standard: &amp;quot;gesendet&amp;quot;)&lt;br /&gt;
; WRITE_DEBUG_LOG: Debug-Logging aktivieren (true/false)&lt;br /&gt;
; SHOW_README: Willkommensdialog beim Start anzeigen (true/false)&lt;br /&gt;
; MAILBODY_FOLDER_NAME: Ordner für Mail-Templates (Standard: &amp;quot;mail_vorlagen&amp;quot;)&lt;br /&gt;
; MAILBODY_RECORD_NAME: Name des Standard-Templates (Standard: &amp;quot;belegversand&amp;quot;)&lt;br /&gt;
; PATH_TO_DRYRUN_PREVIEW: Speicherort der Dry-Run Vorschau-Datei&lt;br /&gt;
&lt;br /&gt;
==== Multiple Empfänger (CSV-Format) ====&lt;br /&gt;
&lt;br /&gt;
Mehrere E-Mail-Adressen können durch Kommas getrennt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
MAIL_TO_DEFAULT=recipient1@example.com, recipient2@example.com&lt;br /&gt;
MAIL_CC_TO_DEFAULT=cc1@example.com, cc2@example.com&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Adressen werden automatisch geparst und in Apple Mail einzeln eingefügt.&lt;br /&gt;
&lt;br /&gt;
== Verwendung ==&lt;br /&gt;
&lt;br /&gt;
=== Grundablauf ===&lt;br /&gt;
&lt;br /&gt;
# Belege in DEVONthink auswählen (Mehrfachauswahl möglich)&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog beantwortet (Empfänger, ZIP-Passwort, Dry-Run?)&lt;br /&gt;
# Dry-Run Vorschau anschauen (optional)&lt;br /&gt;
# Echtlauf → ZIP-Archive erstellt, Mail-Draft geöffnet, Logging durchgeführt&lt;br /&gt;
&lt;br /&gt;
=== Menü-Befehle ===&lt;br /&gt;
&lt;br /&gt;
; START: Haupteinstiegspunkt — startet Setup oder Versand&lt;br /&gt;
; About...: About-Dialog mit Versionsinformation und Links&lt;br /&gt;
&lt;br /&gt;
=== Booking-Jahr Enforcement ===&lt;br /&gt;
&lt;br /&gt;
Das System verhindert Versandvermischung über mehrere Jahre:&lt;br /&gt;
&lt;br /&gt;
; Mixed-Year Selection: Werden Belege aus verschiedenen Jahren auswählt, wird ein Fehler zurückgewiesen&lt;br /&gt;
; Separate Protokolle: Jedes Buchungsjahr hat eigene Versendet-Ordner mit separaten Logs&lt;br /&gt;
; Outsider-Belege: Dokumente außerhalb der Jahresstruktur werden separat gehandhabt&lt;br /&gt;
&lt;br /&gt;
Beispiel-Struktur:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Belege/&lt;br /&gt;
├── 2026/&lt;br /&gt;
│   ├── 01_Januar/&lt;br /&gt;
│   ├── [weitere Monate]&lt;br /&gt;
│   └── Versendet/          [← Logs für 2026-Versand]&lt;br /&gt;
├── 2027/&lt;br /&gt;
│   ├── 01_Januar/&lt;br /&gt;
│   ├── [weitere Monate]&lt;br /&gt;
│   └── Versendet/          [← Logs für 2027-Versand]&lt;br /&gt;
└── Provisionsabrechnungen/&lt;br /&gt;
    └── [← Separate Outsider-Logs]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dry-Run Modus ===&lt;br /&gt;
&lt;br /&gt;
Vor jedem echten Versand kann ein Dry-Run durchgeführt werden:&lt;br /&gt;
&lt;br /&gt;
# Simuliert den kompletten Versandprozess&lt;br /&gt;
# Erstellt Vorschau-Datei mit allen Details&lt;br /&gt;
# Zeigt Dialog mit Zusammenfassung&lt;br /&gt;
# User kann bestätigen oder abbrechen&lt;br /&gt;
&lt;br /&gt;
Die Vorschau-Datei wird auf der lokalen Festplatte gespeichert (Pfad konfigurierbar).&lt;br /&gt;
&lt;br /&gt;
=== Mail-Drafts ===&lt;br /&gt;
&lt;br /&gt;
Das System erstellt keinen automatischen Versand, sondern Mail-Drafts:&lt;br /&gt;
&lt;br /&gt;
# ZIP-Archive werden erzeugt&lt;br /&gt;
# Apple Mail öffnet mit neuem Draft (nicht gesendet!)&lt;br /&gt;
# User kann Template prüfen, weitere Empfänger hinzufügen&lt;br /&gt;
# Benutzerdefinierter Versand per Knopfdruck in Mail&lt;br /&gt;
&lt;br /&gt;
Dies ermöglicht volle Kontrolle über den Versand.&lt;br /&gt;
&lt;br /&gt;
=== Mail-Templates ===&lt;br /&gt;
&lt;br /&gt;
Templates werden aus DEVONthink geladen (`_config/mail_vorlagen/`).&lt;br /&gt;
&lt;br /&gt;
Das System zeigt einen Dialog zur Template-Auswahl, wenn mehrere Vorlagen vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Beispiel-Template:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Sehr geehrte/r Frau/Herr,&lt;br /&gt;
&lt;br /&gt;
beiliegend erhalten Sie die angeforderten Unterlagen.&lt;br /&gt;
&lt;br /&gt;
Mit freundlichen Grüßen&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Protokollierung ==&lt;br /&gt;
&lt;br /&gt;
=== NDJSON-Logs ===&lt;br /&gt;
&lt;br /&gt;
Maschinell lesbar im JSON-Lines Format für technische Weiterverarbeitung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&amp;quot;timestamp&amp;quot;:&amp;quot;2026-01-15T10:30:45Z&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;record&amp;quot;,&amp;quot;record_uuid&amp;quot;:&amp;quot;abc123&amp;quot;,&amp;quot;record_name&amp;quot;:&amp;quot;Invoice-001&amp;quot;,&amp;quot;status&amp;quot;:&amp;quot;sent&amp;quot;}&lt;br /&gt;
{&amp;quot;timestamp&amp;quot;:&amp;quot;2026-01-15T10:30:46Z&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;email&amp;quot;,&amp;quot;to&amp;quot;:&amp;quot;recipient@example.com&amp;quot;,&amp;quot;zip_file&amp;quot;:&amp;quot;archive.zip&amp;quot;,&amp;quot;status&amp;quot;:&amp;quot;created&amp;quot;}&lt;br /&gt;
{&amp;quot;timestamp&amp;quot;:&amp;quot;2026-01-15T10:30:47Z&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;tag&amp;quot;,&amp;quot;record_uuid&amp;quot;:&amp;quot;abc123&amp;quot;,&amp;quot;tag&amp;quot;:&amp;quot;gesendet&amp;quot;,&amp;quot;status&amp;quot;:&amp;quot;applied&amp;quot;}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Markdown-Logs ===&lt;br /&gt;
&lt;br /&gt;
Menschlich lesbar mit Übersichten nach Versandlauf:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
# Belegversand Logs — 2026&lt;br /&gt;
&lt;br /&gt;
## Versandlauf 2026-01-15 10:30&lt;br /&gt;
**Versendete Belege:** 5 Stück&lt;br /&gt;
**Empfänger:** recipient@example.com&lt;br /&gt;
**ZIP-Datei:** belegversand_2026-01-15_103045.zip&lt;br /&gt;
**Passwort:** [konfiguriert]&lt;br /&gt;
**Status:** Erfolgreich&lt;br /&gt;
&lt;br /&gt;
### Versandte Dokumente&lt;br /&gt;
- Invoice-001 (UUID: abc123...)&lt;br /&gt;
- Invoice-002 (UUID: def456...)&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
=== Scripts funktionieren nicht ===&lt;br /&gt;
&lt;br /&gt;
==== Problem: &amp;quot;Script nicht gefunden&amp;quot; ====&lt;br /&gt;
&lt;br /&gt;
Häufigste Ursache: `compile.sh` wurde nicht ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# Prüfen ob `.scpt`-Dateien vorhanden sind: &amp;lt;code&amp;gt;ls ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/Belegversand/Helpers/scripts/&amp;lt;/code&amp;gt;&lt;br /&gt;
# Falls nur `.applescript`-Dateien vorhanden → &amp;lt;code&amp;gt;./compile.sh&amp;lt;/code&amp;gt; erneut ausführen&lt;br /&gt;
# Auf Fehlermeldungen achten&lt;br /&gt;
&lt;br /&gt;
==== Problem: Script-Zugriff verweigert ====&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# System Settings → Privacy &amp;amp; Security → Automation&lt;br /&gt;
# DEVONthink sollte mit entsprechenden Rechten gelistet sein&lt;br /&gt;
# Script Editor öffnen und START.scpt öffnen&lt;br /&gt;
# Compile (⌘K) — sollte ohne Fehler durchlaufen&lt;br /&gt;
&lt;br /&gt;
=== ZIP wird nicht erstellt ===&lt;br /&gt;
&lt;br /&gt;
* ZIP-Passwort in Config überprüfen (keine Sonderzeichen!)&lt;br /&gt;
* Ausreichend Festplatte vorhanden?&lt;br /&gt;
* Staging-Ordner in DEVONthink beschreibbar?&lt;br /&gt;
&lt;br /&gt;
=== Mail-Draft öffnet sich nicht ===&lt;br /&gt;
&lt;br /&gt;
* Apple Mail ist geöffnet?&lt;br /&gt;
* Script-Zugriff für Mail aktiviert?&lt;br /&gt;
* Mail-Templates-Ordner vorhanden?&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Mixed-Year-Selection&amp;quot;-Fehler ===&lt;br /&gt;
&lt;br /&gt;
Dies ist kein Fehler, sondern Schutz vor Versandvermischung:&lt;br /&gt;
&lt;br /&gt;
; Lösung 1: Nur Belege aus einem Buchungsjahr auswählen&lt;br /&gt;
; Lösung 2: Belege in mehreren Versänden verteilen&lt;br /&gt;
&lt;br /&gt;
=== Debug-Informationen aktivieren ===&lt;br /&gt;
&lt;br /&gt;
In `belegversand.conf`:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
WRITE_DEBUG_LOG=true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Debug-Logs erscheinen dann in `/tmp/DT-Belegversand-debug.log`.&lt;br /&gt;
&lt;br /&gt;
== Versionshistorie ==&lt;br /&gt;
&lt;br /&gt;
; 1.4: Booking-Jahr Enforcement, Kompilierungs-Automation, About-Dialog, Wiki-Integration&lt;br /&gt;
; 1.3: Dry-Run Verbesserungen, Markdown-Logs&lt;br /&gt;
; 1.2: Mail-Templates in DEVONthink, interne README&lt;br /&gt;
; 1.1: Konfigurationssystem&lt;br /&gt;
; 1.0: Erste funktionale Version&lt;br /&gt;
&lt;br /&gt;
== Entwicklung ==&lt;br /&gt;
&lt;br /&gt;
Quellcode liegt als `.applescript`-Dateien vor (lesbar, git-freundlich).&lt;br /&gt;
&lt;br /&gt;
Zur lokalen Entwicklung:&lt;br /&gt;
# Quelldateien (`.applescript`) editieren&lt;br /&gt;
# `./compile.sh` ausführen&lt;br /&gt;
# In DEVONthink testen&lt;br /&gt;
# Bei Änderungen: `./compile.sh` erneut ausführen&lt;br /&gt;
&lt;br /&gt;
== Support ==&lt;br /&gt;
&lt;br /&gt;
Für technische Fragen oder Probleme:&lt;br /&gt;
* Wiki-Dokumentation durchlesen (diese Seite)&lt;br /&gt;
* Debug-Log aktivieren und analysieren&lt;br /&gt;
* Im Gitea-Repository ein Issue erstellen (falls Zugriff vorhanden)&lt;br /&gt;
&lt;br /&gt;
== Externe Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation Repository] (privat, erfordert Zugriff)&lt;br /&gt;
* [https://www.devontechnologies.com DEVONthink Homepage]&lt;br /&gt;
* [https://support.apple.com/mail Apple Mail Documentation]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=304</id>
		<title>Belegversand</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Belegversand&amp;diff=304"/>
		<updated>2026-08-18T12:55:39Z</updated>

		<summary type="html">&lt;p&gt;Admin: Ausfühlriche Doku: Appleskript-Paket für die Datenbanksoftware DEVONthink, das beliebige Dokumente aus der Datenbank per Mail automatisuert versendet, diese Dokumente innerhalb von DEVONthink taggt und die Vorgänge protokolliert.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Belegversand =&lt;br /&gt;
&lt;br /&gt;
== Übersicht ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Belegversand&#039;&#039;&#039; ist eine automatisierte AppleScript-Lösung zur Verwaltung von Dokumenten-Versand in DEVONthink. Das System ermöglicht es, Belege aus einer DEVONthink-Datenbank auszuwählen, diese in ZIP-Archive zu packen (optional mit Passwort) und automatische Mail-Drafts mit konfigurierbaren Empfängern zu erstellen. Zusätzlich erfolgt strukturierte Protokollierung über Logging und Tagging-Mechanismen.&lt;br /&gt;
&lt;br /&gt;
; Version: 1.4&lt;br /&gt;
; Plattform: macOS 10.13+&lt;br /&gt;
; Abhängigkeiten: DEVONthink 3.x, Apple Mail&lt;br /&gt;
; Lizenz: Privatgebrauch&lt;br /&gt;
; Repository: https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Voraussetzungen ===&lt;br /&gt;
&lt;br /&gt;
* macOS 10.13 oder neuer&lt;br /&gt;
* DEVONthink 3.x&lt;br /&gt;
* Apple Mail&lt;br /&gt;
* AppleScript-Zugriff in Systemeinstellungen aktiviert&lt;br /&gt;
* Git (zum Klonen des Repositories)&lt;br /&gt;
&lt;br /&gt;
=== Schritt-für-Schritt Anleitung ===&lt;br /&gt;
&lt;br /&gt;
==== 1. Verzeichnisstruktur anlegen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
cd ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 2. Repository klonen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation.git Belegversand&lt;br /&gt;
cd Belegversand&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 3. Scripts kompilieren ====&lt;br /&gt;
&lt;br /&gt;
Dies ist ein &#039;&#039;&#039;wichtiger Schritt&#039;&#039;&#039; und darf nicht übersprungen werden!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chmod +x compile.sh&lt;br /&gt;
./compile.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erwartete Ausgabe:&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Compiliere Belegversand AppleScripts...&lt;br /&gt;
✓ Fertig!&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 4. Erste Ausführung ====&lt;br /&gt;
&lt;br /&gt;
# DEVONthink öffnen&lt;br /&gt;
# Ein Objekt in der gewünschten Datenbank auswählen&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog folgen → Setup wird durchgeführt&lt;br /&gt;
&lt;br /&gt;
Das Setup-Script erstellt automatisch alle notwendigen Ordnerstrukturen und Konfigurationsdateien in DEVONthink.&lt;br /&gt;
&lt;br /&gt;
== Wichtig: .applescript vs. .scpt Dateien ==&lt;br /&gt;
&lt;br /&gt;
Im Repository gibt es zwei Arten von AppleScript-Dateien:&lt;br /&gt;
&lt;br /&gt;
; .applescript: Quelldateien (lesbar, nur für Entwicklung)&lt;br /&gt;
; .scpt: Kompilierte Skripte (binär, werden von DEVONthink ausgeführt)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Kritisch:&#039;&#039;&#039; Die `.applescript`-Quelldateien funktionieren &#039;&#039;&#039;nicht&#039;&#039;&#039; direkt in DEVONthink. Sie enthalten relative Pfade, die zur Laufzeit expandiert werden müssen.&lt;br /&gt;
&lt;br /&gt;
Das `compile.sh`-Script:&lt;br /&gt;
# Kompiliert alle `.applescript` zu `.scpt`&lt;br /&gt;
# Löscht anschließend die `.applescript`-Dateien&lt;br /&gt;
# Hinterlässt nur funktionsfähige `.scpt`-Dateien&lt;br /&gt;
&lt;br /&gt;
Falls nach dem Clone noch `.applescript`-Dateien vorhanden sind, war `compile.sh` nicht erfolgreich. In diesem Fall erneut ausführen und auf Fehlermeldungen achten.&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
=== Automatische Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Nach der ersten Ausführung erstellt das System automatisch folgende Struktur in DEVONthink:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
_config/&lt;br /&gt;
├── belegversand.conf              # Konfigurationsdatei&lt;br /&gt;
├── mail_vorlagen/                 # Mail-Templates&lt;br /&gt;
│   └── belegversand               # Standard-Template&lt;br /&gt;
├── README-Belegversand            # Interne Hilfe&lt;br /&gt;
└── [weitere Dateien nach Versand]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Konfigurationsdatei ===&lt;br /&gt;
&lt;br /&gt;
Die Datei `belegversand.conf` befindet sich in DEVONthink unter `_config → belegversand.conf`.&lt;br /&gt;
&lt;br /&gt;
==== Wichtigste Parameter ====&lt;br /&gt;
&lt;br /&gt;
; MAIL_TO_DEFAULT: Standard-Empfänger (z.B. steuer@example.com)&lt;br /&gt;
; MAIL_CC_TO_DEFAULT: Standard-CC-Empfänger (optional)&lt;br /&gt;
; MAIL_SUBJECT_PREFIX: Präfix für den Mail-Betreff (z.B. &amp;quot;Belegversand&amp;quot;)&lt;br /&gt;
; ZIP_PASSWORD_DEFAULT: Standard-Passwort für ZIP-Archive (optional, keine Sonderzeichen)&lt;br /&gt;
; LOG_SENT_GROUP_NAME: Name der Ordnergruppe für Versandprotokolle (Standard: &amp;quot;Versendet&amp;quot;)&lt;br /&gt;
; SENT_TAG_FOR_DOCS: Tag für versendete Belege (Standard: &amp;quot;gesendet&amp;quot;)&lt;br /&gt;
; WRITE_DEBUG_LOG: Debug-Logging aktivieren (true/false)&lt;br /&gt;
; SHOW_README: Willkommensdialog beim Start anzeigen (true/false)&lt;br /&gt;
; MAILBODY_FOLDER_NAME: Ordner für Mail-Templates (Standard: &amp;quot;mail_vorlagen&amp;quot;)&lt;br /&gt;
; MAILBODY_RECORD_NAME: Name des Standard-Templates (Standard: &amp;quot;belegversand&amp;quot;)&lt;br /&gt;
; PATH_TO_DRYRUN_PREVIEW: Speicherort der Dry-Run Vorschau-Datei&lt;br /&gt;
&lt;br /&gt;
==== Multiple Empfänger (CSV-Format) ====&lt;br /&gt;
&lt;br /&gt;
Mehrere E-Mail-Adressen können durch Kommas getrennt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
MAIL_TO_DEFAULT=recipient1@example.com, recipient2@example.com&lt;br /&gt;
MAIL_CC_TO_DEFAULT=cc1@example.com, cc2@example.com&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Adressen werden automatisch geparst und in Apple Mail einzeln eingefügt.&lt;br /&gt;
&lt;br /&gt;
== Verwendung ==&lt;br /&gt;
&lt;br /&gt;
=== Grundablauf ===&lt;br /&gt;
&lt;br /&gt;
# Belege in DEVONthink auswählen (Mehrfachauswahl möglich)&lt;br /&gt;
# Scripts → START aufrufen&lt;br /&gt;
# Dialog beantwortet (Empfänger, ZIP-Passwort, Dry-Run?)&lt;br /&gt;
# Dry-Run Vorschau anschauen (optional)&lt;br /&gt;
# Echtlauf → ZIP-Archive erstellt, Mail-Draft geöffnet, Logging durchgeführt&lt;br /&gt;
&lt;br /&gt;
=== Menü-Befehle ===&lt;br /&gt;
&lt;br /&gt;
; START: Haupteinstiegspunkt — startet Setup oder Versand&lt;br /&gt;
; About...: About-Dialog mit Versionsinformation und Links&lt;br /&gt;
&lt;br /&gt;
=== Booking-Jahr Enforcement ===&lt;br /&gt;
&lt;br /&gt;
Das System verhindert Versandvermischung über mehrere Jahre:&lt;br /&gt;
&lt;br /&gt;
; Mixed-Year Selection: Werden Belege aus verschiedenen Jahren auswählt, wird ein Fehler zurückgewiesen&lt;br /&gt;
; Separate Protokolle: Jedes Buchungsjahr hat eigene Versendet-Ordner mit separaten Logs&lt;br /&gt;
; Outsider-Belege: Dokumente außerhalb der Jahresstruktur werden separat gehandhabt&lt;br /&gt;
&lt;br /&gt;
Beispiel-Struktur:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Belege/&lt;br /&gt;
├── 2026/&lt;br /&gt;
│   ├── 01_Januar/&lt;br /&gt;
│   ├── [weitere Monate]&lt;br /&gt;
│   └── Versendet/          [← Logs für 2026-Versand]&lt;br /&gt;
├── 2027/&lt;br /&gt;
│   ├── 01_Januar/&lt;br /&gt;
│   ├── [weitere Monate]&lt;br /&gt;
│   └── Versendet/          [← Logs für 2027-Versand]&lt;br /&gt;
└── Provisionsabrechnungen/&lt;br /&gt;
    └── [← Separate Outsider-Logs]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dry-Run Modus ===&lt;br /&gt;
&lt;br /&gt;
Vor jedem echten Versand kann ein Dry-Run durchgeführt werden:&lt;br /&gt;
&lt;br /&gt;
# Simuliert den kompletten Versandprozess&lt;br /&gt;
# Erstellt Vorschau-Datei mit allen Details&lt;br /&gt;
# Zeigt Dialog mit Zusammenfassung&lt;br /&gt;
# User kann bestätigen oder abbrechen&lt;br /&gt;
&lt;br /&gt;
Die Vorschau-Datei wird auf der lokalen Festplatte gespeichert (Pfad konfigurierbar).&lt;br /&gt;
&lt;br /&gt;
=== Mail-Drafts ===&lt;br /&gt;
&lt;br /&gt;
Das System erstellt keinen automatischen Versand, sondern Mail-Drafts:&lt;br /&gt;
&lt;br /&gt;
# ZIP-Archive werden erzeugt&lt;br /&gt;
# Apple Mail öffnet mit neuem Draft (nicht gesendet!)&lt;br /&gt;
# User kann Template prüfen, weitere Empfänger hinzufügen&lt;br /&gt;
# Benutzerdefinierter Versand per Knopfdruck in Mail&lt;br /&gt;
&lt;br /&gt;
Dies ermöglicht volle Kontrolle über den Versand.&lt;br /&gt;
&lt;br /&gt;
=== Mail-Templates ===&lt;br /&gt;
&lt;br /&gt;
Templates werden aus DEVONthink geladen (`_config/mail_vorlagen/`).&lt;br /&gt;
&lt;br /&gt;
Das System zeigt einen Dialog zur Template-Auswahl, wenn mehrere Vorlagen vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Beispiel-Template:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Sehr geehrte/r Frau/Herr,&lt;br /&gt;
&lt;br /&gt;
beiliegend erhalten Sie die angeforderten Unterlagen.&lt;br /&gt;
&lt;br /&gt;
Mit freundlichen Grüßen&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Protokollierung ==&lt;br /&gt;
&lt;br /&gt;
=== NDJSON-Logs ===&lt;br /&gt;
&lt;br /&gt;
Maschinell lesbar im JSON-Lines Format für technische Weiterverarbeitung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&amp;quot;timestamp&amp;quot;:&amp;quot;2026-01-15T10:30:45Z&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;record&amp;quot;,&amp;quot;record_uuid&amp;quot;:&amp;quot;abc123&amp;quot;,&amp;quot;record_name&amp;quot;:&amp;quot;Invoice-001&amp;quot;,&amp;quot;status&amp;quot;:&amp;quot;sent&amp;quot;}&lt;br /&gt;
{&amp;quot;timestamp&amp;quot;:&amp;quot;2026-01-15T10:30:46Z&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;email&amp;quot;,&amp;quot;to&amp;quot;:&amp;quot;recipient@example.com&amp;quot;,&amp;quot;zip_file&amp;quot;:&amp;quot;archive.zip&amp;quot;,&amp;quot;status&amp;quot;:&amp;quot;created&amp;quot;}&lt;br /&gt;
{&amp;quot;timestamp&amp;quot;:&amp;quot;2026-01-15T10:30:47Z&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;tag&amp;quot;,&amp;quot;record_uuid&amp;quot;:&amp;quot;abc123&amp;quot;,&amp;quot;tag&amp;quot;:&amp;quot;gesendet&amp;quot;,&amp;quot;status&amp;quot;:&amp;quot;applied&amp;quot;}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Markdown-Logs ===&lt;br /&gt;
&lt;br /&gt;
Menschlich lesbar mit Übersichten nach Versandlauf:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
# Belegversand Logs — 2026&lt;br /&gt;
&lt;br /&gt;
## Versandlauf 2026-01-15 10:30&lt;br /&gt;
**Versendete Belege:** 5 Stück&lt;br /&gt;
**Empfänger:** recipient@example.com&lt;br /&gt;
**ZIP-Datei:** belegversand_2026-01-15_103045.zip&lt;br /&gt;
**Passwort:** [konfiguriert]&lt;br /&gt;
**Status:** Erfolgreich&lt;br /&gt;
&lt;br /&gt;
### Versandte Dokumente&lt;br /&gt;
- Invoice-001 (UUID: abc123...)&lt;br /&gt;
- Invoice-002 (UUID: def456...)&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
=== Scripts funktionieren nicht ===&lt;br /&gt;
&lt;br /&gt;
==== Problem: &amp;quot;Script nicht gefunden&amp;quot; ====&lt;br /&gt;
&lt;br /&gt;
Häufigste Ursache: `compile.sh` wurde nicht ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# Prüfen ob `.scpt`-Dateien vorhanden sind: &amp;lt;code&amp;gt;ls ~/Library/Application\ Scripts/com.devon-technologies.think/Menu/Belegversand/Helpers/scripts/&amp;lt;/code&amp;gt;&lt;br /&gt;
# Falls nur `.applescript`-Dateien vorhanden → &amp;lt;code&amp;gt;./compile.sh&amp;lt;/code&amp;gt; erneut ausführen&lt;br /&gt;
# Auf Fehlermeldungen achten&lt;br /&gt;
&lt;br /&gt;
==== Problem: Script-Zugriff verweigert ====&lt;br /&gt;
&lt;br /&gt;
Lösung:&lt;br /&gt;
# System Settings → Privacy &amp;amp; Security → Automation&lt;br /&gt;
# DEVONthink sollte mit entsprechenden Rechten gelistet sein&lt;br /&gt;
# Script Editor öffnen und START.scpt öffnen&lt;br /&gt;
# Compile (⌘K) — sollte ohne Fehler durchlaufen&lt;br /&gt;
&lt;br /&gt;
=== ZIP wird nicht erstellt ===&lt;br /&gt;
&lt;br /&gt;
* ZIP-Passwort in Config überprüfen (keine Sonderzeichen!)&lt;br /&gt;
* Ausreichend Festplatte vorhanden?&lt;br /&gt;
* Staging-Ordner in DEVONthink beschreibbar?&lt;br /&gt;
&lt;br /&gt;
=== Mail-Draft öffnet sich nicht ===&lt;br /&gt;
&lt;br /&gt;
* Apple Mail ist geöffnet?&lt;br /&gt;
* Script-Zugriff für Mail aktiviert?&lt;br /&gt;
* Mail-Templates-Ordner vorhanden?&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Mixed-Year-Selection&amp;quot;-Fehler ===&lt;br /&gt;
&lt;br /&gt;
Dies ist kein Fehler, sondern Schutz vor Versandvermischung:&lt;br /&gt;
&lt;br /&gt;
; Lösung 1: Nur Belege aus einem Buchungsjahr auswählen&lt;br /&gt;
; Lösung 2: Belege in mehreren Versänden verteilen&lt;br /&gt;
&lt;br /&gt;
=== Debug-Informationen aktivieren ===&lt;br /&gt;
&lt;br /&gt;
In `belegversand.conf`:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
WRITE_DEBUG_LOG=true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Debug-Logs erscheinen dann in `/tmp/DT-Belegversand-debug.log`.&lt;br /&gt;
&lt;br /&gt;
== Versionshistorie ==&lt;br /&gt;
&lt;br /&gt;
; 1.4: Booking-Jahr Enforcement, Kompilierungs-Automation, About-Dialog, Wiki-Integration&lt;br /&gt;
; 1.3: Dry-Run Verbesserungen, Markdown-Logs&lt;br /&gt;
; 1.2: Mail-Templates in DEVONthink, interne README&lt;br /&gt;
; 1.1: Konfigurationssystem&lt;br /&gt;
; 1.0: Erste funktionale Version&lt;br /&gt;
&lt;br /&gt;
== Entwicklung ==&lt;br /&gt;
&lt;br /&gt;
Quellcode liegt als `.applescript`-Dateien vor (lesbar, git-freundlich).&lt;br /&gt;
&lt;br /&gt;
Zur lokalen Entwicklung:&lt;br /&gt;
# Quelldateien (`.applescript`) editieren&lt;br /&gt;
# `./compile.sh` ausführen&lt;br /&gt;
# In DEVONthink testen&lt;br /&gt;
# Bei Änderungen: `./compile.sh` erneut ausführen&lt;br /&gt;
&lt;br /&gt;
== Support ==&lt;br /&gt;
&lt;br /&gt;
Für technische Fragen oder Probleme:&lt;br /&gt;
* Wiki-Dokumentation durchlesen (diese Seite)&lt;br /&gt;
* Debug-Log aktivieren und analysieren&lt;br /&gt;
* Im Gitea-Repository ein Issue erstellen (falls Zugriff vorhanden)&lt;br /&gt;
&lt;br /&gt;
== Externe Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://gitea.tuxi.ddnss.de/enchiriadis/DEVONthink-Belegversand-Automatisation Repository] (privat, erfordert Zugriff)&lt;br /&gt;
* [https://www.devontechnologies.com DEVONthink Homepage]&lt;br /&gt;
* [https://support.apple.com/mail Apple Mail Documentation]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Projekte&amp;diff=303</id>
		<title>Projekte</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Projekte&amp;diff=303"/>
		<updated>2026-08-18T12:52:53Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Software */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Software ==&lt;br /&gt;
- AI und Anverwandte -&lt;br /&gt;
* [[ChatGPT-Client - Wiki]]&lt;br /&gt;
- Linux-Tools -&lt;br /&gt;
* [[Git-Spickzettel]]&lt;br /&gt;
* [[Mutt - ein textbasierter Mail-Client ]]&lt;br /&gt;
- DEVONthink-Automation&lt;br /&gt;
* [[Belegversand ]]&lt;br /&gt;
&lt;br /&gt;
== Server-Administration ==&lt;br /&gt;
&lt;br /&gt;
=== Sicherheit ===&lt;br /&gt;
* [[SSH]]&lt;br /&gt;
&lt;br /&gt;
=== Webserver ===&lt;br /&gt;
* [[:Kategorie:Webserver|Webserver – Übersicht]]&lt;br /&gt;
&lt;br /&gt;
=== Infrastruktur ===&lt;br /&gt;
* [[Homeserver-Sicherheitsarchitektur]]&lt;br /&gt;
* [[Powertop (Linux-Daemon)]]&lt;br /&gt;
&lt;br /&gt;
== Romanprojekt: Der verborgene Bach ==&lt;br /&gt;
* [[Basis: Die &amp;quot;Kunst der Fuge&amp;quot;, BWV 1080]]&lt;br /&gt;
* [[Plot]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Projekte]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Projekte&amp;diff=302</id>
		<title>Projekte</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Projekte&amp;diff=302"/>
		<updated>2026-08-18T12:32:00Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Software */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Software ==&lt;br /&gt;
* [[ChatGPT-Client - Wiki]]&lt;br /&gt;
* [[Git-Spickzettel]]&lt;br /&gt;
* [[Mutt - ein textbasierter Mail-Client ]]&lt;br /&gt;
test&lt;br /&gt;
&lt;br /&gt;
== Server-Administration ==&lt;br /&gt;
&lt;br /&gt;
=== Sicherheit ===&lt;br /&gt;
* [[SSH]]&lt;br /&gt;
&lt;br /&gt;
=== Webserver ===&lt;br /&gt;
* [[:Kategorie:Webserver|Webserver – Übersicht]]&lt;br /&gt;
&lt;br /&gt;
=== Infrastruktur ===&lt;br /&gt;
* [[Homeserver-Sicherheitsarchitektur]]&lt;br /&gt;
* [[Powertop (Linux-Daemon)]]&lt;br /&gt;
&lt;br /&gt;
== Romanprojekt: Der verborgene Bach ==&lt;br /&gt;
* [[Basis: Die &amp;quot;Kunst der Fuge&amp;quot;, BWV 1080]]&lt;br /&gt;
* [[Plot]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Projekte]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Robert_Franz_(1815-1892),_deutscher_Komponist&amp;diff=265</id>
		<title>Robert Franz (1815-1892), deutscher Komponist</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Robert_Franz_(1815-1892),_deutscher_Komponist&amp;diff=265"/>
		<updated>2026-05-31T13:49:57Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Die Lieder */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Robert Franz}}&lt;br /&gt;
[[Kategorie:Musik]]&lt;br /&gt;
[[Kategorie:Musik/Persönlichkeiten]]&lt;br /&gt;
Robert Franz (eigentlich Robert Franz Julius Knauth; * 28. Juni 1815 in Halle an der Saale; † 24. Oktober 1892 ebenda) war ein deutscher Komponist, Organist und Dirigent.  Zu Lebzeiten von Zeitgenossen wie Robert Schumann, Franz Liszt und Felix Mendelssohn geschätzt, gehört er heute zu den weitgehend vergessenen Komponisten der deutschen Romantik.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Robert Franz.jpg|thumb|right|250px|Robert Franz (1815–1892)]]&lt;br /&gt;
&lt;br /&gt;
== Leben ==&lt;br /&gt;
&lt;br /&gt;
=== Herkunft und Ausbildung ===&lt;br /&gt;
&lt;br /&gt;
Robert Franz stammte aus einer alteingesessenen Hallorer-Familie. (Siehe auch: [[Halloren]]).&lt;br /&gt;
Er wuchs in Halle auf, wo er ab 1828 die Latina der Franckeschen Stiftungen besuchte. Früh fiel er durch musikalische Begabung auf; der dortige Kantor Carl Gottlob Abela ließ ihn die Proben des Schulchors am Klavier begleiten. Von 1835 bis 1837 studierte er Komposition bei Friedrich Schneider in Dessau und kehrte danach nach Halle zurück – in eine Stadt, die er zeit seines Lebens kaum verlassen sollte.&lt;br /&gt;
&lt;br /&gt;
=== Berufliche Laufbahn in Halle ===&lt;br /&gt;
&lt;br /&gt;
Nach schwierigen wirtschaftlichen Anfangsjahren übernahm Franz 1841 das Organistenamt an der Ulrichskirche. Im folgenden Jahr wurde er Dirigent der Singakademie Halle, die später seinen Namen annahm. 1848 heiratete er Marie Hinrichs, Tochter eines Professors und selbst Komponistin; das Paar hatte drei Kinder. 1859 wurde Franz schließlich zum Universitätsmusikdirektor ernannt – der Höhepunkt seiner öffentlichen Laufbahn.&lt;br /&gt;
&lt;br /&gt;
=== Krankheit und Rückzug ===&lt;br /&gt;
&lt;br /&gt;
Seit 1843 litt Franz an einem Nerven- und Ohrenleiden, das sich über Jahrzehnte progressiv verschlimmerte und schließlich zur vollständigen Taubheit führte. 1867 wurde er beurlaubt, &lt;br /&gt;
1868 musste er alle Ämter endgültig aufgeben. Die daraus folgende finanzielle Not war erheblich: Ein 1867 zuerkannter Ehrensold wurde ihm 1877 auf Betreiben von Widersachern wieder entzogen. Seinen Lebensunterhalt sicherte schließlich ein 1873 von Freunden und Kollegen – allen voran Franz Liszt – gestifteter Ehrenfonds in Höhe von 30.000 Talern.&lt;br /&gt;
&lt;br /&gt;
Die letzten rund 25 Jahre seines Lebens verbrachte Franz in nahezu vollständiger Taubheit und sozialem Rückzug. Er starb am 24. Oktober 1892 in Halle.&lt;br /&gt;
&lt;br /&gt;
1885 wurde ihm zu seinem 70. Geburtstag – anlässlich der Feier des 200. Geburtstags Georg Friedrich Händels – das Ehrenbürgerrecht der Stadt Halle verliehen.&lt;br /&gt;
&lt;br /&gt;
=== Familie ===&lt;br /&gt;
&lt;br /&gt;
1848 heiratete Robert Franz in Halle Marie Hinrichs (1828–1891), &lt;br /&gt;
Tochter des Hallenser Philosophieprofessors Hermann Friedrich &lt;br /&gt;
Wilhelm Hinrichs. Marie Franz war selbst Komponistin und hatte bereits 1846 – also &lt;br /&gt;
zwei Jahre vor der Heirat – bei Breitkopf &amp;amp; Härtel in Leipzig einen &lt;br /&gt;
Band mit neun Gesängen für Singstimme und Klavier veröffentlicht.&lt;br /&gt;
&lt;br /&gt;
Dem Paar wurden drei Kinder geboren. Bekannt sind: ein Sohn, der &lt;br /&gt;
1900 als praktischer Arzt in Heidelberg starb, sowie eine Tochter, &lt;br /&gt;
die den Superintendenten Bethge in Giebichenstein heiratete.&lt;br /&gt;
&lt;br /&gt;
Marie Franz starb 1891. Robert Franz, &lt;br /&gt;
taub und weitgehend isoliert, überlebte sie um ein Jahr. &lt;br /&gt;
Beide sind auf dem Stadtgottesacker in Halle begraben.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Robert-franz-im-alter.png |thumb|right|250px|Robert Franz, späte Aufnahme]]&lt;br /&gt;
&lt;br /&gt;
== Das Werk ==&lt;br /&gt;
&lt;br /&gt;
=== Die Lieder ===&lt;br /&gt;
&lt;br /&gt;
Robert Franz schrieb über 350 Kunstlieder für Singstimme und Klavier – und fast ausschließlich das. Keine Symphonien, keine Opern, kein Streichquartett. Diese bewusste Konzentration auf eine einzige Gattung war seine Stärke und zugleich der Grund für sein späteres Vergessen.&lt;br /&gt;
&lt;br /&gt;
Etwa ein Viertel seiner Lieder vertont Texte von Heinrich Heine. Daneben war Karl Wilhelm Osterwald ein bevorzugter Dichter. Franz&#039; Vertonungsweise gilt als außerordentlich textgetreu und harmonisch differenziert – ohne Effekthascherei, in großer Zurückhaltung und mit feinem Klangsinn. Robert Schumann, dem Franz 1843 sein erstes gedrucktes Heft (op. 1, &#039;&#039;Zwölf Gesänge&#039;&#039;) zuschickte, antwortete, die Lieder hätten ihm gefallen „wie seit langer Zeit keine mehr&amp;quot;. Auch Mendelssohn, Liszt und Wagner äußerten sich anerkennend.&lt;br /&gt;
&lt;br /&gt;
Zu den heute noch gelegentlich aufgeführten Liedern gehören:&lt;br /&gt;
* &#039;&#039;Aus meinen großen Schmerzen&#039;&#039;, op. 5 Nr. 1 (Text: Heinrich Heine)&lt;br /&gt;
* &#039;&#039;Auf dem Meere&#039;&#039;, op. 5 Nr. 3 (Text: Heinrich Heine)&lt;br /&gt;
* &#039;&#039;Sterne mit den goldnen Füßchen&#039;&#039;, op. 30 Nr. 1 (Text: Heinrich Heine)&lt;br /&gt;
* &#039;&#039;Schilflieder&#039;&#039;, op. 2 (Text: Nikolaus Lenau)&lt;br /&gt;
&lt;br /&gt;
=== Bearbeitungen von Bach und Händel ===&lt;br /&gt;
&lt;br /&gt;
Neben seinen Liedern hat Franz einen – heute kaum noch bekannten, &lt;br /&gt;
aber musikhistorisch aufschlussreichen – Teil seiner Energie in die &lt;br /&gt;
Bearbeitung älterer Musik investiert. Als Leiter der Singakademie &lt;br /&gt;
musste er Werke von Bach und Händel aufführbar machen – und das &lt;br /&gt;
bedeutete im 19. Jahrhundert: eingreifen.&lt;br /&gt;
&lt;br /&gt;
Konkret tat er dreierlei:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Generalbassaussetzung:&#039;&#039;&#039; Die in Barockpartituren nur als bezifferter oder unbezifferter Bass notierten Begleitstimmen schrieb er vollständig aus – für Klavier oder Orchester.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Uminstrumentierung:&#039;&#039;&#039; Barockbesetzungen ersetzte er durch das romantische Orchester. Cembalo, Gambe, Oboe d&#039;amore – all das wurde durch zeitgenössische Instrumente ersetzt.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Ergänzung fehlender Stimmen:&#039;&#039;&#039; Wo Partituren lückenhaft überliefert waren, schrieb er fehlende Stimmen hinzu.&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis war kein historisches Bach oder Händel, sondern Bach &lt;br /&gt;
und Händel im romantischen Gewand – aufführungspraktisch für das &lt;br /&gt;
19. Jahrhundert gedacht, ästhetisch aber von Anfang an umstritten.&lt;br /&gt;
&lt;br /&gt;
Genau hier lag der Kern des späteren Streits mit Friedrich &lt;br /&gt;
Chrysander und Philipp Spitta (siehe [[#Der Bearbeitungsstreit|&lt;br /&gt;
Der Bearbeitungsstreit]]): nicht ob man den Generalbass aussetzen &lt;br /&gt;
darf, sondern &#039;&#039;wie&#039;&#039; – und ob dabei die Klangsprache des &lt;br /&gt;
19. Jahrhunderts legitim ist.&lt;br /&gt;
&lt;br /&gt;
== Der Bearbeitungsstreit ==&lt;br /&gt;
&lt;br /&gt;
Franz&#039; Ergänzungen des barocken Generalbasssatzes – also seine Ausführung der in Barockpartituren nur skizzenhaft notierten Begleitung – stießen auf scharfen Widerspruch der aufkommenden philologisch-historischen Schule. Besonders Friedrich Chrysander, Herausgeber der Händel-Gesamtausgabe, und Philipp Spitta, der maßgebliche Bach-Forscher der Zeit, kritisierten Franz&#039; Herangehensweise als zu romantisierend und zu wenig historisch korrekt.&lt;br /&gt;
&lt;br /&gt;
Franz seinerseits ließ sich das nicht gefallen. In einem [[Brief vom 1. Februar 1871 | Brief]] an seinen Freund Julius Schäffer schrieb er über Chrysander:&lt;br /&gt;
&lt;br /&gt;
: &#039;&#039;„Das ist ja ein ganz unverschämter Schlingel, der sich ernsthaft einzubilden scheint, Händel, weil er sich sonst einiges Verdienst um ihn erworben hat, ausschließlich als Domäne gepachtet zu haben.&amp;quot;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Der Streit wurde auch öffentlich geführt. Schäffer verfasste zwischen 1875 und 1880 eine Reihe von Streitschriften zur Verteidigung der Franz&#039;schen Bearbeitungen, darunter &#039;&#039;Entgegnung auf Ph. Spitta&#039;s Artikel: Über das Accompagnement in den Kompositionen Seb. Bachs&#039;&#039; und &#039;&#039;Friedr. Chrysander in seinen Klavierauszügen zur deutschen Händel-Ausgabe&#039;&#039;. Franz selbst meldete sich mit einem &#039;&#039;Offenen Brief an Eduard Hanslick&#039;&#039; und den &#039;&#039;Mitteilungen über J. S. Bachs Magnificat&#039;&#039; zu Wort.&lt;br /&gt;
&lt;br /&gt;
Auf Seiten der Franz&#039;schen Bearbeitungen standen namhafte Praktiker wie Liszt, Felix Mottl, Hans Richter und Arthur Nikisch. Die philologische Schule – Chrysander, Spitta – pochte auf Texttreue.&lt;br /&gt;
&lt;br /&gt;
Dieser Streit ist im Kern derselbe, der bis heute nicht wirklich entschieden ist: Wie viel interpretatorische Freiheit darf – oder muss – eine lebendige Aufführung alter Musik haben? Franz stand auf der Seite der musikalischen Praxis; die Gegenseite bereitete den Boden für das vor, was später als Historisch Informierte Aufführungspraxis bekannt werden sollte.&lt;br /&gt;
&lt;br /&gt;
== Warum ist Robert Franz vergessen? ==&lt;br /&gt;
&lt;br /&gt;
Das ist eine berechtigte Frage – und die Antwort ist vielschichtig:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Das Gattungsproblem:&#039;&#039;&#039; Franz schrieb fast ausschließlich Lieder. Im 20. Jahrhundert rückte das Kunstlied zunehmend an den Rand des Konzertlebens. Komponisten, die auch Symphonien, Kammermusik oder größere Vokalwerke hinterlassen haben – Brahms, Schumann, Schubert –, blieben im Repertoire präsent. Franz nicht.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Kein zyklisches Hauptwerk:&#039;&#039;&#039; Anders als Schubert mit der &#039;&#039;Winterreise&#039;&#039; oder der &#039;&#039;Schönen Müllerin&#039;&#039; hinterließ Franz keinen Liederzyklus, der als geschlossenes Abendprogramm funktioniert und vermarktbar ist.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Kein überregionales Netzwerk:&#039;&#039;&#039; Franz lebte und arbeitete sein Leben lang in Halle. Er hatte keine Schüler, die seine Tradition weitergetragen hätten, und keine Präsenz in den großen Musikzentren Wien, Leipzig oder Berlin.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Die Taubheit:&#039;&#039;&#039; 25 Jahre Isolation am Ende seines Lebens bedeuteten: kein Spätwerk, keine Weiterentwicklung, keine späten Meisterwerke wie bei Beethoven oder Schubert.&lt;br /&gt;
&lt;br /&gt;
Schumann hatte Franz übrigens bereits früh ermahnt, sich nicht auf das Lied zu beschränken. Franz blieb trotzdem bei seiner Wahl – konsequent und ohne Kompromisse.&lt;br /&gt;
&lt;br /&gt;
== Zeitgenössische Wertschätzung ==&lt;br /&gt;
&lt;br /&gt;
Dass Franz zu Lebzeiten keineswegs unbekannt war, zeigt eine Episode aus dem Jahr 1873: Als seine finanzielle Lage nach dem Verlust seiner Ämter und Bezüge prekär wurde, organisierten Franz Liszt und andere namhafte Musikerpersönlichkeiten einen Ehrenfonds, der Franz den Lebensunterhalt sicherte. Liszt hatte zudem bereits 1872 eine Monographie über Franz verfasst.&lt;br /&gt;
&lt;br /&gt;
== Weblinks und Quellen ==&lt;br /&gt;
&lt;br /&gt;
* [https://www.deutsche-biographie.de/sfz16975.html Deutsche Biographie – Robert Franz] (Allgemeine Deutsche Biographie, Band 48, 1904)&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Robert_Franz Wikipedia – Robert Franz]&lt;br /&gt;
* [https://www.musikland-sachsenanhalt.de/beitraege/franz-robert-1815-1892/ Musikland Sachsen-Anhalt – Robert Franz]&lt;br /&gt;
* [https://halle.de/kultur-tourismus/stadtgeschichte/bekannte-persoenlichkeiten/beruehmte-hallenser/details/franz-robert Berühmte Hallenser – Stadt Halle]&lt;br /&gt;
* [https://st.museum-digital.de/object/1102 Brief von Robert Franz an Julius Schäffer, 1. Februar 1871] – Stiftung Händel-Haus Halle (museum-digital Sachsen-Anhalt)&lt;br /&gt;
* [https://www.klassik-heute.com/4daction/www_komponist?id=43036&amp;amp;bio= Klassik Heute – Biographie Robert Franz]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&#039;&#039;Seite erstellt im Kontext eines Konzertprogramms mit Liedern von Robert Franz, Mai 2026.&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=264</id>
		<title>Homeserver-Sicherheitsarchitektur</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=264"/>
		<updated>2026-05-27T23:54:01Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Homeserver-Sicherheitsarchitektur: Aufbau, Funktionsweise und Diagnose */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Homeserver-Sicherheitsarchitektur: Aufbau, Funktionsweise und Diagnose ==&lt;br /&gt;
&lt;br /&gt;
Einen eigenen Server an&#039;s Internet zu bekommen, ist nicht allzu schwierig. Ein Dienst, der die eigene, vom Internet-Provider zugewiesene IP-Adresse in einen festen Domain-Namen umwandelt (siehe: [https://de.wikipedia.org/wiki/Dynamisches_DNS Dynamisches DNS]), wird im privaten Bereich die Voraussetzung sein.&lt;br /&gt;
Es gibt hier verschiedene Anbieter, oft auch kostenlose.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Beispiel:&#039;&#039;&#039; Der eigenen, von außen sichtbaren IP 78.123.234.45 wird vom DynDDS-Dienst die Domain &amp;lt;myhomeserver.dyndns.de&amp;gt; zugewiesen.&lt;br /&gt;
Einmal eingerichtet, wird der eigene Rechner antworten, wenn die Domain http://myhomeserver.dyndns.de in die Browser-Adressleiste einkopiert wird. Bei mir war damals die Freude darüber groß.&lt;br /&gt;
&lt;br /&gt;
=== Motivation für einen Server mit OPNsense, Managed Switch und Docker ===&lt;br /&gt;
&lt;br /&gt;
Die Kehrseite: Sowie der Server über&#039;s Internet erreichbar ist, ist er angreifbar.&lt;br /&gt;
Das ist kein theoretisches Szenario. Meiner Erfahrung nach ist es eine Frage von Stunden, bis die ersten Bots &amp;quot;anklopfen&amp;quot;, nach laufenden Diensten suchen, nach offenen Ports, nach Schwachstellen.&lt;br /&gt;
&lt;br /&gt;
Kurz: Eine öffentliche Erreichbarkeit des eigenen Servers über die ungesicherte Adresse...&lt;br /&gt;
&lt;br /&gt;
* http://myhomeserver.dyndns.de&lt;br /&gt;
&lt;br /&gt;
...wäre hochgradig fahrlässig.&lt;br /&gt;
&lt;br /&gt;
Aufgrund einer mangelhaften Konfiguration (offener Samba-Port) hatte ich die sehr reale Erfahrung einer russischen Hackerbande, die einige Hundert Textdateien mit Zahlungsaufforderungen und einen Verschlüsselungstrojaner auf meinem Rechner hinterlassen hatte. Gerettet hatten mich damals die Dateirechte von Linux. Das fehlende E(x)ecutional-Flag und die eingeschränkten Benutzerrechte hatten den Trojaner ausgebremst.&lt;br /&gt;
&lt;br /&gt;
Trotzdem: Nie wieder!&lt;br /&gt;
Ein wenig von dem, was ich gelernt habe, gebe ich ich hier weiter.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Einleitung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt den Aufbau einer &#039;&#039;&#039;sicheren&#039;&#039;&#039; Netzwerkarchitektur für einen Homeserver, der über das öffentliche Internet erreichbar ist. Der Beitrag richtet sich an alle, die ihre Daten selbst kontrollieren wollen — und dabei nicht unfreiwillig Teil einer globalen Angriffs-Infrastruktur werden möchten. Er will zum Verständnis beitragen, wie die einzelnen Komponenten zusammenspielen — und wie man systematisch vorgeht, wenn etwas nicht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der Fokus liegt nicht auf einer spezifischen Hardware-Konfiguration, sondern auf dem allgemeinen Prinzip: Wie kommt ein Request von außen sicher zu einem Docker-Container?&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Annahmen / Szenario ==&lt;br /&gt;
&lt;br /&gt;
Folgende Komponenten werden in diesem Artikel vorausgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver&#039;&#039;&#039; (Raspberry Pi, Intel NUC, oder beliebiger Linux-Server)&lt;br /&gt;
** Betriebssystem: Debian/Ubuntu oder vergleichbar&lt;br /&gt;
** Docker mit mehreren Diensten (z.B. WordPress, Nextcloud, MediaWiki)&lt;br /&gt;
** Caddy als Reverse Proxy (alternativ funktionieren [https://nginx.org/ nginx], [https://httpd.apache.org/ Apache], oder (ggf. kostenpflichtige) proprietäre Lösungen. Caddy allerdings hat das für mich charmante Feature, sich eigenständig um die TSL-Zertifikate und ihre Verlängerung bei LetsEncrypt zu kümmern. Wer schon einmal aufgrund &amp;quot;zu...&amp;quot; vieler unbeabsichtigter Fehlversuche während der Zertifikats-Einrichtung von LetsEncrypt auf Tage gesperrt wurde, wird mein Faible über diesen Automatismus teilen!)&lt;br /&gt;
** fail2ban als Brute-Force-Schutz&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;DynDNS-Dienst&#039;&#039;&#039; der dem Homeserver eine feste Domain zuweist&lt;br /&gt;
** Beispiel: &amp;lt;code&amp;gt;myhomeserver.dyndns.de&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Router / Heimnetz-Gateway&#039;&#039;&#039;&lt;br /&gt;
** Beispiel-IP: &amp;lt;code&amp;gt;192.168.2.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Portweiterleitung, WLAN, DynDNS-Aktualisierung&lt;br /&gt;
** Typisch: FritzBox, aber jeder Router mit Portweiterleitung funktioniert&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; (dedizierte Hardware-Firewall)&lt;br /&gt;
** WAN-Interface: &amp;lt;code&amp;gt;192.168.2.2&amp;lt;/code&amp;gt; (im Router-Netz)&lt;br /&gt;
** LAN-Interface / Server-VLAN: &amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Firewall, NAT, DHCP, IDS/IPS&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Managed Switch&#039;&#039;&#039; (optional, für VLAN-Segmentierung)&lt;br /&gt;
** Trennt Server-VLAN vom Rest des Netzes&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver-IP&#039;&#039;&#039;: &amp;lt;code&amp;gt;192.168.10.100&amp;lt;/code&amp;gt; (per DHCP-Reservation oder besser: Per statischer IP-Adresse fest)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 1: Wie funktionieren die Weiterleitungen? Wer macht was? ==&lt;br /&gt;
&lt;br /&gt;
=== Die Kette von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Ein Request von außen (z.B. Browser ruft &amp;lt;code&amp;gt;https://myhomeserver.dyndns.de&amp;lt;/code&amp;gt; auf) durchläuft folgende Stationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Internet&lt;br /&gt;
    ↓ DNS-Auflösung: dyndns.de → öffentliche IP des Heimnetzes&lt;br /&gt;
Router / Gateway (192.168.2.1)&lt;br /&gt;
    ↓ Portweiterleitung: :80 + :443 (und nur! diese!!) → 192.168.2.2&lt;br /&gt;
OPNsense WAN-Interface (192.168.2.2)&lt;br /&gt;
    ↓ Destination NAT: :80/:443 → 192.168.10.100&lt;br /&gt;
Homeserver eno1/eth0 (192.168.10.100)&lt;br /&gt;
    ↓ Docker-Port-Binding: 0.0.0.0:80 + 0.0.0.0:443&lt;br /&gt;
Caddy / Reverse Proxy (Docker-intern)&lt;br /&gt;
    ↓ Reverse Proxy anhand des Host-Headers&lt;br /&gt;
Ziel-Container (z.B. wordpress, nextcloud, ...)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit ist der Server auf der IP-Ebene (Layer 3 des OSI-Modells) von außen hin &amp;quot;unsichtbar&amp;quot;: Die Firewall (OPNsense) lebt, mit dem Gateway, im 192.168.2-er Netz. Von dort routet sie alle Anfragen über die Ports 80 und 443 an das Interface 192.168.10.100. Dahinter, also im 192.168.10-er-Subnetz, residiert der Heimserver.&lt;br /&gt;
&lt;br /&gt;
Am Ende dieses Beitrages gibt es Sicherheitshinweise. Bitte dringend beachten, dass der Router ausschließlich die Ports &#039;&#039;&#039;80/TCP&#039;&#039;&#039; und &#039;&#039;&#039;443/TCP&#039;&#039;&#039; nach außen frei gibt. Der Webserver wird dabei so konfiguriert, dass HTTP-Daten über Port 80 nach HTTPS auf Port 443 umgeleitet werden.&lt;br /&gt;
&lt;br /&gt;
Die Idee, ausschließlich HTTPS zuzulassen, läge nahe. Damit bräuchte sich der Webserver nicht um die Weiterleitung auf Port 443 zu befassen.&lt;br /&gt;
Bedauerlicherweise wird in diesem Fall der Umgang mit dem TLS-Zertifikat, das den HTTPS-Datenstrom verschlüsselt, scheitern. [https://letsencrypt.org/ LetsEncrypt] benötigt bei Einrichtung und Verlängerung seiner Zertifikate einen offenen 80-er Port.&lt;br /&gt;
&lt;br /&gt;
Sollte es nötig sein, den Server von außen zu administrieren, wird man darüber nachdenken, einen VPN-Tunnel einzurichten. Sicherer jedoch - und einfacher - ist es dennoch, die Administration ausschließlich über einen zertifikats-geschützten SSH-Zugang im inneren 192.168.-er-Netz zuzulassen und, abgesehen von 80 und 443, auf jeden nach außen exponierten Port zu verzichten.&lt;br /&gt;
&lt;br /&gt;
=== Wer macht was? ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Komponente !! Aufgabe !! Konfigurationsort&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Router / Gateway&#039;&#039;&#039; || DynDNS-Aktualisierung, erste NAT-Stufe, WLAN || Router Web-UI → Portfreigaben&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; || Firewall-Regeln, zweite NAT-Stufe (Destination NAT), DHCP für Server-VLAN || OPNsense Web-UI (Standard: https://&amp;amp;lt;wan-ip&amp;amp;gt;:443 oder :8443)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Caddy / Reverse Proxy&#039;&#039;&#039; || TLS-Terminierung, Let&#039;s Encrypt, Weiterleitung an Container || Caddyfile auf dem Homeserver&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Docker&#039;&#039;&#039; || Container-Isolation, internes Netz (Standard: 172.18.0.0/16) || docker-compose.yml pro Dienst&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fail2ban&#039;&#039;&#039; || Brute-Force-Schutz auf Applikationsebene || Jail-Configs im fail2ban-Container&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Wichtig: OPNsense hat ZWEI Firewall-Engines ===&lt;br /&gt;
&lt;br /&gt;
OPNsense 26.x hat zwei parallele Regelwerke:&lt;br /&gt;
* &#039;&#039;&#039;Rules [new]&#039;&#039;&#039; — neue API-basierte Engine&lt;br /&gt;
* &#039;&#039;&#039;Rules&#039;&#039;&#039; — alte Engine (Legacy)&lt;br /&gt;
&lt;br /&gt;
Neue Regeln &#039;&#039;&#039;immer in beiden&#039;&#039;&#039; anlegen! Bei Problemen immer beide prüfen.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 2: Wo steht was? ==&lt;br /&gt;
&lt;br /&gt;
=== IP-Adressen (Beispiel-Setup) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Gerät !! Interface !! IP !! Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
| Router / Gateway || — || 192.168.2.1 || Gateway, WLAN, DynDNS&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense WAN || wan-interface || 192.168.2.2 || Statisch konfiguriert&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense LAN / Server-VLAN || lan-interface || 192.168.10.1 || Gateway für Server-Netz&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver || eno1 / eth0 || 192.168.10.100 || Fest per DHCP-Reservation (MAC-Adresse)&lt;br /&gt;
|-&lt;br /&gt;
| Client-Geräte || WLAN || 192.168.2.x || Im Router-Netz, nicht im Server-VLAN&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Homeserver: Netzwerk-Interface-Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Der Homeserver bezieht seine IP per DHCP vom OPNsense-DHCP-Server. Bei Debian/Ubuntu mit systemd-networkd:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/systemd/network/10-eth0.network&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Korrekter Inhalt (DHCP):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[Match]&lt;br /&gt;
Name=eno1&lt;br /&gt;
&lt;br /&gt;
[Network]&lt;br /&gt;
DHCP=ipv4&lt;br /&gt;
&lt;br /&gt;
[DHCP]&lt;br /&gt;
RouteMetric=100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ &#039;&#039;&#039;Niemals&#039;&#039;&#039; eine statische IP oder einen Gateway manuell eintragen!&lt;br /&gt;
Der Default-Gateway kommt immer vom DHCP-Server der OPNsense-Firewall (&amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Kea DHCP Lease-Datei (OPNsense) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/db/kea/kea-leases4.csv&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier verwaltet Kea die aktiven Leases. Bei Problemen mit doppelten IPs kann diese Datei (nach &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;) auf den Header reduziert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context,pool_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 3: Systematische Diagnose — Schritt für Schritt ==&lt;br /&gt;
&lt;br /&gt;
=== Grundprinzip: Von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Immer von außen nach innen vorgehen — nie raten, immer messen. Jede Schicht einzeln prüfen.&lt;br /&gt;
&lt;br /&gt;
==== Schritt 1: Ist OPNsense überhaupt erreichbar? ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Vom Client-Rechner:&lt;br /&gt;
ping 192.168.2.2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ OPNsense antwortet standardmäßig &#039;&#039;&#039;nicht&#039;&#039;&#039; auf ICMP/Ping von außen — das ist korrekt!&lt;br /&gt;
&lt;br /&gt;
Stattdessen prüfen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Web-UI erreichbar?&lt;br /&gt;
https://192.168.2.2:8443&lt;br /&gt;
&lt;br /&gt;
# Router zeigt OPNsense als verbundenes Gerät?&lt;br /&gt;
http://192.168.2.1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 2: OPNsense intern prüfen ====&lt;br /&gt;
&lt;br /&gt;
Per SSH oder serieller Konsole auf OPNsense:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# WAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;wan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.2.2, status: active&lt;br /&gt;
&lt;br /&gt;
# LAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;lan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.10.1, status: active&lt;br /&gt;
&lt;br /&gt;
# Router erreichbar?&lt;br /&gt;
ping -c 3 192.168.2.1&lt;br /&gt;
&lt;br /&gt;
# Homeserver erreichbar?&lt;br /&gt;
ping -c 3 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 3: Homeserver direkt prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# SSH auf Homeserver:&lt;br /&gt;
ssh root@192.168.10.100&lt;br /&gt;
&lt;br /&gt;
# Alle Container laufen?&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# Internet vom Homeserver aus erreichbar?&lt;br /&gt;
ping -c 3 9.9.9.9&lt;br /&gt;
&lt;br /&gt;
# Routing-Tabelle korrekt?&lt;br /&gt;
ip route show&lt;br /&gt;
# Erwartete Default-Route: default via 192.168.10.1 dev eno1&lt;br /&gt;
# NICHT: default via 192.168.178.x — das wäre falsch!&lt;br /&gt;
&lt;br /&gt;
# Welche IP hat das Interface?&lt;br /&gt;
ip addr show eno1&lt;br /&gt;
# Erwartete IP: 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 4: Caddy / Reverse Proxy prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Läuft Caddy und antwortet er lokal?&lt;br /&gt;
curl -v http://localhost&lt;br /&gt;
# Erwartete Antwort: HTTP 308 Redirect → https://localhost/&lt;br /&gt;
&lt;br /&gt;
# Caddy-Logs auf Fehler prüfen:&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Typische Fehler in den Caddy-Logs:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fehlermeldung !! Bedeutung !! Lösung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dial tcp ...:443: connect: no route to host&amp;lt;/code&amp;gt; || Caddy kommt nicht ins Internet (Let&#039;s Encrypt nicht erreichbar) || Routing auf Homeserver prüfen (Schritt 3)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;no route to host&amp;lt;/code&amp;gt; bei Ping auf 9.9.9.9 || Falscher Default-Gateway || &amp;lt;code&amp;gt;ip route show&amp;lt;/code&amp;gt; prüfen, falsche Route entfernen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Schritt 5: NAT und Firewall-Regeln prüfen (OPNsense Shell) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# NAT-Regeln anzeigen:&lt;br /&gt;
pfctl -s nat | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Firewall-Regeln anzeigen:&lt;br /&gt;
pfctl -s rules | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf WAN-Interface beobachten (kommt der Request an?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;wan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf LAN-Interface beobachten (wird er weitergeleitet?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;lan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Diagnose-Logik:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tcpdump WAN sieht Traffic, LAN nicht → NAT-Regel prüfen!&lt;br /&gt;
tcpdump WAN sieht keinen Traffic    → Portweiterleitung im Router prüfen!&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 6: Bekannte Fallstricke ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Problem !! Symptom !! Ursache !! Fix&lt;br /&gt;
|-&lt;br /&gt;
| Falsche statische Route || &amp;lt;code&amp;gt;ping 9.9.9.9&amp;lt;/code&amp;gt; schlägt fehl || Netzwerk-Config hat statischen Gateway eingetragen || Auf DHCP umstellen, &amp;lt;code&amp;gt;systemctl restart systemd-networkd&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver hat falsche IP || NAT-Regeln greifen nicht || DHCP hat beim Neustart temporär andere IP vergeben || DHCP-Reservation per MAC-Adresse einrichten&lt;br /&gt;
|-&lt;br /&gt;
| DHCP-Leases durcheinander || Server taucht mit zwei IPs auf || Neustart hat neuen Lease vor Ablauf des alten erzeugt || &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;, Lease-CSV bereinigen, &amp;lt;code&amp;gt;configctl kea start&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense Firewall-Regel fehlt || Dienste von außen nicht erreichbar, intern OK || Regel nur in einer der beiden Engines angelegt || Regel in &#039;&#039;&#039;beiden&#039;&#039;&#039; Engines anlegen (Rules [new] + Rules)&lt;br /&gt;
|-&lt;br /&gt;
| NAT-Regel ohne Subnetz-Maske || Traffic kommt nicht an || &amp;lt;code&amp;gt;192.168.178.0&amp;lt;/code&amp;gt; statt &amp;lt;code&amp;gt;192.168.178.0/24&amp;lt;/code&amp;gt; eingetragen || Subnetz-Maske ergänzen — ohne /24 gilt nur die Netzadresse selbst!&lt;br /&gt;
|-&lt;br /&gt;
| Source/Destination Port vertauscht || Verbindungen werden blockiert || Bei Firewall-Regel Port unter &amp;quot;Source&amp;quot; statt &amp;quot;Destination&amp;quot; eingetragen || Source Port: any / Destination Port: gewünschter Port&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Notfall-Cheatsheet ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# OPNsense: Firewall temporär deaktivieren (Notfall!)&lt;br /&gt;
pfctl -d&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Firewall wieder aktivieren&lt;br /&gt;
pfctl -e&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Kea DHCP stoppen/starten&lt;br /&gt;
configctl kea stop&lt;br /&gt;
configctl kea start&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Falsche Default-Route entfernen&lt;br /&gt;
ip route del default via &amp;amp;lt;falsche-gateway-ip&amp;amp;gt; dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: IP manuell setzen (Sofortlösung bei DHCP-Problemen)&lt;br /&gt;
ip addr add 192.168.10.100/24 dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Netzwerk-Dienst neu starten (Verbindung kurz weg!)&lt;br /&gt;
systemctl restart systemd-networkd&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Docker-Logs prüfen&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Alias-Tabellen prüfen (Blocklisten)&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | wc -l&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | grep &amp;amp;lt;IP&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Sicherheitshinweise ==&lt;br /&gt;
&lt;br /&gt;
* SSH-Ports &#039;&#039;&#039;nicht&#039;&#039;&#039; über das Internet freigeben — nur intern erreichbar lassen! Sollte das keine Option sein: VPN-Tunnel!&lt;br /&gt;
* Portweiterleitung im Router auf das &#039;&#039;&#039;Minimum&#039;&#039;&#039; beschränken (nur die Ports 80 + 443 öffnen).&lt;br /&gt;
* Für interne Admin-Interfaces (OPNsense Web-UI, Monitoring) &#039;&#039;&#039;keine(!) externen Freigaben!&#039;&#039;&#039;&lt;br /&gt;
* DHCP-Reservations per MAC-Adresse oder statische IP-Adressen verhindern IP-Wechsel nach Neustarts.&lt;br /&gt;
* Bei Firewall-Regeln: Block-Regeln &#039;&#039;&#039;immer&#039;&#039;&#039; vor Pass-Regeln platzieren.&lt;br /&gt;
&lt;br /&gt;
Abschließend eine absolute Regel, die immer und durch die Ewigkeiten gilt:&lt;br /&gt;
* Dienste, die auf einem Rechner &#039;&#039;&#039;NICHT&#039;&#039;&#039; existieren, werden niemals angegriffen! Wenig ist hier mehr!&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Dieser Artikel basiert auf praktischen Erfahrungen aus dem Betrieb eines selbst gehosteten Servers mit OPNsense, Cisco-Switch und Docker-Stack.&#039;&#039;&lt;br /&gt;
&#039;&#039;Erstellt: Mai 2026&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=263</id>
		<title>Homeserver-Sicherheitsarchitektur</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=263"/>
		<updated>2026-05-27T23:51:30Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Sicherheitshinweise */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Homeserver-Sicherheitsarchitektur: Aufbau, Funktionsweise und Diagnose ==&lt;br /&gt;
&lt;br /&gt;
Einen eigenen Server an&#039;s Internet zu bekommen, ist nicht allzu schwierig. Ein Dienst, der die eigene, vom Internet-Provider zugewiesene IP-Adresse in einen festen Domain-Namen umwandelt (siehe: [https://de.wikipedia.org/wiki/Dynamisches_DNS Dynamisches DNS]), wird im privaten Bereich die Voraussetzung sein.&lt;br /&gt;
Es gibt verschiedene Anbieter, oft auch kostenlose.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Der eigenen, von außen sichtbaren IP 78.123.234.45 wird vom DynDDS-Dienst die Domain &amp;lt;myhomeserver.dyndns.de&amp;gt; zugewiesen.&lt;br /&gt;
Einmal eingerichtet, wird der eigene Rechner antworten, wenn die Domain http://myhomeserver.dyndns.de in die Browser-Adressleiste einkopiert wird.&lt;br /&gt;
&lt;br /&gt;
=== Motivation für einen Server mit OPNsense, Managed Switch und Docker ===&lt;br /&gt;
&lt;br /&gt;
Die Kehrseite: Sowie der Server über&#039;s Internet erreichbar ist, ist er angreifbar.&lt;br /&gt;
Das ist kein theoretisches Szenario. Meiner Erfahrung nach ist es eine Frage von Stunden, bis die ersten Bots &amp;quot;anklopfen&amp;quot;, nach laufenden Diensten suchen, nach offenen Ports, nach Schwachstellen.&lt;br /&gt;
&lt;br /&gt;
Kurz: Eine öffentliche Erreichbarkeit des eigenen Servers über die ungesicherte Adresse...&lt;br /&gt;
&lt;br /&gt;
* http://myhomeserver.dyndns.de&lt;br /&gt;
&lt;br /&gt;
...wäre hochgradig fahrlässig.&lt;br /&gt;
&lt;br /&gt;
Aufgrund einer mangelhaften Konfiguration (offener Samba-Port) hatte ich die sehr reale Erfahrung einer russischen Hackerbande, die einige Hundert Textdateien mit Zahlungsaufforderungen und einen Verschlüsselungstrojaner auf meinem Rechner hinterlassen hatte. Gerettet hatten mich damals die Dateirechte von Linux. Das fehlende E(x)ecutional-Flag und die eingeschränkten Benutzerrechte hatten den Trojaner ausgebremst.&lt;br /&gt;
&lt;br /&gt;
Trotzdem: Nie wieder!&lt;br /&gt;
Ein wenig von dem, was ich gelernt habe, gebe ich ich hier weiter.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Einleitung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt den Aufbau einer &#039;&#039;&#039;sicheren&#039;&#039;&#039; Netzwerkarchitektur für einen Homeserver, der über das öffentliche Internet erreichbar ist. Der Beitrag richtet sich an alle, die ihre Daten selbst kontrollieren wollen — und dabei nicht unfreiwillig Teil einer globalen Angriffs-Infrastruktur werden möchten. Er will zum Verständnis beitragen, wie die einzelnen Komponenten zusammenspielen — und wie man systematisch vorgeht, wenn etwas nicht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der Fokus liegt nicht auf einer spezifischen Hardware-Konfiguration, sondern auf dem allgemeinen Prinzip: Wie kommt ein Request von außen sicher zu einem Docker-Container?&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Annahmen / Szenario ==&lt;br /&gt;
&lt;br /&gt;
Folgende Komponenten werden in diesem Artikel vorausgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver&#039;&#039;&#039; (Raspberry Pi, Intel NUC, oder beliebiger Linux-Server)&lt;br /&gt;
** Betriebssystem: Debian/Ubuntu oder vergleichbar&lt;br /&gt;
** Docker mit mehreren Diensten (z.B. WordPress, Nextcloud, MediaWiki)&lt;br /&gt;
** Caddy als Reverse Proxy (alternativ funktionieren [https://nginx.org/ nginx], [https://httpd.apache.org/ Apache], oder (ggf. kostenpflichtige) proprietäre Lösungen. Caddy allerdings hat das für mich charmante Feature, sich eigenständig um die TSL-Zertifikate und ihre Verlängerung bei LetsEncrypt zu kümmern. Wer schon einmal aufgrund &amp;quot;zu...&amp;quot; vieler unbeabsichtigter Fehlversuche während der Zertifikats-Einrichtung von LetsEncrypt auf Tage gesperrt wurde, wird mein Faible über diesen Automatismus teilen!)&lt;br /&gt;
** fail2ban als Brute-Force-Schutz&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;DynDNS-Dienst&#039;&#039;&#039; der dem Homeserver eine feste Domain zuweist&lt;br /&gt;
** Beispiel: &amp;lt;code&amp;gt;myhomeserver.dyndns.de&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Router / Heimnetz-Gateway&#039;&#039;&#039;&lt;br /&gt;
** Beispiel-IP: &amp;lt;code&amp;gt;192.168.2.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Portweiterleitung, WLAN, DynDNS-Aktualisierung&lt;br /&gt;
** Typisch: FritzBox, aber jeder Router mit Portweiterleitung funktioniert&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; (dedizierte Hardware-Firewall)&lt;br /&gt;
** WAN-Interface: &amp;lt;code&amp;gt;192.168.2.2&amp;lt;/code&amp;gt; (im Router-Netz)&lt;br /&gt;
** LAN-Interface / Server-VLAN: &amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Firewall, NAT, DHCP, IDS/IPS&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Managed Switch&#039;&#039;&#039; (optional, für VLAN-Segmentierung)&lt;br /&gt;
** Trennt Server-VLAN vom Rest des Netzes&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver-IP&#039;&#039;&#039;: &amp;lt;code&amp;gt;192.168.10.100&amp;lt;/code&amp;gt; (per DHCP-Reservation oder besser: Per statischer IP-Adresse fest)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 1: Wie funktionieren die Weiterleitungen? Wer macht was? ==&lt;br /&gt;
&lt;br /&gt;
=== Die Kette von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Ein Request von außen (z.B. Browser ruft &amp;lt;code&amp;gt;https://myhomeserver.dyndns.de&amp;lt;/code&amp;gt; auf) durchläuft folgende Stationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Internet&lt;br /&gt;
    ↓ DNS-Auflösung: dyndns.de → öffentliche IP des Heimnetzes&lt;br /&gt;
Router / Gateway (192.168.2.1)&lt;br /&gt;
    ↓ Portweiterleitung: :80 + :443 (und nur! diese!!) → 192.168.2.2&lt;br /&gt;
OPNsense WAN-Interface (192.168.2.2)&lt;br /&gt;
    ↓ Destination NAT: :80/:443 → 192.168.10.100&lt;br /&gt;
Homeserver eno1/eth0 (192.168.10.100)&lt;br /&gt;
    ↓ Docker-Port-Binding: 0.0.0.0:80 + 0.0.0.0:443&lt;br /&gt;
Caddy / Reverse Proxy (Docker-intern)&lt;br /&gt;
    ↓ Reverse Proxy anhand des Host-Headers&lt;br /&gt;
Ziel-Container (z.B. wordpress, nextcloud, ...)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit ist der Server auf der IP-Ebene (Layer 3 des OSI-Modells) von außen hin &amp;quot;unsichtbar&amp;quot;: Die Firewall (OPNsense) lebt, mit dem Gateway, im 192.168.2-er Netz. Von dort routet sie alle Anfragen über die Ports 80 und 443 an das Interface 192.168.10.100. Dahinter, also im 192.168.10-er-Subnetz, residiert der Heimserver.&lt;br /&gt;
&lt;br /&gt;
Am Ende dieses Beitrages gibt es Sicherheitshinweise. Bitte dringend beachten, dass der Router ausschließlich die Ports &#039;&#039;&#039;80/TCP&#039;&#039;&#039; und &#039;&#039;&#039;443/TCP&#039;&#039;&#039; nach außen frei gibt. Der Webserver wird dabei so konfiguriert, dass HTTP-Daten über Port 80 nach HTTPS auf Port 443 umgeleitet werden.&lt;br /&gt;
&lt;br /&gt;
Die Idee, ausschließlich HTTPS zuzulassen, läge nahe. Damit bräuchte sich der Webserver nicht um die Weiterleitung auf Port 443 zu befassen.&lt;br /&gt;
Bedauerlicherweise wird in diesem Fall der Umgang mit dem TLS-Zertifikat, das den HTTPS-Datenstrom verschlüsselt, scheitern. [https://letsencrypt.org/ LetsEncrypt] benötigt bei Einrichtung und Verlängerung seiner Zertifikate einen offenen 80-er Port.&lt;br /&gt;
&lt;br /&gt;
Sollte es nötig sein, den Server von außen zu administrieren, wird man darüber nachdenken, einen VPN-Tunnel einzurichten. Sicherer jedoch - und einfacher - ist es dennoch, die Administration ausschließlich über einen zertifikats-geschützten SSH-Zugang im inneren 192.168.-er-Netz zuzulassen und, abgesehen von 80 und 443, auf jeden nach außen exponierten Port zu verzichten.&lt;br /&gt;
&lt;br /&gt;
=== Wer macht was? ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Komponente !! Aufgabe !! Konfigurationsort&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Router / Gateway&#039;&#039;&#039; || DynDNS-Aktualisierung, erste NAT-Stufe, WLAN || Router Web-UI → Portfreigaben&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; || Firewall-Regeln, zweite NAT-Stufe (Destination NAT), DHCP für Server-VLAN || OPNsense Web-UI (Standard: https://&amp;amp;lt;wan-ip&amp;amp;gt;:443 oder :8443)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Caddy / Reverse Proxy&#039;&#039;&#039; || TLS-Terminierung, Let&#039;s Encrypt, Weiterleitung an Container || Caddyfile auf dem Homeserver&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Docker&#039;&#039;&#039; || Container-Isolation, internes Netz (Standard: 172.18.0.0/16) || docker-compose.yml pro Dienst&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fail2ban&#039;&#039;&#039; || Brute-Force-Schutz auf Applikationsebene || Jail-Configs im fail2ban-Container&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Wichtig: OPNsense hat ZWEI Firewall-Engines ===&lt;br /&gt;
&lt;br /&gt;
OPNsense 26.x hat zwei parallele Regelwerke:&lt;br /&gt;
* &#039;&#039;&#039;Rules [new]&#039;&#039;&#039; — neue API-basierte Engine&lt;br /&gt;
* &#039;&#039;&#039;Rules&#039;&#039;&#039; — alte Engine (Legacy)&lt;br /&gt;
&lt;br /&gt;
Neue Regeln &#039;&#039;&#039;immer in beiden&#039;&#039;&#039; anlegen! Bei Problemen immer beide prüfen.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 2: Wo steht was? ==&lt;br /&gt;
&lt;br /&gt;
=== IP-Adressen (Beispiel-Setup) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Gerät !! Interface !! IP !! Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
| Router / Gateway || — || 192.168.2.1 || Gateway, WLAN, DynDNS&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense WAN || wan-interface || 192.168.2.2 || Statisch konfiguriert&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense LAN / Server-VLAN || lan-interface || 192.168.10.1 || Gateway für Server-Netz&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver || eno1 / eth0 || 192.168.10.100 || Fest per DHCP-Reservation (MAC-Adresse)&lt;br /&gt;
|-&lt;br /&gt;
| Client-Geräte || WLAN || 192.168.2.x || Im Router-Netz, nicht im Server-VLAN&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Homeserver: Netzwerk-Interface-Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Der Homeserver bezieht seine IP per DHCP vom OPNsense-DHCP-Server. Bei Debian/Ubuntu mit systemd-networkd:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/systemd/network/10-eth0.network&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Korrekter Inhalt (DHCP):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[Match]&lt;br /&gt;
Name=eno1&lt;br /&gt;
&lt;br /&gt;
[Network]&lt;br /&gt;
DHCP=ipv4&lt;br /&gt;
&lt;br /&gt;
[DHCP]&lt;br /&gt;
RouteMetric=100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ &#039;&#039;&#039;Niemals&#039;&#039;&#039; eine statische IP oder einen Gateway manuell eintragen!&lt;br /&gt;
Der Default-Gateway kommt immer vom DHCP-Server der OPNsense-Firewall (&amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Kea DHCP Lease-Datei (OPNsense) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/db/kea/kea-leases4.csv&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier verwaltet Kea die aktiven Leases. Bei Problemen mit doppelten IPs kann diese Datei (nach &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;) auf den Header reduziert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context,pool_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 3: Systematische Diagnose — Schritt für Schritt ==&lt;br /&gt;
&lt;br /&gt;
=== Grundprinzip: Von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Immer von außen nach innen vorgehen — nie raten, immer messen. Jede Schicht einzeln prüfen.&lt;br /&gt;
&lt;br /&gt;
==== Schritt 1: Ist OPNsense überhaupt erreichbar? ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Vom Client-Rechner:&lt;br /&gt;
ping 192.168.2.2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ OPNsense antwortet standardmäßig &#039;&#039;&#039;nicht&#039;&#039;&#039; auf ICMP/Ping von außen — das ist korrekt!&lt;br /&gt;
&lt;br /&gt;
Stattdessen prüfen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Web-UI erreichbar?&lt;br /&gt;
https://192.168.2.2:8443&lt;br /&gt;
&lt;br /&gt;
# Router zeigt OPNsense als verbundenes Gerät?&lt;br /&gt;
http://192.168.2.1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 2: OPNsense intern prüfen ====&lt;br /&gt;
&lt;br /&gt;
Per SSH oder serieller Konsole auf OPNsense:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# WAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;wan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.2.2, status: active&lt;br /&gt;
&lt;br /&gt;
# LAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;lan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.10.1, status: active&lt;br /&gt;
&lt;br /&gt;
# Router erreichbar?&lt;br /&gt;
ping -c 3 192.168.2.1&lt;br /&gt;
&lt;br /&gt;
# Homeserver erreichbar?&lt;br /&gt;
ping -c 3 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 3: Homeserver direkt prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# SSH auf Homeserver:&lt;br /&gt;
ssh root@192.168.10.100&lt;br /&gt;
&lt;br /&gt;
# Alle Container laufen?&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# Internet vom Homeserver aus erreichbar?&lt;br /&gt;
ping -c 3 9.9.9.9&lt;br /&gt;
&lt;br /&gt;
# Routing-Tabelle korrekt?&lt;br /&gt;
ip route show&lt;br /&gt;
# Erwartete Default-Route: default via 192.168.10.1 dev eno1&lt;br /&gt;
# NICHT: default via 192.168.178.x — das wäre falsch!&lt;br /&gt;
&lt;br /&gt;
# Welche IP hat das Interface?&lt;br /&gt;
ip addr show eno1&lt;br /&gt;
# Erwartete IP: 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 4: Caddy / Reverse Proxy prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Läuft Caddy und antwortet er lokal?&lt;br /&gt;
curl -v http://localhost&lt;br /&gt;
# Erwartete Antwort: HTTP 308 Redirect → https://localhost/&lt;br /&gt;
&lt;br /&gt;
# Caddy-Logs auf Fehler prüfen:&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Typische Fehler in den Caddy-Logs:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fehlermeldung !! Bedeutung !! Lösung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dial tcp ...:443: connect: no route to host&amp;lt;/code&amp;gt; || Caddy kommt nicht ins Internet (Let&#039;s Encrypt nicht erreichbar) || Routing auf Homeserver prüfen (Schritt 3)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;no route to host&amp;lt;/code&amp;gt; bei Ping auf 9.9.9.9 || Falscher Default-Gateway || &amp;lt;code&amp;gt;ip route show&amp;lt;/code&amp;gt; prüfen, falsche Route entfernen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Schritt 5: NAT und Firewall-Regeln prüfen (OPNsense Shell) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# NAT-Regeln anzeigen:&lt;br /&gt;
pfctl -s nat | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Firewall-Regeln anzeigen:&lt;br /&gt;
pfctl -s rules | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf WAN-Interface beobachten (kommt der Request an?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;wan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf LAN-Interface beobachten (wird er weitergeleitet?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;lan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Diagnose-Logik:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tcpdump WAN sieht Traffic, LAN nicht → NAT-Regel prüfen!&lt;br /&gt;
tcpdump WAN sieht keinen Traffic    → Portweiterleitung im Router prüfen!&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 6: Bekannte Fallstricke ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Problem !! Symptom !! Ursache !! Fix&lt;br /&gt;
|-&lt;br /&gt;
| Falsche statische Route || &amp;lt;code&amp;gt;ping 9.9.9.9&amp;lt;/code&amp;gt; schlägt fehl || Netzwerk-Config hat statischen Gateway eingetragen || Auf DHCP umstellen, &amp;lt;code&amp;gt;systemctl restart systemd-networkd&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver hat falsche IP || NAT-Regeln greifen nicht || DHCP hat beim Neustart temporär andere IP vergeben || DHCP-Reservation per MAC-Adresse einrichten&lt;br /&gt;
|-&lt;br /&gt;
| DHCP-Leases durcheinander || Server taucht mit zwei IPs auf || Neustart hat neuen Lease vor Ablauf des alten erzeugt || &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;, Lease-CSV bereinigen, &amp;lt;code&amp;gt;configctl kea start&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense Firewall-Regel fehlt || Dienste von außen nicht erreichbar, intern OK || Regel nur in einer der beiden Engines angelegt || Regel in &#039;&#039;&#039;beiden&#039;&#039;&#039; Engines anlegen (Rules [new] + Rules)&lt;br /&gt;
|-&lt;br /&gt;
| NAT-Regel ohne Subnetz-Maske || Traffic kommt nicht an || &amp;lt;code&amp;gt;192.168.178.0&amp;lt;/code&amp;gt; statt &amp;lt;code&amp;gt;192.168.178.0/24&amp;lt;/code&amp;gt; eingetragen || Subnetz-Maske ergänzen — ohne /24 gilt nur die Netzadresse selbst!&lt;br /&gt;
|-&lt;br /&gt;
| Source/Destination Port vertauscht || Verbindungen werden blockiert || Bei Firewall-Regel Port unter &amp;quot;Source&amp;quot; statt &amp;quot;Destination&amp;quot; eingetragen || Source Port: any / Destination Port: gewünschter Port&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Notfall-Cheatsheet ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# OPNsense: Firewall temporär deaktivieren (Notfall!)&lt;br /&gt;
pfctl -d&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Firewall wieder aktivieren&lt;br /&gt;
pfctl -e&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Kea DHCP stoppen/starten&lt;br /&gt;
configctl kea stop&lt;br /&gt;
configctl kea start&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Falsche Default-Route entfernen&lt;br /&gt;
ip route del default via &amp;amp;lt;falsche-gateway-ip&amp;amp;gt; dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: IP manuell setzen (Sofortlösung bei DHCP-Problemen)&lt;br /&gt;
ip addr add 192.168.10.100/24 dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Netzwerk-Dienst neu starten (Verbindung kurz weg!)&lt;br /&gt;
systemctl restart systemd-networkd&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Docker-Logs prüfen&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Alias-Tabellen prüfen (Blocklisten)&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | wc -l&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | grep &amp;amp;lt;IP&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Sicherheitshinweise ==&lt;br /&gt;
&lt;br /&gt;
* SSH-Ports &#039;&#039;&#039;nicht&#039;&#039;&#039; über das Internet freigeben — nur intern erreichbar lassen! Sollte das keine Option sein: VPN-Tunnel!&lt;br /&gt;
* Portweiterleitung im Router auf das &#039;&#039;&#039;Minimum&#039;&#039;&#039; beschränken (nur die Ports 80 + 443 öffnen).&lt;br /&gt;
* Für interne Admin-Interfaces (OPNsense Web-UI, Monitoring) &#039;&#039;&#039;keine(!) externen Freigaben!&#039;&#039;&#039;&lt;br /&gt;
* DHCP-Reservations per MAC-Adresse oder statische IP-Adressen verhindern IP-Wechsel nach Neustarts.&lt;br /&gt;
* Bei Firewall-Regeln: Block-Regeln &#039;&#039;&#039;immer&#039;&#039;&#039; vor Pass-Regeln platzieren.&lt;br /&gt;
&lt;br /&gt;
Abschließend eine absolute Regel, die immer und durch die Ewigkeiten gilt:&lt;br /&gt;
* Dienste, die auf einem Rechner &#039;&#039;&#039;NICHT&#039;&#039;&#039; existieren, werden niemals angegriffen! Wenig ist hier mehr!&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Dieser Artikel basiert auf praktischen Erfahrungen aus dem Betrieb eines selbst gehosteten Servers mit OPNsense, Cisco-Switch und Docker-Stack.&#039;&#039;&lt;br /&gt;
&#039;&#039;Erstellt: Mai 2026&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=262</id>
		<title>Homeserver-Sicherheitsarchitektur</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=262"/>
		<updated>2026-05-27T23:50:55Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Sicherheitshinweise */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Homeserver-Sicherheitsarchitektur: Aufbau, Funktionsweise und Diagnose ==&lt;br /&gt;
&lt;br /&gt;
Einen eigenen Server an&#039;s Internet zu bekommen, ist nicht allzu schwierig. Ein Dienst, der die eigene, vom Internet-Provider zugewiesene IP-Adresse in einen festen Domain-Namen umwandelt (siehe: [https://de.wikipedia.org/wiki/Dynamisches_DNS Dynamisches DNS]), wird im privaten Bereich die Voraussetzung sein.&lt;br /&gt;
Es gibt verschiedene Anbieter, oft auch kostenlose.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Der eigenen, von außen sichtbaren IP 78.123.234.45 wird vom DynDDS-Dienst die Domain &amp;lt;myhomeserver.dyndns.de&amp;gt; zugewiesen.&lt;br /&gt;
Einmal eingerichtet, wird der eigene Rechner antworten, wenn die Domain http://myhomeserver.dyndns.de in die Browser-Adressleiste einkopiert wird.&lt;br /&gt;
&lt;br /&gt;
=== Motivation für einen Server mit OPNsense, Managed Switch und Docker ===&lt;br /&gt;
&lt;br /&gt;
Die Kehrseite: Sowie der Server über&#039;s Internet erreichbar ist, ist er angreifbar.&lt;br /&gt;
Das ist kein theoretisches Szenario. Meiner Erfahrung nach ist es eine Frage von Stunden, bis die ersten Bots &amp;quot;anklopfen&amp;quot;, nach laufenden Diensten suchen, nach offenen Ports, nach Schwachstellen.&lt;br /&gt;
&lt;br /&gt;
Kurz: Eine öffentliche Erreichbarkeit des eigenen Servers über die ungesicherte Adresse...&lt;br /&gt;
&lt;br /&gt;
* http://myhomeserver.dyndns.de&lt;br /&gt;
&lt;br /&gt;
...wäre hochgradig fahrlässig.&lt;br /&gt;
&lt;br /&gt;
Aufgrund einer mangelhaften Konfiguration (offener Samba-Port) hatte ich die sehr reale Erfahrung einer russischen Hackerbande, die einige Hundert Textdateien mit Zahlungsaufforderungen und einen Verschlüsselungstrojaner auf meinem Rechner hinterlassen hatte. Gerettet hatten mich damals die Dateirechte von Linux. Das fehlende E(x)ecutional-Flag und die eingeschränkten Benutzerrechte hatten den Trojaner ausgebremst.&lt;br /&gt;
&lt;br /&gt;
Trotzdem: Nie wieder!&lt;br /&gt;
Ein wenig von dem, was ich gelernt habe, gebe ich ich hier weiter.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Einleitung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt den Aufbau einer &#039;&#039;&#039;sicheren&#039;&#039;&#039; Netzwerkarchitektur für einen Homeserver, der über das öffentliche Internet erreichbar ist. Der Beitrag richtet sich an alle, die ihre Daten selbst kontrollieren wollen — und dabei nicht unfreiwillig Teil einer globalen Angriffs-Infrastruktur werden möchten. Er will zum Verständnis beitragen, wie die einzelnen Komponenten zusammenspielen — und wie man systematisch vorgeht, wenn etwas nicht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der Fokus liegt nicht auf einer spezifischen Hardware-Konfiguration, sondern auf dem allgemeinen Prinzip: Wie kommt ein Request von außen sicher zu einem Docker-Container?&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Annahmen / Szenario ==&lt;br /&gt;
&lt;br /&gt;
Folgende Komponenten werden in diesem Artikel vorausgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver&#039;&#039;&#039; (Raspberry Pi, Intel NUC, oder beliebiger Linux-Server)&lt;br /&gt;
** Betriebssystem: Debian/Ubuntu oder vergleichbar&lt;br /&gt;
** Docker mit mehreren Diensten (z.B. WordPress, Nextcloud, MediaWiki)&lt;br /&gt;
** Caddy als Reverse Proxy (alternativ funktionieren [https://nginx.org/ nginx], [https://httpd.apache.org/ Apache], oder (ggf. kostenpflichtige) proprietäre Lösungen. Caddy allerdings hat das für mich charmante Feature, sich eigenständig um die TSL-Zertifikate und ihre Verlängerung bei LetsEncrypt zu kümmern. Wer schon einmal aufgrund &amp;quot;zu...&amp;quot; vieler unbeabsichtigter Fehlversuche während der Zertifikats-Einrichtung von LetsEncrypt auf Tage gesperrt wurde, wird mein Faible über diesen Automatismus teilen!)&lt;br /&gt;
** fail2ban als Brute-Force-Schutz&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;DynDNS-Dienst&#039;&#039;&#039; der dem Homeserver eine feste Domain zuweist&lt;br /&gt;
** Beispiel: &amp;lt;code&amp;gt;myhomeserver.dyndns.de&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Router / Heimnetz-Gateway&#039;&#039;&#039;&lt;br /&gt;
** Beispiel-IP: &amp;lt;code&amp;gt;192.168.2.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Portweiterleitung, WLAN, DynDNS-Aktualisierung&lt;br /&gt;
** Typisch: FritzBox, aber jeder Router mit Portweiterleitung funktioniert&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; (dedizierte Hardware-Firewall)&lt;br /&gt;
** WAN-Interface: &amp;lt;code&amp;gt;192.168.2.2&amp;lt;/code&amp;gt; (im Router-Netz)&lt;br /&gt;
** LAN-Interface / Server-VLAN: &amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Firewall, NAT, DHCP, IDS/IPS&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Managed Switch&#039;&#039;&#039; (optional, für VLAN-Segmentierung)&lt;br /&gt;
** Trennt Server-VLAN vom Rest des Netzes&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver-IP&#039;&#039;&#039;: &amp;lt;code&amp;gt;192.168.10.100&amp;lt;/code&amp;gt; (per DHCP-Reservation oder besser: Per statischer IP-Adresse fest)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 1: Wie funktionieren die Weiterleitungen? Wer macht was? ==&lt;br /&gt;
&lt;br /&gt;
=== Die Kette von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Ein Request von außen (z.B. Browser ruft &amp;lt;code&amp;gt;https://myhomeserver.dyndns.de&amp;lt;/code&amp;gt; auf) durchläuft folgende Stationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Internet&lt;br /&gt;
    ↓ DNS-Auflösung: dyndns.de → öffentliche IP des Heimnetzes&lt;br /&gt;
Router / Gateway (192.168.2.1)&lt;br /&gt;
    ↓ Portweiterleitung: :80 + :443 (und nur! diese!!) → 192.168.2.2&lt;br /&gt;
OPNsense WAN-Interface (192.168.2.2)&lt;br /&gt;
    ↓ Destination NAT: :80/:443 → 192.168.10.100&lt;br /&gt;
Homeserver eno1/eth0 (192.168.10.100)&lt;br /&gt;
    ↓ Docker-Port-Binding: 0.0.0.0:80 + 0.0.0.0:443&lt;br /&gt;
Caddy / Reverse Proxy (Docker-intern)&lt;br /&gt;
    ↓ Reverse Proxy anhand des Host-Headers&lt;br /&gt;
Ziel-Container (z.B. wordpress, nextcloud, ...)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit ist der Server auf der IP-Ebene (Layer 3 des OSI-Modells) von außen hin &amp;quot;unsichtbar&amp;quot;: Die Firewall (OPNsense) lebt, mit dem Gateway, im 192.168.2-er Netz. Von dort routet sie alle Anfragen über die Ports 80 und 443 an das Interface 192.168.10.100. Dahinter, also im 192.168.10-er-Subnetz, residiert der Heimserver.&lt;br /&gt;
&lt;br /&gt;
Am Ende dieses Beitrages gibt es Sicherheitshinweise. Bitte dringend beachten, dass der Router ausschließlich die Ports &#039;&#039;&#039;80/TCP&#039;&#039;&#039; und &#039;&#039;&#039;443/TCP&#039;&#039;&#039; nach außen frei gibt. Der Webserver wird dabei so konfiguriert, dass HTTP-Daten über Port 80 nach HTTPS auf Port 443 umgeleitet werden.&lt;br /&gt;
&lt;br /&gt;
Die Idee, ausschließlich HTTPS zuzulassen, läge nahe. Damit bräuchte sich der Webserver nicht um die Weiterleitung auf Port 443 zu befassen.&lt;br /&gt;
Bedauerlicherweise wird in diesem Fall der Umgang mit dem TLS-Zertifikat, das den HTTPS-Datenstrom verschlüsselt, scheitern. [https://letsencrypt.org/ LetsEncrypt] benötigt bei Einrichtung und Verlängerung seiner Zertifikate einen offenen 80-er Port.&lt;br /&gt;
&lt;br /&gt;
Sollte es nötig sein, den Server von außen zu administrieren, wird man darüber nachdenken, einen VPN-Tunnel einzurichten. Sicherer jedoch - und einfacher - ist es dennoch, die Administration ausschließlich über einen zertifikats-geschützten SSH-Zugang im inneren 192.168.-er-Netz zuzulassen und, abgesehen von 80 und 443, auf jeden nach außen exponierten Port zu verzichten.&lt;br /&gt;
&lt;br /&gt;
=== Wer macht was? ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Komponente !! Aufgabe !! Konfigurationsort&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Router / Gateway&#039;&#039;&#039; || DynDNS-Aktualisierung, erste NAT-Stufe, WLAN || Router Web-UI → Portfreigaben&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; || Firewall-Regeln, zweite NAT-Stufe (Destination NAT), DHCP für Server-VLAN || OPNsense Web-UI (Standard: https://&amp;amp;lt;wan-ip&amp;amp;gt;:443 oder :8443)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Caddy / Reverse Proxy&#039;&#039;&#039; || TLS-Terminierung, Let&#039;s Encrypt, Weiterleitung an Container || Caddyfile auf dem Homeserver&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Docker&#039;&#039;&#039; || Container-Isolation, internes Netz (Standard: 172.18.0.0/16) || docker-compose.yml pro Dienst&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fail2ban&#039;&#039;&#039; || Brute-Force-Schutz auf Applikationsebene || Jail-Configs im fail2ban-Container&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Wichtig: OPNsense hat ZWEI Firewall-Engines ===&lt;br /&gt;
&lt;br /&gt;
OPNsense 26.x hat zwei parallele Regelwerke:&lt;br /&gt;
* &#039;&#039;&#039;Rules [new]&#039;&#039;&#039; — neue API-basierte Engine&lt;br /&gt;
* &#039;&#039;&#039;Rules&#039;&#039;&#039; — alte Engine (Legacy)&lt;br /&gt;
&lt;br /&gt;
Neue Regeln &#039;&#039;&#039;immer in beiden&#039;&#039;&#039; anlegen! Bei Problemen immer beide prüfen.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 2: Wo steht was? ==&lt;br /&gt;
&lt;br /&gt;
=== IP-Adressen (Beispiel-Setup) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Gerät !! Interface !! IP !! Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
| Router / Gateway || — || 192.168.2.1 || Gateway, WLAN, DynDNS&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense WAN || wan-interface || 192.168.2.2 || Statisch konfiguriert&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense LAN / Server-VLAN || lan-interface || 192.168.10.1 || Gateway für Server-Netz&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver || eno1 / eth0 || 192.168.10.100 || Fest per DHCP-Reservation (MAC-Adresse)&lt;br /&gt;
|-&lt;br /&gt;
| Client-Geräte || WLAN || 192.168.2.x || Im Router-Netz, nicht im Server-VLAN&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Homeserver: Netzwerk-Interface-Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Der Homeserver bezieht seine IP per DHCP vom OPNsense-DHCP-Server. Bei Debian/Ubuntu mit systemd-networkd:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/systemd/network/10-eth0.network&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Korrekter Inhalt (DHCP):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[Match]&lt;br /&gt;
Name=eno1&lt;br /&gt;
&lt;br /&gt;
[Network]&lt;br /&gt;
DHCP=ipv4&lt;br /&gt;
&lt;br /&gt;
[DHCP]&lt;br /&gt;
RouteMetric=100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ &#039;&#039;&#039;Niemals&#039;&#039;&#039; eine statische IP oder einen Gateway manuell eintragen!&lt;br /&gt;
Der Default-Gateway kommt immer vom DHCP-Server der OPNsense-Firewall (&amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Kea DHCP Lease-Datei (OPNsense) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/db/kea/kea-leases4.csv&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier verwaltet Kea die aktiven Leases. Bei Problemen mit doppelten IPs kann diese Datei (nach &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;) auf den Header reduziert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context,pool_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 3: Systematische Diagnose — Schritt für Schritt ==&lt;br /&gt;
&lt;br /&gt;
=== Grundprinzip: Von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Immer von außen nach innen vorgehen — nie raten, immer messen. Jede Schicht einzeln prüfen.&lt;br /&gt;
&lt;br /&gt;
==== Schritt 1: Ist OPNsense überhaupt erreichbar? ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Vom Client-Rechner:&lt;br /&gt;
ping 192.168.2.2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ OPNsense antwortet standardmäßig &#039;&#039;&#039;nicht&#039;&#039;&#039; auf ICMP/Ping von außen — das ist korrekt!&lt;br /&gt;
&lt;br /&gt;
Stattdessen prüfen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Web-UI erreichbar?&lt;br /&gt;
https://192.168.2.2:8443&lt;br /&gt;
&lt;br /&gt;
# Router zeigt OPNsense als verbundenes Gerät?&lt;br /&gt;
http://192.168.2.1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 2: OPNsense intern prüfen ====&lt;br /&gt;
&lt;br /&gt;
Per SSH oder serieller Konsole auf OPNsense:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# WAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;wan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.2.2, status: active&lt;br /&gt;
&lt;br /&gt;
# LAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;lan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.10.1, status: active&lt;br /&gt;
&lt;br /&gt;
# Router erreichbar?&lt;br /&gt;
ping -c 3 192.168.2.1&lt;br /&gt;
&lt;br /&gt;
# Homeserver erreichbar?&lt;br /&gt;
ping -c 3 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 3: Homeserver direkt prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# SSH auf Homeserver:&lt;br /&gt;
ssh root@192.168.10.100&lt;br /&gt;
&lt;br /&gt;
# Alle Container laufen?&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# Internet vom Homeserver aus erreichbar?&lt;br /&gt;
ping -c 3 9.9.9.9&lt;br /&gt;
&lt;br /&gt;
# Routing-Tabelle korrekt?&lt;br /&gt;
ip route show&lt;br /&gt;
# Erwartete Default-Route: default via 192.168.10.1 dev eno1&lt;br /&gt;
# NICHT: default via 192.168.178.x — das wäre falsch!&lt;br /&gt;
&lt;br /&gt;
# Welche IP hat das Interface?&lt;br /&gt;
ip addr show eno1&lt;br /&gt;
# Erwartete IP: 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 4: Caddy / Reverse Proxy prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Läuft Caddy und antwortet er lokal?&lt;br /&gt;
curl -v http://localhost&lt;br /&gt;
# Erwartete Antwort: HTTP 308 Redirect → https://localhost/&lt;br /&gt;
&lt;br /&gt;
# Caddy-Logs auf Fehler prüfen:&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Typische Fehler in den Caddy-Logs:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fehlermeldung !! Bedeutung !! Lösung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dial tcp ...:443: connect: no route to host&amp;lt;/code&amp;gt; || Caddy kommt nicht ins Internet (Let&#039;s Encrypt nicht erreichbar) || Routing auf Homeserver prüfen (Schritt 3)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;no route to host&amp;lt;/code&amp;gt; bei Ping auf 9.9.9.9 || Falscher Default-Gateway || &amp;lt;code&amp;gt;ip route show&amp;lt;/code&amp;gt; prüfen, falsche Route entfernen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Schritt 5: NAT und Firewall-Regeln prüfen (OPNsense Shell) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# NAT-Regeln anzeigen:&lt;br /&gt;
pfctl -s nat | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Firewall-Regeln anzeigen:&lt;br /&gt;
pfctl -s rules | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf WAN-Interface beobachten (kommt der Request an?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;wan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf LAN-Interface beobachten (wird er weitergeleitet?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;lan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Diagnose-Logik:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tcpdump WAN sieht Traffic, LAN nicht → NAT-Regel prüfen!&lt;br /&gt;
tcpdump WAN sieht keinen Traffic    → Portweiterleitung im Router prüfen!&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 6: Bekannte Fallstricke ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Problem !! Symptom !! Ursache !! Fix&lt;br /&gt;
|-&lt;br /&gt;
| Falsche statische Route || &amp;lt;code&amp;gt;ping 9.9.9.9&amp;lt;/code&amp;gt; schlägt fehl || Netzwerk-Config hat statischen Gateway eingetragen || Auf DHCP umstellen, &amp;lt;code&amp;gt;systemctl restart systemd-networkd&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver hat falsche IP || NAT-Regeln greifen nicht || DHCP hat beim Neustart temporär andere IP vergeben || DHCP-Reservation per MAC-Adresse einrichten&lt;br /&gt;
|-&lt;br /&gt;
| DHCP-Leases durcheinander || Server taucht mit zwei IPs auf || Neustart hat neuen Lease vor Ablauf des alten erzeugt || &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;, Lease-CSV bereinigen, &amp;lt;code&amp;gt;configctl kea start&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense Firewall-Regel fehlt || Dienste von außen nicht erreichbar, intern OK || Regel nur in einer der beiden Engines angelegt || Regel in &#039;&#039;&#039;beiden&#039;&#039;&#039; Engines anlegen (Rules [new] + Rules)&lt;br /&gt;
|-&lt;br /&gt;
| NAT-Regel ohne Subnetz-Maske || Traffic kommt nicht an || &amp;lt;code&amp;gt;192.168.178.0&amp;lt;/code&amp;gt; statt &amp;lt;code&amp;gt;192.168.178.0/24&amp;lt;/code&amp;gt; eingetragen || Subnetz-Maske ergänzen — ohne /24 gilt nur die Netzadresse selbst!&lt;br /&gt;
|-&lt;br /&gt;
| Source/Destination Port vertauscht || Verbindungen werden blockiert || Bei Firewall-Regel Port unter &amp;quot;Source&amp;quot; statt &amp;quot;Destination&amp;quot; eingetragen || Source Port: any / Destination Port: gewünschter Port&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Notfall-Cheatsheet ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# OPNsense: Firewall temporär deaktivieren (Notfall!)&lt;br /&gt;
pfctl -d&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Firewall wieder aktivieren&lt;br /&gt;
pfctl -e&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Kea DHCP stoppen/starten&lt;br /&gt;
configctl kea stop&lt;br /&gt;
configctl kea start&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Falsche Default-Route entfernen&lt;br /&gt;
ip route del default via &amp;amp;lt;falsche-gateway-ip&amp;amp;gt; dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: IP manuell setzen (Sofortlösung bei DHCP-Problemen)&lt;br /&gt;
ip addr add 192.168.10.100/24 dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Netzwerk-Dienst neu starten (Verbindung kurz weg!)&lt;br /&gt;
systemctl restart systemd-networkd&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Docker-Logs prüfen&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Alias-Tabellen prüfen (Blocklisten)&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | wc -l&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | grep &amp;amp;lt;IP&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Sicherheitshinweise ==&lt;br /&gt;
&lt;br /&gt;
* SSH-Ports &#039;&#039;&#039;nicht&#039;&#039;&#039; über das Internet freigeben — nur intern erreichbar lassen! Sollte das keine Option sein: VPN-Tunnel!&lt;br /&gt;
* Portweiterleitung im Router auf das &#039;&#039;&#039;Minimum&#039;&#039;&#039; beschränken (nur die Ports 80 + 443 öffnen)&lt;br /&gt;
* Für interne Admin-Interfaces (OPNsense Web-UI, Monitoring) &#039;&#039;&#039;keine(!) externen Freigaben!&#039;&#039;&#039;&lt;br /&gt;
* DHCP-Reservations per MAC-Adresse oder statische IP-Adressen verhindern IP-Wechsel nach Neustarts&lt;br /&gt;
* Bei Firewall-Regeln: Block-Regeln &#039;&#039;&#039;immer&#039;&#039;&#039; vor Pass-Regeln platzieren&lt;br /&gt;
&lt;br /&gt;
Abschließend eine absolute Regel, die immer und durch die Ewigkeiten gilt:&lt;br /&gt;
* Dienste, die auf einem Rechner &#039;&#039;&#039;NICHT&#039;&#039;&#039; existieren, werden niemals angegriffen! Wenig ist hier mehr!&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Dieser Artikel basiert auf praktischen Erfahrungen aus dem Betrieb eines selbst gehosteten Servers mit OPNsense, Cisco-Switch und Docker-Stack.&#039;&#039;&lt;br /&gt;
&#039;&#039;Erstellt: Mai 2026&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=261</id>
		<title>Homeserver-Sicherheitsarchitektur</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=261"/>
		<updated>2026-05-27T23:50:10Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Sicherheitshinweise */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Homeserver-Sicherheitsarchitektur: Aufbau, Funktionsweise und Diagnose ==&lt;br /&gt;
&lt;br /&gt;
Einen eigenen Server an&#039;s Internet zu bekommen, ist nicht allzu schwierig. Ein Dienst, der die eigene, vom Internet-Provider zugewiesene IP-Adresse in einen festen Domain-Namen umwandelt (siehe: [https://de.wikipedia.org/wiki/Dynamisches_DNS Dynamisches DNS]), wird im privaten Bereich die Voraussetzung sein.&lt;br /&gt;
Es gibt verschiedene Anbieter, oft auch kostenlose.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Der eigenen, von außen sichtbaren IP 78.123.234.45 wird vom DynDDS-Dienst die Domain &amp;lt;myhomeserver.dyndns.de&amp;gt; zugewiesen.&lt;br /&gt;
Einmal eingerichtet, wird der eigene Rechner antworten, wenn die Domain http://myhomeserver.dyndns.de in die Browser-Adressleiste einkopiert wird.&lt;br /&gt;
&lt;br /&gt;
=== Motivation für einen Server mit OPNsense, Managed Switch und Docker ===&lt;br /&gt;
&lt;br /&gt;
Die Kehrseite: Sowie der Server über&#039;s Internet erreichbar ist, ist er angreifbar.&lt;br /&gt;
Das ist kein theoretisches Szenario. Meiner Erfahrung nach ist es eine Frage von Stunden, bis die ersten Bots &amp;quot;anklopfen&amp;quot;, nach laufenden Diensten suchen, nach offenen Ports, nach Schwachstellen.&lt;br /&gt;
&lt;br /&gt;
Kurz: Eine öffentliche Erreichbarkeit des eigenen Servers über die ungesicherte Adresse...&lt;br /&gt;
&lt;br /&gt;
* http://myhomeserver.dyndns.de&lt;br /&gt;
&lt;br /&gt;
...wäre hochgradig fahrlässig.&lt;br /&gt;
&lt;br /&gt;
Aufgrund einer mangelhaften Konfiguration (offener Samba-Port) hatte ich die sehr reale Erfahrung einer russischen Hackerbande, die einige Hundert Textdateien mit Zahlungsaufforderungen und einen Verschlüsselungstrojaner auf meinem Rechner hinterlassen hatte. Gerettet hatten mich damals die Dateirechte von Linux. Das fehlende E(x)ecutional-Flag und die eingeschränkten Benutzerrechte hatten den Trojaner ausgebremst.&lt;br /&gt;
&lt;br /&gt;
Trotzdem: Nie wieder!&lt;br /&gt;
Ein wenig von dem, was ich gelernt habe, gebe ich ich hier weiter.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Einleitung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt den Aufbau einer &#039;&#039;&#039;sicheren&#039;&#039;&#039; Netzwerkarchitektur für einen Homeserver, der über das öffentliche Internet erreichbar ist. Der Beitrag richtet sich an alle, die ihre Daten selbst kontrollieren wollen — und dabei nicht unfreiwillig Teil einer globalen Angriffs-Infrastruktur werden möchten. Er will zum Verständnis beitragen, wie die einzelnen Komponenten zusammenspielen — und wie man systematisch vorgeht, wenn etwas nicht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der Fokus liegt nicht auf einer spezifischen Hardware-Konfiguration, sondern auf dem allgemeinen Prinzip: Wie kommt ein Request von außen sicher zu einem Docker-Container?&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Annahmen / Szenario ==&lt;br /&gt;
&lt;br /&gt;
Folgende Komponenten werden in diesem Artikel vorausgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver&#039;&#039;&#039; (Raspberry Pi, Intel NUC, oder beliebiger Linux-Server)&lt;br /&gt;
** Betriebssystem: Debian/Ubuntu oder vergleichbar&lt;br /&gt;
** Docker mit mehreren Diensten (z.B. WordPress, Nextcloud, MediaWiki)&lt;br /&gt;
** Caddy als Reverse Proxy (alternativ funktionieren [https://nginx.org/ nginx], [https://httpd.apache.org/ Apache], oder (ggf. kostenpflichtige) proprietäre Lösungen. Caddy allerdings hat das für mich charmante Feature, sich eigenständig um die TSL-Zertifikate und ihre Verlängerung bei LetsEncrypt zu kümmern. Wer schon einmal aufgrund &amp;quot;zu...&amp;quot; vieler unbeabsichtigter Fehlversuche während der Zertifikats-Einrichtung von LetsEncrypt auf Tage gesperrt wurde, wird mein Faible über diesen Automatismus teilen!)&lt;br /&gt;
** fail2ban als Brute-Force-Schutz&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;DynDNS-Dienst&#039;&#039;&#039; der dem Homeserver eine feste Domain zuweist&lt;br /&gt;
** Beispiel: &amp;lt;code&amp;gt;myhomeserver.dyndns.de&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Router / Heimnetz-Gateway&#039;&#039;&#039;&lt;br /&gt;
** Beispiel-IP: &amp;lt;code&amp;gt;192.168.2.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Portweiterleitung, WLAN, DynDNS-Aktualisierung&lt;br /&gt;
** Typisch: FritzBox, aber jeder Router mit Portweiterleitung funktioniert&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; (dedizierte Hardware-Firewall)&lt;br /&gt;
** WAN-Interface: &amp;lt;code&amp;gt;192.168.2.2&amp;lt;/code&amp;gt; (im Router-Netz)&lt;br /&gt;
** LAN-Interface / Server-VLAN: &amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Firewall, NAT, DHCP, IDS/IPS&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Managed Switch&#039;&#039;&#039; (optional, für VLAN-Segmentierung)&lt;br /&gt;
** Trennt Server-VLAN vom Rest des Netzes&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver-IP&#039;&#039;&#039;: &amp;lt;code&amp;gt;192.168.10.100&amp;lt;/code&amp;gt; (per DHCP-Reservation oder besser: Per statischer IP-Adresse fest)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 1: Wie funktionieren die Weiterleitungen? Wer macht was? ==&lt;br /&gt;
&lt;br /&gt;
=== Die Kette von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Ein Request von außen (z.B. Browser ruft &amp;lt;code&amp;gt;https://myhomeserver.dyndns.de&amp;lt;/code&amp;gt; auf) durchläuft folgende Stationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Internet&lt;br /&gt;
    ↓ DNS-Auflösung: dyndns.de → öffentliche IP des Heimnetzes&lt;br /&gt;
Router / Gateway (192.168.2.1)&lt;br /&gt;
    ↓ Portweiterleitung: :80 + :443 (und nur! diese!!) → 192.168.2.2&lt;br /&gt;
OPNsense WAN-Interface (192.168.2.2)&lt;br /&gt;
    ↓ Destination NAT: :80/:443 → 192.168.10.100&lt;br /&gt;
Homeserver eno1/eth0 (192.168.10.100)&lt;br /&gt;
    ↓ Docker-Port-Binding: 0.0.0.0:80 + 0.0.0.0:443&lt;br /&gt;
Caddy / Reverse Proxy (Docker-intern)&lt;br /&gt;
    ↓ Reverse Proxy anhand des Host-Headers&lt;br /&gt;
Ziel-Container (z.B. wordpress, nextcloud, ...)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit ist der Server auf der IP-Ebene (Layer 3 des OSI-Modells) von außen hin &amp;quot;unsichtbar&amp;quot;: Die Firewall (OPNsense) lebt, mit dem Gateway, im 192.168.2-er Netz. Von dort routet sie alle Anfragen über die Ports 80 und 443 an das Interface 192.168.10.100. Dahinter, also im 192.168.10-er-Subnetz, residiert der Heimserver.&lt;br /&gt;
&lt;br /&gt;
Am Ende dieses Beitrages gibt es Sicherheitshinweise. Bitte dringend beachten, dass der Router ausschließlich die Ports &#039;&#039;&#039;80/TCP&#039;&#039;&#039; und &#039;&#039;&#039;443/TCP&#039;&#039;&#039; nach außen frei gibt. Der Webserver wird dabei so konfiguriert, dass HTTP-Daten über Port 80 nach HTTPS auf Port 443 umgeleitet werden.&lt;br /&gt;
&lt;br /&gt;
Die Idee, ausschließlich HTTPS zuzulassen, läge nahe. Damit bräuchte sich der Webserver nicht um die Weiterleitung auf Port 443 zu befassen.&lt;br /&gt;
Bedauerlicherweise wird in diesem Fall der Umgang mit dem TLS-Zertifikat, das den HTTPS-Datenstrom verschlüsselt, scheitern. [https://letsencrypt.org/ LetsEncrypt] benötigt bei Einrichtung und Verlängerung seiner Zertifikate einen offenen 80-er Port.&lt;br /&gt;
&lt;br /&gt;
Sollte es nötig sein, den Server von außen zu administrieren, wird man darüber nachdenken, einen VPN-Tunnel einzurichten. Sicherer jedoch - und einfacher - ist es dennoch, die Administration ausschließlich über einen zertifikats-geschützten SSH-Zugang im inneren 192.168.-er-Netz zuzulassen und, abgesehen von 80 und 443, auf jeden nach außen exponierten Port zu verzichten.&lt;br /&gt;
&lt;br /&gt;
=== Wer macht was? ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Komponente !! Aufgabe !! Konfigurationsort&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Router / Gateway&#039;&#039;&#039; || DynDNS-Aktualisierung, erste NAT-Stufe, WLAN || Router Web-UI → Portfreigaben&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; || Firewall-Regeln, zweite NAT-Stufe (Destination NAT), DHCP für Server-VLAN || OPNsense Web-UI (Standard: https://&amp;amp;lt;wan-ip&amp;amp;gt;:443 oder :8443)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Caddy / Reverse Proxy&#039;&#039;&#039; || TLS-Terminierung, Let&#039;s Encrypt, Weiterleitung an Container || Caddyfile auf dem Homeserver&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Docker&#039;&#039;&#039; || Container-Isolation, internes Netz (Standard: 172.18.0.0/16) || docker-compose.yml pro Dienst&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fail2ban&#039;&#039;&#039; || Brute-Force-Schutz auf Applikationsebene || Jail-Configs im fail2ban-Container&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Wichtig: OPNsense hat ZWEI Firewall-Engines ===&lt;br /&gt;
&lt;br /&gt;
OPNsense 26.x hat zwei parallele Regelwerke:&lt;br /&gt;
* &#039;&#039;&#039;Rules [new]&#039;&#039;&#039; — neue API-basierte Engine&lt;br /&gt;
* &#039;&#039;&#039;Rules&#039;&#039;&#039; — alte Engine (Legacy)&lt;br /&gt;
&lt;br /&gt;
Neue Regeln &#039;&#039;&#039;immer in beiden&#039;&#039;&#039; anlegen! Bei Problemen immer beide prüfen.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 2: Wo steht was? ==&lt;br /&gt;
&lt;br /&gt;
=== IP-Adressen (Beispiel-Setup) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Gerät !! Interface !! IP !! Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
| Router / Gateway || — || 192.168.2.1 || Gateway, WLAN, DynDNS&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense WAN || wan-interface || 192.168.2.2 || Statisch konfiguriert&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense LAN / Server-VLAN || lan-interface || 192.168.10.1 || Gateway für Server-Netz&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver || eno1 / eth0 || 192.168.10.100 || Fest per DHCP-Reservation (MAC-Adresse)&lt;br /&gt;
|-&lt;br /&gt;
| Client-Geräte || WLAN || 192.168.2.x || Im Router-Netz, nicht im Server-VLAN&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Homeserver: Netzwerk-Interface-Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Der Homeserver bezieht seine IP per DHCP vom OPNsense-DHCP-Server. Bei Debian/Ubuntu mit systemd-networkd:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/systemd/network/10-eth0.network&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Korrekter Inhalt (DHCP):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[Match]&lt;br /&gt;
Name=eno1&lt;br /&gt;
&lt;br /&gt;
[Network]&lt;br /&gt;
DHCP=ipv4&lt;br /&gt;
&lt;br /&gt;
[DHCP]&lt;br /&gt;
RouteMetric=100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ &#039;&#039;&#039;Niemals&#039;&#039;&#039; eine statische IP oder einen Gateway manuell eintragen!&lt;br /&gt;
Der Default-Gateway kommt immer vom DHCP-Server der OPNsense-Firewall (&amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Kea DHCP Lease-Datei (OPNsense) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/db/kea/kea-leases4.csv&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier verwaltet Kea die aktiven Leases. Bei Problemen mit doppelten IPs kann diese Datei (nach &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;) auf den Header reduziert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context,pool_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 3: Systematische Diagnose — Schritt für Schritt ==&lt;br /&gt;
&lt;br /&gt;
=== Grundprinzip: Von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Immer von außen nach innen vorgehen — nie raten, immer messen. Jede Schicht einzeln prüfen.&lt;br /&gt;
&lt;br /&gt;
==== Schritt 1: Ist OPNsense überhaupt erreichbar? ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Vom Client-Rechner:&lt;br /&gt;
ping 192.168.2.2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ OPNsense antwortet standardmäßig &#039;&#039;&#039;nicht&#039;&#039;&#039; auf ICMP/Ping von außen — das ist korrekt!&lt;br /&gt;
&lt;br /&gt;
Stattdessen prüfen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Web-UI erreichbar?&lt;br /&gt;
https://192.168.2.2:8443&lt;br /&gt;
&lt;br /&gt;
# Router zeigt OPNsense als verbundenes Gerät?&lt;br /&gt;
http://192.168.2.1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 2: OPNsense intern prüfen ====&lt;br /&gt;
&lt;br /&gt;
Per SSH oder serieller Konsole auf OPNsense:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# WAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;wan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.2.2, status: active&lt;br /&gt;
&lt;br /&gt;
# LAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;lan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.10.1, status: active&lt;br /&gt;
&lt;br /&gt;
# Router erreichbar?&lt;br /&gt;
ping -c 3 192.168.2.1&lt;br /&gt;
&lt;br /&gt;
# Homeserver erreichbar?&lt;br /&gt;
ping -c 3 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 3: Homeserver direkt prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# SSH auf Homeserver:&lt;br /&gt;
ssh root@192.168.10.100&lt;br /&gt;
&lt;br /&gt;
# Alle Container laufen?&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# Internet vom Homeserver aus erreichbar?&lt;br /&gt;
ping -c 3 9.9.9.9&lt;br /&gt;
&lt;br /&gt;
# Routing-Tabelle korrekt?&lt;br /&gt;
ip route show&lt;br /&gt;
# Erwartete Default-Route: default via 192.168.10.1 dev eno1&lt;br /&gt;
# NICHT: default via 192.168.178.x — das wäre falsch!&lt;br /&gt;
&lt;br /&gt;
# Welche IP hat das Interface?&lt;br /&gt;
ip addr show eno1&lt;br /&gt;
# Erwartete IP: 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 4: Caddy / Reverse Proxy prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Läuft Caddy und antwortet er lokal?&lt;br /&gt;
curl -v http://localhost&lt;br /&gt;
# Erwartete Antwort: HTTP 308 Redirect → https://localhost/&lt;br /&gt;
&lt;br /&gt;
# Caddy-Logs auf Fehler prüfen:&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Typische Fehler in den Caddy-Logs:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fehlermeldung !! Bedeutung !! Lösung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dial tcp ...:443: connect: no route to host&amp;lt;/code&amp;gt; || Caddy kommt nicht ins Internet (Let&#039;s Encrypt nicht erreichbar) || Routing auf Homeserver prüfen (Schritt 3)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;no route to host&amp;lt;/code&amp;gt; bei Ping auf 9.9.9.9 || Falscher Default-Gateway || &amp;lt;code&amp;gt;ip route show&amp;lt;/code&amp;gt; prüfen, falsche Route entfernen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Schritt 5: NAT und Firewall-Regeln prüfen (OPNsense Shell) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# NAT-Regeln anzeigen:&lt;br /&gt;
pfctl -s nat | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Firewall-Regeln anzeigen:&lt;br /&gt;
pfctl -s rules | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf WAN-Interface beobachten (kommt der Request an?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;wan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf LAN-Interface beobachten (wird er weitergeleitet?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;lan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Diagnose-Logik:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tcpdump WAN sieht Traffic, LAN nicht → NAT-Regel prüfen!&lt;br /&gt;
tcpdump WAN sieht keinen Traffic    → Portweiterleitung im Router prüfen!&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 6: Bekannte Fallstricke ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Problem !! Symptom !! Ursache !! Fix&lt;br /&gt;
|-&lt;br /&gt;
| Falsche statische Route || &amp;lt;code&amp;gt;ping 9.9.9.9&amp;lt;/code&amp;gt; schlägt fehl || Netzwerk-Config hat statischen Gateway eingetragen || Auf DHCP umstellen, &amp;lt;code&amp;gt;systemctl restart systemd-networkd&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver hat falsche IP || NAT-Regeln greifen nicht || DHCP hat beim Neustart temporär andere IP vergeben || DHCP-Reservation per MAC-Adresse einrichten&lt;br /&gt;
|-&lt;br /&gt;
| DHCP-Leases durcheinander || Server taucht mit zwei IPs auf || Neustart hat neuen Lease vor Ablauf des alten erzeugt || &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;, Lease-CSV bereinigen, &amp;lt;code&amp;gt;configctl kea start&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense Firewall-Regel fehlt || Dienste von außen nicht erreichbar, intern OK || Regel nur in einer der beiden Engines angelegt || Regel in &#039;&#039;&#039;beiden&#039;&#039;&#039; Engines anlegen (Rules [new] + Rules)&lt;br /&gt;
|-&lt;br /&gt;
| NAT-Regel ohne Subnetz-Maske || Traffic kommt nicht an || &amp;lt;code&amp;gt;192.168.178.0&amp;lt;/code&amp;gt; statt &amp;lt;code&amp;gt;192.168.178.0/24&amp;lt;/code&amp;gt; eingetragen || Subnetz-Maske ergänzen — ohne /24 gilt nur die Netzadresse selbst!&lt;br /&gt;
|-&lt;br /&gt;
| Source/Destination Port vertauscht || Verbindungen werden blockiert || Bei Firewall-Regel Port unter &amp;quot;Source&amp;quot; statt &amp;quot;Destination&amp;quot; eingetragen || Source Port: any / Destination Port: gewünschter Port&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Notfall-Cheatsheet ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# OPNsense: Firewall temporär deaktivieren (Notfall!)&lt;br /&gt;
pfctl -d&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Firewall wieder aktivieren&lt;br /&gt;
pfctl -e&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Kea DHCP stoppen/starten&lt;br /&gt;
configctl kea stop&lt;br /&gt;
configctl kea start&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Falsche Default-Route entfernen&lt;br /&gt;
ip route del default via &amp;amp;lt;falsche-gateway-ip&amp;amp;gt; dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: IP manuell setzen (Sofortlösung bei DHCP-Problemen)&lt;br /&gt;
ip addr add 192.168.10.100/24 dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Netzwerk-Dienst neu starten (Verbindung kurz weg!)&lt;br /&gt;
systemctl restart systemd-networkd&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Docker-Logs prüfen&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Alias-Tabellen prüfen (Blocklisten)&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | wc -l&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | grep &amp;amp;lt;IP&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Sicherheitshinweise ==&lt;br /&gt;
&lt;br /&gt;
* SSH-Ports &#039;&#039;&#039;nicht&#039;&#039;&#039; über das Internet freigeben — nur intern erreichbar lassen! Sollte das keine Option sein: VPN-Tunnel!&lt;br /&gt;
* Portweiterleitung im Router auf das &#039;&#039;&#039;Minimum&#039;&#039;&#039; beschränken (nur die Ports 80 + 443 öffnen)&lt;br /&gt;
* Für interne Admin-Interfaces (OPNsense Web-UI, Monitoring) &#039;&#039;&#039;keine externen Freigaben&#039;&#039;&#039;&lt;br /&gt;
* DHCP-Reservations per MAC-Adresse oder statische IP-Adressen verhindern IP-Wechsel nach Neustarts&lt;br /&gt;
* Bei Firewall-Regeln: Block-Regeln &#039;&#039;&#039;immer&#039;&#039;&#039; vor Pass-Regeln platzieren&lt;br /&gt;
&lt;br /&gt;
Abschließend eine absolute Regel, die immer und durch die Ewigkeiten gilt:&lt;br /&gt;
* Dienste, die auf einem Rechner &#039;&#039;&#039;NICHT&#039;&#039;&#039; existieren, werden niemals angegriffen! Wenig ist hier mehr!&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Dieser Artikel basiert auf praktischen Erfahrungen aus dem Betrieb eines selbst gehosteten Servers mit OPNsense, Cisco-Switch und Docker-Stack.&#039;&#039;&lt;br /&gt;
&#039;&#039;Erstellt: Mai 2026&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=260</id>
		<title>Homeserver-Sicherheitsarchitektur</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=260"/>
		<updated>2026-05-27T23:47:33Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Annahmen / Szenario */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Homeserver-Sicherheitsarchitektur: Aufbau, Funktionsweise und Diagnose ==&lt;br /&gt;
&lt;br /&gt;
Einen eigenen Server an&#039;s Internet zu bekommen, ist nicht allzu schwierig. Ein Dienst, der die eigene, vom Internet-Provider zugewiesene IP-Adresse in einen festen Domain-Namen umwandelt (siehe: [https://de.wikipedia.org/wiki/Dynamisches_DNS Dynamisches DNS]), wird im privaten Bereich die Voraussetzung sein.&lt;br /&gt;
Es gibt verschiedene Anbieter, oft auch kostenlose.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Der eigenen, von außen sichtbaren IP 78.123.234.45 wird vom DynDDS-Dienst die Domain &amp;lt;myhomeserver.dyndns.de&amp;gt; zugewiesen.&lt;br /&gt;
Einmal eingerichtet, wird der eigene Rechner antworten, wenn die Domain http://myhomeserver.dyndns.de in die Browser-Adressleiste einkopiert wird.&lt;br /&gt;
&lt;br /&gt;
=== Motivation für einen Server mit OPNsense, Managed Switch und Docker ===&lt;br /&gt;
&lt;br /&gt;
Die Kehrseite: Sowie der Server über&#039;s Internet erreichbar ist, ist er angreifbar.&lt;br /&gt;
Das ist kein theoretisches Szenario. Meiner Erfahrung nach ist es eine Frage von Stunden, bis die ersten Bots &amp;quot;anklopfen&amp;quot;, nach laufenden Diensten suchen, nach offenen Ports, nach Schwachstellen.&lt;br /&gt;
&lt;br /&gt;
Kurz: Eine öffentliche Erreichbarkeit des eigenen Servers über die ungesicherte Adresse...&lt;br /&gt;
&lt;br /&gt;
* http://myhomeserver.dyndns.de&lt;br /&gt;
&lt;br /&gt;
...wäre hochgradig fahrlässig.&lt;br /&gt;
&lt;br /&gt;
Aufgrund einer mangelhaften Konfiguration (offener Samba-Port) hatte ich die sehr reale Erfahrung einer russischen Hackerbande, die einige Hundert Textdateien mit Zahlungsaufforderungen und einen Verschlüsselungstrojaner auf meinem Rechner hinterlassen hatte. Gerettet hatten mich damals die Dateirechte von Linux. Das fehlende E(x)ecutional-Flag und die eingeschränkten Benutzerrechte hatten den Trojaner ausgebremst.&lt;br /&gt;
&lt;br /&gt;
Trotzdem: Nie wieder!&lt;br /&gt;
Ein wenig von dem, was ich gelernt habe, gebe ich ich hier weiter.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Einleitung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt den Aufbau einer &#039;&#039;&#039;sicheren&#039;&#039;&#039; Netzwerkarchitektur für einen Homeserver, der über das öffentliche Internet erreichbar ist. Der Beitrag richtet sich an alle, die ihre Daten selbst kontrollieren wollen — und dabei nicht unfreiwillig Teil einer globalen Angriffs-Infrastruktur werden möchten. Er will zum Verständnis beitragen, wie die einzelnen Komponenten zusammenspielen — und wie man systematisch vorgeht, wenn etwas nicht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der Fokus liegt nicht auf einer spezifischen Hardware-Konfiguration, sondern auf dem allgemeinen Prinzip: Wie kommt ein Request von außen sicher zu einem Docker-Container?&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Annahmen / Szenario ==&lt;br /&gt;
&lt;br /&gt;
Folgende Komponenten werden in diesem Artikel vorausgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver&#039;&#039;&#039; (Raspberry Pi, Intel NUC, oder beliebiger Linux-Server)&lt;br /&gt;
** Betriebssystem: Debian/Ubuntu oder vergleichbar&lt;br /&gt;
** Docker mit mehreren Diensten (z.B. WordPress, Nextcloud, MediaWiki)&lt;br /&gt;
** Caddy als Reverse Proxy (alternativ funktionieren [https://nginx.org/ nginx], [https://httpd.apache.org/ Apache], oder (ggf. kostenpflichtige) proprietäre Lösungen. Caddy allerdings hat das für mich charmante Feature, sich eigenständig um die TSL-Zertifikate und ihre Verlängerung bei LetsEncrypt zu kümmern. Wer schon einmal aufgrund &amp;quot;zu...&amp;quot; vieler unbeabsichtigter Fehlversuche während der Zertifikats-Einrichtung von LetsEncrypt auf Tage gesperrt wurde, wird mein Faible über diesen Automatismus teilen!)&lt;br /&gt;
** fail2ban als Brute-Force-Schutz&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;DynDNS-Dienst&#039;&#039;&#039; der dem Homeserver eine feste Domain zuweist&lt;br /&gt;
** Beispiel: &amp;lt;code&amp;gt;myhomeserver.dyndns.de&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Router / Heimnetz-Gateway&#039;&#039;&#039;&lt;br /&gt;
** Beispiel-IP: &amp;lt;code&amp;gt;192.168.2.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Portweiterleitung, WLAN, DynDNS-Aktualisierung&lt;br /&gt;
** Typisch: FritzBox, aber jeder Router mit Portweiterleitung funktioniert&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; (dedizierte Hardware-Firewall)&lt;br /&gt;
** WAN-Interface: &amp;lt;code&amp;gt;192.168.2.2&amp;lt;/code&amp;gt; (im Router-Netz)&lt;br /&gt;
** LAN-Interface / Server-VLAN: &amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Firewall, NAT, DHCP, IDS/IPS&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Managed Switch&#039;&#039;&#039; (optional, für VLAN-Segmentierung)&lt;br /&gt;
** Trennt Server-VLAN vom Rest des Netzes&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver-IP&#039;&#039;&#039;: &amp;lt;code&amp;gt;192.168.10.100&amp;lt;/code&amp;gt; (per DHCP-Reservation oder besser: Per statischer IP-Adresse fest)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 1: Wie funktionieren die Weiterleitungen? Wer macht was? ==&lt;br /&gt;
&lt;br /&gt;
=== Die Kette von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Ein Request von außen (z.B. Browser ruft &amp;lt;code&amp;gt;https://myhomeserver.dyndns.de&amp;lt;/code&amp;gt; auf) durchläuft folgende Stationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Internet&lt;br /&gt;
    ↓ DNS-Auflösung: dyndns.de → öffentliche IP des Heimnetzes&lt;br /&gt;
Router / Gateway (192.168.2.1)&lt;br /&gt;
    ↓ Portweiterleitung: :80 + :443 (und nur! diese!!) → 192.168.2.2&lt;br /&gt;
OPNsense WAN-Interface (192.168.2.2)&lt;br /&gt;
    ↓ Destination NAT: :80/:443 → 192.168.10.100&lt;br /&gt;
Homeserver eno1/eth0 (192.168.10.100)&lt;br /&gt;
    ↓ Docker-Port-Binding: 0.0.0.0:80 + 0.0.0.0:443&lt;br /&gt;
Caddy / Reverse Proxy (Docker-intern)&lt;br /&gt;
    ↓ Reverse Proxy anhand des Host-Headers&lt;br /&gt;
Ziel-Container (z.B. wordpress, nextcloud, ...)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit ist der Server auf der IP-Ebene (Layer 3 des OSI-Modells) von außen hin &amp;quot;unsichtbar&amp;quot;: Die Firewall (OPNsense) lebt, mit dem Gateway, im 192.168.2-er Netz. Von dort routet sie alle Anfragen über die Ports 80 und 443 an das Interface 192.168.10.100. Dahinter, also im 192.168.10-er-Subnetz, residiert der Heimserver.&lt;br /&gt;
&lt;br /&gt;
Am Ende dieses Beitrages gibt es Sicherheitshinweise. Bitte dringend beachten, dass der Router ausschließlich die Ports &#039;&#039;&#039;80/TCP&#039;&#039;&#039; und &#039;&#039;&#039;443/TCP&#039;&#039;&#039; nach außen frei gibt. Der Webserver wird dabei so konfiguriert, dass HTTP-Daten über Port 80 nach HTTPS auf Port 443 umgeleitet werden.&lt;br /&gt;
&lt;br /&gt;
Die Idee, ausschließlich HTTPS zuzulassen, läge nahe. Damit bräuchte sich der Webserver nicht um die Weiterleitung auf Port 443 zu befassen.&lt;br /&gt;
Bedauerlicherweise wird in diesem Fall der Umgang mit dem TLS-Zertifikat, das den HTTPS-Datenstrom verschlüsselt, scheitern. [https://letsencrypt.org/ LetsEncrypt] benötigt bei Einrichtung und Verlängerung seiner Zertifikate einen offenen 80-er Port.&lt;br /&gt;
&lt;br /&gt;
Sollte es nötig sein, den Server von außen zu administrieren, wird man darüber nachdenken, einen VPN-Tunnel einzurichten. Sicherer jedoch - und einfacher - ist es dennoch, die Administration ausschließlich über einen zertifikats-geschützten SSH-Zugang im inneren 192.168.-er-Netz zuzulassen und, abgesehen von 80 und 443, auf jeden nach außen exponierten Port zu verzichten.&lt;br /&gt;
&lt;br /&gt;
=== Wer macht was? ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Komponente !! Aufgabe !! Konfigurationsort&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Router / Gateway&#039;&#039;&#039; || DynDNS-Aktualisierung, erste NAT-Stufe, WLAN || Router Web-UI → Portfreigaben&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; || Firewall-Regeln, zweite NAT-Stufe (Destination NAT), DHCP für Server-VLAN || OPNsense Web-UI (Standard: https://&amp;amp;lt;wan-ip&amp;amp;gt;:443 oder :8443)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Caddy / Reverse Proxy&#039;&#039;&#039; || TLS-Terminierung, Let&#039;s Encrypt, Weiterleitung an Container || Caddyfile auf dem Homeserver&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Docker&#039;&#039;&#039; || Container-Isolation, internes Netz (Standard: 172.18.0.0/16) || docker-compose.yml pro Dienst&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fail2ban&#039;&#039;&#039; || Brute-Force-Schutz auf Applikationsebene || Jail-Configs im fail2ban-Container&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Wichtig: OPNsense hat ZWEI Firewall-Engines ===&lt;br /&gt;
&lt;br /&gt;
OPNsense 26.x hat zwei parallele Regelwerke:&lt;br /&gt;
* &#039;&#039;&#039;Rules [new]&#039;&#039;&#039; — neue API-basierte Engine&lt;br /&gt;
* &#039;&#039;&#039;Rules&#039;&#039;&#039; — alte Engine (Legacy)&lt;br /&gt;
&lt;br /&gt;
Neue Regeln &#039;&#039;&#039;immer in beiden&#039;&#039;&#039; anlegen! Bei Problemen immer beide prüfen.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 2: Wo steht was? ==&lt;br /&gt;
&lt;br /&gt;
=== IP-Adressen (Beispiel-Setup) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Gerät !! Interface !! IP !! Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
| Router / Gateway || — || 192.168.2.1 || Gateway, WLAN, DynDNS&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense WAN || wan-interface || 192.168.2.2 || Statisch konfiguriert&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense LAN / Server-VLAN || lan-interface || 192.168.10.1 || Gateway für Server-Netz&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver || eno1 / eth0 || 192.168.10.100 || Fest per DHCP-Reservation (MAC-Adresse)&lt;br /&gt;
|-&lt;br /&gt;
| Client-Geräte || WLAN || 192.168.2.x || Im Router-Netz, nicht im Server-VLAN&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Homeserver: Netzwerk-Interface-Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Der Homeserver bezieht seine IP per DHCP vom OPNsense-DHCP-Server. Bei Debian/Ubuntu mit systemd-networkd:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/systemd/network/10-eth0.network&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Korrekter Inhalt (DHCP):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[Match]&lt;br /&gt;
Name=eno1&lt;br /&gt;
&lt;br /&gt;
[Network]&lt;br /&gt;
DHCP=ipv4&lt;br /&gt;
&lt;br /&gt;
[DHCP]&lt;br /&gt;
RouteMetric=100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ &#039;&#039;&#039;Niemals&#039;&#039;&#039; eine statische IP oder einen Gateway manuell eintragen!&lt;br /&gt;
Der Default-Gateway kommt immer vom DHCP-Server der OPNsense-Firewall (&amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Kea DHCP Lease-Datei (OPNsense) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/db/kea/kea-leases4.csv&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier verwaltet Kea die aktiven Leases. Bei Problemen mit doppelten IPs kann diese Datei (nach &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;) auf den Header reduziert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context,pool_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 3: Systematische Diagnose — Schritt für Schritt ==&lt;br /&gt;
&lt;br /&gt;
=== Grundprinzip: Von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Immer von außen nach innen vorgehen — nie raten, immer messen. Jede Schicht einzeln prüfen.&lt;br /&gt;
&lt;br /&gt;
==== Schritt 1: Ist OPNsense überhaupt erreichbar? ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Vom Client-Rechner:&lt;br /&gt;
ping 192.168.2.2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ OPNsense antwortet standardmäßig &#039;&#039;&#039;nicht&#039;&#039;&#039; auf ICMP/Ping von außen — das ist korrekt!&lt;br /&gt;
&lt;br /&gt;
Stattdessen prüfen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Web-UI erreichbar?&lt;br /&gt;
https://192.168.2.2:8443&lt;br /&gt;
&lt;br /&gt;
# Router zeigt OPNsense als verbundenes Gerät?&lt;br /&gt;
http://192.168.2.1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 2: OPNsense intern prüfen ====&lt;br /&gt;
&lt;br /&gt;
Per SSH oder serieller Konsole auf OPNsense:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# WAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;wan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.2.2, status: active&lt;br /&gt;
&lt;br /&gt;
# LAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;lan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.10.1, status: active&lt;br /&gt;
&lt;br /&gt;
# Router erreichbar?&lt;br /&gt;
ping -c 3 192.168.2.1&lt;br /&gt;
&lt;br /&gt;
# Homeserver erreichbar?&lt;br /&gt;
ping -c 3 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 3: Homeserver direkt prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# SSH auf Homeserver:&lt;br /&gt;
ssh root@192.168.10.100&lt;br /&gt;
&lt;br /&gt;
# Alle Container laufen?&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# Internet vom Homeserver aus erreichbar?&lt;br /&gt;
ping -c 3 9.9.9.9&lt;br /&gt;
&lt;br /&gt;
# Routing-Tabelle korrekt?&lt;br /&gt;
ip route show&lt;br /&gt;
# Erwartete Default-Route: default via 192.168.10.1 dev eno1&lt;br /&gt;
# NICHT: default via 192.168.178.x — das wäre falsch!&lt;br /&gt;
&lt;br /&gt;
# Welche IP hat das Interface?&lt;br /&gt;
ip addr show eno1&lt;br /&gt;
# Erwartete IP: 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 4: Caddy / Reverse Proxy prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Läuft Caddy und antwortet er lokal?&lt;br /&gt;
curl -v http://localhost&lt;br /&gt;
# Erwartete Antwort: HTTP 308 Redirect → https://localhost/&lt;br /&gt;
&lt;br /&gt;
# Caddy-Logs auf Fehler prüfen:&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Typische Fehler in den Caddy-Logs:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fehlermeldung !! Bedeutung !! Lösung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dial tcp ...:443: connect: no route to host&amp;lt;/code&amp;gt; || Caddy kommt nicht ins Internet (Let&#039;s Encrypt nicht erreichbar) || Routing auf Homeserver prüfen (Schritt 3)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;no route to host&amp;lt;/code&amp;gt; bei Ping auf 9.9.9.9 || Falscher Default-Gateway || &amp;lt;code&amp;gt;ip route show&amp;lt;/code&amp;gt; prüfen, falsche Route entfernen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Schritt 5: NAT und Firewall-Regeln prüfen (OPNsense Shell) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# NAT-Regeln anzeigen:&lt;br /&gt;
pfctl -s nat | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Firewall-Regeln anzeigen:&lt;br /&gt;
pfctl -s rules | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf WAN-Interface beobachten (kommt der Request an?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;wan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf LAN-Interface beobachten (wird er weitergeleitet?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;lan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Diagnose-Logik:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tcpdump WAN sieht Traffic, LAN nicht → NAT-Regel prüfen!&lt;br /&gt;
tcpdump WAN sieht keinen Traffic    → Portweiterleitung im Router prüfen!&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 6: Bekannte Fallstricke ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Problem !! Symptom !! Ursache !! Fix&lt;br /&gt;
|-&lt;br /&gt;
| Falsche statische Route || &amp;lt;code&amp;gt;ping 9.9.9.9&amp;lt;/code&amp;gt; schlägt fehl || Netzwerk-Config hat statischen Gateway eingetragen || Auf DHCP umstellen, &amp;lt;code&amp;gt;systemctl restart systemd-networkd&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver hat falsche IP || NAT-Regeln greifen nicht || DHCP hat beim Neustart temporär andere IP vergeben || DHCP-Reservation per MAC-Adresse einrichten&lt;br /&gt;
|-&lt;br /&gt;
| DHCP-Leases durcheinander || Server taucht mit zwei IPs auf || Neustart hat neuen Lease vor Ablauf des alten erzeugt || &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;, Lease-CSV bereinigen, &amp;lt;code&amp;gt;configctl kea start&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense Firewall-Regel fehlt || Dienste von außen nicht erreichbar, intern OK || Regel nur in einer der beiden Engines angelegt || Regel in &#039;&#039;&#039;beiden&#039;&#039;&#039; Engines anlegen (Rules [new] + Rules)&lt;br /&gt;
|-&lt;br /&gt;
| NAT-Regel ohne Subnetz-Maske || Traffic kommt nicht an || &amp;lt;code&amp;gt;192.168.178.0&amp;lt;/code&amp;gt; statt &amp;lt;code&amp;gt;192.168.178.0/24&amp;lt;/code&amp;gt; eingetragen || Subnetz-Maske ergänzen — ohne /24 gilt nur die Netzadresse selbst!&lt;br /&gt;
|-&lt;br /&gt;
| Source/Destination Port vertauscht || Verbindungen werden blockiert || Bei Firewall-Regel Port unter &amp;quot;Source&amp;quot; statt &amp;quot;Destination&amp;quot; eingetragen || Source Port: any / Destination Port: gewünschter Port&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Notfall-Cheatsheet ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# OPNsense: Firewall temporär deaktivieren (Notfall!)&lt;br /&gt;
pfctl -d&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Firewall wieder aktivieren&lt;br /&gt;
pfctl -e&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Kea DHCP stoppen/starten&lt;br /&gt;
configctl kea stop&lt;br /&gt;
configctl kea start&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Falsche Default-Route entfernen&lt;br /&gt;
ip route del default via &amp;amp;lt;falsche-gateway-ip&amp;amp;gt; dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: IP manuell setzen (Sofortlösung bei DHCP-Problemen)&lt;br /&gt;
ip addr add 192.168.10.100/24 dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Netzwerk-Dienst neu starten (Verbindung kurz weg!)&lt;br /&gt;
systemctl restart systemd-networkd&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Docker-Logs prüfen&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Alias-Tabellen prüfen (Blocklisten)&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | wc -l&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | grep &amp;amp;lt;IP&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Sicherheitshinweise ==&lt;br /&gt;
&lt;br /&gt;
* SSH-Ports &#039;&#039;&#039;nicht&#039;&#039;&#039; über das Internet freigeben — nur intern erreichbar lassen! Wenn das nicht geht: VPN-Tunnel!&lt;br /&gt;
* Portweiterleitung im Router auf das &#039;&#039;&#039;Minimum&#039;&#039;&#039; beschränken (nur die Ports 80 + 443 öffnen)&lt;br /&gt;
* Für interne Admin-Interfaces (OPNsense Web-UI, Monitoring) &#039;&#039;&#039;keine externen Freigaben&#039;&#039;&#039;&lt;br /&gt;
* DHCP-Reservations per MAC-Adresse oder statische IP-Adressen verhindern IP-Wechsel nach Neustarts&lt;br /&gt;
* Bei Firewall-Regeln: Block-Regeln &#039;&#039;&#039;immer&#039;&#039;&#039; vor Pass-Regeln platzieren&lt;br /&gt;
&lt;br /&gt;
Abschließend eine absolute Regel, die immer und durch die Ewigkeiten gilt:&lt;br /&gt;
* Dienste, die auf einem Rechner &#039;&#039;&#039;NICHT&#039;&#039;&#039; existieren, werden niemals angegriffen! Wenig ist hier mehr!&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Dieser Artikel basiert auf praktischen Erfahrungen aus dem Betrieb eines selbst gehosteten Servers mit OPNsense, Cisco-Switch und Docker-Stack.&#039;&#039;&lt;br /&gt;
&#039;&#039;Erstellt: Mai 2026&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=259</id>
		<title>Homeserver-Sicherheitsarchitektur</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=259"/>
		<updated>2026-05-27T23:44:52Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Motivation für einen Server mit OPNsense, Managed Switch und Docker */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Homeserver-Sicherheitsarchitektur: Aufbau, Funktionsweise und Diagnose ==&lt;br /&gt;
&lt;br /&gt;
Einen eigenen Server an&#039;s Internet zu bekommen, ist nicht allzu schwierig. Ein Dienst, der die eigene, vom Internet-Provider zugewiesene IP-Adresse in einen festen Domain-Namen umwandelt (siehe: [https://de.wikipedia.org/wiki/Dynamisches_DNS Dynamisches DNS]), wird im privaten Bereich die Voraussetzung sein.&lt;br /&gt;
Es gibt verschiedene Anbieter, oft auch kostenlose.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Der eigenen, von außen sichtbaren IP 78.123.234.45 wird vom DynDDS-Dienst die Domain &amp;lt;myhomeserver.dyndns.de&amp;gt; zugewiesen.&lt;br /&gt;
Einmal eingerichtet, wird der eigene Rechner antworten, wenn die Domain http://myhomeserver.dyndns.de in die Browser-Adressleiste einkopiert wird.&lt;br /&gt;
&lt;br /&gt;
=== Motivation für einen Server mit OPNsense, Managed Switch und Docker ===&lt;br /&gt;
&lt;br /&gt;
Die Kehrseite: Sowie der Server über&#039;s Internet erreichbar ist, ist er angreifbar.&lt;br /&gt;
Das ist kein theoretisches Szenario. Meiner Erfahrung nach ist es eine Frage von Stunden, bis die ersten Bots &amp;quot;anklopfen&amp;quot;, nach laufenden Diensten suchen, nach offenen Ports, nach Schwachstellen.&lt;br /&gt;
&lt;br /&gt;
Kurz: Eine öffentliche Erreichbarkeit des eigenen Servers über die ungesicherte Adresse...&lt;br /&gt;
&lt;br /&gt;
* http://myhomeserver.dyndns.de&lt;br /&gt;
&lt;br /&gt;
...wäre hochgradig fahrlässig.&lt;br /&gt;
&lt;br /&gt;
Aufgrund einer mangelhaften Konfiguration (offener Samba-Port) hatte ich die sehr reale Erfahrung einer russischen Hackerbande, die einige Hundert Textdateien mit Zahlungsaufforderungen und einen Verschlüsselungstrojaner auf meinem Rechner hinterlassen hatte. Gerettet hatten mich damals die Dateirechte von Linux. Das fehlende E(x)ecutional-Flag und die eingeschränkten Benutzerrechte hatten den Trojaner ausgebremst.&lt;br /&gt;
&lt;br /&gt;
Trotzdem: Nie wieder!&lt;br /&gt;
Ein wenig von dem, was ich gelernt habe, gebe ich ich hier weiter.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Einleitung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt den Aufbau einer &#039;&#039;&#039;sicheren&#039;&#039;&#039; Netzwerkarchitektur für einen Homeserver, der über das öffentliche Internet erreichbar ist. Der Beitrag richtet sich an alle, die ihre Daten selbst kontrollieren wollen — und dabei nicht unfreiwillig Teil einer globalen Angriffs-Infrastruktur werden möchten. Er will zum Verständnis beitragen, wie die einzelnen Komponenten zusammenspielen — und wie man systematisch vorgeht, wenn etwas nicht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der Fokus liegt nicht auf einer spezifischen Hardware-Konfiguration, sondern auf dem allgemeinen Prinzip: Wie kommt ein Request von außen sicher zu einem Docker-Container?&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Annahmen / Szenario ==&lt;br /&gt;
&lt;br /&gt;
Folgende Komponenten werden in diesem Artikel vorausgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver&#039;&#039;&#039; (Raspberry Pi, Intel NUC, oder beliebiger Linux-Server)&lt;br /&gt;
** Betriebssystem: Debian/Ubuntu oder vergleichbar&lt;br /&gt;
** Docker mit mehreren Diensten (z.B. WordPress, Nextcloud, MediaWiki)&lt;br /&gt;
** Caddy als Reverse Proxy (alternativ funktionieren [https://nginx.org/ nginx], [https://httpd.apache.org/ Apache], oder (ggf. kostenpflichtige) proprietäre Lösungen. Caddy allerdings hat das für mich charmante Feature, sich eigenständig um die TSL-Zertifikate und ihre Verlängerung bei LetsEncrypt zu kümmern. Wer aufgrund &amp;quot;zu vieler&amp;quot; Fehlversuche bei der Zertifikats-Einrichtung von LetsEncrypt auf Tage gesperrt wurde, wird mein Faible über diesen Automatismus nachvollziehen oder teilen können.)&lt;br /&gt;
** fail2ban als Brute-Force-Schutz&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;DynDNS-Dienst&#039;&#039;&#039; der dem Homeserver eine feste Domain zuweist&lt;br /&gt;
** Beispiel: &amp;lt;code&amp;gt;myhomeserver.dyndns.de&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Router / Heimnetz-Gateway&#039;&#039;&#039;&lt;br /&gt;
** Beispiel-IP: &amp;lt;code&amp;gt;192.168.2.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Portweiterleitung, WLAN, DynDNS-Aktualisierung&lt;br /&gt;
** Typisch: FritzBox, aber jeder Router mit Portweiterleitung funktioniert&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; (dedizierte Hardware-Firewall)&lt;br /&gt;
** WAN-Interface: &amp;lt;code&amp;gt;192.168.2.2&amp;lt;/code&amp;gt; (im Router-Netz)&lt;br /&gt;
** LAN-Interface / Server-VLAN: &amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Firewall, NAT, DHCP, IDS/IPS&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Managed Switch&#039;&#039;&#039; (optional, für VLAN-Segmentierung)&lt;br /&gt;
** Trennt Server-VLAN vom Rest des Netzes&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver-IP&#039;&#039;&#039;: &amp;lt;code&amp;gt;192.168.10.100&amp;lt;/code&amp;gt; (per DHCP-Reservation oder besser: Per statischer IP-Adresse fest)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 1: Wie funktionieren die Weiterleitungen? Wer macht was? ==&lt;br /&gt;
&lt;br /&gt;
=== Die Kette von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Ein Request von außen (z.B. Browser ruft &amp;lt;code&amp;gt;https://myhomeserver.dyndns.de&amp;lt;/code&amp;gt; auf) durchläuft folgende Stationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Internet&lt;br /&gt;
    ↓ DNS-Auflösung: dyndns.de → öffentliche IP des Heimnetzes&lt;br /&gt;
Router / Gateway (192.168.2.1)&lt;br /&gt;
    ↓ Portweiterleitung: :80 + :443 (und nur! diese!!) → 192.168.2.2&lt;br /&gt;
OPNsense WAN-Interface (192.168.2.2)&lt;br /&gt;
    ↓ Destination NAT: :80/:443 → 192.168.10.100&lt;br /&gt;
Homeserver eno1/eth0 (192.168.10.100)&lt;br /&gt;
    ↓ Docker-Port-Binding: 0.0.0.0:80 + 0.0.0.0:443&lt;br /&gt;
Caddy / Reverse Proxy (Docker-intern)&lt;br /&gt;
    ↓ Reverse Proxy anhand des Host-Headers&lt;br /&gt;
Ziel-Container (z.B. wordpress, nextcloud, ...)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit ist der Server auf der IP-Ebene (Layer 3 des OSI-Modells) von außen hin &amp;quot;unsichtbar&amp;quot;: Die Firewall (OPNsense) lebt, mit dem Gateway, im 192.168.2-er Netz. Von dort routet sie alle Anfragen über die Ports 80 und 443 an das Interface 192.168.10.100. Dahinter, also im 192.168.10-er-Subnetz, residiert der Heimserver.&lt;br /&gt;
&lt;br /&gt;
Am Ende dieses Beitrages gibt es Sicherheitshinweise. Bitte dringend beachten, dass der Router ausschließlich die Ports &#039;&#039;&#039;80/TCP&#039;&#039;&#039; und &#039;&#039;&#039;443/TCP&#039;&#039;&#039; nach außen frei gibt. Der Webserver wird dabei so konfiguriert, dass HTTP-Daten über Port 80 nach HTTPS auf Port 443 umgeleitet werden.&lt;br /&gt;
&lt;br /&gt;
Die Idee, ausschließlich HTTPS zuzulassen, läge nahe. Damit bräuchte sich der Webserver nicht um die Weiterleitung auf Port 443 zu befassen.&lt;br /&gt;
Bedauerlicherweise wird in diesem Fall der Umgang mit dem TLS-Zertifikat, das den HTTPS-Datenstrom verschlüsselt, scheitern. [https://letsencrypt.org/ LetsEncrypt] benötigt bei Einrichtung und Verlängerung seiner Zertifikate einen offenen 80-er Port.&lt;br /&gt;
&lt;br /&gt;
Sollte es nötig sein, den Server von außen zu administrieren, wird man darüber nachdenken, einen VPN-Tunnel einzurichten. Sicherer jedoch - und einfacher - ist es dennoch, die Administration ausschließlich über einen zertifikats-geschützten SSH-Zugang im inneren 192.168.-er-Netz zuzulassen und, abgesehen von 80 und 443, auf jeden nach außen exponierten Port zu verzichten.&lt;br /&gt;
&lt;br /&gt;
=== Wer macht was? ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Komponente !! Aufgabe !! Konfigurationsort&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Router / Gateway&#039;&#039;&#039; || DynDNS-Aktualisierung, erste NAT-Stufe, WLAN || Router Web-UI → Portfreigaben&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; || Firewall-Regeln, zweite NAT-Stufe (Destination NAT), DHCP für Server-VLAN || OPNsense Web-UI (Standard: https://&amp;amp;lt;wan-ip&amp;amp;gt;:443 oder :8443)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Caddy / Reverse Proxy&#039;&#039;&#039; || TLS-Terminierung, Let&#039;s Encrypt, Weiterleitung an Container || Caddyfile auf dem Homeserver&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Docker&#039;&#039;&#039; || Container-Isolation, internes Netz (Standard: 172.18.0.0/16) || docker-compose.yml pro Dienst&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fail2ban&#039;&#039;&#039; || Brute-Force-Schutz auf Applikationsebene || Jail-Configs im fail2ban-Container&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Wichtig: OPNsense hat ZWEI Firewall-Engines ===&lt;br /&gt;
&lt;br /&gt;
OPNsense 26.x hat zwei parallele Regelwerke:&lt;br /&gt;
* &#039;&#039;&#039;Rules [new]&#039;&#039;&#039; — neue API-basierte Engine&lt;br /&gt;
* &#039;&#039;&#039;Rules&#039;&#039;&#039; — alte Engine (Legacy)&lt;br /&gt;
&lt;br /&gt;
Neue Regeln &#039;&#039;&#039;immer in beiden&#039;&#039;&#039; anlegen! Bei Problemen immer beide prüfen.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 2: Wo steht was? ==&lt;br /&gt;
&lt;br /&gt;
=== IP-Adressen (Beispiel-Setup) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Gerät !! Interface !! IP !! Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
| Router / Gateway || — || 192.168.2.1 || Gateway, WLAN, DynDNS&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense WAN || wan-interface || 192.168.2.2 || Statisch konfiguriert&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense LAN / Server-VLAN || lan-interface || 192.168.10.1 || Gateway für Server-Netz&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver || eno1 / eth0 || 192.168.10.100 || Fest per DHCP-Reservation (MAC-Adresse)&lt;br /&gt;
|-&lt;br /&gt;
| Client-Geräte || WLAN || 192.168.2.x || Im Router-Netz, nicht im Server-VLAN&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Homeserver: Netzwerk-Interface-Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Der Homeserver bezieht seine IP per DHCP vom OPNsense-DHCP-Server. Bei Debian/Ubuntu mit systemd-networkd:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/systemd/network/10-eth0.network&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Korrekter Inhalt (DHCP):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[Match]&lt;br /&gt;
Name=eno1&lt;br /&gt;
&lt;br /&gt;
[Network]&lt;br /&gt;
DHCP=ipv4&lt;br /&gt;
&lt;br /&gt;
[DHCP]&lt;br /&gt;
RouteMetric=100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ &#039;&#039;&#039;Niemals&#039;&#039;&#039; eine statische IP oder einen Gateway manuell eintragen!&lt;br /&gt;
Der Default-Gateway kommt immer vom DHCP-Server der OPNsense-Firewall (&amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Kea DHCP Lease-Datei (OPNsense) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/db/kea/kea-leases4.csv&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier verwaltet Kea die aktiven Leases. Bei Problemen mit doppelten IPs kann diese Datei (nach &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;) auf den Header reduziert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context,pool_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 3: Systematische Diagnose — Schritt für Schritt ==&lt;br /&gt;
&lt;br /&gt;
=== Grundprinzip: Von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Immer von außen nach innen vorgehen — nie raten, immer messen. Jede Schicht einzeln prüfen.&lt;br /&gt;
&lt;br /&gt;
==== Schritt 1: Ist OPNsense überhaupt erreichbar? ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Vom Client-Rechner:&lt;br /&gt;
ping 192.168.2.2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ OPNsense antwortet standardmäßig &#039;&#039;&#039;nicht&#039;&#039;&#039; auf ICMP/Ping von außen — das ist korrekt!&lt;br /&gt;
&lt;br /&gt;
Stattdessen prüfen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Web-UI erreichbar?&lt;br /&gt;
https://192.168.2.2:8443&lt;br /&gt;
&lt;br /&gt;
# Router zeigt OPNsense als verbundenes Gerät?&lt;br /&gt;
http://192.168.2.1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 2: OPNsense intern prüfen ====&lt;br /&gt;
&lt;br /&gt;
Per SSH oder serieller Konsole auf OPNsense:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# WAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;wan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.2.2, status: active&lt;br /&gt;
&lt;br /&gt;
# LAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;lan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.10.1, status: active&lt;br /&gt;
&lt;br /&gt;
# Router erreichbar?&lt;br /&gt;
ping -c 3 192.168.2.1&lt;br /&gt;
&lt;br /&gt;
# Homeserver erreichbar?&lt;br /&gt;
ping -c 3 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 3: Homeserver direkt prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# SSH auf Homeserver:&lt;br /&gt;
ssh root@192.168.10.100&lt;br /&gt;
&lt;br /&gt;
# Alle Container laufen?&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# Internet vom Homeserver aus erreichbar?&lt;br /&gt;
ping -c 3 9.9.9.9&lt;br /&gt;
&lt;br /&gt;
# Routing-Tabelle korrekt?&lt;br /&gt;
ip route show&lt;br /&gt;
# Erwartete Default-Route: default via 192.168.10.1 dev eno1&lt;br /&gt;
# NICHT: default via 192.168.178.x — das wäre falsch!&lt;br /&gt;
&lt;br /&gt;
# Welche IP hat das Interface?&lt;br /&gt;
ip addr show eno1&lt;br /&gt;
# Erwartete IP: 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 4: Caddy / Reverse Proxy prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Läuft Caddy und antwortet er lokal?&lt;br /&gt;
curl -v http://localhost&lt;br /&gt;
# Erwartete Antwort: HTTP 308 Redirect → https://localhost/&lt;br /&gt;
&lt;br /&gt;
# Caddy-Logs auf Fehler prüfen:&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Typische Fehler in den Caddy-Logs:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fehlermeldung !! Bedeutung !! Lösung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dial tcp ...:443: connect: no route to host&amp;lt;/code&amp;gt; || Caddy kommt nicht ins Internet (Let&#039;s Encrypt nicht erreichbar) || Routing auf Homeserver prüfen (Schritt 3)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;no route to host&amp;lt;/code&amp;gt; bei Ping auf 9.9.9.9 || Falscher Default-Gateway || &amp;lt;code&amp;gt;ip route show&amp;lt;/code&amp;gt; prüfen, falsche Route entfernen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Schritt 5: NAT und Firewall-Regeln prüfen (OPNsense Shell) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# NAT-Regeln anzeigen:&lt;br /&gt;
pfctl -s nat | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Firewall-Regeln anzeigen:&lt;br /&gt;
pfctl -s rules | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf WAN-Interface beobachten (kommt der Request an?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;wan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf LAN-Interface beobachten (wird er weitergeleitet?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;lan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Diagnose-Logik:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tcpdump WAN sieht Traffic, LAN nicht → NAT-Regel prüfen!&lt;br /&gt;
tcpdump WAN sieht keinen Traffic    → Portweiterleitung im Router prüfen!&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 6: Bekannte Fallstricke ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Problem !! Symptom !! Ursache !! Fix&lt;br /&gt;
|-&lt;br /&gt;
| Falsche statische Route || &amp;lt;code&amp;gt;ping 9.9.9.9&amp;lt;/code&amp;gt; schlägt fehl || Netzwerk-Config hat statischen Gateway eingetragen || Auf DHCP umstellen, &amp;lt;code&amp;gt;systemctl restart systemd-networkd&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver hat falsche IP || NAT-Regeln greifen nicht || DHCP hat beim Neustart temporär andere IP vergeben || DHCP-Reservation per MAC-Adresse einrichten&lt;br /&gt;
|-&lt;br /&gt;
| DHCP-Leases durcheinander || Server taucht mit zwei IPs auf || Neustart hat neuen Lease vor Ablauf des alten erzeugt || &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;, Lease-CSV bereinigen, &amp;lt;code&amp;gt;configctl kea start&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense Firewall-Regel fehlt || Dienste von außen nicht erreichbar, intern OK || Regel nur in einer der beiden Engines angelegt || Regel in &#039;&#039;&#039;beiden&#039;&#039;&#039; Engines anlegen (Rules [new] + Rules)&lt;br /&gt;
|-&lt;br /&gt;
| NAT-Regel ohne Subnetz-Maske || Traffic kommt nicht an || &amp;lt;code&amp;gt;192.168.178.0&amp;lt;/code&amp;gt; statt &amp;lt;code&amp;gt;192.168.178.0/24&amp;lt;/code&amp;gt; eingetragen || Subnetz-Maske ergänzen — ohne /24 gilt nur die Netzadresse selbst!&lt;br /&gt;
|-&lt;br /&gt;
| Source/Destination Port vertauscht || Verbindungen werden blockiert || Bei Firewall-Regel Port unter &amp;quot;Source&amp;quot; statt &amp;quot;Destination&amp;quot; eingetragen || Source Port: any / Destination Port: gewünschter Port&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Notfall-Cheatsheet ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# OPNsense: Firewall temporär deaktivieren (Notfall!)&lt;br /&gt;
pfctl -d&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Firewall wieder aktivieren&lt;br /&gt;
pfctl -e&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Kea DHCP stoppen/starten&lt;br /&gt;
configctl kea stop&lt;br /&gt;
configctl kea start&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Falsche Default-Route entfernen&lt;br /&gt;
ip route del default via &amp;amp;lt;falsche-gateway-ip&amp;amp;gt; dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: IP manuell setzen (Sofortlösung bei DHCP-Problemen)&lt;br /&gt;
ip addr add 192.168.10.100/24 dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Netzwerk-Dienst neu starten (Verbindung kurz weg!)&lt;br /&gt;
systemctl restart systemd-networkd&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Docker-Logs prüfen&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Alias-Tabellen prüfen (Blocklisten)&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | wc -l&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | grep &amp;amp;lt;IP&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Sicherheitshinweise ==&lt;br /&gt;
&lt;br /&gt;
* SSH-Ports &#039;&#039;&#039;nicht&#039;&#039;&#039; über das Internet freigeben — nur intern erreichbar lassen! Wenn das nicht geht: VPN-Tunnel!&lt;br /&gt;
* Portweiterleitung im Router auf das &#039;&#039;&#039;Minimum&#039;&#039;&#039; beschränken (nur die Ports 80 + 443 öffnen)&lt;br /&gt;
* Für interne Admin-Interfaces (OPNsense Web-UI, Monitoring) &#039;&#039;&#039;keine externen Freigaben&#039;&#039;&#039;&lt;br /&gt;
* DHCP-Reservations per MAC-Adresse oder statische IP-Adressen verhindern IP-Wechsel nach Neustarts&lt;br /&gt;
* Bei Firewall-Regeln: Block-Regeln &#039;&#039;&#039;immer&#039;&#039;&#039; vor Pass-Regeln platzieren&lt;br /&gt;
&lt;br /&gt;
Abschließend eine absolute Regel, die immer und durch die Ewigkeiten gilt:&lt;br /&gt;
* Dienste, die auf einem Rechner &#039;&#039;&#039;NICHT&#039;&#039;&#039; existieren, werden niemals angegriffen! Wenig ist hier mehr!&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Dieser Artikel basiert auf praktischen Erfahrungen aus dem Betrieb eines selbst gehosteten Servers mit OPNsense, Cisco-Switch und Docker-Stack.&#039;&#039;&lt;br /&gt;
&#039;&#039;Erstellt: Mai 2026&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=258</id>
		<title>Homeserver-Sicherheitsarchitektur</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=258"/>
		<updated>2026-05-27T23:43:44Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Homeserver-Sicherheitsarchitektur: Aufbau, Funktionsweise und Diagnose */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Homeserver-Sicherheitsarchitektur: Aufbau, Funktionsweise und Diagnose ==&lt;br /&gt;
&lt;br /&gt;
Einen eigenen Server an&#039;s Internet zu bekommen, ist nicht allzu schwierig. Ein Dienst, der die eigene, vom Internet-Provider zugewiesene IP-Adresse in einen festen Domain-Namen umwandelt (siehe: [https://de.wikipedia.org/wiki/Dynamisches_DNS Dynamisches DNS]), wird im privaten Bereich die Voraussetzung sein.&lt;br /&gt;
Es gibt verschiedene Anbieter, oft auch kostenlose.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Der eigenen, von außen sichtbaren IP 78.123.234.45 wird vom DynDDS-Dienst die Domain &amp;lt;myhomeserver.dyndns.de&amp;gt; zugewiesen.&lt;br /&gt;
Einmal eingerichtet, wird der eigene Rechner antworten, wenn die Domain http://myhomeserver.dyndns.de in die Browser-Adressleiste einkopiert wird.&lt;br /&gt;
&lt;br /&gt;
=== Motivation für einen Server mit OPNsense, Managed Switch und Docker ===&lt;br /&gt;
&lt;br /&gt;
Die Kehrseite: Sowie der Server über&#039;s Internet erreichbar ist, ist er angreifbar.&lt;br /&gt;
Das ist kein theoretisches Szenario. Meiner Erfahrung nach ist es eine Frage von Stunden, bis die ersten Bots &amp;quot;anklopfen&amp;quot;, nach laufenden Diensten suchen, nach offenen Ports, nach Schwachstellen.&lt;br /&gt;
&lt;br /&gt;
Kurz: Die öffentliche Erreichbarkeit des eigenen Servers über die ungesicherte Adresse...&lt;br /&gt;
&lt;br /&gt;
* http://myhomeserver.dyndns.de&lt;br /&gt;
&lt;br /&gt;
...ist fahrlässig.&lt;br /&gt;
&lt;br /&gt;
Aufgrund einer mangelhaften Konfiguration (offener Samba-Port) hatte ich die sehr reale Erfahrung einer russischen Hackerbande, die einige Hundert Textdateien mit Zahlungsaufforderungen und einen Verschlüsselungstrojaner auf meinem Rechner hinterlassen hatte. Gerettet hatten mich damals die Dateirechte von Linux. Das fehlende E(x)ecutional-Flag und die eingeschränkten Benutzerrechte hatten den Trojaner ausgebremst.&lt;br /&gt;
&lt;br /&gt;
Trotzdem: Nie wieder!&lt;br /&gt;
Ein wenig von dem, was ich gelernt habe, gebe ich ich hier weiter.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Einleitung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt den Aufbau einer &#039;&#039;&#039;sicheren&#039;&#039;&#039; Netzwerkarchitektur für einen Homeserver, der über das öffentliche Internet erreichbar ist. Der Beitrag richtet sich an alle, die ihre Daten selbst kontrollieren wollen — und dabei nicht unfreiwillig Teil einer globalen Angriffs-Infrastruktur werden möchten. Er will zum Verständnis beitragen, wie die einzelnen Komponenten zusammenspielen — und wie man systematisch vorgeht, wenn etwas nicht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der Fokus liegt nicht auf einer spezifischen Hardware-Konfiguration, sondern auf dem allgemeinen Prinzip: Wie kommt ein Request von außen sicher zu einem Docker-Container?&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Annahmen / Szenario ==&lt;br /&gt;
&lt;br /&gt;
Folgende Komponenten werden in diesem Artikel vorausgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver&#039;&#039;&#039; (Raspberry Pi, Intel NUC, oder beliebiger Linux-Server)&lt;br /&gt;
** Betriebssystem: Debian/Ubuntu oder vergleichbar&lt;br /&gt;
** Docker mit mehreren Diensten (z.B. WordPress, Nextcloud, MediaWiki)&lt;br /&gt;
** Caddy als Reverse Proxy (alternativ funktionieren [https://nginx.org/ nginx], [https://httpd.apache.org/ Apache], oder (ggf. kostenpflichtige) proprietäre Lösungen. Caddy allerdings hat das für mich charmante Feature, sich eigenständig um die TSL-Zertifikate und ihre Verlängerung bei LetsEncrypt zu kümmern. Wer aufgrund &amp;quot;zu vieler&amp;quot; Fehlversuche bei der Zertifikats-Einrichtung von LetsEncrypt auf Tage gesperrt wurde, wird mein Faible über diesen Automatismus nachvollziehen oder teilen können.)&lt;br /&gt;
** fail2ban als Brute-Force-Schutz&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;DynDNS-Dienst&#039;&#039;&#039; der dem Homeserver eine feste Domain zuweist&lt;br /&gt;
** Beispiel: &amp;lt;code&amp;gt;myhomeserver.dyndns.de&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Router / Heimnetz-Gateway&#039;&#039;&#039;&lt;br /&gt;
** Beispiel-IP: &amp;lt;code&amp;gt;192.168.2.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Portweiterleitung, WLAN, DynDNS-Aktualisierung&lt;br /&gt;
** Typisch: FritzBox, aber jeder Router mit Portweiterleitung funktioniert&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; (dedizierte Hardware-Firewall)&lt;br /&gt;
** WAN-Interface: &amp;lt;code&amp;gt;192.168.2.2&amp;lt;/code&amp;gt; (im Router-Netz)&lt;br /&gt;
** LAN-Interface / Server-VLAN: &amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Firewall, NAT, DHCP, IDS/IPS&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Managed Switch&#039;&#039;&#039; (optional, für VLAN-Segmentierung)&lt;br /&gt;
** Trennt Server-VLAN vom Rest des Netzes&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver-IP&#039;&#039;&#039;: &amp;lt;code&amp;gt;192.168.10.100&amp;lt;/code&amp;gt; (per DHCP-Reservation oder besser: Per statischer IP-Adresse fest)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 1: Wie funktionieren die Weiterleitungen? Wer macht was? ==&lt;br /&gt;
&lt;br /&gt;
=== Die Kette von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Ein Request von außen (z.B. Browser ruft &amp;lt;code&amp;gt;https://myhomeserver.dyndns.de&amp;lt;/code&amp;gt; auf) durchläuft folgende Stationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Internet&lt;br /&gt;
    ↓ DNS-Auflösung: dyndns.de → öffentliche IP des Heimnetzes&lt;br /&gt;
Router / Gateway (192.168.2.1)&lt;br /&gt;
    ↓ Portweiterleitung: :80 + :443 (und nur! diese!!) → 192.168.2.2&lt;br /&gt;
OPNsense WAN-Interface (192.168.2.2)&lt;br /&gt;
    ↓ Destination NAT: :80/:443 → 192.168.10.100&lt;br /&gt;
Homeserver eno1/eth0 (192.168.10.100)&lt;br /&gt;
    ↓ Docker-Port-Binding: 0.0.0.0:80 + 0.0.0.0:443&lt;br /&gt;
Caddy / Reverse Proxy (Docker-intern)&lt;br /&gt;
    ↓ Reverse Proxy anhand des Host-Headers&lt;br /&gt;
Ziel-Container (z.B. wordpress, nextcloud, ...)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit ist der Server auf der IP-Ebene (Layer 3 des OSI-Modells) von außen hin &amp;quot;unsichtbar&amp;quot;: Die Firewall (OPNsense) lebt, mit dem Gateway, im 192.168.2-er Netz. Von dort routet sie alle Anfragen über die Ports 80 und 443 an das Interface 192.168.10.100. Dahinter, also im 192.168.10-er-Subnetz, residiert der Heimserver.&lt;br /&gt;
&lt;br /&gt;
Am Ende dieses Beitrages gibt es Sicherheitshinweise. Bitte dringend beachten, dass der Router ausschließlich die Ports &#039;&#039;&#039;80/TCP&#039;&#039;&#039; und &#039;&#039;&#039;443/TCP&#039;&#039;&#039; nach außen frei gibt. Der Webserver wird dabei so konfiguriert, dass HTTP-Daten über Port 80 nach HTTPS auf Port 443 umgeleitet werden.&lt;br /&gt;
&lt;br /&gt;
Die Idee, ausschließlich HTTPS zuzulassen, läge nahe. Damit bräuchte sich der Webserver nicht um die Weiterleitung auf Port 443 zu befassen.&lt;br /&gt;
Bedauerlicherweise wird in diesem Fall der Umgang mit dem TLS-Zertifikat, das den HTTPS-Datenstrom verschlüsselt, scheitern. [https://letsencrypt.org/ LetsEncrypt] benötigt bei Einrichtung und Verlängerung seiner Zertifikate einen offenen 80-er Port.&lt;br /&gt;
&lt;br /&gt;
Sollte es nötig sein, den Server von außen zu administrieren, wird man darüber nachdenken, einen VPN-Tunnel einzurichten. Sicherer jedoch - und einfacher - ist es dennoch, die Administration ausschließlich über einen zertifikats-geschützten SSH-Zugang im inneren 192.168.-er-Netz zuzulassen und, abgesehen von 80 und 443, auf jeden nach außen exponierten Port zu verzichten.&lt;br /&gt;
&lt;br /&gt;
=== Wer macht was? ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Komponente !! Aufgabe !! Konfigurationsort&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Router / Gateway&#039;&#039;&#039; || DynDNS-Aktualisierung, erste NAT-Stufe, WLAN || Router Web-UI → Portfreigaben&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; || Firewall-Regeln, zweite NAT-Stufe (Destination NAT), DHCP für Server-VLAN || OPNsense Web-UI (Standard: https://&amp;amp;lt;wan-ip&amp;amp;gt;:443 oder :8443)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Caddy / Reverse Proxy&#039;&#039;&#039; || TLS-Terminierung, Let&#039;s Encrypt, Weiterleitung an Container || Caddyfile auf dem Homeserver&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Docker&#039;&#039;&#039; || Container-Isolation, internes Netz (Standard: 172.18.0.0/16) || docker-compose.yml pro Dienst&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fail2ban&#039;&#039;&#039; || Brute-Force-Schutz auf Applikationsebene || Jail-Configs im fail2ban-Container&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Wichtig: OPNsense hat ZWEI Firewall-Engines ===&lt;br /&gt;
&lt;br /&gt;
OPNsense 26.x hat zwei parallele Regelwerke:&lt;br /&gt;
* &#039;&#039;&#039;Rules [new]&#039;&#039;&#039; — neue API-basierte Engine&lt;br /&gt;
* &#039;&#039;&#039;Rules&#039;&#039;&#039; — alte Engine (Legacy)&lt;br /&gt;
&lt;br /&gt;
Neue Regeln &#039;&#039;&#039;immer in beiden&#039;&#039;&#039; anlegen! Bei Problemen immer beide prüfen.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 2: Wo steht was? ==&lt;br /&gt;
&lt;br /&gt;
=== IP-Adressen (Beispiel-Setup) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Gerät !! Interface !! IP !! Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
| Router / Gateway || — || 192.168.2.1 || Gateway, WLAN, DynDNS&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense WAN || wan-interface || 192.168.2.2 || Statisch konfiguriert&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense LAN / Server-VLAN || lan-interface || 192.168.10.1 || Gateway für Server-Netz&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver || eno1 / eth0 || 192.168.10.100 || Fest per DHCP-Reservation (MAC-Adresse)&lt;br /&gt;
|-&lt;br /&gt;
| Client-Geräte || WLAN || 192.168.2.x || Im Router-Netz, nicht im Server-VLAN&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Homeserver: Netzwerk-Interface-Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Der Homeserver bezieht seine IP per DHCP vom OPNsense-DHCP-Server. Bei Debian/Ubuntu mit systemd-networkd:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/systemd/network/10-eth0.network&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Korrekter Inhalt (DHCP):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[Match]&lt;br /&gt;
Name=eno1&lt;br /&gt;
&lt;br /&gt;
[Network]&lt;br /&gt;
DHCP=ipv4&lt;br /&gt;
&lt;br /&gt;
[DHCP]&lt;br /&gt;
RouteMetric=100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ &#039;&#039;&#039;Niemals&#039;&#039;&#039; eine statische IP oder einen Gateway manuell eintragen!&lt;br /&gt;
Der Default-Gateway kommt immer vom DHCP-Server der OPNsense-Firewall (&amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Kea DHCP Lease-Datei (OPNsense) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/db/kea/kea-leases4.csv&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier verwaltet Kea die aktiven Leases. Bei Problemen mit doppelten IPs kann diese Datei (nach &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;) auf den Header reduziert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context,pool_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 3: Systematische Diagnose — Schritt für Schritt ==&lt;br /&gt;
&lt;br /&gt;
=== Grundprinzip: Von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Immer von außen nach innen vorgehen — nie raten, immer messen. Jede Schicht einzeln prüfen.&lt;br /&gt;
&lt;br /&gt;
==== Schritt 1: Ist OPNsense überhaupt erreichbar? ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Vom Client-Rechner:&lt;br /&gt;
ping 192.168.2.2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ OPNsense antwortet standardmäßig &#039;&#039;&#039;nicht&#039;&#039;&#039; auf ICMP/Ping von außen — das ist korrekt!&lt;br /&gt;
&lt;br /&gt;
Stattdessen prüfen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Web-UI erreichbar?&lt;br /&gt;
https://192.168.2.2:8443&lt;br /&gt;
&lt;br /&gt;
# Router zeigt OPNsense als verbundenes Gerät?&lt;br /&gt;
http://192.168.2.1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 2: OPNsense intern prüfen ====&lt;br /&gt;
&lt;br /&gt;
Per SSH oder serieller Konsole auf OPNsense:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# WAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;wan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.2.2, status: active&lt;br /&gt;
&lt;br /&gt;
# LAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;lan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.10.1, status: active&lt;br /&gt;
&lt;br /&gt;
# Router erreichbar?&lt;br /&gt;
ping -c 3 192.168.2.1&lt;br /&gt;
&lt;br /&gt;
# Homeserver erreichbar?&lt;br /&gt;
ping -c 3 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 3: Homeserver direkt prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# SSH auf Homeserver:&lt;br /&gt;
ssh root@192.168.10.100&lt;br /&gt;
&lt;br /&gt;
# Alle Container laufen?&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# Internet vom Homeserver aus erreichbar?&lt;br /&gt;
ping -c 3 9.9.9.9&lt;br /&gt;
&lt;br /&gt;
# Routing-Tabelle korrekt?&lt;br /&gt;
ip route show&lt;br /&gt;
# Erwartete Default-Route: default via 192.168.10.1 dev eno1&lt;br /&gt;
# NICHT: default via 192.168.178.x — das wäre falsch!&lt;br /&gt;
&lt;br /&gt;
# Welche IP hat das Interface?&lt;br /&gt;
ip addr show eno1&lt;br /&gt;
# Erwartete IP: 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 4: Caddy / Reverse Proxy prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Läuft Caddy und antwortet er lokal?&lt;br /&gt;
curl -v http://localhost&lt;br /&gt;
# Erwartete Antwort: HTTP 308 Redirect → https://localhost/&lt;br /&gt;
&lt;br /&gt;
# Caddy-Logs auf Fehler prüfen:&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Typische Fehler in den Caddy-Logs:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fehlermeldung !! Bedeutung !! Lösung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dial tcp ...:443: connect: no route to host&amp;lt;/code&amp;gt; || Caddy kommt nicht ins Internet (Let&#039;s Encrypt nicht erreichbar) || Routing auf Homeserver prüfen (Schritt 3)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;no route to host&amp;lt;/code&amp;gt; bei Ping auf 9.9.9.9 || Falscher Default-Gateway || &amp;lt;code&amp;gt;ip route show&amp;lt;/code&amp;gt; prüfen, falsche Route entfernen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Schritt 5: NAT und Firewall-Regeln prüfen (OPNsense Shell) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# NAT-Regeln anzeigen:&lt;br /&gt;
pfctl -s nat | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Firewall-Regeln anzeigen:&lt;br /&gt;
pfctl -s rules | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf WAN-Interface beobachten (kommt der Request an?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;wan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf LAN-Interface beobachten (wird er weitergeleitet?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;lan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Diagnose-Logik:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tcpdump WAN sieht Traffic, LAN nicht → NAT-Regel prüfen!&lt;br /&gt;
tcpdump WAN sieht keinen Traffic    → Portweiterleitung im Router prüfen!&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 6: Bekannte Fallstricke ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Problem !! Symptom !! Ursache !! Fix&lt;br /&gt;
|-&lt;br /&gt;
| Falsche statische Route || &amp;lt;code&amp;gt;ping 9.9.9.9&amp;lt;/code&amp;gt; schlägt fehl || Netzwerk-Config hat statischen Gateway eingetragen || Auf DHCP umstellen, &amp;lt;code&amp;gt;systemctl restart systemd-networkd&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver hat falsche IP || NAT-Regeln greifen nicht || DHCP hat beim Neustart temporär andere IP vergeben || DHCP-Reservation per MAC-Adresse einrichten&lt;br /&gt;
|-&lt;br /&gt;
| DHCP-Leases durcheinander || Server taucht mit zwei IPs auf || Neustart hat neuen Lease vor Ablauf des alten erzeugt || &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;, Lease-CSV bereinigen, &amp;lt;code&amp;gt;configctl kea start&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense Firewall-Regel fehlt || Dienste von außen nicht erreichbar, intern OK || Regel nur in einer der beiden Engines angelegt || Regel in &#039;&#039;&#039;beiden&#039;&#039;&#039; Engines anlegen (Rules [new] + Rules)&lt;br /&gt;
|-&lt;br /&gt;
| NAT-Regel ohne Subnetz-Maske || Traffic kommt nicht an || &amp;lt;code&amp;gt;192.168.178.0&amp;lt;/code&amp;gt; statt &amp;lt;code&amp;gt;192.168.178.0/24&amp;lt;/code&amp;gt; eingetragen || Subnetz-Maske ergänzen — ohne /24 gilt nur die Netzadresse selbst!&lt;br /&gt;
|-&lt;br /&gt;
| Source/Destination Port vertauscht || Verbindungen werden blockiert || Bei Firewall-Regel Port unter &amp;quot;Source&amp;quot; statt &amp;quot;Destination&amp;quot; eingetragen || Source Port: any / Destination Port: gewünschter Port&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Notfall-Cheatsheet ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# OPNsense: Firewall temporär deaktivieren (Notfall!)&lt;br /&gt;
pfctl -d&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Firewall wieder aktivieren&lt;br /&gt;
pfctl -e&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Kea DHCP stoppen/starten&lt;br /&gt;
configctl kea stop&lt;br /&gt;
configctl kea start&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Falsche Default-Route entfernen&lt;br /&gt;
ip route del default via &amp;amp;lt;falsche-gateway-ip&amp;amp;gt; dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: IP manuell setzen (Sofortlösung bei DHCP-Problemen)&lt;br /&gt;
ip addr add 192.168.10.100/24 dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Netzwerk-Dienst neu starten (Verbindung kurz weg!)&lt;br /&gt;
systemctl restart systemd-networkd&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Docker-Logs prüfen&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Alias-Tabellen prüfen (Blocklisten)&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | wc -l&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | grep &amp;amp;lt;IP&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Sicherheitshinweise ==&lt;br /&gt;
&lt;br /&gt;
* SSH-Ports &#039;&#039;&#039;nicht&#039;&#039;&#039; über das Internet freigeben — nur intern erreichbar lassen! Wenn das nicht geht: VPN-Tunnel!&lt;br /&gt;
* Portweiterleitung im Router auf das &#039;&#039;&#039;Minimum&#039;&#039;&#039; beschränken (nur die Ports 80 + 443 öffnen)&lt;br /&gt;
* Für interne Admin-Interfaces (OPNsense Web-UI, Monitoring) &#039;&#039;&#039;keine externen Freigaben&#039;&#039;&#039;&lt;br /&gt;
* DHCP-Reservations per MAC-Adresse oder statische IP-Adressen verhindern IP-Wechsel nach Neustarts&lt;br /&gt;
* Bei Firewall-Regeln: Block-Regeln &#039;&#039;&#039;immer&#039;&#039;&#039; vor Pass-Regeln platzieren&lt;br /&gt;
&lt;br /&gt;
Abschließend eine absolute Regel, die immer und durch die Ewigkeiten gilt:&lt;br /&gt;
* Dienste, die auf einem Rechner &#039;&#039;&#039;NICHT&#039;&#039;&#039; existieren, werden niemals angegriffen! Wenig ist hier mehr!&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Dieser Artikel basiert auf praktischen Erfahrungen aus dem Betrieb eines selbst gehosteten Servers mit OPNsense, Cisco-Switch und Docker-Stack.&#039;&#039;&lt;br /&gt;
&#039;&#039;Erstellt: Mai 2026&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=257</id>
		<title>Homeserver-Sicherheitsarchitektur</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=257"/>
		<updated>2026-05-27T23:43:04Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Ein Leitfaden für selbst gehostete Server mit OPNsense, Managed Switch und Docker */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Homeserver-Sicherheitsarchitektur: Aufbau, Funktionsweise und Diagnose ==&lt;br /&gt;
&lt;br /&gt;
Einen eigenen Server an&#039;s Internet zu bekommen, ist nicht allzu schwierig. Ein Dienst, der die eigene, vom Internet-Provider zugewiesene IP-Adresse in einen festen Domain-Namen umwandelt (siehe: [https://de.wikipedia.org/wiki/Dynamisches_DNS Dynamisches DNS]), wird im privaten Bereich die Voraussetzung sein.&lt;br /&gt;
Es gibt verschiedene Anbieter, oft auch kostenlose.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Der eigenen, von außen sichtbaren IP 78.123.234.45 wird vom DynDDS-Dienst die Domain &amp;lt;myhomeserver.dyndns.de&amp;gt; zugewiesen.&lt;br /&gt;
Einmal eingerichtet, wird der eigene Rechner antworten, wenn die Domain http://myhomeserver.dyndns.de in die Browser-Adressleiste einkopiert wird.&lt;br /&gt;
&lt;br /&gt;
=== Motivation für einen Server mit OPNsense, Managed Switch und Docker ===&lt;br /&gt;
&lt;br /&gt;
Die Kehrseite: Sowie der Server über&#039;s Internet erreichbar ist, ist er angreifbar.&lt;br /&gt;
Das ist kein theoretisches Szenario. Meiner Erfahrung nach ist es eine Frage von Stunden, bis die ersten Bots &amp;quot;anklopfen&amp;quot;, nach laufenden Diensten suchen, nach offenen Ports, nach Schwachstellen.&lt;br /&gt;
Die öffentliche Erreichbarkeit des eigenen Servers über die ungesicherte Adresse...&lt;br /&gt;
* http://myhomeserver.dyndns.de&lt;br /&gt;
...ist fahrlässig.&lt;br /&gt;
&lt;br /&gt;
Aufgrund einer mangelhaften Konfiguration (offener Samba-Port) hatte ich die sehr reale Erfahrung einer russischen Hackerbande, die einige Hundert Textdateien mit Zahlungsaufforderungen und einen Verschlüsselungstrojaner auf meinem Rechner hinterlassen hatte. Gerettet hatten mich damals die Dateirechte von Linux. Das fehlende E(x)ecutional-Flag und die eingeschränkten Benutzerrechte hatten den Trojaner ausgebremst.&lt;br /&gt;
&lt;br /&gt;
Trotzdem: Nie wieder!&lt;br /&gt;
Ein wenig von dem, was ich gelernt habe, gebe ich ich hier weiter.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Einleitung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt den Aufbau einer &#039;&#039;&#039;sicheren&#039;&#039;&#039; Netzwerkarchitektur für einen Homeserver, der über das öffentliche Internet erreichbar ist. Der Beitrag richtet sich an alle, die ihre Daten selbst kontrollieren wollen — und dabei nicht unfreiwillig Teil einer globalen Angriffs-Infrastruktur werden möchten. Er will zum Verständnis beitragen, wie die einzelnen Komponenten zusammenspielen — und wie man systematisch vorgeht, wenn etwas nicht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der Fokus liegt nicht auf einer spezifischen Hardware-Konfiguration, sondern auf dem allgemeinen Prinzip: Wie kommt ein Request von außen sicher zu einem Docker-Container?&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Annahmen / Szenario ==&lt;br /&gt;
&lt;br /&gt;
Folgende Komponenten werden in diesem Artikel vorausgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver&#039;&#039;&#039; (Raspberry Pi, Intel NUC, oder beliebiger Linux-Server)&lt;br /&gt;
** Betriebssystem: Debian/Ubuntu oder vergleichbar&lt;br /&gt;
** Docker mit mehreren Diensten (z.B. WordPress, Nextcloud, MediaWiki)&lt;br /&gt;
** Caddy als Reverse Proxy (alternativ funktionieren [https://nginx.org/ nginx], [https://httpd.apache.org/ Apache], oder (ggf. kostenpflichtige) proprietäre Lösungen. Caddy allerdings hat das für mich charmante Feature, sich eigenständig um die TSL-Zertifikate und ihre Verlängerung bei LetsEncrypt zu kümmern. Wer aufgrund &amp;quot;zu vieler&amp;quot; Fehlversuche bei der Zertifikats-Einrichtung von LetsEncrypt auf Tage gesperrt wurde, wird mein Faible über diesen Automatismus nachvollziehen oder teilen können.)&lt;br /&gt;
** fail2ban als Brute-Force-Schutz&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;DynDNS-Dienst&#039;&#039;&#039; der dem Homeserver eine feste Domain zuweist&lt;br /&gt;
** Beispiel: &amp;lt;code&amp;gt;myhomeserver.dyndns.de&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Router / Heimnetz-Gateway&#039;&#039;&#039;&lt;br /&gt;
** Beispiel-IP: &amp;lt;code&amp;gt;192.168.2.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Portweiterleitung, WLAN, DynDNS-Aktualisierung&lt;br /&gt;
** Typisch: FritzBox, aber jeder Router mit Portweiterleitung funktioniert&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; (dedizierte Hardware-Firewall)&lt;br /&gt;
** WAN-Interface: &amp;lt;code&amp;gt;192.168.2.2&amp;lt;/code&amp;gt; (im Router-Netz)&lt;br /&gt;
** LAN-Interface / Server-VLAN: &amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Firewall, NAT, DHCP, IDS/IPS&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Managed Switch&#039;&#039;&#039; (optional, für VLAN-Segmentierung)&lt;br /&gt;
** Trennt Server-VLAN vom Rest des Netzes&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver-IP&#039;&#039;&#039;: &amp;lt;code&amp;gt;192.168.10.100&amp;lt;/code&amp;gt; (per DHCP-Reservation oder besser: Per statischer IP-Adresse fest)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 1: Wie funktionieren die Weiterleitungen? Wer macht was? ==&lt;br /&gt;
&lt;br /&gt;
=== Die Kette von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Ein Request von außen (z.B. Browser ruft &amp;lt;code&amp;gt;https://myhomeserver.dyndns.de&amp;lt;/code&amp;gt; auf) durchläuft folgende Stationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Internet&lt;br /&gt;
    ↓ DNS-Auflösung: dyndns.de → öffentliche IP des Heimnetzes&lt;br /&gt;
Router / Gateway (192.168.2.1)&lt;br /&gt;
    ↓ Portweiterleitung: :80 + :443 (und nur! diese!!) → 192.168.2.2&lt;br /&gt;
OPNsense WAN-Interface (192.168.2.2)&lt;br /&gt;
    ↓ Destination NAT: :80/:443 → 192.168.10.100&lt;br /&gt;
Homeserver eno1/eth0 (192.168.10.100)&lt;br /&gt;
    ↓ Docker-Port-Binding: 0.0.0.0:80 + 0.0.0.0:443&lt;br /&gt;
Caddy / Reverse Proxy (Docker-intern)&lt;br /&gt;
    ↓ Reverse Proxy anhand des Host-Headers&lt;br /&gt;
Ziel-Container (z.B. wordpress, nextcloud, ...)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit ist der Server auf der IP-Ebene (Layer 3 des OSI-Modells) von außen hin &amp;quot;unsichtbar&amp;quot;: Die Firewall (OPNsense) lebt, mit dem Gateway, im 192.168.2-er Netz. Von dort routet sie alle Anfragen über die Ports 80 und 443 an das Interface 192.168.10.100. Dahinter, also im 192.168.10-er-Subnetz, residiert der Heimserver.&lt;br /&gt;
&lt;br /&gt;
Am Ende dieses Beitrages gibt es Sicherheitshinweise. Bitte dringend beachten, dass der Router ausschließlich die Ports &#039;&#039;&#039;80/TCP&#039;&#039;&#039; und &#039;&#039;&#039;443/TCP&#039;&#039;&#039; nach außen frei gibt. Der Webserver wird dabei so konfiguriert, dass HTTP-Daten über Port 80 nach HTTPS auf Port 443 umgeleitet werden.&lt;br /&gt;
&lt;br /&gt;
Die Idee, ausschließlich HTTPS zuzulassen, läge nahe. Damit bräuchte sich der Webserver nicht um die Weiterleitung auf Port 443 zu befassen.&lt;br /&gt;
Bedauerlicherweise wird in diesem Fall der Umgang mit dem TLS-Zertifikat, das den HTTPS-Datenstrom verschlüsselt, scheitern. [https://letsencrypt.org/ LetsEncrypt] benötigt bei Einrichtung und Verlängerung seiner Zertifikate einen offenen 80-er Port.&lt;br /&gt;
&lt;br /&gt;
Sollte es nötig sein, den Server von außen zu administrieren, wird man darüber nachdenken, einen VPN-Tunnel einzurichten. Sicherer jedoch - und einfacher - ist es dennoch, die Administration ausschließlich über einen zertifikats-geschützten SSH-Zugang im inneren 192.168.-er-Netz zuzulassen und, abgesehen von 80 und 443, auf jeden nach außen exponierten Port zu verzichten.&lt;br /&gt;
&lt;br /&gt;
=== Wer macht was? ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Komponente !! Aufgabe !! Konfigurationsort&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Router / Gateway&#039;&#039;&#039; || DynDNS-Aktualisierung, erste NAT-Stufe, WLAN || Router Web-UI → Portfreigaben&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; || Firewall-Regeln, zweite NAT-Stufe (Destination NAT), DHCP für Server-VLAN || OPNsense Web-UI (Standard: https://&amp;amp;lt;wan-ip&amp;amp;gt;:443 oder :8443)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Caddy / Reverse Proxy&#039;&#039;&#039; || TLS-Terminierung, Let&#039;s Encrypt, Weiterleitung an Container || Caddyfile auf dem Homeserver&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Docker&#039;&#039;&#039; || Container-Isolation, internes Netz (Standard: 172.18.0.0/16) || docker-compose.yml pro Dienst&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fail2ban&#039;&#039;&#039; || Brute-Force-Schutz auf Applikationsebene || Jail-Configs im fail2ban-Container&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Wichtig: OPNsense hat ZWEI Firewall-Engines ===&lt;br /&gt;
&lt;br /&gt;
OPNsense 26.x hat zwei parallele Regelwerke:&lt;br /&gt;
* &#039;&#039;&#039;Rules [new]&#039;&#039;&#039; — neue API-basierte Engine&lt;br /&gt;
* &#039;&#039;&#039;Rules&#039;&#039;&#039; — alte Engine (Legacy)&lt;br /&gt;
&lt;br /&gt;
Neue Regeln &#039;&#039;&#039;immer in beiden&#039;&#039;&#039; anlegen! Bei Problemen immer beide prüfen.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 2: Wo steht was? ==&lt;br /&gt;
&lt;br /&gt;
=== IP-Adressen (Beispiel-Setup) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Gerät !! Interface !! IP !! Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
| Router / Gateway || — || 192.168.2.1 || Gateway, WLAN, DynDNS&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense WAN || wan-interface || 192.168.2.2 || Statisch konfiguriert&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense LAN / Server-VLAN || lan-interface || 192.168.10.1 || Gateway für Server-Netz&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver || eno1 / eth0 || 192.168.10.100 || Fest per DHCP-Reservation (MAC-Adresse)&lt;br /&gt;
|-&lt;br /&gt;
| Client-Geräte || WLAN || 192.168.2.x || Im Router-Netz, nicht im Server-VLAN&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Homeserver: Netzwerk-Interface-Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Der Homeserver bezieht seine IP per DHCP vom OPNsense-DHCP-Server. Bei Debian/Ubuntu mit systemd-networkd:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/systemd/network/10-eth0.network&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Korrekter Inhalt (DHCP):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[Match]&lt;br /&gt;
Name=eno1&lt;br /&gt;
&lt;br /&gt;
[Network]&lt;br /&gt;
DHCP=ipv4&lt;br /&gt;
&lt;br /&gt;
[DHCP]&lt;br /&gt;
RouteMetric=100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ &#039;&#039;&#039;Niemals&#039;&#039;&#039; eine statische IP oder einen Gateway manuell eintragen!&lt;br /&gt;
Der Default-Gateway kommt immer vom DHCP-Server der OPNsense-Firewall (&amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Kea DHCP Lease-Datei (OPNsense) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/db/kea/kea-leases4.csv&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier verwaltet Kea die aktiven Leases. Bei Problemen mit doppelten IPs kann diese Datei (nach &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;) auf den Header reduziert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context,pool_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 3: Systematische Diagnose — Schritt für Schritt ==&lt;br /&gt;
&lt;br /&gt;
=== Grundprinzip: Von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Immer von außen nach innen vorgehen — nie raten, immer messen. Jede Schicht einzeln prüfen.&lt;br /&gt;
&lt;br /&gt;
==== Schritt 1: Ist OPNsense überhaupt erreichbar? ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Vom Client-Rechner:&lt;br /&gt;
ping 192.168.2.2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ OPNsense antwortet standardmäßig &#039;&#039;&#039;nicht&#039;&#039;&#039; auf ICMP/Ping von außen — das ist korrekt!&lt;br /&gt;
&lt;br /&gt;
Stattdessen prüfen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Web-UI erreichbar?&lt;br /&gt;
https://192.168.2.2:8443&lt;br /&gt;
&lt;br /&gt;
# Router zeigt OPNsense als verbundenes Gerät?&lt;br /&gt;
http://192.168.2.1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 2: OPNsense intern prüfen ====&lt;br /&gt;
&lt;br /&gt;
Per SSH oder serieller Konsole auf OPNsense:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# WAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;wan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.2.2, status: active&lt;br /&gt;
&lt;br /&gt;
# LAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;lan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.10.1, status: active&lt;br /&gt;
&lt;br /&gt;
# Router erreichbar?&lt;br /&gt;
ping -c 3 192.168.2.1&lt;br /&gt;
&lt;br /&gt;
# Homeserver erreichbar?&lt;br /&gt;
ping -c 3 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 3: Homeserver direkt prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# SSH auf Homeserver:&lt;br /&gt;
ssh root@192.168.10.100&lt;br /&gt;
&lt;br /&gt;
# Alle Container laufen?&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# Internet vom Homeserver aus erreichbar?&lt;br /&gt;
ping -c 3 9.9.9.9&lt;br /&gt;
&lt;br /&gt;
# Routing-Tabelle korrekt?&lt;br /&gt;
ip route show&lt;br /&gt;
# Erwartete Default-Route: default via 192.168.10.1 dev eno1&lt;br /&gt;
# NICHT: default via 192.168.178.x — das wäre falsch!&lt;br /&gt;
&lt;br /&gt;
# Welche IP hat das Interface?&lt;br /&gt;
ip addr show eno1&lt;br /&gt;
# Erwartete IP: 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 4: Caddy / Reverse Proxy prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Läuft Caddy und antwortet er lokal?&lt;br /&gt;
curl -v http://localhost&lt;br /&gt;
# Erwartete Antwort: HTTP 308 Redirect → https://localhost/&lt;br /&gt;
&lt;br /&gt;
# Caddy-Logs auf Fehler prüfen:&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Typische Fehler in den Caddy-Logs:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fehlermeldung !! Bedeutung !! Lösung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dial tcp ...:443: connect: no route to host&amp;lt;/code&amp;gt; || Caddy kommt nicht ins Internet (Let&#039;s Encrypt nicht erreichbar) || Routing auf Homeserver prüfen (Schritt 3)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;no route to host&amp;lt;/code&amp;gt; bei Ping auf 9.9.9.9 || Falscher Default-Gateway || &amp;lt;code&amp;gt;ip route show&amp;lt;/code&amp;gt; prüfen, falsche Route entfernen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Schritt 5: NAT und Firewall-Regeln prüfen (OPNsense Shell) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# NAT-Regeln anzeigen:&lt;br /&gt;
pfctl -s nat | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Firewall-Regeln anzeigen:&lt;br /&gt;
pfctl -s rules | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf WAN-Interface beobachten (kommt der Request an?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;wan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf LAN-Interface beobachten (wird er weitergeleitet?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;lan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Diagnose-Logik:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tcpdump WAN sieht Traffic, LAN nicht → NAT-Regel prüfen!&lt;br /&gt;
tcpdump WAN sieht keinen Traffic    → Portweiterleitung im Router prüfen!&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 6: Bekannte Fallstricke ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Problem !! Symptom !! Ursache !! Fix&lt;br /&gt;
|-&lt;br /&gt;
| Falsche statische Route || &amp;lt;code&amp;gt;ping 9.9.9.9&amp;lt;/code&amp;gt; schlägt fehl || Netzwerk-Config hat statischen Gateway eingetragen || Auf DHCP umstellen, &amp;lt;code&amp;gt;systemctl restart systemd-networkd&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver hat falsche IP || NAT-Regeln greifen nicht || DHCP hat beim Neustart temporär andere IP vergeben || DHCP-Reservation per MAC-Adresse einrichten&lt;br /&gt;
|-&lt;br /&gt;
| DHCP-Leases durcheinander || Server taucht mit zwei IPs auf || Neustart hat neuen Lease vor Ablauf des alten erzeugt || &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;, Lease-CSV bereinigen, &amp;lt;code&amp;gt;configctl kea start&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense Firewall-Regel fehlt || Dienste von außen nicht erreichbar, intern OK || Regel nur in einer der beiden Engines angelegt || Regel in &#039;&#039;&#039;beiden&#039;&#039;&#039; Engines anlegen (Rules [new] + Rules)&lt;br /&gt;
|-&lt;br /&gt;
| NAT-Regel ohne Subnetz-Maske || Traffic kommt nicht an || &amp;lt;code&amp;gt;192.168.178.0&amp;lt;/code&amp;gt; statt &amp;lt;code&amp;gt;192.168.178.0/24&amp;lt;/code&amp;gt; eingetragen || Subnetz-Maske ergänzen — ohne /24 gilt nur die Netzadresse selbst!&lt;br /&gt;
|-&lt;br /&gt;
| Source/Destination Port vertauscht || Verbindungen werden blockiert || Bei Firewall-Regel Port unter &amp;quot;Source&amp;quot; statt &amp;quot;Destination&amp;quot; eingetragen || Source Port: any / Destination Port: gewünschter Port&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Notfall-Cheatsheet ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# OPNsense: Firewall temporär deaktivieren (Notfall!)&lt;br /&gt;
pfctl -d&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Firewall wieder aktivieren&lt;br /&gt;
pfctl -e&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Kea DHCP stoppen/starten&lt;br /&gt;
configctl kea stop&lt;br /&gt;
configctl kea start&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Falsche Default-Route entfernen&lt;br /&gt;
ip route del default via &amp;amp;lt;falsche-gateway-ip&amp;amp;gt; dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: IP manuell setzen (Sofortlösung bei DHCP-Problemen)&lt;br /&gt;
ip addr add 192.168.10.100/24 dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Netzwerk-Dienst neu starten (Verbindung kurz weg!)&lt;br /&gt;
systemctl restart systemd-networkd&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Docker-Logs prüfen&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Alias-Tabellen prüfen (Blocklisten)&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | wc -l&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | grep &amp;amp;lt;IP&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Sicherheitshinweise ==&lt;br /&gt;
&lt;br /&gt;
* SSH-Ports &#039;&#039;&#039;nicht&#039;&#039;&#039; über das Internet freigeben — nur intern erreichbar lassen! Wenn das nicht geht: VPN-Tunnel!&lt;br /&gt;
* Portweiterleitung im Router auf das &#039;&#039;&#039;Minimum&#039;&#039;&#039; beschränken (nur die Ports 80 + 443 öffnen)&lt;br /&gt;
* Für interne Admin-Interfaces (OPNsense Web-UI, Monitoring) &#039;&#039;&#039;keine externen Freigaben&#039;&#039;&#039;&lt;br /&gt;
* DHCP-Reservations per MAC-Adresse oder statische IP-Adressen verhindern IP-Wechsel nach Neustarts&lt;br /&gt;
* Bei Firewall-Regeln: Block-Regeln &#039;&#039;&#039;immer&#039;&#039;&#039; vor Pass-Regeln platzieren&lt;br /&gt;
&lt;br /&gt;
Abschließend eine absolute Regel, die immer und durch die Ewigkeiten gilt:&lt;br /&gt;
* Dienste, die auf einem Rechner &#039;&#039;&#039;NICHT&#039;&#039;&#039; existieren, werden niemals angegriffen! Wenig ist hier mehr!&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Dieser Artikel basiert auf praktischen Erfahrungen aus dem Betrieb eines selbst gehosteten Servers mit OPNsense, Cisco-Switch und Docker-Stack.&#039;&#039;&lt;br /&gt;
&#039;&#039;Erstellt: Mai 2026&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=256</id>
		<title>Homeserver-Sicherheitsarchitektur</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=256"/>
		<updated>2026-05-27T23:41:44Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Homeserver-Sicherheitsarchitektur: Aufbau, Funktionsweise und Diagnose */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Homeserver-Sicherheitsarchitektur: Aufbau, Funktionsweise und Diagnose ==&lt;br /&gt;
&lt;br /&gt;
Einen eigenen Server an&#039;s Internet zu bekommen, ist nicht allzu schwierig. Ein Dienst, der die eigene, vom Internet-Provider zugewiesene IP-Adresse in einen festen Domain-Namen umwandelt (siehe: [https://de.wikipedia.org/wiki/Dynamisches_DNS Dynamisches DNS]), wird im privaten Bereich die Voraussetzung sein.&lt;br /&gt;
Es gibt verschiedene Anbieter, oft auch kostenlose.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Der eigenen, von außen sichtbaren IP 78.123.234.45 wird vom DynDDS-Dienst die Domain &amp;lt;myhomeserver.dyndns.de&amp;gt; zugewiesen.&lt;br /&gt;
Einmal eingerichtet, wird der eigene Rechner antworten, wenn die Domain http://myhomeserver.dyndns.de in die Browser-Adressleiste einkopiert wird.&lt;br /&gt;
&lt;br /&gt;
=== Ein Leitfaden für selbst gehostete Server mit OPNsense, Managed Switch und Docker ===&lt;br /&gt;
&lt;br /&gt;
Die Kehrseite: Sowie der Server über&#039;s Internet erreichbar ist, ist er angreifbar.&lt;br /&gt;
Das ist kein theoretisches Szenario. Meiner Erfahrung nach ist es eine Frage von Stunden, bis die ersten Bots &amp;quot;anklopfen&amp;quot;, nach laufenden Diensten suchen, nach offenen Ports, nach Schwachstellen.&lt;br /&gt;
Die öffentliche Erreichbarkeit des eigenen Servers über die ungesicherte Adresse...&lt;br /&gt;
* http://myhomeserver.dyndns.de&lt;br /&gt;
...ist fahrlässig.&lt;br /&gt;
&lt;br /&gt;
Aufgrund einer mangelhaften Konfiguration (offener Samba-Port) hatte ich die sehr reale Erfahrung einer russischen Hackerbande, die einige Hundert Textdateien mit Zahlungsaufforderungen und einen Verschlüsselungstrojaner auf meinem Rechner hinterlassen hatte. Gerettet hatten mich damals die Dateirechte von Linux. Das fehlende E(x)ecutional-Flag und die eingeschränkten Benutzerrechte hatten den Trojaner ausgebremst.&lt;br /&gt;
&lt;br /&gt;
Trotzdem: Nie wieder!&lt;br /&gt;
Ein wenig von dem, was ich gelernt habe, gebe ich ich hier weiter.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Einleitung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt den Aufbau einer &#039;&#039;&#039;sicheren&#039;&#039;&#039; Netzwerkarchitektur für einen Homeserver, der über das öffentliche Internet erreichbar ist. Der Beitrag richtet sich an alle, die ihre Daten selbst kontrollieren wollen — und dabei nicht unfreiwillig Teil einer globalen Angriffs-Infrastruktur werden möchten. Er will zum Verständnis beitragen, wie die einzelnen Komponenten zusammenspielen — und wie man systematisch vorgeht, wenn etwas nicht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der Fokus liegt nicht auf einer spezifischen Hardware-Konfiguration, sondern auf dem allgemeinen Prinzip: Wie kommt ein Request von außen sicher zu einem Docker-Container?&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Annahmen / Szenario ==&lt;br /&gt;
&lt;br /&gt;
Folgende Komponenten werden in diesem Artikel vorausgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver&#039;&#039;&#039; (Raspberry Pi, Intel NUC, oder beliebiger Linux-Server)&lt;br /&gt;
** Betriebssystem: Debian/Ubuntu oder vergleichbar&lt;br /&gt;
** Docker mit mehreren Diensten (z.B. WordPress, Nextcloud, MediaWiki)&lt;br /&gt;
** Caddy als Reverse Proxy (alternativ funktionieren [https://nginx.org/ nginx], [https://httpd.apache.org/ Apache], oder (ggf. kostenpflichtige) proprietäre Lösungen. Caddy allerdings hat das für mich charmante Feature, sich eigenständig um die TSL-Zertifikate und ihre Verlängerung bei LetsEncrypt zu kümmern. Wer aufgrund &amp;quot;zu vieler&amp;quot; Fehlversuche bei der Zertifikats-Einrichtung von LetsEncrypt auf Tage gesperrt wurde, wird mein Faible über diesen Automatismus nachvollziehen oder teilen können.)&lt;br /&gt;
** fail2ban als Brute-Force-Schutz&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;DynDNS-Dienst&#039;&#039;&#039; der dem Homeserver eine feste Domain zuweist&lt;br /&gt;
** Beispiel: &amp;lt;code&amp;gt;myhomeserver.dyndns.de&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Router / Heimnetz-Gateway&#039;&#039;&#039;&lt;br /&gt;
** Beispiel-IP: &amp;lt;code&amp;gt;192.168.2.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Portweiterleitung, WLAN, DynDNS-Aktualisierung&lt;br /&gt;
** Typisch: FritzBox, aber jeder Router mit Portweiterleitung funktioniert&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; (dedizierte Hardware-Firewall)&lt;br /&gt;
** WAN-Interface: &amp;lt;code&amp;gt;192.168.2.2&amp;lt;/code&amp;gt; (im Router-Netz)&lt;br /&gt;
** LAN-Interface / Server-VLAN: &amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Firewall, NAT, DHCP, IDS/IPS&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Managed Switch&#039;&#039;&#039; (optional, für VLAN-Segmentierung)&lt;br /&gt;
** Trennt Server-VLAN vom Rest des Netzes&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver-IP&#039;&#039;&#039;: &amp;lt;code&amp;gt;192.168.10.100&amp;lt;/code&amp;gt; (per DHCP-Reservation oder besser: Per statischer IP-Adresse fest)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 1: Wie funktionieren die Weiterleitungen? Wer macht was? ==&lt;br /&gt;
&lt;br /&gt;
=== Die Kette von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Ein Request von außen (z.B. Browser ruft &amp;lt;code&amp;gt;https://myhomeserver.dyndns.de&amp;lt;/code&amp;gt; auf) durchläuft folgende Stationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Internet&lt;br /&gt;
    ↓ DNS-Auflösung: dyndns.de → öffentliche IP des Heimnetzes&lt;br /&gt;
Router / Gateway (192.168.2.1)&lt;br /&gt;
    ↓ Portweiterleitung: :80 + :443 (und nur! diese!!) → 192.168.2.2&lt;br /&gt;
OPNsense WAN-Interface (192.168.2.2)&lt;br /&gt;
    ↓ Destination NAT: :80/:443 → 192.168.10.100&lt;br /&gt;
Homeserver eno1/eth0 (192.168.10.100)&lt;br /&gt;
    ↓ Docker-Port-Binding: 0.0.0.0:80 + 0.0.0.0:443&lt;br /&gt;
Caddy / Reverse Proxy (Docker-intern)&lt;br /&gt;
    ↓ Reverse Proxy anhand des Host-Headers&lt;br /&gt;
Ziel-Container (z.B. wordpress, nextcloud, ...)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit ist der Server auf der IP-Ebene (Layer 3 des OSI-Modells) von außen hin &amp;quot;unsichtbar&amp;quot;: Die Firewall (OPNsense) lebt, mit dem Gateway, im 192.168.2-er Netz. Von dort routet sie alle Anfragen über die Ports 80 und 443 an das Interface 192.168.10.100. Dahinter, also im 192.168.10-er-Subnetz, residiert der Heimserver.&lt;br /&gt;
&lt;br /&gt;
Am Ende dieses Beitrages gibt es Sicherheitshinweise. Bitte dringend beachten, dass der Router ausschließlich die Ports &#039;&#039;&#039;80/TCP&#039;&#039;&#039; und &#039;&#039;&#039;443/TCP&#039;&#039;&#039; nach außen frei gibt. Der Webserver wird dabei so konfiguriert, dass HTTP-Daten über Port 80 nach HTTPS auf Port 443 umgeleitet werden.&lt;br /&gt;
&lt;br /&gt;
Die Idee, ausschließlich HTTPS zuzulassen, läge nahe. Damit bräuchte sich der Webserver nicht um die Weiterleitung auf Port 443 zu befassen.&lt;br /&gt;
Bedauerlicherweise wird in diesem Fall der Umgang mit dem TLS-Zertifikat, das den HTTPS-Datenstrom verschlüsselt, scheitern. [https://letsencrypt.org/ LetsEncrypt] benötigt bei Einrichtung und Verlängerung seiner Zertifikate einen offenen 80-er Port.&lt;br /&gt;
&lt;br /&gt;
Sollte es nötig sein, den Server von außen zu administrieren, wird man darüber nachdenken, einen VPN-Tunnel einzurichten. Sicherer jedoch - und einfacher - ist es dennoch, die Administration ausschließlich über einen zertifikats-geschützten SSH-Zugang im inneren 192.168.-er-Netz zuzulassen und, abgesehen von 80 und 443, auf jeden nach außen exponierten Port zu verzichten.&lt;br /&gt;
&lt;br /&gt;
=== Wer macht was? ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Komponente !! Aufgabe !! Konfigurationsort&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Router / Gateway&#039;&#039;&#039; || DynDNS-Aktualisierung, erste NAT-Stufe, WLAN || Router Web-UI → Portfreigaben&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; || Firewall-Regeln, zweite NAT-Stufe (Destination NAT), DHCP für Server-VLAN || OPNsense Web-UI (Standard: https://&amp;amp;lt;wan-ip&amp;amp;gt;:443 oder :8443)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Caddy / Reverse Proxy&#039;&#039;&#039; || TLS-Terminierung, Let&#039;s Encrypt, Weiterleitung an Container || Caddyfile auf dem Homeserver&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Docker&#039;&#039;&#039; || Container-Isolation, internes Netz (Standard: 172.18.0.0/16) || docker-compose.yml pro Dienst&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fail2ban&#039;&#039;&#039; || Brute-Force-Schutz auf Applikationsebene || Jail-Configs im fail2ban-Container&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Wichtig: OPNsense hat ZWEI Firewall-Engines ===&lt;br /&gt;
&lt;br /&gt;
OPNsense 26.x hat zwei parallele Regelwerke:&lt;br /&gt;
* &#039;&#039;&#039;Rules [new]&#039;&#039;&#039; — neue API-basierte Engine&lt;br /&gt;
* &#039;&#039;&#039;Rules&#039;&#039;&#039; — alte Engine (Legacy)&lt;br /&gt;
&lt;br /&gt;
Neue Regeln &#039;&#039;&#039;immer in beiden&#039;&#039;&#039; anlegen! Bei Problemen immer beide prüfen.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 2: Wo steht was? ==&lt;br /&gt;
&lt;br /&gt;
=== IP-Adressen (Beispiel-Setup) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Gerät !! Interface !! IP !! Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
| Router / Gateway || — || 192.168.2.1 || Gateway, WLAN, DynDNS&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense WAN || wan-interface || 192.168.2.2 || Statisch konfiguriert&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense LAN / Server-VLAN || lan-interface || 192.168.10.1 || Gateway für Server-Netz&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver || eno1 / eth0 || 192.168.10.100 || Fest per DHCP-Reservation (MAC-Adresse)&lt;br /&gt;
|-&lt;br /&gt;
| Client-Geräte || WLAN || 192.168.2.x || Im Router-Netz, nicht im Server-VLAN&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Homeserver: Netzwerk-Interface-Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Der Homeserver bezieht seine IP per DHCP vom OPNsense-DHCP-Server. Bei Debian/Ubuntu mit systemd-networkd:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/systemd/network/10-eth0.network&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Korrekter Inhalt (DHCP):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[Match]&lt;br /&gt;
Name=eno1&lt;br /&gt;
&lt;br /&gt;
[Network]&lt;br /&gt;
DHCP=ipv4&lt;br /&gt;
&lt;br /&gt;
[DHCP]&lt;br /&gt;
RouteMetric=100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ &#039;&#039;&#039;Niemals&#039;&#039;&#039; eine statische IP oder einen Gateway manuell eintragen!&lt;br /&gt;
Der Default-Gateway kommt immer vom DHCP-Server der OPNsense-Firewall (&amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Kea DHCP Lease-Datei (OPNsense) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/db/kea/kea-leases4.csv&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier verwaltet Kea die aktiven Leases. Bei Problemen mit doppelten IPs kann diese Datei (nach &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;) auf den Header reduziert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context,pool_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 3: Systematische Diagnose — Schritt für Schritt ==&lt;br /&gt;
&lt;br /&gt;
=== Grundprinzip: Von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Immer von außen nach innen vorgehen — nie raten, immer messen. Jede Schicht einzeln prüfen.&lt;br /&gt;
&lt;br /&gt;
==== Schritt 1: Ist OPNsense überhaupt erreichbar? ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Vom Client-Rechner:&lt;br /&gt;
ping 192.168.2.2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ OPNsense antwortet standardmäßig &#039;&#039;&#039;nicht&#039;&#039;&#039; auf ICMP/Ping von außen — das ist korrekt!&lt;br /&gt;
&lt;br /&gt;
Stattdessen prüfen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Web-UI erreichbar?&lt;br /&gt;
https://192.168.2.2:8443&lt;br /&gt;
&lt;br /&gt;
# Router zeigt OPNsense als verbundenes Gerät?&lt;br /&gt;
http://192.168.2.1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 2: OPNsense intern prüfen ====&lt;br /&gt;
&lt;br /&gt;
Per SSH oder serieller Konsole auf OPNsense:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# WAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;wan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.2.2, status: active&lt;br /&gt;
&lt;br /&gt;
# LAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;lan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.10.1, status: active&lt;br /&gt;
&lt;br /&gt;
# Router erreichbar?&lt;br /&gt;
ping -c 3 192.168.2.1&lt;br /&gt;
&lt;br /&gt;
# Homeserver erreichbar?&lt;br /&gt;
ping -c 3 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 3: Homeserver direkt prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# SSH auf Homeserver:&lt;br /&gt;
ssh root@192.168.10.100&lt;br /&gt;
&lt;br /&gt;
# Alle Container laufen?&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# Internet vom Homeserver aus erreichbar?&lt;br /&gt;
ping -c 3 9.9.9.9&lt;br /&gt;
&lt;br /&gt;
# Routing-Tabelle korrekt?&lt;br /&gt;
ip route show&lt;br /&gt;
# Erwartete Default-Route: default via 192.168.10.1 dev eno1&lt;br /&gt;
# NICHT: default via 192.168.178.x — das wäre falsch!&lt;br /&gt;
&lt;br /&gt;
# Welche IP hat das Interface?&lt;br /&gt;
ip addr show eno1&lt;br /&gt;
# Erwartete IP: 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 4: Caddy / Reverse Proxy prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Läuft Caddy und antwortet er lokal?&lt;br /&gt;
curl -v http://localhost&lt;br /&gt;
# Erwartete Antwort: HTTP 308 Redirect → https://localhost/&lt;br /&gt;
&lt;br /&gt;
# Caddy-Logs auf Fehler prüfen:&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Typische Fehler in den Caddy-Logs:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fehlermeldung !! Bedeutung !! Lösung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dial tcp ...:443: connect: no route to host&amp;lt;/code&amp;gt; || Caddy kommt nicht ins Internet (Let&#039;s Encrypt nicht erreichbar) || Routing auf Homeserver prüfen (Schritt 3)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;no route to host&amp;lt;/code&amp;gt; bei Ping auf 9.9.9.9 || Falscher Default-Gateway || &amp;lt;code&amp;gt;ip route show&amp;lt;/code&amp;gt; prüfen, falsche Route entfernen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Schritt 5: NAT und Firewall-Regeln prüfen (OPNsense Shell) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# NAT-Regeln anzeigen:&lt;br /&gt;
pfctl -s nat | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Firewall-Regeln anzeigen:&lt;br /&gt;
pfctl -s rules | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf WAN-Interface beobachten (kommt der Request an?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;wan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf LAN-Interface beobachten (wird er weitergeleitet?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;lan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Diagnose-Logik:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tcpdump WAN sieht Traffic, LAN nicht → NAT-Regel prüfen!&lt;br /&gt;
tcpdump WAN sieht keinen Traffic    → Portweiterleitung im Router prüfen!&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 6: Bekannte Fallstricke ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Problem !! Symptom !! Ursache !! Fix&lt;br /&gt;
|-&lt;br /&gt;
| Falsche statische Route || &amp;lt;code&amp;gt;ping 9.9.9.9&amp;lt;/code&amp;gt; schlägt fehl || Netzwerk-Config hat statischen Gateway eingetragen || Auf DHCP umstellen, &amp;lt;code&amp;gt;systemctl restart systemd-networkd&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver hat falsche IP || NAT-Regeln greifen nicht || DHCP hat beim Neustart temporär andere IP vergeben || DHCP-Reservation per MAC-Adresse einrichten&lt;br /&gt;
|-&lt;br /&gt;
| DHCP-Leases durcheinander || Server taucht mit zwei IPs auf || Neustart hat neuen Lease vor Ablauf des alten erzeugt || &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;, Lease-CSV bereinigen, &amp;lt;code&amp;gt;configctl kea start&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense Firewall-Regel fehlt || Dienste von außen nicht erreichbar, intern OK || Regel nur in einer der beiden Engines angelegt || Regel in &#039;&#039;&#039;beiden&#039;&#039;&#039; Engines anlegen (Rules [new] + Rules)&lt;br /&gt;
|-&lt;br /&gt;
| NAT-Regel ohne Subnetz-Maske || Traffic kommt nicht an || &amp;lt;code&amp;gt;192.168.178.0&amp;lt;/code&amp;gt; statt &amp;lt;code&amp;gt;192.168.178.0/24&amp;lt;/code&amp;gt; eingetragen || Subnetz-Maske ergänzen — ohne /24 gilt nur die Netzadresse selbst!&lt;br /&gt;
|-&lt;br /&gt;
| Source/Destination Port vertauscht || Verbindungen werden blockiert || Bei Firewall-Regel Port unter &amp;quot;Source&amp;quot; statt &amp;quot;Destination&amp;quot; eingetragen || Source Port: any / Destination Port: gewünschter Port&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Notfall-Cheatsheet ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# OPNsense: Firewall temporär deaktivieren (Notfall!)&lt;br /&gt;
pfctl -d&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Firewall wieder aktivieren&lt;br /&gt;
pfctl -e&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Kea DHCP stoppen/starten&lt;br /&gt;
configctl kea stop&lt;br /&gt;
configctl kea start&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Falsche Default-Route entfernen&lt;br /&gt;
ip route del default via &amp;amp;lt;falsche-gateway-ip&amp;amp;gt; dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: IP manuell setzen (Sofortlösung bei DHCP-Problemen)&lt;br /&gt;
ip addr add 192.168.10.100/24 dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Netzwerk-Dienst neu starten (Verbindung kurz weg!)&lt;br /&gt;
systemctl restart systemd-networkd&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Docker-Logs prüfen&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Alias-Tabellen prüfen (Blocklisten)&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | wc -l&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | grep &amp;amp;lt;IP&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Sicherheitshinweise ==&lt;br /&gt;
&lt;br /&gt;
* SSH-Ports &#039;&#039;&#039;nicht&#039;&#039;&#039; über das Internet freigeben — nur intern erreichbar lassen! Wenn das nicht geht: VPN-Tunnel!&lt;br /&gt;
* Portweiterleitung im Router auf das &#039;&#039;&#039;Minimum&#039;&#039;&#039; beschränken (nur die Ports 80 + 443 öffnen)&lt;br /&gt;
* Für interne Admin-Interfaces (OPNsense Web-UI, Monitoring) &#039;&#039;&#039;keine externen Freigaben&#039;&#039;&#039;&lt;br /&gt;
* DHCP-Reservations per MAC-Adresse oder statische IP-Adressen verhindern IP-Wechsel nach Neustarts&lt;br /&gt;
* Bei Firewall-Regeln: Block-Regeln &#039;&#039;&#039;immer&#039;&#039;&#039; vor Pass-Regeln platzieren&lt;br /&gt;
&lt;br /&gt;
Abschließend eine absolute Regel, die immer und durch die Ewigkeiten gilt:&lt;br /&gt;
* Dienste, die auf einem Rechner &#039;&#039;&#039;NICHT&#039;&#039;&#039; existieren, werden niemals angegriffen! Wenig ist hier mehr!&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Dieser Artikel basiert auf praktischen Erfahrungen aus dem Betrieb eines selbst gehosteten Servers mit OPNsense, Cisco-Switch und Docker-Stack.&#039;&#039;&lt;br /&gt;
&#039;&#039;Erstellt: Mai 2026&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=255</id>
		<title>Homeserver-Sicherheitsarchitektur</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=255"/>
		<updated>2026-05-27T23:33:14Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Homeserver-Sicherheitsarchitektur: Aufbau, Funktionsweise und Diagnose */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Homeserver-Sicherheitsarchitektur: Aufbau, Funktionsweise und Diagnose ==&lt;br /&gt;
&lt;br /&gt;
Einen eigenen Server an&#039;s Internet zu bekommen, ist nicht allzu schwierig. Ein Dienst, der die eigene, vom Internet-Provider zugewiesene IP-Adresse in einen festen Domain-Namen umwandelt (siehe: [https://de.wikipedia.org/wiki/Dynamisches_DNS Dynamisches DNS]), wird im privaten Bereich die Voraussetzung sein.&lt;br /&gt;
Es gibt verschiedene Anbieter, oft auch kostenlose.&lt;br /&gt;
Einmal eingerichtet, &lt;br /&gt;
&lt;br /&gt;
=== Ein Leitfaden für selbst gehostete Server mit OPNsense, Managed Switch und Docker ===&lt;br /&gt;
&lt;br /&gt;
Die Kehrseite: Sowie der Server über&#039;s Internet erreichbar ist, ist er angreifbar. Das ist kein theoretisches Szenario. Meiner Erfahrung nach ist es eine Frage von Stunden, bis die ersten Bots &amp;quot;anklopfen&amp;quot;, nach laufenden Diensten suchen, nach offenen Ports, nach Schwachstellen.&lt;br /&gt;
&lt;br /&gt;
Aufgrund einer mangelhaften Konfiguration (offener Samba-Port) hatte ich die sehr reale Erfahrung einer russischen Hackerbande, die einige Hundert Textdateien mit Zahlungsaufforderungen und einen Verschlüsselungstrojaner auf meinem Rechner hinterlassen hatte. Gerettet hatten mich damals die Dateirechte von Linux. Das fehlende E(x)ecutional-Flag und die eingeschränkten Benutzerrechte hatten den Trojaner ausgebremst.&lt;br /&gt;
&lt;br /&gt;
Trotzdem: Nie wieder!&lt;br /&gt;
Ein wenig von dem, was ich gelernt habe, gebe ich ich hier weiter.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Einleitung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt den Aufbau einer &#039;&#039;&#039;sicheren&#039;&#039;&#039; Netzwerkarchitektur für einen Homeserver, der über das öffentliche Internet erreichbar ist. Der Beitrag richtet sich an alle, die ihre Daten selbst kontrollieren wollen — und dabei nicht unfreiwillig Teil einer globalen Angriffs-Infrastruktur werden möchten. Er will zum Verständnis beitragen, wie die einzelnen Komponenten zusammenspielen — und wie man systematisch vorgeht, wenn etwas nicht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der Fokus liegt nicht auf einer spezifischen Hardware-Konfiguration, sondern auf dem allgemeinen Prinzip: Wie kommt ein Request von außen sicher zu einem Docker-Container?&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Annahmen / Szenario ==&lt;br /&gt;
&lt;br /&gt;
Folgende Komponenten werden in diesem Artikel vorausgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver&#039;&#039;&#039; (Raspberry Pi, Intel NUC, oder beliebiger Linux-Server)&lt;br /&gt;
** Betriebssystem: Debian/Ubuntu oder vergleichbar&lt;br /&gt;
** Docker mit mehreren Diensten (z.B. WordPress, Nextcloud, MediaWiki)&lt;br /&gt;
** Caddy als Reverse Proxy (alternativ funktionieren [https://nginx.org/ nginx], [https://httpd.apache.org/ Apache], oder (ggf. kostenpflichtige) proprietäre Lösungen. Caddy allerdings hat das für mich charmante Feature, sich eigenständig um die TSL-Zertifikate und ihre Verlängerung bei LetsEncrypt zu kümmern. Wer aufgrund &amp;quot;zu vieler&amp;quot; Fehlversuche bei der Zertifikats-Einrichtung von LetsEncrypt auf Tage gesperrt wurde, wird mein Faible über diesen Automatismus nachvollziehen oder teilen können.)&lt;br /&gt;
** fail2ban als Brute-Force-Schutz&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;DynDNS-Dienst&#039;&#039;&#039; der dem Homeserver eine feste Domain zuweist&lt;br /&gt;
** Beispiel: &amp;lt;code&amp;gt;myhomeserver.dyndns.de&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Router / Heimnetz-Gateway&#039;&#039;&#039;&lt;br /&gt;
** Beispiel-IP: &amp;lt;code&amp;gt;192.168.2.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Portweiterleitung, WLAN, DynDNS-Aktualisierung&lt;br /&gt;
** Typisch: FritzBox, aber jeder Router mit Portweiterleitung funktioniert&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; (dedizierte Hardware-Firewall)&lt;br /&gt;
** WAN-Interface: &amp;lt;code&amp;gt;192.168.2.2&amp;lt;/code&amp;gt; (im Router-Netz)&lt;br /&gt;
** LAN-Interface / Server-VLAN: &amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Firewall, NAT, DHCP, IDS/IPS&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Managed Switch&#039;&#039;&#039; (optional, für VLAN-Segmentierung)&lt;br /&gt;
** Trennt Server-VLAN vom Rest des Netzes&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver-IP&#039;&#039;&#039;: &amp;lt;code&amp;gt;192.168.10.100&amp;lt;/code&amp;gt; (per DHCP-Reservation oder besser: Per statischer IP-Adresse fest)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 1: Wie funktionieren die Weiterleitungen? Wer macht was? ==&lt;br /&gt;
&lt;br /&gt;
=== Die Kette von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Ein Request von außen (z.B. Browser ruft &amp;lt;code&amp;gt;https://myhomeserver.dyndns.de&amp;lt;/code&amp;gt; auf) durchläuft folgende Stationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Internet&lt;br /&gt;
    ↓ DNS-Auflösung: dyndns.de → öffentliche IP des Heimnetzes&lt;br /&gt;
Router / Gateway (192.168.2.1)&lt;br /&gt;
    ↓ Portweiterleitung: :80 + :443 (und nur! diese!!) → 192.168.2.2&lt;br /&gt;
OPNsense WAN-Interface (192.168.2.2)&lt;br /&gt;
    ↓ Destination NAT: :80/:443 → 192.168.10.100&lt;br /&gt;
Homeserver eno1/eth0 (192.168.10.100)&lt;br /&gt;
    ↓ Docker-Port-Binding: 0.0.0.0:80 + 0.0.0.0:443&lt;br /&gt;
Caddy / Reverse Proxy (Docker-intern)&lt;br /&gt;
    ↓ Reverse Proxy anhand des Host-Headers&lt;br /&gt;
Ziel-Container (z.B. wordpress, nextcloud, ...)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit ist der Server auf der IP-Ebene (Layer 3 des OSI-Modells) von außen hin &amp;quot;unsichtbar&amp;quot;: Die Firewall (OPNsense) lebt, mit dem Gateway, im 192.168.2-er Netz. Von dort routet sie alle Anfragen über die Ports 80 und 443 an das Interface 192.168.10.100. Dahinter, also im 192.168.10-er-Subnetz, residiert der Heimserver.&lt;br /&gt;
&lt;br /&gt;
Am Ende dieses Beitrages gibt es Sicherheitshinweise. Bitte dringend beachten, dass der Router ausschließlich die Ports &#039;&#039;&#039;80/TCP&#039;&#039;&#039; und &#039;&#039;&#039;443/TCP&#039;&#039;&#039; nach außen frei gibt. Der Webserver wird dabei so konfiguriert, dass HTTP-Daten über Port 80 nach HTTPS auf Port 443 umgeleitet werden.&lt;br /&gt;
&lt;br /&gt;
Die Idee, ausschließlich HTTPS zuzulassen, läge nahe. Damit bräuchte sich der Webserver nicht um die Weiterleitung auf Port 443 zu befassen.&lt;br /&gt;
Bedauerlicherweise wird in diesem Fall der Umgang mit dem TLS-Zertifikat, das den HTTPS-Datenstrom verschlüsselt, scheitern. [https://letsencrypt.org/ LetsEncrypt] benötigt bei Einrichtung und Verlängerung seiner Zertifikate einen offenen 80-er Port.&lt;br /&gt;
&lt;br /&gt;
Sollte es nötig sein, den Server von außen zu administrieren, wird man darüber nachdenken, einen VPN-Tunnel einzurichten. Sicherer jedoch - und einfacher - ist es dennoch, die Administration ausschließlich über einen zertifikats-geschützten SSH-Zugang im inneren 192.168.-er-Netz zuzulassen und, abgesehen von 80 und 443, auf jeden nach außen exponierten Port zu verzichten.&lt;br /&gt;
&lt;br /&gt;
=== Wer macht was? ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Komponente !! Aufgabe !! Konfigurationsort&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Router / Gateway&#039;&#039;&#039; || DynDNS-Aktualisierung, erste NAT-Stufe, WLAN || Router Web-UI → Portfreigaben&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; || Firewall-Regeln, zweite NAT-Stufe (Destination NAT), DHCP für Server-VLAN || OPNsense Web-UI (Standard: https://&amp;amp;lt;wan-ip&amp;amp;gt;:443 oder :8443)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Caddy / Reverse Proxy&#039;&#039;&#039; || TLS-Terminierung, Let&#039;s Encrypt, Weiterleitung an Container || Caddyfile auf dem Homeserver&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Docker&#039;&#039;&#039; || Container-Isolation, internes Netz (Standard: 172.18.0.0/16) || docker-compose.yml pro Dienst&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fail2ban&#039;&#039;&#039; || Brute-Force-Schutz auf Applikationsebene || Jail-Configs im fail2ban-Container&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Wichtig: OPNsense hat ZWEI Firewall-Engines ===&lt;br /&gt;
&lt;br /&gt;
OPNsense 26.x hat zwei parallele Regelwerke:&lt;br /&gt;
* &#039;&#039;&#039;Rules [new]&#039;&#039;&#039; — neue API-basierte Engine&lt;br /&gt;
* &#039;&#039;&#039;Rules&#039;&#039;&#039; — alte Engine (Legacy)&lt;br /&gt;
&lt;br /&gt;
Neue Regeln &#039;&#039;&#039;immer in beiden&#039;&#039;&#039; anlegen! Bei Problemen immer beide prüfen.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 2: Wo steht was? ==&lt;br /&gt;
&lt;br /&gt;
=== IP-Adressen (Beispiel-Setup) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Gerät !! Interface !! IP !! Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
| Router / Gateway || — || 192.168.2.1 || Gateway, WLAN, DynDNS&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense WAN || wan-interface || 192.168.2.2 || Statisch konfiguriert&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense LAN / Server-VLAN || lan-interface || 192.168.10.1 || Gateway für Server-Netz&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver || eno1 / eth0 || 192.168.10.100 || Fest per DHCP-Reservation (MAC-Adresse)&lt;br /&gt;
|-&lt;br /&gt;
| Client-Geräte || WLAN || 192.168.2.x || Im Router-Netz, nicht im Server-VLAN&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Homeserver: Netzwerk-Interface-Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Der Homeserver bezieht seine IP per DHCP vom OPNsense-DHCP-Server. Bei Debian/Ubuntu mit systemd-networkd:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/systemd/network/10-eth0.network&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Korrekter Inhalt (DHCP):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[Match]&lt;br /&gt;
Name=eno1&lt;br /&gt;
&lt;br /&gt;
[Network]&lt;br /&gt;
DHCP=ipv4&lt;br /&gt;
&lt;br /&gt;
[DHCP]&lt;br /&gt;
RouteMetric=100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ &#039;&#039;&#039;Niemals&#039;&#039;&#039; eine statische IP oder einen Gateway manuell eintragen!&lt;br /&gt;
Der Default-Gateway kommt immer vom DHCP-Server der OPNsense-Firewall (&amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Kea DHCP Lease-Datei (OPNsense) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/db/kea/kea-leases4.csv&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier verwaltet Kea die aktiven Leases. Bei Problemen mit doppelten IPs kann diese Datei (nach &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;) auf den Header reduziert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context,pool_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 3: Systematische Diagnose — Schritt für Schritt ==&lt;br /&gt;
&lt;br /&gt;
=== Grundprinzip: Von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Immer von außen nach innen vorgehen — nie raten, immer messen. Jede Schicht einzeln prüfen.&lt;br /&gt;
&lt;br /&gt;
==== Schritt 1: Ist OPNsense überhaupt erreichbar? ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Vom Client-Rechner:&lt;br /&gt;
ping 192.168.2.2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ OPNsense antwortet standardmäßig &#039;&#039;&#039;nicht&#039;&#039;&#039; auf ICMP/Ping von außen — das ist korrekt!&lt;br /&gt;
&lt;br /&gt;
Stattdessen prüfen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Web-UI erreichbar?&lt;br /&gt;
https://192.168.2.2:8443&lt;br /&gt;
&lt;br /&gt;
# Router zeigt OPNsense als verbundenes Gerät?&lt;br /&gt;
http://192.168.2.1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 2: OPNsense intern prüfen ====&lt;br /&gt;
&lt;br /&gt;
Per SSH oder serieller Konsole auf OPNsense:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# WAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;wan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.2.2, status: active&lt;br /&gt;
&lt;br /&gt;
# LAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;lan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.10.1, status: active&lt;br /&gt;
&lt;br /&gt;
# Router erreichbar?&lt;br /&gt;
ping -c 3 192.168.2.1&lt;br /&gt;
&lt;br /&gt;
# Homeserver erreichbar?&lt;br /&gt;
ping -c 3 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 3: Homeserver direkt prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# SSH auf Homeserver:&lt;br /&gt;
ssh root@192.168.10.100&lt;br /&gt;
&lt;br /&gt;
# Alle Container laufen?&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# Internet vom Homeserver aus erreichbar?&lt;br /&gt;
ping -c 3 9.9.9.9&lt;br /&gt;
&lt;br /&gt;
# Routing-Tabelle korrekt?&lt;br /&gt;
ip route show&lt;br /&gt;
# Erwartete Default-Route: default via 192.168.10.1 dev eno1&lt;br /&gt;
# NICHT: default via 192.168.178.x — das wäre falsch!&lt;br /&gt;
&lt;br /&gt;
# Welche IP hat das Interface?&lt;br /&gt;
ip addr show eno1&lt;br /&gt;
# Erwartete IP: 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 4: Caddy / Reverse Proxy prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Läuft Caddy und antwortet er lokal?&lt;br /&gt;
curl -v http://localhost&lt;br /&gt;
# Erwartete Antwort: HTTP 308 Redirect → https://localhost/&lt;br /&gt;
&lt;br /&gt;
# Caddy-Logs auf Fehler prüfen:&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Typische Fehler in den Caddy-Logs:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fehlermeldung !! Bedeutung !! Lösung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dial tcp ...:443: connect: no route to host&amp;lt;/code&amp;gt; || Caddy kommt nicht ins Internet (Let&#039;s Encrypt nicht erreichbar) || Routing auf Homeserver prüfen (Schritt 3)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;no route to host&amp;lt;/code&amp;gt; bei Ping auf 9.9.9.9 || Falscher Default-Gateway || &amp;lt;code&amp;gt;ip route show&amp;lt;/code&amp;gt; prüfen, falsche Route entfernen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Schritt 5: NAT und Firewall-Regeln prüfen (OPNsense Shell) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# NAT-Regeln anzeigen:&lt;br /&gt;
pfctl -s nat | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Firewall-Regeln anzeigen:&lt;br /&gt;
pfctl -s rules | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf WAN-Interface beobachten (kommt der Request an?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;wan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf LAN-Interface beobachten (wird er weitergeleitet?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;lan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Diagnose-Logik:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tcpdump WAN sieht Traffic, LAN nicht → NAT-Regel prüfen!&lt;br /&gt;
tcpdump WAN sieht keinen Traffic    → Portweiterleitung im Router prüfen!&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 6: Bekannte Fallstricke ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Problem !! Symptom !! Ursache !! Fix&lt;br /&gt;
|-&lt;br /&gt;
| Falsche statische Route || &amp;lt;code&amp;gt;ping 9.9.9.9&amp;lt;/code&amp;gt; schlägt fehl || Netzwerk-Config hat statischen Gateway eingetragen || Auf DHCP umstellen, &amp;lt;code&amp;gt;systemctl restart systemd-networkd&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver hat falsche IP || NAT-Regeln greifen nicht || DHCP hat beim Neustart temporär andere IP vergeben || DHCP-Reservation per MAC-Adresse einrichten&lt;br /&gt;
|-&lt;br /&gt;
| DHCP-Leases durcheinander || Server taucht mit zwei IPs auf || Neustart hat neuen Lease vor Ablauf des alten erzeugt || &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;, Lease-CSV bereinigen, &amp;lt;code&amp;gt;configctl kea start&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense Firewall-Regel fehlt || Dienste von außen nicht erreichbar, intern OK || Regel nur in einer der beiden Engines angelegt || Regel in &#039;&#039;&#039;beiden&#039;&#039;&#039; Engines anlegen (Rules [new] + Rules)&lt;br /&gt;
|-&lt;br /&gt;
| NAT-Regel ohne Subnetz-Maske || Traffic kommt nicht an || &amp;lt;code&amp;gt;192.168.178.0&amp;lt;/code&amp;gt; statt &amp;lt;code&amp;gt;192.168.178.0/24&amp;lt;/code&amp;gt; eingetragen || Subnetz-Maske ergänzen — ohne /24 gilt nur die Netzadresse selbst!&lt;br /&gt;
|-&lt;br /&gt;
| Source/Destination Port vertauscht || Verbindungen werden blockiert || Bei Firewall-Regel Port unter &amp;quot;Source&amp;quot; statt &amp;quot;Destination&amp;quot; eingetragen || Source Port: any / Destination Port: gewünschter Port&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Notfall-Cheatsheet ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# OPNsense: Firewall temporär deaktivieren (Notfall!)&lt;br /&gt;
pfctl -d&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Firewall wieder aktivieren&lt;br /&gt;
pfctl -e&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Kea DHCP stoppen/starten&lt;br /&gt;
configctl kea stop&lt;br /&gt;
configctl kea start&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Falsche Default-Route entfernen&lt;br /&gt;
ip route del default via &amp;amp;lt;falsche-gateway-ip&amp;amp;gt; dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: IP manuell setzen (Sofortlösung bei DHCP-Problemen)&lt;br /&gt;
ip addr add 192.168.10.100/24 dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Netzwerk-Dienst neu starten (Verbindung kurz weg!)&lt;br /&gt;
systemctl restart systemd-networkd&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Docker-Logs prüfen&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Alias-Tabellen prüfen (Blocklisten)&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | wc -l&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | grep &amp;amp;lt;IP&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Sicherheitshinweise ==&lt;br /&gt;
&lt;br /&gt;
* SSH-Ports &#039;&#039;&#039;nicht&#039;&#039;&#039; über das Internet freigeben — nur intern erreichbar lassen! Wenn das nicht geht: VPN-Tunnel!&lt;br /&gt;
* Portweiterleitung im Router auf das &#039;&#039;&#039;Minimum&#039;&#039;&#039; beschränken (nur die Ports 80 + 443 öffnen)&lt;br /&gt;
* Für interne Admin-Interfaces (OPNsense Web-UI, Monitoring) &#039;&#039;&#039;keine externen Freigaben&#039;&#039;&#039;&lt;br /&gt;
* DHCP-Reservations per MAC-Adresse oder statische IP-Adressen verhindern IP-Wechsel nach Neustarts&lt;br /&gt;
* Bei Firewall-Regeln: Block-Regeln &#039;&#039;&#039;immer&#039;&#039;&#039; vor Pass-Regeln platzieren&lt;br /&gt;
&lt;br /&gt;
Abschließend eine absolute Regel, die immer und durch die Ewigkeiten gilt:&lt;br /&gt;
* Dienste, die auf einem Rechner &#039;&#039;&#039;NICHT&#039;&#039;&#039; existieren, werden niemals angegriffen! Wenig ist hier mehr!&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Dieser Artikel basiert auf praktischen Erfahrungen aus dem Betrieb eines selbst gehosteten Servers mit OPNsense, Cisco-Switch und Docker-Stack.&#039;&#039;&lt;br /&gt;
&#039;&#039;Erstellt: Mai 2026&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=254</id>
		<title>Homeserver-Sicherheitsarchitektur</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=254"/>
		<updated>2026-05-27T23:31:54Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Sicherheitshinweise */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Homeserver-Sicherheitsarchitektur: Aufbau, Funktionsweise und Diagnose ==&lt;br /&gt;
&lt;br /&gt;
Einen eigenen Server an&#039;s Internet zu bekommen, ist nicht allzu schwierig. Ein Dienst, der die eigene, vom Internet-Provider zugewiesene IP-Adresse in einen festen Domain-Namen umwandelt (siehe: [https://de.wikipedia.org/wiki/Dynamisches_DNS Dynamisches DNS]), wird im privaten Bereich die Voraussetzung sein.&lt;br /&gt;
Es gibt verschiedene Anbieter, oft auch kostenlose.&lt;br /&gt;
&lt;br /&gt;
=== Ein Leitfaden für selbst gehostete Server mit OPNsense, Managed Switch und Docker ===&lt;br /&gt;
&lt;br /&gt;
Die Kehrseite: Sowie der Server über&#039;s Internet erreichbar ist, ist er angreifbar. Das ist kein theoretisches Szenario. Meiner Erfahrung nach ist es eine Frage von Stunden, bis die ersten Bots &amp;quot;anklopfen&amp;quot;, nach laufenden Diensten suchen, nach offenen Ports, nach Schwachstellen.&lt;br /&gt;
&lt;br /&gt;
Aufgrund einer mangelhaften Konfiguration (offener Samba-Port) hatte ich die sehr reale Erfahrung einer russischen Hackerbande, die einige Hundert Textdateien mit Zahlungsaufforderungen und einen Verschlüsselungstrojaner auf meinem Rechner hinterlassen hatte. Gerettet hatten mich damals die Dateirechte von Linux. Das fehlende E(x)ecutional-Flag und die eingeschränkten Benutzerrechte hatten den Trojaner ausgebremst.&lt;br /&gt;
&lt;br /&gt;
Trotzdem: Nie wieder!&lt;br /&gt;
Ein wenig von dem, was ich gelernt habe, gebe ich ich hier weiter.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Einleitung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt den Aufbau einer &#039;&#039;&#039;sicheren&#039;&#039;&#039; Netzwerkarchitektur für einen Homeserver, der über das öffentliche Internet erreichbar ist. Der Beitrag richtet sich an alle, die ihre Daten selbst kontrollieren wollen — und dabei nicht unfreiwillig Teil einer globalen Angriffs-Infrastruktur werden möchten. Er will zum Verständnis beitragen, wie die einzelnen Komponenten zusammenspielen — und wie man systematisch vorgeht, wenn etwas nicht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der Fokus liegt nicht auf einer spezifischen Hardware-Konfiguration, sondern auf dem allgemeinen Prinzip: Wie kommt ein Request von außen sicher zu einem Docker-Container?&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Annahmen / Szenario ==&lt;br /&gt;
&lt;br /&gt;
Folgende Komponenten werden in diesem Artikel vorausgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver&#039;&#039;&#039; (Raspberry Pi, Intel NUC, oder beliebiger Linux-Server)&lt;br /&gt;
** Betriebssystem: Debian/Ubuntu oder vergleichbar&lt;br /&gt;
** Docker mit mehreren Diensten (z.B. WordPress, Nextcloud, MediaWiki)&lt;br /&gt;
** Caddy als Reverse Proxy (alternativ funktionieren [https://nginx.org/ nginx], [https://httpd.apache.org/ Apache], oder (ggf. kostenpflichtige) proprietäre Lösungen. Caddy allerdings hat das für mich charmante Feature, sich eigenständig um die TSL-Zertifikate und ihre Verlängerung bei LetsEncrypt zu kümmern. Wer aufgrund &amp;quot;zu vieler&amp;quot; Fehlversuche bei der Zertifikats-Einrichtung von LetsEncrypt auf Tage gesperrt wurde, wird mein Faible über diesen Automatismus nachvollziehen oder teilen können.)&lt;br /&gt;
** fail2ban als Brute-Force-Schutz&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;DynDNS-Dienst&#039;&#039;&#039; der dem Homeserver eine feste Domain zuweist&lt;br /&gt;
** Beispiel: &amp;lt;code&amp;gt;myhomeserver.dyndns.de&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Router / Heimnetz-Gateway&#039;&#039;&#039;&lt;br /&gt;
** Beispiel-IP: &amp;lt;code&amp;gt;192.168.2.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Portweiterleitung, WLAN, DynDNS-Aktualisierung&lt;br /&gt;
** Typisch: FritzBox, aber jeder Router mit Portweiterleitung funktioniert&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; (dedizierte Hardware-Firewall)&lt;br /&gt;
** WAN-Interface: &amp;lt;code&amp;gt;192.168.2.2&amp;lt;/code&amp;gt; (im Router-Netz)&lt;br /&gt;
** LAN-Interface / Server-VLAN: &amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Firewall, NAT, DHCP, IDS/IPS&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Managed Switch&#039;&#039;&#039; (optional, für VLAN-Segmentierung)&lt;br /&gt;
** Trennt Server-VLAN vom Rest des Netzes&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver-IP&#039;&#039;&#039;: &amp;lt;code&amp;gt;192.168.10.100&amp;lt;/code&amp;gt; (per DHCP-Reservation oder besser: Per statischer IP-Adresse fest)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 1: Wie funktionieren die Weiterleitungen? Wer macht was? ==&lt;br /&gt;
&lt;br /&gt;
=== Die Kette von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Ein Request von außen (z.B. Browser ruft &amp;lt;code&amp;gt;https://myhomeserver.dyndns.de&amp;lt;/code&amp;gt; auf) durchläuft folgende Stationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Internet&lt;br /&gt;
    ↓ DNS-Auflösung: dyndns.de → öffentliche IP des Heimnetzes&lt;br /&gt;
Router / Gateway (192.168.2.1)&lt;br /&gt;
    ↓ Portweiterleitung: :80 + :443 (und nur! diese!!) → 192.168.2.2&lt;br /&gt;
OPNsense WAN-Interface (192.168.2.2)&lt;br /&gt;
    ↓ Destination NAT: :80/:443 → 192.168.10.100&lt;br /&gt;
Homeserver eno1/eth0 (192.168.10.100)&lt;br /&gt;
    ↓ Docker-Port-Binding: 0.0.0.0:80 + 0.0.0.0:443&lt;br /&gt;
Caddy / Reverse Proxy (Docker-intern)&lt;br /&gt;
    ↓ Reverse Proxy anhand des Host-Headers&lt;br /&gt;
Ziel-Container (z.B. wordpress, nextcloud, ...)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit ist der Server auf der IP-Ebene (Layer 3 des OSI-Modells) von außen hin &amp;quot;unsichtbar&amp;quot;: Die Firewall (OPNsense) lebt, mit dem Gateway, im 192.168.2-er Netz. Von dort routet sie alle Anfragen über die Ports 80 und 443 an das Interface 192.168.10.100. Dahinter, also im 192.168.10-er-Subnetz, residiert der Heimserver.&lt;br /&gt;
&lt;br /&gt;
Am Ende dieses Beitrages gibt es Sicherheitshinweise. Bitte dringend beachten, dass der Router ausschließlich die Ports &#039;&#039;&#039;80/TCP&#039;&#039;&#039; und &#039;&#039;&#039;443/TCP&#039;&#039;&#039; nach außen frei gibt. Der Webserver wird dabei so konfiguriert, dass HTTP-Daten über Port 80 nach HTTPS auf Port 443 umgeleitet werden.&lt;br /&gt;
&lt;br /&gt;
Die Idee, ausschließlich HTTPS zuzulassen, läge nahe. Damit bräuchte sich der Webserver nicht um die Weiterleitung auf Port 443 zu befassen.&lt;br /&gt;
Bedauerlicherweise wird in diesem Fall der Umgang mit dem TLS-Zertifikat, das den HTTPS-Datenstrom verschlüsselt, scheitern. [https://letsencrypt.org/ LetsEncrypt] benötigt bei Einrichtung und Verlängerung seiner Zertifikate einen offenen 80-er Port.&lt;br /&gt;
&lt;br /&gt;
Sollte es nötig sein, den Server von außen zu administrieren, wird man darüber nachdenken, einen VPN-Tunnel einzurichten. Sicherer jedoch - und einfacher - ist es dennoch, die Administration ausschließlich über einen zertifikats-geschützten SSH-Zugang im inneren 192.168.-er-Netz zuzulassen und, abgesehen von 80 und 443, auf jeden nach außen exponierten Port zu verzichten.&lt;br /&gt;
&lt;br /&gt;
=== Wer macht was? ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Komponente !! Aufgabe !! Konfigurationsort&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Router / Gateway&#039;&#039;&#039; || DynDNS-Aktualisierung, erste NAT-Stufe, WLAN || Router Web-UI → Portfreigaben&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; || Firewall-Regeln, zweite NAT-Stufe (Destination NAT), DHCP für Server-VLAN || OPNsense Web-UI (Standard: https://&amp;amp;lt;wan-ip&amp;amp;gt;:443 oder :8443)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Caddy / Reverse Proxy&#039;&#039;&#039; || TLS-Terminierung, Let&#039;s Encrypt, Weiterleitung an Container || Caddyfile auf dem Homeserver&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Docker&#039;&#039;&#039; || Container-Isolation, internes Netz (Standard: 172.18.0.0/16) || docker-compose.yml pro Dienst&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fail2ban&#039;&#039;&#039; || Brute-Force-Schutz auf Applikationsebene || Jail-Configs im fail2ban-Container&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Wichtig: OPNsense hat ZWEI Firewall-Engines ===&lt;br /&gt;
&lt;br /&gt;
OPNsense 26.x hat zwei parallele Regelwerke:&lt;br /&gt;
* &#039;&#039;&#039;Rules [new]&#039;&#039;&#039; — neue API-basierte Engine&lt;br /&gt;
* &#039;&#039;&#039;Rules&#039;&#039;&#039; — alte Engine (Legacy)&lt;br /&gt;
&lt;br /&gt;
Neue Regeln &#039;&#039;&#039;immer in beiden&#039;&#039;&#039; anlegen! Bei Problemen immer beide prüfen.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 2: Wo steht was? ==&lt;br /&gt;
&lt;br /&gt;
=== IP-Adressen (Beispiel-Setup) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Gerät !! Interface !! IP !! Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
| Router / Gateway || — || 192.168.2.1 || Gateway, WLAN, DynDNS&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense WAN || wan-interface || 192.168.2.2 || Statisch konfiguriert&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense LAN / Server-VLAN || lan-interface || 192.168.10.1 || Gateway für Server-Netz&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver || eno1 / eth0 || 192.168.10.100 || Fest per DHCP-Reservation (MAC-Adresse)&lt;br /&gt;
|-&lt;br /&gt;
| Client-Geräte || WLAN || 192.168.2.x || Im Router-Netz, nicht im Server-VLAN&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Homeserver: Netzwerk-Interface-Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Der Homeserver bezieht seine IP per DHCP vom OPNsense-DHCP-Server. Bei Debian/Ubuntu mit systemd-networkd:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/systemd/network/10-eth0.network&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Korrekter Inhalt (DHCP):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[Match]&lt;br /&gt;
Name=eno1&lt;br /&gt;
&lt;br /&gt;
[Network]&lt;br /&gt;
DHCP=ipv4&lt;br /&gt;
&lt;br /&gt;
[DHCP]&lt;br /&gt;
RouteMetric=100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ &#039;&#039;&#039;Niemals&#039;&#039;&#039; eine statische IP oder einen Gateway manuell eintragen!&lt;br /&gt;
Der Default-Gateway kommt immer vom DHCP-Server der OPNsense-Firewall (&amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Kea DHCP Lease-Datei (OPNsense) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/db/kea/kea-leases4.csv&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier verwaltet Kea die aktiven Leases. Bei Problemen mit doppelten IPs kann diese Datei (nach &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;) auf den Header reduziert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context,pool_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 3: Systematische Diagnose — Schritt für Schritt ==&lt;br /&gt;
&lt;br /&gt;
=== Grundprinzip: Von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Immer von außen nach innen vorgehen — nie raten, immer messen. Jede Schicht einzeln prüfen.&lt;br /&gt;
&lt;br /&gt;
==== Schritt 1: Ist OPNsense überhaupt erreichbar? ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Vom Client-Rechner:&lt;br /&gt;
ping 192.168.2.2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ OPNsense antwortet standardmäßig &#039;&#039;&#039;nicht&#039;&#039;&#039; auf ICMP/Ping von außen — das ist korrekt!&lt;br /&gt;
&lt;br /&gt;
Stattdessen prüfen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Web-UI erreichbar?&lt;br /&gt;
https://192.168.2.2:8443&lt;br /&gt;
&lt;br /&gt;
# Router zeigt OPNsense als verbundenes Gerät?&lt;br /&gt;
http://192.168.2.1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 2: OPNsense intern prüfen ====&lt;br /&gt;
&lt;br /&gt;
Per SSH oder serieller Konsole auf OPNsense:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# WAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;wan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.2.2, status: active&lt;br /&gt;
&lt;br /&gt;
# LAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;lan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.10.1, status: active&lt;br /&gt;
&lt;br /&gt;
# Router erreichbar?&lt;br /&gt;
ping -c 3 192.168.2.1&lt;br /&gt;
&lt;br /&gt;
# Homeserver erreichbar?&lt;br /&gt;
ping -c 3 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 3: Homeserver direkt prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# SSH auf Homeserver:&lt;br /&gt;
ssh root@192.168.10.100&lt;br /&gt;
&lt;br /&gt;
# Alle Container laufen?&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# Internet vom Homeserver aus erreichbar?&lt;br /&gt;
ping -c 3 9.9.9.9&lt;br /&gt;
&lt;br /&gt;
# Routing-Tabelle korrekt?&lt;br /&gt;
ip route show&lt;br /&gt;
# Erwartete Default-Route: default via 192.168.10.1 dev eno1&lt;br /&gt;
# NICHT: default via 192.168.178.x — das wäre falsch!&lt;br /&gt;
&lt;br /&gt;
# Welche IP hat das Interface?&lt;br /&gt;
ip addr show eno1&lt;br /&gt;
# Erwartete IP: 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 4: Caddy / Reverse Proxy prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Läuft Caddy und antwortet er lokal?&lt;br /&gt;
curl -v http://localhost&lt;br /&gt;
# Erwartete Antwort: HTTP 308 Redirect → https://localhost/&lt;br /&gt;
&lt;br /&gt;
# Caddy-Logs auf Fehler prüfen:&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Typische Fehler in den Caddy-Logs:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fehlermeldung !! Bedeutung !! Lösung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dial tcp ...:443: connect: no route to host&amp;lt;/code&amp;gt; || Caddy kommt nicht ins Internet (Let&#039;s Encrypt nicht erreichbar) || Routing auf Homeserver prüfen (Schritt 3)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;no route to host&amp;lt;/code&amp;gt; bei Ping auf 9.9.9.9 || Falscher Default-Gateway || &amp;lt;code&amp;gt;ip route show&amp;lt;/code&amp;gt; prüfen, falsche Route entfernen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Schritt 5: NAT und Firewall-Regeln prüfen (OPNsense Shell) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# NAT-Regeln anzeigen:&lt;br /&gt;
pfctl -s nat | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Firewall-Regeln anzeigen:&lt;br /&gt;
pfctl -s rules | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf WAN-Interface beobachten (kommt der Request an?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;wan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf LAN-Interface beobachten (wird er weitergeleitet?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;lan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Diagnose-Logik:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tcpdump WAN sieht Traffic, LAN nicht → NAT-Regel prüfen!&lt;br /&gt;
tcpdump WAN sieht keinen Traffic    → Portweiterleitung im Router prüfen!&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 6: Bekannte Fallstricke ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Problem !! Symptom !! Ursache !! Fix&lt;br /&gt;
|-&lt;br /&gt;
| Falsche statische Route || &amp;lt;code&amp;gt;ping 9.9.9.9&amp;lt;/code&amp;gt; schlägt fehl || Netzwerk-Config hat statischen Gateway eingetragen || Auf DHCP umstellen, &amp;lt;code&amp;gt;systemctl restart systemd-networkd&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver hat falsche IP || NAT-Regeln greifen nicht || DHCP hat beim Neustart temporär andere IP vergeben || DHCP-Reservation per MAC-Adresse einrichten&lt;br /&gt;
|-&lt;br /&gt;
| DHCP-Leases durcheinander || Server taucht mit zwei IPs auf || Neustart hat neuen Lease vor Ablauf des alten erzeugt || &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;, Lease-CSV bereinigen, &amp;lt;code&amp;gt;configctl kea start&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense Firewall-Regel fehlt || Dienste von außen nicht erreichbar, intern OK || Regel nur in einer der beiden Engines angelegt || Regel in &#039;&#039;&#039;beiden&#039;&#039;&#039; Engines anlegen (Rules [new] + Rules)&lt;br /&gt;
|-&lt;br /&gt;
| NAT-Regel ohne Subnetz-Maske || Traffic kommt nicht an || &amp;lt;code&amp;gt;192.168.178.0&amp;lt;/code&amp;gt; statt &amp;lt;code&amp;gt;192.168.178.0/24&amp;lt;/code&amp;gt; eingetragen || Subnetz-Maske ergänzen — ohne /24 gilt nur die Netzadresse selbst!&lt;br /&gt;
|-&lt;br /&gt;
| Source/Destination Port vertauscht || Verbindungen werden blockiert || Bei Firewall-Regel Port unter &amp;quot;Source&amp;quot; statt &amp;quot;Destination&amp;quot; eingetragen || Source Port: any / Destination Port: gewünschter Port&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Notfall-Cheatsheet ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# OPNsense: Firewall temporär deaktivieren (Notfall!)&lt;br /&gt;
pfctl -d&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Firewall wieder aktivieren&lt;br /&gt;
pfctl -e&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Kea DHCP stoppen/starten&lt;br /&gt;
configctl kea stop&lt;br /&gt;
configctl kea start&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Falsche Default-Route entfernen&lt;br /&gt;
ip route del default via &amp;amp;lt;falsche-gateway-ip&amp;amp;gt; dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: IP manuell setzen (Sofortlösung bei DHCP-Problemen)&lt;br /&gt;
ip addr add 192.168.10.100/24 dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Netzwerk-Dienst neu starten (Verbindung kurz weg!)&lt;br /&gt;
systemctl restart systemd-networkd&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Docker-Logs prüfen&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Alias-Tabellen prüfen (Blocklisten)&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | wc -l&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | grep &amp;amp;lt;IP&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Sicherheitshinweise ==&lt;br /&gt;
&lt;br /&gt;
* SSH-Ports &#039;&#039;&#039;nicht&#039;&#039;&#039; über das Internet freigeben — nur intern erreichbar lassen! Wenn das nicht geht: VPN-Tunnel!&lt;br /&gt;
* Portweiterleitung im Router auf das &#039;&#039;&#039;Minimum&#039;&#039;&#039; beschränken (nur die Ports 80 + 443 öffnen)&lt;br /&gt;
* Für interne Admin-Interfaces (OPNsense Web-UI, Monitoring) &#039;&#039;&#039;keine externen Freigaben&#039;&#039;&#039;&lt;br /&gt;
* DHCP-Reservations per MAC-Adresse oder statische IP-Adressen verhindern IP-Wechsel nach Neustarts&lt;br /&gt;
* Bei Firewall-Regeln: Block-Regeln &#039;&#039;&#039;immer&#039;&#039;&#039; vor Pass-Regeln platzieren&lt;br /&gt;
&lt;br /&gt;
Abschließend eine absolute Regel, die immer und durch die Ewigkeiten gilt:&lt;br /&gt;
* Dienste, die auf einem Rechner &#039;&#039;&#039;NICHT&#039;&#039;&#039; existieren, werden niemals angegriffen! Wenig ist hier mehr!&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Dieser Artikel basiert auf praktischen Erfahrungen aus dem Betrieb eines selbst gehosteten Servers mit OPNsense, Cisco-Switch und Docker-Stack.&#039;&#039;&lt;br /&gt;
&#039;&#039;Erstellt: Mai 2026&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=253</id>
		<title>Homeserver-Sicherheitsarchitektur</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=253"/>
		<updated>2026-05-27T23:28:03Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Die Kette von außen nach innen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Homeserver-Sicherheitsarchitektur: Aufbau, Funktionsweise und Diagnose ==&lt;br /&gt;
&lt;br /&gt;
Einen eigenen Server an&#039;s Internet zu bekommen, ist nicht allzu schwierig. Ein Dienst, der die eigene, vom Internet-Provider zugewiesene IP-Adresse in einen festen Domain-Namen umwandelt (siehe: [https://de.wikipedia.org/wiki/Dynamisches_DNS Dynamisches DNS]), wird im privaten Bereich die Voraussetzung sein.&lt;br /&gt;
Es gibt verschiedene Anbieter, oft auch kostenlose.&lt;br /&gt;
&lt;br /&gt;
=== Ein Leitfaden für selbst gehostete Server mit OPNsense, Managed Switch und Docker ===&lt;br /&gt;
&lt;br /&gt;
Die Kehrseite: Sowie der Server über&#039;s Internet erreichbar ist, ist er angreifbar. Das ist kein theoretisches Szenario. Meiner Erfahrung nach ist es eine Frage von Stunden, bis die ersten Bots &amp;quot;anklopfen&amp;quot;, nach laufenden Diensten suchen, nach offenen Ports, nach Schwachstellen.&lt;br /&gt;
&lt;br /&gt;
Aufgrund einer mangelhaften Konfiguration (offener Samba-Port) hatte ich die sehr reale Erfahrung einer russischen Hackerbande, die einige Hundert Textdateien mit Zahlungsaufforderungen und einen Verschlüsselungstrojaner auf meinem Rechner hinterlassen hatte. Gerettet hatten mich damals die Dateirechte von Linux. Das fehlende E(x)ecutional-Flag und die eingeschränkten Benutzerrechte hatten den Trojaner ausgebremst.&lt;br /&gt;
&lt;br /&gt;
Trotzdem: Nie wieder!&lt;br /&gt;
Ein wenig von dem, was ich gelernt habe, gebe ich ich hier weiter.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Einleitung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt den Aufbau einer &#039;&#039;&#039;sicheren&#039;&#039;&#039; Netzwerkarchitektur für einen Homeserver, der über das öffentliche Internet erreichbar ist. Der Beitrag richtet sich an alle, die ihre Daten selbst kontrollieren wollen — und dabei nicht unfreiwillig Teil einer globalen Angriffs-Infrastruktur werden möchten. Er will zum Verständnis beitragen, wie die einzelnen Komponenten zusammenspielen — und wie man systematisch vorgeht, wenn etwas nicht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der Fokus liegt nicht auf einer spezifischen Hardware-Konfiguration, sondern auf dem allgemeinen Prinzip: Wie kommt ein Request von außen sicher zu einem Docker-Container?&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Annahmen / Szenario ==&lt;br /&gt;
&lt;br /&gt;
Folgende Komponenten werden in diesem Artikel vorausgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver&#039;&#039;&#039; (Raspberry Pi, Intel NUC, oder beliebiger Linux-Server)&lt;br /&gt;
** Betriebssystem: Debian/Ubuntu oder vergleichbar&lt;br /&gt;
** Docker mit mehreren Diensten (z.B. WordPress, Nextcloud, MediaWiki)&lt;br /&gt;
** Caddy als Reverse Proxy (alternativ funktionieren [https://nginx.org/ nginx], [https://httpd.apache.org/ Apache], oder (ggf. kostenpflichtige) proprietäre Lösungen. Caddy allerdings hat das für mich charmante Feature, sich eigenständig um die TSL-Zertifikate und ihre Verlängerung bei LetsEncrypt zu kümmern. Wer aufgrund &amp;quot;zu vieler&amp;quot; Fehlversuche bei der Zertifikats-Einrichtung von LetsEncrypt auf Tage gesperrt wurde, wird mein Faible über diesen Automatismus nachvollziehen oder teilen können.)&lt;br /&gt;
** fail2ban als Brute-Force-Schutz&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;DynDNS-Dienst&#039;&#039;&#039; der dem Homeserver eine feste Domain zuweist&lt;br /&gt;
** Beispiel: &amp;lt;code&amp;gt;myhomeserver.dyndns.de&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Router / Heimnetz-Gateway&#039;&#039;&#039;&lt;br /&gt;
** Beispiel-IP: &amp;lt;code&amp;gt;192.168.2.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Portweiterleitung, WLAN, DynDNS-Aktualisierung&lt;br /&gt;
** Typisch: FritzBox, aber jeder Router mit Portweiterleitung funktioniert&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; (dedizierte Hardware-Firewall)&lt;br /&gt;
** WAN-Interface: &amp;lt;code&amp;gt;192.168.2.2&amp;lt;/code&amp;gt; (im Router-Netz)&lt;br /&gt;
** LAN-Interface / Server-VLAN: &amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Firewall, NAT, DHCP, IDS/IPS&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Managed Switch&#039;&#039;&#039; (optional, für VLAN-Segmentierung)&lt;br /&gt;
** Trennt Server-VLAN vom Rest des Netzes&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver-IP&#039;&#039;&#039;: &amp;lt;code&amp;gt;192.168.10.100&amp;lt;/code&amp;gt; (per DHCP-Reservation oder besser: Per statischer IP-Adresse fest)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 1: Wie funktionieren die Weiterleitungen? Wer macht was? ==&lt;br /&gt;
&lt;br /&gt;
=== Die Kette von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Ein Request von außen (z.B. Browser ruft &amp;lt;code&amp;gt;https://myhomeserver.dyndns.de&amp;lt;/code&amp;gt; auf) durchläuft folgende Stationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Internet&lt;br /&gt;
    ↓ DNS-Auflösung: dyndns.de → öffentliche IP des Heimnetzes&lt;br /&gt;
Router / Gateway (192.168.2.1)&lt;br /&gt;
    ↓ Portweiterleitung: :80 + :443 (und nur! diese!!) → 192.168.2.2&lt;br /&gt;
OPNsense WAN-Interface (192.168.2.2)&lt;br /&gt;
    ↓ Destination NAT: :80/:443 → 192.168.10.100&lt;br /&gt;
Homeserver eno1/eth0 (192.168.10.100)&lt;br /&gt;
    ↓ Docker-Port-Binding: 0.0.0.0:80 + 0.0.0.0:443&lt;br /&gt;
Caddy / Reverse Proxy (Docker-intern)&lt;br /&gt;
    ↓ Reverse Proxy anhand des Host-Headers&lt;br /&gt;
Ziel-Container (z.B. wordpress, nextcloud, ...)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit ist der Server auf der IP-Ebene (Layer 3 des OSI-Modells) von außen hin &amp;quot;unsichtbar&amp;quot;: Die Firewall (OPNsense) lebt, mit dem Gateway, im 192.168.2-er Netz. Von dort routet sie alle Anfragen über die Ports 80 und 443 an das Interface 192.168.10.100. Dahinter, also im 192.168.10-er-Subnetz, residiert der Heimserver.&lt;br /&gt;
&lt;br /&gt;
Am Ende dieses Beitrages gibt es Sicherheitshinweise. Bitte dringend beachten, dass der Router ausschließlich die Ports &#039;&#039;&#039;80/TCP&#039;&#039;&#039; und &#039;&#039;&#039;443/TCP&#039;&#039;&#039; nach außen frei gibt. Der Webserver wird dabei so konfiguriert, dass HTTP-Daten über Port 80 nach HTTPS auf Port 443 umgeleitet werden.&lt;br /&gt;
&lt;br /&gt;
Die Idee, ausschließlich HTTPS zuzulassen, läge nahe. Damit bräuchte sich der Webserver nicht um die Weiterleitung auf Port 443 zu befassen.&lt;br /&gt;
Bedauerlicherweise wird in diesem Fall der Umgang mit dem TLS-Zertifikat, das den HTTPS-Datenstrom verschlüsselt, scheitern. [https://letsencrypt.org/ LetsEncrypt] benötigt bei Einrichtung und Verlängerung seiner Zertifikate einen offenen 80-er Port.&lt;br /&gt;
&lt;br /&gt;
Sollte es nötig sein, den Server von außen zu administrieren, wird man darüber nachdenken, einen VPN-Tunnel einzurichten. Sicherer jedoch - und einfacher - ist es dennoch, die Administration ausschließlich über einen zertifikats-geschützten SSH-Zugang im inneren 192.168.-er-Netz zuzulassen und, abgesehen von 80 und 443, auf jeden nach außen exponierten Port zu verzichten.&lt;br /&gt;
&lt;br /&gt;
=== Wer macht was? ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Komponente !! Aufgabe !! Konfigurationsort&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Router / Gateway&#039;&#039;&#039; || DynDNS-Aktualisierung, erste NAT-Stufe, WLAN || Router Web-UI → Portfreigaben&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; || Firewall-Regeln, zweite NAT-Stufe (Destination NAT), DHCP für Server-VLAN || OPNsense Web-UI (Standard: https://&amp;amp;lt;wan-ip&amp;amp;gt;:443 oder :8443)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Caddy / Reverse Proxy&#039;&#039;&#039; || TLS-Terminierung, Let&#039;s Encrypt, Weiterleitung an Container || Caddyfile auf dem Homeserver&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Docker&#039;&#039;&#039; || Container-Isolation, internes Netz (Standard: 172.18.0.0/16) || docker-compose.yml pro Dienst&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fail2ban&#039;&#039;&#039; || Brute-Force-Schutz auf Applikationsebene || Jail-Configs im fail2ban-Container&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Wichtig: OPNsense hat ZWEI Firewall-Engines ===&lt;br /&gt;
&lt;br /&gt;
OPNsense 26.x hat zwei parallele Regelwerke:&lt;br /&gt;
* &#039;&#039;&#039;Rules [new]&#039;&#039;&#039; — neue API-basierte Engine&lt;br /&gt;
* &#039;&#039;&#039;Rules&#039;&#039;&#039; — alte Engine (Legacy)&lt;br /&gt;
&lt;br /&gt;
Neue Regeln &#039;&#039;&#039;immer in beiden&#039;&#039;&#039; anlegen! Bei Problemen immer beide prüfen.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 2: Wo steht was? ==&lt;br /&gt;
&lt;br /&gt;
=== IP-Adressen (Beispiel-Setup) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Gerät !! Interface !! IP !! Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
| Router / Gateway || — || 192.168.2.1 || Gateway, WLAN, DynDNS&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense WAN || wan-interface || 192.168.2.2 || Statisch konfiguriert&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense LAN / Server-VLAN || lan-interface || 192.168.10.1 || Gateway für Server-Netz&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver || eno1 / eth0 || 192.168.10.100 || Fest per DHCP-Reservation (MAC-Adresse)&lt;br /&gt;
|-&lt;br /&gt;
| Client-Geräte || WLAN || 192.168.2.x || Im Router-Netz, nicht im Server-VLAN&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Homeserver: Netzwerk-Interface-Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Der Homeserver bezieht seine IP per DHCP vom OPNsense-DHCP-Server. Bei Debian/Ubuntu mit systemd-networkd:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/systemd/network/10-eth0.network&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Korrekter Inhalt (DHCP):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[Match]&lt;br /&gt;
Name=eno1&lt;br /&gt;
&lt;br /&gt;
[Network]&lt;br /&gt;
DHCP=ipv4&lt;br /&gt;
&lt;br /&gt;
[DHCP]&lt;br /&gt;
RouteMetric=100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ &#039;&#039;&#039;Niemals&#039;&#039;&#039; eine statische IP oder einen Gateway manuell eintragen!&lt;br /&gt;
Der Default-Gateway kommt immer vom DHCP-Server der OPNsense-Firewall (&amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Kea DHCP Lease-Datei (OPNsense) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/db/kea/kea-leases4.csv&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier verwaltet Kea die aktiven Leases. Bei Problemen mit doppelten IPs kann diese Datei (nach &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;) auf den Header reduziert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context,pool_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 3: Systematische Diagnose — Schritt für Schritt ==&lt;br /&gt;
&lt;br /&gt;
=== Grundprinzip: Von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Immer von außen nach innen vorgehen — nie raten, immer messen. Jede Schicht einzeln prüfen.&lt;br /&gt;
&lt;br /&gt;
==== Schritt 1: Ist OPNsense überhaupt erreichbar? ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Vom Client-Rechner:&lt;br /&gt;
ping 192.168.2.2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ OPNsense antwortet standardmäßig &#039;&#039;&#039;nicht&#039;&#039;&#039; auf ICMP/Ping von außen — das ist korrekt!&lt;br /&gt;
&lt;br /&gt;
Stattdessen prüfen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Web-UI erreichbar?&lt;br /&gt;
https://192.168.2.2:8443&lt;br /&gt;
&lt;br /&gt;
# Router zeigt OPNsense als verbundenes Gerät?&lt;br /&gt;
http://192.168.2.1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 2: OPNsense intern prüfen ====&lt;br /&gt;
&lt;br /&gt;
Per SSH oder serieller Konsole auf OPNsense:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# WAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;wan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.2.2, status: active&lt;br /&gt;
&lt;br /&gt;
# LAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;lan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.10.1, status: active&lt;br /&gt;
&lt;br /&gt;
# Router erreichbar?&lt;br /&gt;
ping -c 3 192.168.2.1&lt;br /&gt;
&lt;br /&gt;
# Homeserver erreichbar?&lt;br /&gt;
ping -c 3 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 3: Homeserver direkt prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# SSH auf Homeserver:&lt;br /&gt;
ssh root@192.168.10.100&lt;br /&gt;
&lt;br /&gt;
# Alle Container laufen?&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# Internet vom Homeserver aus erreichbar?&lt;br /&gt;
ping -c 3 9.9.9.9&lt;br /&gt;
&lt;br /&gt;
# Routing-Tabelle korrekt?&lt;br /&gt;
ip route show&lt;br /&gt;
# Erwartete Default-Route: default via 192.168.10.1 dev eno1&lt;br /&gt;
# NICHT: default via 192.168.178.x — das wäre falsch!&lt;br /&gt;
&lt;br /&gt;
# Welche IP hat das Interface?&lt;br /&gt;
ip addr show eno1&lt;br /&gt;
# Erwartete IP: 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 4: Caddy / Reverse Proxy prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Läuft Caddy und antwortet er lokal?&lt;br /&gt;
curl -v http://localhost&lt;br /&gt;
# Erwartete Antwort: HTTP 308 Redirect → https://localhost/&lt;br /&gt;
&lt;br /&gt;
# Caddy-Logs auf Fehler prüfen:&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Typische Fehler in den Caddy-Logs:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fehlermeldung !! Bedeutung !! Lösung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dial tcp ...:443: connect: no route to host&amp;lt;/code&amp;gt; || Caddy kommt nicht ins Internet (Let&#039;s Encrypt nicht erreichbar) || Routing auf Homeserver prüfen (Schritt 3)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;no route to host&amp;lt;/code&amp;gt; bei Ping auf 9.9.9.9 || Falscher Default-Gateway || &amp;lt;code&amp;gt;ip route show&amp;lt;/code&amp;gt; prüfen, falsche Route entfernen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Schritt 5: NAT und Firewall-Regeln prüfen (OPNsense Shell) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# NAT-Regeln anzeigen:&lt;br /&gt;
pfctl -s nat | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Firewall-Regeln anzeigen:&lt;br /&gt;
pfctl -s rules | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf WAN-Interface beobachten (kommt der Request an?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;wan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf LAN-Interface beobachten (wird er weitergeleitet?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;lan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Diagnose-Logik:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tcpdump WAN sieht Traffic, LAN nicht → NAT-Regel prüfen!&lt;br /&gt;
tcpdump WAN sieht keinen Traffic    → Portweiterleitung im Router prüfen!&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 6: Bekannte Fallstricke ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Problem !! Symptom !! Ursache !! Fix&lt;br /&gt;
|-&lt;br /&gt;
| Falsche statische Route || &amp;lt;code&amp;gt;ping 9.9.9.9&amp;lt;/code&amp;gt; schlägt fehl || Netzwerk-Config hat statischen Gateway eingetragen || Auf DHCP umstellen, &amp;lt;code&amp;gt;systemctl restart systemd-networkd&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver hat falsche IP || NAT-Regeln greifen nicht || DHCP hat beim Neustart temporär andere IP vergeben || DHCP-Reservation per MAC-Adresse einrichten&lt;br /&gt;
|-&lt;br /&gt;
| DHCP-Leases durcheinander || Server taucht mit zwei IPs auf || Neustart hat neuen Lease vor Ablauf des alten erzeugt || &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;, Lease-CSV bereinigen, &amp;lt;code&amp;gt;configctl kea start&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense Firewall-Regel fehlt || Dienste von außen nicht erreichbar, intern OK || Regel nur in einer der beiden Engines angelegt || Regel in &#039;&#039;&#039;beiden&#039;&#039;&#039; Engines anlegen (Rules [new] + Rules)&lt;br /&gt;
|-&lt;br /&gt;
| NAT-Regel ohne Subnetz-Maske || Traffic kommt nicht an || &amp;lt;code&amp;gt;192.168.178.0&amp;lt;/code&amp;gt; statt &amp;lt;code&amp;gt;192.168.178.0/24&amp;lt;/code&amp;gt; eingetragen || Subnetz-Maske ergänzen — ohne /24 gilt nur die Netzadresse selbst!&lt;br /&gt;
|-&lt;br /&gt;
| Source/Destination Port vertauscht || Verbindungen werden blockiert || Bei Firewall-Regel Port unter &amp;quot;Source&amp;quot; statt &amp;quot;Destination&amp;quot; eingetragen || Source Port: any / Destination Port: gewünschter Port&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Notfall-Cheatsheet ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# OPNsense: Firewall temporär deaktivieren (Notfall!)&lt;br /&gt;
pfctl -d&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Firewall wieder aktivieren&lt;br /&gt;
pfctl -e&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Kea DHCP stoppen/starten&lt;br /&gt;
configctl kea stop&lt;br /&gt;
configctl kea start&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Falsche Default-Route entfernen&lt;br /&gt;
ip route del default via &amp;amp;lt;falsche-gateway-ip&amp;amp;gt; dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: IP manuell setzen (Sofortlösung bei DHCP-Problemen)&lt;br /&gt;
ip addr add 192.168.10.100/24 dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Netzwerk-Dienst neu starten (Verbindung kurz weg!)&lt;br /&gt;
systemctl restart systemd-networkd&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Docker-Logs prüfen&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Alias-Tabellen prüfen (Blocklisten)&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | wc -l&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | grep &amp;amp;lt;IP&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Sicherheitshinweise ==&lt;br /&gt;
&lt;br /&gt;
* SSH-Ports &#039;&#039;&#039;nicht&#039;&#039;&#039; über das Internet freigeben — nur intern erreichbar lassen! Wenn das nicht geht: VPN-Tunnel!&lt;br /&gt;
* Portweiterleitung im Router auf das &#039;&#039;&#039;Minimum&#039;&#039;&#039; beschränken (nur die Ports 80 + 443 öffnen)&lt;br /&gt;
* Für interne Admin-Interfaces (OPNsense Web-UI, Monitoring) &#039;&#039;&#039;keine externen Freigaben&#039;&#039;&#039;&lt;br /&gt;
* DHCP-Reservations per MAC-Adresse oder statische IP-Adressen verhindern IP-Wechsel nach Neustarts&lt;br /&gt;
* Bei Firewall-Regeln: Block-Regeln &#039;&#039;&#039;immer&#039;&#039;&#039; vor Pass-Regeln platzieren&lt;br /&gt;
&lt;br /&gt;
Abschließend eine absolute Regeln, die immer und durch die Ewigkeiten gilt:&lt;br /&gt;
* Dienste, die auf einem Rechner &#039;&#039;&#039;NICHT&#039;&#039;&#039; existieren, werden niemals angegriffen! Wenig ist hier mehr!&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Dieser Artikel basiert auf praktischen Erfahrungen aus dem Betrieb eines selbst gehosteten Servers mit OPNsense, Cisco-Switch und Docker-Stack.&#039;&#039;&lt;br /&gt;
&#039;&#039;Erstellt: Mai 2026&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=252</id>
		<title>Homeserver-Sicherheitsarchitektur</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=252"/>
		<updated>2026-05-27T23:27:33Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Die Kette von außen nach innen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Homeserver-Sicherheitsarchitektur: Aufbau, Funktionsweise und Diagnose ==&lt;br /&gt;
&lt;br /&gt;
Einen eigenen Server an&#039;s Internet zu bekommen, ist nicht allzu schwierig. Ein Dienst, der die eigene, vom Internet-Provider zugewiesene IP-Adresse in einen festen Domain-Namen umwandelt (siehe: [https://de.wikipedia.org/wiki/Dynamisches_DNS Dynamisches DNS]), wird im privaten Bereich die Voraussetzung sein.&lt;br /&gt;
Es gibt verschiedene Anbieter, oft auch kostenlose.&lt;br /&gt;
&lt;br /&gt;
=== Ein Leitfaden für selbst gehostete Server mit OPNsense, Managed Switch und Docker ===&lt;br /&gt;
&lt;br /&gt;
Die Kehrseite: Sowie der Server über&#039;s Internet erreichbar ist, ist er angreifbar. Das ist kein theoretisches Szenario. Meiner Erfahrung nach ist es eine Frage von Stunden, bis die ersten Bots &amp;quot;anklopfen&amp;quot;, nach laufenden Diensten suchen, nach offenen Ports, nach Schwachstellen.&lt;br /&gt;
&lt;br /&gt;
Aufgrund einer mangelhaften Konfiguration (offener Samba-Port) hatte ich die sehr reale Erfahrung einer russischen Hackerbande, die einige Hundert Textdateien mit Zahlungsaufforderungen und einen Verschlüsselungstrojaner auf meinem Rechner hinterlassen hatte. Gerettet hatten mich damals die Dateirechte von Linux. Das fehlende E(x)ecutional-Flag und die eingeschränkten Benutzerrechte hatten den Trojaner ausgebremst.&lt;br /&gt;
&lt;br /&gt;
Trotzdem: Nie wieder!&lt;br /&gt;
Ein wenig von dem, was ich gelernt habe, gebe ich ich hier weiter.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Einleitung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt den Aufbau einer &#039;&#039;&#039;sicheren&#039;&#039;&#039; Netzwerkarchitektur für einen Homeserver, der über das öffentliche Internet erreichbar ist. Der Beitrag richtet sich an alle, die ihre Daten selbst kontrollieren wollen — und dabei nicht unfreiwillig Teil einer globalen Angriffs-Infrastruktur werden möchten. Er will zum Verständnis beitragen, wie die einzelnen Komponenten zusammenspielen — und wie man systematisch vorgeht, wenn etwas nicht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der Fokus liegt nicht auf einer spezifischen Hardware-Konfiguration, sondern auf dem allgemeinen Prinzip: Wie kommt ein Request von außen sicher zu einem Docker-Container?&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Annahmen / Szenario ==&lt;br /&gt;
&lt;br /&gt;
Folgende Komponenten werden in diesem Artikel vorausgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver&#039;&#039;&#039; (Raspberry Pi, Intel NUC, oder beliebiger Linux-Server)&lt;br /&gt;
** Betriebssystem: Debian/Ubuntu oder vergleichbar&lt;br /&gt;
** Docker mit mehreren Diensten (z.B. WordPress, Nextcloud, MediaWiki)&lt;br /&gt;
** Caddy als Reverse Proxy (alternativ funktionieren [https://nginx.org/ nginx], [https://httpd.apache.org/ Apache], oder (ggf. kostenpflichtige) proprietäre Lösungen. Caddy allerdings hat das für mich charmante Feature, sich eigenständig um die TSL-Zertifikate und ihre Verlängerung bei LetsEncrypt zu kümmern. Wer aufgrund &amp;quot;zu vieler&amp;quot; Fehlversuche bei der Zertifikats-Einrichtung von LetsEncrypt auf Tage gesperrt wurde, wird mein Faible über diesen Automatismus nachvollziehen oder teilen können.)&lt;br /&gt;
** fail2ban als Brute-Force-Schutz&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;DynDNS-Dienst&#039;&#039;&#039; der dem Homeserver eine feste Domain zuweist&lt;br /&gt;
** Beispiel: &amp;lt;code&amp;gt;myhomeserver.dyndns.de&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Router / Heimnetz-Gateway&#039;&#039;&#039;&lt;br /&gt;
** Beispiel-IP: &amp;lt;code&amp;gt;192.168.2.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Portweiterleitung, WLAN, DynDNS-Aktualisierung&lt;br /&gt;
** Typisch: FritzBox, aber jeder Router mit Portweiterleitung funktioniert&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; (dedizierte Hardware-Firewall)&lt;br /&gt;
** WAN-Interface: &amp;lt;code&amp;gt;192.168.2.2&amp;lt;/code&amp;gt; (im Router-Netz)&lt;br /&gt;
** LAN-Interface / Server-VLAN: &amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Firewall, NAT, DHCP, IDS/IPS&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Managed Switch&#039;&#039;&#039; (optional, für VLAN-Segmentierung)&lt;br /&gt;
** Trennt Server-VLAN vom Rest des Netzes&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver-IP&#039;&#039;&#039;: &amp;lt;code&amp;gt;192.168.10.100&amp;lt;/code&amp;gt; (per DHCP-Reservation oder besser: Per statischer IP-Adresse fest)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 1: Wie funktionieren die Weiterleitungen? Wer macht was? ==&lt;br /&gt;
&lt;br /&gt;
=== Die Kette von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Ein Request von außen (z.B. Browser ruft &amp;lt;code&amp;gt;https://myhomeserver.dyndns.de&amp;lt;/code&amp;gt; auf) durchläuft folgende Stationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Internet&lt;br /&gt;
    ↓ DNS-Auflösung: dyndns.de → öffentliche IP des Heimnetzes&lt;br /&gt;
Router / Gateway (192.168.2.1)&lt;br /&gt;
    ↓ Portweiterleitung: :80 + :443 (und nur! diese!!) → 192.168.2.2&lt;br /&gt;
OPNsense WAN-Interface (192.168.2.2)&lt;br /&gt;
    ↓ Destination NAT: :80/:443 → 192.168.10.100&lt;br /&gt;
Homeserver eno1/eth0 (192.168.10.100)&lt;br /&gt;
    ↓ Docker-Port-Binding: 0.0.0.0:80 + 0.0.0.0:443&lt;br /&gt;
Caddy / Reverse Proxy (Docker-intern)&lt;br /&gt;
    ↓ Reverse Proxy anhand des Host-Headers&lt;br /&gt;
Ziel-Container (z.B. wordpress, nextcloud, ...)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit ist der Server auf der IP-Ebene (Layer 3 des OSI-Modells) von außen hin &amp;quot;unsichtbar&amp;quot;: Die Firewall (OPNsense) lebt, mit dem Gateway, im 192.168.2-er Netz. Von dort routet sie alle Anfragen über die Ports 80 und 443 an das Interface 192.168.10.100. Dahinter, also im 192.168.10-er-Subnetz, residiert der Heimserver.&lt;br /&gt;
&lt;br /&gt;
Am Ende dieses Beitrages gibt es Sicherheitshinweise. Bitte dringend beachten, dass der Router ausschließlich die Ports &#039;&#039;&#039;80/TCP&#039;&#039;&#039; und &#039;&#039;&#039;443/TCP&#039;&#039;&#039; nach außen frei gibt. Der Webserver wird dabei so konfiguriert, dass HTTP-Daten über Port 80 nach HTTPS auf Port 443 umgeleitet werden.&lt;br /&gt;
&lt;br /&gt;
Die Idee, ausschließlich HTTPS zuzulassen, läge nahe. Damit bräuchte sich der Webserver nicht um die Weiterleitung auf Port 443 zu befassen.&lt;br /&gt;
Bedauerlicherweise wird in diesem Fall der Umgang mit dem TLS-Zertifikat, das den HTTPS-Datenstrom verschlüsselt, scheitern. [https://letsencrypt.org/ LetsEncrypt] benötigt bei Einrichtung und Verlängerung seiner Zertifikate einen offenen 80-er Port.&lt;br /&gt;
&lt;br /&gt;
Sollte es nötig sein, den Server von außen zu administrieren, wird man darüber nachdenken, einen VPN-Tunnel einzurichten. Sicherer jedoch - und einfacher - ist es dennoch, die Administration ausschließlich über einen zertifikats-geschützten SSH-Zugang im inneren 192.168.-er-Netz zuzulassen, und, abgesehen von 80 und 443, auf jeden nach außen exponierten Port zu verzichten.&lt;br /&gt;
&lt;br /&gt;
=== Wer macht was? ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Komponente !! Aufgabe !! Konfigurationsort&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Router / Gateway&#039;&#039;&#039; || DynDNS-Aktualisierung, erste NAT-Stufe, WLAN || Router Web-UI → Portfreigaben&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; || Firewall-Regeln, zweite NAT-Stufe (Destination NAT), DHCP für Server-VLAN || OPNsense Web-UI (Standard: https://&amp;amp;lt;wan-ip&amp;amp;gt;:443 oder :8443)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Caddy / Reverse Proxy&#039;&#039;&#039; || TLS-Terminierung, Let&#039;s Encrypt, Weiterleitung an Container || Caddyfile auf dem Homeserver&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Docker&#039;&#039;&#039; || Container-Isolation, internes Netz (Standard: 172.18.0.0/16) || docker-compose.yml pro Dienst&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fail2ban&#039;&#039;&#039; || Brute-Force-Schutz auf Applikationsebene || Jail-Configs im fail2ban-Container&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Wichtig: OPNsense hat ZWEI Firewall-Engines ===&lt;br /&gt;
&lt;br /&gt;
OPNsense 26.x hat zwei parallele Regelwerke:&lt;br /&gt;
* &#039;&#039;&#039;Rules [new]&#039;&#039;&#039; — neue API-basierte Engine&lt;br /&gt;
* &#039;&#039;&#039;Rules&#039;&#039;&#039; — alte Engine (Legacy)&lt;br /&gt;
&lt;br /&gt;
Neue Regeln &#039;&#039;&#039;immer in beiden&#039;&#039;&#039; anlegen! Bei Problemen immer beide prüfen.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 2: Wo steht was? ==&lt;br /&gt;
&lt;br /&gt;
=== IP-Adressen (Beispiel-Setup) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Gerät !! Interface !! IP !! Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
| Router / Gateway || — || 192.168.2.1 || Gateway, WLAN, DynDNS&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense WAN || wan-interface || 192.168.2.2 || Statisch konfiguriert&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense LAN / Server-VLAN || lan-interface || 192.168.10.1 || Gateway für Server-Netz&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver || eno1 / eth0 || 192.168.10.100 || Fest per DHCP-Reservation (MAC-Adresse)&lt;br /&gt;
|-&lt;br /&gt;
| Client-Geräte || WLAN || 192.168.2.x || Im Router-Netz, nicht im Server-VLAN&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Homeserver: Netzwerk-Interface-Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Der Homeserver bezieht seine IP per DHCP vom OPNsense-DHCP-Server. Bei Debian/Ubuntu mit systemd-networkd:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/systemd/network/10-eth0.network&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Korrekter Inhalt (DHCP):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[Match]&lt;br /&gt;
Name=eno1&lt;br /&gt;
&lt;br /&gt;
[Network]&lt;br /&gt;
DHCP=ipv4&lt;br /&gt;
&lt;br /&gt;
[DHCP]&lt;br /&gt;
RouteMetric=100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ &#039;&#039;&#039;Niemals&#039;&#039;&#039; eine statische IP oder einen Gateway manuell eintragen!&lt;br /&gt;
Der Default-Gateway kommt immer vom DHCP-Server der OPNsense-Firewall (&amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Kea DHCP Lease-Datei (OPNsense) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/db/kea/kea-leases4.csv&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier verwaltet Kea die aktiven Leases. Bei Problemen mit doppelten IPs kann diese Datei (nach &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;) auf den Header reduziert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context,pool_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 3: Systematische Diagnose — Schritt für Schritt ==&lt;br /&gt;
&lt;br /&gt;
=== Grundprinzip: Von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Immer von außen nach innen vorgehen — nie raten, immer messen. Jede Schicht einzeln prüfen.&lt;br /&gt;
&lt;br /&gt;
==== Schritt 1: Ist OPNsense überhaupt erreichbar? ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Vom Client-Rechner:&lt;br /&gt;
ping 192.168.2.2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ OPNsense antwortet standardmäßig &#039;&#039;&#039;nicht&#039;&#039;&#039; auf ICMP/Ping von außen — das ist korrekt!&lt;br /&gt;
&lt;br /&gt;
Stattdessen prüfen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Web-UI erreichbar?&lt;br /&gt;
https://192.168.2.2:8443&lt;br /&gt;
&lt;br /&gt;
# Router zeigt OPNsense als verbundenes Gerät?&lt;br /&gt;
http://192.168.2.1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 2: OPNsense intern prüfen ====&lt;br /&gt;
&lt;br /&gt;
Per SSH oder serieller Konsole auf OPNsense:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# WAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;wan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.2.2, status: active&lt;br /&gt;
&lt;br /&gt;
# LAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;lan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.10.1, status: active&lt;br /&gt;
&lt;br /&gt;
# Router erreichbar?&lt;br /&gt;
ping -c 3 192.168.2.1&lt;br /&gt;
&lt;br /&gt;
# Homeserver erreichbar?&lt;br /&gt;
ping -c 3 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 3: Homeserver direkt prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# SSH auf Homeserver:&lt;br /&gt;
ssh root@192.168.10.100&lt;br /&gt;
&lt;br /&gt;
# Alle Container laufen?&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# Internet vom Homeserver aus erreichbar?&lt;br /&gt;
ping -c 3 9.9.9.9&lt;br /&gt;
&lt;br /&gt;
# Routing-Tabelle korrekt?&lt;br /&gt;
ip route show&lt;br /&gt;
# Erwartete Default-Route: default via 192.168.10.1 dev eno1&lt;br /&gt;
# NICHT: default via 192.168.178.x — das wäre falsch!&lt;br /&gt;
&lt;br /&gt;
# Welche IP hat das Interface?&lt;br /&gt;
ip addr show eno1&lt;br /&gt;
# Erwartete IP: 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 4: Caddy / Reverse Proxy prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Läuft Caddy und antwortet er lokal?&lt;br /&gt;
curl -v http://localhost&lt;br /&gt;
# Erwartete Antwort: HTTP 308 Redirect → https://localhost/&lt;br /&gt;
&lt;br /&gt;
# Caddy-Logs auf Fehler prüfen:&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Typische Fehler in den Caddy-Logs:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fehlermeldung !! Bedeutung !! Lösung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dial tcp ...:443: connect: no route to host&amp;lt;/code&amp;gt; || Caddy kommt nicht ins Internet (Let&#039;s Encrypt nicht erreichbar) || Routing auf Homeserver prüfen (Schritt 3)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;no route to host&amp;lt;/code&amp;gt; bei Ping auf 9.9.9.9 || Falscher Default-Gateway || &amp;lt;code&amp;gt;ip route show&amp;lt;/code&amp;gt; prüfen, falsche Route entfernen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Schritt 5: NAT und Firewall-Regeln prüfen (OPNsense Shell) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# NAT-Regeln anzeigen:&lt;br /&gt;
pfctl -s nat | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Firewall-Regeln anzeigen:&lt;br /&gt;
pfctl -s rules | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf WAN-Interface beobachten (kommt der Request an?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;wan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf LAN-Interface beobachten (wird er weitergeleitet?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;lan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Diagnose-Logik:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tcpdump WAN sieht Traffic, LAN nicht → NAT-Regel prüfen!&lt;br /&gt;
tcpdump WAN sieht keinen Traffic    → Portweiterleitung im Router prüfen!&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 6: Bekannte Fallstricke ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Problem !! Symptom !! Ursache !! Fix&lt;br /&gt;
|-&lt;br /&gt;
| Falsche statische Route || &amp;lt;code&amp;gt;ping 9.9.9.9&amp;lt;/code&amp;gt; schlägt fehl || Netzwerk-Config hat statischen Gateway eingetragen || Auf DHCP umstellen, &amp;lt;code&amp;gt;systemctl restart systemd-networkd&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver hat falsche IP || NAT-Regeln greifen nicht || DHCP hat beim Neustart temporär andere IP vergeben || DHCP-Reservation per MAC-Adresse einrichten&lt;br /&gt;
|-&lt;br /&gt;
| DHCP-Leases durcheinander || Server taucht mit zwei IPs auf || Neustart hat neuen Lease vor Ablauf des alten erzeugt || &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;, Lease-CSV bereinigen, &amp;lt;code&amp;gt;configctl kea start&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense Firewall-Regel fehlt || Dienste von außen nicht erreichbar, intern OK || Regel nur in einer der beiden Engines angelegt || Regel in &#039;&#039;&#039;beiden&#039;&#039;&#039; Engines anlegen (Rules [new] + Rules)&lt;br /&gt;
|-&lt;br /&gt;
| NAT-Regel ohne Subnetz-Maske || Traffic kommt nicht an || &amp;lt;code&amp;gt;192.168.178.0&amp;lt;/code&amp;gt; statt &amp;lt;code&amp;gt;192.168.178.0/24&amp;lt;/code&amp;gt; eingetragen || Subnetz-Maske ergänzen — ohne /24 gilt nur die Netzadresse selbst!&lt;br /&gt;
|-&lt;br /&gt;
| Source/Destination Port vertauscht || Verbindungen werden blockiert || Bei Firewall-Regel Port unter &amp;quot;Source&amp;quot; statt &amp;quot;Destination&amp;quot; eingetragen || Source Port: any / Destination Port: gewünschter Port&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Notfall-Cheatsheet ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# OPNsense: Firewall temporär deaktivieren (Notfall!)&lt;br /&gt;
pfctl -d&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Firewall wieder aktivieren&lt;br /&gt;
pfctl -e&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Kea DHCP stoppen/starten&lt;br /&gt;
configctl kea stop&lt;br /&gt;
configctl kea start&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Falsche Default-Route entfernen&lt;br /&gt;
ip route del default via &amp;amp;lt;falsche-gateway-ip&amp;amp;gt; dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: IP manuell setzen (Sofortlösung bei DHCP-Problemen)&lt;br /&gt;
ip addr add 192.168.10.100/24 dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Netzwerk-Dienst neu starten (Verbindung kurz weg!)&lt;br /&gt;
systemctl restart systemd-networkd&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Docker-Logs prüfen&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Alias-Tabellen prüfen (Blocklisten)&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | wc -l&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | grep &amp;amp;lt;IP&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Sicherheitshinweise ==&lt;br /&gt;
&lt;br /&gt;
* SSH-Ports &#039;&#039;&#039;nicht&#039;&#039;&#039; über das Internet freigeben — nur intern erreichbar lassen! Wenn das nicht geht: VPN-Tunnel!&lt;br /&gt;
* Portweiterleitung im Router auf das &#039;&#039;&#039;Minimum&#039;&#039;&#039; beschränken (nur die Ports 80 + 443 öffnen)&lt;br /&gt;
* Für interne Admin-Interfaces (OPNsense Web-UI, Monitoring) &#039;&#039;&#039;keine externen Freigaben&#039;&#039;&#039;&lt;br /&gt;
* DHCP-Reservations per MAC-Adresse oder statische IP-Adressen verhindern IP-Wechsel nach Neustarts&lt;br /&gt;
* Bei Firewall-Regeln: Block-Regeln &#039;&#039;&#039;immer&#039;&#039;&#039; vor Pass-Regeln platzieren&lt;br /&gt;
&lt;br /&gt;
Abschließend eine absolute Regeln, die immer und durch die Ewigkeiten gilt:&lt;br /&gt;
* Dienste, die auf einem Rechner &#039;&#039;&#039;NICHT&#039;&#039;&#039; existieren, werden niemals angegriffen! Wenig ist hier mehr!&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Dieser Artikel basiert auf praktischen Erfahrungen aus dem Betrieb eines selbst gehosteten Servers mit OPNsense, Cisco-Switch und Docker-Stack.&#039;&#039;&lt;br /&gt;
&#039;&#039;Erstellt: Mai 2026&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=251</id>
		<title>Homeserver-Sicherheitsarchitektur</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=251"/>
		<updated>2026-05-27T23:26:53Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Die Kette von außen nach innen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Homeserver-Sicherheitsarchitektur: Aufbau, Funktionsweise und Diagnose ==&lt;br /&gt;
&lt;br /&gt;
Einen eigenen Server an&#039;s Internet zu bekommen, ist nicht allzu schwierig. Ein Dienst, der die eigene, vom Internet-Provider zugewiesene IP-Adresse in einen festen Domain-Namen umwandelt (siehe: [https://de.wikipedia.org/wiki/Dynamisches_DNS Dynamisches DNS]), wird im privaten Bereich die Voraussetzung sein.&lt;br /&gt;
Es gibt verschiedene Anbieter, oft auch kostenlose.&lt;br /&gt;
&lt;br /&gt;
=== Ein Leitfaden für selbst gehostete Server mit OPNsense, Managed Switch und Docker ===&lt;br /&gt;
&lt;br /&gt;
Die Kehrseite: Sowie der Server über&#039;s Internet erreichbar ist, ist er angreifbar. Das ist kein theoretisches Szenario. Meiner Erfahrung nach ist es eine Frage von Stunden, bis die ersten Bots &amp;quot;anklopfen&amp;quot;, nach laufenden Diensten suchen, nach offenen Ports, nach Schwachstellen.&lt;br /&gt;
&lt;br /&gt;
Aufgrund einer mangelhaften Konfiguration (offener Samba-Port) hatte ich die sehr reale Erfahrung einer russischen Hackerbande, die einige Hundert Textdateien mit Zahlungsaufforderungen und einen Verschlüsselungstrojaner auf meinem Rechner hinterlassen hatte. Gerettet hatten mich damals die Dateirechte von Linux. Das fehlende E(x)ecutional-Flag und die eingeschränkten Benutzerrechte hatten den Trojaner ausgebremst.&lt;br /&gt;
&lt;br /&gt;
Trotzdem: Nie wieder!&lt;br /&gt;
Ein wenig von dem, was ich gelernt habe, gebe ich ich hier weiter.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Einleitung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt den Aufbau einer &#039;&#039;&#039;sicheren&#039;&#039;&#039; Netzwerkarchitektur für einen Homeserver, der über das öffentliche Internet erreichbar ist. Der Beitrag richtet sich an alle, die ihre Daten selbst kontrollieren wollen — und dabei nicht unfreiwillig Teil einer globalen Angriffs-Infrastruktur werden möchten. Er will zum Verständnis beitragen, wie die einzelnen Komponenten zusammenspielen — und wie man systematisch vorgeht, wenn etwas nicht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der Fokus liegt nicht auf einer spezifischen Hardware-Konfiguration, sondern auf dem allgemeinen Prinzip: Wie kommt ein Request von außen sicher zu einem Docker-Container?&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Annahmen / Szenario ==&lt;br /&gt;
&lt;br /&gt;
Folgende Komponenten werden in diesem Artikel vorausgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver&#039;&#039;&#039; (Raspberry Pi, Intel NUC, oder beliebiger Linux-Server)&lt;br /&gt;
** Betriebssystem: Debian/Ubuntu oder vergleichbar&lt;br /&gt;
** Docker mit mehreren Diensten (z.B. WordPress, Nextcloud, MediaWiki)&lt;br /&gt;
** Caddy als Reverse Proxy (alternativ funktionieren [https://nginx.org/ nginx], [https://httpd.apache.org/ Apache], oder (ggf. kostenpflichtige) proprietäre Lösungen. Caddy allerdings hat das für mich charmante Feature, sich eigenständig um die TSL-Zertifikate und ihre Verlängerung bei LetsEncrypt zu kümmern. Wer aufgrund &amp;quot;zu vieler&amp;quot; Fehlversuche bei der Zertifikats-Einrichtung von LetsEncrypt auf Tage gesperrt wurde, wird mein Faible über diesen Automatismus nachvollziehen oder teilen können.)&lt;br /&gt;
** fail2ban als Brute-Force-Schutz&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;DynDNS-Dienst&#039;&#039;&#039; der dem Homeserver eine feste Domain zuweist&lt;br /&gt;
** Beispiel: &amp;lt;code&amp;gt;myhomeserver.dyndns.de&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Router / Heimnetz-Gateway&#039;&#039;&#039;&lt;br /&gt;
** Beispiel-IP: &amp;lt;code&amp;gt;192.168.2.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Portweiterleitung, WLAN, DynDNS-Aktualisierung&lt;br /&gt;
** Typisch: FritzBox, aber jeder Router mit Portweiterleitung funktioniert&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; (dedizierte Hardware-Firewall)&lt;br /&gt;
** WAN-Interface: &amp;lt;code&amp;gt;192.168.2.2&amp;lt;/code&amp;gt; (im Router-Netz)&lt;br /&gt;
** LAN-Interface / Server-VLAN: &amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Firewall, NAT, DHCP, IDS/IPS&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Managed Switch&#039;&#039;&#039; (optional, für VLAN-Segmentierung)&lt;br /&gt;
** Trennt Server-VLAN vom Rest des Netzes&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver-IP&#039;&#039;&#039;: &amp;lt;code&amp;gt;192.168.10.100&amp;lt;/code&amp;gt; (per DHCP-Reservation oder besser: Per statischer IP-Adresse fest)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 1: Wie funktionieren die Weiterleitungen? Wer macht was? ==&lt;br /&gt;
&lt;br /&gt;
=== Die Kette von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Ein Request von außen (z.B. Browser ruft &amp;lt;code&amp;gt;https://myhomeserver.dyndns.de&amp;lt;/code&amp;gt; auf) durchläuft folgende Stationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Internet&lt;br /&gt;
    ↓ DNS-Auflösung: dyndns.de → öffentliche IP des Heimnetzes&lt;br /&gt;
Router / Gateway (192.168.2.1)&lt;br /&gt;
    ↓ Portweiterleitung: :80 + :443 (und nur! diese!!) → 192.168.2.2&lt;br /&gt;
OPNsense WAN-Interface (192.168.2.2)&lt;br /&gt;
    ↓ Destination NAT: :80/:443 → 192.168.10.100&lt;br /&gt;
Homeserver eno1/eth0 (192.168.10.100)&lt;br /&gt;
    ↓ Docker-Port-Binding: 0.0.0.0:80 + 0.0.0.0:443&lt;br /&gt;
Caddy / Reverse Proxy (Docker-intern)&lt;br /&gt;
    ↓ Reverse Proxy anhand des Host-Headers&lt;br /&gt;
Ziel-Container (z.B. wordpress, nextcloud, ...)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit ist der Server auf der IP-Ebene (Layer 3 des OSI-Modells) von außen hin &amp;quot;unsichtbar&amp;quot;: Die Firewall (OPNsense) lebt, mit dem Gateway, im 192.168.2-er Netz. Von dort routet sie alle Anfragen über die Ports 80 und 443 an das Interface 192.168.10.100. Dahinter, also im 192.168.10-er-Subnetz, residiert der Heimserver.&lt;br /&gt;
&lt;br /&gt;
Am Ende dieses Beitrages gibt es Sicherheitshinweise. Bitte dringend beachten, dass der Router ausschließlich die Ports &#039;&#039;&#039;80/TCP&#039;&#039;&#039; und &#039;&#039;&#039;443/TCP&#039;&#039;&#039; nach außen frei gibt. Der Webserver wird dabei so konfiguriert, dass HTTP-Daten über Port 80 nach HTTPS auf Port 443 umgeleitet werden.&lt;br /&gt;
&lt;br /&gt;
Die Idee, ausschließlich HTTPS zuzulassen, läge nahe. Damit bräuchte sich der Webserver nicht um die Weiterleitung auf Port 443 zu befassen.&lt;br /&gt;
Bedauerlicherweise wird in diesem Fall der Umgang mit dem TLS-Zertifikat, das den HTTPS-Datenstrom verschlüsselt, scheitern. [https://letsencrypt.org/ LetsEncrypt] benötigt bei Einrichtung und Verlängerung seiner Zertifikate einen offenen 80-er Port.&lt;br /&gt;
&lt;br /&gt;
Sollte es nötig sein, den Server von außen zu administrieren, wird man darüber nachdenken, einen VPN-Tunnel einzurichten. Sicherer jedoch - und einfacher - ist es dennoch, die Administration ausschließlich über einen zertifikats-geschützten SSH-Zugang im inneren 192.168.-er-Netz zuzulassen, und, jenseits von 80 und 443, auf jeden nach außen exponierten Port zu verzichten.&lt;br /&gt;
&lt;br /&gt;
=== Wer macht was? ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Komponente !! Aufgabe !! Konfigurationsort&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Router / Gateway&#039;&#039;&#039; || DynDNS-Aktualisierung, erste NAT-Stufe, WLAN || Router Web-UI → Portfreigaben&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; || Firewall-Regeln, zweite NAT-Stufe (Destination NAT), DHCP für Server-VLAN || OPNsense Web-UI (Standard: https://&amp;amp;lt;wan-ip&amp;amp;gt;:443 oder :8443)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Caddy / Reverse Proxy&#039;&#039;&#039; || TLS-Terminierung, Let&#039;s Encrypt, Weiterleitung an Container || Caddyfile auf dem Homeserver&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Docker&#039;&#039;&#039; || Container-Isolation, internes Netz (Standard: 172.18.0.0/16) || docker-compose.yml pro Dienst&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fail2ban&#039;&#039;&#039; || Brute-Force-Schutz auf Applikationsebene || Jail-Configs im fail2ban-Container&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Wichtig: OPNsense hat ZWEI Firewall-Engines ===&lt;br /&gt;
&lt;br /&gt;
OPNsense 26.x hat zwei parallele Regelwerke:&lt;br /&gt;
* &#039;&#039;&#039;Rules [new]&#039;&#039;&#039; — neue API-basierte Engine&lt;br /&gt;
* &#039;&#039;&#039;Rules&#039;&#039;&#039; — alte Engine (Legacy)&lt;br /&gt;
&lt;br /&gt;
Neue Regeln &#039;&#039;&#039;immer in beiden&#039;&#039;&#039; anlegen! Bei Problemen immer beide prüfen.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 2: Wo steht was? ==&lt;br /&gt;
&lt;br /&gt;
=== IP-Adressen (Beispiel-Setup) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Gerät !! Interface !! IP !! Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
| Router / Gateway || — || 192.168.2.1 || Gateway, WLAN, DynDNS&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense WAN || wan-interface || 192.168.2.2 || Statisch konfiguriert&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense LAN / Server-VLAN || lan-interface || 192.168.10.1 || Gateway für Server-Netz&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver || eno1 / eth0 || 192.168.10.100 || Fest per DHCP-Reservation (MAC-Adresse)&lt;br /&gt;
|-&lt;br /&gt;
| Client-Geräte || WLAN || 192.168.2.x || Im Router-Netz, nicht im Server-VLAN&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Homeserver: Netzwerk-Interface-Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Der Homeserver bezieht seine IP per DHCP vom OPNsense-DHCP-Server. Bei Debian/Ubuntu mit systemd-networkd:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/systemd/network/10-eth0.network&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Korrekter Inhalt (DHCP):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[Match]&lt;br /&gt;
Name=eno1&lt;br /&gt;
&lt;br /&gt;
[Network]&lt;br /&gt;
DHCP=ipv4&lt;br /&gt;
&lt;br /&gt;
[DHCP]&lt;br /&gt;
RouteMetric=100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ &#039;&#039;&#039;Niemals&#039;&#039;&#039; eine statische IP oder einen Gateway manuell eintragen!&lt;br /&gt;
Der Default-Gateway kommt immer vom DHCP-Server der OPNsense-Firewall (&amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Kea DHCP Lease-Datei (OPNsense) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/db/kea/kea-leases4.csv&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier verwaltet Kea die aktiven Leases. Bei Problemen mit doppelten IPs kann diese Datei (nach &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;) auf den Header reduziert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context,pool_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 3: Systematische Diagnose — Schritt für Schritt ==&lt;br /&gt;
&lt;br /&gt;
=== Grundprinzip: Von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Immer von außen nach innen vorgehen — nie raten, immer messen. Jede Schicht einzeln prüfen.&lt;br /&gt;
&lt;br /&gt;
==== Schritt 1: Ist OPNsense überhaupt erreichbar? ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Vom Client-Rechner:&lt;br /&gt;
ping 192.168.2.2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ OPNsense antwortet standardmäßig &#039;&#039;&#039;nicht&#039;&#039;&#039; auf ICMP/Ping von außen — das ist korrekt!&lt;br /&gt;
&lt;br /&gt;
Stattdessen prüfen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Web-UI erreichbar?&lt;br /&gt;
https://192.168.2.2:8443&lt;br /&gt;
&lt;br /&gt;
# Router zeigt OPNsense als verbundenes Gerät?&lt;br /&gt;
http://192.168.2.1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 2: OPNsense intern prüfen ====&lt;br /&gt;
&lt;br /&gt;
Per SSH oder serieller Konsole auf OPNsense:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# WAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;wan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.2.2, status: active&lt;br /&gt;
&lt;br /&gt;
# LAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;lan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.10.1, status: active&lt;br /&gt;
&lt;br /&gt;
# Router erreichbar?&lt;br /&gt;
ping -c 3 192.168.2.1&lt;br /&gt;
&lt;br /&gt;
# Homeserver erreichbar?&lt;br /&gt;
ping -c 3 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 3: Homeserver direkt prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# SSH auf Homeserver:&lt;br /&gt;
ssh root@192.168.10.100&lt;br /&gt;
&lt;br /&gt;
# Alle Container laufen?&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# Internet vom Homeserver aus erreichbar?&lt;br /&gt;
ping -c 3 9.9.9.9&lt;br /&gt;
&lt;br /&gt;
# Routing-Tabelle korrekt?&lt;br /&gt;
ip route show&lt;br /&gt;
# Erwartete Default-Route: default via 192.168.10.1 dev eno1&lt;br /&gt;
# NICHT: default via 192.168.178.x — das wäre falsch!&lt;br /&gt;
&lt;br /&gt;
# Welche IP hat das Interface?&lt;br /&gt;
ip addr show eno1&lt;br /&gt;
# Erwartete IP: 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 4: Caddy / Reverse Proxy prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Läuft Caddy und antwortet er lokal?&lt;br /&gt;
curl -v http://localhost&lt;br /&gt;
# Erwartete Antwort: HTTP 308 Redirect → https://localhost/&lt;br /&gt;
&lt;br /&gt;
# Caddy-Logs auf Fehler prüfen:&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Typische Fehler in den Caddy-Logs:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fehlermeldung !! Bedeutung !! Lösung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dial tcp ...:443: connect: no route to host&amp;lt;/code&amp;gt; || Caddy kommt nicht ins Internet (Let&#039;s Encrypt nicht erreichbar) || Routing auf Homeserver prüfen (Schritt 3)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;no route to host&amp;lt;/code&amp;gt; bei Ping auf 9.9.9.9 || Falscher Default-Gateway || &amp;lt;code&amp;gt;ip route show&amp;lt;/code&amp;gt; prüfen, falsche Route entfernen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Schritt 5: NAT und Firewall-Regeln prüfen (OPNsense Shell) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# NAT-Regeln anzeigen:&lt;br /&gt;
pfctl -s nat | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Firewall-Regeln anzeigen:&lt;br /&gt;
pfctl -s rules | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf WAN-Interface beobachten (kommt der Request an?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;wan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf LAN-Interface beobachten (wird er weitergeleitet?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;lan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Diagnose-Logik:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tcpdump WAN sieht Traffic, LAN nicht → NAT-Regel prüfen!&lt;br /&gt;
tcpdump WAN sieht keinen Traffic    → Portweiterleitung im Router prüfen!&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 6: Bekannte Fallstricke ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Problem !! Symptom !! Ursache !! Fix&lt;br /&gt;
|-&lt;br /&gt;
| Falsche statische Route || &amp;lt;code&amp;gt;ping 9.9.9.9&amp;lt;/code&amp;gt; schlägt fehl || Netzwerk-Config hat statischen Gateway eingetragen || Auf DHCP umstellen, &amp;lt;code&amp;gt;systemctl restart systemd-networkd&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver hat falsche IP || NAT-Regeln greifen nicht || DHCP hat beim Neustart temporär andere IP vergeben || DHCP-Reservation per MAC-Adresse einrichten&lt;br /&gt;
|-&lt;br /&gt;
| DHCP-Leases durcheinander || Server taucht mit zwei IPs auf || Neustart hat neuen Lease vor Ablauf des alten erzeugt || &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;, Lease-CSV bereinigen, &amp;lt;code&amp;gt;configctl kea start&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense Firewall-Regel fehlt || Dienste von außen nicht erreichbar, intern OK || Regel nur in einer der beiden Engines angelegt || Regel in &#039;&#039;&#039;beiden&#039;&#039;&#039; Engines anlegen (Rules [new] + Rules)&lt;br /&gt;
|-&lt;br /&gt;
| NAT-Regel ohne Subnetz-Maske || Traffic kommt nicht an || &amp;lt;code&amp;gt;192.168.178.0&amp;lt;/code&amp;gt; statt &amp;lt;code&amp;gt;192.168.178.0/24&amp;lt;/code&amp;gt; eingetragen || Subnetz-Maske ergänzen — ohne /24 gilt nur die Netzadresse selbst!&lt;br /&gt;
|-&lt;br /&gt;
| Source/Destination Port vertauscht || Verbindungen werden blockiert || Bei Firewall-Regel Port unter &amp;quot;Source&amp;quot; statt &amp;quot;Destination&amp;quot; eingetragen || Source Port: any / Destination Port: gewünschter Port&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Notfall-Cheatsheet ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# OPNsense: Firewall temporär deaktivieren (Notfall!)&lt;br /&gt;
pfctl -d&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Firewall wieder aktivieren&lt;br /&gt;
pfctl -e&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Kea DHCP stoppen/starten&lt;br /&gt;
configctl kea stop&lt;br /&gt;
configctl kea start&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Falsche Default-Route entfernen&lt;br /&gt;
ip route del default via &amp;amp;lt;falsche-gateway-ip&amp;amp;gt; dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: IP manuell setzen (Sofortlösung bei DHCP-Problemen)&lt;br /&gt;
ip addr add 192.168.10.100/24 dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Netzwerk-Dienst neu starten (Verbindung kurz weg!)&lt;br /&gt;
systemctl restart systemd-networkd&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Docker-Logs prüfen&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Alias-Tabellen prüfen (Blocklisten)&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | wc -l&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | grep &amp;amp;lt;IP&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Sicherheitshinweise ==&lt;br /&gt;
&lt;br /&gt;
* SSH-Ports &#039;&#039;&#039;nicht&#039;&#039;&#039; über das Internet freigeben — nur intern erreichbar lassen! Wenn das nicht geht: VPN-Tunnel!&lt;br /&gt;
* Portweiterleitung im Router auf das &#039;&#039;&#039;Minimum&#039;&#039;&#039; beschränken (nur die Ports 80 + 443 öffnen)&lt;br /&gt;
* Für interne Admin-Interfaces (OPNsense Web-UI, Monitoring) &#039;&#039;&#039;keine externen Freigaben&#039;&#039;&#039;&lt;br /&gt;
* DHCP-Reservations per MAC-Adresse oder statische IP-Adressen verhindern IP-Wechsel nach Neustarts&lt;br /&gt;
* Bei Firewall-Regeln: Block-Regeln &#039;&#039;&#039;immer&#039;&#039;&#039; vor Pass-Regeln platzieren&lt;br /&gt;
&lt;br /&gt;
Abschließend eine absolute Regeln, die immer und durch die Ewigkeiten gilt:&lt;br /&gt;
* Dienste, die auf einem Rechner &#039;&#039;&#039;NICHT&#039;&#039;&#039; existieren, werden niemals angegriffen! Wenig ist hier mehr!&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Dieser Artikel basiert auf praktischen Erfahrungen aus dem Betrieb eines selbst gehosteten Servers mit OPNsense, Cisco-Switch und Docker-Stack.&#039;&#039;&lt;br /&gt;
&#039;&#039;Erstellt: Mai 2026&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=250</id>
		<title>Homeserver-Sicherheitsarchitektur</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=250"/>
		<updated>2026-05-27T23:23:03Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Die Kette von außen nach innen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Homeserver-Sicherheitsarchitektur: Aufbau, Funktionsweise und Diagnose ==&lt;br /&gt;
&lt;br /&gt;
Einen eigenen Server an&#039;s Internet zu bekommen, ist nicht allzu schwierig. Ein Dienst, der die eigene, vom Internet-Provider zugewiesene IP-Adresse in einen festen Domain-Namen umwandelt (siehe: [https://de.wikipedia.org/wiki/Dynamisches_DNS Dynamisches DNS]), wird im privaten Bereich die Voraussetzung sein.&lt;br /&gt;
Es gibt verschiedene Anbieter, oft auch kostenlose.&lt;br /&gt;
&lt;br /&gt;
=== Ein Leitfaden für selbst gehostete Server mit OPNsense, Managed Switch und Docker ===&lt;br /&gt;
&lt;br /&gt;
Die Kehrseite: Sowie der Server über&#039;s Internet erreichbar ist, ist er angreifbar. Das ist kein theoretisches Szenario. Meiner Erfahrung nach ist es eine Frage von Stunden, bis die ersten Bots &amp;quot;anklopfen&amp;quot;, nach laufenden Diensten suchen, nach offenen Ports, nach Schwachstellen.&lt;br /&gt;
&lt;br /&gt;
Aufgrund einer mangelhaften Konfiguration (offener Samba-Port) hatte ich die sehr reale Erfahrung einer russischen Hackerbande, die einige Hundert Textdateien mit Zahlungsaufforderungen und einen Verschlüsselungstrojaner auf meinem Rechner hinterlassen hatte. Gerettet hatten mich damals die Dateirechte von Linux. Das fehlende E(x)ecutional-Flag und die eingeschränkten Benutzerrechte hatten den Trojaner ausgebremst.&lt;br /&gt;
&lt;br /&gt;
Trotzdem: Nie wieder!&lt;br /&gt;
Ein wenig von dem, was ich gelernt habe, gebe ich ich hier weiter.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Einleitung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt den Aufbau einer &#039;&#039;&#039;sicheren&#039;&#039;&#039; Netzwerkarchitektur für einen Homeserver, der über das öffentliche Internet erreichbar ist. Der Beitrag richtet sich an alle, die ihre Daten selbst kontrollieren wollen — und dabei nicht unfreiwillig Teil einer globalen Angriffs-Infrastruktur werden möchten. Er will zum Verständnis beitragen, wie die einzelnen Komponenten zusammenspielen — und wie man systematisch vorgeht, wenn etwas nicht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der Fokus liegt nicht auf einer spezifischen Hardware-Konfiguration, sondern auf dem allgemeinen Prinzip: Wie kommt ein Request von außen sicher zu einem Docker-Container?&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Annahmen / Szenario ==&lt;br /&gt;
&lt;br /&gt;
Folgende Komponenten werden in diesem Artikel vorausgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver&#039;&#039;&#039; (Raspberry Pi, Intel NUC, oder beliebiger Linux-Server)&lt;br /&gt;
** Betriebssystem: Debian/Ubuntu oder vergleichbar&lt;br /&gt;
** Docker mit mehreren Diensten (z.B. WordPress, Nextcloud, MediaWiki)&lt;br /&gt;
** Caddy als Reverse Proxy (alternativ funktionieren [https://nginx.org/ nginx], [https://httpd.apache.org/ Apache], oder (ggf. kostenpflichtige) proprietäre Lösungen. Caddy allerdings hat das für mich charmante Feature, sich eigenständig um die TSL-Zertifikate und ihre Verlängerung bei LetsEncrypt zu kümmern. Wer aufgrund &amp;quot;zu vieler&amp;quot; Fehlversuche bei der Zertifikats-Einrichtung von LetsEncrypt auf Tage gesperrt wurde, wird mein Faible über diesen Automatismus nachvollziehen oder teilen können.)&lt;br /&gt;
** fail2ban als Brute-Force-Schutz&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;DynDNS-Dienst&#039;&#039;&#039; der dem Homeserver eine feste Domain zuweist&lt;br /&gt;
** Beispiel: &amp;lt;code&amp;gt;myhomeserver.dyndns.de&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Router / Heimnetz-Gateway&#039;&#039;&#039;&lt;br /&gt;
** Beispiel-IP: &amp;lt;code&amp;gt;192.168.2.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Portweiterleitung, WLAN, DynDNS-Aktualisierung&lt;br /&gt;
** Typisch: FritzBox, aber jeder Router mit Portweiterleitung funktioniert&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; (dedizierte Hardware-Firewall)&lt;br /&gt;
** WAN-Interface: &amp;lt;code&amp;gt;192.168.2.2&amp;lt;/code&amp;gt; (im Router-Netz)&lt;br /&gt;
** LAN-Interface / Server-VLAN: &amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Firewall, NAT, DHCP, IDS/IPS&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Managed Switch&#039;&#039;&#039; (optional, für VLAN-Segmentierung)&lt;br /&gt;
** Trennt Server-VLAN vom Rest des Netzes&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver-IP&#039;&#039;&#039;: &amp;lt;code&amp;gt;192.168.10.100&amp;lt;/code&amp;gt; (per DHCP-Reservation oder besser: Per statischer IP-Adresse fest)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 1: Wie funktionieren die Weiterleitungen? Wer macht was? ==&lt;br /&gt;
&lt;br /&gt;
=== Die Kette von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Ein Request von außen (z.B. Browser ruft &amp;lt;code&amp;gt;https://myhomeserver.dyndns.de&amp;lt;/code&amp;gt; auf) durchläuft folgende Stationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Internet&lt;br /&gt;
    ↓ DNS-Auflösung: dyndns.de → öffentliche IP des Heimnetzes&lt;br /&gt;
Router / Gateway (192.168.2.1)&lt;br /&gt;
    ↓ Portweiterleitung: :80 + :443 (und nur! diese!!) → 192.168.2.2&lt;br /&gt;
OPNsense WAN-Interface (192.168.2.2)&lt;br /&gt;
    ↓ Destination NAT: :80/:443 → 192.168.10.100&lt;br /&gt;
Homeserver eno1/eth0 (192.168.10.100)&lt;br /&gt;
    ↓ Docker-Port-Binding: 0.0.0.0:80 + 0.0.0.0:443&lt;br /&gt;
Caddy / Reverse Proxy (Docker-intern)&lt;br /&gt;
    ↓ Reverse Proxy anhand des Host-Headers&lt;br /&gt;
Ziel-Container (z.B. wordpress, nextcloud, ...)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit ist der Server auf der IP-Ebene (Layer 3 des OSI-Modells) von außen hin &amp;quot;unsichtbar&amp;quot;: Die Firewall (OPNsense) lebt, mit dem Gateway, im 192.168.2-er Netz. Von dort routet sie alle Anfragen über die Ports 80 und 443 an das Interface 192.168.10.100. Dahinter, also im 192.168.10-er-Subnetz, residiert der Heimserver.&lt;br /&gt;
&lt;br /&gt;
Am Ende dieses Beitrages gibt es Sicherheitshinweise. Bitte dringend beachten, dass der Router ausschließlich die Ports &#039;&#039;&#039;80/TCP&#039;&#039;&#039; und &#039;&#039;&#039;443/TCP&#039;&#039;&#039; nach außen frei gibt. Der Webserver wird dabei so konfiguriert, dass HTTP-Daten über Port 80 nach HTTPS auf Port 443 umgeleitet werden.&lt;br /&gt;
&lt;br /&gt;
Die Idee, ausschließlich HTTPS zuzulassen, läge nahe. Damit bräuchte sich der Webserver nicht um die Weiterleitung auf Port 443 zu befassen.&lt;br /&gt;
Bedauerlicherweise wird in diesem Fall der Umgang mit dem TLS-Zertifikat, das den HTTPS-Datenstrom verschlüsselt, scheitern. [https://letsencrypt.org/ LetsEncrypt] benötigt bei Einrichtung und Verlängerung seiner Zertifikate einen offenen 80-er Port.&lt;br /&gt;
&lt;br /&gt;
Sollte es nötig sein, den Server von außen zu administrieren, wird man sicherlich darüber nachdenken, einen VPN-Tunnel einzurichten. Noch sicherer - und einfacher - ist es dennoch, die Administration ausschließlich über einen zertifikats-geschützten SSH-Zugang im inneren 192.168.-er-Netz zuzulassen.&lt;br /&gt;
&lt;br /&gt;
=== Wer macht was? ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Komponente !! Aufgabe !! Konfigurationsort&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Router / Gateway&#039;&#039;&#039; || DynDNS-Aktualisierung, erste NAT-Stufe, WLAN || Router Web-UI → Portfreigaben&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; || Firewall-Regeln, zweite NAT-Stufe (Destination NAT), DHCP für Server-VLAN || OPNsense Web-UI (Standard: https://&amp;amp;lt;wan-ip&amp;amp;gt;:443 oder :8443)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Caddy / Reverse Proxy&#039;&#039;&#039; || TLS-Terminierung, Let&#039;s Encrypt, Weiterleitung an Container || Caddyfile auf dem Homeserver&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Docker&#039;&#039;&#039; || Container-Isolation, internes Netz (Standard: 172.18.0.0/16) || docker-compose.yml pro Dienst&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fail2ban&#039;&#039;&#039; || Brute-Force-Schutz auf Applikationsebene || Jail-Configs im fail2ban-Container&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Wichtig: OPNsense hat ZWEI Firewall-Engines ===&lt;br /&gt;
&lt;br /&gt;
OPNsense 26.x hat zwei parallele Regelwerke:&lt;br /&gt;
* &#039;&#039;&#039;Rules [new]&#039;&#039;&#039; — neue API-basierte Engine&lt;br /&gt;
* &#039;&#039;&#039;Rules&#039;&#039;&#039; — alte Engine (Legacy)&lt;br /&gt;
&lt;br /&gt;
Neue Regeln &#039;&#039;&#039;immer in beiden&#039;&#039;&#039; anlegen! Bei Problemen immer beide prüfen.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 2: Wo steht was? ==&lt;br /&gt;
&lt;br /&gt;
=== IP-Adressen (Beispiel-Setup) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Gerät !! Interface !! IP !! Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
| Router / Gateway || — || 192.168.2.1 || Gateway, WLAN, DynDNS&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense WAN || wan-interface || 192.168.2.2 || Statisch konfiguriert&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense LAN / Server-VLAN || lan-interface || 192.168.10.1 || Gateway für Server-Netz&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver || eno1 / eth0 || 192.168.10.100 || Fest per DHCP-Reservation (MAC-Adresse)&lt;br /&gt;
|-&lt;br /&gt;
| Client-Geräte || WLAN || 192.168.2.x || Im Router-Netz, nicht im Server-VLAN&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Homeserver: Netzwerk-Interface-Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Der Homeserver bezieht seine IP per DHCP vom OPNsense-DHCP-Server. Bei Debian/Ubuntu mit systemd-networkd:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/systemd/network/10-eth0.network&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Korrekter Inhalt (DHCP):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[Match]&lt;br /&gt;
Name=eno1&lt;br /&gt;
&lt;br /&gt;
[Network]&lt;br /&gt;
DHCP=ipv4&lt;br /&gt;
&lt;br /&gt;
[DHCP]&lt;br /&gt;
RouteMetric=100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ &#039;&#039;&#039;Niemals&#039;&#039;&#039; eine statische IP oder einen Gateway manuell eintragen!&lt;br /&gt;
Der Default-Gateway kommt immer vom DHCP-Server der OPNsense-Firewall (&amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Kea DHCP Lease-Datei (OPNsense) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/db/kea/kea-leases4.csv&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier verwaltet Kea die aktiven Leases. Bei Problemen mit doppelten IPs kann diese Datei (nach &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;) auf den Header reduziert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context,pool_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 3: Systematische Diagnose — Schritt für Schritt ==&lt;br /&gt;
&lt;br /&gt;
=== Grundprinzip: Von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Immer von außen nach innen vorgehen — nie raten, immer messen. Jede Schicht einzeln prüfen.&lt;br /&gt;
&lt;br /&gt;
==== Schritt 1: Ist OPNsense überhaupt erreichbar? ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Vom Client-Rechner:&lt;br /&gt;
ping 192.168.2.2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ OPNsense antwortet standardmäßig &#039;&#039;&#039;nicht&#039;&#039;&#039; auf ICMP/Ping von außen — das ist korrekt!&lt;br /&gt;
&lt;br /&gt;
Stattdessen prüfen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Web-UI erreichbar?&lt;br /&gt;
https://192.168.2.2:8443&lt;br /&gt;
&lt;br /&gt;
# Router zeigt OPNsense als verbundenes Gerät?&lt;br /&gt;
http://192.168.2.1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 2: OPNsense intern prüfen ====&lt;br /&gt;
&lt;br /&gt;
Per SSH oder serieller Konsole auf OPNsense:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# WAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;wan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.2.2, status: active&lt;br /&gt;
&lt;br /&gt;
# LAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;lan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.10.1, status: active&lt;br /&gt;
&lt;br /&gt;
# Router erreichbar?&lt;br /&gt;
ping -c 3 192.168.2.1&lt;br /&gt;
&lt;br /&gt;
# Homeserver erreichbar?&lt;br /&gt;
ping -c 3 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 3: Homeserver direkt prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# SSH auf Homeserver:&lt;br /&gt;
ssh root@192.168.10.100&lt;br /&gt;
&lt;br /&gt;
# Alle Container laufen?&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# Internet vom Homeserver aus erreichbar?&lt;br /&gt;
ping -c 3 9.9.9.9&lt;br /&gt;
&lt;br /&gt;
# Routing-Tabelle korrekt?&lt;br /&gt;
ip route show&lt;br /&gt;
# Erwartete Default-Route: default via 192.168.10.1 dev eno1&lt;br /&gt;
# NICHT: default via 192.168.178.x — das wäre falsch!&lt;br /&gt;
&lt;br /&gt;
# Welche IP hat das Interface?&lt;br /&gt;
ip addr show eno1&lt;br /&gt;
# Erwartete IP: 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 4: Caddy / Reverse Proxy prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Läuft Caddy und antwortet er lokal?&lt;br /&gt;
curl -v http://localhost&lt;br /&gt;
# Erwartete Antwort: HTTP 308 Redirect → https://localhost/&lt;br /&gt;
&lt;br /&gt;
# Caddy-Logs auf Fehler prüfen:&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Typische Fehler in den Caddy-Logs:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fehlermeldung !! Bedeutung !! Lösung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dial tcp ...:443: connect: no route to host&amp;lt;/code&amp;gt; || Caddy kommt nicht ins Internet (Let&#039;s Encrypt nicht erreichbar) || Routing auf Homeserver prüfen (Schritt 3)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;no route to host&amp;lt;/code&amp;gt; bei Ping auf 9.9.9.9 || Falscher Default-Gateway || &amp;lt;code&amp;gt;ip route show&amp;lt;/code&amp;gt; prüfen, falsche Route entfernen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Schritt 5: NAT und Firewall-Regeln prüfen (OPNsense Shell) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# NAT-Regeln anzeigen:&lt;br /&gt;
pfctl -s nat | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Firewall-Regeln anzeigen:&lt;br /&gt;
pfctl -s rules | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf WAN-Interface beobachten (kommt der Request an?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;wan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf LAN-Interface beobachten (wird er weitergeleitet?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;lan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Diagnose-Logik:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tcpdump WAN sieht Traffic, LAN nicht → NAT-Regel prüfen!&lt;br /&gt;
tcpdump WAN sieht keinen Traffic    → Portweiterleitung im Router prüfen!&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 6: Bekannte Fallstricke ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Problem !! Symptom !! Ursache !! Fix&lt;br /&gt;
|-&lt;br /&gt;
| Falsche statische Route || &amp;lt;code&amp;gt;ping 9.9.9.9&amp;lt;/code&amp;gt; schlägt fehl || Netzwerk-Config hat statischen Gateway eingetragen || Auf DHCP umstellen, &amp;lt;code&amp;gt;systemctl restart systemd-networkd&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver hat falsche IP || NAT-Regeln greifen nicht || DHCP hat beim Neustart temporär andere IP vergeben || DHCP-Reservation per MAC-Adresse einrichten&lt;br /&gt;
|-&lt;br /&gt;
| DHCP-Leases durcheinander || Server taucht mit zwei IPs auf || Neustart hat neuen Lease vor Ablauf des alten erzeugt || &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;, Lease-CSV bereinigen, &amp;lt;code&amp;gt;configctl kea start&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense Firewall-Regel fehlt || Dienste von außen nicht erreichbar, intern OK || Regel nur in einer der beiden Engines angelegt || Regel in &#039;&#039;&#039;beiden&#039;&#039;&#039; Engines anlegen (Rules [new] + Rules)&lt;br /&gt;
|-&lt;br /&gt;
| NAT-Regel ohne Subnetz-Maske || Traffic kommt nicht an || &amp;lt;code&amp;gt;192.168.178.0&amp;lt;/code&amp;gt; statt &amp;lt;code&amp;gt;192.168.178.0/24&amp;lt;/code&amp;gt; eingetragen || Subnetz-Maske ergänzen — ohne /24 gilt nur die Netzadresse selbst!&lt;br /&gt;
|-&lt;br /&gt;
| Source/Destination Port vertauscht || Verbindungen werden blockiert || Bei Firewall-Regel Port unter &amp;quot;Source&amp;quot; statt &amp;quot;Destination&amp;quot; eingetragen || Source Port: any / Destination Port: gewünschter Port&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Notfall-Cheatsheet ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# OPNsense: Firewall temporär deaktivieren (Notfall!)&lt;br /&gt;
pfctl -d&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Firewall wieder aktivieren&lt;br /&gt;
pfctl -e&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Kea DHCP stoppen/starten&lt;br /&gt;
configctl kea stop&lt;br /&gt;
configctl kea start&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Falsche Default-Route entfernen&lt;br /&gt;
ip route del default via &amp;amp;lt;falsche-gateway-ip&amp;amp;gt; dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: IP manuell setzen (Sofortlösung bei DHCP-Problemen)&lt;br /&gt;
ip addr add 192.168.10.100/24 dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Netzwerk-Dienst neu starten (Verbindung kurz weg!)&lt;br /&gt;
systemctl restart systemd-networkd&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Docker-Logs prüfen&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Alias-Tabellen prüfen (Blocklisten)&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | wc -l&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | grep &amp;amp;lt;IP&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Sicherheitshinweise ==&lt;br /&gt;
&lt;br /&gt;
* SSH-Ports &#039;&#039;&#039;nicht&#039;&#039;&#039; über das Internet freigeben — nur intern erreichbar lassen! Wenn das nicht geht: VPN-Tunnel!&lt;br /&gt;
* Portweiterleitung im Router auf das &#039;&#039;&#039;Minimum&#039;&#039;&#039; beschränken (nur die Ports 80 + 443 öffnen)&lt;br /&gt;
* Für interne Admin-Interfaces (OPNsense Web-UI, Monitoring) &#039;&#039;&#039;keine externen Freigaben&#039;&#039;&#039;&lt;br /&gt;
* DHCP-Reservations per MAC-Adresse oder statische IP-Adressen verhindern IP-Wechsel nach Neustarts&lt;br /&gt;
* Bei Firewall-Regeln: Block-Regeln &#039;&#039;&#039;immer&#039;&#039;&#039; vor Pass-Regeln platzieren&lt;br /&gt;
&lt;br /&gt;
Abschließend eine absolute Regeln, die immer und durch die Ewigkeiten gilt:&lt;br /&gt;
* Dienste, die auf einem Rechner &#039;&#039;&#039;NICHT&#039;&#039;&#039; existieren, werden niemals angegriffen! Wenig ist hier mehr!&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Dieser Artikel basiert auf praktischen Erfahrungen aus dem Betrieb eines selbst gehosteten Servers mit OPNsense, Cisco-Switch und Docker-Stack.&#039;&#039;&lt;br /&gt;
&#039;&#039;Erstellt: Mai 2026&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=249</id>
		<title>Homeserver-Sicherheitsarchitektur</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=249"/>
		<updated>2026-05-27T23:19:58Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Die Kette von außen nach innen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Homeserver-Sicherheitsarchitektur: Aufbau, Funktionsweise und Diagnose ==&lt;br /&gt;
&lt;br /&gt;
Einen eigenen Server an&#039;s Internet zu bekommen, ist nicht allzu schwierig. Ein Dienst, der die eigene, vom Internet-Provider zugewiesene IP-Adresse in einen festen Domain-Namen umwandelt (siehe: [https://de.wikipedia.org/wiki/Dynamisches_DNS Dynamisches DNS]), wird im privaten Bereich die Voraussetzung sein.&lt;br /&gt;
Es gibt verschiedene Anbieter, oft auch kostenlose.&lt;br /&gt;
&lt;br /&gt;
=== Ein Leitfaden für selbst gehostete Server mit OPNsense, Managed Switch und Docker ===&lt;br /&gt;
&lt;br /&gt;
Die Kehrseite: Sowie der Server über&#039;s Internet erreichbar ist, ist er angreifbar. Das ist kein theoretisches Szenario. Meiner Erfahrung nach ist es eine Frage von Stunden, bis die ersten Bots &amp;quot;anklopfen&amp;quot;, nach laufenden Diensten suchen, nach offenen Ports, nach Schwachstellen.&lt;br /&gt;
&lt;br /&gt;
Aufgrund einer mangelhaften Konfiguration (offener Samba-Port) hatte ich die sehr reale Erfahrung einer russischen Hackerbande, die einige Hundert Textdateien mit Zahlungsaufforderungen und einen Verschlüsselungstrojaner auf meinem Rechner hinterlassen hatte. Gerettet hatten mich damals die Dateirechte von Linux. Das fehlende E(x)ecutional-Flag und die eingeschränkten Benutzerrechte hatten den Trojaner ausgebremst.&lt;br /&gt;
&lt;br /&gt;
Trotzdem: Nie wieder!&lt;br /&gt;
Ein wenig von dem, was ich gelernt habe, gebe ich ich hier weiter.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Einleitung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt den Aufbau einer &#039;&#039;&#039;sicheren&#039;&#039;&#039; Netzwerkarchitektur für einen Homeserver, der über das öffentliche Internet erreichbar ist. Der Beitrag richtet sich an alle, die ihre Daten selbst kontrollieren wollen — und dabei nicht unfreiwillig Teil einer globalen Angriffs-Infrastruktur werden möchten. Er will zum Verständnis beitragen, wie die einzelnen Komponenten zusammenspielen — und wie man systematisch vorgeht, wenn etwas nicht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der Fokus liegt nicht auf einer spezifischen Hardware-Konfiguration, sondern auf dem allgemeinen Prinzip: Wie kommt ein Request von außen sicher zu einem Docker-Container?&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Annahmen / Szenario ==&lt;br /&gt;
&lt;br /&gt;
Folgende Komponenten werden in diesem Artikel vorausgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver&#039;&#039;&#039; (Raspberry Pi, Intel NUC, oder beliebiger Linux-Server)&lt;br /&gt;
** Betriebssystem: Debian/Ubuntu oder vergleichbar&lt;br /&gt;
** Docker mit mehreren Diensten (z.B. WordPress, Nextcloud, MediaWiki)&lt;br /&gt;
** Caddy als Reverse Proxy (alternativ funktionieren [https://nginx.org/ nginx], [https://httpd.apache.org/ Apache], oder (ggf. kostenpflichtige) proprietäre Lösungen. Caddy allerdings hat das für mich charmante Feature, sich eigenständig um die TSL-Zertifikate und ihre Verlängerung bei LetsEncrypt zu kümmern. Wer aufgrund &amp;quot;zu vieler&amp;quot; Fehlversuche bei der Zertifikats-Einrichtung von LetsEncrypt auf Tage gesperrt wurde, wird mein Faible über diesen Automatismus nachvollziehen oder teilen können.)&lt;br /&gt;
** fail2ban als Brute-Force-Schutz&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;DynDNS-Dienst&#039;&#039;&#039; der dem Homeserver eine feste Domain zuweist&lt;br /&gt;
** Beispiel: &amp;lt;code&amp;gt;myhomeserver.dyndns.de&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Router / Heimnetz-Gateway&#039;&#039;&#039;&lt;br /&gt;
** Beispiel-IP: &amp;lt;code&amp;gt;192.168.2.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Portweiterleitung, WLAN, DynDNS-Aktualisierung&lt;br /&gt;
** Typisch: FritzBox, aber jeder Router mit Portweiterleitung funktioniert&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; (dedizierte Hardware-Firewall)&lt;br /&gt;
** WAN-Interface: &amp;lt;code&amp;gt;192.168.2.2&amp;lt;/code&amp;gt; (im Router-Netz)&lt;br /&gt;
** LAN-Interface / Server-VLAN: &amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Firewall, NAT, DHCP, IDS/IPS&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Managed Switch&#039;&#039;&#039; (optional, für VLAN-Segmentierung)&lt;br /&gt;
** Trennt Server-VLAN vom Rest des Netzes&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver-IP&#039;&#039;&#039;: &amp;lt;code&amp;gt;192.168.10.100&amp;lt;/code&amp;gt; (per DHCP-Reservation oder besser: Per statischer IP-Adresse fest)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 1: Wie funktionieren die Weiterleitungen? Wer macht was? ==&lt;br /&gt;
&lt;br /&gt;
=== Die Kette von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Ein Request von außen (z.B. Browser ruft &amp;lt;code&amp;gt;https://myhomeserver.dyndns.de&amp;lt;/code&amp;gt; auf) durchläuft folgende Stationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Internet&lt;br /&gt;
    ↓ DNS-Auflösung: dyndns.de → öffentliche IP des Heimnetzes&lt;br /&gt;
Router / Gateway (192.168.2.1)&lt;br /&gt;
    ↓ Portweiterleitung: :80 + :443 (und nur! diese!!) → 192.168.2.2&lt;br /&gt;
OPNsense WAN-Interface (192.168.2.2)&lt;br /&gt;
    ↓ Destination NAT: :80/:443 → 192.168.10.100&lt;br /&gt;
Homeserver eno1/eth0 (192.168.10.100)&lt;br /&gt;
    ↓ Docker-Port-Binding: 0.0.0.0:80 + 0.0.0.0:443&lt;br /&gt;
Caddy / Reverse Proxy (Docker-intern)&lt;br /&gt;
    ↓ Reverse Proxy anhand des Host-Headers&lt;br /&gt;
Ziel-Container (z.B. wordpress, nextcloud, ...)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit ist der Server auf der IP-Ebene (Layer 3 des OSI-Modells) von außen hin &amp;quot;unsichtbar&amp;quot;: Die Firewall (OPNsense) lebt, mit dem Gateway, im 192.168.2-er Netz. Von dort routet sie alle Anfragen über die Ports 80 und 443 an das Interface 192.168.10.100. Dahinter, also im 192.168.10-er-Subnetz, residiert der Heimserver.&lt;br /&gt;
&lt;br /&gt;
Am Ende dieses Beitrages gibt es Sicherheitshinweise. Bitte dringend beachten, dass der Router ausschließlich die Ports &#039;&#039;&#039;80/TCP&#039;&#039;&#039; und &#039;&#039;&#039;443/TCP&#039;&#039;&#039; nach außen frei gibt. Der Webserver wird dabei so konfiguriert, dass HTTP-Daten über Port 80 nach HTTPS auf Port 443 umgeleitet werden.&lt;br /&gt;
&lt;br /&gt;
Die Idee, ausschließlich HTTPS zuzulassen, läge nahe. Damit bräuchte sich der Webserver nicht um die Weiterleitung auf Port 443 zu befassen.&lt;br /&gt;
Bedauerlicherweise wird in diesem Fall der Umgang mit dem TLS-Zertifikat, das den HTTPS-Datenstrom verschlüsselt, scheitern. [https://letsencrypt.org/ LetsEncrypt] benötigt bei Einrichtung und Verlängerung seiner Zertifikate einen offenen 80-er Port.&lt;br /&gt;
&lt;br /&gt;
Sollte es nötig sein, den Server von außen zu administrieren, wäre das am sichersten über ein VPN zu realisieren. Sicherer - und einfacher - ist es dennoch, die Administration ausschließlich über einen zertifikats-geschützten SSH-Zugang im inneren 192.168.-er-Netz zuzulassen.&lt;br /&gt;
&lt;br /&gt;
=== Wer macht was? ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Komponente !! Aufgabe !! Konfigurationsort&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Router / Gateway&#039;&#039;&#039; || DynDNS-Aktualisierung, erste NAT-Stufe, WLAN || Router Web-UI → Portfreigaben&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; || Firewall-Regeln, zweite NAT-Stufe (Destination NAT), DHCP für Server-VLAN || OPNsense Web-UI (Standard: https://&amp;amp;lt;wan-ip&amp;amp;gt;:443 oder :8443)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Caddy / Reverse Proxy&#039;&#039;&#039; || TLS-Terminierung, Let&#039;s Encrypt, Weiterleitung an Container || Caddyfile auf dem Homeserver&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Docker&#039;&#039;&#039; || Container-Isolation, internes Netz (Standard: 172.18.0.0/16) || docker-compose.yml pro Dienst&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fail2ban&#039;&#039;&#039; || Brute-Force-Schutz auf Applikationsebene || Jail-Configs im fail2ban-Container&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Wichtig: OPNsense hat ZWEI Firewall-Engines ===&lt;br /&gt;
&lt;br /&gt;
OPNsense 26.x hat zwei parallele Regelwerke:&lt;br /&gt;
* &#039;&#039;&#039;Rules [new]&#039;&#039;&#039; — neue API-basierte Engine&lt;br /&gt;
* &#039;&#039;&#039;Rules&#039;&#039;&#039; — alte Engine (Legacy)&lt;br /&gt;
&lt;br /&gt;
Neue Regeln &#039;&#039;&#039;immer in beiden&#039;&#039;&#039; anlegen! Bei Problemen immer beide prüfen.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 2: Wo steht was? ==&lt;br /&gt;
&lt;br /&gt;
=== IP-Adressen (Beispiel-Setup) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Gerät !! Interface !! IP !! Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
| Router / Gateway || — || 192.168.2.1 || Gateway, WLAN, DynDNS&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense WAN || wan-interface || 192.168.2.2 || Statisch konfiguriert&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense LAN / Server-VLAN || lan-interface || 192.168.10.1 || Gateway für Server-Netz&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver || eno1 / eth0 || 192.168.10.100 || Fest per DHCP-Reservation (MAC-Adresse)&lt;br /&gt;
|-&lt;br /&gt;
| Client-Geräte || WLAN || 192.168.2.x || Im Router-Netz, nicht im Server-VLAN&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Homeserver: Netzwerk-Interface-Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Der Homeserver bezieht seine IP per DHCP vom OPNsense-DHCP-Server. Bei Debian/Ubuntu mit systemd-networkd:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/systemd/network/10-eth0.network&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Korrekter Inhalt (DHCP):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[Match]&lt;br /&gt;
Name=eno1&lt;br /&gt;
&lt;br /&gt;
[Network]&lt;br /&gt;
DHCP=ipv4&lt;br /&gt;
&lt;br /&gt;
[DHCP]&lt;br /&gt;
RouteMetric=100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ &#039;&#039;&#039;Niemals&#039;&#039;&#039; eine statische IP oder einen Gateway manuell eintragen!&lt;br /&gt;
Der Default-Gateway kommt immer vom DHCP-Server der OPNsense-Firewall (&amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Kea DHCP Lease-Datei (OPNsense) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/db/kea/kea-leases4.csv&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier verwaltet Kea die aktiven Leases. Bei Problemen mit doppelten IPs kann diese Datei (nach &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;) auf den Header reduziert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context,pool_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 3: Systematische Diagnose — Schritt für Schritt ==&lt;br /&gt;
&lt;br /&gt;
=== Grundprinzip: Von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Immer von außen nach innen vorgehen — nie raten, immer messen. Jede Schicht einzeln prüfen.&lt;br /&gt;
&lt;br /&gt;
==== Schritt 1: Ist OPNsense überhaupt erreichbar? ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Vom Client-Rechner:&lt;br /&gt;
ping 192.168.2.2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ OPNsense antwortet standardmäßig &#039;&#039;&#039;nicht&#039;&#039;&#039; auf ICMP/Ping von außen — das ist korrekt!&lt;br /&gt;
&lt;br /&gt;
Stattdessen prüfen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Web-UI erreichbar?&lt;br /&gt;
https://192.168.2.2:8443&lt;br /&gt;
&lt;br /&gt;
# Router zeigt OPNsense als verbundenes Gerät?&lt;br /&gt;
http://192.168.2.1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 2: OPNsense intern prüfen ====&lt;br /&gt;
&lt;br /&gt;
Per SSH oder serieller Konsole auf OPNsense:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# WAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;wan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.2.2, status: active&lt;br /&gt;
&lt;br /&gt;
# LAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;lan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.10.1, status: active&lt;br /&gt;
&lt;br /&gt;
# Router erreichbar?&lt;br /&gt;
ping -c 3 192.168.2.1&lt;br /&gt;
&lt;br /&gt;
# Homeserver erreichbar?&lt;br /&gt;
ping -c 3 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 3: Homeserver direkt prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# SSH auf Homeserver:&lt;br /&gt;
ssh root@192.168.10.100&lt;br /&gt;
&lt;br /&gt;
# Alle Container laufen?&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# Internet vom Homeserver aus erreichbar?&lt;br /&gt;
ping -c 3 9.9.9.9&lt;br /&gt;
&lt;br /&gt;
# Routing-Tabelle korrekt?&lt;br /&gt;
ip route show&lt;br /&gt;
# Erwartete Default-Route: default via 192.168.10.1 dev eno1&lt;br /&gt;
# NICHT: default via 192.168.178.x — das wäre falsch!&lt;br /&gt;
&lt;br /&gt;
# Welche IP hat das Interface?&lt;br /&gt;
ip addr show eno1&lt;br /&gt;
# Erwartete IP: 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 4: Caddy / Reverse Proxy prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Läuft Caddy und antwortet er lokal?&lt;br /&gt;
curl -v http://localhost&lt;br /&gt;
# Erwartete Antwort: HTTP 308 Redirect → https://localhost/&lt;br /&gt;
&lt;br /&gt;
# Caddy-Logs auf Fehler prüfen:&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Typische Fehler in den Caddy-Logs:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fehlermeldung !! Bedeutung !! Lösung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dial tcp ...:443: connect: no route to host&amp;lt;/code&amp;gt; || Caddy kommt nicht ins Internet (Let&#039;s Encrypt nicht erreichbar) || Routing auf Homeserver prüfen (Schritt 3)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;no route to host&amp;lt;/code&amp;gt; bei Ping auf 9.9.9.9 || Falscher Default-Gateway || &amp;lt;code&amp;gt;ip route show&amp;lt;/code&amp;gt; prüfen, falsche Route entfernen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Schritt 5: NAT und Firewall-Regeln prüfen (OPNsense Shell) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# NAT-Regeln anzeigen:&lt;br /&gt;
pfctl -s nat | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Firewall-Regeln anzeigen:&lt;br /&gt;
pfctl -s rules | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf WAN-Interface beobachten (kommt der Request an?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;wan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf LAN-Interface beobachten (wird er weitergeleitet?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;lan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Diagnose-Logik:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tcpdump WAN sieht Traffic, LAN nicht → NAT-Regel prüfen!&lt;br /&gt;
tcpdump WAN sieht keinen Traffic    → Portweiterleitung im Router prüfen!&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 6: Bekannte Fallstricke ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Problem !! Symptom !! Ursache !! Fix&lt;br /&gt;
|-&lt;br /&gt;
| Falsche statische Route || &amp;lt;code&amp;gt;ping 9.9.9.9&amp;lt;/code&amp;gt; schlägt fehl || Netzwerk-Config hat statischen Gateway eingetragen || Auf DHCP umstellen, &amp;lt;code&amp;gt;systemctl restart systemd-networkd&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver hat falsche IP || NAT-Regeln greifen nicht || DHCP hat beim Neustart temporär andere IP vergeben || DHCP-Reservation per MAC-Adresse einrichten&lt;br /&gt;
|-&lt;br /&gt;
| DHCP-Leases durcheinander || Server taucht mit zwei IPs auf || Neustart hat neuen Lease vor Ablauf des alten erzeugt || &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;, Lease-CSV bereinigen, &amp;lt;code&amp;gt;configctl kea start&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense Firewall-Regel fehlt || Dienste von außen nicht erreichbar, intern OK || Regel nur in einer der beiden Engines angelegt || Regel in &#039;&#039;&#039;beiden&#039;&#039;&#039; Engines anlegen (Rules [new] + Rules)&lt;br /&gt;
|-&lt;br /&gt;
| NAT-Regel ohne Subnetz-Maske || Traffic kommt nicht an || &amp;lt;code&amp;gt;192.168.178.0&amp;lt;/code&amp;gt; statt &amp;lt;code&amp;gt;192.168.178.0/24&amp;lt;/code&amp;gt; eingetragen || Subnetz-Maske ergänzen — ohne /24 gilt nur die Netzadresse selbst!&lt;br /&gt;
|-&lt;br /&gt;
| Source/Destination Port vertauscht || Verbindungen werden blockiert || Bei Firewall-Regel Port unter &amp;quot;Source&amp;quot; statt &amp;quot;Destination&amp;quot; eingetragen || Source Port: any / Destination Port: gewünschter Port&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Notfall-Cheatsheet ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# OPNsense: Firewall temporär deaktivieren (Notfall!)&lt;br /&gt;
pfctl -d&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Firewall wieder aktivieren&lt;br /&gt;
pfctl -e&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Kea DHCP stoppen/starten&lt;br /&gt;
configctl kea stop&lt;br /&gt;
configctl kea start&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Falsche Default-Route entfernen&lt;br /&gt;
ip route del default via &amp;amp;lt;falsche-gateway-ip&amp;amp;gt; dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: IP manuell setzen (Sofortlösung bei DHCP-Problemen)&lt;br /&gt;
ip addr add 192.168.10.100/24 dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Netzwerk-Dienst neu starten (Verbindung kurz weg!)&lt;br /&gt;
systemctl restart systemd-networkd&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Docker-Logs prüfen&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Alias-Tabellen prüfen (Blocklisten)&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | wc -l&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | grep &amp;amp;lt;IP&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Sicherheitshinweise ==&lt;br /&gt;
&lt;br /&gt;
* SSH-Ports &#039;&#039;&#039;nicht&#039;&#039;&#039; über das Internet freigeben — nur intern erreichbar lassen! Wenn das nicht geht: VPN-Tunnel!&lt;br /&gt;
* Portweiterleitung im Router auf das &#039;&#039;&#039;Minimum&#039;&#039;&#039; beschränken (nur die Ports 80 + 443 öffnen)&lt;br /&gt;
* Für interne Admin-Interfaces (OPNsense Web-UI, Monitoring) &#039;&#039;&#039;keine externen Freigaben&#039;&#039;&#039;&lt;br /&gt;
* DHCP-Reservations per MAC-Adresse oder statische IP-Adressen verhindern IP-Wechsel nach Neustarts&lt;br /&gt;
* Bei Firewall-Regeln: Block-Regeln &#039;&#039;&#039;immer&#039;&#039;&#039; vor Pass-Regeln platzieren&lt;br /&gt;
&lt;br /&gt;
Abschließend eine absolute Regeln, die immer und durch die Ewigkeiten gilt:&lt;br /&gt;
* Dienste, die auf einem Rechner &#039;&#039;&#039;NICHT&#039;&#039;&#039; existieren, werden niemals angegriffen! Wenig ist hier mehr!&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Dieser Artikel basiert auf praktischen Erfahrungen aus dem Betrieb eines selbst gehosteten Servers mit OPNsense, Cisco-Switch und Docker-Stack.&#039;&#039;&lt;br /&gt;
&#039;&#039;Erstellt: Mai 2026&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=248</id>
		<title>Homeserver-Sicherheitsarchitektur</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=248"/>
		<updated>2026-05-27T23:18:44Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Die Kette von außen nach innen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Homeserver-Sicherheitsarchitektur: Aufbau, Funktionsweise und Diagnose ==&lt;br /&gt;
&lt;br /&gt;
Einen eigenen Server an&#039;s Internet zu bekommen, ist nicht allzu schwierig. Ein Dienst, der die eigene, vom Internet-Provider zugewiesene IP-Adresse in einen festen Domain-Namen umwandelt (siehe: [https://de.wikipedia.org/wiki/Dynamisches_DNS Dynamisches DNS]), wird im privaten Bereich die Voraussetzung sein.&lt;br /&gt;
Es gibt verschiedene Anbieter, oft auch kostenlose.&lt;br /&gt;
&lt;br /&gt;
=== Ein Leitfaden für selbst gehostete Server mit OPNsense, Managed Switch und Docker ===&lt;br /&gt;
&lt;br /&gt;
Die Kehrseite: Sowie der Server über&#039;s Internet erreichbar ist, ist er angreifbar. Das ist kein theoretisches Szenario. Meiner Erfahrung nach ist es eine Frage von Stunden, bis die ersten Bots &amp;quot;anklopfen&amp;quot;, nach laufenden Diensten suchen, nach offenen Ports, nach Schwachstellen.&lt;br /&gt;
&lt;br /&gt;
Aufgrund einer mangelhaften Konfiguration (offener Samba-Port) hatte ich die sehr reale Erfahrung einer russischen Hackerbande, die einige Hundert Textdateien mit Zahlungsaufforderungen und einen Verschlüsselungstrojaner auf meinem Rechner hinterlassen hatte. Gerettet hatten mich damals die Dateirechte von Linux. Das fehlende E(x)ecutional-Flag und die eingeschränkten Benutzerrechte hatten den Trojaner ausgebremst.&lt;br /&gt;
&lt;br /&gt;
Trotzdem: Nie wieder!&lt;br /&gt;
Ein wenig von dem, was ich gelernt habe, gebe ich ich hier weiter.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Einleitung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt den Aufbau einer &#039;&#039;&#039;sicheren&#039;&#039;&#039; Netzwerkarchitektur für einen Homeserver, der über das öffentliche Internet erreichbar ist. Der Beitrag richtet sich an alle, die ihre Daten selbst kontrollieren wollen — und dabei nicht unfreiwillig Teil einer globalen Angriffs-Infrastruktur werden möchten. Er will zum Verständnis beitragen, wie die einzelnen Komponenten zusammenspielen — und wie man systematisch vorgeht, wenn etwas nicht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der Fokus liegt nicht auf einer spezifischen Hardware-Konfiguration, sondern auf dem allgemeinen Prinzip: Wie kommt ein Request von außen sicher zu einem Docker-Container?&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Annahmen / Szenario ==&lt;br /&gt;
&lt;br /&gt;
Folgende Komponenten werden in diesem Artikel vorausgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver&#039;&#039;&#039; (Raspberry Pi, Intel NUC, oder beliebiger Linux-Server)&lt;br /&gt;
** Betriebssystem: Debian/Ubuntu oder vergleichbar&lt;br /&gt;
** Docker mit mehreren Diensten (z.B. WordPress, Nextcloud, MediaWiki)&lt;br /&gt;
** Caddy als Reverse Proxy (alternativ funktionieren [https://nginx.org/ nginx], [https://httpd.apache.org/ Apache], oder (ggf. kostenpflichtige) proprietäre Lösungen. Caddy allerdings hat das für mich charmante Feature, sich eigenständig um die TSL-Zertifikate und ihre Verlängerung bei LetsEncrypt zu kümmern. Wer aufgrund &amp;quot;zu vieler&amp;quot; Fehlversuche bei der Zertifikats-Einrichtung von LetsEncrypt auf Tage gesperrt wurde, wird mein Faible über diesen Automatismus nachvollziehen oder teilen können.)&lt;br /&gt;
** fail2ban als Brute-Force-Schutz&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;DynDNS-Dienst&#039;&#039;&#039; der dem Homeserver eine feste Domain zuweist&lt;br /&gt;
** Beispiel: &amp;lt;code&amp;gt;myhomeserver.dyndns.de&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Router / Heimnetz-Gateway&#039;&#039;&#039;&lt;br /&gt;
** Beispiel-IP: &amp;lt;code&amp;gt;192.168.2.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Portweiterleitung, WLAN, DynDNS-Aktualisierung&lt;br /&gt;
** Typisch: FritzBox, aber jeder Router mit Portweiterleitung funktioniert&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; (dedizierte Hardware-Firewall)&lt;br /&gt;
** WAN-Interface: &amp;lt;code&amp;gt;192.168.2.2&amp;lt;/code&amp;gt; (im Router-Netz)&lt;br /&gt;
** LAN-Interface / Server-VLAN: &amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Firewall, NAT, DHCP, IDS/IPS&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Managed Switch&#039;&#039;&#039; (optional, für VLAN-Segmentierung)&lt;br /&gt;
** Trennt Server-VLAN vom Rest des Netzes&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver-IP&#039;&#039;&#039;: &amp;lt;code&amp;gt;192.168.10.100&amp;lt;/code&amp;gt; (per DHCP-Reservation oder besser: Per statischer IP-Adresse fest)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 1: Wie funktionieren die Weiterleitungen? Wer macht was? ==&lt;br /&gt;
&lt;br /&gt;
=== Die Kette von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Ein Request von außen (z.B. Browser ruft &amp;lt;code&amp;gt;https://myhomeserver.dyndns.de&amp;lt;/code&amp;gt; auf) durchläuft folgende Stationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Internet&lt;br /&gt;
    ↓ DNS-Auflösung: dyndns.de → öffentliche IP des Heimnetzes&lt;br /&gt;
Router / Gateway (192.168.2.1)&lt;br /&gt;
    ↓ Portweiterleitung: :80 + :443 (und nur! diese!!) → 192.168.2.2&lt;br /&gt;
OPNsense WAN-Interface (192.168.2.2)&lt;br /&gt;
    ↓ Destination NAT: :80/:443 → 192.168.10.100&lt;br /&gt;
Homeserver eno1/eth0 (192.168.10.100)&lt;br /&gt;
    ↓ Docker-Port-Binding: 0.0.0.0:80 + 0.0.0.0:443&lt;br /&gt;
Caddy / Reverse Proxy (Docker-intern)&lt;br /&gt;
    ↓ Reverse Proxy anhand des Host-Headers&lt;br /&gt;
Ziel-Container (z.B. wordpress, nextcloud, ...)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit ist der Server auf der IP-Ebene (Layer 3 des OSI-Modells) von außen hin &amp;quot;unsichtbar&amp;quot;: Die Firewall (OPNsense) lebt, mit dem Gateway, im 192.168.2-er Netz. Von dort routet sie alle Anfragen über die Ports 80 und 443 an das Interface 192.168.10.100. Dahinter, also im 192.168.10-er-Subnetz, residiert der Heimserver.&lt;br /&gt;
&lt;br /&gt;
Am Ende dieses Beitrages gibt es Sicherheitshinweise. Bitte dringend beachten, dass der Router ausschließlich die Ports &#039;&#039;&#039;80/TCP&#039;&#039;&#039; und &#039;&#039;&#039;443/TCP&#039;&#039;&#039; nach außen frei gibt. Der Webserver wird dabei so konfiguriert, dass HTTP-Daten über Port 80 nach HTTPS auf Port 443 umgeleitet werden.&lt;br /&gt;
&lt;br /&gt;
Die Idee, ausschließlich HTTPS zuzulassen, läge nahe. Damit bräuchte sich der Webserver nicht um die Weiterleitung auf Port 443 zu befassen.&lt;br /&gt;
Bedauerlicherweise wird in diesem Fall der Umgang mit dem TLS-Zertifikat, das den HTTPS-Datenstrom verschlüsselt, scheitern. [https://letsencrypt.org/ LetsEncrypt] benötigt bei Einrichtung und Verlängerung seiner Zertifikate einen offenen 80-er Port.&lt;br /&gt;
&lt;br /&gt;
Sollte es nötig sein, den Server von außen zu administrieren, wäre das am sichersten über ein VPN mit SSH/Zertifikat zu realisieren. Sicherer - und einfacher - ist es dennoch, die Administration ausschließlich über einen SSH-Zugang im inneren 192.168.-er-Netz zuzulassen.&lt;br /&gt;
&lt;br /&gt;
=== Wer macht was? ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Komponente !! Aufgabe !! Konfigurationsort&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Router / Gateway&#039;&#039;&#039; || DynDNS-Aktualisierung, erste NAT-Stufe, WLAN || Router Web-UI → Portfreigaben&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; || Firewall-Regeln, zweite NAT-Stufe (Destination NAT), DHCP für Server-VLAN || OPNsense Web-UI (Standard: https://&amp;amp;lt;wan-ip&amp;amp;gt;:443 oder :8443)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Caddy / Reverse Proxy&#039;&#039;&#039; || TLS-Terminierung, Let&#039;s Encrypt, Weiterleitung an Container || Caddyfile auf dem Homeserver&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Docker&#039;&#039;&#039; || Container-Isolation, internes Netz (Standard: 172.18.0.0/16) || docker-compose.yml pro Dienst&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fail2ban&#039;&#039;&#039; || Brute-Force-Schutz auf Applikationsebene || Jail-Configs im fail2ban-Container&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Wichtig: OPNsense hat ZWEI Firewall-Engines ===&lt;br /&gt;
&lt;br /&gt;
OPNsense 26.x hat zwei parallele Regelwerke:&lt;br /&gt;
* &#039;&#039;&#039;Rules [new]&#039;&#039;&#039; — neue API-basierte Engine&lt;br /&gt;
* &#039;&#039;&#039;Rules&#039;&#039;&#039; — alte Engine (Legacy)&lt;br /&gt;
&lt;br /&gt;
Neue Regeln &#039;&#039;&#039;immer in beiden&#039;&#039;&#039; anlegen! Bei Problemen immer beide prüfen.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 2: Wo steht was? ==&lt;br /&gt;
&lt;br /&gt;
=== IP-Adressen (Beispiel-Setup) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Gerät !! Interface !! IP !! Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
| Router / Gateway || — || 192.168.2.1 || Gateway, WLAN, DynDNS&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense WAN || wan-interface || 192.168.2.2 || Statisch konfiguriert&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense LAN / Server-VLAN || lan-interface || 192.168.10.1 || Gateway für Server-Netz&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver || eno1 / eth0 || 192.168.10.100 || Fest per DHCP-Reservation (MAC-Adresse)&lt;br /&gt;
|-&lt;br /&gt;
| Client-Geräte || WLAN || 192.168.2.x || Im Router-Netz, nicht im Server-VLAN&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Homeserver: Netzwerk-Interface-Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Der Homeserver bezieht seine IP per DHCP vom OPNsense-DHCP-Server. Bei Debian/Ubuntu mit systemd-networkd:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/systemd/network/10-eth0.network&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Korrekter Inhalt (DHCP):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[Match]&lt;br /&gt;
Name=eno1&lt;br /&gt;
&lt;br /&gt;
[Network]&lt;br /&gt;
DHCP=ipv4&lt;br /&gt;
&lt;br /&gt;
[DHCP]&lt;br /&gt;
RouteMetric=100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ &#039;&#039;&#039;Niemals&#039;&#039;&#039; eine statische IP oder einen Gateway manuell eintragen!&lt;br /&gt;
Der Default-Gateway kommt immer vom DHCP-Server der OPNsense-Firewall (&amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Kea DHCP Lease-Datei (OPNsense) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/db/kea/kea-leases4.csv&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier verwaltet Kea die aktiven Leases. Bei Problemen mit doppelten IPs kann diese Datei (nach &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;) auf den Header reduziert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context,pool_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 3: Systematische Diagnose — Schritt für Schritt ==&lt;br /&gt;
&lt;br /&gt;
=== Grundprinzip: Von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Immer von außen nach innen vorgehen — nie raten, immer messen. Jede Schicht einzeln prüfen.&lt;br /&gt;
&lt;br /&gt;
==== Schritt 1: Ist OPNsense überhaupt erreichbar? ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Vom Client-Rechner:&lt;br /&gt;
ping 192.168.2.2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ OPNsense antwortet standardmäßig &#039;&#039;&#039;nicht&#039;&#039;&#039; auf ICMP/Ping von außen — das ist korrekt!&lt;br /&gt;
&lt;br /&gt;
Stattdessen prüfen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Web-UI erreichbar?&lt;br /&gt;
https://192.168.2.2:8443&lt;br /&gt;
&lt;br /&gt;
# Router zeigt OPNsense als verbundenes Gerät?&lt;br /&gt;
http://192.168.2.1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 2: OPNsense intern prüfen ====&lt;br /&gt;
&lt;br /&gt;
Per SSH oder serieller Konsole auf OPNsense:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# WAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;wan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.2.2, status: active&lt;br /&gt;
&lt;br /&gt;
# LAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;lan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.10.1, status: active&lt;br /&gt;
&lt;br /&gt;
# Router erreichbar?&lt;br /&gt;
ping -c 3 192.168.2.1&lt;br /&gt;
&lt;br /&gt;
# Homeserver erreichbar?&lt;br /&gt;
ping -c 3 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 3: Homeserver direkt prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# SSH auf Homeserver:&lt;br /&gt;
ssh root@192.168.10.100&lt;br /&gt;
&lt;br /&gt;
# Alle Container laufen?&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# Internet vom Homeserver aus erreichbar?&lt;br /&gt;
ping -c 3 9.9.9.9&lt;br /&gt;
&lt;br /&gt;
# Routing-Tabelle korrekt?&lt;br /&gt;
ip route show&lt;br /&gt;
# Erwartete Default-Route: default via 192.168.10.1 dev eno1&lt;br /&gt;
# NICHT: default via 192.168.178.x — das wäre falsch!&lt;br /&gt;
&lt;br /&gt;
# Welche IP hat das Interface?&lt;br /&gt;
ip addr show eno1&lt;br /&gt;
# Erwartete IP: 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 4: Caddy / Reverse Proxy prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Läuft Caddy und antwortet er lokal?&lt;br /&gt;
curl -v http://localhost&lt;br /&gt;
# Erwartete Antwort: HTTP 308 Redirect → https://localhost/&lt;br /&gt;
&lt;br /&gt;
# Caddy-Logs auf Fehler prüfen:&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Typische Fehler in den Caddy-Logs:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fehlermeldung !! Bedeutung !! Lösung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dial tcp ...:443: connect: no route to host&amp;lt;/code&amp;gt; || Caddy kommt nicht ins Internet (Let&#039;s Encrypt nicht erreichbar) || Routing auf Homeserver prüfen (Schritt 3)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;no route to host&amp;lt;/code&amp;gt; bei Ping auf 9.9.9.9 || Falscher Default-Gateway || &amp;lt;code&amp;gt;ip route show&amp;lt;/code&amp;gt; prüfen, falsche Route entfernen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Schritt 5: NAT und Firewall-Regeln prüfen (OPNsense Shell) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# NAT-Regeln anzeigen:&lt;br /&gt;
pfctl -s nat | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Firewall-Regeln anzeigen:&lt;br /&gt;
pfctl -s rules | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf WAN-Interface beobachten (kommt der Request an?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;wan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf LAN-Interface beobachten (wird er weitergeleitet?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;lan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Diagnose-Logik:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tcpdump WAN sieht Traffic, LAN nicht → NAT-Regel prüfen!&lt;br /&gt;
tcpdump WAN sieht keinen Traffic    → Portweiterleitung im Router prüfen!&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 6: Bekannte Fallstricke ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Problem !! Symptom !! Ursache !! Fix&lt;br /&gt;
|-&lt;br /&gt;
| Falsche statische Route || &amp;lt;code&amp;gt;ping 9.9.9.9&amp;lt;/code&amp;gt; schlägt fehl || Netzwerk-Config hat statischen Gateway eingetragen || Auf DHCP umstellen, &amp;lt;code&amp;gt;systemctl restart systemd-networkd&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver hat falsche IP || NAT-Regeln greifen nicht || DHCP hat beim Neustart temporär andere IP vergeben || DHCP-Reservation per MAC-Adresse einrichten&lt;br /&gt;
|-&lt;br /&gt;
| DHCP-Leases durcheinander || Server taucht mit zwei IPs auf || Neustart hat neuen Lease vor Ablauf des alten erzeugt || &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;, Lease-CSV bereinigen, &amp;lt;code&amp;gt;configctl kea start&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense Firewall-Regel fehlt || Dienste von außen nicht erreichbar, intern OK || Regel nur in einer der beiden Engines angelegt || Regel in &#039;&#039;&#039;beiden&#039;&#039;&#039; Engines anlegen (Rules [new] + Rules)&lt;br /&gt;
|-&lt;br /&gt;
| NAT-Regel ohne Subnetz-Maske || Traffic kommt nicht an || &amp;lt;code&amp;gt;192.168.178.0&amp;lt;/code&amp;gt; statt &amp;lt;code&amp;gt;192.168.178.0/24&amp;lt;/code&amp;gt; eingetragen || Subnetz-Maske ergänzen — ohne /24 gilt nur die Netzadresse selbst!&lt;br /&gt;
|-&lt;br /&gt;
| Source/Destination Port vertauscht || Verbindungen werden blockiert || Bei Firewall-Regel Port unter &amp;quot;Source&amp;quot; statt &amp;quot;Destination&amp;quot; eingetragen || Source Port: any / Destination Port: gewünschter Port&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Notfall-Cheatsheet ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# OPNsense: Firewall temporär deaktivieren (Notfall!)&lt;br /&gt;
pfctl -d&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Firewall wieder aktivieren&lt;br /&gt;
pfctl -e&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Kea DHCP stoppen/starten&lt;br /&gt;
configctl kea stop&lt;br /&gt;
configctl kea start&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Falsche Default-Route entfernen&lt;br /&gt;
ip route del default via &amp;amp;lt;falsche-gateway-ip&amp;amp;gt; dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: IP manuell setzen (Sofortlösung bei DHCP-Problemen)&lt;br /&gt;
ip addr add 192.168.10.100/24 dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Netzwerk-Dienst neu starten (Verbindung kurz weg!)&lt;br /&gt;
systemctl restart systemd-networkd&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Docker-Logs prüfen&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Alias-Tabellen prüfen (Blocklisten)&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | wc -l&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | grep &amp;amp;lt;IP&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Sicherheitshinweise ==&lt;br /&gt;
&lt;br /&gt;
* SSH-Ports &#039;&#039;&#039;nicht&#039;&#039;&#039; über das Internet freigeben — nur intern erreichbar lassen! Wenn das nicht geht: VPN-Tunnel!&lt;br /&gt;
* Portweiterleitung im Router auf das &#039;&#039;&#039;Minimum&#039;&#039;&#039; beschränken (nur die Ports 80 + 443 öffnen)&lt;br /&gt;
* Für interne Admin-Interfaces (OPNsense Web-UI, Monitoring) &#039;&#039;&#039;keine externen Freigaben&#039;&#039;&#039;&lt;br /&gt;
* DHCP-Reservations per MAC-Adresse oder statische IP-Adressen verhindern IP-Wechsel nach Neustarts&lt;br /&gt;
* Bei Firewall-Regeln: Block-Regeln &#039;&#039;&#039;immer&#039;&#039;&#039; vor Pass-Regeln platzieren&lt;br /&gt;
&lt;br /&gt;
Abschließend eine absolute Regeln, die immer und durch die Ewigkeiten gilt:&lt;br /&gt;
* Dienste, die auf einem Rechner &#039;&#039;&#039;NICHT&#039;&#039;&#039; existieren, werden niemals angegriffen! Wenig ist hier mehr!&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Dieser Artikel basiert auf praktischen Erfahrungen aus dem Betrieb eines selbst gehosteten Servers mit OPNsense, Cisco-Switch und Docker-Stack.&#039;&#039;&lt;br /&gt;
&#039;&#039;Erstellt: Mai 2026&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=247</id>
		<title>Homeserver-Sicherheitsarchitektur</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=247"/>
		<updated>2026-05-27T23:10:07Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Die Kette von außen nach innen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Homeserver-Sicherheitsarchitektur: Aufbau, Funktionsweise und Diagnose ==&lt;br /&gt;
&lt;br /&gt;
Einen eigenen Server an&#039;s Internet zu bekommen, ist nicht allzu schwierig. Ein Dienst, der die eigene, vom Internet-Provider zugewiesene IP-Adresse in einen festen Domain-Namen umwandelt (siehe: [https://de.wikipedia.org/wiki/Dynamisches_DNS Dynamisches DNS]), wird im privaten Bereich die Voraussetzung sein.&lt;br /&gt;
Es gibt verschiedene Anbieter, oft auch kostenlose.&lt;br /&gt;
&lt;br /&gt;
=== Ein Leitfaden für selbst gehostete Server mit OPNsense, Managed Switch und Docker ===&lt;br /&gt;
&lt;br /&gt;
Die Kehrseite: Sowie der Server über&#039;s Internet erreichbar ist, ist er angreifbar. Das ist kein theoretisches Szenario. Meiner Erfahrung nach ist es eine Frage von Stunden, bis die ersten Bots &amp;quot;anklopfen&amp;quot;, nach laufenden Diensten suchen, nach offenen Ports, nach Schwachstellen.&lt;br /&gt;
&lt;br /&gt;
Aufgrund einer mangelhaften Konfiguration (offener Samba-Port) hatte ich die sehr reale Erfahrung einer russischen Hackerbande, die einige Hundert Textdateien mit Zahlungsaufforderungen und einen Verschlüsselungstrojaner auf meinem Rechner hinterlassen hatte. Gerettet hatten mich damals die Dateirechte von Linux. Das fehlende E(x)ecutional-Flag und die eingeschränkten Benutzerrechte hatten den Trojaner ausgebremst.&lt;br /&gt;
&lt;br /&gt;
Trotzdem: Nie wieder!&lt;br /&gt;
Ein wenig von dem, was ich gelernt habe, gebe ich ich hier weiter.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Einleitung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt den Aufbau einer &#039;&#039;&#039;sicheren&#039;&#039;&#039; Netzwerkarchitektur für einen Homeserver, der über das öffentliche Internet erreichbar ist. Der Beitrag richtet sich an alle, die ihre Daten selbst kontrollieren wollen — und dabei nicht unfreiwillig Teil einer globalen Angriffs-Infrastruktur werden möchten. Er will zum Verständnis beitragen, wie die einzelnen Komponenten zusammenspielen — und wie man systematisch vorgeht, wenn etwas nicht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der Fokus liegt nicht auf einer spezifischen Hardware-Konfiguration, sondern auf dem allgemeinen Prinzip: Wie kommt ein Request von außen sicher zu einem Docker-Container?&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Annahmen / Szenario ==&lt;br /&gt;
&lt;br /&gt;
Folgende Komponenten werden in diesem Artikel vorausgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver&#039;&#039;&#039; (Raspberry Pi, Intel NUC, oder beliebiger Linux-Server)&lt;br /&gt;
** Betriebssystem: Debian/Ubuntu oder vergleichbar&lt;br /&gt;
** Docker mit mehreren Diensten (z.B. WordPress, Nextcloud, MediaWiki)&lt;br /&gt;
** Caddy als Reverse Proxy (alternativ funktionieren [https://nginx.org/ nginx], [https://httpd.apache.org/ Apache], oder (ggf. kostenpflichtige) proprietäre Lösungen. Caddy allerdings hat das für mich charmante Feature, sich eigenständig um die TSL-Zertifikate und ihre Verlängerung bei LetsEncrypt zu kümmern. Wer aufgrund &amp;quot;zu vieler&amp;quot; Fehlversuche bei der Zertifikats-Einrichtung von LetsEncrypt auf Tage gesperrt wurde, wird mein Faible über diesen Automatismus nachvollziehen oder teilen können.)&lt;br /&gt;
** fail2ban als Brute-Force-Schutz&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;DynDNS-Dienst&#039;&#039;&#039; der dem Homeserver eine feste Domain zuweist&lt;br /&gt;
** Beispiel: &amp;lt;code&amp;gt;myhomeserver.dyndns.de&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Router / Heimnetz-Gateway&#039;&#039;&#039;&lt;br /&gt;
** Beispiel-IP: &amp;lt;code&amp;gt;192.168.2.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Portweiterleitung, WLAN, DynDNS-Aktualisierung&lt;br /&gt;
** Typisch: FritzBox, aber jeder Router mit Portweiterleitung funktioniert&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; (dedizierte Hardware-Firewall)&lt;br /&gt;
** WAN-Interface: &amp;lt;code&amp;gt;192.168.2.2&amp;lt;/code&amp;gt; (im Router-Netz)&lt;br /&gt;
** LAN-Interface / Server-VLAN: &amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Firewall, NAT, DHCP, IDS/IPS&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Managed Switch&#039;&#039;&#039; (optional, für VLAN-Segmentierung)&lt;br /&gt;
** Trennt Server-VLAN vom Rest des Netzes&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver-IP&#039;&#039;&#039;: &amp;lt;code&amp;gt;192.168.10.100&amp;lt;/code&amp;gt; (per DHCP-Reservation oder besser: Per statischer IP-Adresse fest)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 1: Wie funktionieren die Weiterleitungen? Wer macht was? ==&lt;br /&gt;
&lt;br /&gt;
=== Die Kette von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Ein Request von außen (z.B. Browser ruft &amp;lt;code&amp;gt;https://myhomeserver.dyndns.de&amp;lt;/code&amp;gt; auf) durchläuft folgende Stationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Internet&lt;br /&gt;
    ↓ DNS-Auflösung: dyndns.de → öffentliche IP des Heimnetzes&lt;br /&gt;
Router / Gateway (192.168.2.1)&lt;br /&gt;
    ↓ Portweiterleitung: :80 + :443 (und nur! diese!!) → 192.168.2.2&lt;br /&gt;
OPNsense WAN-Interface (192.168.2.2)&lt;br /&gt;
    ↓ Destination NAT: :80/:443 → 192.168.10.100&lt;br /&gt;
Homeserver eno1/eth0 (192.168.10.100)&lt;br /&gt;
    ↓ Docker-Port-Binding: 0.0.0.0:80 + 0.0.0.0:443&lt;br /&gt;
Caddy / Reverse Proxy (Docker-intern)&lt;br /&gt;
    ↓ Reverse Proxy anhand des Host-Headers&lt;br /&gt;
Ziel-Container (z.B. wordpress, nextcloud, ...)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit ist der Server auf der IP-Ebene (Layer 3 des OSI-Modells) von außen hin &amp;quot;unsichtbar&amp;quot;: Die Firewall (OPNsense) lebt, mit dem Gateway, im 192.168.2-er Netz. Von dort routet sie alle Anfragen über die Ports 80 und 443 an das Interface 192.168.10.100. Dahinter, also im 192.168.10-er-Subnetz, residiert der Heimserver.&lt;br /&gt;
&lt;br /&gt;
Am Ende dieses Beitrages gibt es Sicherheitshinweise. Bitte dringend beachten, dass der Router ausschließlich die Ports &#039;&#039;&#039;80/TCP&#039;&#039;&#039; und &#039;&#039;&#039;443/TCP&#039;&#039;&#039; nach außen frei gibt. Der Webserver wird dabei so konfiguriert, dass HTTP-Daten über Port 80 nach HTTPS, 443 umgeleitet werden.&lt;br /&gt;
&lt;br /&gt;
Die Idee, Port 80 ebenfalls dicht zu machen und ausschließlich HTTPS zuzulassen, liegt nahe, scheitert aber spätestens beim TLS-Zertifikat. [https://letsencrypt.org/ LetsEncrypt] benötigt bei Einrichtung und Verlängerung der Zertifikate einen offenen 80-er Port.&lt;br /&gt;
&lt;br /&gt;
Sollte es nötig sein, den Server von außen zu administrieren, wäre das vermutlich am sichersten über ein VPN mit SSH/Zertifikat zu realisieren.&lt;br /&gt;
&lt;br /&gt;
=== Wer macht was? ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Komponente !! Aufgabe !! Konfigurationsort&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Router / Gateway&#039;&#039;&#039; || DynDNS-Aktualisierung, erste NAT-Stufe, WLAN || Router Web-UI → Portfreigaben&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; || Firewall-Regeln, zweite NAT-Stufe (Destination NAT), DHCP für Server-VLAN || OPNsense Web-UI (Standard: https://&amp;amp;lt;wan-ip&amp;amp;gt;:443 oder :8443)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Caddy / Reverse Proxy&#039;&#039;&#039; || TLS-Terminierung, Let&#039;s Encrypt, Weiterleitung an Container || Caddyfile auf dem Homeserver&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Docker&#039;&#039;&#039; || Container-Isolation, internes Netz (Standard: 172.18.0.0/16) || docker-compose.yml pro Dienst&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fail2ban&#039;&#039;&#039; || Brute-Force-Schutz auf Applikationsebene || Jail-Configs im fail2ban-Container&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Wichtig: OPNsense hat ZWEI Firewall-Engines ===&lt;br /&gt;
&lt;br /&gt;
OPNsense 26.x hat zwei parallele Regelwerke:&lt;br /&gt;
* &#039;&#039;&#039;Rules [new]&#039;&#039;&#039; — neue API-basierte Engine&lt;br /&gt;
* &#039;&#039;&#039;Rules&#039;&#039;&#039; — alte Engine (Legacy)&lt;br /&gt;
&lt;br /&gt;
Neue Regeln &#039;&#039;&#039;immer in beiden&#039;&#039;&#039; anlegen! Bei Problemen immer beide prüfen.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 2: Wo steht was? ==&lt;br /&gt;
&lt;br /&gt;
=== IP-Adressen (Beispiel-Setup) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Gerät !! Interface !! IP !! Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
| Router / Gateway || — || 192.168.2.1 || Gateway, WLAN, DynDNS&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense WAN || wan-interface || 192.168.2.2 || Statisch konfiguriert&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense LAN / Server-VLAN || lan-interface || 192.168.10.1 || Gateway für Server-Netz&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver || eno1 / eth0 || 192.168.10.100 || Fest per DHCP-Reservation (MAC-Adresse)&lt;br /&gt;
|-&lt;br /&gt;
| Client-Geräte || WLAN || 192.168.2.x || Im Router-Netz, nicht im Server-VLAN&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Homeserver: Netzwerk-Interface-Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Der Homeserver bezieht seine IP per DHCP vom OPNsense-DHCP-Server. Bei Debian/Ubuntu mit systemd-networkd:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/systemd/network/10-eth0.network&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Korrekter Inhalt (DHCP):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[Match]&lt;br /&gt;
Name=eno1&lt;br /&gt;
&lt;br /&gt;
[Network]&lt;br /&gt;
DHCP=ipv4&lt;br /&gt;
&lt;br /&gt;
[DHCP]&lt;br /&gt;
RouteMetric=100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ &#039;&#039;&#039;Niemals&#039;&#039;&#039; eine statische IP oder einen Gateway manuell eintragen!&lt;br /&gt;
Der Default-Gateway kommt immer vom DHCP-Server der OPNsense-Firewall (&amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Kea DHCP Lease-Datei (OPNsense) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/db/kea/kea-leases4.csv&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier verwaltet Kea die aktiven Leases. Bei Problemen mit doppelten IPs kann diese Datei (nach &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;) auf den Header reduziert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context,pool_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 3: Systematische Diagnose — Schritt für Schritt ==&lt;br /&gt;
&lt;br /&gt;
=== Grundprinzip: Von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Immer von außen nach innen vorgehen — nie raten, immer messen. Jede Schicht einzeln prüfen.&lt;br /&gt;
&lt;br /&gt;
==== Schritt 1: Ist OPNsense überhaupt erreichbar? ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Vom Client-Rechner:&lt;br /&gt;
ping 192.168.2.2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ OPNsense antwortet standardmäßig &#039;&#039;&#039;nicht&#039;&#039;&#039; auf ICMP/Ping von außen — das ist korrekt!&lt;br /&gt;
&lt;br /&gt;
Stattdessen prüfen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Web-UI erreichbar?&lt;br /&gt;
https://192.168.2.2:8443&lt;br /&gt;
&lt;br /&gt;
# Router zeigt OPNsense als verbundenes Gerät?&lt;br /&gt;
http://192.168.2.1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 2: OPNsense intern prüfen ====&lt;br /&gt;
&lt;br /&gt;
Per SSH oder serieller Konsole auf OPNsense:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# WAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;wan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.2.2, status: active&lt;br /&gt;
&lt;br /&gt;
# LAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;lan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.10.1, status: active&lt;br /&gt;
&lt;br /&gt;
# Router erreichbar?&lt;br /&gt;
ping -c 3 192.168.2.1&lt;br /&gt;
&lt;br /&gt;
# Homeserver erreichbar?&lt;br /&gt;
ping -c 3 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 3: Homeserver direkt prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# SSH auf Homeserver:&lt;br /&gt;
ssh root@192.168.10.100&lt;br /&gt;
&lt;br /&gt;
# Alle Container laufen?&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# Internet vom Homeserver aus erreichbar?&lt;br /&gt;
ping -c 3 9.9.9.9&lt;br /&gt;
&lt;br /&gt;
# Routing-Tabelle korrekt?&lt;br /&gt;
ip route show&lt;br /&gt;
# Erwartete Default-Route: default via 192.168.10.1 dev eno1&lt;br /&gt;
# NICHT: default via 192.168.178.x — das wäre falsch!&lt;br /&gt;
&lt;br /&gt;
# Welche IP hat das Interface?&lt;br /&gt;
ip addr show eno1&lt;br /&gt;
# Erwartete IP: 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 4: Caddy / Reverse Proxy prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Läuft Caddy und antwortet er lokal?&lt;br /&gt;
curl -v http://localhost&lt;br /&gt;
# Erwartete Antwort: HTTP 308 Redirect → https://localhost/&lt;br /&gt;
&lt;br /&gt;
# Caddy-Logs auf Fehler prüfen:&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Typische Fehler in den Caddy-Logs:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fehlermeldung !! Bedeutung !! Lösung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dial tcp ...:443: connect: no route to host&amp;lt;/code&amp;gt; || Caddy kommt nicht ins Internet (Let&#039;s Encrypt nicht erreichbar) || Routing auf Homeserver prüfen (Schritt 3)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;no route to host&amp;lt;/code&amp;gt; bei Ping auf 9.9.9.9 || Falscher Default-Gateway || &amp;lt;code&amp;gt;ip route show&amp;lt;/code&amp;gt; prüfen, falsche Route entfernen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Schritt 5: NAT und Firewall-Regeln prüfen (OPNsense Shell) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# NAT-Regeln anzeigen:&lt;br /&gt;
pfctl -s nat | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Firewall-Regeln anzeigen:&lt;br /&gt;
pfctl -s rules | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf WAN-Interface beobachten (kommt der Request an?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;wan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf LAN-Interface beobachten (wird er weitergeleitet?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;lan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Diagnose-Logik:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tcpdump WAN sieht Traffic, LAN nicht → NAT-Regel prüfen!&lt;br /&gt;
tcpdump WAN sieht keinen Traffic    → Portweiterleitung im Router prüfen!&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 6: Bekannte Fallstricke ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Problem !! Symptom !! Ursache !! Fix&lt;br /&gt;
|-&lt;br /&gt;
| Falsche statische Route || &amp;lt;code&amp;gt;ping 9.9.9.9&amp;lt;/code&amp;gt; schlägt fehl || Netzwerk-Config hat statischen Gateway eingetragen || Auf DHCP umstellen, &amp;lt;code&amp;gt;systemctl restart systemd-networkd&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver hat falsche IP || NAT-Regeln greifen nicht || DHCP hat beim Neustart temporär andere IP vergeben || DHCP-Reservation per MAC-Adresse einrichten&lt;br /&gt;
|-&lt;br /&gt;
| DHCP-Leases durcheinander || Server taucht mit zwei IPs auf || Neustart hat neuen Lease vor Ablauf des alten erzeugt || &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;, Lease-CSV bereinigen, &amp;lt;code&amp;gt;configctl kea start&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense Firewall-Regel fehlt || Dienste von außen nicht erreichbar, intern OK || Regel nur in einer der beiden Engines angelegt || Regel in &#039;&#039;&#039;beiden&#039;&#039;&#039; Engines anlegen (Rules [new] + Rules)&lt;br /&gt;
|-&lt;br /&gt;
| NAT-Regel ohne Subnetz-Maske || Traffic kommt nicht an || &amp;lt;code&amp;gt;192.168.178.0&amp;lt;/code&amp;gt; statt &amp;lt;code&amp;gt;192.168.178.0/24&amp;lt;/code&amp;gt; eingetragen || Subnetz-Maske ergänzen — ohne /24 gilt nur die Netzadresse selbst!&lt;br /&gt;
|-&lt;br /&gt;
| Source/Destination Port vertauscht || Verbindungen werden blockiert || Bei Firewall-Regel Port unter &amp;quot;Source&amp;quot; statt &amp;quot;Destination&amp;quot; eingetragen || Source Port: any / Destination Port: gewünschter Port&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Notfall-Cheatsheet ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# OPNsense: Firewall temporär deaktivieren (Notfall!)&lt;br /&gt;
pfctl -d&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Firewall wieder aktivieren&lt;br /&gt;
pfctl -e&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Kea DHCP stoppen/starten&lt;br /&gt;
configctl kea stop&lt;br /&gt;
configctl kea start&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Falsche Default-Route entfernen&lt;br /&gt;
ip route del default via &amp;amp;lt;falsche-gateway-ip&amp;amp;gt; dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: IP manuell setzen (Sofortlösung bei DHCP-Problemen)&lt;br /&gt;
ip addr add 192.168.10.100/24 dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Netzwerk-Dienst neu starten (Verbindung kurz weg!)&lt;br /&gt;
systemctl restart systemd-networkd&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Docker-Logs prüfen&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Alias-Tabellen prüfen (Blocklisten)&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | wc -l&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | grep &amp;amp;lt;IP&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Sicherheitshinweise ==&lt;br /&gt;
&lt;br /&gt;
* SSH-Ports &#039;&#039;&#039;nicht&#039;&#039;&#039; über das Internet freigeben — nur intern erreichbar lassen! Wenn das nicht geht: VPN-Tunnel!&lt;br /&gt;
* Portweiterleitung im Router auf das &#039;&#039;&#039;Minimum&#039;&#039;&#039; beschränken (nur die Ports 80 + 443 öffnen)&lt;br /&gt;
* Für interne Admin-Interfaces (OPNsense Web-UI, Monitoring) &#039;&#039;&#039;keine externen Freigaben&#039;&#039;&#039;&lt;br /&gt;
* DHCP-Reservations per MAC-Adresse oder statische IP-Adressen verhindern IP-Wechsel nach Neustarts&lt;br /&gt;
* Bei Firewall-Regeln: Block-Regeln &#039;&#039;&#039;immer&#039;&#039;&#039; vor Pass-Regeln platzieren&lt;br /&gt;
&lt;br /&gt;
Abschließend eine absolute Regeln, die immer und durch die Ewigkeiten gilt:&lt;br /&gt;
* Dienste, die auf einem Rechner &#039;&#039;&#039;NICHT&#039;&#039;&#039; existieren, werden niemals angegriffen! Wenig ist hier mehr!&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Dieser Artikel basiert auf praktischen Erfahrungen aus dem Betrieb eines selbst gehosteten Servers mit OPNsense, Cisco-Switch und Docker-Stack.&#039;&#039;&lt;br /&gt;
&#039;&#039;Erstellt: Mai 2026&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=246</id>
		<title>Homeserver-Sicherheitsarchitektur</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=246"/>
		<updated>2026-05-27T23:05:01Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Sicherheitshinweise */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Homeserver-Sicherheitsarchitektur: Aufbau, Funktionsweise und Diagnose ==&lt;br /&gt;
&lt;br /&gt;
Einen eigenen Server an&#039;s Internet zu bekommen, ist nicht allzu schwierig. Ein Dienst, der die eigene, vom Internet-Provider zugewiesene IP-Adresse in einen festen Domain-Namen umwandelt (siehe: [https://de.wikipedia.org/wiki/Dynamisches_DNS Dynamisches DNS]), wird im privaten Bereich die Voraussetzung sein.&lt;br /&gt;
Es gibt verschiedene Anbieter, oft auch kostenlose.&lt;br /&gt;
&lt;br /&gt;
=== Ein Leitfaden für selbst gehostete Server mit OPNsense, Managed Switch und Docker ===&lt;br /&gt;
&lt;br /&gt;
Die Kehrseite: Sowie der Server über&#039;s Internet erreichbar ist, ist er angreifbar. Das ist kein theoretisches Szenario. Meiner Erfahrung nach ist es eine Frage von Stunden, bis die ersten Bots &amp;quot;anklopfen&amp;quot;, nach laufenden Diensten suchen, nach offenen Ports, nach Schwachstellen.&lt;br /&gt;
&lt;br /&gt;
Aufgrund einer mangelhaften Konfiguration (offener Samba-Port) hatte ich die sehr reale Erfahrung einer russischen Hackerbande, die einige Hundert Textdateien mit Zahlungsaufforderungen und einen Verschlüsselungstrojaner auf meinem Rechner hinterlassen hatte. Gerettet hatten mich damals die Dateirechte von Linux. Das fehlende E(x)ecutional-Flag und die eingeschränkten Benutzerrechte hatten den Trojaner ausgebremst.&lt;br /&gt;
&lt;br /&gt;
Trotzdem: Nie wieder!&lt;br /&gt;
Ein wenig von dem, was ich gelernt habe, gebe ich ich hier weiter.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Einleitung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt den Aufbau einer &#039;&#039;&#039;sicheren&#039;&#039;&#039; Netzwerkarchitektur für einen Homeserver, der über das öffentliche Internet erreichbar ist. Der Beitrag richtet sich an alle, die ihre Daten selbst kontrollieren wollen — und dabei nicht unfreiwillig Teil einer globalen Angriffs-Infrastruktur werden möchten. Er will zum Verständnis beitragen, wie die einzelnen Komponenten zusammenspielen — und wie man systematisch vorgeht, wenn etwas nicht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der Fokus liegt nicht auf einer spezifischen Hardware-Konfiguration, sondern auf dem allgemeinen Prinzip: Wie kommt ein Request von außen sicher zu einem Docker-Container?&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Annahmen / Szenario ==&lt;br /&gt;
&lt;br /&gt;
Folgende Komponenten werden in diesem Artikel vorausgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver&#039;&#039;&#039; (Raspberry Pi, Intel NUC, oder beliebiger Linux-Server)&lt;br /&gt;
** Betriebssystem: Debian/Ubuntu oder vergleichbar&lt;br /&gt;
** Docker mit mehreren Diensten (z.B. WordPress, Nextcloud, MediaWiki)&lt;br /&gt;
** Caddy als Reverse Proxy (alternativ funktionieren [https://nginx.org/ nginx], [https://httpd.apache.org/ Apache], oder (ggf. kostenpflichtige) proprietäre Lösungen. Caddy allerdings hat das für mich charmante Feature, sich eigenständig um die TSL-Zertifikate und ihre Verlängerung bei LetsEncrypt zu kümmern. Wer aufgrund &amp;quot;zu vieler&amp;quot; Fehlversuche bei der Zertifikats-Einrichtung von LetsEncrypt auf Tage gesperrt wurde, wird mein Faible über diesen Automatismus nachvollziehen oder teilen können.)&lt;br /&gt;
** fail2ban als Brute-Force-Schutz&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;DynDNS-Dienst&#039;&#039;&#039; der dem Homeserver eine feste Domain zuweist&lt;br /&gt;
** Beispiel: &amp;lt;code&amp;gt;myhomeserver.dyndns.de&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Router / Heimnetz-Gateway&#039;&#039;&#039;&lt;br /&gt;
** Beispiel-IP: &amp;lt;code&amp;gt;192.168.2.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Portweiterleitung, WLAN, DynDNS-Aktualisierung&lt;br /&gt;
** Typisch: FritzBox, aber jeder Router mit Portweiterleitung funktioniert&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; (dedizierte Hardware-Firewall)&lt;br /&gt;
** WAN-Interface: &amp;lt;code&amp;gt;192.168.2.2&amp;lt;/code&amp;gt; (im Router-Netz)&lt;br /&gt;
** LAN-Interface / Server-VLAN: &amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Firewall, NAT, DHCP, IDS/IPS&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Managed Switch&#039;&#039;&#039; (optional, für VLAN-Segmentierung)&lt;br /&gt;
** Trennt Server-VLAN vom Rest des Netzes&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver-IP&#039;&#039;&#039;: &amp;lt;code&amp;gt;192.168.10.100&amp;lt;/code&amp;gt; (per DHCP-Reservation oder besser: Per statischer IP-Adresse fest)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 1: Wie funktionieren die Weiterleitungen? Wer macht was? ==&lt;br /&gt;
&lt;br /&gt;
=== Die Kette von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Ein Request von außen (z.B. Browser ruft &amp;lt;code&amp;gt;https://myhomeserver.dyndns.de&amp;lt;/code&amp;gt; auf) durchläuft folgende Stationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Internet&lt;br /&gt;
    ↓ DNS-Auflösung: dyndns.de → öffentliche IP des Heimnetzes&lt;br /&gt;
Router / Gateway (192.168.2.1)&lt;br /&gt;
    ↓ Portweiterleitung: :80 + :443 (und nur! diese!!) → 192.168.2.2&lt;br /&gt;
OPNsense WAN-Interface (192.168.2.2)&lt;br /&gt;
    ↓ Destination NAT: :80/:443 → 192.168.10.100&lt;br /&gt;
Homeserver eno1/eth0 (192.168.10.100)&lt;br /&gt;
    ↓ Docker-Port-Binding: 0.0.0.0:80 + 0.0.0.0:443&lt;br /&gt;
Caddy / Reverse Proxy (Docker-intern)&lt;br /&gt;
    ↓ Reverse Proxy anhand des Host-Headers&lt;br /&gt;
Ziel-Container (z.B. wordpress, nextcloud, ...)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit ist der Server auf der IP-Ebene (Layer 3 des OSI-Modells) von außen hin &amp;quot;unsichtbar&amp;quot;: Die Firewall (OPNsense) lebt, mit dem Gateway, im 192.168.2-er Netz. Von dort routet sie alle Anfragen über die Ports 80 und 443 an das Interface 192.168.10.100. Dahinter, also im 192.168.10-er-Subnetz, residiert der Heimserver.&lt;br /&gt;
&lt;br /&gt;
Am Ende dieses Beitrages gibt es Sicherheitshinweise. Bitte dringend beachten, dass der Router ausschließlich die Ports 80/TCP und 443/TCP nach außen frei gibt. Sollte es nötig sein, den Server von außen zu administrieren, wäre das vermutlich am sichersten über ein VPN mit SSH/Zertifikat zu realisieren.&lt;br /&gt;
&lt;br /&gt;
=== Wer macht was? ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Komponente !! Aufgabe !! Konfigurationsort&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Router / Gateway&#039;&#039;&#039; || DynDNS-Aktualisierung, erste NAT-Stufe, WLAN || Router Web-UI → Portfreigaben&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; || Firewall-Regeln, zweite NAT-Stufe (Destination NAT), DHCP für Server-VLAN || OPNsense Web-UI (Standard: https://&amp;amp;lt;wan-ip&amp;amp;gt;:443 oder :8443)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Caddy / Reverse Proxy&#039;&#039;&#039; || TLS-Terminierung, Let&#039;s Encrypt, Weiterleitung an Container || Caddyfile auf dem Homeserver&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Docker&#039;&#039;&#039; || Container-Isolation, internes Netz (Standard: 172.18.0.0/16) || docker-compose.yml pro Dienst&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fail2ban&#039;&#039;&#039; || Brute-Force-Schutz auf Applikationsebene || Jail-Configs im fail2ban-Container&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Wichtig: OPNsense hat ZWEI Firewall-Engines ===&lt;br /&gt;
&lt;br /&gt;
OPNsense 26.x hat zwei parallele Regelwerke:&lt;br /&gt;
* &#039;&#039;&#039;Rules [new]&#039;&#039;&#039; — neue API-basierte Engine&lt;br /&gt;
* &#039;&#039;&#039;Rules&#039;&#039;&#039; — alte Engine (Legacy)&lt;br /&gt;
&lt;br /&gt;
Neue Regeln &#039;&#039;&#039;immer in beiden&#039;&#039;&#039; anlegen! Bei Problemen immer beide prüfen.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 2: Wo steht was? ==&lt;br /&gt;
&lt;br /&gt;
=== IP-Adressen (Beispiel-Setup) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Gerät !! Interface !! IP !! Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
| Router / Gateway || — || 192.168.2.1 || Gateway, WLAN, DynDNS&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense WAN || wan-interface || 192.168.2.2 || Statisch konfiguriert&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense LAN / Server-VLAN || lan-interface || 192.168.10.1 || Gateway für Server-Netz&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver || eno1 / eth0 || 192.168.10.100 || Fest per DHCP-Reservation (MAC-Adresse)&lt;br /&gt;
|-&lt;br /&gt;
| Client-Geräte || WLAN || 192.168.2.x || Im Router-Netz, nicht im Server-VLAN&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Homeserver: Netzwerk-Interface-Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Der Homeserver bezieht seine IP per DHCP vom OPNsense-DHCP-Server. Bei Debian/Ubuntu mit systemd-networkd:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/systemd/network/10-eth0.network&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Korrekter Inhalt (DHCP):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[Match]&lt;br /&gt;
Name=eno1&lt;br /&gt;
&lt;br /&gt;
[Network]&lt;br /&gt;
DHCP=ipv4&lt;br /&gt;
&lt;br /&gt;
[DHCP]&lt;br /&gt;
RouteMetric=100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ &#039;&#039;&#039;Niemals&#039;&#039;&#039; eine statische IP oder einen Gateway manuell eintragen!&lt;br /&gt;
Der Default-Gateway kommt immer vom DHCP-Server der OPNsense-Firewall (&amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Kea DHCP Lease-Datei (OPNsense) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/db/kea/kea-leases4.csv&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier verwaltet Kea die aktiven Leases. Bei Problemen mit doppelten IPs kann diese Datei (nach &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;) auf den Header reduziert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context,pool_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 3: Systematische Diagnose — Schritt für Schritt ==&lt;br /&gt;
&lt;br /&gt;
=== Grundprinzip: Von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Immer von außen nach innen vorgehen — nie raten, immer messen. Jede Schicht einzeln prüfen.&lt;br /&gt;
&lt;br /&gt;
==== Schritt 1: Ist OPNsense überhaupt erreichbar? ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Vom Client-Rechner:&lt;br /&gt;
ping 192.168.2.2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ OPNsense antwortet standardmäßig &#039;&#039;&#039;nicht&#039;&#039;&#039; auf ICMP/Ping von außen — das ist korrekt!&lt;br /&gt;
&lt;br /&gt;
Stattdessen prüfen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Web-UI erreichbar?&lt;br /&gt;
https://192.168.2.2:8443&lt;br /&gt;
&lt;br /&gt;
# Router zeigt OPNsense als verbundenes Gerät?&lt;br /&gt;
http://192.168.2.1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 2: OPNsense intern prüfen ====&lt;br /&gt;
&lt;br /&gt;
Per SSH oder serieller Konsole auf OPNsense:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# WAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;wan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.2.2, status: active&lt;br /&gt;
&lt;br /&gt;
# LAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;lan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.10.1, status: active&lt;br /&gt;
&lt;br /&gt;
# Router erreichbar?&lt;br /&gt;
ping -c 3 192.168.2.1&lt;br /&gt;
&lt;br /&gt;
# Homeserver erreichbar?&lt;br /&gt;
ping -c 3 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 3: Homeserver direkt prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# SSH auf Homeserver:&lt;br /&gt;
ssh root@192.168.10.100&lt;br /&gt;
&lt;br /&gt;
# Alle Container laufen?&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# Internet vom Homeserver aus erreichbar?&lt;br /&gt;
ping -c 3 9.9.9.9&lt;br /&gt;
&lt;br /&gt;
# Routing-Tabelle korrekt?&lt;br /&gt;
ip route show&lt;br /&gt;
# Erwartete Default-Route: default via 192.168.10.1 dev eno1&lt;br /&gt;
# NICHT: default via 192.168.178.x — das wäre falsch!&lt;br /&gt;
&lt;br /&gt;
# Welche IP hat das Interface?&lt;br /&gt;
ip addr show eno1&lt;br /&gt;
# Erwartete IP: 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 4: Caddy / Reverse Proxy prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Läuft Caddy und antwortet er lokal?&lt;br /&gt;
curl -v http://localhost&lt;br /&gt;
# Erwartete Antwort: HTTP 308 Redirect → https://localhost/&lt;br /&gt;
&lt;br /&gt;
# Caddy-Logs auf Fehler prüfen:&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Typische Fehler in den Caddy-Logs:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fehlermeldung !! Bedeutung !! Lösung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dial tcp ...:443: connect: no route to host&amp;lt;/code&amp;gt; || Caddy kommt nicht ins Internet (Let&#039;s Encrypt nicht erreichbar) || Routing auf Homeserver prüfen (Schritt 3)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;no route to host&amp;lt;/code&amp;gt; bei Ping auf 9.9.9.9 || Falscher Default-Gateway || &amp;lt;code&amp;gt;ip route show&amp;lt;/code&amp;gt; prüfen, falsche Route entfernen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Schritt 5: NAT und Firewall-Regeln prüfen (OPNsense Shell) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# NAT-Regeln anzeigen:&lt;br /&gt;
pfctl -s nat | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Firewall-Regeln anzeigen:&lt;br /&gt;
pfctl -s rules | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf WAN-Interface beobachten (kommt der Request an?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;wan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf LAN-Interface beobachten (wird er weitergeleitet?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;lan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Diagnose-Logik:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tcpdump WAN sieht Traffic, LAN nicht → NAT-Regel prüfen!&lt;br /&gt;
tcpdump WAN sieht keinen Traffic    → Portweiterleitung im Router prüfen!&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 6: Bekannte Fallstricke ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Problem !! Symptom !! Ursache !! Fix&lt;br /&gt;
|-&lt;br /&gt;
| Falsche statische Route || &amp;lt;code&amp;gt;ping 9.9.9.9&amp;lt;/code&amp;gt; schlägt fehl || Netzwerk-Config hat statischen Gateway eingetragen || Auf DHCP umstellen, &amp;lt;code&amp;gt;systemctl restart systemd-networkd&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver hat falsche IP || NAT-Regeln greifen nicht || DHCP hat beim Neustart temporär andere IP vergeben || DHCP-Reservation per MAC-Adresse einrichten&lt;br /&gt;
|-&lt;br /&gt;
| DHCP-Leases durcheinander || Server taucht mit zwei IPs auf || Neustart hat neuen Lease vor Ablauf des alten erzeugt || &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;, Lease-CSV bereinigen, &amp;lt;code&amp;gt;configctl kea start&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense Firewall-Regel fehlt || Dienste von außen nicht erreichbar, intern OK || Regel nur in einer der beiden Engines angelegt || Regel in &#039;&#039;&#039;beiden&#039;&#039;&#039; Engines anlegen (Rules [new] + Rules)&lt;br /&gt;
|-&lt;br /&gt;
| NAT-Regel ohne Subnetz-Maske || Traffic kommt nicht an || &amp;lt;code&amp;gt;192.168.178.0&amp;lt;/code&amp;gt; statt &amp;lt;code&amp;gt;192.168.178.0/24&amp;lt;/code&amp;gt; eingetragen || Subnetz-Maske ergänzen — ohne /24 gilt nur die Netzadresse selbst!&lt;br /&gt;
|-&lt;br /&gt;
| Source/Destination Port vertauscht || Verbindungen werden blockiert || Bei Firewall-Regel Port unter &amp;quot;Source&amp;quot; statt &amp;quot;Destination&amp;quot; eingetragen || Source Port: any / Destination Port: gewünschter Port&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Notfall-Cheatsheet ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# OPNsense: Firewall temporär deaktivieren (Notfall!)&lt;br /&gt;
pfctl -d&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Firewall wieder aktivieren&lt;br /&gt;
pfctl -e&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Kea DHCP stoppen/starten&lt;br /&gt;
configctl kea stop&lt;br /&gt;
configctl kea start&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Falsche Default-Route entfernen&lt;br /&gt;
ip route del default via &amp;amp;lt;falsche-gateway-ip&amp;amp;gt; dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: IP manuell setzen (Sofortlösung bei DHCP-Problemen)&lt;br /&gt;
ip addr add 192.168.10.100/24 dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Netzwerk-Dienst neu starten (Verbindung kurz weg!)&lt;br /&gt;
systemctl restart systemd-networkd&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Docker-Logs prüfen&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Alias-Tabellen prüfen (Blocklisten)&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | wc -l&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | grep &amp;amp;lt;IP&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Sicherheitshinweise ==&lt;br /&gt;
&lt;br /&gt;
* SSH-Ports &#039;&#039;&#039;nicht&#039;&#039;&#039; über das Internet freigeben — nur intern erreichbar lassen! Wenn das nicht geht: VPN-Tunnel!&lt;br /&gt;
* Portweiterleitung im Router auf das &#039;&#039;&#039;Minimum&#039;&#039;&#039; beschränken (nur die Ports 80 + 443 öffnen)&lt;br /&gt;
* Für interne Admin-Interfaces (OPNsense Web-UI, Monitoring) &#039;&#039;&#039;keine externen Freigaben&#039;&#039;&#039;&lt;br /&gt;
* DHCP-Reservations per MAC-Adresse oder statische IP-Adressen verhindern IP-Wechsel nach Neustarts&lt;br /&gt;
* Bei Firewall-Regeln: Block-Regeln &#039;&#039;&#039;immer&#039;&#039;&#039; vor Pass-Regeln platzieren&lt;br /&gt;
&lt;br /&gt;
Abschließend eine absolute Regeln, die immer und durch die Ewigkeiten gilt:&lt;br /&gt;
* Dienste, die auf einem Rechner &#039;&#039;&#039;NICHT&#039;&#039;&#039; existieren, werden niemals angegriffen! Wenig ist hier mehr!&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Dieser Artikel basiert auf praktischen Erfahrungen aus dem Betrieb eines selbst gehosteten Servers mit OPNsense, Cisco-Switch und Docker-Stack.&#039;&#039;&lt;br /&gt;
&#039;&#039;Erstellt: Mai 2026&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=245</id>
		<title>Homeserver-Sicherheitsarchitektur</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=245"/>
		<updated>2026-05-27T23:02:23Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Sicherheitshinweise */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Homeserver-Sicherheitsarchitektur: Aufbau, Funktionsweise und Diagnose ==&lt;br /&gt;
&lt;br /&gt;
Einen eigenen Server an&#039;s Internet zu bekommen, ist nicht allzu schwierig. Ein Dienst, der die eigene, vom Internet-Provider zugewiesene IP-Adresse in einen festen Domain-Namen umwandelt (siehe: [https://de.wikipedia.org/wiki/Dynamisches_DNS Dynamisches DNS]), wird im privaten Bereich die Voraussetzung sein.&lt;br /&gt;
Es gibt verschiedene Anbieter, oft auch kostenlose.&lt;br /&gt;
&lt;br /&gt;
=== Ein Leitfaden für selbst gehostete Server mit OPNsense, Managed Switch und Docker ===&lt;br /&gt;
&lt;br /&gt;
Die Kehrseite: Sowie der Server über&#039;s Internet erreichbar ist, ist er angreifbar. Das ist kein theoretisches Szenario. Meiner Erfahrung nach ist es eine Frage von Stunden, bis die ersten Bots &amp;quot;anklopfen&amp;quot;, nach laufenden Diensten suchen, nach offenen Ports, nach Schwachstellen.&lt;br /&gt;
&lt;br /&gt;
Aufgrund einer mangelhaften Konfiguration (offener Samba-Port) hatte ich die sehr reale Erfahrung einer russischen Hackerbande, die einige Hundert Textdateien mit Zahlungsaufforderungen und einen Verschlüsselungstrojaner auf meinem Rechner hinterlassen hatte. Gerettet hatten mich damals die Dateirechte von Linux. Das fehlende E(x)ecutional-Flag und die eingeschränkten Benutzerrechte hatten den Trojaner ausgebremst.&lt;br /&gt;
&lt;br /&gt;
Trotzdem: Nie wieder!&lt;br /&gt;
Ein wenig von dem, was ich gelernt habe, gebe ich ich hier weiter.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Einleitung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt den Aufbau einer &#039;&#039;&#039;sicheren&#039;&#039;&#039; Netzwerkarchitektur für einen Homeserver, der über das öffentliche Internet erreichbar ist. Der Beitrag richtet sich an alle, die ihre Daten selbst kontrollieren wollen — und dabei nicht unfreiwillig Teil einer globalen Angriffs-Infrastruktur werden möchten. Er will zum Verständnis beitragen, wie die einzelnen Komponenten zusammenspielen — und wie man systematisch vorgeht, wenn etwas nicht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der Fokus liegt nicht auf einer spezifischen Hardware-Konfiguration, sondern auf dem allgemeinen Prinzip: Wie kommt ein Request von außen sicher zu einem Docker-Container?&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Annahmen / Szenario ==&lt;br /&gt;
&lt;br /&gt;
Folgende Komponenten werden in diesem Artikel vorausgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver&#039;&#039;&#039; (Raspberry Pi, Intel NUC, oder beliebiger Linux-Server)&lt;br /&gt;
** Betriebssystem: Debian/Ubuntu oder vergleichbar&lt;br /&gt;
** Docker mit mehreren Diensten (z.B. WordPress, Nextcloud, MediaWiki)&lt;br /&gt;
** Caddy als Reverse Proxy (alternativ funktionieren [https://nginx.org/ nginx], [https://httpd.apache.org/ Apache], oder (ggf. kostenpflichtige) proprietäre Lösungen. Caddy allerdings hat das für mich charmante Feature, sich eigenständig um die TSL-Zertifikate und ihre Verlängerung bei LetsEncrypt zu kümmern. Wer aufgrund &amp;quot;zu vieler&amp;quot; Fehlversuche bei der Zertifikats-Einrichtung von LetsEncrypt auf Tage gesperrt wurde, wird mein Faible über diesen Automatismus nachvollziehen oder teilen können.)&lt;br /&gt;
** fail2ban als Brute-Force-Schutz&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;DynDNS-Dienst&#039;&#039;&#039; der dem Homeserver eine feste Domain zuweist&lt;br /&gt;
** Beispiel: &amp;lt;code&amp;gt;myhomeserver.dyndns.de&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Router / Heimnetz-Gateway&#039;&#039;&#039;&lt;br /&gt;
** Beispiel-IP: &amp;lt;code&amp;gt;192.168.2.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Portweiterleitung, WLAN, DynDNS-Aktualisierung&lt;br /&gt;
** Typisch: FritzBox, aber jeder Router mit Portweiterleitung funktioniert&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; (dedizierte Hardware-Firewall)&lt;br /&gt;
** WAN-Interface: &amp;lt;code&amp;gt;192.168.2.2&amp;lt;/code&amp;gt; (im Router-Netz)&lt;br /&gt;
** LAN-Interface / Server-VLAN: &amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Firewall, NAT, DHCP, IDS/IPS&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Managed Switch&#039;&#039;&#039; (optional, für VLAN-Segmentierung)&lt;br /&gt;
** Trennt Server-VLAN vom Rest des Netzes&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver-IP&#039;&#039;&#039;: &amp;lt;code&amp;gt;192.168.10.100&amp;lt;/code&amp;gt; (per DHCP-Reservation oder besser: Per statischer IP-Adresse fest)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 1: Wie funktionieren die Weiterleitungen? Wer macht was? ==&lt;br /&gt;
&lt;br /&gt;
=== Die Kette von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Ein Request von außen (z.B. Browser ruft &amp;lt;code&amp;gt;https://myhomeserver.dyndns.de&amp;lt;/code&amp;gt; auf) durchläuft folgende Stationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Internet&lt;br /&gt;
    ↓ DNS-Auflösung: dyndns.de → öffentliche IP des Heimnetzes&lt;br /&gt;
Router / Gateway (192.168.2.1)&lt;br /&gt;
    ↓ Portweiterleitung: :80 + :443 (und nur! diese!!) → 192.168.2.2&lt;br /&gt;
OPNsense WAN-Interface (192.168.2.2)&lt;br /&gt;
    ↓ Destination NAT: :80/:443 → 192.168.10.100&lt;br /&gt;
Homeserver eno1/eth0 (192.168.10.100)&lt;br /&gt;
    ↓ Docker-Port-Binding: 0.0.0.0:80 + 0.0.0.0:443&lt;br /&gt;
Caddy / Reverse Proxy (Docker-intern)&lt;br /&gt;
    ↓ Reverse Proxy anhand des Host-Headers&lt;br /&gt;
Ziel-Container (z.B. wordpress, nextcloud, ...)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit ist der Server auf der IP-Ebene (Layer 3 des OSI-Modells) von außen hin &amp;quot;unsichtbar&amp;quot;: Die Firewall (OPNsense) lebt, mit dem Gateway, im 192.168.2-er Netz. Von dort routet sie alle Anfragen über die Ports 80 und 443 an das Interface 192.168.10.100. Dahinter, also im 192.168.10-er-Subnetz, residiert der Heimserver.&lt;br /&gt;
&lt;br /&gt;
Am Ende dieses Beitrages gibt es Sicherheitshinweise. Bitte dringend beachten, dass der Router ausschließlich die Ports 80/TCP und 443/TCP nach außen frei gibt. Sollte es nötig sein, den Server von außen zu administrieren, wäre das vermutlich am sichersten über ein VPN mit SSH/Zertifikat zu realisieren.&lt;br /&gt;
&lt;br /&gt;
=== Wer macht was? ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Komponente !! Aufgabe !! Konfigurationsort&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Router / Gateway&#039;&#039;&#039; || DynDNS-Aktualisierung, erste NAT-Stufe, WLAN || Router Web-UI → Portfreigaben&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; || Firewall-Regeln, zweite NAT-Stufe (Destination NAT), DHCP für Server-VLAN || OPNsense Web-UI (Standard: https://&amp;amp;lt;wan-ip&amp;amp;gt;:443 oder :8443)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Caddy / Reverse Proxy&#039;&#039;&#039; || TLS-Terminierung, Let&#039;s Encrypt, Weiterleitung an Container || Caddyfile auf dem Homeserver&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Docker&#039;&#039;&#039; || Container-Isolation, internes Netz (Standard: 172.18.0.0/16) || docker-compose.yml pro Dienst&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fail2ban&#039;&#039;&#039; || Brute-Force-Schutz auf Applikationsebene || Jail-Configs im fail2ban-Container&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Wichtig: OPNsense hat ZWEI Firewall-Engines ===&lt;br /&gt;
&lt;br /&gt;
OPNsense 26.x hat zwei parallele Regelwerke:&lt;br /&gt;
* &#039;&#039;&#039;Rules [new]&#039;&#039;&#039; — neue API-basierte Engine&lt;br /&gt;
* &#039;&#039;&#039;Rules&#039;&#039;&#039; — alte Engine (Legacy)&lt;br /&gt;
&lt;br /&gt;
Neue Regeln &#039;&#039;&#039;immer in beiden&#039;&#039;&#039; anlegen! Bei Problemen immer beide prüfen.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 2: Wo steht was? ==&lt;br /&gt;
&lt;br /&gt;
=== IP-Adressen (Beispiel-Setup) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Gerät !! Interface !! IP !! Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
| Router / Gateway || — || 192.168.2.1 || Gateway, WLAN, DynDNS&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense WAN || wan-interface || 192.168.2.2 || Statisch konfiguriert&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense LAN / Server-VLAN || lan-interface || 192.168.10.1 || Gateway für Server-Netz&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver || eno1 / eth0 || 192.168.10.100 || Fest per DHCP-Reservation (MAC-Adresse)&lt;br /&gt;
|-&lt;br /&gt;
| Client-Geräte || WLAN || 192.168.2.x || Im Router-Netz, nicht im Server-VLAN&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Homeserver: Netzwerk-Interface-Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Der Homeserver bezieht seine IP per DHCP vom OPNsense-DHCP-Server. Bei Debian/Ubuntu mit systemd-networkd:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/systemd/network/10-eth0.network&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Korrekter Inhalt (DHCP):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[Match]&lt;br /&gt;
Name=eno1&lt;br /&gt;
&lt;br /&gt;
[Network]&lt;br /&gt;
DHCP=ipv4&lt;br /&gt;
&lt;br /&gt;
[DHCP]&lt;br /&gt;
RouteMetric=100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ &#039;&#039;&#039;Niemals&#039;&#039;&#039; eine statische IP oder einen Gateway manuell eintragen!&lt;br /&gt;
Der Default-Gateway kommt immer vom DHCP-Server der OPNsense-Firewall (&amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Kea DHCP Lease-Datei (OPNsense) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/db/kea/kea-leases4.csv&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier verwaltet Kea die aktiven Leases. Bei Problemen mit doppelten IPs kann diese Datei (nach &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;) auf den Header reduziert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context,pool_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 3: Systematische Diagnose — Schritt für Schritt ==&lt;br /&gt;
&lt;br /&gt;
=== Grundprinzip: Von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Immer von außen nach innen vorgehen — nie raten, immer messen. Jede Schicht einzeln prüfen.&lt;br /&gt;
&lt;br /&gt;
==== Schritt 1: Ist OPNsense überhaupt erreichbar? ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Vom Client-Rechner:&lt;br /&gt;
ping 192.168.2.2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ OPNsense antwortet standardmäßig &#039;&#039;&#039;nicht&#039;&#039;&#039; auf ICMP/Ping von außen — das ist korrekt!&lt;br /&gt;
&lt;br /&gt;
Stattdessen prüfen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Web-UI erreichbar?&lt;br /&gt;
https://192.168.2.2:8443&lt;br /&gt;
&lt;br /&gt;
# Router zeigt OPNsense als verbundenes Gerät?&lt;br /&gt;
http://192.168.2.1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 2: OPNsense intern prüfen ====&lt;br /&gt;
&lt;br /&gt;
Per SSH oder serieller Konsole auf OPNsense:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# WAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;wan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.2.2, status: active&lt;br /&gt;
&lt;br /&gt;
# LAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;lan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.10.1, status: active&lt;br /&gt;
&lt;br /&gt;
# Router erreichbar?&lt;br /&gt;
ping -c 3 192.168.2.1&lt;br /&gt;
&lt;br /&gt;
# Homeserver erreichbar?&lt;br /&gt;
ping -c 3 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 3: Homeserver direkt prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# SSH auf Homeserver:&lt;br /&gt;
ssh root@192.168.10.100&lt;br /&gt;
&lt;br /&gt;
# Alle Container laufen?&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# Internet vom Homeserver aus erreichbar?&lt;br /&gt;
ping -c 3 9.9.9.9&lt;br /&gt;
&lt;br /&gt;
# Routing-Tabelle korrekt?&lt;br /&gt;
ip route show&lt;br /&gt;
# Erwartete Default-Route: default via 192.168.10.1 dev eno1&lt;br /&gt;
# NICHT: default via 192.168.178.x — das wäre falsch!&lt;br /&gt;
&lt;br /&gt;
# Welche IP hat das Interface?&lt;br /&gt;
ip addr show eno1&lt;br /&gt;
# Erwartete IP: 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 4: Caddy / Reverse Proxy prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Läuft Caddy und antwortet er lokal?&lt;br /&gt;
curl -v http://localhost&lt;br /&gt;
# Erwartete Antwort: HTTP 308 Redirect → https://localhost/&lt;br /&gt;
&lt;br /&gt;
# Caddy-Logs auf Fehler prüfen:&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Typische Fehler in den Caddy-Logs:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fehlermeldung !! Bedeutung !! Lösung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dial tcp ...:443: connect: no route to host&amp;lt;/code&amp;gt; || Caddy kommt nicht ins Internet (Let&#039;s Encrypt nicht erreichbar) || Routing auf Homeserver prüfen (Schritt 3)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;no route to host&amp;lt;/code&amp;gt; bei Ping auf 9.9.9.9 || Falscher Default-Gateway || &amp;lt;code&amp;gt;ip route show&amp;lt;/code&amp;gt; prüfen, falsche Route entfernen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Schritt 5: NAT und Firewall-Regeln prüfen (OPNsense Shell) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# NAT-Regeln anzeigen:&lt;br /&gt;
pfctl -s nat | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Firewall-Regeln anzeigen:&lt;br /&gt;
pfctl -s rules | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf WAN-Interface beobachten (kommt der Request an?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;wan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf LAN-Interface beobachten (wird er weitergeleitet?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;lan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Diagnose-Logik:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tcpdump WAN sieht Traffic, LAN nicht → NAT-Regel prüfen!&lt;br /&gt;
tcpdump WAN sieht keinen Traffic    → Portweiterleitung im Router prüfen!&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 6: Bekannte Fallstricke ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Problem !! Symptom !! Ursache !! Fix&lt;br /&gt;
|-&lt;br /&gt;
| Falsche statische Route || &amp;lt;code&amp;gt;ping 9.9.9.9&amp;lt;/code&amp;gt; schlägt fehl || Netzwerk-Config hat statischen Gateway eingetragen || Auf DHCP umstellen, &amp;lt;code&amp;gt;systemctl restart systemd-networkd&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver hat falsche IP || NAT-Regeln greifen nicht || DHCP hat beim Neustart temporär andere IP vergeben || DHCP-Reservation per MAC-Adresse einrichten&lt;br /&gt;
|-&lt;br /&gt;
| DHCP-Leases durcheinander || Server taucht mit zwei IPs auf || Neustart hat neuen Lease vor Ablauf des alten erzeugt || &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;, Lease-CSV bereinigen, &amp;lt;code&amp;gt;configctl kea start&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense Firewall-Regel fehlt || Dienste von außen nicht erreichbar, intern OK || Regel nur in einer der beiden Engines angelegt || Regel in &#039;&#039;&#039;beiden&#039;&#039;&#039; Engines anlegen (Rules [new] + Rules)&lt;br /&gt;
|-&lt;br /&gt;
| NAT-Regel ohne Subnetz-Maske || Traffic kommt nicht an || &amp;lt;code&amp;gt;192.168.178.0&amp;lt;/code&amp;gt; statt &amp;lt;code&amp;gt;192.168.178.0/24&amp;lt;/code&amp;gt; eingetragen || Subnetz-Maske ergänzen — ohne /24 gilt nur die Netzadresse selbst!&lt;br /&gt;
|-&lt;br /&gt;
| Source/Destination Port vertauscht || Verbindungen werden blockiert || Bei Firewall-Regel Port unter &amp;quot;Source&amp;quot; statt &amp;quot;Destination&amp;quot; eingetragen || Source Port: any / Destination Port: gewünschter Port&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Notfall-Cheatsheet ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# OPNsense: Firewall temporär deaktivieren (Notfall!)&lt;br /&gt;
pfctl -d&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Firewall wieder aktivieren&lt;br /&gt;
pfctl -e&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Kea DHCP stoppen/starten&lt;br /&gt;
configctl kea stop&lt;br /&gt;
configctl kea start&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Falsche Default-Route entfernen&lt;br /&gt;
ip route del default via &amp;amp;lt;falsche-gateway-ip&amp;amp;gt; dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: IP manuell setzen (Sofortlösung bei DHCP-Problemen)&lt;br /&gt;
ip addr add 192.168.10.100/24 dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Netzwerk-Dienst neu starten (Verbindung kurz weg!)&lt;br /&gt;
systemctl restart systemd-networkd&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Docker-Logs prüfen&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Alias-Tabellen prüfen (Blocklisten)&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | wc -l&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | grep &amp;amp;lt;IP&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Sicherheitshinweise ==&lt;br /&gt;
&lt;br /&gt;
* SSH-Ports &#039;&#039;&#039;nicht&#039;&#039;&#039; über das Internet freigeben — nur intern erreichbar lassen! Wenn das nicht geht: VPN-Tunnel!&lt;br /&gt;
* Portweiterleitung im Router auf das &#039;&#039;&#039;Minimum&#039;&#039;&#039; beschränken (nur 80 + 443)&lt;br /&gt;
* Für interne Admin-Interfaces (OPNsense Web-UI, Monitoring) &#039;&#039;&#039;keine externen Freigaben&#039;&#039;&#039;&lt;br /&gt;
* DHCP-Reservations per MAC-Adresse oder statische IP-Adressen verhindern IP-Wechsel nach Neustarts&lt;br /&gt;
* Bei Firewall-Regeln: Block-Regeln &#039;&#039;&#039;immer&#039;&#039;&#039; vor Pass-Regeln platzieren&lt;br /&gt;
&lt;br /&gt;
Abschließend eine absolute Regeln, die immer und durch die Ewigkeiten gilt:&lt;br /&gt;
* Dienste, die &#039;&#039;&#039;NICHT&#039;&#039;&#039; existieren, werden nicht angegriffen! Wenig ist hier immer mehr!&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Dieser Artikel basiert auf praktischen Erfahrungen aus dem Betrieb eines selbst gehosteten Servers mit OPNsense, Cisco-Switch und Docker-Stack.&#039;&#039;&lt;br /&gt;
&#039;&#039;Erstellt: Mai 2026&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=244</id>
		<title>Homeserver-Sicherheitsarchitektur</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=244"/>
		<updated>2026-05-27T22:58:09Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Die Kette von außen nach innen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Homeserver-Sicherheitsarchitektur: Aufbau, Funktionsweise und Diagnose ==&lt;br /&gt;
&lt;br /&gt;
Einen eigenen Server an&#039;s Internet zu bekommen, ist nicht allzu schwierig. Ein Dienst, der die eigene, vom Internet-Provider zugewiesene IP-Adresse in einen festen Domain-Namen umwandelt (siehe: [https://de.wikipedia.org/wiki/Dynamisches_DNS Dynamisches DNS]), wird im privaten Bereich die Voraussetzung sein.&lt;br /&gt;
Es gibt verschiedene Anbieter, oft auch kostenlose.&lt;br /&gt;
&lt;br /&gt;
=== Ein Leitfaden für selbst gehostete Server mit OPNsense, Managed Switch und Docker ===&lt;br /&gt;
&lt;br /&gt;
Die Kehrseite: Sowie der Server über&#039;s Internet erreichbar ist, ist er angreifbar. Das ist kein theoretisches Szenario. Meiner Erfahrung nach ist es eine Frage von Stunden, bis die ersten Bots &amp;quot;anklopfen&amp;quot;, nach laufenden Diensten suchen, nach offenen Ports, nach Schwachstellen.&lt;br /&gt;
&lt;br /&gt;
Aufgrund einer mangelhaften Konfiguration (offener Samba-Port) hatte ich die sehr reale Erfahrung einer russischen Hackerbande, die einige Hundert Textdateien mit Zahlungsaufforderungen und einen Verschlüsselungstrojaner auf meinem Rechner hinterlassen hatte. Gerettet hatten mich damals die Dateirechte von Linux. Das fehlende E(x)ecutional-Flag und die eingeschränkten Benutzerrechte hatten den Trojaner ausgebremst.&lt;br /&gt;
&lt;br /&gt;
Trotzdem: Nie wieder!&lt;br /&gt;
Ein wenig von dem, was ich gelernt habe, gebe ich ich hier weiter.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Einleitung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt den Aufbau einer &#039;&#039;&#039;sicheren&#039;&#039;&#039; Netzwerkarchitektur für einen Homeserver, der über das öffentliche Internet erreichbar ist. Der Beitrag richtet sich an alle, die ihre Daten selbst kontrollieren wollen — und dabei nicht unfreiwillig Teil einer globalen Angriffs-Infrastruktur werden möchten. Er will zum Verständnis beitragen, wie die einzelnen Komponenten zusammenspielen — und wie man systematisch vorgeht, wenn etwas nicht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der Fokus liegt nicht auf einer spezifischen Hardware-Konfiguration, sondern auf dem allgemeinen Prinzip: Wie kommt ein Request von außen sicher zu einem Docker-Container?&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Annahmen / Szenario ==&lt;br /&gt;
&lt;br /&gt;
Folgende Komponenten werden in diesem Artikel vorausgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver&#039;&#039;&#039; (Raspberry Pi, Intel NUC, oder beliebiger Linux-Server)&lt;br /&gt;
** Betriebssystem: Debian/Ubuntu oder vergleichbar&lt;br /&gt;
** Docker mit mehreren Diensten (z.B. WordPress, Nextcloud, MediaWiki)&lt;br /&gt;
** Caddy als Reverse Proxy (alternativ funktionieren [https://nginx.org/ nginx], [https://httpd.apache.org/ Apache], oder (ggf. kostenpflichtige) proprietäre Lösungen. Caddy allerdings hat das für mich charmante Feature, sich eigenständig um die TSL-Zertifikate und ihre Verlängerung bei LetsEncrypt zu kümmern. Wer aufgrund &amp;quot;zu vieler&amp;quot; Fehlversuche bei der Zertifikats-Einrichtung von LetsEncrypt auf Tage gesperrt wurde, wird mein Faible über diesen Automatismus nachvollziehen oder teilen können.)&lt;br /&gt;
** fail2ban als Brute-Force-Schutz&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;DynDNS-Dienst&#039;&#039;&#039; der dem Homeserver eine feste Domain zuweist&lt;br /&gt;
** Beispiel: &amp;lt;code&amp;gt;myhomeserver.dyndns.de&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Router / Heimnetz-Gateway&#039;&#039;&#039;&lt;br /&gt;
** Beispiel-IP: &amp;lt;code&amp;gt;192.168.2.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Portweiterleitung, WLAN, DynDNS-Aktualisierung&lt;br /&gt;
** Typisch: FritzBox, aber jeder Router mit Portweiterleitung funktioniert&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; (dedizierte Hardware-Firewall)&lt;br /&gt;
** WAN-Interface: &amp;lt;code&amp;gt;192.168.2.2&amp;lt;/code&amp;gt; (im Router-Netz)&lt;br /&gt;
** LAN-Interface / Server-VLAN: &amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Firewall, NAT, DHCP, IDS/IPS&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Managed Switch&#039;&#039;&#039; (optional, für VLAN-Segmentierung)&lt;br /&gt;
** Trennt Server-VLAN vom Rest des Netzes&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver-IP&#039;&#039;&#039;: &amp;lt;code&amp;gt;192.168.10.100&amp;lt;/code&amp;gt; (per DHCP-Reservation oder besser: Per statischer IP-Adresse fest)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 1: Wie funktionieren die Weiterleitungen? Wer macht was? ==&lt;br /&gt;
&lt;br /&gt;
=== Die Kette von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Ein Request von außen (z.B. Browser ruft &amp;lt;code&amp;gt;https://myhomeserver.dyndns.de&amp;lt;/code&amp;gt; auf) durchläuft folgende Stationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Internet&lt;br /&gt;
    ↓ DNS-Auflösung: dyndns.de → öffentliche IP des Heimnetzes&lt;br /&gt;
Router / Gateway (192.168.2.1)&lt;br /&gt;
    ↓ Portweiterleitung: :80 + :443 (und nur! diese!!) → 192.168.2.2&lt;br /&gt;
OPNsense WAN-Interface (192.168.2.2)&lt;br /&gt;
    ↓ Destination NAT: :80/:443 → 192.168.10.100&lt;br /&gt;
Homeserver eno1/eth0 (192.168.10.100)&lt;br /&gt;
    ↓ Docker-Port-Binding: 0.0.0.0:80 + 0.0.0.0:443&lt;br /&gt;
Caddy / Reverse Proxy (Docker-intern)&lt;br /&gt;
    ↓ Reverse Proxy anhand des Host-Headers&lt;br /&gt;
Ziel-Container (z.B. wordpress, nextcloud, ...)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit ist der Server auf der IP-Ebene (Layer 3 des OSI-Modells) von außen hin &amp;quot;unsichtbar&amp;quot;: Die Firewall (OPNsense) lebt, mit dem Gateway, im 192.168.2-er Netz. Von dort routet sie alle Anfragen über die Ports 80 und 443 an das Interface 192.168.10.100. Dahinter, also im 192.168.10-er-Subnetz, residiert der Heimserver.&lt;br /&gt;
&lt;br /&gt;
Am Ende dieses Beitrages gibt es Sicherheitshinweise. Bitte dringend beachten, dass der Router ausschließlich die Ports 80/TCP und 443/TCP nach außen frei gibt. Sollte es nötig sein, den Server von außen zu administrieren, wäre das vermutlich am sichersten über ein VPN mit SSH/Zertifikat zu realisieren.&lt;br /&gt;
&lt;br /&gt;
=== Wer macht was? ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Komponente !! Aufgabe !! Konfigurationsort&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Router / Gateway&#039;&#039;&#039; || DynDNS-Aktualisierung, erste NAT-Stufe, WLAN || Router Web-UI → Portfreigaben&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; || Firewall-Regeln, zweite NAT-Stufe (Destination NAT), DHCP für Server-VLAN || OPNsense Web-UI (Standard: https://&amp;amp;lt;wan-ip&amp;amp;gt;:443 oder :8443)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Caddy / Reverse Proxy&#039;&#039;&#039; || TLS-Terminierung, Let&#039;s Encrypt, Weiterleitung an Container || Caddyfile auf dem Homeserver&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Docker&#039;&#039;&#039; || Container-Isolation, internes Netz (Standard: 172.18.0.0/16) || docker-compose.yml pro Dienst&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fail2ban&#039;&#039;&#039; || Brute-Force-Schutz auf Applikationsebene || Jail-Configs im fail2ban-Container&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Wichtig: OPNsense hat ZWEI Firewall-Engines ===&lt;br /&gt;
&lt;br /&gt;
OPNsense 26.x hat zwei parallele Regelwerke:&lt;br /&gt;
* &#039;&#039;&#039;Rules [new]&#039;&#039;&#039; — neue API-basierte Engine&lt;br /&gt;
* &#039;&#039;&#039;Rules&#039;&#039;&#039; — alte Engine (Legacy)&lt;br /&gt;
&lt;br /&gt;
Neue Regeln &#039;&#039;&#039;immer in beiden&#039;&#039;&#039; anlegen! Bei Problemen immer beide prüfen.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 2: Wo steht was? ==&lt;br /&gt;
&lt;br /&gt;
=== IP-Adressen (Beispiel-Setup) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Gerät !! Interface !! IP !! Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
| Router / Gateway || — || 192.168.2.1 || Gateway, WLAN, DynDNS&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense WAN || wan-interface || 192.168.2.2 || Statisch konfiguriert&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense LAN / Server-VLAN || lan-interface || 192.168.10.1 || Gateway für Server-Netz&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver || eno1 / eth0 || 192.168.10.100 || Fest per DHCP-Reservation (MAC-Adresse)&lt;br /&gt;
|-&lt;br /&gt;
| Client-Geräte || WLAN || 192.168.2.x || Im Router-Netz, nicht im Server-VLAN&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Homeserver: Netzwerk-Interface-Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Der Homeserver bezieht seine IP per DHCP vom OPNsense-DHCP-Server. Bei Debian/Ubuntu mit systemd-networkd:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/systemd/network/10-eth0.network&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Korrekter Inhalt (DHCP):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[Match]&lt;br /&gt;
Name=eno1&lt;br /&gt;
&lt;br /&gt;
[Network]&lt;br /&gt;
DHCP=ipv4&lt;br /&gt;
&lt;br /&gt;
[DHCP]&lt;br /&gt;
RouteMetric=100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ &#039;&#039;&#039;Niemals&#039;&#039;&#039; eine statische IP oder einen Gateway manuell eintragen!&lt;br /&gt;
Der Default-Gateway kommt immer vom DHCP-Server der OPNsense-Firewall (&amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Kea DHCP Lease-Datei (OPNsense) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/db/kea/kea-leases4.csv&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier verwaltet Kea die aktiven Leases. Bei Problemen mit doppelten IPs kann diese Datei (nach &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;) auf den Header reduziert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context,pool_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 3: Systematische Diagnose — Schritt für Schritt ==&lt;br /&gt;
&lt;br /&gt;
=== Grundprinzip: Von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Immer von außen nach innen vorgehen — nie raten, immer messen. Jede Schicht einzeln prüfen.&lt;br /&gt;
&lt;br /&gt;
==== Schritt 1: Ist OPNsense überhaupt erreichbar? ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Vom Client-Rechner:&lt;br /&gt;
ping 192.168.2.2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ OPNsense antwortet standardmäßig &#039;&#039;&#039;nicht&#039;&#039;&#039; auf ICMP/Ping von außen — das ist korrekt!&lt;br /&gt;
&lt;br /&gt;
Stattdessen prüfen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Web-UI erreichbar?&lt;br /&gt;
https://192.168.2.2:8443&lt;br /&gt;
&lt;br /&gt;
# Router zeigt OPNsense als verbundenes Gerät?&lt;br /&gt;
http://192.168.2.1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 2: OPNsense intern prüfen ====&lt;br /&gt;
&lt;br /&gt;
Per SSH oder serieller Konsole auf OPNsense:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# WAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;wan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.2.2, status: active&lt;br /&gt;
&lt;br /&gt;
# LAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;lan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.10.1, status: active&lt;br /&gt;
&lt;br /&gt;
# Router erreichbar?&lt;br /&gt;
ping -c 3 192.168.2.1&lt;br /&gt;
&lt;br /&gt;
# Homeserver erreichbar?&lt;br /&gt;
ping -c 3 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 3: Homeserver direkt prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# SSH auf Homeserver:&lt;br /&gt;
ssh root@192.168.10.100&lt;br /&gt;
&lt;br /&gt;
# Alle Container laufen?&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# Internet vom Homeserver aus erreichbar?&lt;br /&gt;
ping -c 3 9.9.9.9&lt;br /&gt;
&lt;br /&gt;
# Routing-Tabelle korrekt?&lt;br /&gt;
ip route show&lt;br /&gt;
# Erwartete Default-Route: default via 192.168.10.1 dev eno1&lt;br /&gt;
# NICHT: default via 192.168.178.x — das wäre falsch!&lt;br /&gt;
&lt;br /&gt;
# Welche IP hat das Interface?&lt;br /&gt;
ip addr show eno1&lt;br /&gt;
# Erwartete IP: 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 4: Caddy / Reverse Proxy prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Läuft Caddy und antwortet er lokal?&lt;br /&gt;
curl -v http://localhost&lt;br /&gt;
# Erwartete Antwort: HTTP 308 Redirect → https://localhost/&lt;br /&gt;
&lt;br /&gt;
# Caddy-Logs auf Fehler prüfen:&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Typische Fehler in den Caddy-Logs:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fehlermeldung !! Bedeutung !! Lösung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dial tcp ...:443: connect: no route to host&amp;lt;/code&amp;gt; || Caddy kommt nicht ins Internet (Let&#039;s Encrypt nicht erreichbar) || Routing auf Homeserver prüfen (Schritt 3)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;no route to host&amp;lt;/code&amp;gt; bei Ping auf 9.9.9.9 || Falscher Default-Gateway || &amp;lt;code&amp;gt;ip route show&amp;lt;/code&amp;gt; prüfen, falsche Route entfernen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Schritt 5: NAT und Firewall-Regeln prüfen (OPNsense Shell) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# NAT-Regeln anzeigen:&lt;br /&gt;
pfctl -s nat | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Firewall-Regeln anzeigen:&lt;br /&gt;
pfctl -s rules | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf WAN-Interface beobachten (kommt der Request an?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;wan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf LAN-Interface beobachten (wird er weitergeleitet?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;lan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Diagnose-Logik:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tcpdump WAN sieht Traffic, LAN nicht → NAT-Regel prüfen!&lt;br /&gt;
tcpdump WAN sieht keinen Traffic    → Portweiterleitung im Router prüfen!&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 6: Bekannte Fallstricke ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Problem !! Symptom !! Ursache !! Fix&lt;br /&gt;
|-&lt;br /&gt;
| Falsche statische Route || &amp;lt;code&amp;gt;ping 9.9.9.9&amp;lt;/code&amp;gt; schlägt fehl || Netzwerk-Config hat statischen Gateway eingetragen || Auf DHCP umstellen, &amp;lt;code&amp;gt;systemctl restart systemd-networkd&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver hat falsche IP || NAT-Regeln greifen nicht || DHCP hat beim Neustart temporär andere IP vergeben || DHCP-Reservation per MAC-Adresse einrichten&lt;br /&gt;
|-&lt;br /&gt;
| DHCP-Leases durcheinander || Server taucht mit zwei IPs auf || Neustart hat neuen Lease vor Ablauf des alten erzeugt || &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;, Lease-CSV bereinigen, &amp;lt;code&amp;gt;configctl kea start&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense Firewall-Regel fehlt || Dienste von außen nicht erreichbar, intern OK || Regel nur in einer der beiden Engines angelegt || Regel in &#039;&#039;&#039;beiden&#039;&#039;&#039; Engines anlegen (Rules [new] + Rules)&lt;br /&gt;
|-&lt;br /&gt;
| NAT-Regel ohne Subnetz-Maske || Traffic kommt nicht an || &amp;lt;code&amp;gt;192.168.178.0&amp;lt;/code&amp;gt; statt &amp;lt;code&amp;gt;192.168.178.0/24&amp;lt;/code&amp;gt; eingetragen || Subnetz-Maske ergänzen — ohne /24 gilt nur die Netzadresse selbst!&lt;br /&gt;
|-&lt;br /&gt;
| Source/Destination Port vertauscht || Verbindungen werden blockiert || Bei Firewall-Regel Port unter &amp;quot;Source&amp;quot; statt &amp;quot;Destination&amp;quot; eingetragen || Source Port: any / Destination Port: gewünschter Port&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Notfall-Cheatsheet ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# OPNsense: Firewall temporär deaktivieren (Notfall!)&lt;br /&gt;
pfctl -d&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Firewall wieder aktivieren&lt;br /&gt;
pfctl -e&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Kea DHCP stoppen/starten&lt;br /&gt;
configctl kea stop&lt;br /&gt;
configctl kea start&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Falsche Default-Route entfernen&lt;br /&gt;
ip route del default via &amp;amp;lt;falsche-gateway-ip&amp;amp;gt; dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: IP manuell setzen (Sofortlösung bei DHCP-Problemen)&lt;br /&gt;
ip addr add 192.168.10.100/24 dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Netzwerk-Dienst neu starten (Verbindung kurz weg!)&lt;br /&gt;
systemctl restart systemd-networkd&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Docker-Logs prüfen&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Alias-Tabellen prüfen (Blocklisten)&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | wc -l&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | grep &amp;amp;lt;IP&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Sicherheitshinweise ==&lt;br /&gt;
&lt;br /&gt;
* SSH-Ports &#039;&#039;&#039;nicht&#039;&#039;&#039; über das Internet freigeben — nur intern erreichbar lassen&lt;br /&gt;
* Portweiterleitung im Router auf das &#039;&#039;&#039;Minimum&#039;&#039;&#039; beschränken (nur 80 + 443)&lt;br /&gt;
* Für interne Admin-Interfaces (OPNsense Web-UI, Monitoring) &#039;&#039;&#039;keine externen Freigaben&#039;&#039;&#039;&lt;br /&gt;
* DHCP-Reservations per MAC-Adresse verhindern IP-Wechsel nach Neustarts&lt;br /&gt;
* Bei Firewall-Regeln: Block-Regeln &#039;&#039;&#039;immer&#039;&#039;&#039; vor Pass-Regeln platzieren&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Dieser Artikel basiert auf praktischen Erfahrungen aus dem Betrieb eines selbst gehosteten Servers mit OPNsense, Cisco-Switch und Docker-Stack.&#039;&#039;&lt;br /&gt;
&#039;&#039;Erstellt: Mai 2026&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=243</id>
		<title>Homeserver-Sicherheitsarchitektur</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=243"/>
		<updated>2026-05-27T22:50:18Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Die Kette von außen nach innen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Homeserver-Sicherheitsarchitektur: Aufbau, Funktionsweise und Diagnose ==&lt;br /&gt;
&lt;br /&gt;
Einen eigenen Server an&#039;s Internet zu bekommen, ist nicht allzu schwierig. Ein Dienst, der die eigene, vom Internet-Provider zugewiesene IP-Adresse in einen festen Domain-Namen umwandelt (siehe: [https://de.wikipedia.org/wiki/Dynamisches_DNS Dynamisches DNS]), wird im privaten Bereich die Voraussetzung sein.&lt;br /&gt;
Es gibt verschiedene Anbieter, oft auch kostenlose.&lt;br /&gt;
&lt;br /&gt;
=== Ein Leitfaden für selbst gehostete Server mit OPNsense, Managed Switch und Docker ===&lt;br /&gt;
&lt;br /&gt;
Die Kehrseite: Sowie der Server über&#039;s Internet erreichbar ist, ist er angreifbar. Das ist kein theoretisches Szenario. Meiner Erfahrung nach ist es eine Frage von Stunden, bis die ersten Bots &amp;quot;anklopfen&amp;quot;, nach laufenden Diensten suchen, nach offenen Ports, nach Schwachstellen.&lt;br /&gt;
&lt;br /&gt;
Aufgrund einer mangelhaften Konfiguration (offener Samba-Port) hatte ich die sehr reale Erfahrung einer russischen Hackerbande, die einige Hundert Textdateien mit Zahlungsaufforderungen und einen Verschlüsselungstrojaner auf meinem Rechner hinterlassen hatte. Gerettet hatten mich damals die Dateirechte von Linux. Das fehlende E(x)ecutional-Flag und die eingeschränkten Benutzerrechte hatten den Trojaner ausgebremst.&lt;br /&gt;
&lt;br /&gt;
Trotzdem: Nie wieder!&lt;br /&gt;
Ein wenig von dem, was ich gelernt habe, gebe ich ich hier weiter.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Einleitung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt den Aufbau einer &#039;&#039;&#039;sicheren&#039;&#039;&#039; Netzwerkarchitektur für einen Homeserver, der über das öffentliche Internet erreichbar ist. Der Beitrag richtet sich an alle, die ihre Daten selbst kontrollieren wollen — und dabei nicht unfreiwillig Teil einer globalen Angriffs-Infrastruktur werden möchten. Er will zum Verständnis beitragen, wie die einzelnen Komponenten zusammenspielen — und wie man systematisch vorgeht, wenn etwas nicht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der Fokus liegt nicht auf einer spezifischen Hardware-Konfiguration, sondern auf dem allgemeinen Prinzip: Wie kommt ein Request von außen sicher zu einem Docker-Container?&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Annahmen / Szenario ==&lt;br /&gt;
&lt;br /&gt;
Folgende Komponenten werden in diesem Artikel vorausgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver&#039;&#039;&#039; (Raspberry Pi, Intel NUC, oder beliebiger Linux-Server)&lt;br /&gt;
** Betriebssystem: Debian/Ubuntu oder vergleichbar&lt;br /&gt;
** Docker mit mehreren Diensten (z.B. WordPress, Nextcloud, MediaWiki)&lt;br /&gt;
** Caddy als Reverse Proxy (alternativ funktionieren [https://nginx.org/ nginx], [https://httpd.apache.org/ Apache], oder (ggf. kostenpflichtige) proprietäre Lösungen. Caddy allerdings hat das für mich charmante Feature, sich eigenständig um die TSL-Zertifikate und ihre Verlängerung bei LetsEncrypt zu kümmern. Wer aufgrund &amp;quot;zu vieler&amp;quot; Fehlversuche bei der Zertifikats-Einrichtung von LetsEncrypt auf Tage gesperrt wurde, wird mein Faible über diesen Automatismus nachvollziehen oder teilen können.)&lt;br /&gt;
** fail2ban als Brute-Force-Schutz&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;DynDNS-Dienst&#039;&#039;&#039; der dem Homeserver eine feste Domain zuweist&lt;br /&gt;
** Beispiel: &amp;lt;code&amp;gt;myhomeserver.dyndns.de&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Router / Heimnetz-Gateway&#039;&#039;&#039;&lt;br /&gt;
** Beispiel-IP: &amp;lt;code&amp;gt;192.168.2.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Portweiterleitung, WLAN, DynDNS-Aktualisierung&lt;br /&gt;
** Typisch: FritzBox, aber jeder Router mit Portweiterleitung funktioniert&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; (dedizierte Hardware-Firewall)&lt;br /&gt;
** WAN-Interface: &amp;lt;code&amp;gt;192.168.2.2&amp;lt;/code&amp;gt; (im Router-Netz)&lt;br /&gt;
** LAN-Interface / Server-VLAN: &amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Firewall, NAT, DHCP, IDS/IPS&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Managed Switch&#039;&#039;&#039; (optional, für VLAN-Segmentierung)&lt;br /&gt;
** Trennt Server-VLAN vom Rest des Netzes&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver-IP&#039;&#039;&#039;: &amp;lt;code&amp;gt;192.168.10.100&amp;lt;/code&amp;gt; (per DHCP-Reservation oder besser: Per statischer IP-Adresse fest)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 1: Wie funktionieren die Weiterleitungen? Wer macht was? ==&lt;br /&gt;
&lt;br /&gt;
=== Die Kette von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Ein Request von außen (z.B. Browser ruft &amp;lt;code&amp;gt;https://myhomeserver.dyndns.de&amp;lt;/code&amp;gt; auf) durchläuft folgende Stationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Internet&lt;br /&gt;
    ↓ DNS-Auflösung: dyndns.de → öffentliche IP des Heimnetzes&lt;br /&gt;
Router / Gateway (192.168.2.1)&lt;br /&gt;
    ↓ Portweiterleitung: :80 + :443 (und nur! diese!!) → 192.168.2.2&lt;br /&gt;
OPNsense WAN-Interface (192.168.2.2)&lt;br /&gt;
    ↓ Destination NAT: :80/:443 → 192.168.10.100&lt;br /&gt;
Homeserver eno1/eth0 (192.168.10.100)&lt;br /&gt;
    ↓ Docker-Port-Binding: 0.0.0.0:80 + 0.0.0.0:443&lt;br /&gt;
Caddy / Reverse Proxy (Docker-intern)&lt;br /&gt;
    ↓ Reverse Proxy anhand des Host-Headers&lt;br /&gt;
Ziel-Container (z.B. wordpress, nextcloud, ...)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit ist der Server auf der IP-Ebene (Layer 3 des OSI-Modells) von außen hin &amp;quot;unsichtbar&amp;quot;: Die Firewall (OPNsense) lebt, mit dem Gateway, im 192.168.2-er Netz. Von dort routet sie alle Anfragen über die Ports 80 und 443 an das Interface 192.168.10.100. Dahinter, also im 192.168.10-er-Subnetz, residiert der Heimserver.&lt;br /&gt;
&lt;br /&gt;
=== Wer macht was? ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Komponente !! Aufgabe !! Konfigurationsort&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Router / Gateway&#039;&#039;&#039; || DynDNS-Aktualisierung, erste NAT-Stufe, WLAN || Router Web-UI → Portfreigaben&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; || Firewall-Regeln, zweite NAT-Stufe (Destination NAT), DHCP für Server-VLAN || OPNsense Web-UI (Standard: https://&amp;amp;lt;wan-ip&amp;amp;gt;:443 oder :8443)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Caddy / Reverse Proxy&#039;&#039;&#039; || TLS-Terminierung, Let&#039;s Encrypt, Weiterleitung an Container || Caddyfile auf dem Homeserver&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Docker&#039;&#039;&#039; || Container-Isolation, internes Netz (Standard: 172.18.0.0/16) || docker-compose.yml pro Dienst&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fail2ban&#039;&#039;&#039; || Brute-Force-Schutz auf Applikationsebene || Jail-Configs im fail2ban-Container&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Wichtig: OPNsense hat ZWEI Firewall-Engines ===&lt;br /&gt;
&lt;br /&gt;
OPNsense 26.x hat zwei parallele Regelwerke:&lt;br /&gt;
* &#039;&#039;&#039;Rules [new]&#039;&#039;&#039; — neue API-basierte Engine&lt;br /&gt;
* &#039;&#039;&#039;Rules&#039;&#039;&#039; — alte Engine (Legacy)&lt;br /&gt;
&lt;br /&gt;
Neue Regeln &#039;&#039;&#039;immer in beiden&#039;&#039;&#039; anlegen! Bei Problemen immer beide prüfen.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 2: Wo steht was? ==&lt;br /&gt;
&lt;br /&gt;
=== IP-Adressen (Beispiel-Setup) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Gerät !! Interface !! IP !! Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
| Router / Gateway || — || 192.168.2.1 || Gateway, WLAN, DynDNS&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense WAN || wan-interface || 192.168.2.2 || Statisch konfiguriert&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense LAN / Server-VLAN || lan-interface || 192.168.10.1 || Gateway für Server-Netz&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver || eno1 / eth0 || 192.168.10.100 || Fest per DHCP-Reservation (MAC-Adresse)&lt;br /&gt;
|-&lt;br /&gt;
| Client-Geräte || WLAN || 192.168.2.x || Im Router-Netz, nicht im Server-VLAN&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Homeserver: Netzwerk-Interface-Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Der Homeserver bezieht seine IP per DHCP vom OPNsense-DHCP-Server. Bei Debian/Ubuntu mit systemd-networkd:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/systemd/network/10-eth0.network&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Korrekter Inhalt (DHCP):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[Match]&lt;br /&gt;
Name=eno1&lt;br /&gt;
&lt;br /&gt;
[Network]&lt;br /&gt;
DHCP=ipv4&lt;br /&gt;
&lt;br /&gt;
[DHCP]&lt;br /&gt;
RouteMetric=100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ &#039;&#039;&#039;Niemals&#039;&#039;&#039; eine statische IP oder einen Gateway manuell eintragen!&lt;br /&gt;
Der Default-Gateway kommt immer vom DHCP-Server der OPNsense-Firewall (&amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Kea DHCP Lease-Datei (OPNsense) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/db/kea/kea-leases4.csv&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier verwaltet Kea die aktiven Leases. Bei Problemen mit doppelten IPs kann diese Datei (nach &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;) auf den Header reduziert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context,pool_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 3: Systematische Diagnose — Schritt für Schritt ==&lt;br /&gt;
&lt;br /&gt;
=== Grundprinzip: Von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Immer von außen nach innen vorgehen — nie raten, immer messen. Jede Schicht einzeln prüfen.&lt;br /&gt;
&lt;br /&gt;
==== Schritt 1: Ist OPNsense überhaupt erreichbar? ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Vom Client-Rechner:&lt;br /&gt;
ping 192.168.2.2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ OPNsense antwortet standardmäßig &#039;&#039;&#039;nicht&#039;&#039;&#039; auf ICMP/Ping von außen — das ist korrekt!&lt;br /&gt;
&lt;br /&gt;
Stattdessen prüfen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Web-UI erreichbar?&lt;br /&gt;
https://192.168.2.2:8443&lt;br /&gt;
&lt;br /&gt;
# Router zeigt OPNsense als verbundenes Gerät?&lt;br /&gt;
http://192.168.2.1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 2: OPNsense intern prüfen ====&lt;br /&gt;
&lt;br /&gt;
Per SSH oder serieller Konsole auf OPNsense:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# WAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;wan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.2.2, status: active&lt;br /&gt;
&lt;br /&gt;
# LAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;lan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.10.1, status: active&lt;br /&gt;
&lt;br /&gt;
# Router erreichbar?&lt;br /&gt;
ping -c 3 192.168.2.1&lt;br /&gt;
&lt;br /&gt;
# Homeserver erreichbar?&lt;br /&gt;
ping -c 3 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 3: Homeserver direkt prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# SSH auf Homeserver:&lt;br /&gt;
ssh root@192.168.10.100&lt;br /&gt;
&lt;br /&gt;
# Alle Container laufen?&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# Internet vom Homeserver aus erreichbar?&lt;br /&gt;
ping -c 3 9.9.9.9&lt;br /&gt;
&lt;br /&gt;
# Routing-Tabelle korrekt?&lt;br /&gt;
ip route show&lt;br /&gt;
# Erwartete Default-Route: default via 192.168.10.1 dev eno1&lt;br /&gt;
# NICHT: default via 192.168.178.x — das wäre falsch!&lt;br /&gt;
&lt;br /&gt;
# Welche IP hat das Interface?&lt;br /&gt;
ip addr show eno1&lt;br /&gt;
# Erwartete IP: 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 4: Caddy / Reverse Proxy prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Läuft Caddy und antwortet er lokal?&lt;br /&gt;
curl -v http://localhost&lt;br /&gt;
# Erwartete Antwort: HTTP 308 Redirect → https://localhost/&lt;br /&gt;
&lt;br /&gt;
# Caddy-Logs auf Fehler prüfen:&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Typische Fehler in den Caddy-Logs:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fehlermeldung !! Bedeutung !! Lösung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dial tcp ...:443: connect: no route to host&amp;lt;/code&amp;gt; || Caddy kommt nicht ins Internet (Let&#039;s Encrypt nicht erreichbar) || Routing auf Homeserver prüfen (Schritt 3)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;no route to host&amp;lt;/code&amp;gt; bei Ping auf 9.9.9.9 || Falscher Default-Gateway || &amp;lt;code&amp;gt;ip route show&amp;lt;/code&amp;gt; prüfen, falsche Route entfernen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Schritt 5: NAT und Firewall-Regeln prüfen (OPNsense Shell) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# NAT-Regeln anzeigen:&lt;br /&gt;
pfctl -s nat | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Firewall-Regeln anzeigen:&lt;br /&gt;
pfctl -s rules | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf WAN-Interface beobachten (kommt der Request an?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;wan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf LAN-Interface beobachten (wird er weitergeleitet?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;lan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Diagnose-Logik:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tcpdump WAN sieht Traffic, LAN nicht → NAT-Regel prüfen!&lt;br /&gt;
tcpdump WAN sieht keinen Traffic    → Portweiterleitung im Router prüfen!&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 6: Bekannte Fallstricke ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Problem !! Symptom !! Ursache !! Fix&lt;br /&gt;
|-&lt;br /&gt;
| Falsche statische Route || &amp;lt;code&amp;gt;ping 9.9.9.9&amp;lt;/code&amp;gt; schlägt fehl || Netzwerk-Config hat statischen Gateway eingetragen || Auf DHCP umstellen, &amp;lt;code&amp;gt;systemctl restart systemd-networkd&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver hat falsche IP || NAT-Regeln greifen nicht || DHCP hat beim Neustart temporär andere IP vergeben || DHCP-Reservation per MAC-Adresse einrichten&lt;br /&gt;
|-&lt;br /&gt;
| DHCP-Leases durcheinander || Server taucht mit zwei IPs auf || Neustart hat neuen Lease vor Ablauf des alten erzeugt || &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;, Lease-CSV bereinigen, &amp;lt;code&amp;gt;configctl kea start&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense Firewall-Regel fehlt || Dienste von außen nicht erreichbar, intern OK || Regel nur in einer der beiden Engines angelegt || Regel in &#039;&#039;&#039;beiden&#039;&#039;&#039; Engines anlegen (Rules [new] + Rules)&lt;br /&gt;
|-&lt;br /&gt;
| NAT-Regel ohne Subnetz-Maske || Traffic kommt nicht an || &amp;lt;code&amp;gt;192.168.178.0&amp;lt;/code&amp;gt; statt &amp;lt;code&amp;gt;192.168.178.0/24&amp;lt;/code&amp;gt; eingetragen || Subnetz-Maske ergänzen — ohne /24 gilt nur die Netzadresse selbst!&lt;br /&gt;
|-&lt;br /&gt;
| Source/Destination Port vertauscht || Verbindungen werden blockiert || Bei Firewall-Regel Port unter &amp;quot;Source&amp;quot; statt &amp;quot;Destination&amp;quot; eingetragen || Source Port: any / Destination Port: gewünschter Port&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Notfall-Cheatsheet ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# OPNsense: Firewall temporär deaktivieren (Notfall!)&lt;br /&gt;
pfctl -d&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Firewall wieder aktivieren&lt;br /&gt;
pfctl -e&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Kea DHCP stoppen/starten&lt;br /&gt;
configctl kea stop&lt;br /&gt;
configctl kea start&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Falsche Default-Route entfernen&lt;br /&gt;
ip route del default via &amp;amp;lt;falsche-gateway-ip&amp;amp;gt; dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: IP manuell setzen (Sofortlösung bei DHCP-Problemen)&lt;br /&gt;
ip addr add 192.168.10.100/24 dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Netzwerk-Dienst neu starten (Verbindung kurz weg!)&lt;br /&gt;
systemctl restart systemd-networkd&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Docker-Logs prüfen&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Alias-Tabellen prüfen (Blocklisten)&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | wc -l&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | grep &amp;amp;lt;IP&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Sicherheitshinweise ==&lt;br /&gt;
&lt;br /&gt;
* SSH-Ports &#039;&#039;&#039;nicht&#039;&#039;&#039; über das Internet freigeben — nur intern erreichbar lassen&lt;br /&gt;
* Portweiterleitung im Router auf das &#039;&#039;&#039;Minimum&#039;&#039;&#039; beschränken (nur 80 + 443)&lt;br /&gt;
* Für interne Admin-Interfaces (OPNsense Web-UI, Monitoring) &#039;&#039;&#039;keine externen Freigaben&#039;&#039;&#039;&lt;br /&gt;
* DHCP-Reservations per MAC-Adresse verhindern IP-Wechsel nach Neustarts&lt;br /&gt;
* Bei Firewall-Regeln: Block-Regeln &#039;&#039;&#039;immer&#039;&#039;&#039; vor Pass-Regeln platzieren&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Dieser Artikel basiert auf praktischen Erfahrungen aus dem Betrieb eines selbst gehosteten Servers mit OPNsense, Cisco-Switch und Docker-Stack.&#039;&#039;&lt;br /&gt;
&#039;&#039;Erstellt: Mai 2026&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=242</id>
		<title>Homeserver-Sicherheitsarchitektur</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=242"/>
		<updated>2026-05-27T22:43:38Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Annahmen / Szenario */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Homeserver-Sicherheitsarchitektur: Aufbau, Funktionsweise und Diagnose ==&lt;br /&gt;
&lt;br /&gt;
Einen eigenen Server an&#039;s Internet zu bekommen, ist nicht allzu schwierig. Ein Dienst, der die eigene, vom Internet-Provider zugewiesene IP-Adresse in einen festen Domain-Namen umwandelt (siehe: [https://de.wikipedia.org/wiki/Dynamisches_DNS Dynamisches DNS]), wird im privaten Bereich die Voraussetzung sein.&lt;br /&gt;
Es gibt verschiedene Anbieter, oft auch kostenlose.&lt;br /&gt;
&lt;br /&gt;
=== Ein Leitfaden für selbst gehostete Server mit OPNsense, Managed Switch und Docker ===&lt;br /&gt;
&lt;br /&gt;
Die Kehrseite: Sowie der Server über&#039;s Internet erreichbar ist, ist er angreifbar. Das ist kein theoretisches Szenario. Meiner Erfahrung nach ist es eine Frage von Stunden, bis die ersten Bots &amp;quot;anklopfen&amp;quot;, nach laufenden Diensten suchen, nach offenen Ports, nach Schwachstellen.&lt;br /&gt;
&lt;br /&gt;
Aufgrund einer mangelhaften Konfiguration (offener Samba-Port) hatte ich die sehr reale Erfahrung einer russischen Hackerbande, die einige Hundert Textdateien mit Zahlungsaufforderungen und einen Verschlüsselungstrojaner auf meinem Rechner hinterlassen hatte. Gerettet hatten mich damals die Dateirechte von Linux. Das fehlende E(x)ecutional-Flag und die eingeschränkten Benutzerrechte hatten den Trojaner ausgebremst.&lt;br /&gt;
&lt;br /&gt;
Trotzdem: Nie wieder!&lt;br /&gt;
Ein wenig von dem, was ich gelernt habe, gebe ich ich hier weiter.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Einleitung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt den Aufbau einer &#039;&#039;&#039;sicheren&#039;&#039;&#039; Netzwerkarchitektur für einen Homeserver, der über das öffentliche Internet erreichbar ist. Der Beitrag richtet sich an alle, die ihre Daten selbst kontrollieren wollen — und dabei nicht unfreiwillig Teil einer globalen Angriffs-Infrastruktur werden möchten. Er will zum Verständnis beitragen, wie die einzelnen Komponenten zusammenspielen — und wie man systematisch vorgeht, wenn etwas nicht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der Fokus liegt nicht auf einer spezifischen Hardware-Konfiguration, sondern auf dem allgemeinen Prinzip: Wie kommt ein Request von außen sicher zu einem Docker-Container?&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Annahmen / Szenario ==&lt;br /&gt;
&lt;br /&gt;
Folgende Komponenten werden in diesem Artikel vorausgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver&#039;&#039;&#039; (Raspberry Pi, Intel NUC, oder beliebiger Linux-Server)&lt;br /&gt;
** Betriebssystem: Debian/Ubuntu oder vergleichbar&lt;br /&gt;
** Docker mit mehreren Diensten (z.B. WordPress, Nextcloud, MediaWiki)&lt;br /&gt;
** Caddy als Reverse Proxy (alternativ funktionieren [https://nginx.org/ nginx], [https://httpd.apache.org/ Apache], oder (ggf. kostenpflichtige) proprietäre Lösungen. Caddy allerdings hat das für mich charmante Feature, sich eigenständig um die TSL-Zertifikate und ihre Verlängerung bei LetsEncrypt zu kümmern. Wer aufgrund &amp;quot;zu vieler&amp;quot; Fehlversuche bei der Zertifikats-Einrichtung von LetsEncrypt auf Tage gesperrt wurde, wird mein Faible über diesen Automatismus nachvollziehen oder teilen können.)&lt;br /&gt;
** fail2ban als Brute-Force-Schutz&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;DynDNS-Dienst&#039;&#039;&#039; der dem Homeserver eine feste Domain zuweist&lt;br /&gt;
** Beispiel: &amp;lt;code&amp;gt;myhomeserver.dyndns.de&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Router / Heimnetz-Gateway&#039;&#039;&#039;&lt;br /&gt;
** Beispiel-IP: &amp;lt;code&amp;gt;192.168.2.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Portweiterleitung, WLAN, DynDNS-Aktualisierung&lt;br /&gt;
** Typisch: FritzBox, aber jeder Router mit Portweiterleitung funktioniert&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; (dedizierte Hardware-Firewall)&lt;br /&gt;
** WAN-Interface: &amp;lt;code&amp;gt;192.168.2.2&amp;lt;/code&amp;gt; (im Router-Netz)&lt;br /&gt;
** LAN-Interface / Server-VLAN: &amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Firewall, NAT, DHCP, IDS/IPS&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Managed Switch&#039;&#039;&#039; (optional, für VLAN-Segmentierung)&lt;br /&gt;
** Trennt Server-VLAN vom Rest des Netzes&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver-IP&#039;&#039;&#039;: &amp;lt;code&amp;gt;192.168.10.100&amp;lt;/code&amp;gt; (per DHCP-Reservation oder besser: Per statischer IP-Adresse fest)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 1: Wie funktionieren die Weiterleitungen? Wer macht was? ==&lt;br /&gt;
&lt;br /&gt;
=== Die Kette von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Ein Request von außen (z.B. Browser ruft &amp;lt;code&amp;gt;https://myhomeserver.dyndns.de&amp;lt;/code&amp;gt; auf) durchläuft folgende Stationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Internet&lt;br /&gt;
    ↓ DNS-Auflösung: dyndns.de → öffentliche IP des Heimnetzes&lt;br /&gt;
Router / Gateway (192.168.2.1)&lt;br /&gt;
    ↓ Portweiterleitung: :80 + :443 → 192.168.2.2&lt;br /&gt;
OPNsense WAN-Interface (192.168.2.2)&lt;br /&gt;
    ↓ Destination NAT: :80/:443 → 192.168.10.100&lt;br /&gt;
Homeserver eno1/eth0 (192.168.10.100)&lt;br /&gt;
    ↓ Docker-Port-Binding: 0.0.0.0:80 + 0.0.0.0:443&lt;br /&gt;
Caddy / Reverse Proxy (Docker-intern)&lt;br /&gt;
    ↓ Reverse Proxy anhand des Host-Headers&lt;br /&gt;
Ziel-Container (z.B. wordpress, nextcloud, ...)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Wer macht was? ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Komponente !! Aufgabe !! Konfigurationsort&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Router / Gateway&#039;&#039;&#039; || DynDNS-Aktualisierung, erste NAT-Stufe, WLAN || Router Web-UI → Portfreigaben&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; || Firewall-Regeln, zweite NAT-Stufe (Destination NAT), DHCP für Server-VLAN || OPNsense Web-UI (Standard: https://&amp;amp;lt;wan-ip&amp;amp;gt;:443 oder :8443)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Caddy / Reverse Proxy&#039;&#039;&#039; || TLS-Terminierung, Let&#039;s Encrypt, Weiterleitung an Container || Caddyfile auf dem Homeserver&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Docker&#039;&#039;&#039; || Container-Isolation, internes Netz (Standard: 172.18.0.0/16) || docker-compose.yml pro Dienst&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fail2ban&#039;&#039;&#039; || Brute-Force-Schutz auf Applikationsebene || Jail-Configs im fail2ban-Container&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Wichtig: OPNsense hat ZWEI Firewall-Engines ===&lt;br /&gt;
&lt;br /&gt;
OPNsense 26.x hat zwei parallele Regelwerke:&lt;br /&gt;
* &#039;&#039;&#039;Rules [new]&#039;&#039;&#039; — neue API-basierte Engine&lt;br /&gt;
* &#039;&#039;&#039;Rules&#039;&#039;&#039; — alte Engine (Legacy)&lt;br /&gt;
&lt;br /&gt;
Neue Regeln &#039;&#039;&#039;immer in beiden&#039;&#039;&#039; anlegen! Bei Problemen immer beide prüfen.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 2: Wo steht was? ==&lt;br /&gt;
&lt;br /&gt;
=== IP-Adressen (Beispiel-Setup) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Gerät !! Interface !! IP !! Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
| Router / Gateway || — || 192.168.2.1 || Gateway, WLAN, DynDNS&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense WAN || wan-interface || 192.168.2.2 || Statisch konfiguriert&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense LAN / Server-VLAN || lan-interface || 192.168.10.1 || Gateway für Server-Netz&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver || eno1 / eth0 || 192.168.10.100 || Fest per DHCP-Reservation (MAC-Adresse)&lt;br /&gt;
|-&lt;br /&gt;
| Client-Geräte || WLAN || 192.168.2.x || Im Router-Netz, nicht im Server-VLAN&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Homeserver: Netzwerk-Interface-Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Der Homeserver bezieht seine IP per DHCP vom OPNsense-DHCP-Server. Bei Debian/Ubuntu mit systemd-networkd:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/systemd/network/10-eth0.network&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Korrekter Inhalt (DHCP):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[Match]&lt;br /&gt;
Name=eno1&lt;br /&gt;
&lt;br /&gt;
[Network]&lt;br /&gt;
DHCP=ipv4&lt;br /&gt;
&lt;br /&gt;
[DHCP]&lt;br /&gt;
RouteMetric=100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ &#039;&#039;&#039;Niemals&#039;&#039;&#039; eine statische IP oder einen Gateway manuell eintragen!&lt;br /&gt;
Der Default-Gateway kommt immer vom DHCP-Server der OPNsense-Firewall (&amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Kea DHCP Lease-Datei (OPNsense) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/db/kea/kea-leases4.csv&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier verwaltet Kea die aktiven Leases. Bei Problemen mit doppelten IPs kann diese Datei (nach &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;) auf den Header reduziert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context,pool_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 3: Systematische Diagnose — Schritt für Schritt ==&lt;br /&gt;
&lt;br /&gt;
=== Grundprinzip: Von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Immer von außen nach innen vorgehen — nie raten, immer messen. Jede Schicht einzeln prüfen.&lt;br /&gt;
&lt;br /&gt;
==== Schritt 1: Ist OPNsense überhaupt erreichbar? ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Vom Client-Rechner:&lt;br /&gt;
ping 192.168.2.2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ OPNsense antwortet standardmäßig &#039;&#039;&#039;nicht&#039;&#039;&#039; auf ICMP/Ping von außen — das ist korrekt!&lt;br /&gt;
&lt;br /&gt;
Stattdessen prüfen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Web-UI erreichbar?&lt;br /&gt;
https://192.168.2.2:8443&lt;br /&gt;
&lt;br /&gt;
# Router zeigt OPNsense als verbundenes Gerät?&lt;br /&gt;
http://192.168.2.1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 2: OPNsense intern prüfen ====&lt;br /&gt;
&lt;br /&gt;
Per SSH oder serieller Konsole auf OPNsense:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# WAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;wan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.2.2, status: active&lt;br /&gt;
&lt;br /&gt;
# LAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;lan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.10.1, status: active&lt;br /&gt;
&lt;br /&gt;
# Router erreichbar?&lt;br /&gt;
ping -c 3 192.168.2.1&lt;br /&gt;
&lt;br /&gt;
# Homeserver erreichbar?&lt;br /&gt;
ping -c 3 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 3: Homeserver direkt prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# SSH auf Homeserver:&lt;br /&gt;
ssh root@192.168.10.100&lt;br /&gt;
&lt;br /&gt;
# Alle Container laufen?&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# Internet vom Homeserver aus erreichbar?&lt;br /&gt;
ping -c 3 9.9.9.9&lt;br /&gt;
&lt;br /&gt;
# Routing-Tabelle korrekt?&lt;br /&gt;
ip route show&lt;br /&gt;
# Erwartete Default-Route: default via 192.168.10.1 dev eno1&lt;br /&gt;
# NICHT: default via 192.168.178.x — das wäre falsch!&lt;br /&gt;
&lt;br /&gt;
# Welche IP hat das Interface?&lt;br /&gt;
ip addr show eno1&lt;br /&gt;
# Erwartete IP: 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 4: Caddy / Reverse Proxy prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Läuft Caddy und antwortet er lokal?&lt;br /&gt;
curl -v http://localhost&lt;br /&gt;
# Erwartete Antwort: HTTP 308 Redirect → https://localhost/&lt;br /&gt;
&lt;br /&gt;
# Caddy-Logs auf Fehler prüfen:&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Typische Fehler in den Caddy-Logs:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fehlermeldung !! Bedeutung !! Lösung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dial tcp ...:443: connect: no route to host&amp;lt;/code&amp;gt; || Caddy kommt nicht ins Internet (Let&#039;s Encrypt nicht erreichbar) || Routing auf Homeserver prüfen (Schritt 3)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;no route to host&amp;lt;/code&amp;gt; bei Ping auf 9.9.9.9 || Falscher Default-Gateway || &amp;lt;code&amp;gt;ip route show&amp;lt;/code&amp;gt; prüfen, falsche Route entfernen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Schritt 5: NAT und Firewall-Regeln prüfen (OPNsense Shell) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# NAT-Regeln anzeigen:&lt;br /&gt;
pfctl -s nat | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Firewall-Regeln anzeigen:&lt;br /&gt;
pfctl -s rules | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf WAN-Interface beobachten (kommt der Request an?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;wan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf LAN-Interface beobachten (wird er weitergeleitet?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;lan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Diagnose-Logik:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tcpdump WAN sieht Traffic, LAN nicht → NAT-Regel prüfen!&lt;br /&gt;
tcpdump WAN sieht keinen Traffic    → Portweiterleitung im Router prüfen!&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 6: Bekannte Fallstricke ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Problem !! Symptom !! Ursache !! Fix&lt;br /&gt;
|-&lt;br /&gt;
| Falsche statische Route || &amp;lt;code&amp;gt;ping 9.9.9.9&amp;lt;/code&amp;gt; schlägt fehl || Netzwerk-Config hat statischen Gateway eingetragen || Auf DHCP umstellen, &amp;lt;code&amp;gt;systemctl restart systemd-networkd&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver hat falsche IP || NAT-Regeln greifen nicht || DHCP hat beim Neustart temporär andere IP vergeben || DHCP-Reservation per MAC-Adresse einrichten&lt;br /&gt;
|-&lt;br /&gt;
| DHCP-Leases durcheinander || Server taucht mit zwei IPs auf || Neustart hat neuen Lease vor Ablauf des alten erzeugt || &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;, Lease-CSV bereinigen, &amp;lt;code&amp;gt;configctl kea start&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense Firewall-Regel fehlt || Dienste von außen nicht erreichbar, intern OK || Regel nur in einer der beiden Engines angelegt || Regel in &#039;&#039;&#039;beiden&#039;&#039;&#039; Engines anlegen (Rules [new] + Rules)&lt;br /&gt;
|-&lt;br /&gt;
| NAT-Regel ohne Subnetz-Maske || Traffic kommt nicht an || &amp;lt;code&amp;gt;192.168.178.0&amp;lt;/code&amp;gt; statt &amp;lt;code&amp;gt;192.168.178.0/24&amp;lt;/code&amp;gt; eingetragen || Subnetz-Maske ergänzen — ohne /24 gilt nur die Netzadresse selbst!&lt;br /&gt;
|-&lt;br /&gt;
| Source/Destination Port vertauscht || Verbindungen werden blockiert || Bei Firewall-Regel Port unter &amp;quot;Source&amp;quot; statt &amp;quot;Destination&amp;quot; eingetragen || Source Port: any / Destination Port: gewünschter Port&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Notfall-Cheatsheet ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# OPNsense: Firewall temporär deaktivieren (Notfall!)&lt;br /&gt;
pfctl -d&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Firewall wieder aktivieren&lt;br /&gt;
pfctl -e&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Kea DHCP stoppen/starten&lt;br /&gt;
configctl kea stop&lt;br /&gt;
configctl kea start&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Falsche Default-Route entfernen&lt;br /&gt;
ip route del default via &amp;amp;lt;falsche-gateway-ip&amp;amp;gt; dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: IP manuell setzen (Sofortlösung bei DHCP-Problemen)&lt;br /&gt;
ip addr add 192.168.10.100/24 dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Netzwerk-Dienst neu starten (Verbindung kurz weg!)&lt;br /&gt;
systemctl restart systemd-networkd&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Docker-Logs prüfen&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Alias-Tabellen prüfen (Blocklisten)&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | wc -l&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | grep &amp;amp;lt;IP&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Sicherheitshinweise ==&lt;br /&gt;
&lt;br /&gt;
* SSH-Ports &#039;&#039;&#039;nicht&#039;&#039;&#039; über das Internet freigeben — nur intern erreichbar lassen&lt;br /&gt;
* Portweiterleitung im Router auf das &#039;&#039;&#039;Minimum&#039;&#039;&#039; beschränken (nur 80 + 443)&lt;br /&gt;
* Für interne Admin-Interfaces (OPNsense Web-UI, Monitoring) &#039;&#039;&#039;keine externen Freigaben&#039;&#039;&#039;&lt;br /&gt;
* DHCP-Reservations per MAC-Adresse verhindern IP-Wechsel nach Neustarts&lt;br /&gt;
* Bei Firewall-Regeln: Block-Regeln &#039;&#039;&#039;immer&#039;&#039;&#039; vor Pass-Regeln platzieren&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Dieser Artikel basiert auf praktischen Erfahrungen aus dem Betrieb eines selbst gehosteten Servers mit OPNsense, Cisco-Switch und Docker-Stack.&#039;&#039;&lt;br /&gt;
&#039;&#039;Erstellt: Mai 2026&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=241</id>
		<title>Homeserver-Sicherheitsarchitektur</title>
		<link rel="alternate" type="text/html" href="https://wiki.tuxi.ddnss.de/index.php?title=Homeserver-Sicherheitsarchitektur&amp;diff=241"/>
		<updated>2026-05-27T22:39:21Z</updated>

		<summary type="html">&lt;p&gt;Admin: Die Seite wurde neu angelegt: „== Homeserver-Sicherheitsarchitektur: Aufbau, Funktionsweise und Diagnose ==  Einen eigenen Server an&amp;#039;s Internet zu bekommen, ist nicht allzu schwierig. Ein Dienst, der die eigene, vom Internet-Provider zugewiesene IP-Adresse in einen festen Domain-Namen umwandelt (siehe: [https://de.wikipedia.org/wiki/Dynamisches_DNS Dynamisches DNS]), wird im privaten Bereich die Voraussetzung sein. Es gibt verschiedene Anbieter, oft auch kostenlose.  === Ein Leitfaden…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Homeserver-Sicherheitsarchitektur: Aufbau, Funktionsweise und Diagnose ==&lt;br /&gt;
&lt;br /&gt;
Einen eigenen Server an&#039;s Internet zu bekommen, ist nicht allzu schwierig. Ein Dienst, der die eigene, vom Internet-Provider zugewiesene IP-Adresse in einen festen Domain-Namen umwandelt (siehe: [https://de.wikipedia.org/wiki/Dynamisches_DNS Dynamisches DNS]), wird im privaten Bereich die Voraussetzung sein.&lt;br /&gt;
Es gibt verschiedene Anbieter, oft auch kostenlose.&lt;br /&gt;
&lt;br /&gt;
=== Ein Leitfaden für selbst gehostete Server mit OPNsense, Managed Switch und Docker ===&lt;br /&gt;
&lt;br /&gt;
Die Kehrseite: Sowie der Server über&#039;s Internet erreichbar ist, ist er angreifbar. Das ist kein theoretisches Szenario. Meiner Erfahrung nach ist es eine Frage von Stunden, bis die ersten Bots &amp;quot;anklopfen&amp;quot;, nach laufenden Diensten suchen, nach offenen Ports, nach Schwachstellen.&lt;br /&gt;
&lt;br /&gt;
Aufgrund einer mangelhaften Konfiguration (offener Samba-Port) hatte ich die sehr reale Erfahrung einer russischen Hackerbande, die einige Hundert Textdateien mit Zahlungsaufforderungen und einen Verschlüsselungstrojaner auf meinem Rechner hinterlassen hatte. Gerettet hatten mich damals die Dateirechte von Linux. Das fehlende E(x)ecutional-Flag und die eingeschränkten Benutzerrechte hatten den Trojaner ausgebremst.&lt;br /&gt;
&lt;br /&gt;
Trotzdem: Nie wieder!&lt;br /&gt;
Ein wenig von dem, was ich gelernt habe, gebe ich ich hier weiter.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Einleitung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt den Aufbau einer &#039;&#039;&#039;sicheren&#039;&#039;&#039; Netzwerkarchitektur für einen Homeserver, der über das öffentliche Internet erreichbar ist. Der Beitrag richtet sich an alle, die ihre Daten selbst kontrollieren wollen — und dabei nicht unfreiwillig Teil einer globalen Angriffs-Infrastruktur werden möchten. Er will zum Verständnis beitragen, wie die einzelnen Komponenten zusammenspielen — und wie man systematisch vorgeht, wenn etwas nicht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der Fokus liegt nicht auf einer spezifischen Hardware-Konfiguration, sondern auf dem allgemeinen Prinzip: Wie kommt ein Request von außen sicher zu einem Docker-Container?&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Annahmen / Szenario ==&lt;br /&gt;
&lt;br /&gt;
Folgende Komponenten werden in diesem Artikel vorausgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver&#039;&#039;&#039; (Raspberry Pi, Intel NUC, oder beliebiger Linux-Server)&lt;br /&gt;
** Betriebssystem: Debian/Ubuntu oder vergleichbar&lt;br /&gt;
** Docker mit mehreren Diensten (z.B. WordPress, Nextcloud, MediaWiki)&lt;br /&gt;
** Caddy als Reverse Proxy (alternativ: nginx, Apache, aber Caddy hat das für mich charmante Feature, sich eigenständig um die TSL-Zertifikate und ihre Verlängerung bei LetsEncrypt zu kümmern. Wer aufgrund &amp;quot;zu vieler&amp;quot; Fehlversuche bei der Zertifikats-Einrichtung von LetsEncrypt auf Tage gesperrt wurde, wird mein Faible über diesen Automatismus nachvollziehen oder teilen können.)&lt;br /&gt;
** fail2ban als Brute-Force-Schutz&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;DynDNS-Dienst&#039;&#039;&#039; der dem Homeserver eine feste Domain zuweist&lt;br /&gt;
** Beispiel: &amp;lt;code&amp;gt;myhomeserver.dyndns.de&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Router / Heimnetz-Gateway&#039;&#039;&#039;&lt;br /&gt;
** Beispiel-IP: &amp;lt;code&amp;gt;192.168.2.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Portweiterleitung, WLAN, DynDNS-Aktualisierung&lt;br /&gt;
** Typisch: FritzBox, aber jeder Router mit Portweiterleitung funktioniert&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; (dedizierte Hardware-Firewall)&lt;br /&gt;
** WAN-Interface: &amp;lt;code&amp;gt;192.168.2.2&amp;lt;/code&amp;gt; (im Router-Netz)&lt;br /&gt;
** LAN-Interface / Server-VLAN: &amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Aufgabe: Firewall, NAT, DHCP, IDS/IPS&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Managed Switch&#039;&#039;&#039; (optional, für VLAN-Segmentierung)&lt;br /&gt;
** Trennt Server-VLAN vom Rest des Netzes&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Homeserver-IP&#039;&#039;&#039;: &amp;lt;code&amp;gt;192.168.10.100&amp;lt;/code&amp;gt; (per DHCP-Reservation oder besser: Per statischer IP-Adresse fest)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 1: Wie funktionieren die Weiterleitungen? Wer macht was? ==&lt;br /&gt;
&lt;br /&gt;
=== Die Kette von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Ein Request von außen (z.B. Browser ruft &amp;lt;code&amp;gt;https://myhomeserver.dyndns.de&amp;lt;/code&amp;gt; auf) durchläuft folgende Stationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Internet&lt;br /&gt;
    ↓ DNS-Auflösung: dyndns.de → öffentliche IP des Heimnetzes&lt;br /&gt;
Router / Gateway (192.168.2.1)&lt;br /&gt;
    ↓ Portweiterleitung: :80 + :443 → 192.168.2.2&lt;br /&gt;
OPNsense WAN-Interface (192.168.2.2)&lt;br /&gt;
    ↓ Destination NAT: :80/:443 → 192.168.10.100&lt;br /&gt;
Homeserver eno1/eth0 (192.168.10.100)&lt;br /&gt;
    ↓ Docker-Port-Binding: 0.0.0.0:80 + 0.0.0.0:443&lt;br /&gt;
Caddy / Reverse Proxy (Docker-intern)&lt;br /&gt;
    ↓ Reverse Proxy anhand des Host-Headers&lt;br /&gt;
Ziel-Container (z.B. wordpress, nextcloud, ...)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Wer macht was? ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Komponente !! Aufgabe !! Konfigurationsort&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Router / Gateway&#039;&#039;&#039; || DynDNS-Aktualisierung, erste NAT-Stufe, WLAN || Router Web-UI → Portfreigaben&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;OPNsense Firewall&#039;&#039;&#039; || Firewall-Regeln, zweite NAT-Stufe (Destination NAT), DHCP für Server-VLAN || OPNsense Web-UI (Standard: https://&amp;amp;lt;wan-ip&amp;amp;gt;:443 oder :8443)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Caddy / Reverse Proxy&#039;&#039;&#039; || TLS-Terminierung, Let&#039;s Encrypt, Weiterleitung an Container || Caddyfile auf dem Homeserver&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Docker&#039;&#039;&#039; || Container-Isolation, internes Netz (Standard: 172.18.0.0/16) || docker-compose.yml pro Dienst&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fail2ban&#039;&#039;&#039; || Brute-Force-Schutz auf Applikationsebene || Jail-Configs im fail2ban-Container&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Wichtig: OPNsense hat ZWEI Firewall-Engines ===&lt;br /&gt;
&lt;br /&gt;
OPNsense 26.x hat zwei parallele Regelwerke:&lt;br /&gt;
* &#039;&#039;&#039;Rules [new]&#039;&#039;&#039; — neue API-basierte Engine&lt;br /&gt;
* &#039;&#039;&#039;Rules&#039;&#039;&#039; — alte Engine (Legacy)&lt;br /&gt;
&lt;br /&gt;
Neue Regeln &#039;&#039;&#039;immer in beiden&#039;&#039;&#039; anlegen! Bei Problemen immer beide prüfen.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 2: Wo steht was? ==&lt;br /&gt;
&lt;br /&gt;
=== IP-Adressen (Beispiel-Setup) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Gerät !! Interface !! IP !! Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
| Router / Gateway || — || 192.168.2.1 || Gateway, WLAN, DynDNS&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense WAN || wan-interface || 192.168.2.2 || Statisch konfiguriert&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense LAN / Server-VLAN || lan-interface || 192.168.10.1 || Gateway für Server-Netz&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver || eno1 / eth0 || 192.168.10.100 || Fest per DHCP-Reservation (MAC-Adresse)&lt;br /&gt;
|-&lt;br /&gt;
| Client-Geräte || WLAN || 192.168.2.x || Im Router-Netz, nicht im Server-VLAN&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Homeserver: Netzwerk-Interface-Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Der Homeserver bezieht seine IP per DHCP vom OPNsense-DHCP-Server. Bei Debian/Ubuntu mit systemd-networkd:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/systemd/network/10-eth0.network&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Korrekter Inhalt (DHCP):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[Match]&lt;br /&gt;
Name=eno1&lt;br /&gt;
&lt;br /&gt;
[Network]&lt;br /&gt;
DHCP=ipv4&lt;br /&gt;
&lt;br /&gt;
[DHCP]&lt;br /&gt;
RouteMetric=100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ &#039;&#039;&#039;Niemals&#039;&#039;&#039; eine statische IP oder einen Gateway manuell eintragen!&lt;br /&gt;
Der Default-Gateway kommt immer vom DHCP-Server der OPNsense-Firewall (&amp;lt;code&amp;gt;192.168.10.1&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Kea DHCP Lease-Datei (OPNsense) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/db/kea/kea-leases4.csv&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier verwaltet Kea die aktiven Leases. Bei Problemen mit doppelten IPs kann diese Datei (nach &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;) auf den Header reduziert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context,pool_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Abschnitt 3: Systematische Diagnose — Schritt für Schritt ==&lt;br /&gt;
&lt;br /&gt;
=== Grundprinzip: Von außen nach innen ===&lt;br /&gt;
&lt;br /&gt;
Immer von außen nach innen vorgehen — nie raten, immer messen. Jede Schicht einzeln prüfen.&lt;br /&gt;
&lt;br /&gt;
==== Schritt 1: Ist OPNsense überhaupt erreichbar? ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Vom Client-Rechner:&lt;br /&gt;
ping 192.168.2.2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
⚠️ OPNsense antwortet standardmäßig &#039;&#039;&#039;nicht&#039;&#039;&#039; auf ICMP/Ping von außen — das ist korrekt!&lt;br /&gt;
&lt;br /&gt;
Stattdessen prüfen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Web-UI erreichbar?&lt;br /&gt;
https://192.168.2.2:8443&lt;br /&gt;
&lt;br /&gt;
# Router zeigt OPNsense als verbundenes Gerät?&lt;br /&gt;
http://192.168.2.1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 2: OPNsense intern prüfen ====&lt;br /&gt;
&lt;br /&gt;
Per SSH oder serieller Konsole auf OPNsense:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# WAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;wan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.2.2, status: active&lt;br /&gt;
&lt;br /&gt;
# LAN-Interface OK?&lt;br /&gt;
ifconfig &amp;amp;lt;lan-interface&amp;amp;gt;&lt;br /&gt;
# Erwartete Ausgabe: inet 192.168.10.1, status: active&lt;br /&gt;
&lt;br /&gt;
# Router erreichbar?&lt;br /&gt;
ping -c 3 192.168.2.1&lt;br /&gt;
&lt;br /&gt;
# Homeserver erreichbar?&lt;br /&gt;
ping -c 3 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 3: Homeserver direkt prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# SSH auf Homeserver:&lt;br /&gt;
ssh root@192.168.10.100&lt;br /&gt;
&lt;br /&gt;
# Alle Container laufen?&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# Internet vom Homeserver aus erreichbar?&lt;br /&gt;
ping -c 3 9.9.9.9&lt;br /&gt;
&lt;br /&gt;
# Routing-Tabelle korrekt?&lt;br /&gt;
ip route show&lt;br /&gt;
# Erwartete Default-Route: default via 192.168.10.1 dev eno1&lt;br /&gt;
# NICHT: default via 192.168.178.x — das wäre falsch!&lt;br /&gt;
&lt;br /&gt;
# Welche IP hat das Interface?&lt;br /&gt;
ip addr show eno1&lt;br /&gt;
# Erwartete IP: 192.168.10.100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 4: Caddy / Reverse Proxy prüfen ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Läuft Caddy und antwortet er lokal?&lt;br /&gt;
curl -v http://localhost&lt;br /&gt;
# Erwartete Antwort: HTTP 308 Redirect → https://localhost/&lt;br /&gt;
&lt;br /&gt;
# Caddy-Logs auf Fehler prüfen:&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Typische Fehler in den Caddy-Logs:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fehlermeldung !! Bedeutung !! Lösung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dial tcp ...:443: connect: no route to host&amp;lt;/code&amp;gt; || Caddy kommt nicht ins Internet (Let&#039;s Encrypt nicht erreichbar) || Routing auf Homeserver prüfen (Schritt 3)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;no route to host&amp;lt;/code&amp;gt; bei Ping auf 9.9.9.9 || Falscher Default-Gateway || &amp;lt;code&amp;gt;ip route show&amp;lt;/code&amp;gt; prüfen, falsche Route entfernen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Schritt 5: NAT und Firewall-Regeln prüfen (OPNsense Shell) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# NAT-Regeln anzeigen:&lt;br /&gt;
pfctl -s nat | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Firewall-Regeln anzeigen:&lt;br /&gt;
pfctl -s rules | grep &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf WAN-Interface beobachten (kommt der Request an?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;wan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Traffic auf LAN-Interface beobachten (wird er weitergeleitet?):&lt;br /&gt;
tcpdump -i &amp;amp;lt;lan-interface&amp;amp;gt; port &amp;amp;lt;PORT&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Diagnose-Logik:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tcpdump WAN sieht Traffic, LAN nicht → NAT-Regel prüfen!&lt;br /&gt;
tcpdump WAN sieht keinen Traffic    → Portweiterleitung im Router prüfen!&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schritt 6: Bekannte Fallstricke ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Problem !! Symptom !! Ursache !! Fix&lt;br /&gt;
|-&lt;br /&gt;
| Falsche statische Route || &amp;lt;code&amp;gt;ping 9.9.9.9&amp;lt;/code&amp;gt; schlägt fehl || Netzwerk-Config hat statischen Gateway eingetragen || Auf DHCP umstellen, &amp;lt;code&amp;gt;systemctl restart systemd-networkd&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver hat falsche IP || NAT-Regeln greifen nicht || DHCP hat beim Neustart temporär andere IP vergeben || DHCP-Reservation per MAC-Adresse einrichten&lt;br /&gt;
|-&lt;br /&gt;
| DHCP-Leases durcheinander || Server taucht mit zwei IPs auf || Neustart hat neuen Lease vor Ablauf des alten erzeugt || &amp;lt;code&amp;gt;configctl kea stop&amp;lt;/code&amp;gt;, Lease-CSV bereinigen, &amp;lt;code&amp;gt;configctl kea start&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| OPNsense Firewall-Regel fehlt || Dienste von außen nicht erreichbar, intern OK || Regel nur in einer der beiden Engines angelegt || Regel in &#039;&#039;&#039;beiden&#039;&#039;&#039; Engines anlegen (Rules [new] + Rules)&lt;br /&gt;
|-&lt;br /&gt;
| NAT-Regel ohne Subnetz-Maske || Traffic kommt nicht an || &amp;lt;code&amp;gt;192.168.178.0&amp;lt;/code&amp;gt; statt &amp;lt;code&amp;gt;192.168.178.0/24&amp;lt;/code&amp;gt; eingetragen || Subnetz-Maske ergänzen — ohne /24 gilt nur die Netzadresse selbst!&lt;br /&gt;
|-&lt;br /&gt;
| Source/Destination Port vertauscht || Verbindungen werden blockiert || Bei Firewall-Regel Port unter &amp;quot;Source&amp;quot; statt &amp;quot;Destination&amp;quot; eingetragen || Source Port: any / Destination Port: gewünschter Port&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Notfall-Cheatsheet ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# OPNsense: Firewall temporär deaktivieren (Notfall!)&lt;br /&gt;
pfctl -d&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Firewall wieder aktivieren&lt;br /&gt;
pfctl -e&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Kea DHCP stoppen/starten&lt;br /&gt;
configctl kea stop&lt;br /&gt;
configctl kea start&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Falsche Default-Route entfernen&lt;br /&gt;
ip route del default via &amp;amp;lt;falsche-gateway-ip&amp;amp;gt; dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: IP manuell setzen (Sofortlösung bei DHCP-Problemen)&lt;br /&gt;
ip addr add 192.168.10.100/24 dev eno1&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Netzwerk-Dienst neu starten (Verbindung kurz weg!)&lt;br /&gt;
systemctl restart systemd-networkd&lt;br /&gt;
&lt;br /&gt;
# Homeserver: Docker-Logs prüfen&lt;br /&gt;
docker logs caddy --tail 50&lt;br /&gt;
docker ps&lt;br /&gt;
&lt;br /&gt;
# OPNsense: Alias-Tabellen prüfen (Blocklisten)&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | wc -l&lt;br /&gt;
pfctl -t &amp;amp;lt;tabellenname&amp;amp;gt; -T show | grep &amp;amp;lt;IP&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Sicherheitshinweise ==&lt;br /&gt;
&lt;br /&gt;
* SSH-Ports &#039;&#039;&#039;nicht&#039;&#039;&#039; über das Internet freigeben — nur intern erreichbar lassen&lt;br /&gt;
* Portweiterleitung im Router auf das &#039;&#039;&#039;Minimum&#039;&#039;&#039; beschränken (nur 80 + 443)&lt;br /&gt;
* Für interne Admin-Interfaces (OPNsense Web-UI, Monitoring) &#039;&#039;&#039;keine externen Freigaben&#039;&#039;&#039;&lt;br /&gt;
* DHCP-Reservations per MAC-Adresse verhindern IP-Wechsel nach Neustarts&lt;br /&gt;
* Bei Firewall-Regeln: Block-Regeln &#039;&#039;&#039;immer&#039;&#039;&#039; vor Pass-Regeln platzieren&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Dieser Artikel basiert auf praktischen Erfahrungen aus dem Betrieb eines selbst gehosteten Servers mit OPNsense, Cisco-Switch und Docker-Stack.&#039;&#039;&lt;br /&gt;
&#039;&#039;Erstellt: Mai 2026&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
</feed>