# Selbstaktualisierung

> HTML: https://remote.ivjn.us/docs/de/self-update/

CLI und eigenständiger Agent können ihre eigene Programmdatei von der Veröffentlichungsseite aktualisieren – unter Windows x64/arm64, Linux x64/arm64 (glibc- und statische musl-Builds), macOS Apple Silicon sowie FreeBSD/NetBSD x64/arm64:

```sh
remote-cli update self --check
remote-cli update self
remote-agent update self --check
remote-agent update self
```

| Plattform | Release-Archiv | Neustart nach einmaligem `remote-agent update self` |
| --- | --- | --- |
| Windows x64 / arm64 | `remote-windows-x64.zip` / `remote-windows-arm64.zip` | Geplante Aufgabe `RemoteAgent`, danach Prozessneustart |
| Linux glibc x64 / arm64 | `remote-linux-x64.tar.gz` / `remote-linux-arm64.tar.gz` | systemd-System- oder -Benutzereinheit, OpenRC, danach Prozessneustart |
| Linux musl x64 / arm64 | `remote-linux-musl-x64.tar.gz` / `remote-linux-musl-arm64.tar.gz` | Wie Linux glibc |
| macOS Apple Silicon | `remote-macos-arm64.tar.gz` | LaunchAgent `us.ivjn.remote-agent` |
| FreeBSD / NetBSD x64 / arm64 | `remote-freebsd-*.tar.gz` / `remote-netbsd-*.tar.gz` | rc.d `remote_agent` aus `remote-agent install --system`; sonst manuell neu starten |

Der Updater behält die C-Laufzeit der laufenden Programmdatei bei: Ein musl-Build installiert nur das musl-Archiv, ein glibc-Build nur das glibc-Archiv. OpenWrt bleibt auch auf x64/arm64 bei opkg/apk: Seine Pakete enthalten keinen Archiv-Updater, und ein musl-Archiv auf einem Host mit `/etc/openwrt_release` verweigert das Selbstupdate. Eine Plattform wird nur aktualisiert, wenn ihr Archiv im Manifest steht; Installationen, die vor der Unterstützung dieser Plattform gebaut wurden, müssen einmal manuell ersetzt werden.

Kontenanmeldung oder Gerätekonfiguration sind nicht erforderlich.

Für die Erstinstallation des Agent selbst (Programm, private Konfiguration und Betriebssystem-Autostart) empfiehlt sich unter Linux, macOS und Windows `remote-agent install` / `remote-agent uninstall`; siehe [platforms.md](/docs/de/platform-installation.md). Dieser Befehl benötigt keinen Netzwerkzugriff; Kopplung bleibt ein eigener Schritt. Sobald eine Version mit `install` auf dem Rechner liegt, können spätere Aktualisierungen `update self` oder auf unterstützten Plattformen die automatische Aktualisierung verwenden.

`--check` vergleicht die SHA-256-Metadaten der Programme aus dem Manifest ohne Archivdownload. Fehlen diese Metadaten, wird das Archiv heruntergeladen und geprüft. Hashes unterscheiden Entwicklungsbuilds gleicher Version; die Prüfung verändert nichts. Die Installation verhindert Downgrades und prüft Version, Größe und Hash des Programms.

