diff --git a/docs/GNAI-001-INFRA_BaseSystem.md b/docs/GNAI-001-INFRA_BaseSystem.md
index 461da2d..6e30717 100644
--- a/docs/GNAI-001-INFRA_BaseSystem.md
+++ b/docs/GNAI-001-INFRA_BaseSystem.md
@@ -37,12 +37,10 @@ Vor der Betriebssystem-Installation sind folgende Schritte im BIOS (Aufrufen via
* Im BIOS navigieren zu: `Tool` -> `Instant Flash`.
* BIOS-Version auf **`19.02`** (oder neuer) aktualisieren.
-
2. **RAM-Performance:**
* Navigieren zu: `OC Tweaker` -> `DRAM Configuration`.
* **Load XMP Setting:** auf **XMP Profile 1** stellen.
-
3. **Virtualisierung & PCI-Einstellungen (Wichtig für GPU/ROCm):**
* Navigieren zu: `Advanced` -> `CPU Configuration` -> **Intel Virtualization Technology** -> `Enabled`.
* Navigieren zu: `Advanced` -> `PCI Configuration`:
@@ -165,7 +163,6 @@ apt update
# Grundlegende Tools und GPU-Firmware installieren
apt install -y curl wget git htop tmux pciutils firmware-amd-graphics firmware-linux-nonfree
-
```
#### 4. SSH-Schlüssel hinterlegen (Remote-Zugriff)
@@ -178,7 +175,6 @@ mkdir -p ~/.ssh
chmod 700 ~/.ssh
nano ~/.ssh/authorized_keys # Public-Key des Admin-PCs einfügen
chmod 600 ~/.ssh/authorized_keys
-
```
---
@@ -200,4 +196,4 @@ Vor der Übergabe an das KI-Team (Phase 2) muss das System folgende Punkte beste
| Datum | Version | Geändert von | Beschreibung der Änderung |
| --- | --- | --- | --- |
| 2026-08-24 | 1.0 | spektr | Erstellung des Initial-Dokuments (Hardware & OS) |
-| 2026-08-24 | 1.1 | spektr / Assistant | Detaillierung der BIOS-ReBAR-Settings, Netinst-CLI-Schritte, Post-Installation & Abnahmekriterien hinzugefügt. |
\ No newline at end of file
+| 2026-08-24 | 1.1 | spektr / Assistant | Detaillierung der BIOS-ReBAR-Settings, Netinst-CLI-Schritte, Post-Installation & Abnahmekriterien hinzugefügt. |
diff --git a/docs/GNAI-002-INFRA_Users.md b/docs/GNAI-002-INFRA_Users.md
index db4a12a..2915fe8 100644
--- a/docs/GNAI-002-INFRA_Users.md
+++ b/docs/GNAI-002-INFRA_Users.md
@@ -1,9 +1,7 @@
-# Standard Operating Procedure (SOP)
-
-**Dokumenten-ID:** GNAI-INFRA-002
-
-**Titel:** Benutzerverwaltung, SSH-Härtung & Netzwerkkonfiguration (Phase 2)
+# Standard Operating Procedure
+**Dokumenten-ID:** GNAI-002-INFRA
+**Titel:** Benutzerverwaltung, SSH-Härtung & Netzwerkkonfiguration (Phase 2)
**Version:** 1.0
---
@@ -33,7 +31,6 @@ Als `root` am Server anmelden:
```bash
su -
apt update && apt install -y sudo
-
```
#### 2. Benutzer anlegen & Berechtigungen vergeben
@@ -46,7 +43,6 @@ Neuen Benutzer anlegen und zur `sudo`-Gruppe hinzufügen:
# Beispiel für Benutzer 'ghost' oder 'debugofen'
sudo adduser debugofen
sudo usermod -aG sudo debugofen
-
```
---
@@ -55,18 +51,16 @@ sudo usermod -aG sudo debugofen
#### 1. Netzschnittstelle ermitteln & anpassen
-Lass dir die primäre Netzwerkschnittstelle anzeigen (z. B. `enp8s0`):
+Primäre Netzwerkschnittstelle anzeigen lassen (z. B. `enp8s0`):
```bash
ip addr show
-
```
-Bearbeite die Datei `/etc/network/interfaces`:
+Datei bearbeiten: `/etc/network/interfaces`:
```bash
sudo nano /etc/network/interfaces
-
```
Netzwerkkonfiguration für statische IP eintragen:
@@ -82,16 +76,14 @@ iface enp8s0 inet static
address 10.0.0.90/24
gateway 10.0.0.1
dns-nameservers 10.0.0.1 1.1.1.1
-
```
#### 2. DNS-Resolver prüfen/anpassen
-Prüfe die Datei `/etc/resolv.conf`:
+Datei überprüfen `/etc/resolv.conf`:
```bash
sudo nano /etc/resolv.conf
-
```
Sicherstellen, dass folgende Nameserver eingetragen sind:
@@ -99,7 +91,6 @@ Sicherstellen, dass folgende Nameserver eingetragen sind:
```text
nameserver 10.0.0.1
nameserver 1.1.1.1
-
```
#### 3. Netzwerkdienst neustarten & Funktion prüfen
@@ -108,7 +99,6 @@ nameserver 1.1.1.1
sudo systemctl restart networking
ip -4 addr
ping -c 4 google.com
-
```
*(Tritt ein Konfigurationskonflikt auf, das System einmal per `sudo reboot` neustarten).*
@@ -117,24 +107,22 @@ ping -c 4 google.com
### 3.3 SSH-Key-Generierung & Übertragung (Workstation-Seite)
-Führe diese Schritte auf der **lokalen Workstation** aus.
+Die folgenden Schritte werden auf der **lokalen Workstation** ausgeführt.
#### 1. Ed25519 SSH-Schlüsselpaar erzeugen
```bash
ssh-keygen -t ed25519 -C "ghost@ghostnet-ki" -f ~/.ssh/id_ed25519_ghost
ssh-keygen -t ed25519 -C "debugofen@ghostnet-ki" -f ~/.ssh/id_ed25519_debugofen
-
```
#### 2. Public Keys auf den Server übertragen
-Verwende `ssh-copy-id`, um die öffentlichen Schlüssel auf den Server zu kopieren (vorläufig noch mit Passwort-Authentifizierung):
+Der Befehl `ssh-copy-id` wird verwendet, um die öffentlichen Schlüssel auf den Server zu kopieren (vorläufig noch mit Passwort-Authentifizierung):
```bash
ssh-copy-id -i ~/.ssh/id_ed25519_ghost.pub ghost@10.0.0.90
ssh-copy-id -i ~/.ssh/id_ed25519_debugofen.pub debugofen@10.0.0.90
-
```
#### 3. Schlüsselbasierten Login testen
@@ -142,16 +130,14 @@ ssh-copy-id -i ~/.ssh/id_ed25519_debugofen.pub debugofen@10.0.0.90
```bash
ssh -i ~/.ssh/id_ed25519_ghost ghost@10.0.0.90
ssh -i ~/.ssh/id_ed25519_debugofen debugofen@10.0.0.90
-
```
#### 4. Workstation Client-Config einrichten (`~/.ssh/config`)
-Erstelle/bearbeite die Datei `~/.ssh/config` auf der Workstation, um Kurznamen für Verbindungen zu nutzen:
+Die Datei `~/.ssh/config` auf der Workstation erstellen/bearbeiten, um Kurznamen für Verbindungen zu nutzen:
```bash
nano ~/.ssh/config
-
```
Inhalt eintragen:
@@ -165,21 +151,18 @@ Host ghostnet.ki
Hostname 10.0.0.90
User ghost
IdentityFile ~/.ssh/id_ed25519_ghost
-
```
Berechtigungen auf der Workstation korrigieren:
```bash
chmod 600 ~/.ssh/config
-
```
Verbindung über den Alias testen:
```bash
ssh ghostnet.ki
-
```
---
@@ -192,10 +175,9 @@ Sobald der SSH-Key-Login erfolgreich getestet wurde, wird die Passwort-Authentif
```bash
sudo nano /etc/ssh/sshd_config.d/99-security.conf
-
```
-Füge folgenden Inhalt ein:
+Den folgenden Inhalt einfügen:
```text
# Root-Login über SSH komplett verbieten
@@ -210,7 +192,6 @@ PermitEmptyPasswords no
# Nur explizite SSH-Key Methoden erlauben
PubkeyAuthentication yes
-
```
#### 2. SSH-Konfiguration prüfen und Dienst neustarten
@@ -223,7 +204,6 @@ sudo sshd -t
# Wenn sshd -t keine Fehler ausgibt, Dienst neustarten
sudo systemctl restart sshd
-
```
---
diff --git a/docs/GNAI-004-SEC_Access-Control.md b/docs/GNAI-004-SEC_Access-Control.md
index 495cdd5..95000d1 100644
--- a/docs/GNAI-004-SEC_Access-Control.md
+++ b/docs/GNAI-004-SEC_Access-Control.md
@@ -4,7 +4,7 @@
**Titel:** Homelab / LLM-Infrastruktur – Sicherheits-, Authentifizierungs- und Zugriffskonzept
**Version:** 1.0
**Status:** Architekturentscheidung
-**Vorgänger / Referenzen:** GNAI-INFRA-003
+**Vorgänger / Referenzen:** GNAI-003-INFRA
---
diff --git a/docs/GNAI-005-SEC_Reverse-Proxy.md b/docs/GNAI-005-SEC_Reverse-Proxy.md
new file mode 100644
index 0000000..61bf8f3
--- /dev/null
+++ b/docs/GNAI-005-SEC_Reverse-Proxy.md
@@ -0,0 +1,314 @@
+# Technical Architecture Specification
+
+**Dokumenten-ID:** GNAI-006-SEC
+**Titel:** Homelab / Infrastructure – Reverse Proxy & Containerized IPS Specification
+**Version:** 1.0
+**Status:** Aktiv
+**Vorgänger / Referenzen:** GNAI-003-INFRA, GNAI-004-SEC
+
+---
+
+## 1. Zweck & Geltungsbereich
+
+Dieses Dokument definiert die verbindliche System- und Sicherheitsarchitektur für den zentralen Reverse Proxy und das Intrusion Prevention System (IPS) der Ghostnet-Infrastruktur auf Proxmox LXC 103 (`reverse-proxy`).
+
+**Umfang dieses Dokuments:**
+
+* Betrieb von Nginx Proxy Manager (NPM) als zentraler Ingress-Controller
+* Containerisiertes Fail2Ban als IPS mit nftables-Integration auf dem LXC
+* Log-Parsing-Regeln und Filterdefinitionen für das NPM-spezifische Access-Log-Format
+* Gehärtete Firewall-Baseline und Zugriffssteuerung
+
+---
+
+## 2. System- Baseline (LXC 103)
+
+| Parameter | Wert |
+| --- | --- |
+| Container-ID | CT 103 |
+| Hostname | `reverse-proxy`
|
+| Betriebssystem | Debian GNU/Linux 13 (Trixie) |
+| Unprivileged | Ja |
+| Cores / RAM / Swap | 2 Cores / 1024 MB RAM / 512 MB Swap |
+| RootFS | 8 GB |
+| Netzwerkkonfiguration | IP: `10.0.0.10/24` | GW: `10.0.0.1` | Bridge: `vmbr0`
|
+| LXC Features | `nesting=1`, `keyctl=1`
|
+| Proxmox Host | Proxmox VE 8.4.21 (Kernel `6.8.12-23-pve`) |
+
+*Hinweis zur Proxmox-Firewall:* Proxmox Cluster- und Node-Firewalls sind deaktiviert (`enable 0`). Die Paketfilterung erfolgt exklusiv lokal über `nftables` innerhalb des LXC.
+
+---
+
+## 3. Netzwerk- & Firewall-Architektur (nftables)
+
+Die lokale Paketfilterung basiert auf `nftables` mit einer strikten `INPUT policy drop`-Doktrin.
+
+```nftables
+table inet filter {
+ chain input {
+ type filter hook input priority filter; policy drop;
+ iifname "lo" accept
+ ct state invalid drop
+ ct state established,related accept
+ ip protocol icmp accept
+ ip saddr 10.0.0.0/24 tcp dport { 22, 81 } accept
+ tcp dport { 80, 443 } accept
+ }
+
+ chain forward {
+ type filter hook forward priority filter; policy accept;
+ }
+
+ chain output {
+ type filter hook output priority filter; policy accept;
+ }
+}
+```
+
+### Port-Matrix
+
+| Port | Protokoll | Zweck | Erreichbarkeit |
+| --- | --- | --- | --- |
+| 80 | TCP | HTTP Ingress (NPM) | Öffentlich |
+| 443 | TCP | HTTPS Ingress (NPM) | Öffentlich |
+| 81 | TCP | NPM Web Admin Interface | Nur LAN (`10.0.0.0/24`) |
+| 22 | TCP | OpenSSH Management | Nur LAN (`10.0.0.0/24`) |
+| 3000 | TCP | NPM Node.js Backend | Intern / Nicht exponiert |
+
+---
+
+## 4. Container-Infrastruktur (Podman Quadlets)
+
+Nginx Proxy Manager und Fail2Ban werden als rootful Podman-Container via systemd Quadlets mit `Network=host` betrieben.
+
+### 4.1 Nginx Proxy Manager Quadlet
+
+* **Datei:** `/etc/containers/systemd/nginx-proxy-manager.container`
+* **Image:** `docker.io/jc21/nginx-proxy-manager:2.11.1` *(ausdrücklich gepinnt)*
+
+```ini
+[Unit]
+Description=Nginx Proxy Manager
+Wants=network-online.target
+After=network-online.target
+
+[Container]
+Image=docker.io/jc21/nginx-proxy-manager:2.11.1
+ContainerName=nginx-proxy-manager
+Network=host
+Volume=/opt/nginx-proxy-manager/data:/data:rw
+Volume=/opt/nginx-proxy-manager/letsencrypt:/etc/letsencrypt:rw
+Environment=DISABLE_IPV6=true
+Environment=TZ=Europe/Berlin
+
+[Service]
+Restart=always
+TimeoutStartSec=300
+
+[Install]
+WantedBy=multi-user.target
+```
+
+### 4.2 Fail2Ban IPS Quadlet
+
+* **Datei:** `/etc/containers/systemd/fail2ban.container`
+* **Image:** `lscr.io/linuxserver/fail2ban:latest`
+* **Capabilities:** `NET_ADMIN`, `NET_RAW` *(kein `--privileged`)*
+
+```ini
+[Unit]
+Description=Fail2Ban
+Wants=network-online.target
+After=network-online.target
+
+[Container]
+Image=lscr.io/linuxserver/fail2ban:latest
+ContainerName=fail2ban
+Network=host
+AddCapability=NET_ADMIN
+AddCapability=NET_RAW
+Volume=/opt/fail2ban/config:/config:rw
+Volume=/opt/nginx-proxy-manager/data/logs:/remotelogs/npm:ro
+Environment=TZ=Europe/Berlin
+
+[Service]
+Restart=always
+TimeoutStartSec=300
+
+[Install]
+WantedBy=multi-user.target
+```
+
+---
+
+## 5. NPM Logformat & Parsing-Regeln
+
+NPM nutzt ein eigenes Access-Log-Format, bei dem die eigentliche Client-IP nicht am Zeilenanfang steht.
+
+**Beispielzeile:**
+
+```text
+[03/Sep/2026:18:35:02 +0200] - 204 204 - POST https jellyfin.ghostnet.selfhost.eu "/Sessions/Playing/Progress" [Client 93.228.100.74] [Length 0] [Gzip -] [Sent-to 10.0.0.11] "JellyfinDesktop/2.0.0" "-"
+```
+
+**Verbindliche Parser-Regeln:**
+
+1. Die Client-IP muss zwingend aus dem Feld `[Client ]` extrahiert werden.
+2. URL-Pfade oder Host-Header dürfen nicht fälschlicherweise als IP-Quelle interpretiert werden.
+3. Statuscodes oder Response-Zeiten sind für automatisches Banning ungeeignet, da legitim nicht erreichbare Backends (502) False Positives auslösen würden.
+
+---
+
+## 6. Fail2Ban-Konfiguration & Jails
+
+LinuxServer.io nutzt `/config/fail2ban/` als interne Konfigurationsstruktur. Sämtliche Konfigurationen liegen persistent auf dem Host unter `/opt/fail2ban/config/fail2ban/`.
+
+### 6.1 Wichtige Erkenntnis zur Action-Syntax
+
+Standardmäßig nutzt die Action `nftables-multiport` bei fehlenden Parametern Port 22 (SSH). **Sperrports müssen zwingend direkt in der `action`-Zeile des Jails in eckigen Klammern übergeben werden**, um Anfragen auf HTTP/HTTPS durchzusetzen:
+
+```ini
+action = nftables-multiport[port="80,443", protocol=tcp]
+```
+---
+
+### 6.2 Jail 1: Exploit & Scanner Protection (`npm-scanner`)
+
+Gezielte Blockade von Pfad-Traversal-Versuchen, Secret-Abfragen und automatisierten Framework-Scans.
+
+* **Filter:** `/opt/fail2ban/config/fail2ban/filter.d/npm-scanner.conf`
+
+ ```ini
+ [Definition]
+ failregex = ^\[.*\] - [0-9]{3} [0-9]{3} - (GET|POST|HEAD) [^ ]+ [^ ]+ "/(?:[^"]*/)?(?:\.env[^"/]*|\.git/[^" ]*|\.aws/[^" ]*|wp-config\.php[^" ]*|wp-login\.php(?:\?[^" ]*)?|wp-admin(?:/[^" ]*)?|actuator(?:/[^" ]*)?|_ignition(?:/[^" ]*)?|storage/logs(?:/[^" ]*))" \[Client \]
+ ignoreregex =
+ ```
+
+* **Jail:** `/opt/fail2ban/config/fail2ban/jail.d/npm-scanner.local`
+
+ ```ini
+ [npm-scanner]
+ enabled = true
+ filter = npm-scanner
+ backend = auto
+ logpath = /remotelogs/npm/proxy-host-*_access.log
+ findtime = 10m
+ maxretry = 3
+ bantime = 1h
+ ignoreip = 127.0.0.1/8 10.0.0.0/24
+ action = nftables-multiport[port="80,443", protocol=tcp]
+ ```
+
+---
+
+### 6.3 Jail 2: Bad User-Agents (`npm-badbots`)
+
+Blockade bekannter Angriffs-Scanner und Reconnaissance-Tools.
+
+* **Filter:** `/opt/fail2ban/config/fail2ban/filter.d/npm-badbots.conf`
+ *(Wichtig: Nutzt lokale Case-Insensitivity `(?i:...)`, um Python-RegEx-Kompilierungsfehler zu vermeiden)*
+
+ ```ini
+ [Definition]
+ failregex = ^\[.*\] - [0-9]{3} [0-9]{3} - (?:GET|POST|HEAD|OPTIONS) [^ ]+ [^ ]+ "[^"]*" \[Client \] .* "[^"]*(?i:sqlmap|nikto|nmap|masscan|zgrab|nessus|openvas|dirbuster|gobuster|wpscan|python-requests|go-http-client|censys|whatweb|acunetix)[^"]*"
+ ignoreregex =
+ ```
+
+* **Jail:** `/opt/fail2ban/config/fail2ban/jail.d/npm-badbots.local`
+
+ ```ini
+ [npm-badbots]
+ enabled = true
+ filter = npm-badbots
+ backend = auto
+ logpath = /remotelogs/npm/proxy-host-*_access.log
+ findtime = 10m
+ maxretry = 2
+ bantime = 24h
+ ignoreip = 127.0.0.1/8 10.0.0.0/24
+ action = nftables-multiport[port="80,443", protocol=tcp]
+ ```
+
+---
+
+## 7. Aktive Proxy Hosts
+
+Aktuell im Nginx Proxy Manager konfigurierte und aktive Routen:
+
+| ID | Hostname | Backend-Ziel | Dienst |
+| --- | --- | --- | --- |
+| 1 | `jellyfin.ghostnet.selfhost.eu` | `10.0.0.11:8096` | Jellyfin Media Server |
+| 3 | `nextcloud.ghostnet.selfhost.eu` | `10.0.0.12:8080` | Nextcloud Cloud Storage |
+| 4 | `git.ghostnet.selfhost.eu` | `10.0.0.17:3000` | Gitea Code Hosting |
+| 7 | `auth.ghostnet.selfhost.eu` | `10.0.0.4:8080` | Keycloak Identity Provider |
+| 10 | `japan.ghostnet.selfhost.eu` | `10.0.0.23:80` | Japanese Web App |
+| 12 | `vault.ghostnet.selfhost.eu` | `10.0.0.47:8080` | Vaultwarden Password Manager |
+
+---
+
+## 8. Betriebs- & Diagnosekommandos
+
+### Fail2Ban-Status
+
+```bash
+# Gesamtstatus der aktiven Jails
+podman exec fail2ban fail2ban-client status
+
+# Spezifischen Jail prüfen
+podman exec fail2ban fail2ban-client status npm-scanner
+podman exec fail2ban fail2ban-client status npm-badbots
+```
+
+### Filter mit echten Logs testen
+
+```bash
+podman exec fail2ban fail2ban-regex \
+ /remotelogs/npm/proxy-host-10_access.log \
+ /config/fail2ban/filter.d/npm-scanner.conf
+```
+
+### nftables-Regeln & aktive Bans auf dem Host verifizieren
+
+```bash
+nft list ruleset | grep -A 10 "table inet f2b-table"
+```
+
+### Manuelle Sperre / Freigabe
+
+```bash
+# IP manuell sperren
+podman exec fail2ban fail2ban-client set npm-scanner banip
+
+# IP manuell freigeben
+podman exec fail2ban fail2ban-client set npm-scanner unbanip
+```
+
+---
+
+## 9. Sicherheits- & Betriebsregeln für Administrierende
+
+1. **Kein generisches Statuscode-Banning:** Generische HTTP `4xx`- oder `5xx`-Fehler dürfen nicht als pauschales Ban-Kriterium verwendet werden.
+2. **Keine verfrühten Upgrades:** Die NPM-Version ist auf `2.11.1` festgeschrieben. Upgrades müssen separat in einer Testumgebung evaluiert werden.
+3. **Privilegien-Minimierung:** Der Fail2Ban-Container wird strikt ohne `--privileged` betrieben (`NET_ADMIN` und `NET_RAW` reichen aus).
+4. **Whitelist-Pflicht:** Das Subnetz `10.0.0.0/24` sowie `127.0.0.1/8` müssen in allen Jails in `ignoreip` hinterlegt bleiben, um Aussperrungen zu verhindern.
+5. **Syntax-Check vor Reload:** Jede Änderung an Fail2Ban-Konfigurationen ist vorab mit `podman exec fail2ban fail2ban-client -t` auf Gültigkeit zu prüfen.
+
+---
+
+## 10. Backup & Disaster Recovery
+
+Es existiert ein vollständiges Proxmox LXC Snapshot-Backup von CT 103:
+
+* **Backup-Datei:** `/var/lib/vz/dump/vzdump-lxc-103-2026_08_31-19_11_10.tar.zst`
+
+Vor strukturellen Änderungen an `nftables` oder den Podman Quadlets ist stets ein neuer Proxmox LXC-Snapshot zu erstellen.
+
+---
+
+## 11. Änderungsverlauf
+
+| Datum | Version | Geändert von | Beschreibung |
+| --- | --- | --- | --- |
+| 2026-08-28 | 0.1 | spektr | Erstellung der ersten Baseline-Drafts. |
+| 2026-09-05 | 0.9 | spektr | Implementierung Fail2Ban Container & Test-Setup (F2B-01). |
+| 2026-09-07 | 1.0 | spektr | Korrektur Action-Syntax (`port="80,443"`), Behebung RegEx-Fehler (`npm-badbots`), E2E-Validierung in nftables abgeschlossen (F2B-02). Finales SOP erstellt. |