peardock
Decentralized Docker management on the modern Holepunch stack.
| Layer | Technology |
|---|---|
| Transport | HyperDHT (Noise-encrypted P2P) |
| RPC | protomux-rpc + compact-encoding JSON |
| Client | Pear desktop app |
| Docker | dockerode |
No central control plane. The server announces a keypair on the DHT; clients connect with its public key.
Quick start
One-line installer (recommended)
Interactive installer — detects OS/arch, asks server vs client, installs a Linux systemd service for the server or a desktop client for your platform:
curl -fsSL https://git.ssh.surf/snxraven/peardock/raw/branch/main/scripts/install.sh | bash
Non-interactive examples:
# Server (Linux systemd → peardock.service)
curl -fsSL https://git.ssh.surf/snxraven/peardock/raw/branch/main/scripts/install.sh | bash -s -- --server --yes
# Desktop client only
curl -fsSL https://git.ssh.surf/snxraven/peardock/raw/branch/main/scripts/install.sh | bash -s -- --client --yes
Downloads artifacts from the rolling release (peardock-server-* / peardock-client-*).
1. Install from source
npm install
# Node.js ≥ 20 required
2. Run the server (machine with Docker)
npm run server
You will see:
peardock server ready
Public key (paste into the client):
<64 hex characters>
Keep this process running. Identity is stored in .env:
| Variable | Meaning |
|---|---|
SERVER_SEED |
Secret 32-byte seed (never share) |
SERVER_PUBLIC_KEY |
Derived public key (share with clients) |
SERVER_KEY |
Legacy alias for the seed (still accepted) |
3. Run the desktop client
Ensure the Pear binary is on your PATH (one-time):
# macOS
export PATH="$HOME/Library/Application Support/pear/bin:$PATH"
# make permanent in fish:
# fish_add_path "$HOME/Library/Application Support/pear/bin"
Then:
npm run dev
# or: pear run -d .
Paste the public key into the sidebar connection field.
Note: Pear may print
DEPRECATED: pear run is deprecated. That is a platform-wide message. This app uses the supported pear-electron + pear-bridge entry (index.js) so it is not a legacy HTML app. Long-term OTA packaging uses hello-pear-electron /pear-runtime.
Production Pear app
pear stage .
pear release .
pear run pear://<your-app-key>
Standalone binaries (CI / release)
64-bit only: linux-x64, linux-arm64, darwin-x64, darwin-arm64, win32-x64, win32-arm64.
# Everything CI ships (cross-compile server + client for all hosts)
npm run make
# Or one target:
npm run make:server:linux-x64
npm run make:client:win32-arm64
# → out/peardock-server-<host>/ and out/peardock-<platform>-<arch>/
Gitea CI (Ubuntu) cross-builds all of those hosts and publishes tag rolling (secret RELEASE_TOKEN). See docs/RELEASE.md.
Architecture
shared/ Protocol constants + encodings (both sides)
server/
server.js Entry: HyperDHT listen
core/ Keys, peer registry
rpc/ PeerSession (protomux-rpc), handler registration
handlers/ Domain methods (containers, images, volumes, …)
services/ Docker client, stats, 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
app.js + libs/ Pear UI
assets/ App logos + favicons (from peardock-branding/)
build/icon.* Electron package icons (.png / .icns / .ico)
peardock-branding/ Master brand package (source of truth)
RPC model
Client → server methods (examples): handshake, ping, listContainers, killContainer, containerTop, deployContainer, pruneImages, getSystemDf, startTerminal, …
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). See ROADMAP.md for coverage and remaining work.
Deployment
- Host — Linux/macOS with Docker socket access for the server user.
- Process —
systemd/pm2/ Docker supervisingnode server/server.js. - Network — HyperDHT holepunches; allow UDP when possible. Bootstrap peers are built into
hyperdht. - Secrets — Back up
SERVER_SEED. Rotating seed changes the public key; clients must reconnect. - Pear — Stage/release the desktop app separately from the control-plane server.
- Security — Connections are E2E encrypted (Noise). Rate limits apply per peer. RPC methods are gated by role (
viewer/operator/admin; default admin). Privileged actions append to an audit log. Docker CLI is allow-listed to read-only style commands. Optional env:PEARDOCK_DEFAULT_ROLE,PEARDOCK_ADMIN_KEYS,PEARDOCK_BROWSE_ROOTS,PEARDOCK_AUDIT. - Holesail tunnels (on by default) — Expose published container/host ports over Holesail
hs://keys (separate from control-plane RPC). Opt out withENABLE_HOLESAIL=0. See docs/HOLESAIL.md. Note: the requiredholesaildependency is AGPL-3.0.
Example systemd unit:
[Unit]
Description=peardock HyperDHT server
After=docker.service
Requires=docker.service
[Service]
WorkingDirectory=/opt/peardock
ExecStart=/usr/bin/node server/server.js
Restart=on-failure
Environment=NODE_ENV=production
[Install]
WantedBy=multi-user.target
Scripts
| Command | Description |
|---|---|
npm run server |
Start HyperDHT Docker control plane |
npm run dev |
Pear desktop app (dev) |
npm test |
Unit + fuzz + load + integration tests |
npm run healthcheck |
Docker socket health probe |
npm run soak / soak:24h |
Certification soak against Docker |
npm run release:checksums |
Release tarball + SHA-256 (+ optional GPG) |
See ROADMAP.md (complete) and docs/ for operators, threat model, and releases.
Dependencies (current)
hyperdht^6.33protomux-rpc^1.10protomux^3.11compact-encoding^3.3b4a^1.8hypercore-crypto^3.7dockerode^5dotenv^17graceful-goodbye^1.3
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/ |
License
Apache-2.0