Die Standardquelle ist `https://r2.ivjn.us` (die öffentliche R2-Domain für `downloads/`). `--source https://your-mirror.example/releases` wählt einen vertrauenswürdigen Spiegel mit derselben Struktur für `downloads/manifest.json` und Archive. GitHub Releases ([mbcc2006/remote-control releases](/#downloads)) veröffentlichen dieselbe Klasse von Desktoparchiven als **zusätzlichen** Downloadkanal. Sie ersetzen **nicht** das Websiteformat; die Selbstaktualisierung verwendet weiter `r2.ivjn.us`, sofern `--source` nicht auf einen Spiegel mit `downloads/manifest.json` zeigt. Ausschließlich HTTPS wird akzeptiert, Weiterleitungen werden abgelehnt und Kontotokens werden nicht gesendet. Der Archivname wird anhand von Betriebssystem und Architektur gewählt; Größe und SHA-256 werden gegen das HTTPS-Manifest geprüft und nur der exakt passende Programmeintrag extrahiert. Desktopclients prüfen zuerst `downloads/manifest.json.sig` mit eingebauten öffentlichen Ed25519-Schlüsseln. Fehlende Signaturen, veränderte Bytes oder unbekannte Schlüssel führen zur Ablehnung. Spiegel müssen Manifest und Signatur unverändert ausliefern; die Signatur muss vor der Einführung von Clients mit Signaturpflicht veröffentlicht werden.

Vor Installation muss das neue Programm eine zeitlich begrenzte `--version`-Prüfung bestehen. Eine benachbarte `.update.lock`-Datei serialisiert Aktualisierungen; das aktuelle Programm wird erneut geprüft, um gleichzeitigen Austausch zu erkennen. Nur das Programm und seine Aktualisierungs-/Sicherungsdateien werden verändert. Geräte-IDs, Zugangsdaten und Konfiguration bleiben erhalten.

Unter macOS muss das heruntergeladene Programm vor der Versionsprüfung zusätzlich `codesign --verify --strict` bestehen. Veröffentlichte Signatur und Bytes bleiben beim Austausch erhalten, damit spätere Hashvergleiche stabil sind.

Das bisherige Programm bleibt als `<executable>.previous` erhalten. Stoppen Sie bei Bedarf den Agent und stellen Sie diese Datei am ursprünglichen Programmpfad wieder her. Unter Windows wird das geladene Programm vor der Installation des Ersatzes zur Sicherung umbenannt; bei Installationsfehler wird der ursprüngliche Name wiederhergestellt.

Nach erfolgreichem `remote-agent update self` (ohne `--check`) versucht der Updater, den laufenden Agent neu zu starten, damit die neue Programmdatei geladen wird: Unter Linux (glibc und musl) führt er `systemctl restart remote-agent`, dann `systemctl --user restart remote-agent` und, falls `/etc/init.d/remote-agent` existiert, `rc-service remote-agent restart` (OpenRC) aus; ist nichts davon verfügbar, startet er andere `remote-agent`-Daemons per SIGTERM mit ihren bisherigen Argumenten neu. Unter Windows (x64 und arm64) startet er die geplante Aufgabe `RemoteAgent` neu, mit Rückfall auf Prozessebene. Unter FreeBSD/NetBSD führt er das von `remote-agent install --system` installierte rc.d-Skript `remote_agent restart` aus und meldet sonst, dass ein manueller Neustart nötig ist. Ist der aktualisierende Prozess selbst der Daemon (Argumente nicht `update self`), ersetzt er sich unter Unix per `exec` (PID bleibt für Supervisoren erhalten) bzw. startet unter Windows einen losgelösten Ersatzprozess. `remote-cli update self` startet nie einen Agent neu. Statuszeilen melden, ob der Neustart über systemd, OpenRC, rc.d, eine geplante Aufgabe oder einen neuen Prozess erfolgte oder nicht möglich war (das Update selbst ist trotzdem erfolgreich). Mit den Rechten des Installationseigentümers ausführen; der Updater erhöht keine Rechte. Beim Neustart protokollierte Befehlszeilen schwärzen `--token`-Werte. Läuft noch ein früherer Windows-Agent aus der Sicherung, diesen vor dem nächsten Update neu starten.

## Automatische Aktualisierung des Desktop-Agent-Daemons

Der laufende Agent-Daemon (kein einmaliges `update self`) **prüft regelmäßig** dasselbe Website-Manifest und aktualisiert sich, wenn sich das veröffentlichte `remote-agent`-Programm im Hash unterscheidet. Standardverhalten:

- **Standardmäßig aktiviert** auf unterstützten Desktopbuilds (Windows x64/arm64 / Linux x64/arm64 glibc und musl / macOS arm64 / FreeBSD und NetBSD x64/arm64).
- Deaktivierung über `REMOTE_AUTO_UPDATE=0` (auch `false` / `no` / `off`), JSON-Konfiguration `"auto_update": false` oder CLI `--auto-update false`.
- Erste Prüfung etwa 90 Sekunden nach Start, danach ungefähr alle 12 Stunden, nicht bei jedem Heartbeat.
- Fortschritt wird deutlich protokolliert; Gerätetokens gelangen **niemals** an das Update-CDN.
- OpenWrt (auch ein musl-Archiv auf einem OpenWrt-Host) überspringt Desktop-Auto-Updates; Android nutzt seinen eigenen OTA-Weg. Nicht zugeordnete Architekturen wie Intel-Mac oder 32-Bit-ARM liefern einen Fehler „kein Release-Archiv“ und können nicht automatisch aktualisieren.

## Ferngesteuerte Aktualisierung (Operator → Gerät)

Operatoren mit gewöhnlicher Gerätesitzung (dieselben ACLs wie `OpenExec`) können ein Onlinegerät zur Prüfung oder Installation einer Aktualisierung auffordern:

Protokoll (WebSocket-JSON):

- `OperatorUp::update_device` `{ session_id, device_id, check_only, source? }`
- Exchange → `DeviceDown::update_req`
- Gerät → Fortschrittsmeldungen `DeviceUp::update_status` / `OperatorDown::update_status` mit `phase`:
  `checking` | `downloading` | `applying` | `up_to_date` | `available` | `applied` | `error`

Konsole: in den Gerätedetails **Nach Updates suchen** / **Update ausrollen**.

CLI, entsprechend anderen Gerätesitzungsoperationen:

```sh
remote-cli device update <device_id> --check
remote-cli device update <device_id>
remote-cli device update <device_id> --source https://r2.ivjn.us
```

Bei aktiviertem LAN bildet die LAN-Steuerung `update_device` genauso ab wie andere open-*-Nachrichten von `OperatorUp`.

OpenWrt und andere nicht unterstützte Agents liefern eine eindeutige Phase `error`, statt ein falsches Artefakt zu installieren. Windows arm64, Linux musl, macOS Apple Silicon und FreeBSD/NetBSD nutzen denselben Desktop-Archivpfad wie Windows x64 und Linux glibc.

## Android-Agent-OTA

Die Android-Agent-APK (`remote-agent-android.apk` auf der Website) kann sich über dasselbe HTTPS-Manifest aktualisieren:

Öffnen Sie im Agent **Einstellungen → Nach Updates suchen**, um manuell zu prüfen. Die Prüfung lädt und verifiziert die APK; bei verfügbarem Update ist eine separate Bestätigung erforderlich, bevor der Android-Installer geöffnet wird.

- APK herunterladen, **Bytes + SHA-256** prüfen und `versionCode` sowie Paketname mit der installierten App vergleichen. Neu gebaute Versionen mit gleicher Versionsnummer, aber anderem Hash können ebenfalls installierbar sein.
- Installation über `PackageInstaller`. Die App deklariert `REQUEST_INSTALL_PACKAGES`. Beim ersten OTA muss der Benutzer möglicherweise „Unbekannte Apps installieren“ für Remote Agent in den Systemeinstellungen erlauben und anschließend den angezeigten Systeminstaller bestätigen.
- Ein Installationsstart liefert `available` mit einer Meldung über die ausstehende Installation, nicht `applied`. Der private Installer-Callback öffnet die Systembestätigung. Wiederholte Anfragen für dieselbe ausstehende APK verwenden dieselbe Sitzung; fehlgeschlagene und veraltete Selbstaktualisierungssitzungen werden verworfen. Prüfen Sie installierte Version und Hash nach Wiederverbindung des Agent.
- Während `AgentService` läuft, erfolgen automatische Prüfungen in einem ähnlichen Intervall.
- Remote-`update_req` wird vom nativen Agent verarbeitet, der die APK-Steuerbrücke aufruft (`action: ota_update`).
- Appprivater Speicher (Geräte-ID / Token) bleibt beim Paketaustausch erhalten; `MY_PACKAGE_REPLACED` startet die Verbindung bei aktivierter Funktion weiterhin neu.

Rust Agent/CLI/Exchange, Browser-Erweiterung, Android-Apps und Web-Konsole verwenden gemeinsam Version 0.1.27. Versionen künftig zusammen erhöhen; Android versionCode ist 30. Vor dem Paketbau `python scripts/check-release-versions.py` ausführen.

## Aktualisierung der Android-Konsole

Die native Konsole besitzt eine eigene Schaltfläche **Einstellungen → Nach Updates suchen**, die vor und nach Anmeldung verfügbar ist. Sie liest das öffentliche Website-Manifest ohne Kontozugangsdaten und vergleicht den installierten Build mit dem veröffentlichten `versionCode`. Fehlen Build-Metadaten im Manifest und stimmen Marketingversionen überein, bietet sie einen Download an, ohne zu behaupten, die installierte App sei aktuell.

**Installationspaket herunterladen** öffnet die Website-APK im Browser; schließen Sie die Installation über Androids Bestätigungsbildschirm ab. Damit wird die Konsole auf dem aktuellen Telefon aktualisiert. Update-Steuerelemente einer Gerätedetailseite betreffen weiterhin jenes entfernte Gerät.

## „Nach Updates suchen“ in der Konsole (gemeinsamer Ablauf)

Die Gerätedetails bieten nur noch eine Aktion „Nach Updates suchen“. Zunächst wird `update_device { check_only: true }` gesendet:

- `up_to_date` → „Bereits aktuelle Version x.y.z“ anzeigen.
- `available` → „Aktuell → Neu (Größe)“ anzeigen. Der Benutzer wählt „Update ausrollen / Später“. Nach Bestätigung wird `check_only: false` gesendet und Fortschritt und Ergebnis werden angezeigt.
- Meldet Android nach dem Ausrollen „Installation pending …“, wird auf die nötige Systembestätigung am Gerät hingewiesen.
- Bei Offlinegeräten und Browsergeräten wird der Grund direkt angezeigt; bei nicht unterstützter Plattform „Dieses Gerät unterstützt keine Fernaktualisierung“.

Ergebnisnachrichten enthalten `current <版本>` und `size <字节> bytes`.

Siehe außerdem `docs/watchdog.md` im Repository für den optionalen Verfügbarkeits-Watchdog (`--watchdog`, `REMOTE_WATCHDOG=1`).

Die Android-Diagnose zeigt das letzte automatische Update mit Zeitstempel auch ohne READ_LOGS. Feste Meldungen unterscheiden HTTP-Status, DNS, Zeitüberschreitung, TLS, Manifest, APK-Größe/Hash und Installationsberechtigung. Dieselbe sichere Meldung erscheint mit dem Tag RemoteAgentOTA in logcat; vollständige Gerätelogs benötigen weiterhin READ_LOGS. URLs, Pfade und Zugangsdaten aus Ausnahmen werden nicht übernommen.
