learn · how it works

Peer-to-peer Docker control

PearDock is decentralized Docker management on the Holepunch stack. You never need to open ports, expose Docker, or worry about remote access again. You only need keys, peers, and the Engine you already run.

Key concept Your laptop and a remote Docker host talk directly over an encrypted P2P stream. No inbound firewall rules. No public dockerd. No always-on VPN. Discovery and NAT traversal use HyperDHT. Docker commands ride protomux-rpc on that stream.

Why peer-to-peer for Docker?

Docker Engine is powerful locally. Remotely, people usually open a TLS API port, maintain a VPN, or enroll hosts in a hosted panel. PearDock takes another path: treat the host as a peer you reach with a public key. No open ports, no exposed Engine, no remote-access checklist that never ends.

You can manage a home lab behind CGNAT, a VPS without punching firewall holes, or a fleet of edge machines. Peers need to complete HyperDHT hole punching (or a relay fallback), and you need the right key material.

The traditional remote-Docker model

Most “remote Docker” setups trade convenience for a large attack surface or a permanent middleman.

✕ Centralized / exposed

  • Expose dockerd TCP + TLS to the internet
  • Always-on VPN just to run docker ps
  • Hosted panel with your hosts enrolled forever
  • Single vendor outage = no ops UI

✓ PearDock peer model

  • Never open inbound ports for Docker or the control UI
  • Clients dial the public key over HyperDHT
  • Noise-encrypted RPC end to end. No VPN required.
  • You keep Docker and state on your machines
flowchart LR
  subgraph Traditional["Traditional"]
    A1[Laptop] --> VPN[VPN / open :2376 / SaaS]
    VPN --> D1[dockerd]
  end
  subgraph PearDock["PearDock"]
    A2[Desktop client] -- "HyperDHT + Noise + protomux-rpc" --> S2[peardock-server]
    S2 --> D2[dockerd]
  end
      

Identity: seeds and public keys

PearDock v2 identity is a HyperDHT keypair derived from a secret seed. It is not a shared “topic string” like some older swarm designs.

MaterialWho has itPurpose
SERVER_SEED Server only (secret) 32-byte seed; generates the listening keypair. Never share.
SERVER_PUBLIC_KEY Operators / clients 64 hex chars. Paste into the client to dial this host.
Client keys Each desktop install Peer identity for ACL, invites, and reconnect cache.

On first start the server writes SERVER_SEED and SERVER_PUBLIC_KEY to /opt/peardock/.env (mode 600) and prints the public key in the journal. Check the .env file for both values before connecting. Rotating the seed changes the public key. All clients must re-add the peer. Back up that file like any other root secret.

!
Not the same as a Holesail hs:// URL. The server public key is for PearDock control RPC. Tunnel capabilities are separate secrets created per published port.

How a client finds and connects to a server

Under the hood this is classic Holepunch connectivity: announce, look up, hole-punch (or relay), then encrypt. PearDock’s application layer starts only after that secure stream exists.

Client

Desktop app holds public key + optional invite

lookup

HyperDHT

Distributed peer discovery & signaling

announce

Server

Listens on keypair next to Docker

Announce

The server registers its presence on HyperDHT under its cryptographic identity so dialers can find a path.

Lookup & punch

The client queries the DHT, then both sides attempt coordinated UDP probes so NAT mappings open (“hole punching”).

Encrypt & RPC

A Noise-encrypted stream carries protomux-rpc methods and server→client pushes (stats, logs, events).

sequenceDiagram
  participant C as Client
  participant DHT as HyperDHT
  participant S as peardock-server
  participant D as dockerd
  S->>DHT: announce identity
  C->>DHT: lookup public key
  DHT-->>C: candidate endpoints
  C->>S: hole punch / connect
  C->>S: Noise handshake
  C->>S: protomux-rpc handshake
  S-->>C: role · protocol version
  C->>S: listContainers / deploy / …
  S->>D: dockerode
  D-->>S: result
  S-->>C: response + optional pushes
      

NAT traversal & hole punching

Most devices sit behind Network Address Translation. Routers map private IPs to public ports and block unsolicited inbound traffic. That is why “just open Docker on the internet” is a bad default, and why P2P needs help to dial home.

What hole punching does

  1. Both peers learn public endpoints via DHT-assisted signaling (not a single app-specific rendezvous you host).
  2. Simultaneous outbound probes create temporary NAT mappings toward each other.
  3. Direct path preferred when mappings cooperate (common on home NAT).
  4. Relay fallback may apply when both sides are hard symmetric NAT. Traffic stays encrypted. Relays do not get plaintext Docker commands.

Easier NAT

Open / consistent mappings → hole punching usually succeeds quickly. Typical home routers often work well.

Harder NAT / CGNAT

Symmetric NAT or carrier-grade NAT can block direct paths. The stack may need more probes or a relay. Still no need to expose dockerd publicly.

PearDock benefits from the same Holepunch/libudx generation of tools that power Hyperswarm and Holesail. You don’t configure port forwards for the control channel. You share a key. That is the whole remote-access story: no open ports, no exposed Engine, no perpetual VPN.

Control plane: protomux-rpc over HyperDHT

Once the encrypted stream is up, PearDock speaks a structured RPC protocol, not ad-hoc JSON lines. That is how the UI stays rich: typed methods, roles, and live pushes.

UI

