
Selbst gehostetes Steuerungsdeck und Remote-Desktop für Linux-Workstations über Tailscale, mit WebRTC-Streaming, Sprachsteuerung mit lokalem LLM, Szenen-Makros, virtueller Eingabe, Dateiübertragung und Live-Systemtelemetrie.
Verwandle ein altes Android-Handy (oder jedes Gerät mit einem Browser) in eine selbst gehostete Steuerkonsole und Remote-Desktop für Ihren Linux-Workstation – über Ihr privates Tailscale-Netzwerk, ohne Apps von Drittanbietern.
Es begann als „Was mache ich mit einem alten Telefon?“ und wurde zu einer Kontrollebene für eine Hyprland-Maschine: Fenster-/Workspace-Steuerung, Szenenmakros, ein Push-to-Talk-Sprachrouter mit einem lokalen LLM-Assistenten, kontextbezogene In-App-Steuerung, bidirektionales Audio- + Bildschirm-Streaming, ein Touch-Remote-Desktop, eine virtuelle Tastatur/Maus, Dateitransfer + Telefon→PC-Freigabe und Live-Telemetrie – alles bereitgestellt als installierte PWA mit einem Phosphor-Terminal-Look.
Hinweis zur Portabilität. Dies wurde für ein bestimmtes Setup entwickelt: Arch-basiertes Linux (Garuda) + Hyprland + PipeWire + NVIDIA + Tailscale, mit den end-4 / illogical-impulse Dotfiles. Die Architektur ist generisch, aber mehrere Integrationen sind umgebungsspezifisch (Monitor-Namen, Workspace-Bindungen, der matugen-Theme-Pfad,
cpupower/nvidia-smi). Behandeln Sie es als funktionierende Referenz zur Anpassung, nicht als schlüsselfertiges Paket.
Die Benutzeroberfläche ist eine geteilte, dunkle, landschaftsorientierte Web-App (Thema synchronisiert mit Ihrem Desktop):
| Tab | Funktion |
|---|---|
| Workspaces | Live-Workspace-Raster pro Monitor (tippen zum Wechseln), Live-Fensterliste (tippen zum Fokussieren), DPMS-Umschaltung pro Monitor + ddcutil Helligkeit |
| Remote | Bildschirm-Trackpad (Ziehen/Tippen/Zwei-Finger) + virtuelle Tastatur mit Modifikatoren und Tastenkombinationen über ein Kernel-uinput-Gerät |
| Modes | One-Tap-Szenenmakros – ganze App-Layouts über Monitore starten/schließen/anordnen (z.B. „Arbeit“/„Frei“) |
| Voice | Push-to-Talk-Sprachrouter (faster-whisper, CPU): Lead-Word-Lanes – macro (führt einen Modus/Befehl aus), type (Diktieren), input (Phrase → Tastenkombination) – mit Bestätigung vor Ausführung, plus „friday“, einem schreibgeschützten lokalen LLM-Antworter (Ollama + Qwen) mit selbst gehosteter Websuche und Live-Systemstatus-Erfassung |
| Audio | Mikrofon/Lautsprecher-Stummschaltung, Lautstärke, Ausgabe- und Eingabegeräte-Auswahl, playerctl-Transport + Cover (verfolgt den aktiven MPRIS-Player) |
| Stream | Bidirektionales WebRTC-Audio (PC↔Telefon, mit Telefon-als-Mikrofon und Telefon-nur-Ausgabe) + Bildschirm-Video, und tippen zur Steuerung des gestreamten Bildschirms = ein echter Remote-Desktop |
| System | Leistungsmodus-Umschaltung, Live-Theme-Wechsel, Tailscale-Status, Top-Prozesse (tippen zum Beenden), Sperren, NetworkManager-Neustart, Aussetzen/Neustart/Ausschalten |
| Files | Screenshot eines Monitors → auf dem Telefon anzeigen/herunterladen; Datei Telefon→PC ablegen |
| Config | Bearbeiten der commands.json/modes.json (und Kontext/Sprach)-Konfiguration vom Telefon aus (JSON-validiert) |
Immer sichtbar, über den Registerkarten – ein Kontextstreifen, der anzeigt, was gerade passiert: ein aktiver Anruf (Stummschaltung / zu ihm springen), aktuell abgespielte Medien + Transport, und In-App-Tastatursteuerung für die fokussierte App (YouTube / Brave / Teams), geliefert ohne die Fokus zu stehlen.
Zwei weitere, außerhalb der Registerkarten:
Plus: Bildschirm-Numpad-PIN-Anmeldung, Bildschirm-Wake-Lock, Vollbild-Querformat-PWA und Brute-Force-Aus sperren bei der Anmeldung.
phone / laptop (browser PWA)
│ HTTPS + WSS (Tailscale-only)
▼
tailscale serve ──► FastAPI web app ── Unix socket ──► deckd
(real TLS cert) (runs as your user) (action names) (runs as root)
│ │
hyprctl · pactl · ddcutil · grim · fixed allowlist of
wf-recorder · uinput · WebRTC privileged commands
(cpupower, nvidia-smi,
systemctl, …)
Zwei Prozesse:
app/ — die Web-App läuft als Ihr normaler Benutzer. Sie erledigt alles, was kein Root benötigt: Hyprland-Steuerung, Audio, Helligkeit, Bildschirmaufnahme, virtuelle Eingabe, WebRTC-Streaming, Dateitransfer.deckd/ — ein kleiner Root-Helfer (nur stdlib, keine Abhängigkeiten) für die wenigen privilegierten Aktionen. Die Web-App sendet ihm niemals Shell-Zeichenketten – nur Aktionsnamen aus einer festen Allowlist (governor_performance, gpu_power_limit, suspend, …), validiert in deckd/actions.py, bevor etwas ausgeführt wird. Selbst wenn die Web-App vollständig kompromittiert wäre, ist die Schadenszone genau auf die allowlistierten Aktionen beschränkt, ohne Argument-Einschleusung. Der Socket ist root:<Gruppe>-Modus 0660.tailscale serve macht es unter Ihrem MagicDNS-Namen mit einem echten Let's-Encrypt-Zertifikat zugänglich; es bindet niemals an 0.0.0.0.Die Web-App kann Ihre konfigurierten Shell-Befehle ausführen und als Ihr Benutzer Eingaben senden – es ist, von Natur aus, eine Fernsteuerung für Ihren Rechner. Halten Sie sie in Ihrem Tailnet, hinter der PIN, und setzen Sie sie nicht öffentlich aus.
pactl/PulseAudio-Kompatibilität)hyprctl, pactl / pw-record / pw-play, playerctl, ddcutil,
wf-recorder, grim, cpupower, nvidia-smi, kitty (oder Ihr Terminal)input-Gruppe (für /dev/uinput) und der i2c-Gruppe (für ddcutil)aiortc + PyAV (installiert über uv) für Audio/Video-Streaminggit clone <your-repo-url> phone-deck
cd phone-deck
uv sync # creates .venv and installs dependencies
uv run python -m app.set_pin # set your unlock PIN
deckd)Bearbeiten Sie zuerst systemd/deckd.service – setzen Sie die Pfade und DECK_SOCKET_GROUP auf eine Gruppe, zu der Ihr Benutzer gehört (normalerweise Ihre primäre Gruppe):
sudo cp systemd/deckd.service /etc/systemd/system/
sudo systemctl daemon-reload && sudo systemctl enable --now deckd
deckd verwendet das System-Python (nur stdlib – kein venv erforderlich).
Starten Sie sie direkt für die Entwicklung:
uv run uvicorn app.main:app --host 127.0.0.1 --port 8765