From c3009b4a1bdc383b36682ff475ad3287db4a4f50 Mon Sep 17 00:00:00 2001
From: Raven Scott On connect, the client calls Never share
As admin (public key +
Settings → Peers manages client-side saved hosts (public keys, aliases).
- Server-side ACL — invites, revoke, roles — stays under Access.
+ Server-side ACL for invites, revoke, and roles stays under Access.
Pull and push stream layer events over Handshake
handshake. The server returns:
-
diff --git a/docs/faq.html b/docs/faq.html
index f6d8bee..5a9a33c 100644
--- a/docs/faq.html
+++ b/docs/faq.html
@@ -124,8 +124,8 @@
PROTOCOL_VERSION (currently 3 — HMAC auth with capability + adminProof)PROTOCOL_VERSION (currently 3, HMAC auth with capability and adminProof)peerId for this connection (stable client public key hex)auth.modeContainers
@@ -200,7 +200,7 @@
listContainers, inspectContainer, start, stop, kill, restart, pause/unpausecheckImageUpdates — compare local image digests to remote registry manifests (viewer)checkImageUpdates: compare local image digests to remote registry manifests (viewer)deployContainer (supports alwaysPull), recreateContainer, updateContainer, duplicateContainerremoveContainer — graceful stop (short grace + kill fallback) before delete so force-remove does not hangremoveContainer: graceful stop (short grace then kill fallback) before delete so force remove does not hangbulkContainerOperation, containerTop, archive, renamestartTerminal / terminal I/O; getContainerLogs / log followlistInvites, invitePeer, deleteInvite,
revokePeer, unrevokePeer, listRevokedPeers,
- clearRevokedPeers, setPeerRole — admin only
+ clearRevokedPeers, setPeerRole (admin only)
(invite strings are secrets)
What do I share with clients?
-
SERVER_PUBLIC_KEY only (64 hex) — read-only.SERVER_SEED (from the same .env) — never send the seed over chat to operators.SERVER_PUBLIC_KEY only (64 hex). Read-only.SERVER_SEED from the same .env. Never send the seed over chat to operators.pd1.… invite from Access → Create invite (embeds key + capability; no seed).SERVER_SEED with operators.SERVER_SEED in Add peer), open Access → Create invite
and copy the full string starting with pd1.. The operator pastes that entire string in Add peer.
- Public key and HMAC capability are embedded — no Autopass/RocksDB and no seed sharing.
- Invites can be persistent (default) or limited by TTL / max uses. Revoke peers from Access when devices are lost.
+ Public key and HMAC capability are embedded. No Autopass or RocksDB. No seed sharing.
+ Invites can be persistent (default) or limited by TTL or max uses. Revoke peers from Access when devices are lost.
Deep dive: Security model.
Where did Peers go? Where are saved hosts?
What does the Updates column on containers mean?
@@ -226,7 +226,7 @@ npm run sign:macos -- out/peardock-darwin-arm64/peardock.app
push:pullProgress /
push:pushProgress. The desktop job tray aggregates them into hybrid overall
- progress, phase labels, and a fixed-height layer track — not a single misleading percentage.
+ progress, phase labels, and a fixed-height layer track. Not a single misleading percentage.
How do I update?
diff --git a/docs/index.html b/docs/index.html
index 9caee6e..6b5b6ac 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -171,7 +171,7 @@
The server listens on a HyperDHT keypair. Clients connect with its public key.
Transport is Noise-encrypted. The desktop UI is an Electron (or Pear) app with a full
Engine surface: containers, registry browser, templates, stacks, Swarm, job tray,
- and Holesail tunnels — without SaaS tenancy or remote-access headaches.
+ and Holesail tunnels. No SaaS tenancy. No remote access headaches.
SERVER_PUBLIC_KEYSERVER_SEEDSERVER_SEEDpd1.… invite string (never truncate).pd1. invite in Add peer — the client decodes public key + HMAC capability and connects with the granted role (no seed, no RocksDB/Autopass).pd1. invite in Add peer. The client decodes public key and HMAC capability, then connects with the granted role (no seed, no RocksDB or Autopass).Credentials are encrypted at rest (AES-GCM; KDF is Bare-safe). - The desktop app has a top-level Registry view — not under Access. + The desktop app has a top-level Registry view. It is not under Access.
/opt/peardock/.env. Open that file (or grep it) before connecting:
- # Preferred — both keys after first start
+ # Preferred: both keys after first start
sudo grep -E '^(SERVER_PUBLIC_KEY|SERVER_SEED)=' /opt/peardock/.env
# or: sudo cat /opt/peardock/.env
@@ -190,7 +190,7 @@ sudo journalctl -u peardock -n 80 --no-pager | grep -i 'public key'
SERVER_SEED
- Admins only — never give to operators
+ Admins only. Never give to operators.
Paste with the public key → admin
@@ -247,7 +247,7 @@ flowchart LR
Public key only (SERVER_PUBLIC_KEY) Viewer (read-only)
Public key + SERVER_SEED (from the same .env) Admin
- Full pd1.… invite (from Access → Create invite) Role in the invite — no seed sharing
+ Full pd1.… invite (from Access → Create invite) Role in the invite. No seed sharing.
PearDock is a self-hosted P2P Docker control plane. There is no central login. Anyone who knows the server public key can attempt a HyperDHT dial. - That alone must not mean full Docker control — so the default role is viewer (read-only). + That alone must not mean full Docker control. The default role is viewer (read-only).
[Desktop client] --Noise/HyperDHT--> [peardock-server] --unix socket--> [dockerd]
|
@@ -147,7 +147,7 @@
Public key only (SERVER_PUBLIC_KEY) Viewer (read-only)
Public key + SERVER_SEED Admin (seed never sent on the wire)
- Full pd1.… invite Role in the invite — no seed sharing
+ Full pd1.… invite Role in the invite. No seed sharing.
@@ -228,8 +228,8 @@
4. Handshake elevation
Baseline role (usually viewer) is resolved from env / admin keys / peer policy. Then handshake may elevate:
- - adminProof — seed ownership → admin
- - capability — HMAC grant from a
pd1. invite (or direct token)
+ - adminProof: seed ownership maps to admin
+ - capability: HMAC grant from a
pd1. invite (or direct token)
- Otherwise stay at baseline
@@ -247,7 +247,7 @@
Optional: PEARDOCK_ADMIN_KEYS (fixed admin peer ids),
PEARDOCK_DEFAULT_ROLE, PEARDOCK_PEER_ALLOWLIST=1,
- PEARDOCK_INSECURE_OPEN_ADMIN=1 (dev only — everyone is admin).
+ PEARDOCK_INSECURE_OPEN_ADMIN=1 (dev only; everyone is admin).
5. Admin seed proof
@@ -305,10 +305,10 @@
7. Registration, reconnect, revoke
State lives in peardock-peers.json (override with PEARDOCK_PEER_POLICY):
- peers — registered elevated client identities for reconnect
- capabilities — active grants (by jti)
- spentJtis — deleted or exhausted grants
- revoked — hard ban list of peer ids
+ peers: registered elevated client identities for reconnect
+ capabilities: active grants (by jti)
+ spentJtis: deleted or exhausted grants
+ revoked: hard ban list of peer ids
After a successful elevate, reconnect can use the registered role even if that invite jti is later deleted.
diff --git a/download.html b/download.html
index c3f9a1c..5a669c1 100644
--- a/download.html
+++ b/download.html
@@ -147,12 +147,12 @@ curl -fsSL https://install.peardock.boats | bash -s -- --both --yes
Installs binary to /opt/peardock/peardock-server
Creates system user peardock and adds it to the docker group (for /var/run/docker.sock)
Writes /etc/systemd/system/peardock.service and optionally enables it
- Creates /opt/peardock/.env (mode 600) — check this file after first start for your keys
+ Creates /opt/peardock/.env (mode 600). Check this file after first start for your keys.
sudo systemctl status peardock
sudo journalctl -u peardock -f
-# After first start — keys are in .env (preferred)
+# After first start, keys are in .env (preferred)
sudo grep -E '^(SERVER_PUBLIC_KEY|SERVER_SEED)=' /opt/peardock/.env
# SERVER_PUBLIC_KEY → share for viewer / paste in client
diff --git a/index.html b/index.html
index b5589f9..20f6201 100644
--- a/index.html
+++ b/index.html
@@ -3,8 +3,8 @@
- PearDock · Decentralized Docker management
-
+ PearDock · P2P Docker ops without open ports
+
@@ -27,8 +27,8 @@
-
-
+
+
@@ -38,8 +38,8 @@
-
-
+
+
@@ -136,8 +136,10 @@
+
+
@@ -152,47 +154,118 @@
- v2 · HyperDHT · AGPL-3.0
+ v2 · Live job tray · AGPL-3.0
- Docker ops without
- opening ports
+ Remote Docker that
+ never needs a port
- Peer-to-peer Docker management on the Holepunch stack.
- Share a public key, then manage containers, stacks, and tunnels over encrypted P2P.
- Never open ports, expose Docker to the internet, or worry about remote access again.
- No SaaS. No VPN. No inbound firewall rules.
+ PearDock is a peer-to-peer ops console for Docker on HyperDHT.
+ Connect with a public key, then run containers, stacks, terminals, and tunnels over Noise-encrypted RPC.
+ No open ports. No VPN. No SaaS middleman.
+
+
+ Identity is a keypair
+ Share a 64-hex public key. Nothing listens on a public Docker port.
+
+
+ Ops that feel local
+ Dashboard, terminals, image updates, stacks, and registry vault in one dark UI.
+
+
+ Progress you can trust
+ Multi-step job tray with hybrid layer pull and push. Not a spinner and a prayer.
-
+
-
-
+
+
+
+
+
+
+ Job tray
+ Activity
+
+ Pull nginx:latest…
+
+
+
+
+
+
+
+
+ Product tour
+ The real console, animated
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Overview
+ Dashboard
+ Live engine health, storage, and activity on the active peer
+
+
+
+ Deploy
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Engine
+
+ Version27.0.2
+ Containers5
+ Running5
+ Images10
+ Storage driveroverlay2
+
+
+
+ Host
+
+ Memory10.74 GB
+ CPU cores8
+ Operating systemUbuntu 26.04 LTS
+ Architecturex86_64
+ Kernel7.0.0-27-generic
+
+
+
+ Disk
+
+ Image layers3.57 GB
+ Images (10)3.57 GB
+ Containers (5)50.85 MB
+ Volumes (16)30.95 MB
+ Build cache0 B
+
+
+
+ Live events
+
+ 04:22:09startcontainer vpn
+ 04:22:09exechealthcheck vpn
+ 04:22:04diecontainer vpn
+ 04:21:59createcontainer api
+
+
+
+
+
+
+
+
+
+
+ Dashboard that stays live
+ KPI strip, Engine, Host, Disk, live Docker events, and quick actions. This is the same shell operators use after connect. Counts and events update continuously in this demo.
+
+ - Connection health: latency, Docker version, role
+ - Disk bars from
systemDf style metrics
+ - Event timeline streaming from the active peer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Pull image
+ nginx:latest
+
+
+
+ Closing in 3s…
+ 1/4
+ running
+
+
+
+
+
+
+ Resolve & authenticate
+
+
+
+
+ Pull layers (hybrid progress)
+
+
+
+
+ Create container
+
+
+
+
+ Start & publish ports
+
+
+
+
+
+ Resolving
+
+ …
+
+
+
+
+ …
+ …
+ …
+ …
+
+
+ Resolving image nginx:latest…
+
+
+ Live output
+
+
+
+
+
+
+
+ Hybrid pull, real layer UI
+
+ The same job panel as the app. You get a step timeline, overall bar, layer pip track, and four fixed layer slots with per layer download and extract bars. Waiting count and activity line follow. Create and start run after the pull.
+
+
+ - Per-layer MB progress (download → extract)
+ - Pip track colors: wait / download / extract / done
+ - Stable height while pulling (no layout jump)
+ - Live log lines under the progress card
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name
+ State
+ Image
+ Ports
+ Updates
+ Actions
+
+
+
+
+ vpn
+ running
+ gluetun:latest
+ none
+
+
+
+
+ apache-httpd
+ running
+ httpd:latest
+ 8080→80
+
+
+
+
+ api
+ running
+ ghcr.io/app:1.4
+ 3000→3000
+
+
+
+
+ worker
+ exited
+ node:20
+ none
+
+
+
+
+ redis
+ running
+ redis:7.0.7
+ 6379→6379
+
+
+
+
+
+
+
+
+
+
+
+ Containers with update digests
+ State badges, published ports, and the Updates column (✓ up to date, ↑ pull available). Matches the real list, with terminal and logs actions per row.
+
+ - Registry digest compare for each tag
+ - Click ↑ to pull via the job tray
+ - Bulk actions and role-gated remove
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Restoring connections
+ Reconnecting to your saved servers over HyperDHT…
+
+
+ Dialing HyperDHT…
+
+
+
+
+
+
+
+
+
+
+ Boot restore, not a blank splash
+ On launch the client re-dials saved peers with live status and progress. It lands on the dashboard when a peer is online.
+
+ - Last-active peer preferred
+ - Auto-reconnect every 5s if the link drops
+ - pd1 invites for operator access without sharing the seed
+
+
+
+
+
+
@@ -232,9 +689,9 @@
Features
Full Engine coverage.
Zero ports to open.
- Containers, images, volumes, networks, stacks, Swarm, terminals, logs, GitOps,
- registry browser + vault, image update checks, Portainer-style templates,
- roles, and Holesail tunnels in a desktop console built for real ops.
+ Containers, images, volumes, networks, stacks, Swarm, terminals, logs, and GitOps.
+ Registry browser and vault. Image update checks. Portainer-style templates. Roles and Holesail tunnels.
+ All in a desktop console built for real ops.
Remote Docker without port forwards, public dockerd, or a permanent VPN.
@@ -243,17 +700,17 @@
No ports. No VPN.
- Server identity is a HyperDHT keypair. Share the public key; peers holepunch. Nothing phones home, nothing listens on a public Docker port.
+ Server identity is a HyperDHT keypair. Share the public key. Peers holepunch. Nothing phones home. Nothing listens on a public Docker port.
Noise encryption
- Every control connection is end-to-end encrypted. Roles (viewer, operator, admin), allowlists, pd1 invites, and audit logging help multi-operator fleets stay safe.
+ Every control connection is end-to-end encrypted. Roles cover viewer, operator, and admin. Allowlists, pd1 invites, and audit logging help multi-operator fleets stay safe.
Docker ops console
- Deploy templates, add containers, recreate, prune, stack env files, image update indicators, secrets/configs, and schedules. Built for real operators.
+ Deploy templates. Add containers. Recreate and prune. Stack env files, image update indicators, secrets, configs, and schedules. Built for real operators.
@@ -263,7 +720,7 @@
Desktop client
- Electron (or Pear) with multi-peer fleet, multi-step job tray and hybrid pull progress, live stats, terminals, and OTA-ready packaging.
+ Electron or Pear. Multi-peer fleet. Multi-step job tray with hybrid pull progress. Live stats, terminals, and OTA-ready packaging.
@@ -281,18 +738,37 @@
-
+
- Architecture
- Two planes. Still zero open ports.
+ How it works
+ Keys, peers, Docker.
Still zero open ports.
Control traffic uses HyperDHT and protomux-rpc. Service access uses Holesail.
- Both are peer-to-peer. No inbound firewall rules. No public Docker API.
+ Both are peer-to-peer.
+ No inbound firewall rules. No public Docker API.
+
+
+ 1
+ Run the server
+ On a host with Docker, install via one-liner or binary. Identity is a HyperDHT keypair printed at start: SERVER_PUBLIC_KEY and seed.
+
+
+ 2
+ Launch the client
+ Electron desktop (or Pear). Paste a public key, key + seed, or a pd1. invite. Multi-peer fleet lives in the sidebar.
+
+
+ 3
+ Operate
+ Deploy, terminal, logs, stacks, registry, tunnels. Long work streams through the job tray with real progress.
+
+
+
@@ -322,7 +798,7 @@
Control plane
- Handshake, containers (including image update checks), deploy stacks and templates, logs, stats pushes, terminal streams, registry vault + remote browser, and peer policy. Protocol version is negotiated on connect.
+ Handshake, containers (including image update checks), deploy stacks and templates, logs, and stats pushes. Terminal streams, registry vault, remote browser, and peer policy. Protocol version is negotiated on connect.
Data / tunnels
@@ -343,8 +819,8 @@
Fleet
- Multi-peer. Multi-host. One client.
- Connect to many servers at once. Tag environments (prod / staging / lab). Switch contexts without losing job history or health signals. Manage saved hosts under Settings → Peers; server ACL under Access.
+ Multi-peer. Multi-host.
One client.
+ Connect to many servers at once. Tag environments (prod / staging / lab). Switch contexts without losing job history or health signals. Manage saved hosts under Settings → Peers. Server ACL lives under Access.
- Peer disk cache under
~/.config/peardock
- Connection health badge: latency, Docker status, role
@@ -361,7 +837,7 @@
Operations
Deploy like you mean it.
- Portainer-style templates and blank Add container. Compose stacks with env files and overrides. Image update indicators. System prune. Volume file browser. Multi-step job tray with hybrid pull progress.
+ Portainer-style templates and blank Add container. Compose stacks with env files and overrides. Image update indicators, system prune, and volume file browser. Multi-step job tray with hybrid pull progress. See the demo.
- Container and stack templates; always-pull on create / duplicate
- GitOps-friendly stack deploy; remove cleans project networks
@@ -377,16 +853,16 @@
Tunnels
- Share a service, never open a port.
+ Share a service.
Never open a port.
Create a Holesail tunnel from a container or host port. Copy the hs:// URL.
Remote peers bind locally. You never punch a firewall hole or expose Docker to the internet.
- No inbound port forwards. P2P hole punching instead.
- - Secure mode by default (capability ≠ raw listen key)
- - SSRF guard: loopback / allowlisted hosts only
- - Max concurrent tunnels · audited create/close
+ - Secure mode by default (capability is not a raw listen key)
+ - SSRF guard: loopback and allowlisted hosts only
+ - Max concurrent tunnels. Audited create and close.
Holesail guide →
@@ -432,8 +908,8 @@
Quick start
Install in one line. Connect in three steps.
- No public IP gymnastics, no open ports, no VPN checklist.
- Interactive installer pulls rolling binaries, wires Linux systemd + docker group for the server, or installs a desktop client.
+ No public IP gymnastics. No open ports. No VPN checklist.
+ The interactive installer pulls rolling binaries. It wires Linux systemd and the docker group for the server, or installs a desktop client.
@@ -488,5 +964,6 @@ curl -fsSL https://install.peardock.boats | bash -s -- --client --yes
+