Compare local RepoDigests to remote registry manifest digests, show status in the containers table Updates column, and support force recheck with vault credentials for private registries.
peardock
Decentralized Docker management on the modern Holepunch stack.
Share a public key. Manage containers, stacks, Swarm, logs, terminals, and tunnels over encrypted peer-to-peer connections. No central control plane, no VPN required, and no need to open inbound ports for Docker or the control UI.
| Layer | Technology |
|---|---|
| Transport | HyperDHT (Noise-encrypted P2P) |
| RPC | protomux-rpc + compact-encoding JSON |
| Server | Bare standalone binary or Node.js (dockerode) |
| Client | Electron desktop (preferred) or Pear dev shell |
| Port tunnels | Holesail (hs://, separate data plane) |
| License | AGPL-3.0 (same family as Holesail) |
Site and docs: peardock.boats · Source: git.ssh.surf/snxraven/peardock · Rolling binaries: releases
Quick start
One-line installer (recommended)
Interactive installer detects OS/arch, installs a Linux systemd server and/or a desktop client, and pulls artifacts from the rolling release:
curl -fsSL https://install.peardock.boats | bash
Non-interactive:
# Server (Linux → /opt/peardock + peardock.service + docker group)
curl -fsSL https://install.peardock.boats | bash -s -- --server --yes
# Desktop client (Linux or macOS)
curl -fsSL https://install.peardock.boats | bash -s -- --client --yes
# Both
curl -fsSL https://install.peardock.boats | bash -s -- --both --yes
After the server starts once, keys are written to /opt/peardock/.env (mode 600). Check that file first:
# Preferred: keys live in the env file after first start
sudo grep -E '^(SERVER_PUBLIC_KEY|SERVER_SEED)=' /opt/peardock/.env
# Also printed in the journal on boot
sudo journalctl -u peardock -n 80 --no-pager | grep -i 'public key'
| Variable | Use |
|---|---|
SERVER_PUBLIC_KEY |
Safe to share — paste alone for viewer (read-only) |
SERVER_SEED |
Admin only — paste with the public key for full admin; never give to operators |
Open the desktop client → Add peer:
| Paste | Access |
|---|---|
Public key only (64 hex from .env) |
Viewer (read-only) |
Public key + SERVER_SEED (from .env) |
Admin (HMAC proof; seed stays in the client session) |
| pd1. invite (from Access → Create invite) | Role granted by the invite — no seed sharing |
Clients use a stable DHT identity and auto-reconnect if the link drops.
More detail: docs/OPERATOR.md · peardock.boats/download · peardock.boats/docs/quickstart
Install from source
git clone https://git.ssh.surf/snxraven/peardock.git
cd peardock
npm install # Node.js ≥ 20
npm run server # control plane (needs Docker socket)
npm run start:client # Electron GUI (builds electron/app.bundle.cjs then launches)
You should see:
peardock server ready
Public key (viewer / read-only by default):
<64 hex characters>
Admin: paste public key + SERVER_SEED in the client.
Operators: create a pd1. invite from Access (never share SERVER_SEED).
Identity is stored in .env (or /opt/peardock/.env for package installs):
| Variable | Meaning |
|---|---|
SERVER_SEED |
Secret 32-byte seed (admin only — never share with operators) |
SERVER_PUBLIC_KEY |
Derived public key (safe to share; alone = read-only) |
SERVER_KEY |
Legacy alias for the seed (still accepted) |
PEARDOCK_INSECURE_OPEN_ADMIN |
Set 1 only for single-operator dev (everyone is admin) |
Pear development shell (optional)
# macOS: ensure pear is on PATH
export PATH="$HOME/Library/Application Support/pear/bin:$PATH"
npm run dev
# or: pear run -d .
Pear may print DEPRECATED: pear run is deprecated (platform-wide). For day-to-day operators, prefer the Electron client from the rolling release or npm run start:client.
What you get
- Full Engine surface over P2P: containers, images, volumes, networks, compose stacks, logs, stats, terminals, prune, schedules, registry vault
- Docker Swarm UI and RPC (services, nodes, tasks, secrets, configs, scale). On by default; set
ENABLE_SWARM=0to disable - Holesail tunnels for published ports without firewall holes. On by default; set
ENABLE_HOLESAIL=0to disable. See docs/HOLESAIL.md - Roles:
viewer/operator/admin(default viewer; admin via seed proof or pd1. invite) - Multi-peer fleet in one desktop client with reconnect and job tray
- Standalone binaries for six 64-bit hosts (server Bare + client Electron)
Architecture
shared/ Protocol constants + encodings (client + server)
server/
server.js Entry: HyperDHT listen
core/ Keys, peer registry, audit
rpc/ PeerSession (protomux-rpc), handler registration
handlers/ Domain methods (containers, swarm, tunnels, vault, …)
services/ Docker client, stats, metrics, event stream
utils/ Validation, rate limit, logging, compose
client/
connection.js Single HyperDHT + protomux-rpc link
manager.js Multi-server connections + persistence
api.js Typed RPC helpers
holesailLocal.js Local Holesail client (data plane)
electron/ Electron main / packaged desktop shell
ui/ + app.js + libs/ Desktop UI
assets/ Logos + favicons
peardock-branding/ Master brand package
deploy/ systemd unit
scripts/ install.sh, make, rolling release, healthcheck
Two planes (do not conflate)
| Plane | Technology | Purpose |
|---|---|---|
| Control | HyperDHT + protomux-rpc | Docker ops, ACL, logs, deploy, stats |
| Data / tunnels | Holesail | L4 proxy of host:port via hs:// |
RPC model
Client → server (examples): handshake, ping, listContainers, deployContainer, deployStack, startTerminal, scaleService, createTunnel, …
Server → client pushes: push:containers, push:allStats, push:logs, push:pullProgress, push:buildProgress, push:dockerEvent, push:terminalOutput, …
Defined in shared/protocol.js (PROTOCOL_VERSION negotiated on connect).
Deployment
- Host with Docker socket access for the service user (
peardockin groupdocker). - Process: installer Bare binary + systemd, or
node server/server.jsunder systemd/pm2. - Network: HyperDHT hole punching (UDP when possible). No need to expose Docker TCP or a public control port.
- Secrets: back up
SERVER_SEED. Rotating it changes the public key; clients must reconnect. - Client: rolling Electron package, or
npm run start:clientfrom source. - Security: Noise E2E, rate limits, roles, optional audit and peer allowlist. See docs/SECURITY_AUTH.md and docs/THREAT_MODEL.md.
- Feature flags (defaults): Swarm and Holesail on; plugins off. Opt out with
ENABLE_SWARM=0/ENABLE_HOLESAIL=0.
Canonical systemd unit: deploy/peardock.service (matches what install.sh writes).
[Unit]
Description=peardock HyperDHT Docker control plane
After=network-online.target
Wants=network-online.target
Wants=docker.service
[Service]
Type=simple
WorkingDirectory=/opt/peardock
ExecStart=/opt/peardock/peardock-server
Restart=on-failure
User=peardock
Group=docker
SupplementaryGroups=docker
Environment=NODE_ENV=production
EnvironmentFile=-/opt/peardock/.env
ReadWritePaths=/opt/peardock
[Install]
WantedBy=multi-user.target
Source-install alternative: ExecStart=/usr/bin/node /opt/peardock/server/server.js.
Standalone binaries
64-bit only: linux-x64, linux-arm64, darwin-x64, darwin-arm64, win32-x64, win32-arm64.
npm run make # all server + client hosts (same as CI)
npm run make:server:linux-x64
npm run make:client:darwin-arm64
# → out/peardock-server-<host>/ and out/peardock-<platform>-<arch>/
Gitea CI publishes tag rolling on every main build (secret RELEASE_TOKEN). See docs/RELEASE.md.
Asset patterns:
peardock-server-VERSION-HOST.tar.gz(+.sha256)peardock-client-VERSION-HOST.tar.gz(+.sha256; macOS includes a.app)
macOS clients from Linux CI are ad-hoc signed. If Gatekeeper blocks: right-click → Open, or xattr -cr ~/Applications/peardock.app. Re-sign: npm run sign:macos -- out/peardock-darwin-arm64/peardock.app.
Scripts
| Command | Description |
|---|---|
npm run server |
HyperDHT Docker control plane (Node) |
npm run start:client |
Build client bundle + Electron GUI |
npm run dev |
Pear desktop shell (dev) |
npm test |
Unit + integration tests (brittle) |
npm run healthcheck |
Docker socket health probe |
npm run soak / soak:24h |
Certification soak against Docker |
npm run make |
Cross-build all server + client hosts |
npm run make:server / make:client |
Server-only or client-only builds |
npm run sign:macos |
Ad-hoc / identity re-sign for .app |
npm run release:checksums |
Tarball + SHA-256 (+ optional GPG) |
npm run release:rolling |
Local dry-run helper for rolling publish |
Documentation
Full technical docs live under docs/ (architecture diagrams, protocol, codebase map, server/client deep dives).
| Doc | Contents |
|---|---|
| docs/README.md | Documentation hub + system overview |
| docs/ARCHITECTURE.md | Design, two planes, session lifecycle, mermaid charts |
| docs/CODEBASE-MAP.md | Directory and module map |
| docs/PROTOCOL.md | RPC methods, roles, pushes |
| docs/SERVER.md | Server internals |
| docs/CLIENT-UI.md | Client stack and desktop UI |
| docs/FEATURES.md | Feature catalog |
| docs/OPERATOR.md | Install, systemd, roles, vault, flags, logging, backup |
| docs/HOLESAIL.md | Control vs data plane, tunnel RPC, security |
| docs/SECURITY_AUTH.md | Admin seed proof, roles, pd1 invites, revoke |
| docs/THREAT_MODEL.md | Assets, trust boundaries, hardening checklist |
| docs/RELEASE.md | Host matrix, bare/Electron builds, rolling CI |
| docs/SBOM.md | SBOM generation, license notes |
| ROADMAP.md | Feature tracks and status |
| peardock.boats/docs | Public operator docs mirror |
Configuration (common env)
| Variable | Default / notes |
|---|---|
SERVER_SEED |
Generated on first start if missing |
PEARDOCK_DEFAULT_ROLE |
viewer (secure default; elevate via seed/pd1 invite) |
PEARDOCK_ADMIN_KEYS |
Comma-separated client public keys treated as admin |
PEARDOCK_INSECURE_OPEN_ADMIN |
1 only for single-operator dev (everyone admin) |
PEARDOCK_PEER_ALLOWLIST |
1 to require registered peers |
PEARDOCK_AUDIT |
1 to append privileged actions to audit log |
PEARDOCK_BROWSE_ROOTS |
Allowed host paths for file browse |
ENABLE_SWARM |
On (1); set 0 to disable Swarm RPC |
ENABLE_HOLESAIL |
On (1); set 0 to disable tunnels |
ENABLE_PLUGINS |
Off unless 1 |
PEARDOCK_MAX_TUNNELS |
20 |
LOG_LEVEL / LOG_FORMAT |
info / json recommended under journald |
Full tables: docs/OPERATOR.md.
Breaking changes from v1
| v1 (legacy) | v2 (current) |
|---|---|
Hyperswarm topic = SERVER_KEY |
HyperDHT listen on keypair from seed |
| Share topic hex with clients | Share public key with clients |
| Raw JSON on duplex streams | protomux-rpc methods + push channels |
Monolithic server.js switch |
Modular handlers under server/handlers/ |
Clients and servers are not wire-compatible across major versions.
License
GNU Affero General Public License v3.0 (AGPL-3.0).
PearDock matches Holesail (also AGPL-3.0). If you modify PearDock and let others interact with it over a network, review AGPL source-offer obligations (AGPL §13). See docs/SBOM.md and peardock.boats/legal/license.
Owned and engineered by HoneyPeer, LLC (DeKalb County, Georgia, USA). Legal: [email protected].
