Update site for .env keys and pd1 connection invites.
Quick start, operator, security, FAQ, download, home, and learn pages now point operators at /opt/peardock/.env for public key and seed, and document viewer / admin / pd1. invite roles.
This commit is contained in:
@@ -221,8 +221,9 @@ sequenceDiagram
|
||||
<h2>Security surfaces</h2>
|
||||
<ul>
|
||||
<li>Noise transport (HyperDHT)</li>
|
||||
<li>Roles: viewer / operator / admin + method ACL</li>
|
||||
<li>Optional peer allowlist + invites</li>
|
||||
<li>Roles: viewer (default) / operator / admin + method ACL</li>
|
||||
<li>Elevate via <code>SERVER_SEED</code> proof or self-contained <code>pd1.</code> invites</li>
|
||||
<li>Optional peer allowlist + revoke</li>
|
||||
<li>Rate limits per peer</li>
|
||||
<li>Audit log for privileged methods</li>
|
||||
<li>Registry vault AES-GCM (keyed from seed)</li>
|
||||
|
||||
+35
-6
@@ -123,11 +123,35 @@
|
||||
</p>
|
||||
|
||||
<h2>What do I share with clients?</h2>
|
||||
<p>The server <strong>public key</strong> (64 hex characters). Never share <code>SERVER_SEED</code>.</p>
|
||||
<ul>
|
||||
<li><strong>Viewers:</strong> <code>SERVER_PUBLIC_KEY</code> only (64 hex) — read-only.</li>
|
||||
<li><strong>Admins:</strong> public key + <code>SERVER_SEED</code> (from the same <code>.env</code>) — never send the seed over chat to operators.</li>
|
||||
<li><strong>Operators:</strong> a full <code>pd1.…</code> invite from Access → Create invite (embeds key + capability; no seed).</li>
|
||||
</ul>
|
||||
<p>Never share <code>SERVER_SEED</code> with operators.</p>
|
||||
|
||||
<h2>Where is the public key after install?</h2>
|
||||
<pre><code>sudo journalctl -u peardock -n 80 --no-pager | grep -i 'public key'</code></pre>
|
||||
<p>Also stored under <code>/opt/peardock/.env</code> as <code>SERVER_PUBLIC_KEY</code> when generated.</p>
|
||||
<h2>Where are the public key and seed after install?</h2>
|
||||
<p>
|
||||
After the first successful start, both are written to
|
||||
<code>/opt/peardock/.env</code>. <strong>Check that file:</strong>
|
||||
</p>
|
||||
<pre><code>sudo grep -E '^(SERVER_PUBLIC_KEY|SERVER_SEED)=' /opt/peardock/.env
|
||||
# or: sudo cat /opt/peardock/.env
|
||||
|
||||
# Public key also appears in the journal
|
||||
sudo journalctl -u peardock -n 80 --no-pager | grep -i 'public key'</code></pre>
|
||||
<p>
|
||||
<code>SERVER_PUBLIC_KEY</code> is safe to share for viewer access.
|
||||
<code>SERVER_SEED</code> is admin-only. Keep <code>.env</code> mode 600 and back it up offline.
|
||||
</p>
|
||||
|
||||
<h2>How do invites work?</h2>
|
||||
<p>
|
||||
As admin (public key + <code>SERVER_SEED</code> in Add peer), open <strong>Access → Create invite</strong>
|
||||
and copy the full string starting with <code>pd1.</code>. 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.
|
||||
</p>
|
||||
|
||||
<h2>Container list empty / “permission denied” on Docker</h2>
|
||||
<p>The service user <code>peardock</code> needs the docker group:</p>
|
||||
@@ -159,8 +183,13 @@ npm run sign:macos -- out/peardock-darwin-arm64/peardock.app</code></pre>
|
||||
<h2>Can I run without Holesail?</h2>
|
||||
<p>Yes: <code>ENABLE_HOLESAIL=0</code> in the server environment. Control-plane Docker management still works.</p>
|
||||
|
||||
<h2>Default role is admin. Is that safe?</h2>
|
||||
<p>Convenient for a single trusted operator. For multi-operator fleets, set <code>PEARDOCK_DEFAULT_ROLE</code>, <code>PEARDOCK_ADMIN_KEYS</code>, and allowlist. See <a href="/docs/security">threat model</a>.</p>
|
||||
<h2>Default role is viewer. How do I get admin?</h2>
|
||||
<p>
|
||||
Public key alone is <strong>viewer</strong> (read-only). For admin, paste
|
||||
<code>SERVER_PUBLIC_KEY</code> + <code>SERVER_SEED</code> from <code>/opt/peardock/.env</code>
|
||||
in Add peer. For multi-operator fleets, create <code>pd1.</code> invites instead of sharing the seed.
|
||||
Optional: <code>PEARDOCK_ADMIN_KEYS</code>, allowlist. See <a href="/docs/security">threat model</a>.
|
||||
</p>
|
||||
|
||||
<h2>v1 vs v2</h2>
|
||||
<p>v1 used Hyperswarm topics and raw JSON streams. v2 uses HyperDHT keypairs, public keys, and protomux-rpc. Clients and servers are not wire-compatible across major versions.</p>
|
||||
|
||||
@@ -158,6 +158,9 @@
|
||||
</div>
|
||||
<p>
|
||||
Interactive installer: server (Linux + systemd + docker group) or desktop client.
|
||||
After the server starts, check <code>/opt/peardock/.env</code> for
|
||||
<code>SERVER_PUBLIC_KEY</code> and <code>SERVER_SEED</code>, then connect from the desktop client
|
||||
(public key = viewer, key + seed = admin, or a full <code>pd1.</code> invite for operators).
|
||||
See <a href="/docs/quickstart">Quick start</a> and <a href="/download">Download</a>.
|
||||
</p>
|
||||
|
||||
|
||||
+41
-9
@@ -111,8 +111,26 @@
|
||||
<pre><code>curl -fsSL https://install.peardock.boats | bash -s -- --server --yes</code></pre>
|
||||
<p>This installs the Bare server binary, creates user <code>peardock</code>, adds it to the <strong>docker</strong> group, writes a systemd unit, and can enable the service immediately.</p>
|
||||
<pre><code>sudo systemctl status peardock
|
||||
sudo journalctl -u peardock -f
|
||||
# copy public key from logs into the desktop client</code></pre>
|
||||
sudo journalctl -u peardock -f</code></pre>
|
||||
|
||||
<h3>Check <code>/opt/peardock/.env</code> for your keys</h3>
|
||||
<p>
|
||||
After the first successful start, identity is written to the env file (mode 600).
|
||||
<strong>Always check this file</strong> for both values:
|
||||
</p>
|
||||
<pre><code>sudo grep -E '^(SERVER_PUBLIC_KEY|SERVER_SEED)=' /opt/peardock/.env
|
||||
# or: sudo cat /opt/peardock/.env</code></pre>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>Variable</th><th>Who</th><th>Client paste</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td><code>SERVER_PUBLIC_KEY</code></td><td>Safe to share</td><td>Alone → <strong>viewer</strong></td></tr>
|
||||
<tr><td><code>SERVER_SEED</code></td><td>Admins only — never share with operators</td><td>With public key → <strong>admin</strong></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p>Full flags and client install: <a href="/download">Download & install</a>.</p>
|
||||
|
||||
<h2>Paths (installer defaults)</h2>
|
||||
@@ -123,7 +141,7 @@ sudo journalctl -u peardock -f
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td><code>/opt/peardock/peardock-server</code></td><td>Server binary</td></tr>
|
||||
<tr><td><code>/opt/peardock/.env</code></td><td>Identity / env (mode 600)</td></tr>
|
||||
<tr><td><code>/opt/peardock/.env</code></td><td><code>SERVER_SEED</code> + <code>SERVER_PUBLIC_KEY</code> (mode 600)</td></tr>
|
||||
<tr><td><code>/etc/systemd/system/peardock.service</code></td><td>systemd unit</td></tr>
|
||||
<tr><td><code>journalctl -u peardock</code></td><td>Logs</td></tr>
|
||||
</tbody>
|
||||
@@ -191,20 +209,34 @@ sudo journalctl -u peardock -f</code></pre>
|
||||
# exit 0 if Docker socket answers</code></pre>
|
||||
|
||||
<h2>Multi-operator setup</h2>
|
||||
<p>Default peer role is <strong>viewer</strong> (public key alone is read-only). Elevate with seed proof or invites.</p>
|
||||
<ol>
|
||||
<li>On first connect, note the client’s peer id (handshake returns <code>peerId</code>).</li>
|
||||
<li>Configure <code>/opt/peardock/.env</code> (or Environment= in the unit):</li>
|
||||
<li>Read <code>SERVER_PUBLIC_KEY</code> and <code>SERVER_SEED</code> from <code>/opt/peardock/.env</code>.</li>
|
||||
<li>Connect as <strong>admin</strong>: desktop client → Add peer → public key + <code>SERVER_SEED</code> (seed stays on the client; never share it).</li>
|
||||
<li>Optional harden flags in the same <code>.env</code> (or <code>Environment=</code> in the unit):</li>
|
||||
</ol>
|
||||
<pre><code>PEARDOCK_DEFAULT_ROLE=viewer
|
||||
PEARDOCK_ADMIN_KEYS=<64-hex-client-public-key>
|
||||
PEARDOCK_PEER_ALLOWLIST=1
|
||||
PEARDOCK_BROWSE_ROOTS=/var/lib/docker/volumes
|
||||
PEARDOCK_AUDIT=1</code></pre>
|
||||
<ol start="3">
|
||||
<li>As admin: <strong>Access → Create invite</strong> → send token to operator.</li>
|
||||
<li>Operator connects with server public key + invite token as supported.</li>
|
||||
<li><strong>Revoke</strong> lost devices from Access.</li>
|
||||
<ol start="4">
|
||||
<li>As admin: <strong>Access → Create invite</strong> → copy the full <code>pd1.…</code> invite string (never truncate).</li>
|
||||
<li>Operator pastes the full <code>pd1.</code> invite in <strong>Add peer</strong> — the client decodes public key + HMAC capability and connects with the granted role (no seed, no RocksDB/Autopass).</li>
|
||||
<li><strong>Revoke</strong> lost devices from Access. Delete spent invites before minting a replacement if needed.</li>
|
||||
</ol>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>Connect with</th><th>Role</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>Server public key only</td><td><code>viewer</code></td></tr>
|
||||
<tr><td>Public key + <code>SERVER_SEED</code></td><td><code>admin</code></td></tr>
|
||||
<tr><td>peardock invite (<code>pd1.…</code>)</td><td>Role in package (<code>viewer</code> / <code>operator</code> / <code>admin</code>)</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<h2>Registry vault</h2>
|
||||
<p>Credentials encrypted at rest (AES-GCM derived from <code>SERVER_SEED</code>):</p>
|
||||
|
||||
+57
-12
@@ -157,7 +157,7 @@ curl -fsSL https://install.peardock.boats | bash -s -- --both --yes</code></pre>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td><code>/opt/peardock/peardock-server</code></td><td>Bare standalone binary</td></tr>
|
||||
<tr><td><code>/opt/peardock/.env</code></td><td><code>SERVER_SEED</code> / public key material</td></tr>
|
||||
<tr><td><code>/opt/peardock/.env</code></td><td><strong>Check this file</strong> for <code>SERVER_PUBLIC_KEY</code> and <code>SERVER_SEED</code> (mode 600)</td></tr>
|
||||
<tr><td><code>/etc/systemd/system/peardock.service</code></td><td>systemd unit (user <code>peardock</code>, group <code>docker</code>)</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -165,10 +165,43 @@ curl -fsSL https://install.peardock.boats | bash -s -- --both --yes</code></pre>
|
||||
<pre><code>sudo systemctl enable --now peardock
|
||||
sudo systemctl status peardock
|
||||
sudo journalctl -u peardock -f</code></pre>
|
||||
<p>On first start the logs print:</p>
|
||||
|
||||
<h3 id="keys">Keys live in <code>.env</code></h3>
|
||||
<p>
|
||||
After the first successful start, the server writes identity into
|
||||
<code>/opt/peardock/.env</code>. <strong>Open that file</strong> (or grep it) before connecting:
|
||||
</p>
|
||||
<pre><code># Preferred — both keys after first start
|
||||
sudo grep -E '^(SERVER_PUBLIC_KEY|SERVER_SEED)=' /opt/peardock/.env
|
||||
# or: sudo cat /opt/peardock/.env
|
||||
|
||||
# Also printed in the journal on boot
|
||||
sudo journalctl -u peardock -n 80 --no-pager | grep -i 'public key'</code></pre>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>Variable</th><th>Who</th><th>In the client</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>SERVER_PUBLIC_KEY</code></td>
|
||||
<td>Safe to share</td>
|
||||
<td>Paste alone → <strong>viewer</strong> (read-only)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>SERVER_SEED</code></td>
|
||||
<td><strong>Admins only</strong> — never give to operators</td>
|
||||
<td>Paste with the public key → <strong>admin</strong></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p>Boot log shape:</p>
|
||||
<pre><code> peardock server ready
|
||||
Public key (paste into the client):
|
||||
<64 hex characters></code></pre>
|
||||
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).</code></pre>
|
||||
|
||||
<div class="callout warn">
|
||||
<div class="callout-icon">!</div>
|
||||
@@ -195,20 +228,32 @@ npm run dev</code></pre>
|
||||
<h2 id="connect">4. Connect</h2>
|
||||
<pre class="mermaid">
|
||||
flowchart LR
|
||||
A[Install server] --> B[Copy public key from journal]
|
||||
A[Install server] --> B["Read keys from /opt/peardock/.env"]
|
||||
B --> C[Install / open client]
|
||||
C --> D[Add peer · paste key]
|
||||
C --> D[Add peer · key / seed / pd1 invite]
|
||||
D --> E[Handshake · role · live UI]
|
||||
</pre>
|
||||
<ol>
|
||||
<li>Copy the server <strong>public key</strong> (64 hex chars) from journal logs.</li>
|
||||
<li>Open the client → <strong>Add peer</strong> / sidebar connection field.</li>
|
||||
<li>Paste the key (optional alias / invite token).</li>
|
||||
<li>Handshake negotiates protocol version, returns <code>peerId</code> and role.</li>
|
||||
<li>On the Docker host, read keys from <code>/opt/peardock/.env</code> (<code>SERVER_PUBLIC_KEY</code>, and <code>SERVER_SEED</code> if you need admin).</li>
|
||||
<li>Open the client → <strong>Add peer</strong>.</li>
|
||||
<li>Paste one of the options below (optional alias).</li>
|
||||
<li>Handshake returns <code>peerId</code> and role; the live UI loads.</li>
|
||||
</ol>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>Paste in Add peer</th><th>Access</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>Public key only (<code>SERVER_PUBLIC_KEY</code>)</td><td><strong>Viewer</strong> (read-only)</td></tr>
|
||||
<tr><td>Public key + <code>SERVER_SEED</code> (from the same <code>.env</code>)</td><td><strong>Admin</strong></td></tr>
|
||||
<tr><td>Full <code>pd1.…</code> invite (from Access → Create invite)</td><td>Role in the invite — <strong>no seed sharing</strong></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p>
|
||||
Default role is <strong>admin</strong> for a single operator.
|
||||
Harden multi-operator fleets via the <a href="/docs/operator">operator guide</a>
|
||||
Default peer role is <strong>viewer</strong> (public key alone). Elevate with seed proof or a
|
||||
<code>pd1.</code> invite. Multi-operator fleets: <a href="/docs/operator">operator guide</a>
|
||||
and <a href="/docs/security">threat model</a>.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
+18
-12
@@ -119,7 +119,7 @@
|
||||
<tr><td><code>SERVER_SEED</code></td><td>Critical: identity and vault key derivation</td></tr>
|
||||
<tr><td>Docker socket access</td><td>Critical: full host container control</td></tr>
|
||||
<tr><td>Registry passwords (vault)</td><td>High: encrypted at rest</td></tr>
|
||||
<tr><td>Peer invite tokens</td><td>Medium: short-lived capabilities</td></tr>
|
||||
<tr><td>HMAC capability grants / <code>pd1.</code> invites</td><td>Medium: elevated access without seed (TTL / max uses optional)</td></tr>
|
||||
<tr><td>Audit log</td><td>Medium: forensic integrity</td></tr>
|
||||
<tr><td>Container data / env secrets</td><td>High: via inspect, logs, exec</td></tr>
|
||||
</tbody>
|
||||
@@ -134,18 +134,18 @@
|
||||
+-- peardock-audit.log</code></pre>
|
||||
<ul>
|
||||
<li><strong>Anyone with the server public key</strong> can attempt a DHT connection.</li>
|
||||
<li><strong>Default role is admin</strong> unless default role / admin keys / peer policy tighten it.</li>
|
||||
<li>Swarm / plugins are off unless feature flags enable them.</li>
|
||||
<li><strong>Default role is viewer (read-only)</strong> unless elevated via admin seed proof, HMAC capability (<code>pd1.</code> invite), <code>PEARDOCK_ADMIN_KEYS</code>, peer policy, or <code>PEARDOCK_INSECURE_OPEN_ADMIN=1</code>.</li>
|
||||
<li>Swarm is on by default (<code>ENABLE_SWARM=0</code> to disable). Plugins are off unless <code>ENABLE_PLUGINS=1</code>.</li>
|
||||
<li>Holesail tunnels are on by default. Each <code>hs://</code> URL is a port capability.</li>
|
||||
<li>Host FS browse is default-deny unless browse roots / open mode are set.</li>
|
||||
</ul>
|
||||
|
||||
<h2>3. Adversaries</h2>
|
||||
<ol>
|
||||
<li><strong>Remote peer with public key only:</strong> should not get Docker control if allowlist and non-admin default are set.</li>
|
||||
<li><strong>Stolen invite token:</strong> limited by TTL and max uses. Rotate after use.</li>
|
||||
<li><strong>Remote peer with public key only:</strong> gets <strong>viewer</strong> only (read-only lists/inspect/logs).</li>
|
||||
<li><strong>Stolen <code>pd1.</code> invite / capability:</strong> limited by TTL / max uses + HMAC; revoke peer after redeem.</li>
|
||||
<li><strong>Compromised client:</strong> can use any role the peer holds until revoke.</li>
|
||||
<li><strong>Local host attacker with filesystem:</strong> can steal seed and vault if file perms are wrong.</li>
|
||||
<li><strong>Local host attacker with filesystem:</strong> can steal seed and vault if file perms are wrong — keep <code>/opt/peardock/.env</code> mode 600.</li>
|
||||
<li><strong>Malicious container:</strong> out of scope for PearDock. Engine isolation applies.</li>
|
||||
</ol>
|
||||
|
||||
@@ -158,7 +158,10 @@
|
||||
<tbody>
|
||||
<tr><td>Transport E2E</td><td>HyperDHT Noise</td></tr>
|
||||
<tr><td>Capability ACL</td><td>viewer / operator / admin + MethodRoles</td></tr>
|
||||
<tr><td>Peer policy</td><td>Invite, register, revoke, optional allowlist</td></tr>
|
||||
<tr><td>Default role</td><td><strong>viewer</strong>; elevate via seed HMAC or <code>pd1.</code> invite</td></tr>
|
||||
<tr><td>Admin proof</td><td>HMAC-SHA256 from <code>SERVER_SEED</code> (seed never on the wire)</td></tr>
|
||||
<tr><td><code>pd1.</code> invites</td><td>Self-contained public key + capability share string (no vault DB)</td></tr>
|
||||
<tr><td>Peer policy</td><td>Register, revoke, capability jti spend, optional allowlist</td></tr>
|
||||
<tr><td>Audit</td><td>Append-only log for privileged methods</td></tr>
|
||||
<tr><td>Rate limit</td><td>Per-peer limiter on RPC</td></tr>
|
||||
<tr><td>Registry secrets</td><td>AES-256-GCM vault</td></tr>
|
||||
@@ -170,7 +173,7 @@
|
||||
|
||||
<h2>5. Residual risks</h2>
|
||||
<ul>
|
||||
<li><strong>Default admin</strong> is intentional for single-operator setup. Change it for multi-tenant fleets.</li>
|
||||
<li><strong>Default viewer</strong> is intentional for production. Use <code>PEARDOCK_INSECURE_OPEN_ADMIN=1</code> only for single-operator dev.</li>
|
||||
<li>Binary image/export streams are size-capped but still large; DoS via memory if many concurrent transfers.</li>
|
||||
<li>JSON-over-RPC relies on handler validation (not full hyperschema end-to-end).</li>
|
||||
<li>Swarm secrets/configs once enabled are highly privileged.</li>
|
||||
@@ -178,14 +181,17 @@
|
||||
|
||||
<h2>6. Operator hardening checklist</h2>
|
||||
<ul>
|
||||
<li>Generate unique <code>SERVER_SEED</code>; back up offline; never commit <code>.env</code></li>
|
||||
<li>Set <code>PEARDOCK_DEFAULT_ROLE=viewer</code> or <code>operator</code></li>
|
||||
<li>Set <code>PEARDOCK_ADMIN_KEYS=<your client public key hex></code></li>
|
||||
<li>After install, confirm keys in <code>/opt/peardock/.env</code> (<code>SERVER_PUBLIC_KEY</code>, <code>SERVER_SEED</code>); back up seed offline; never commit <code>.env</code></li>
|
||||
<li>Connect as admin with public key + <code>SERVER_SEED</code> in the client (seed is session-only)</li>
|
||||
<li>Share operators via Access → <code>pd1.</code> invite (never share <code>SERVER_SEED</code>)</li>
|
||||
<li>Confirm public-key-only peers are viewer (read-only)</li>
|
||||
<li>Set <code>PEARDOCK_ADMIN_KEYS=<your client public key hex></code> for fixed admin machines (optional)</li>
|
||||
<li>Enable <code>PEARDOCK_PEER_ALLOWLIST=1</code> after registering operators</li>
|
||||
<li>Do <strong>not</strong> set <code>PEARDOCK_INSECURE_OPEN_ADMIN</code> in production</li>
|
||||
<li>Set <code>PEARDOCK_BROWSE_ROOTS</code> only if host path pickers are needed</li>
|
||||
<li>Enable <code>PEARDOCK_AUDIT=1</code></li>
|
||||
<li>Treat <code>hs://</code> tunnel URLs as secrets; set <code>ENABLE_HOLESAIL=0</code> if unused</li>
|
||||
<li>Restrict filesystem permissions on vault, peers, and seed files</li>
|
||||
<li>File mode <code>600</code> on vault, peer policy, tunnels, audit, <code>.env</code>, identity</li>
|
||||
</ul>
|
||||
|
||||
<div class="docs-pager">
|
||||
|
||||
Reference in New Issue
Block a user