# Kopfloser Betrieb auf Linux Der Dienst `IBKRTrader.Daemon` fährt Trading-Kern, Worker, Accounting, Supervisor, REST-API und MCP-Light **ohne Oberfläche**. Er nutzt denselben Host-Aufbau wie die Desktop-Shell (`IBKRTrader.Hosting`), damit beide Varianten nicht auseinanderlaufen. ## Veröffentlichen ```bash dotnet publish src/IBKRTrader.Daemon -c Release -r linux-x64 --self-contained false -o out/ ``` Ergebnis: ~11 MB, ein ELF-Launcher `IBKRTrader.Daemon`, **keine Windows-Abhängigkeiten**. Mit `--self-contained true` entfällt die Runtime-Installation auf dem Zielhost (dann ~80 MB). ## Voraussetzungen auf dem Host | Paket | Wofür | Pflicht? | |---|---|---| | `dotnet-runtime-10.0` | Laufzeit | ja (außer bei `--self-contained`) | | `libicu` | Kulturen und Zeitzonen-ID-Umrechnung | **ja – siehe Warnung unten** | | `fonts-dejavu-core` | PDF-Export des Accounting-Moduls | nur für den PDF-Export | | `mariadb-client` | `mariadb-dump` für den BackupWorker | nur fürs DB-Backup | > **ICU ist nicht optional.** Ohne ICU (bzw. mit `InvariantGlobalization=true`) passieren zwei > Dinge – beide **lautlos**, ohne Fehlermeldung: > 1. `AppTimeZone` kann Windows-Zeitzonen-IDs nicht mehr auflösen und fällt auf die > Systemzeitzone zurück, im Container also meist UTC. Genau die Verschiebung von > Buchungszeitstempeln, die wir beseitigt haben. > 2. Der PDF-Export formatiert Beträge fest gegen `de-DE`. Ohne ICU liefert > `CultureInfo.GetCultureInfo("de-DE")` die invariante Kultur – aus `1.234,56` wird > `1,234.56`, in einem Dokument, das als prüfbare Aufstellung gilt. > > Der Daemon setzt deshalb ausdrücklich `InvariantGlobalization=false`. ## Verzeichnisse Die Anwendung schreibt in drei Verzeichnisse. Aufgelöst wird in dieser Reihenfolge: 1. Umgebungsvariable — `IBKRTRADER_CONFIG_DIR`, `IBKRTRADER_DATA_DIR`, `IBKRTRADER_LOG_DIR` 2. Neben der Binärdatei, **wenn dort geschrieben werden darf** (Entwicklung, portable Installation) 3. Sonst FHS — `/etc/ibkrtrader`, `/var/lib/ibkrtrader`, `/var/log/ibkrtrader` | Verzeichnis | Inhalt | |---|---| | Config | `settings.json`, `master.key`, `openrouter.key` | | Data | `Backups/` | | Logs | Textlog je Modul, JSONL je Tag | Beim Start steht die tatsächliche Ablage im Log (`Ablage: config=…, data=…, logs=…`). ## Einrichtung ```bash sudo useradd --system --no-create-home --shell /usr/sbin/nologin ibkrtrader sudo mkdir -p /opt/ibkrtrader /etc/ibkrtrader /var/lib/ibkrtrader /var/log/ibkrtrader sudo chown -R ibkrtrader:ibkrtrader /var/lib/ibkrtrader /var/log/ibkrtrader /etc/ibkrtrader sudo chmod 750 /etc/ibkrtrader ``` Master-Key ablegen (**nicht** in die Unit-Datei – die ist für alle lesbar): ```bash sudo install -o ibkrtrader -g ibkrtrader -m 600 /dev/null /etc/ibkrtrader/master.key ``` Der Dienst warnt beim Start, wenn `master.key` oder `openrouter.key` für Gruppe oder andere zugänglich sind — Windows-ACLs übertragen sich beim Kopieren auf einen Linux-Host nicht. ## Dienst einrichten ```bash sudo cp deploy/ibkrtrader.service /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable --now ibkrtrader journalctl -u ibkrtrader -f ``` ## Vor dem ersten Start prüfen ```bash /opt/ibkrtrader/IBKRTrader.Daemon --check ``` Baut den Host, fährt alle Startprüfungen (Zeitzone, Ablageorte, Master-Key, DB-TLS) und beendet sich — **ohne** Worker zu starten oder eine Verbindung zur Börse aufzubauen. Geeignet für Deployment-Skripte und CI. ```bash /opt/ibkrtrader/IBKRTrader.Daemon --db-version ``` Gibt die MariaDB-Serverversion aus (für das EF-`ServerVersion`-Pinning). ## Betriebszeitzone `Trading.ApplicationTimeZoneId` in `settings.json`, IANA-Schreibweise: | Instanz | Wert | |---|---| | EU | `Europe/Berlin` | | US | `America/New_York` | **Vor den ersten Trades festlegen und danach nicht mehr ändern.** Ein Wechsel verschiebt rückwirkend die Tagesgrenzen von Logs, Berichten und Buchungsperioden. Gespeichert wird immer UTC — nur so bleiben die Daten beider Instanzen vergleichbar. ## Was der Daemon *nicht* löst Das **IB Gateway** ist eine Java-Anwendung mit Oberfläche. Für den Dauerbetrieb ohne Bildschirm braucht es IBC plus Xvfb, dazu die Behandlung des täglichen Neustarts und des 2FA-Handlings — eine eigene Baustelle, unabhängig von diesem Dienst. Alternative: das Gateway bleibt auf dem Windows-Rechner, der Linux-Dienst verbindet sich über Port 4002. Dann muss in der TWS-Konfiguration die erlaubte Client-IP eingetragen sein; der TWS-API-Verkehr ist **unverschlüsselt** und gehört nicht über ein unvertrautes Netz.