Einstellungen → VPN → WireGuard → Server: Einwahl anlegen (Name, Kundennetz, LAN-IP der FritzBox); ARIA erzeugt beide Schluesselpaare + PSK, ⬇ liefert die Datei fuer die Gegenseite (FritzBox-Netzwerk-Kopplung oder Standard-WireGuard). Jede Einwahl = eigener VPN-Satellit-Container mit fester IP im Netz aria-vpn (10.213.213.0/24, ausserhalb von Dockers Pools). Neuer Verteiler (satellite/vpn_relay.py, aria-vpn-relay, Host-Netz, VPN_RELAY_PORT 51820): ordnet jedes Paket per WireGuard-mac1 bzw. Sitzungsnummer dem richtigen Container zu, ohne zu entschluesseln; Fremdes wird still verworfen. Anleitung NPM-Stream / ohne Nginx / ufw im ℹ des Server-Reiters und im satellite/README. Lokal Ende-zu-Ende getestet: zwei Kunden mit demselben Netz 192.168.178.0/24 gleichzeitig ueber einen Port, jeder erreicht nur sein eigenes LAN; kein Weg Kunde → ARIA, Kunde 1 → Einwahl 2, Container → Internet; fremder Schluessel und Muell am Verteiler ohne Antwort. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
194 lines
10 KiB
Markdown
194 lines
10 KiB
Markdown
# ARIA Satellit 🛰️
|
||
|
||
Ein eigenständiger **Außenposten-Container** für ein fremdes Netz (Büro, Werkstatt,
|
||
Ferienwohnung …). Er verbindet sich als RVS-Client in Stefans Raum und gibt ARIA
|
||
**Augen und Hände in genau diesem Netz** — ohne dass der Haupt-Stack dort stehen muss.
|
||
|
||
- **Augen (Info):** entdeckt Geräte via **mDNS/Zeroconf** (Chromecast, AirPlay, Sonos,
|
||
Drucker, NAS …), **SSDP/UPnP + DIAL** (Smart-TVs, Fire TV) und der **ARP-Tabelle**
|
||
(rohe Hosts). Meldet ARIA ein Live-Inventar.
|
||
- **Hände (Steuerung):** **DIAL-App-Launch** (z.B. YouTube-Video auf dem Fire TV),
|
||
**Wake-on-LAN**, generisches **HTTP**. Nur wenn freigeschaltet (siehe Sicherheit).
|
||
|
||
## ⚠️ Wichtig: der Satellit MUSS im echten Ziel-LAN laufen
|
||
|
||
Discovery (mDNS/SSDP-Multicast + ARP) funktioniert **nur**, wenn der Prozess
|
||
tatsächlich im selben LAN wie die Geräte hängt — z.B. `192.168.0.0/24`, wo der
|
||
Fire TV steht.
|
||
|
||
**Docker Desktop (Mac/Windows) geht NICHT.** Dort ist `network_mode: host` das Netz
|
||
der Docker-Linux-VM (NAT, `192.168.65.x` / `172.x`), **nicht** dein echtes LAN.
|
||
Der Satellit sieht dann nur Docker-Container statt der echten Geräte. (Der Satellit
|
||
erkennt das selbst und meldet eine ⚠-Warnung im Diagnostic + Log.)
|
||
|
||
Richtig deployen — zwei Wege:
|
||
|
||
**A) Linux-Box im Ziel-LAN mit Docker Engine** (empfohlen, z.B. Raspberry Pi / NUC im Büro):
|
||
```bash
|
||
cd satellite
|
||
cp .env.example .env # RVS-Zugang + SATELLITE_LOCATION
|
||
docker compose up -d --build
|
||
docker compose logs -f # "Netz: primary_ip=192.168.0.x" + "[scan] N Geraete"
|
||
```
|
||
`network_mode: host` (schon gesetzt) gibt hier echtes LAN + Multicast.
|
||
|
||
> **Fehler `KeyError: 'ContainerConfig'` beim Neubauen?**
|
||
> Das ist ein **Bug im alten `docker-compose` 1.29.2** (Python-Version), nicht im
|
||
> Satelliten: Beim *Ersetzen* eines bestehenden Containers mit Volume liest es ein
|
||
> Feld aus dem Image, das neuere Docker-Versionen nicht mehr schreiben. Zwei Fixes:
|
||
> ```bash
|
||
> docker compose up -d --build # v2 (mit LEERZEICHEN) — falls vorhanden
|
||
> # oder mit der alten Version: alten Container erst weg, dann neu anlegen
|
||
> docker-compose rm -sf satellite && docker-compose up -d --build
|
||
> ```
|
||
> Der `./data`-Ordner (Credentials, ADB-Schlüssel, APK-Cache) bleibt dabei erhalten —
|
||
> er ist ein Bind-Mount, kein Container-Volume.
|
||
|
||
**B) Nativ als Python-Prozess** (für Mac/Windows-Test oder ohne Docker) — läuft direkt
|
||
auf einer Maschine im Ziel-LAN. Das Script lädt die `.env` **selbst** (muss im
|
||
`satellite/`-Ordner liegen):
|
||
```bash
|
||
cd satellite
|
||
cp .env.example .env # RVS-Zugang + SATELLITE_LOCATION eintragen
|
||
pip install -r requirements.txt
|
||
python satellite.py # liest .env automatisch
|
||
```
|
||
(Echte Umgebungsvariablen haben Vorrang — `export RVS_TOKEN=...` überschreibt die
|
||
`.env`, falls du das lieber magst.)
|
||
|
||
`RVS_HOST/PORT/TLS/TOKEN` **identisch** zum Haupt-Stack (gleicher Raum, damit ARIA
|
||
den Satelliten erreicht). `SATELLITE_LOCATION` ist der Name, über den ARIA das Netz
|
||
anspricht („Büro").
|
||
|
||
**Satellit im selben Netz wie der RVS** (z.B. Rechenzentrum, direkt auf die
|
||
interne IP statt NAT-Hairpin): `RVS_HOST=<interne-ip>` + **`RVS_SNI=<zert-name>`**
|
||
(der Name, für den das Caddy-Zertifikat gilt). Ohne das scheitert TLS an
|
||
`tlsv1 alert internal error`. Zuhause / normal: `RVS_SNI` leer lassen.
|
||
|
||
**Kontrolle:** im Log/Diagnostic muss `primary_ip` im Ziel-LAN liegen
|
||
(`192.168.0.x`) — steht da `192.168.65.x` oder `172.x`, sitzt der Satellit im
|
||
falschen (Docker-)Netz.
|
||
|
||
## Als Dienst installieren (Autostart, ohne Docker)
|
||
|
||
Legt automatisch ein `.venv` an, installiert die Requirements und richtet einen
|
||
Dienst ein, der bei Boot startet und bei Absturz neu hochkommt. `.env` vorher
|
||
anlegen.
|
||
|
||
**Linux (systemd) / macOS (launchd):**
|
||
```bash
|
||
cd satellite
|
||
bash install.sh # installieren + starten
|
||
bash install.sh uninstall # entfernen
|
||
```
|
||
- Linux-Logs: `journalctl -u aria-satellite -f`
|
||
- macOS-Logs: `tail -f satellite.log` (evtl. „Lokales Netzwerk"-Zugriff erlauben)
|
||
|
||
**Windows (Scheduled Task) — PowerShell als Administrator:**
|
||
```powershell
|
||
cd satellite
|
||
powershell -ExecutionPolicy Bypass -File install.ps1 # installieren + starten
|
||
powershell -ExecutionPolicy Bypass -File install.ps1 -Uninstall # entfernen
|
||
```
|
||
- Log: `Get-Content -Wait satellite.log`
|
||
|
||
## So nutzt ARIA es
|
||
|
||
ARIA hat drei Brain-Tools:
|
||
- `satellite_list` — welche Netze/Satelliten sind online + was können sie.
|
||
- `satellite_devices(satellite)` — Inventar eines Netzes.
|
||
- `satellite_command(satellite, device, action, params)` — Aktion ausführen.
|
||
|
||
Beispiel „YouTube-Video auf dem Büro-Stick":
|
||
```
|
||
satellite_command(satellite="Büro", device="Fire TV",
|
||
action="dial.launch", params={"app":"YouTube","v":"<videoId>"})
|
||
```
|
||
|
||
## Sicherheit
|
||
|
||
Der Satellit scannt ein Netz **und** ist über einen Cloud-Relay erreichbar — deshalb:
|
||
|
||
- Reagiert **nur** auf den eigenen RVS-Raum (Token).
|
||
- **`CONTROL_ENABLED=false`** = reiner Info-Satellit (steuert nichts). Standard-sicher.
|
||
- Bei `true`: nur Aktionen aus **`CONTROL_ALLOWLIST`**, alles andere wird abgelehnt.
|
||
- Jede ausgeführte Aktion wird **geloggt**.
|
||
- Keine offenen Ports — reiner Client.
|
||
|
||
Empfehlung: in vertrauenswürdigen Netzen `CONTROL_ENABLED=true` mit enger Allowlist;
|
||
sonst `false` und nur beobachten.
|
||
|
||
## VPN-Satelliten (WireGuard, ohne Installation beim Kunden)
|
||
|
||
Ein VPN-Satellit ist ein Satellit, der **nicht im Kundennetz** läuft, sondern auf ARIA —
|
||
verbunden über einen WireGuard-Tunnel. Angelegt wird er in der Diagnostic unter
|
||
**Einstellungen → VPN → WireGuard**; im Reiter Satelliten steht er unter „VPN-Satelliten 🔐“.
|
||
|
||
**Clients** (ARIA wählt sich beim Kunden ein): die WireGuard-Datei des Kunden hochladen
|
||
oder einfügen, Namen vergeben, einschalten.
|
||
- **An** = Container mit Neustart-Automatik (verbindet sich nach einem Neustart wieder).
|
||
**Aus** = Container weg, Datei und Log bleiben — Kundennetze nur bei Bedarf.
|
||
- ✏️ bearbeiten · ⬇ Datei wieder herunterladen · ℹ Verlauf (wann verbunden, wie lange,
|
||
Datenmenge) · 🗑 löschen. Log-Aufbewahrung im Reiter Einstellungen.
|
||
|
||
**Wie es gebaut ist** (`Dockerfile.vpn`, `vpn_entry.py`, `diagnostic/vpn.js`):
|
||
- **Ein Container pro Verbindung** (`aria-vpn-<id>`, Netz `aria-vpn`, nur `NET_ADMIN`).
|
||
Eigener Netz-Namensraum: überlappende Kundennetze (überall `192.168.178.0/24`) stören
|
||
sich nicht, und lokale Satelliten im Host-Netz sehen die VPN-Netze nie.
|
||
- **Firewall im Container:** durch den Tunnel nur ausgehend, zurück kommen nur Antworten —
|
||
auch wenn die Gegenseite den Tunnel aufgebaut hat, führt keine Verbindung vom Kundennetz
|
||
zu ARIA. Ins ARIA-Netz/Internet darf der Container nur zum RVS und zum Tunnel-Endpunkt.
|
||
- `wg0` wird selbst aufgesetzt, nicht per `wg-quick`: `DNS`/`PostUp` aus fremden Dateien
|
||
werden ignoriert, und bei `AllowedIPs = 0.0.0.0/0` bleibt der Weg zum RVS trotzdem
|
||
außerhalb des Tunnels. Endpunkte mit Hostnamen (DynDNS) werden neu aufgelöst, solange
|
||
keine Verbindung steht.
|
||
- **Scan:** über WireGuard gibt es kein mDNS/SSDP/ARP — der VPN-Satellit klopft die Netze
|
||
aktiv ab (`SCAN_NETS`, Standard = AllowedIPs ohne `0.0.0.0/0`; typische Ports, auch
|
||
„Verbindung abgelehnt“ zählt als Gerät). FritzBoxen erkennt er an Port 49000.
|
||
- Daten pro Verbindung unter `aria-data/config/diag-state/vpn/<id>/` (`tunnel/wg.conf`
|
||
mit privatem Schlüssel, `status.json`, `events.jsonl`, `data/` = Zugangsdaten usw.).
|
||
|
||
**Voraussetzungen auf der ARIA-VM:**
|
||
- WireGuard-Kernelmodul: `modprobe wireguard` und dauerhaft
|
||
`echo wireguard > /etc/modules-load.d/wireguard.conf`
|
||
- Image bauen: `docker compose up -d --build vpn-satellite-image` (baut nur das Image,
|
||
der Container beendet sich sofort wieder — das ist richtig so).
|
||
|
||
**Server** (Kunden wählen sich bei ARIA ein, z.B. per FritzBox): im Reiter Server
|
||
„+ Hinzufügen“, Namen, Kundennetz (z.B. `192.168.178.0/24`) und LAN-IP der FritzBox eintragen.
|
||
ARIA erzeugt beide Schlüsselpaare und einen Pre-Shared-Key; ⬇ liefert die Datei für die
|
||
Gegenseite:
|
||
- **FritzBox** (Netzwerk-Kopplung): `Address` = LAN-IP der Box, `AllowedIPs` = ARIAs
|
||
Tunnelnetz `10.222.<n>.0/24` (kein `0.0.0.0/0` — das lehnt die FritzBox ab). Import:
|
||
Internet → Freigaben → VPN (WireGuard) → Verbindung hinzufügen → Netzwerke koppeln →
|
||
Einstellungen aus Datei übernehmen. *Noch nicht an einer echten FritzBox getestet.*
|
||
- **Standard-WireGuard** (Linux, andere Router): eigene Tunnel-Adresse `10.222.<n>.2`; das
|
||
Kundennetz muss die Gegenseite dann selbst weiterleiten bzw. maskieren.
|
||
|
||
Alle Einwahlen kommen über **einen** Port: Der **Verteiler** (`vpn_relay.py`, Container
|
||
`aria-vpn-relay`, Host-Netz, `VPN_RELAY_PORT`, Standard 51820) ordnet jedes Paket anhand der
|
||
WireGuard-Prüfsumme `mac1` der richtigen Verbindung zu — jede Einwahl hat ihr eigenes
|
||
Server-Schlüsselpaar und ihren eigenen Container mit fester IP im Netz `aria-vpn`
|
||
(`10.213.213.0/24`, änderbar mit `VPN_SUBNET`). Entschlüsselt wird dabei nichts; fremde
|
||
Schlüssel und alles andere verwirft er still. Auch zwei Kunden mit demselben Netz
|
||
(`192.168.178.0/24`) funktionieren gleichzeitig.
|
||
|
||
**Erreichbar machen — UDP 443 auf dem RVS-Hostnamen** (TCP 443 bleibt beim RVS):
|
||
- *Mit Nginx Proxy Manager:* Hosts → **Streams** → Add Stream: Incoming Port `443`,
|
||
Forward Host = ARIA-VM, Forward Port `51820`, **TCP Forwarding aus, UDP Forwarding an**
|
||
(TCP würde mit den Proxy-Hosts kollidieren). Im docker-compose des NPM `- '443:443/udp'`
|
||
ergänzen und neu starten. Am Router UDP 443 ebenfalls auf den NPM-Rechner leiten.
|
||
Hinweis: ARIA sieht dann als Absender den NPM statt der Kunden-IP; die erzeugten Dateien
|
||
senden alle 25 s ein Lebenszeichen, damit nginx die Zuordnung behält.
|
||
- *Ohne Nginx:* den RVS-Port am Router zusätzlich als **UDP** weiterleiten — direkt auf die
|
||
ARIA-VM, Port `51820`.
|
||
- *Mit ufw als Firewall:*
|
||
```bash
|
||
# auf dem NPM-Rechner: UDP 443 aus dem Internet erlauben
|
||
ufw allow 443/udp comment 'WireGuard -> ARIA'
|
||
# auf der ARIA-VM: Verteiler-Port NUR vom NPM erlauben
|
||
ufw allow proto udp from <IP-des-NPM> to any port 51820 comment 'VPN-Verteiler nur vom NPM'
|
||
# ohne Nginx statt dessen (der Router leitet direkt auf die VM):
|
||
ufw allow 51820/udp
|
||
```
|