Default peers are read-only; admin requires seed proof and operators redeem AutoPass packages with signed grants. ACL UI and docs match the new trust model.
PearDock documentation
Complete technical documentation for the peardock codebase (v2.x / protocol version 2).
PearDock is decentralized Docker management: a HyperDHT control plane, structured protomux-rpc, a desktop client (Electron or Pear), and optional Holesail L4 tunnels. There is no SaaS broker. You share a public key; peers hole-punch and talk end-to-end encrypted.
| License | AGPL-3.0 |
| Package | peardock 2.0.1 (package.json) |
| Protocol | peardock/rpc · PROTOCOL_VERSION = 2 (shared/protocol.js) |
| Site | peardock.boats |
| Install | curl -fsSL https://install.peardock.boats | bash |
| Source | git.ssh.surf/snxraven/peardock |
Documentation map
Understanding the system
| Document | What you will learn |
|---|---|
| ARCHITECTURE.md | End-to-end design, two planes, connection lifecycle, mermaid diagrams |
| CODEBASE-MAP.md | Every top-level directory and major module, responsibilities, entry points |
| PROTOCOL.md | RPC methods, pushes, roles (MethodRoles), encodings, handshake |
| SERVER.md | Server boot, PeerSession middleware, handlers, services, persistence |
| CLIENT-UI.md | ConnectionManager, Electron vs Pear, UI views, jobs, local Holesail |
| FEATURES.md | Feature catalog by domain (containers, Swarm, tunnels, vault, …) |
Operating and shipping
| Document | What you will learn |
|---|---|
| OPERATOR.md | Install, systemd, ACL, env flags, logging, backup |
| HOLESAIL.md | Data-plane tunnels in depth |
| THREAT_MODEL.md | Assets, adversaries, controls, hardening checklist |
| RELEASE.md | Host matrix, Bare + Electron builds, rolling CI |
| SBOM.md | SBOM generation and license notes |
Product planning
| Document | What you will learn |
|---|---|
| ../ROADMAP.md | Feature tracks and status |
| ../README.md | Project overview and quick start |
One-picture overview
flowchart TB
subgraph ClientHost["Operator machine"]
UI["Desktop UI<br/>index.html + ui/ + libs/"]
CM["ConnectionManager<br/>client/manager.js"]
CONN["PearDockConnection<br/>client/connection.js"]
HL["Holesail local client<br/>client/holesailLocal.js"]
UI --> CM --> CONN
UI --> HL
end
subgraph Network["Holepunch network"]
DHT["HyperDHT<br/>discovery + Noise stream"]
end
subgraph ServerHost["Docker host"]
SRV["server/server.js<br/>DHT createServer"]
PS["PeerSession<br/>protomux-rpc"]
H["handlers/*"]
DK["dockerode → dockerd"]
HS["HolesailServer<br/>services/holesail-tunnels.js"]
SRV --> PS --> H --> DK
H --> HS
end
CONN -->|"dial public key"| DHT
DHT --> SRV
HL -.->|"hs:// data plane"| HS
HS --> PORT["127.0.0.1:published-port"]
Mental model in five minutes
1. Identity is a keypair, not a topic
The server derives a HyperDHT keypair from SERVER_SEED (persisted in .env). Clients dial the 64-character public key. This replaced v1’s Hyperswarm “topic = seed” model.
2. Control plane is structured RPC
Once the Noise-encrypted stream is up, both sides speak protomux-rpc with protocol id peardock/rpc. The client calls methods (listContainers, deployStack, …). The server may push channels (push:containers, push:allStats, push:logs, …).
3. Docker stays on the server host
All Engine access goes through dockerode on the machine running peardock-server (typically the Unix socket). The client never holds the Docker socket.
4. Two planes
| Plane | Path | Purpose |
|---|---|---|
| Control | HyperDHT + protomux-rpc | Manage Docker, ACL, audit, live UI |
| Data | Holesail hs:// |
Tunnel published TCP/UDP ports without firewall holes |
5. Capabilities are gated by role
Every method has a minimum role in MethodRoles (viewer < operator < admin). Unknown methods default to admin. Default peer role is viewer (read-only); elevate with admin seed proof, AutoPass HMAC capability, PEARDOCK_ADMIN_KEYS, or PEARDOCK_INSECURE_OPEN_ADMIN=1 for single-operator dev.
Connection lifecycle
sequenceDiagram
participant C as Desktop client
participant DHT as HyperDHT
participant S as peardock-server
participant D as dockerd
S->>DHT: listen(keyPair)
Note over S: Print SERVER_PUBLIC_KEY
C->>DHT: connect(publicKey)
DHT-->>C: secret stream (Noise)
C->>S: protomux-rpc open
C->>S: handshake { protocolVersion, adminProof? | capability? }
S-->>C: { peerId, role, protocolVersion, auth.mode }
C->>S: listContainers / deploy / …
S->>D: dockerode API
D-->>S: result
S-->>C: RPC response
S-->>C: push:containers / push:allStats / …
Client reconnect: ConnectionManager retries every 5 seconds (configurable) after unexpected drops until success or intentional disconnect. Last active peer is restored from disk cache (~/.config/peardock style paths via peerCache.js).
Repository layout (summary)
peardock/
├── shared/ # Protocol + encodings + arg schema (both sides)
├── server/ # HyperDHT control plane + dockerode
│ ├── server.js # Process entry
│ ├── core/ # Keys, ACL, audit, peer policy, vault crypto
│ ├── rpc/ # PeerSession, handler registration, binary streams
│ ├── handlers/ # One module per domain
│ ├── services/ # Docker client, events, stats, tunnels, schedules
│ └── utils/ # Logger, rate limit, compose, validation
├── client/ # Connection stack used by the UI
├── ui/ + libs/ # Desktop presentation + helpers
├── electron/ # Packaged Electron main / preload / OTA
├── index.js # Pear entry (pear-electron + holesail Bare control)
├── index.html # App shell markup
├── scripts/ # install.sh, make, rolling release, soak
├── deploy/ # systemd unit
├── test/ # brittle tests
└── docs/ # You are here
Full module-by-module guide: CODEBASE-MAP.md.
Runtime topologies
flowchart LR
subgraph Dev["Development"]
N1["node server/server.js"]
E1["npm run start:client<br/>Electron"]
P1["npm run dev<br/>Pear"]
end
subgraph Prod["Production package"]
B["peardock-server<br/>Bare binary"]
EC["peardock-client<br/>Electron app"]
SYS["systemd peardock.service"]
SYS --> B
end
E1 --> N1
P1 --> N1
EC --> B
| Mode | Server | Client |
|---|---|---|
| Dev | npm run server |
npm run start:client or npm run dev |
| Package | /opt/peardock/peardock-server |
Rolling Electron tarball / .app |
| Installer | install.peardock.boats → systemd + binary |
same script --client |
Feature flags at a glance
| Flag | Default | Surface |
|---|---|---|
ENABLE_HOLESAIL |
on | Tunnel RPC + Holesail servers |
ENABLE_SWARM |
on | Swarm services/nodes/tasks/secrets/configs |
ENABLE_PLUGINS |
off | Plugin install/enable/remove |
PEARDOCK_DEFAULT_ROLE |
admin |
Role for unknown peers |
PEARDOCK_PEER_ALLOWLIST |
off | Require registered peers |
PEARDOCK_AUDIT |
off | Append-only privileged audit log |
Details: OPERATOR.md, THREAT_MODEL.md.
Security snapshot
flowchart TB
PK["Knows public key"] --> DIAL["Can dial DHT"]
DIAL --> HS["handshake"]
HS --> AUTH{"Auth mode"}
AUTH -->|pubkey only| VIEW["viewer"]
AUTH -->|adminProof seed| ADMIN["admin"]
AUTH -->|capability AutoPass| CAP["grant role"]
VIEW --> MR["MethodRoles check"]
ADMIN --> MR
CAP --> MR
MR --> RL["Rate limiter"]
RL --> SCH["schema validateMethodArgs"]
SCH --> HND["Handler → dockerode"]
HND --> AUD["Audit if privileged"]
Hardening checklist and residual risks: THREAT_MODEL.md.
How to read this docs set
- New to PearDock? Start with this page + ARCHITECTURE.md, then OPERATOR.md.
- Implementing a feature? CODEBASE-MAP.md → domain handler under
server/handlers/→ method inshared/protocol.js→ client helper inclient/api.js→ UI inui/orlibs/. - Debugging connectivity? PROTOCOL.md handshake + CLIENT-UI.md reconnect + server logs (
LOG_FORMAT=json). - Tunnels? HOLESAIL.md + FEATURES.md.
- Shipping binaries? RELEASE.md.
Conventions used in these docs
- Paths are repo-relative unless noted.
- “Server” means the HyperDHT control-plane process (
server/server.jsor Barepeardock-server). - “Client” means the desktop app stack (
client/+ UI), packaged as Electron or run under Pear. - Mermaid diagrams render on GitHub, Gitea, and many IDEs; if not, the surrounding text still stands alone.
- Public website HTML under peardock-website is a mirror of operator docs, not the source of truth for code architecture. This
docs/tree is the code documentation.
Keeping docs honest
When you change behavior, update:
shared/protocol.js(Methods,MethodRoles,Pushes,PROTOCOL_VERSION)- The matching handler + any client API wrapper
- The relevant file in
docs/(especially PROTOCOL, FEATURES, SERVER, CLIENT-UI) - Root
README.mdif install/flags/scripts changed - Website legal/docs only if product claims change
Last aligned with codebase layout and protocol as of peardock 2.0.1 / PROTOCOL_VERSION 2.