17/Documentation
Bereitstellungsvarianten B–E
Andere Eingänge als der Standard: ein Identity-Aware-Proxy, ein Reverse-Proxy ohne Tailscale, ein Off-Host-Ingress, mehrere Collies auf einem Host (einer pro Benutzer oder mehrere Instanzen für einen Benutzer) und der Standby-Eingang einer Crew
Die Bridge bindet 127.0.0.1. Bereitstellungen unterscheiden sich durch Ingress und Identitätsprüfung. Variante A (einfaches tailscale serve) befindet sich in der README. Die Sicherheitsanforderungen in docs/security.md gelten für alle Varianten.
- Eingangstüren, Produkt für Produkt: Tailscale, Cloudflare Tunnel, Nginx Proxy Manager, NetBird, Caddy
Einzelne Geräte können auch ohne Proxy über Koppeln autorisiert werden.
---
Variante B: Identity-Aware-Proxy + gerätespezifische Autorisierung
Collie liest eine opake Geräte-ID aus COLLIE_DEVICE_HEADER und prüft COLLIE_DEVICE_ALLOWLIST. IDs auf der Positivliste erhalten Schreibzugriff; fehlende oder nicht gelistete IDs erhalten schreibgeschützten Zugriff (Terminal-Eingaben, Uploads und Bereichsaktionen sind blockiert). Die Kopplung ist eine zweite Hürde und immer aktiv: Jedes Gerät benötigt außerdem ein Kopplungstoken für jeden Aufruf von /api, Lesezugriffe eingeschlossen.
Collie-Konfiguration (.env):
COLLIE_HOST=127.0.0.1 # keep loopback (default)
COLLIE_DEVICE_HEADER=X-Device-Id # the header your proxy injects
# ids allowed to drive agents; others → read-only
COLLIE_DEVICE_ALLOWLIST=my-phone,my-laptop
# only if the proxy does NOT forward the public Host
# COLLIE_ALLOWED_ORIGINS=https://collie.example.com
# REQUIRED unless the proxy forwards a Host Collie already knows: loopback, a
# discovered Tailscale host, or an allowed origin's host
# COLLIE_PUBLIC_HOSTS=collie.example.com
# opt out of Host validation entirely (re-opens DNS rebinding)
# COLLIE_ALLOW_ANY_HOST=1
# COLLIE_TRUSTED_USER still composes on top if your ingress also injects
# Tailscale-User-Login
# accept a request carrying no Tailscale-User-Login at all
# COLLIE_TRUSTED_USER_OPTIONAL=1Proxy-Anforderungen:
- Gerät authentifizieren (mTLS, SSO, Forward-Auth).
- Geräte-Header überschreiben bei jeder Upstream-Anfrage, um clientseitiges Spoofing zu verhindern.
- Proxy auf Loopback (
127.0.0.1:$COLLIE_PORT). - Öffentlichen
Hostunverändert weiterleiten oder tragen Sie den öffentlichen Origin inCOLLIE_ALLOWED_ORIGINSein, um die Same-Origin-Prüfung zu bestehen.
Beispielhafte Nginx-Konfiguration:
location / {
proxy_set_header X-Device-Id $device_id;
proxy_set_header Host $host;
proxy_pass http://127.0.0.1:8787;
}Überprüfen Sie Header-Injection und -Überschreibung von einem externen Gerät aus. Jeder Aufruf von /api außer /api/health und /api/pair benötigt ein Kopplungstoken; koppeln Sie daher zuerst ein Terminal. Führen Sie auf dem Host collie pair aus. Dies gibt einen 8-stelligen Code aus. Fordern Sie den Code von dem Gerät an, mit dem Sie testen. Der Header Origin muss mit der öffentlichen URL übereinstimmen. Die Antwort enthält das Token. Speichern Sie es in einer Shell-Variable und fügen Sie es niemals in eine Datei ein:
$ collie pair # on the host; note the code it prints
$ TOKEN=$(curl -s -X POST https://collie.example.com/api/pair \
-H 'Content-Type: application/json' -H 'Origin: https://collie.example.com' \
-d '{"code":"ABCD1234","label":"header-check"}' | jq -r .token)Führen Sie dann die Header-Prüfung mit dem Token aus:
$ curl -s -H "Authorization: Bearer $TOKEN" https://collie.example.com/api/snapshot | jq -c .device
{"enforced":true,"device":"header-check","authorized":true}
$ curl -s -H "Authorization: Bearer $TOKEN" -H 'X-Device-Id: not-listed' https://collie.example.com/api/snapshot | jq -c .device
{"enforced":true,"device":"header-check","authorized":true}Mit einem Token benennt device die gekoppelte Bezeichnung (header-check), nicht den Header-Wert. Kein Feld gibt mehr den rohen Header-Wert zurück; prüfen Sie daher authorized: Es ist nur dann true, wenn der von der Bridge empfangene Header in COLLIE_DEVICE_ALLOWLIST enthalten ist und das Token gültig ist. Wenn die zweite Prüfung "authorized":false zurückgibt, hängt der Proxy den Header des Clients an, anstatt ihn zu überschreiben. Wenn Sie fertig sind, entfernen Sie das Testgerät mit collie devices revoke header-check.
Betriebshinweise:
- Direkter Loopback-Zugriff (
http://127.0.0.1:$COLLIE_PORT) sendet keinen Header, ist schreibgeschützt und benötigt dennoch ein Kopplungstoken. - Um Befehle lokal über curl auszuführen, übergeben Sie das Token und den Header explizit an Loopback:
curl -H "Authorization: Bearer $TOKEN" -H 'X-Device-Id: my-laptop' http://127.0.0.1:$COLLIE_PORT/api/... - Entziehen Sie den Zugriff, indem Sie die ID aus
COLLIE_DEVICE_ALLOWLISTentfernen und neu starten (Standalone:bin/collie restart; Herdr:herdr plugin action invoke restart --plugin herdr.collie). - Aktivieren Sie
COLLIE_DEVICE_HEADERnicht bei einfachemtailscale serve; Header werden dabei nicht überschrieben.
---
Variante C: Reverse-Proxy als einziger Eingang (kein Tailscale)
Verwenden Sie dies beim Betrieb außerhalb von Tailscale oder hinter einem dedizierten TLS/SSO-Proxy. COLLIE_SKIP_SERVE=1 verhindert, dass Collie tailscale serve verwaltet.
Die vier Proxy-Anforderungen aus Variante B gelten.
Beispielkonfiguration für Caddy:
collie.example.com {
reverse_proxy 127.0.0.1:8787 {
header_up X-Device-Id {your_device_id}
header_up Host {host}
}
}Collie-Konfiguration (.env):
# proxy is ingress; never run tailscale serve
COLLIE_SKIP_SERVE=1
# REQUIRED — Host validation fails closed, and `collie start` discovers no
# tailnet name here
COLLIE_PUBLIC_HOSTS=collie.example.com
# opt out of Host validation (re-opens DNS rebinding)
# COLLIE_ALLOW_ANY_HOST=1
# exact public origin for the same-origin gate
COLLIE_ALLOWED_ORIGINS=https://collie.example.com
COLLIE_DEVICE_HEADER=X-Device-Id # the header your proxy injects…
# …and the ids allowed to drive; others → read-only
COLLIE_DEVICE_ALLOWLIST=my-phone,my-laptop
# optional — status banner, `collie qr`, and the address a lead hands
# joining machines (crew)
# COLLIE_PUBLIC_URL=https://collie.example.comCOLLIE_TRUSTED_USER hat ohne Tailscale keine Wirkung. Header pro Gerät oder die eigene Authentifizierung des Proxys dienen als Zugriffskontrolle.
Routing für /auth/ und Caching
- Leiten Sie
/sw.jsundindex.htmlmit dem OriginCache-Control(no-cache) weiter. Blockieren Sie statische Assets für nicht authentifizierte Clients nicht, da Service-Worker sonst nicht aktualisiert werden können. - Leiten Sie Authentifizierungsabläufe unter
/auth/*weiter (oder/cdn-cgi/access/für Cloudflare Access). Service-Worker umgehen das Caching für/auth/*. - Forward-Auth-Weiterleitungen bei API-Anfragen werden als 401-Fehler behandelt, um die Login-Benutzeroberfläche anzuzeigen. Authentik-Setups sollten
/auth/an/outpost.goauthentik.io/startweiterleiten. - Ohne Proxy auf
/auth/antwortet Collie dort mit404. Die Seite weist ein nicht gekoppeltes Gerät nun an,collie pairauszuführen und den Code in den Einstellungen einzugeben. Sie leitet nie weiter, da der Pfad zu Ihrem Proxy gehört.
collie.example.com {
handle /auth/* {
reverse_proxy 127.0.0.1:9091
}
handle {
forward_auth 127.0.0.1:9091 { ... }
reverse_proxy 127.0.0.1:8787 { ... }
}
}Überprüfen Sie den Endpunkt und die Caching-Regeln. $TOKEN ist ein Kopplungstoken, angefordert wie in Variante B; authorized ist true, wenn Ihr Header auf der Positivliste steht:
$ curl -s -H "Authorization: Bearer $TOKEN" https://collie.example.com/api/snapshot | jq -c .device
{"enforced":true,"device":"header-check","authorized":true}
$ curl -sI https://collie.example.com/sw.js | grep -i '^cache-control'
cache-control: no-cache---
Variante D: Externer Identity-Proxy über das Tailnet
Verwenden Sie dies, wenn Sie Datenverkehr über einen zentralen Tailscale-Ingress-Knoten leiten.
Die Anforderungen aus Variante B gelten, mit der Ausnahme, dass der Proxy auf den Tailscale-HTTP-Endpunkt des Hosts statt auf Loopback zielt.
Tailscale-ACLs (erforderlich)
Da tailscale serve Client-Header unverändert weiterleitet, müssen Tailscale-ACLs den direkten Portzugriff ausschließlich auf den Ingress-Knoten beschränken.
Tailscale / Headscale ≥ 0.29:
"grants": [
{ "src": ["tag:ingress"], "dst": ["tag:agent-host"], "ip": ["tcp:8787"] },
]Headscale ≤ 0.28:
acls:
- action: accept
src: ["ingress-node"]
dst: ["agent-host:8787"]
- action: accept
src: ["my-phone", "my-laptop"]
dst: ["agent-host:1-8786", "agent-host:8788-65535"]Collie-Konfiguration (.env):
# proxy terminates TLS; this hop is tailnet-internal
COLLIE_SERVE_MODE=http
COLLIE_HOST=127.0.0.1 # keep loopback (default)
# header your forward-auth injects — REQUIRED here
COLLIE_DEVICE_HEADER=X-Tailnet-Device
# ids allowed to drive; others + header-less → read-only
COLLIE_DEVICE_ALLOWLIST=my-phone,my-laptop
# REQUIRED — the Host the proxy forwards. COLLIE_TAILSCALE_HOSTS carries the bare
# tailnet name `collie start` found; a rewritten Host is yours to list.
# COLLIE_ALLOW_ANY_HOST=1 opts out.
COLLIE_PUBLIC_HOSTS=host:8787,host.your-tailnet.ts.net:8787
# the public origin the browser actually uses
COLLIE_ALLOWED_ORIGINS=https://collie.example.comCOLLIE_TRUSTED_USER entspricht der Identität des Ingress-Knotens, nicht der des Endbenutzers dahinter.
Überprüfung:
Von einem Tailnet-Peer ohne Ingress. $TOKEN ist ein Kopplungstoken, angefordert wie in Variante B:
$ curl -s -H "Authorization: Bearer $TOKEN" https://collie.example.com/api/snapshot | jq -c .device
{"enforced":true,"device":"header-check","authorized":true}
$ curl -s --max-time 10 -H 'X-Tailnet-Device: my-phone' http://host.your-tailnet.ts.net:8787/api/snapshot
curl: (28) Connection timed outAuf dem Agenten-Host sendet eine Anfrage keinen Header, daher ist authorized selbst mit einem gültigen Token false:
$ curl -s -H "Authorization: Bearer $TOKEN" http://127.0.0.1:8787/api/snapshot | jq -c .device
{"enforced":true,"device":"header-check","authorized":false}---
Variante E: Jedes andere Mesh oder Tunnel (NetBird, ZeroTier, Cloudflare Tunnel)
Richten Sie den Tunnel/Proxy auf 127.0.0.1:$COLLIE_PORT aus.
Collie-Konfiguration (.env):
COLLIE_SKIP_SERVE=1 # never run tailscale serve
# REQUIRED — exact public host; Host validation fails closed and finds no
# tailnet name here
COLLIE_PUBLIC_HOSTS=collie.example.com
# exact public origin for the same-origin gate
COLLIE_ALLOWED_ORIGINS=https://collie.example.comRegeln:
COLLIE_TRUSTED_USERist ohne Tailscale inaktiv. Verwenden SieCOLLIE_DEVICE_HEADERoder die Authentifizierung des Tunnels.- Verwenden Sie einen statischen Hostnamen, damit das PWA-Caching und
COLLIE_PUBLIC_HOSTSgültig bleiben.
---
Eingangstüren, Produkt für Produkt
Grobe Konfigurationen für die Eingangstüren, nach denen häufig gefragt wird. Jede endet an derselben Stelle: HTTPS auf einem festen Hostnamen, weitergeleitet an 127.0.0.1:$COLLIE_PORT auf diesem Host.
Hinweis. Web Push, das Mikrofon und die Installation auf dem Startbildschirm erfordern HTTPS mit einem Zertifikat, dem das Telefon vertraut. Über einfaches HTTP liest und antwortet Collie weiterhin in einem Browser-Tab, und diese drei Funktionen bleiben deaktiviert (Spracheingabe und Web-Push).
Jede Eingangstür außer Tailscale verwendet dieselben drei Zeilen in Collies .env, gefolgt von einem Neustart:
COLLIE_SKIP_SERVE=1 # you own the door, not Collie
COLLIE_PUBLIC_HOSTS=collie.example.com # the hostname the phone opens
COLLIE_ALLOWED_ORIGINS=https://collie.example.com # the same, as an originFühren Sie den Proxy oder Tunnel auf demselben Host wie Collie aus. Collie weist Verbindungen ab, die nicht vom Loopback stammen. Ein Proxy auf einem anderen Rechner erfordert daher stattdessen Variante D.
Koppeln Sie das Telefon anschließend mit collie pair. Keine dieser Türen prüft, welches Gerät tippen darf; das übernimmt die Kopplung (Ein Gerät koppeln).
| Tür | Standardmäßig privat | HTTPS-Zertifikat | Zusätzlicher Schritt |
|---|---|---|---|
| Tailscale | ja, nur Tailnet | Tailscale stellt es aus | HTTPS-Zertifikate einmalig aktivieren |
| Cloudflare Tunnel | nein, öffentlich | Cloudflare stellt es aus | Cloudflare Access-Anmeldung vorgeschaltet |
| Nginx Proxy Manager | hängt vom Host ab | Let's Encrypt | Host-Netzwerk für den Container |
| NetBird | ja, nur Mesh | kein eigenes | ein Proxy auf dem Host, DNS-Challenge |
| Caddy | hängt vom Host ab | Let's Encrypt, automatisch | ein DNS-Plugin für einen privaten Namen |
Tailscale
Die Standardeinstellung und die einzige Tür, die Collie selbst verwaltet: collie start führt tailscale serve auf Ihrem MagicDNS-Namen aus.
- Öffnen Sie in der Tailscale-Admin-Konsole DNS, aktivieren Sie MagicDNS und dann HTTPS aktivieren.
- Starten Sie Collie, das sich selbst im Tailnet veröffentlicht.
collie start
- Setzen Sie
COLLIE_TRUSTED_USERin.envauf Ihr Tailnet-Login und starten Sie dann neu.collie restart
Variante A enthält den Rest. Setzen Sie COLLIE_SKIP_SERVE für diese Tür nicht.
Verwenden Sie Niemals tailscale funnel. Funnel stellt den Port ins öffentliche Internet.Cloudflare Tunnel
cloudflared stellt eine ausgehende Verbindung zu Cloudflare her, daher wird auf Ihrem Router kein Port geöffnet. Der Hostname ist öffentlich, daher muss ein Login davorstehen.
- Melden Sie sich an, erstellen Sie einen Tunnel und verweisen Sie einen Hostnamen darauf.
cloudflared tunnel login cloudflared tunnel create collie cloudflared tunnel route dns collie collie.example.com
- Schreiben Sie
~/.cloudflared/config.ymlmit der voncreateausgegebenen Tunnel-ID.tunnel: <tunnel-id> credentials-file: /home/you/.cloudflared/<tunnel-id>.json ingress: - hostname: collie.example.com service: http://127.0.0.1:8787 - service: http_status:404
- Installieren Sie ihn mit dieser Konfiguration als Dienst, damit er einen Neustart übersteht.
sudo cloudflared --config ~/.cloudflared/config.yml service install
- Fügen Sie in Cloudflare Zero Trust eine selbst gehostete Anwendung für
collie.example.comhinzu, mit einer Richtlinie, die nur Ihre E-Mail-Adresse zulässt.
Ein im Zero-Trust-Dashboard erstellter Tunnel funktioniert ebenfalls: Setzen Sie den Dienst seines öffentlichen Hostnamens auf http://127.0.0.1:8787. cloudflared leitet den öffentlichen Hostnamen als Host weiter, was COLLIE_PUBLIC_HOSTS erwartet.
Warnung. Ohne Schritt 4 erhält jeder, der den Hostnamen findet, eine Shell auf Ihrem Rechner. Cloudflare Access ist das Schloss der Tür; die Kopplung entscheidet anschließend, welches Gerät tippen darf.
- Lassen Sie Collie die Sperre prüfen. Kopieren Sie in der Access-Anwendung das Application Audience (AUD)-Tag. Fügen Sie es sowie Ihren Teamnamen in
.envein und starten Sie dann neu.COLLIE_ACCESS_TEAM=myteam # from myteam.cloudflareaccess.com COLLIE_ACCESS_AUD=<the AUD tag>Jede Anfrage über den Tunnel muss nun ein Token enthalten, das Cloudflare für diese Anwendung signiert hat. Wenn die Access-Anwendung gelöscht wird, eine Bypass-Regel erhält oder noch nicht alle Edge-Knoten erreicht hat, lehnt Collie die Anfrage ab, anstatt die Bereiche anzuzeigen. Die Prüfung der Audience ist wesentlich: Jede Access-Anwendung innerhalb eines Teams signiert mit demselben Schlüssel, daher wird auch ein Token für eine andere Anwendung abgelehnt.
Collie ruft die öffentlichen Schlüssel des Teams beim Start sowie stündlich ab. Bis der erste Abruf gelingt, erhält jede Remote-Anfrage
503. Schlägt ein späterer Abruf fehl, behält Collie die vorhandenen Schlüssel bei. Definieren Sie beide Zeilen oder keine: Eine Zeile allein führt zur Ablehnung jeder Remote-Anfrage. In jedem Fall nennt das Bridge-Protokoll das Problem in einer einzelnen Zeile; prüfen Sie daher das Protokoll nach dem Neustart.Ausschließlich ein Prozess auf diesem Rechner umgeht das Token: eine Anfrage an
127.0.0.1oderlocalhost, die wederCf-*noch einen Forwarding-Header (X-Forwarded-For,X-Forwarded-Host,X-Forwarded-Proto,Forwarded,X-Real-Ip) enthält. Zum Schreiben ist weiterhin eine Kopplung erforderlich./api/healthund die Crew-Links benötigen ebenfalls kein Token.collie doctorist ein solcher lokaler Aufrufer; ein grüner Status bei doctor belegt daher weder das Laden der Schlüssel noch die Gültigkeit eines Tokens. Rufen Sie den Hostnamen vom Smartphone aus auf, um dies zu überprüfen. ADR 0081 erläutert die Hintergründe.Beachten Sie diese Regeln bei aktivem Gate:
- Nur ein Eingang gleichzeitig. Wenn Access aktiviert ist, benötigt eine Anfrage über
tailscale serve, Caddy oder Traefik ebenfalls ein Token, da diese standardmäßig einen Weiterleitungs-Header hinzufügen. Ein Rechner, der sowohl einen Tunnel als auch einen Tailnet-Namen (tailscale serve) bereitstellt, verliert den Tailnet-Zugang für Browser: Diese Anfragen enthalten kein Access-Token und erhalten401. - Kein zweiter Proxy zwischencloudflaredund Collie, der Anfragen lokal erscheinen lässt. Einer, derHostin127.0.0.1oderlocalhostumschreibt und dieCf-*- sowie Weiterleitungs-Header entfernt, tut dies absichtlich. Ein reines nginxproxy_pass http://127.0.0.1:8787tut dies standardmäßig: Es sendetHost: 127.0.0.1:8787und fügt keinen Weiterleitungs-Header hinzu, sofern Sie keinen konfigurieren. Diese Anfragen überspringen das Token. Richten Siecloudflareddirekt auf Collie aus. - Fügen Sie keine Access-Bypass-Regeln für Collie-Pfade hinzu, nicht für das Manifest, den Service-Worker oder die Icons. Access fügt das Token jeder Anfrage hinzu, die es durchlässt. Ein umgangener Pfad enthält kein Token, daher antwortet Collie mit401.
Access leitet zum Anmelden auf /cdn-cgi/access/ um. Halten Sie sw.js und index.html ungecacht, wie in Routing für /auth/ und Caching beschrieben.
Nginx Proxy Manager
Ein Reverse-Proxy mit Web-UI und integriertem Let's Encrypt. Er läuft in Docker, und innerhalb eines Containers ist 127.0.0.1 der Container, nicht Ihr Host.
- Weisen Sie dem Container das Host-Netzwerk zu, damit er Collie über Loopback erreichen kann.
services: npm: image: jc21/nginx-proxy-manager:latest network_mode: host volumes: - ./data:/data - ./letsencrypt:/etc/letsencrypt
- Öffnen Sie die Benutzeroberfläche auf Port 81 und fügen Sie einen Proxy Host hinzu: Domain
collie.example.com, Schemahttp, Weiterleitung an127.0.0.1, Port8787. - Fordern Sie auf dem Reiter SSL ein Let's-Encrypt-Zertifikat an und aktivieren Sie SSL erzwingen.
Lassen Sie Assets zwischenspeichern deaktiviert, damit der Service-Worker aktualisiert werden kann. Collie pollt über einfaches HTTP, daher spielt der Schalter Websockets-Unterstützung keine Rolle.
Für einen Namen, der nur innerhalb Ihres Netzwerks aufgelöst wird, wählen Sie Eine DNS-Challenge verwenden auf dem SSL-Reiter. Let's Encrypt kann einen privaten Host nicht über HTTP erreichen.
Warnung.host.docker.internalmithost-gatewayfunktioniert hier nicht. Es erreicht die Docker-Bridge-Adresse, und Collie lauscht ausschließlich auf127.0.0.1.
Wenn der Proxy für das Internet offen ist, fügen Sie dem Proxy-Host eine Zugriffsliste hinzu, oder lassen Sie die Ports 80 und 443 auf dem Router geschlossen und erreichen Sie den Host über ein VPN.
NetBird
NetBird ist ein WireGuard-Mesh, ähnlich wie ein Tailnet. Es überträgt den Datenverkehr, und ein Reverse-Proxy auf dem Host stellt HTTPS bereit.
- Fügen Sie den Host und das Telefon demselben NetBird-Netzwerk hinzu.
netbird up
- Leiten Sie einen DNS-Eintrag für
collie.example.comauf die NetBird-Adresse des Hosts (100.x.y.z). - Führen Sie Caddy auf dem Host aus, gebunden an diese Adresse, mit einem DNS-Challenge-Zertifikat.
collie.example.com { bind 100.x.y.z tls { dns cloudflare {env.CF_API_TOKEN} } reverse_proxy 127.0.0.1:8787 }
Die DNS-Challenge weist nach, dass Sie die Domäne besitzen, ohne dass Let's Encrypt den Host erreichen muss; der Name kann also auf eine private Adresse verweisen. Caddy benötigt das DNS-Plugin für Ihren Anbieter, beispielsweise xcaddy build --with github.com/caddy-dns/cloudflare.
Ein NetBird-Peer-Name wie host.netbird.cloud besitzt kein öffentlich vertrauenswürdiges Zertifikat; verwenden Sie daher eine Domäne, die Sie besitzen. Das gleiche Vorgehen funktioniert für ZeroTier oder jedes andere Mesh.
Caddy
Caddy bezieht und erneuert sein Zertifikat selbst. Auf einem Host, der auf den Ports 80 und 443 erreichbar ist, genügt diese Konfiguration:
collie.example.com {
reverse_proxy 127.0.0.1:8787
}Fügen Sie für einen privaten Namen den Block tls { dns … } aus NetBird oben ein. Ein öffentlicher Host benötigt zudem eine vorgeschaltete Anmeldung, wie in Variante C.
---
Collie unter einem Pfad bereitstellen
Ein einziger Release-Build bedient jeden Einhängepfad. Setzen Sie den Pfad in der Instanz-.env (oder [serve] base_path in config.toml), starten Sie neu, und die Bridge stellt die Anwendung, ihre Assets und /api/* unter diesem Pfad bereit:
# https://<your-node>/collie/ — leading and trailing slash both optional; the bridge adds them
COLLIE_BASE_PATH=/collieAkzeptiert: /collie, collie/, /apps/collie/. Abgelehnt, mit einer Zeile im Protokoll und Verwendung des Wurzelverzeichnisses stattdessen: ein .- oder ..-Segment, Leerraumzeichen, ?, #. collie doctor gibt den Einhängepfad in der Zeile front-door aus.
Mit dem standardmäßigen Haupteingang veröffentlicht collie serve (und jedes collie start) tailscale serve --set-path=/collie/ statt des Wurzelverzeichnisses, sodass eine andere Anwendung / auf demselben Knoten behalten kann. Tailscale entfernt den Einhängepfad vor dem Weiterleiten, und die Bridge akzeptiert auch Anfragen, die ihn noch enthalten; ein Reverse-Proxy funktioniert daher auf beide Weisen. Um Ihre Konfiguration zu prüfen:
curl -s https://<your-node>/collie/api/health # JSON, not HTML, means the mount is rightHängen Sie die Bridge hinter Ihrem eigenen Proxy (Variante C) unter demselben Pfad ein. Caddy: handle_path /collie/* { reverse_proxy 127.0.0.1:8787 }. Nginx: location /collie/ { proxy_pass http://127.0.0.1:8787/; }. Wenn Sie COLLIE_PUBLIC_URL setzen, binden Sie den Pfad ein: https://collie.example.com/collie/.
Eine Änderung des Einhängepfads ist eine neue Anwendung auf dem Telefon. Gültigkeitsbereich und Identität der installierten PWA entsprechen dem Pfad, von dem aus sie installiert wurde. Entfernen Sie nach dem Ändern von COLLIE_BASE_PATH oder dem Zurückwechseln auf das Wurzelverzeichnis das Startbildschirm-Symbol und fügen Sie es von der neuen Adresse aus erneut hinzu; das alte verweist weiterhin auf einen Pfad, den die Bridge nicht mehr bedient. Die Bridge selbst benötigt lediglich einen Neustart, und collie serve verschiebt den Eingang selbstständig: Sie hebt die Zuordnung auf, die ihr Eintrag benennt, bevor sie die neue veröffentlicht.
---
Mehrere Collies auf einem Host
Um unabhängige Instanzen pro Benutzer auf einem gemeinsam genutzten System zu hosten (ADR 0001):
# ~/.config/herdr/plugins/config/herdr.collie/.env — one per Unix user
# this user's loopback bridge port — unique per user
COLLIE_PORT=8801
# this user's tailnet https listener — unique per user
COLLIE_SERVE_PORT=8443
COLLIE_TRUSTED_USER=dev-a@example.com # only this tailnet login may drive these agentsURL-Prüfung für eigenständige Binärdatei: bin/collie url. URL-Prüfung für Herdr-Plugin: herdr plugin action invoke url --plugin herdr.collie.
Voraussetzungen:
- Verwenden Sie getrennte Unix-Benutzer und separate Instanzen von
herdr/Collie. - Setzen Sie
COLLIE_TRUSTED_USERimmer, um den Zugriff pro Port einzuschränken. - Initiale Tailscale-Bindungen erfordern eine Konfiguration durch den Operator: Führen Sie
bin/collie serve(oder das Herdr-Äquivalent) mit Operator-Rechten aus.
COLLIE_SERVE_PORT legt den Eingangsport für eine Instanz fest. COLLIE_INSTANCE erstellt eine isolierte Instanz mit eigener Service-Unit und Konfiguration auf demselben Host (Mehrere Collie-Instanzen auf einem Host).
---
Mehrere Collie-Instanzen auf einem Host
Verwenden Sie dieses Setup, um ein zweites, separates Collie auf derselben Maschine auszuführen. Beispiele sind der Betrieb einer stabilen Version neben einer Arbeitskopie oder die Ausführung eines zweiten Multiplexers (tmux/zellij) neben dem von Herdr verwalteten Standard. Jede Instanz erhält einen dedizierten Port, eine Konfiguration, ein Zustandsverzeichnis und eine Service-Unit. Dies unterscheidet sich von Mehrere Collies auf einem Host, wo eine Instanz pro Unix-Benutzer zugewiesen wird. Hier führt ein Benutzer mehrere Instanzen aus.
Die zweite Instanz erstellen
Setzen Sie COLLIE_INSTANCE=<name>, um die Instanz zu benennen. Der Name muss [a-z0-9-]{1,16} entsprechen. Eine benannte Instanz erfordert zudem einen expliziten COLLIE_PORT. Das CLI bricht mit einem Fehler ab, wenn dieser Port fehlt; es leitet keinen Standardwert ab.
Erstellen Sie ~/.config/herdr/plugins/config/herdr.collie-<name>/.env:
COLLIE_INSTANCE=<name> # required — [a-z0-9-], max 16 chars
COLLIE_PORT=8788 # required for a named instance — no default is inferred
# Unset, this defaults to ~/.local/state/collie, with no instance suffix
COLLIE_STATE_DIR=/home/you/.local/state/collie-<name>COLLIE_INSTANCE, COLLIE_PORT und COLLIE_STATE_DIR können sich alle in dieser .env-Datei befinden. Die zusammengeführte Umgebung löst die Instanz auf. HERDR_PLUGIN_CONFIG_DIR überschreibt das Verzeichnis, in dem das CLI nach der Konfiguration sucht.
Eine Service-Unit pro Instanz ausführen
collie start schreibt die Unit, wenn die Umgebung die Instanz festlegt. Der Operator schreibt sie nicht von Hand. Unter macOS schreibt es stattdessen eine launchd-plist unter ~/Library/LaunchAgents/. Die Unit setzt COLLIE_PORT, COLLIE_INSTANCE, COLLIE_PLUGIN_ROOT, HERDR_PLUGIN_CONFIG_DIR und EnvironmentFile=-<config dir>/.env. --instance <name> auf ExecStart existiert einzig, damit zwei Instanzen, die sich ein Binary teilen, ihre Bridges unterscheiden können (cli/unit.ts systemdUnit()):
ExecStart=<root>/bin/collie _exec-bridge --instance <name>
Environment=COLLIE_PORT=8788
Environment=COLLIE_INSTANCE=<name>
Environment=COLLIE_PLUGIN_ROOT=<root>
Environment=HERDR_PLUGIN_CONFIG_DIR=<config dir>
EnvironmentFile=-<config dir>/.envDas CLI verwaltet eine instanzspezifische tailscale serve-Handler-Datei, sodass die Ausführung von unserve auf einer Instanz das Mapping für eine andere nicht löscht.
Eine benannte Instanz über das CLI ansteuern
Jedes CLI-Verb (pair, devices, url, qr, crew …, logs, push-test, …) ermittelt seine Zielinstanz aus der Prozessumgebung. Setzen Sie COLLIE_INSTANCE, bevor Sie das Verb aufrufen:
COLLIE_INSTANCE=next bin/collie pair
COLLIE_INSTANCE=next bin/collie devices listOhne COLLIE_INSTANCE fragt das CLI Herdr ab. Herdr erfasst nur das Plugin ohne Suffix, daher wird der Befehl für die erste Instanz ausgeführt. Setzen Sie COLLIE_INSTANCE immer explizit, wenn Sie mehrere Instanzen auf einem Host ausführen, um Änderungen an der falschen Instanz zu vermeiden.
Die Verweigerungsregel
Wenn COLLIE_INSTANCE gesetzt ist, aber herdr.collie-<name>/.env fehlt, bricht das CLI mit einem Fehler ab. Es greift nicht auf die Konfiguration einer anderen Instanz zurück.
Kopplung erfolgt pro Instanz
collie pair schreibt einen Kopplungscode in das Zustandsverzeichnis dieser Instanz. Der ausgegebene QR-Code kodiert die eigene URL dieser Instanz, da jede Instanz ihr eigenes Zustandsverzeichnis und über COLLIE_PUBLIC_URL oder ihren eigenen Port einen eigenen Zugang hat. Öffnen Sie die spezifische URL dieser Instanz auf dem Smartphone und geben Sie den Code unter Einstellungen → System → Gekoppelte Geräte ein. Ein für eine Instanz erstellter Code kann kein Gerät mit einer anderen Instanz koppeln (Ein Gerät koppeln).
---
Der Standby-Eingang: der Failover-Pfad einer Crew
Für Crew-Bereitstellungen. Konfiguriert einen vorab autorisierten deputy zur Übernahme, falls das lead unerreichbar wird (ADR 0027, ADR 0028, CREW_PROTOCOL.md §18).
Einstellungen für deputy und lead:
| Schlüssel | Standard | Funktion |
|---|---|---|
COLLIE_STANDBY_PORT | (nicht gesetzt) | Port für den Standby-Listener. Nicht gesetzt deaktiviert die Standby-Tür. Muss auf Lead und deputy übereinstimmen. |
COLLIE_STANDBY_HOST | 127.0.0.1 | Bind-Adresse (127.0.0.1 für lokale Proxys, Overlay-IP für Remote). |
COLLIE_STANDBY_ARM_MS | max(30000, 2.5 × COLLIE_POLL_IDLE_MS) | Erforderliche Dauer der Lead-Inaktivität vor dem Scharfschalten. |
Setzen Sie COLLIE_STANDBY_PORT sowohl auf dem Lead als auch auf dem deputy auf einen identischen, ungenutzten Port.
Die Voraussetzung: ein Hostname, zwei Backends
Lead und deputy müssen vom selben Ursprung bereitgestellt werden, um die PWA-Registrierung und die Geräteanmeldedaten zu teilen. Eine eigenständige Crew ohne einheitlichen Ingress stellt sich über bin/collie promote (oder Herdr: herdr plugin action invoke promote --plugin herdr.collie; CREW_PROTOCOL §14.4) wieder her.
Beispielkonfiguration für Traefik:
http:
routers:
collie:
rule: "Host(`collie.example.com`)"
service: collie-crew
tls: {}
services:
collie-crew:
failover:
service: collie-lead
fallback: collie-deputy
collie-lead:
loadBalancer:
servers:
- url: "http://lead.internal:8787"
healthCheck:
path: /standby/health
interval: 5s
timeout: 2s
collie-deputy:
loadBalancer:
servers:
- url: "http://deputy.internal:8788" # COLLIE_STANDBY_PORT
healthCheck:
path: /standby/health
interval: 5s
timeout: 2sAntworten der Zustandsprüfung: Lead gibt 200 zurück (ungleich 200, wenn abgesetzt); deputy gibt 503 zurück, bis er scharfgeschaltet ist, danach 200.
Einmalig einrichten, solange das System fehlerfrei läuft
Standalone-Einrichtung auf dem Lead:
bin/collie pair
bin/collie crew deputy nas
bin/collie crew statusHerdr-Einrichtung auf dem Lead:
herdr plugin action invoke pair --plugin herdr.collie
herdr plugin action invoke crew --plugin herdr.collie deputy nas
herdr plugin action invoke crew --plugin herdr.collie statusKonfigurieren Sie auf dem deputy COLLIE_STANDBY_PORT=8788 und starten Sie neu. Stellen Sie sicher, dass alle Peers neu starten, um den deputy warrant zu laden. Überprüfen Sie dies unter https://collie.example.com/standby.
⚠️ Der deputy muss überwacht werden
Bei einer Übernahme schreibt der deputy den Status und beendet sich mit dem Statuscode 75 (EX_TEMPFAIL), um einen Prozessneustart (bridge/index.ts) auszulösen.
Stellen Sie sicher, dass der Supervisor bei Beendigungscodes ungleich null neu startet (systemd: Restart=always oder Restart=on-failure).
Der Ernstfall: das Betriebshandbuch
- Öffnen Sie
https://collie.example.com. - Wenn der Lead fehlerhaft ist, leitet der Proxy zu
/standbyweiter. - Prüfen Sie den Standby-Status des deputy.
- Wählen Sie Übernehmen aus.
- Der deputy überprüft den Peer-Konsens, wendet den warrant an und beendet sich mit
75. - Der Supervisor startet den Prozess neu; die PWA lädt sich als neuer Lead neu.
Nach der Wiederherstellung:
- Aktualisieren Sie die Peer-Adresse des abgesetzten Knotens: Standalone
bin/collie crew set-address <member> <host:port>oder Herdrherdr plugin action invoke crew --plugin herdr.collie set-address <member> <host:port>. - Weisen Sie einen neuen deputy zu: Standalone
bin/collie crew deputy <member>oder Herdrherdr plugin action invoke crew --plugin herdr.collie deputy <member>. - Führen Sie
crew rotateerst aus, wenn alle Mitglieder die Verbindung wiederhergestellt haben.
Diese Seite auf GitHub bearbeiten