Desktop client (Electron / Pear) for containers, registry, stacks, templates, Swarm, tunnels, terminals, and the job tray.

protomux-rpc

Request/response methods + push channels. PROTOCOL_VERSION negotiated on connect (currently 3).

HyperDHT

Peer discovery, hole punch coordination, Noise transport under the app protocol.

handlers

Server modules for containers, images, volumes, networks, stacks, Swarm, vault, registry browser, image updates, tunnels…

dockerode

Talks to local dockerd (usually the unix socket; server user in the docker group).

Client → server (examples)

Server → client pushes

Method ↔ role maps live in the shared protocol. Viewers can observe; operators mutate day-to-day; admins get destructive and policy-level actions. See RPC & API and Security.

Data plane: Holesail tunnels (optional traffic path)

Managing Docker is not the same as reaching a published web app or TCP service. PearDock keeps a second plane for that: Holesail L4 tunnels. Still no open host ports. Share an hs:// key instead of a firewall rule.

flowchart LR
  subgraph Control["Control plane"]
    UI[Client RPC]
    SRV[Server handlers]
    UI --> SRV
    SRV --> DK[Docker Engine]
  end
  subgraph Data["Data plane"]
    HC[Holesail client]
    HS[HolesailServer]
    HC -- "hs:// capability" --> HS
    HS --> Port["host:published-port"]
  end
  Control -.->|"orthogonal"| Data
      
PlaneTechnologyCarries
Control HyperDHT + protomux-rpc Docker ops, ACL, logs stream control, deploy, stats
Data / tunnels Holesail Raw TCP/UDP bytes to a published host port via hs://

Why not use only Holesail? Holesail moves bytes between sockets. It is not an RPC framework, role system, or audit log. PearDock needs structured methods and live UI channels, so control stays on protomux-rpc.

Tunnels are on by default (ENABLE_HOLESAIL=0 to disable). Treat every hs:// URL as a capability secret. Details: Holesail guide.

Security model (operator mental model)

P2P does not mean “open to the world.” It means “reachable by those who hold the right cryptographic handles.”

You still must secure Docker itself: who is in the docker group, what images you run, and how secrets enter containers. PearDock is a control surface. It inherits the power of the Engine socket it uses.

Deep dive: Threat model & hardening · Vulnerability reporting

Multi-peer fleet UX

One desktop client can keep many servers. Each peer is a separate HyperDHT identity with its own role and health.

There is no “log into PearDock cloud.” There is only: which public keys did you add, and which of those peers are online.

End-to-end: first session

From zero to a live containers list. This is the path most operators take.

flowchart TB
  A[Install peardock-server on Docker host] --> B["Read keys from /opt/peardock/.env"]
  B --> C[Install desktop client]
  C --> D[Add peer · key / seed / pd1 invite]
  D --> E[Handshake · role · protocol version]
  E --> F[listContainers · stats pushes · manage]
  F --> G{Need app traffic?}
  G -->|Yes| H[Create Holesail tunnel · share hs://]
  G -->|No| I[Stay on control plane only]
      
  1. Install the server (one-liner or binary) on a machine with Docker.
  2. Read SERVER_PUBLIC_KEY and (for admin) SERVER_SEED from /opt/peardock/.env.
  3. Install the client; Add peer with key / key+seed / full pd1. invite; wait for health.
  4. Operate: containers (updates), registry, templates, stacks, logs, terminal, Swarm, prune…
  5. Optionally tunnel a published port with Holesail for users outside the control path.

Install: Download & install · Guide: Quick start · Binaries: Releases

Glossary

HyperDHT

Distributed hash table used for peer announcements, lookups, and hole-punch coordination. Peers find each other by cryptographic identity without PearDock hosting a central directory of your fleet.

Noise / Secret Stream

Encrypted, mutually authenticated transport under HyperDHT connections. Application data (RPC) is not sent in the clear across the peer path.

protomux-rpc

RPC framework PearDock uses for named methods and server-initiated push channels over a multiplexed stream.

Hole punching

Technique where two NATed peers send coordinated outbound packets so temporary firewall mappings allow a direct path. If both sides are hostile NAT, encrypted relays may assist.

NAT / CGNAT

Network Address Translation (and carrier-grade NAT) share public IPs and block unsolicited inbound connections. That is why “open port 2376” is painful and unsafe as a default.

Public key vs SERVER_SEED

Both are written to /opt/peardock/.env on first start. The public key is what clients dial (viewer if used alone). The seed is secret server identity. Paste it with the public key for admin only. Sharing the seed is equivalent to handing over admin.

pd1. invite

Self-contained peardock share string from Access → Create invite. Embeds public key + HMAC capability so operators connect without receiving SERVER_SEED. Paste the full string in Add peer (never truncate).

Holesail / hs://

Peer-to-peer L4 reverse proxy. An hs:// URL is a capability to reach a specific tunnel endpoint. It is separate from PearDock’s Docker control key.

dockerode

Node.js Docker client used by the PearDock server to talk to the local Docker Engine API (typically via the unix socket).

Role (viewer / operator / admin)

Server-enforced permission tier for RPC methods. UI may hide actions, but the server is the authority.

Rolling release

Continuously updated binary channel used by the installer and releases page. Recommended for current peardock-server and peardock-client builds.

Ready to try it?

Install a server next to Docker, paste the public key into the client, and operate without a central control plane.