
Knocker, ein knock-basierter Zugangskontrolldienst für dein Homelab

Knocker ist ein selbstgehosteter Dienst, der ein HTTP-basiertes "Knock-Knock"-Single-Packet-Authorization-(SPA-)Gateway für dein Homelab bereitstellt, mit Web-, CLI- sowie GNOME- und Android-Clients. Es kann als Authentifizierung für deinen Reverse Proxy wie Caddy verwendet werden oder sogar auf Firewall-Ebene mithilfe der FirewallD-Integration. Es ermöglicht dir, deine Dienste vollständig privat zu halten und sie nur bei Bedarf für autorisierte IP-Adressen zu öffnen.
Dies ist ideal für Homelab-Umgebungen, in denen du Dienste im Internet verfügbar machen möchtest, ohne eine dauerhafte VPN-Verbindung, während du deine öffentlich exponierte Angriffsfläche minimierst.
Knocker-Web Statische PWA-Web-App, die das Knocking (Whitelisting) beim Neuladen unterstützt
Knocker-CLI Ein in Go geschriebenes CLI mit Unterstützung für Hintergrund-Knocks, die optional durch IP-Änderungen ausgelöst werden.
Knocker-gnome eine GNOME-Erweiterung, die auf dem Knocker-CLI aufbaut.
Knocker-EXPO Eine experimentelle Android-App, geschrieben in React EXPO mit Unterstützung für Hintergrund-Knock-Anfragen
sequenceDiagram
participant User
participant Caddy as Reverse Proxy (Caddy)
participant Knocker
participant Service as Protected Service
User->>Caddy: HTTP request to protected service
Caddy->>Knocker: GET /verify (copies X-Forwarded-For)
Knocker-->>Knocker: check always_allowed_ips / excluded_paths / whitelist
alt IP whitelisted
Knocker-->>Caddy: 200 OK (empty body)
Caddy->>Service: forward request
Service-->>Caddy: 200 OK
Caddy-->>User: 200 OK
else IP not whitelisted
Knocker-->>Caddy: 401 Unauthorized (empty body)
Caddy-->>User: 401 Unauthorized
end
Note over User,Knocker: Performing a "knock" (to add whitelist entry)
User->>Knocker: POST /knock (X-Api-Key, optional ip_address, ttl)
Knocker->>Knocker: validate API key, determine client IP
Knocker->>Knocker: update whitelist.json with expiry
Knocker-->>User: 200 OK (whitelisted_entry, expires_at, expires_in_seconds)
Dieses Projekt ist dafür ausgelegt, als Docker-Container mithilfe der bereitgestellten docker-compose.yml-Datei bereitgestellt zu werden. Es verwendet die vorgefertigten Docker-Images mit Unterstützung für AMD64, ARMv8 und ARMv7
Knocker bietet verschiedene Image-Tags für verschiedene Anwendungsfälle:
latest Neueste stabile Version (empfohlen für Produktion)v1.2.3 Spezifische Versions-Tags (gepinnte Versionen)main Entwicklungszweig (rollierende Updates, möglicherweise instabil)Konfiguration:
knocker.example.yaml in knocker.yaml um.knocker.yaml hinzu; das Beispiel enthält absichtlich keine nutzbaren Standardwerte.trusted_proxies-Liste in knocker.yaml: Sie darf nur die eigene(n) Adresse(n) des Reverse Proxys enthalten, nicht dessen Subnetz. Da Knocker X-Forwarded-For nur von einem aufgelisteten Peer vertraut, macht ein Eintrag für ein ganzes Subnetz (z. B. 172.16.238.0/24) jeden Container in diesem Netzwerk zu einer Identitätsinstanz -- jeder von ihnen könnte jede Client-IP beanspruchen oder beliebige Adressen mit einem regulären Key freischalten. Docker vergibt standardmäßig keine stabilen Container-IPs, also pinne den Proxy mit ipv4_address / ipv6_address (siehe den auskommentierten caddy-Dienst in docker-compose.yml) und liste diese exakten /32- und /128-Adressen auf.whitelist.storage_path unter dem Arbeitsverzeichnis der App, /data oder /tmp.firewalld.enabled: true setzt und die zugehörigen Einstellungen anpasst. Hinweis: Dies erfordert, dass der Container als Root läuft.Dienst starten:
docker compose up -d
Dies zieht das vorgefertigte knocker-Image und startet sowohl den knocker- als auch den caddy-Dienst.
Knocker funktioniert, indem es als Auth-Gateway für deinen Reverse Proxy agiert. Es bietet einen Verify-Endpunkt, um zu prüfen, ob die anfragende IP freigeschaltet ist oder nicht; falls nicht, antwortet es mit einem 401 und der Reverse Proxy lehnt die Verbindung ab.
Caddy hat die forward_auth-Direktive, um Verbindungen mithilfe eines Auth-Endpunkts zu prüfen.
Definiere ein wiederverwendbares Snippet: Es ist bewährte Praxis, ein Snippet in deiner Caddyfile für die Auth-Prüfung zu definieren.
Schütze deine Dienste: Importiere das Snippet für jeden Dienst, den du schützen möchtest.
Beispiel Caddyfile:
# Caddyfile
# Define a reusable snippet for the knock-knock check.
# It points to the knocker service using Docker's internal DNS.
(knocker_auth) {
forward_auth knocker:8000 {
uri /verify
}
}
# The public endpoint for performing the knock.
# Make sure this domain points to your Caddy server's IP.
knock.your-domain.com {
request_body {
max_size 4KB
}
reverse_proxy knocker:8000
}
# An example protected service.
jellyfin.your-domain.com {
import knocker_auth # Apply the forward_auth check
reverse_proxy jellyfin_service_name:8096
}
Wenn ein Benutzer nicht freigeschaltet ist, gibt Caddys forward_auth-Direktive eine 401 Unauthorized-Antwort mit leerem Body zurück.
Wichtiger Hinweis: Caddys handle_errors-Direktive funktioniert nicht mit forward_auth-Antworten. Die Fehlerantwort kommt direkt vom Authentifizierungsdienst (knocker), nicht von Caddy selbst, daher kann handle_errors diese Antworten nicht abfangen oder verändern.
Knocker bietet erweiterte Firewall-Integration über firewalld, indem es dynamische, zeitbasierte Firewall-Regeln erstellt, die basierend auf der in Knock-Anfragen angegebenen TTL automatisch ablaufen. Diese Funktion arbeitet auf Netzwerkebene und ermöglicht es dir, Knocker für Nicht-HTTP-Dienste wie SSH oder Spieleserver zu verwenden.