Eine schlanke Wake-on-LAN-Weboberfläche für den Heimgebrauch – mit modernem Passkey-Login (Fingerabdruck / Face ID) statt nur Passwort. Ein Ordner PHP, keine Datenbank, kein Composer, keine Build-Tools: hochladen, Passwort setzen, fertig.
Vom Smartphone aus: Seite öffnen → Finger auflegen → Rechner aufwecken.
Drei umschaltbare Designs (Standard ist Hell):
| Hell | Dunkel | Bunt |
|---|---|---|
![]() |
![]() |
![]() |
| Login mit Passkey | Geräte verwalten | Passkeys verwalten | Sicherung |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
- 🖥️ Wake on LAN: weckt Rechner im Heimnetz per Magic Packet (UDP-Broadcast, zur Sicherheit an mehrere Adressen und Ports); ist eine IP hinterlegt, meldet die Seite anschliessend, sobald das Gerät erreichbar ist
- 🔐 Login-Schutz: Passwort-Login mit Sperre nach zu vielen Fehlversuchen
- 👆 Passkeys (WebAuthn): Anmeldung per Fingerabdruck/Face ID, pro Gerät registrierbar; auf bekannten Geräten startet die Abfrage beim Öffnen der Seite automatisch - pro Gerät abschaltbar, wenn man sich dort lieber mit dem Passwort anmeldet
- 🎨 Drei Designs: Hell, Dunkel und Bunt – jederzeit über den Umschalter oben rechts wählbar, die Wahl wird pro Browser gemerkt
- 🌍 Mehrsprachig: Deutsch, Englisch, Französisch und Spanisch, umschaltbar im Hamburger-Menü; beim ersten Besuch wird die Browsersprache erkannt. Weitere Sprachen sind leicht ergänzbar (siehe Sprache hinzufügen)
- 📱 Für Smartphones optimiert: grosse Buttons, antippbare Gerätekacheln, Navigation im Hamburger-Menü
- ⚙️ Geräteverwaltung im Browser: Zielgeräte (Name, MAC, IP) hinzufügen, nachträglich ändern und entfernen, ohne Dateien zu editieren
- ⏰ Zeitgesteuertes Aufwecken: pro Gerät Uhrzeit und Wochentage festlegen, z.B. Mo–Fr um 07:30. Läuft das Gerät schon, passiert nichts (braucht die Hintergrundprüfung)
- 📜 Verlauf: wer wann welches Gerät aufgeweckt hat, Anmeldungen und Fehlversuche, Online-/Offline-Wechsel sowie Änderungen an Geräten und Passkeys
- ⏱️ Laufzeit-Anzeige: jede Gerätekachel zeigt, seit wann das Gerät läuft oder aus ist (genau mit eingerichteter Hintergrundprüfung)
- 💾 Sicherung & Wiederherstellung: Konfiguration und Laufzeitdaten als ZIP herunterladen und bei Bedarf wieder einspielen
- 🔁 Reverse-Proxy-tauglich: funktioniert hinter gängigen Reverse Proxies (Nginx Proxy Manager, Traefik, Caddy, der Reverse-Proxy in Synology DSM u.ä.)
- 🗂️ Keine Datenbank: alle Daten liegen in selbstschützenden Dateien im Ordner
auth/
- PHP 8.0 oder neuer mit den Extensions openssl und sockets (kein mbstring, kein Composer nötig)
- Ein Webserver (Apache, nginx, Caddy, ... – oder ein fertiges Paket wie XAMPP, ein Docker-PHP-Image oder die Web Station eines NAS)
- HTTPS mit gültigem Zertifikat – ohne HTTPS verweigert der Browser Passkeys
- Der Server muss im selben LAN stehen wie die aufzuweckenden Geräte (Magic Packets sind Broadcasts und verlassen das lokale Netz nicht – ein gemieteter Webspace im Internet funktioniert daher nicht)
- Docker: nur mit
network_mode: host, sonst kommen die Broadcasts nicht ins LAN
Tipp: Am einfachsten das fertige Installations-ZIP von der Releases-Seite herunterladen (
wol-passkey-<version>.zip). Es enthält nur die für den Betrieb nötigen Dateien – ohne Screenshots, Entwicklungs-Dateien usw. Der „Source code"-Download enthält dagegen das komplette Projekt und ist für die Installation nicht nötig.
- Das Installations-ZIP herunterladen, entpacken und den Inhalt des Ordners in ein Verzeichnis des Webservers hochladen
config.sample.phpnachconfig.phpkopieren und anpassen:$setup_key: einen eigenen langen Zufallswert eintragen (z.B. aus dem Passwort-Manager). Wer diesen Schlüssel kennt, kann das Login-Passwort zurücksetzen – geheim halten!$networkbroadcast: Broadcast-Adresse des Heimnetzes (Netz192.168.1.x→192.168.1.255)$maclist: optional erste Zielgeräte eintragen (später bequem über die Weboberfläche pflegbar)
- Dem Webserver-Benutzer Schreibrechte auf den Ordner
auth/geben (Linux z.B.chown www-data auth/bzw.chmod; bei einem NAS über den Datei-Manager dem Web-Benutzer, meist Gruppehttp, Lese-/Schreibrecht geben) https://deine-domain/setup.phpaufrufen, Setup-Schlüssel eingeben und Login-Passwort setzen- Anmelden und unter „Passkey verwalten" den Fingerabdruck des Geräts registrieren – ab dann geht der Login ohne Passwort
Auf einem Proxmox-Host gibt es eine Abkürzung. Ein Aufruf auf der Host-Shell legt einen Debian-Container mit nginx und PHP-FPM an, installiert die App, erzeugt einen zufälligen Setup-Schlüssel und leitet die Broadcast-Adresse aus dem Subnetz des Containers ab:
COMMUNITY_SCRIPTS_URL=https://raw.githubusercontent.com/brunoz78/ProxmoxVED/main bash -c "$(curl -fsSL https://raw.githubusercontent.com/brunoz78/ProxmoxVED/main/ct/wol-passkey.sh)"Der Setup-Schlüssel wird am Ende angezeigt; danach direkt mit Schritt 4 oben
weiter. Spätere Updates laufen mit update im Container. Die
Hintergrundprüfung ist im Container bereits eingerichtet.
Das Script nutzt das Framework von community-scripts,
liegt aber in einem eigenen Fork und ist nicht Teil der offiziellen
Sammlung. Aufbau und Hintergründe: proxmox/README.md.
Damit die App weiss, seit wann ein Gerät läuft oder aus ist und damit
Zeitpläne ausgeführt werden, muss cron.php einmal pro Minute laufen – auch
wenn niemand die Seite offen hat. Ohne diese
Prüfung wird der Status nur bei Seitenaufrufen erfasst; die Kacheln zeigen
dann „seit spätestens …", und der Verlauf weist darauf hin.
-
Proxmox-LXC (Script oben): bereits eingerichtet, als systemd-Timer
wol-passkey-check.timer -
Linux-Server, VM, Raspberry Pi: als Webserver-Benutzer in die Crontab eintragen, z.B. mit
sudo crontab -u www-data -e:* * * * * php /var/www/wol-passkey/cron.php -
NAS mit Aufgabenplaner (z.B. Synology DSM): eine regelmässig wiederholte Aufgabe mit demselben Befehl anlegen, wenn möglich als Webserver-Benutzer (bei Synology
http). Je nach PHP-Paket heisst der Befehl z.B.php82stattphp. -
Docker: per Cron auf dem Host, z.B.
* * * * * docker exec -u www-data <container> php /var/www/html/cron.php
Nicht als root ausführen: Sonst gehören die Datendateien in auth/ danach
root, und die Webseite kann sie nicht mehr ändern. cron.php verweigert in
diesem Fall den Start.
Zeitzone prüfen: Ohne Einstellung läuft PHP oft auf UTC, ein Zeitplan
„07:30" wäre in Mitteleuropa dann erst um 09:30 dran. Die Seite „Zeitplan"
zeigt unten die Serverzeit an. Stimmt sie nicht, in der config.php
$timezone = "Europe/Zurich"; eintragen (leer = Zeitzone des Servers).
Nach dem Login zeigt die App automatisch einen Hinweis an, sobald auf GitHub eine neuere Version veröffentlicht wurde (Prüfung höchstens 1x täglich, rein informativ – es wird nichts automatisch heruntergeladen oder installiert). Ein Klick auf den Hinweis führt zur Releases-Seite.
So aktualisierst du von Hand:
- Das neue Installations-ZIP von der Releases-Seite herunterladen und entpacken
- Den Inhalt des Ordners auf den Webserver hochladen und dabei alle vorhandenen Dateien überschreiben
- Fertig –
config.phpsowie die selbst erzeugten Daten inauth/(data.php,devices-data.php,log-data.php,status-data.php) sind nicht im Installations-ZIP enthalten und bleiben unangetastet; Login-Passwort, Passkeys, Geräteliste und Verlauf bleiben erhalten
Ein Blick ins CHANGELOG.md lohnt sich vor dem Update.
Im Hamburger-Menü unter „Sicherung" lässt sich config.php sowie die
Laufzeitdaten (Login-Passwort, Passkeys, Geräteliste) als ZIP herunterladen -
praktisch vor einem Update, einem Server-Umzug oder einfach als
Sicherheitsnetz. Die ZIP-Datei enthält den Setup-Schlüssel und das
Passwort-Hash und sollte entsprechend sicher aufbewahrt werden.
Über dieselbe Seite lässt sich eine zuvor heruntergeladene ZIP-Datei auch
wieder einspielen; enthält sie nur einzelne Dateien, bleiben die übrigen
unangetastet. Das setzt die PHP-Extension zip voraus - fehlt sie, zeigt die
Seite einen entsprechenden Hinweis.
Passkeys sind an die Domain gebunden, die im Browser steht. Damit der Server diese Domain kennt, muss der Proxy zwei Header mitschicken:
Nginx Proxy Manager (Custom Location bzw. Advanced-Tab):
location / {
proxy_pass http://192.168.1.10/wol/;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}Bei anderen Reverse Proxies dieselben zwei Header setzen. Beispiel
Synology DSM: Systemsteuerung → Anmeldeportal → Erweitert → Reverse Proxy →
Eintrag bearbeiten → Benutzerdefinierte Kopfzeile → X-Forwarded-Host = $host
und X-Forwarded-Proto = $scheme.
Ohne diese Header erscheint bei der Passkey-Registrierung die Fehlermeldung „The relying party ID is not a registrable domain suffix of, nor equal to the current domain".
Wichtig: Ein Passkey gilt nur für die Domain, unter der er registriert wurde. Die Seite also immer über dieselbe Adresse aufrufen (Lesezeichen!).
-
Die Anwendung ist bewusst ein Ein-Benutzer-System für den Heimgebrauch: ein gemeinsames Passwort, eine gemeinsame Passkey-Liste – keine Benutzerkonten, keine Rollen
-
config.php(enthält den Setup-Schlüssel) niemals veröffentlichen; sie steht deshalb in der.gitignore -
Die Datendateien in
auth/(Passwort-Hash, Passkey-Schlüssel, Geräteliste) schützen sich selbst gegen direkten Web-Zugriff (403). Die mitgelieferten.htaccess-Dateien blockieren die Ordner auf Apache zusätzlich; auf nginx empfiehlt sich analog:location ~ ^/(auth|lib|lang)/ { deny all; }
-
Nach 5 falschen Passwort-Versuchen wird das Login 5 Minuten gesperrt (einstellbar in
auth/config.php) -
Passwort vergessen?
setup.phpaufrufen und mit dem Setup-Schlüssel ein neues setzen
Die Texte liegen als einfache PHP-Arrays im Ordner lang/. Eine neue Sprache
braucht keine Code-Änderung an den Seiten:
-
lang/de.phpnachlang/<code>.phpkopieren (z.B.lang/fr.php) -
Die Texte rechts vom
=>übersetzen -
Den Code in
auth/i18n.phpbeii18n_languages()eintragen:return [ 'de' => 'Deutsch', 'en' => 'English', 'fr' => 'Français', ];
Fehlt in einer Sprachdatei ein Text, wird automatisch der deutsche verwendet (Deutsch ist die Ausgangssprache). Die gewählte Sprache wird in einem Cookie gemerkt; beim ersten Besuch entscheidet die Browsersprache, sonst Englisch.
Das Installations-ZIP (nur die für den Betrieb nötigen Dateien) wird mit einem mitgelieferten Skript erzeugt – plattformübergreifend mit korrekten Vorwärts-Schrägstrichen (wichtig fürs Entpacken auf Linux/NAS):
php tools/build-release.php 1.0.1Ergebnis: dist/wol-passkey-1.0.1.zip. Das Skript schliesst automatisch die
geheime config.php, Screenshots und Entwicklungs-Dateien aus und bricht ab,
falls versehentlich ein Geheimnis im Archiv landen würde. Die Versionsnummer im
Dateinamen ist das Argument.
Anschliessend an ein GitHub-Release anhängen – entweder über die Weboberfläche (Releases → Draft/Edit release → Datei ins „Attach binaries"-Feld ziehen) oder per Kommandozeile:
gh release create v1.0.1 dist/wol-passkey-1.0.1.zip --title "v1.0.1" --notes "…"
# oder an ein bestehendes Release anhängen:
gh release upload v1.0.1 dist/wol-passkey-1.0.1.zip- Ursprüngliches WOL-Skript: © 2014 Barry Schiffer, erweitert von Manuel Azevedo
- WebAuthn-Bibliothek: lbuchs/WebAuthn
(MIT-Lizenz, im Ordner
lib/webauthn/enthalten) - Icon: Streamline Icons Free Pack via Iconfinder
MIT – siehe LICENSE.






