Files
p2ns.space/app/docs/how-it-works/page.tsx
T
2026-05-29 06:47:06 -04:00

670 lines
57 KiB
TypeScript

import type { Metadata } from 'next';
import CodeBlock from '@/components/ui/CodeBlock';
import P2NSFlowDiagram from '@/components/diagrams/P2NSFlowDiagram';
export const metadata: Metadata = {
title: 'How It Works - P2NS Documentation',
description: 'Complete explanation of how P2NS works from domain registration to accessing services. Understand the P2NS workflow and processes.',
keywords: ['P2NS how it works', 'workflow', 'process', 'domain registration', 'P2NS explanation'],
authors: [{ name: 'Raven Scott' }],
openGraph: {
title: 'How It Works - P2NS Documentation',
description: 'Complete explanation of how P2NS works from domain registration to accessing services',
url: 'https://p2ns.space/docs/how-it-works',
siteName: 'P2NS',
type: 'website',
},
twitter: {
card: 'summary_large_image',
title: 'How It Works - P2NS Documentation',
description: 'Complete explanation of how P2NS works from domain registration to accessing services',
},
alternates: {
canonical: 'https://p2ns.space/docs/how-it-works',
},
};
export default function HowItWorksPage() {
return (
<div className="min-h-screen">
<section className="py-20 bg-gradient-to-b from-blue-50 to-white dark:from-gray-900 dark:to-gray-800">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<h1 className="text-4xl sm:text-5xl font-bold text-gray-900 dark:text-white mb-6">
How It Works
</h1>
<p className="text-xl text-gray-600 dark:text-gray-300">
Understanding the complete P2NS workflow from start to finish
</p>
</div>
</section>
<section className="py-20 bg-white dark:bg-gray-900">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6">Introduction</h2>
<p className="text-gray-600 dark:text-gray-300 mb-4">
P2NS (Peer-to-Peer Name System) is a decentralized DNS system that allows you to access services and websites
without relying on traditional DNS servers or centralized infrastructure. Instead, it uses a peer-to-peer network
where nodes work together to resolve domain names and establish direct connections.
</p>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Unlike traditional DNS where a central authority controls domain names, P2NS uses a distributed ledger where
anyone can claim a domain and peers vote to reach consensus on which service should be associated with each domain.
This makes it resistant to censorship and single points of failure.
</p>
<p className="text-gray-600 dark:text-gray-300 mb-6">
The system uses UDP hole-punching (via HyperDHT) to connect through firewalls and NAT, making it possible to
reach services behind restrictive networks. Two P2P layers work together: <strong className="text-gray-900 dark:text-white">Hyperswarm</strong> on the
P2NS topic syncs DNS claims and votes; <strong className="text-gray-900 dark:text-white">Holesail</strong> uses separate hashes on the DHT for each
published service tunnel. Let's walk through exactly how this works, step by step.
</p>
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">The Big Picture</h2>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Here's a high-level view of what happens when you access a P2NS domain:
</p>
<div className="mb-6">
<P2NSFlowDiagram />
</div>
<p className="text-gray-600 dark:text-gray-300 mb-6">
The key components are: <strong className="text-gray-900 dark:text-white">peers</strong> (Hyperswarm + Corestore/Autopass for DNS state),
<strong className="text-gray-900 dark:text-white"> protomux-rpc</strong> (core invites and plugin traffic),
<strong className="text-gray-900 dark:text-white">Holesail</strong> (per-service tunnels),
<strong className="text-gray-900 dark:text-white">virtual interfaces</strong> (local IPs per domain), and
<strong className="text-gray-900 dark:text-white">HTTPS/HTTP proxies</strong> (TLS and routing). Built-in sites such as{' '}
<code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">p2ns.admin</code> and plugin domains under{' '}
<code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">plugin-sites/</code> are resolved without a P2P claim.
</p>
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">Step-by-Step Process</h2>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4">Part 1: Setting Up a Domain (Service Provider Side)</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Before anyone can access a service through P2NS, the service provider needs to register their domain. Here's how it works:
</p>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">1. Generate a Holesail Hash</h4>
<p className="text-gray-600 dark:text-gray-300 mb-4">
The service provider first needs to create a Holesail connection hash. They run:
</p>
<CodeBlock code="holesail --live 80 --public" />
<p className="text-gray-600 dark:text-gray-300 mb-4">
Use <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">--public</code> so the service is announced on HyperDHT for remote peers.
This generates a hash like <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">hs://s00084bf87dfa89a3048fb081c0e6207eb5a</code>.
That hash is independent of the P2NS swarm topic—peers use it only when connecting to your service tunnel.
</p>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">2. Create a Domain Claim</h4>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Next, they register their domain (e.g., <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">example.tld</code>)
by creating a claim in the P2P network. This claim says &quot;I own example.tld and it should point to this Holesail hash.&quot;
Claims live in the shared <strong className="text-gray-900 dark:text-white">Autopass</strong> store (<code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">dnsPass</code>) on top of Corestore—an append-only, signed log replicated across writers.
</p>
<p className="text-gray-600 dark:text-gray-300 mb-4">
You can add domains via the admin UI (<code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">https://p2ns.admin</code>),{' '}
<code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">cache/domains.json</code> (genesis master by default), or the API. On a <strong className="text-gray-900 dark:text-white">new</strong> network, exactly one node runs as{' '}
<strong className="text-gray-900 dark:text-white">genesis master</strong> (<code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">--master --genesis</code>) to create the shared Autopass ledger and{' '}
<code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">cache/network.json</code>. Everyone else joins with <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">node p2ns.js</code> (joiner) or an optional secondary master (<code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">--master</code> without <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">--genesis</code>) after receiving an invite.
</p>
<p className="text-gray-600 dark:text-gray-300 mb-4">
The claim is stored with a key like <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">claim:example.tld:claimant-id</code>
where <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">claimant-id</code> is a unique identifier for the person making the claim.
</p>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">3. Peer Discovery and Sync</h4>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Once the claim is created, it's automatically synchronized to all connected peers in the network. Each peer maintains
a copy of the distributed ledger, so the claim propagates throughout the network. This happens in real-time as peers
connect and exchange data.
</p>
<p className="text-gray-600 dark:text-gray-300 mb-6">
If multiple people claim the same domain, the network uses a voting and consensus mechanism to decide which claim
is legitimate (we'll cover this in detail later).
</p>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4 mt-8">Part 2: Peer Discovery and Network Formation</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
For P2NS to work, nodes need to find and connect to each other. This happens automatically using a technology called Hyperswarm.
</p>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">1. Topic-Based Discovery</h4>
<p className="text-gray-600 dark:text-gray-300 mb-4">
All P2NS nodes use the same "topic" to find each other. Think of it like a meeting room number - everyone who wants
to participate in P2NS goes to the same room. The topic is a 32-byte buffer from <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">sha256(TOPIC_SEED)</code> (default <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">p2ns-dns</code>),
which ensures all P2NS nodes discover each other regardless of where they are in the world.
</p>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">2. Connection Establishment</h4>
<p className="text-gray-600 dark:text-gray-300 mb-4">
When a node starts up, it joins Hyperswarm on this topic. Under the hood, <strong>HyperDHT</strong> announces and
looks up peers, coordinates UDP hole punching, and falls back to encrypted relays when needed. Each connection
completes a Noise XX handshake before any application data flows.
</p>
<p className="text-gray-600 dark:text-gray-300 mb-4">
The connection process involves:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-4">
<li>Noise XX handshake proves each peer holds the advertised key</li>
<li>Protomux multiplexes core RPC and plugin protocols on the same connection</li>
<li>Autopass replicates <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">dnsPass</code> to authorized writers (separate from the P2NS topic used only for discovery)</li>
</ul>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">3. Joining as a Writer (Genesis, Masters, Joiners)</h4>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Only peers with Autopass writer access can append claims and votes. All nodes on a network share <strong className="text-gray-900 dark:text-white">one</strong> Autopass ledger identified by <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">networkId</code> in <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">cache/network.json</code>:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-4">
<li><strong className="text-gray-900 dark:text-white">Genesis master</strong> — <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">--master --genesis</code> creates the ledger (once per network)</li>
<li><strong className="text-gray-900 dark:text-white">Secondary masters</strong> — <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">--master</code> on empty storage waits for an invite (no implicit second ledger)</li>
<li><strong className="text-gray-900 dark:text-white">Joiners</strong> — <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">node p2ns.js</code>; no master flag required for everyday use</li>
</ul>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Admission uses protomux-rpc on the P2NS swarm connection:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-4">
<li><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">invite.request</code> — peer asks a master or writer for an invite</li>
<li><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">invite.deliver</code> / <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">invite.ack</code> — invite wire is delivered and acknowledged</li>
<li><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">core.status</code> — exposes <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">networkId</code>, invite capability, and split-network warnings</li>
</ul>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Masters may proactively send invites when new peers connect (<code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">MASTER_PROACTIVE_INVITE_DELAY</code>).
Quorum counts writers with initialized <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">dnsPass</code>, not raw swarm connections.
See <a href="/docs/architecture" className="text-blue-600 dark:text-blue-400 hover:underline">Architecture</a> and <a href="/docs/configuration" className="text-blue-600 dark:text-blue-400 hover:underline">Configuration</a>.
</p>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">4. Data Synchronization</h4>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Once a peer is a writer, new claims and votes append to <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">dnsPass</code> and replicate
to other writers through Autopass. Corestore manages the underlying Hypercore logs. When a new claim or vote is added, authorized peers receive it automatically.
</p>
<p className="text-gray-600 dark:text-gray-300 mb-4">
This means:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-6">
<li>Every node has a complete copy of all domain claims and votes</li>
<li>New information propagates through the network automatically</li>
<li>The network is resilient - if some nodes go offline, others still have the data</li>
<li>No central server is needed - the network is truly decentralized</li>
</ul>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4 mt-8">Part 3: DNS Resolution (When Someone Wants to Access)</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Now let's see what happens when someone wants to access a P2NS domain. This is where the magic happens!
</p>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">1. The DNS Query</h4>
<p className="text-gray-600 dark:text-gray-300 mb-4">
When you type a domain like <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">https://example.tld</code>
in your browser, or when an application makes a DNS query, it goes to the P2NS DNS server (port 53 by default, configurable).
This server is configured as your system&apos;s DNS resolver, so queries flow through P2NS first.
</p>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">2. Internal and Local Records</h4>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Before P2P lookup, the resolver checks:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-4">
<li><strong className="text-gray-900 dark:text-white">Internal domains:</strong> <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">p2ns.admin</code> and any domain with a plugin under <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">plugin-sites/&#123;domain&#125;/config.json</code> (e.g. <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">peer.directory</code>, <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">peer.paste</code>)</li>
<li><strong className="text-gray-900 dark:text-white">Local DNS:</strong> entries in <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">cache/local_dns.json</code> override both P2P and public DNS</li>
</ul>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">3. Checking the Cache</h4>
<p className="text-gray-600 dark:text-gray-300 mb-4">
First, P2NS checks its local cache to see if it recently resolved this domain. If the cache entry is still valid
(typically cached for 30 seconds), it returns the cached result immediately. This makes repeated queries very fast.
</p>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">4. Querying the P2P Network</h4>
<p className="text-gray-600 dark:text-gray-300 mb-4">
If not in cache, P2NS looks up the domain in the distributed ledger. It searches through all the claims stored locally
(remember, each node has a complete copy) to find any claims for the requested domain.
</p>
<p className="text-gray-600 dark:text-gray-300 mb-4">
The system looks for entries with keys like <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">claim:example.tld:*</code>
to find all people who have claimed this domain.
</p>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">5. Consensus Mechanism</h4>
<p className="text-gray-600 dark:text-gray-300 mb-4">
If multiple people have claimed the same domain, P2NS uses a consensus algorithm to determine which one is correct:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-4">
<li><strong className="text-gray-900 dark:text-white">Count votes:</strong> Each claim can have votes from other peers. The system counts how many votes each claimant has received.</li>
<li><strong className="text-gray-900 dark:text-white">Check quorum:</strong> Configurable via <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">CONSENSUS_QUORUM_THRESHOLD</code> (default 50% of active peers) and <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">CONSENSUS_MIN_VOTES</code> (default 2).</li>
<li><strong className="text-gray-900 dark:text-white">Resolve ties:</strong> If two claimants have the same number of votes, the system uses a tie-breaker (like preferring the oldest claim).</li>
<li><strong className="text-gray-900 dark:text-white">Return the hash:</strong> Once consensus is reached, the system returns the Holesail hash associated with the winning claim.</li>
</ul>
<p className="text-gray-600 dark:text-gray-300 mb-4">
This ensures that everyone in the network agrees on which service should be associated with each domain name.
</p>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">6. Fallback to Public DNS</h4>
<p className="text-gray-600 dark:text-gray-300 mb-6">
If the domain is not internal, not in local DNS, and not resolved via P2P consensus, P2NS forwards to <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">PUBLIC_DNS_SERVER</code> (comma-separated list supported for failover).
You can use P2P domains and the public internet through one resolver.
</p>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4 mt-8">Part 4: Virtual Interface Setup</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Once P2NS has the Holesail hash for a domain, it needs to set up local networking to route traffic to that domain.
This is where virtual network interfaces come in.
</p>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">1. Assigning a Local IP Address</h4>
<p className="text-gray-600 dark:text-gray-300 mb-4">
P2NS assigns each domain a unique local IP address from a configured subnet (default: <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">192.168.3.x</code>).
For example, the first domain might get <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">192.168.3.2</code>,
the second gets <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">192.168.3.3</code>, and so on.
</p>
<p className="text-gray-600 dark:text-gray-300 mb-4">
You can configure multiple subnets with different IP ranges, and P2NS will automatically allocate IPs from available subnets.
This gives you flexibility to organize domains across different network ranges.
</p>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">2. Creating the Virtual Interface</h4>
<p className="text-gray-600 dark:text-gray-300 mb-4">
P2NS creates a virtual network interface (like <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">lo0</code> on macOS or <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">lo</code> on Linux)
and adds the IP address as an alias. This makes the IP address available on your local machine, even though it's not
connected to a physical network.
</p>
<p className="text-gray-600 dark:text-gray-300 mb-4">
The virtual interface acts like a local network adapter, allowing your system to route traffic to that IP address.
When your browser or application connects to the domain, it resolves to this local IP, and the traffic gets intercepted
by P2NS for processing.
</p>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">3. Why Virtual Interfaces?</h4>
<p className="text-gray-600 dark:text-gray-300 mb-6">
Virtual interfaces are necessary because:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-6">
<li>They allow P2NS to intercept traffic destined for P2P domains</li>
<li>They provide a consistent local endpoint for routing</li>
<li>They enable the HTTPS proxy to handle TLS connections properly</li>
<li>They allow multiple domains to coexist on the same machine without conflicts</li>
</ul>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4 mt-8">Part 5: Holesail Connection Establishment</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Now that we have a local IP address, P2NS needs to establish a connection to the actual service. This is where Holesail
comes in - it's the technology that punches through firewalls and NAT to create direct connections.
</p>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">1. What Holesail Does</h4>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Holesail uses UDP hole-punching to establish connections through firewalls and NAT (Network Address Translation).
Traditional networking often fails when both the client and server are behind firewalls, but Holesail solves this by:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-4">
<li>Using HyperDHT (the distributed hash table) to exchange endpoints and coordinate simultaneous UDP probes</li>
<li>Sending UDP packets from both sides simultaneously to "punch holes" in the firewall</li>
<li>Establishing a direct peer-to-peer connection once the hole is punched, with encrypted relay fallback when needed</li>
<li>Maintaining tunnels; optional <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">FULL_PERSISTENCE</code> keeps clients/servers alive across restarts (see Configuration)</li>
</ul>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Holesail server and client configs persist under <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">cache/holesail_servers.json</code> and{' '}
<code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">cache/holesail_clients.json</code>.
</p>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">2. Using the Hash to Connect</h4>
<p className="text-gray-600 dark:text-gray-300 mb-4">
The Holesail hash we got from the domain claim is a random cryptographic string that acts as a key to look up the service
on the DHT. When P2NS needs to connect, it:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-4">
<li>Uses the hash to query the DHT for the service information</li>
<li>Retrieves the metadata stored on the DHT (host, port, protocol configuration)</li>
<li>Uses this information along with the hash to establish the connection</li>
</ul>
<p className="text-gray-600 dark:text-gray-300 mb-4">
P2NS creates a Holesail client that uses this hash to look up and connect to the service provider's Holesail server.
The connection process happens automatically in the background.
</p>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">3. Connection Persistence</h4>
<p className="text-gray-600 dark:text-gray-300 mb-6">
Once established, the Holesail connection can be kept alive persistently. This means:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-6">
<li>Subsequent requests to the same domain reuse the existing connection (faster)</li>
<li>The connection automatically reconnects if it drops</li>
<li>You can configure timeout behavior for non-persistent connections</li>
<li>Multiple domains can share connections when appropriate</li>
</ul>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4 mt-8">Part 6: HTTPS Proxy and Routing</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Now we have a Holesail tunnel established, but we still need to handle HTTPS properly and route requests correctly.
This is where the proxy servers come in.
</p>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">1. TLS Certificate Generation</h4>
<p className="text-gray-600 dark:text-gray-300 mb-4">
P2NS automatically generates TLS certificates for each domain using its own Certificate Authority (CA). When you first
access a P2NS domain, the system:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-4">
<li>Generates a certificate for the domain if it doesn't exist</li>
<li>Signs it with the P2NS root CA</li>
<li>Includes the domain name and local IP in the certificate (Subject Alternative Names)</li>
<li>Stores the certificate for reuse</li>
</ul>
<p className="text-gray-600 dark:text-gray-300 mb-4">
You need to trust the P2NS root CA in your browser/system to avoid security warnings. P2NS auto-installs on macOS and Windows;
on Linux, Chrome requires both the system CA bundle and the NSS trust database (<code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">certutil</code> / <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">~/.pki/nssdb</code>) — see{' '}
<a href="/docs/troubleshooting#certificate-authority-issues" className="text-blue-600 dark:text-blue-400 hover:underline">Troubleshooting</a>.
</p>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">2. HTTPS Proxy Server</h4>
<p className="text-gray-600 dark:text-gray-300 mb-4">
P2NS runs an HTTPS proxy server on port 443. When your browser makes an HTTPS request to a P2NS domain:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-4">
<li>The request goes to the P2NS HTTPS proxy</li>
<li>The proxy uses the domain's TLS certificate to establish a secure connection with your browser</li>
<li>The proxy then forwards the request through the Holesail tunnel to the actual service</li>
<li>Responses flow back through the tunnel and proxy to your browser</li>
</ul>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">3. HTTP to HTTPS Redirect</h4>
<p className="text-gray-600 dark:text-gray-300 mb-4">
P2NS also runs an HTTP server on port 80 that automatically redirects all HTTP requests to HTTPS. This ensures
all connections are encrypted and secure.
</p>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">4. WebSocket Support</h4>
<p className="text-gray-600 dark:text-gray-300 mb-6">
The proxy also supports WebSocket connections, allowing real-time applications to work through P2NS. WebSocket
upgrades are handled transparently, maintaining the connection through the Holesail tunnel.
</p>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4 mt-8">Part 7: Complete Request Flow</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Let's put it all together! Here's exactly what happens when you access a P2NS domain:
</p>
<div className="bg-gray-50 dark:bg-gray-800 p-6 rounded-lg mb-6">
<ol className="list-decimal pl-6 space-y-3 text-gray-700 dark:text-gray-300">
<li><strong className="text-gray-900 dark:text-white">You type</strong> <code className="bg-gray-200 dark:bg-gray-700 px-1.5 py-0.5 rounded">https://example.tld</code> in your browser</li>
<li><strong className="text-gray-900 dark:text-white">DNS query:</strong> Your system queries the P2NS DNS server (port 53) for <code className="bg-gray-200 dark:bg-gray-700 px-1.5 py-0.5 rounded">example.tld</code></li>
<li><strong className="text-gray-900 dark:text-white">Cache check:</strong> P2NS checks its cache - if found and valid, returns cached result</li>
<li><strong className="text-gray-900 dark:text-white">P2P lookup:</strong> If not cached, P2NS searches the distributed ledger for claims matching <code className="bg-gray-200 dark:bg-gray-700 px-1.5 py-0.5 rounded">example.tld</code></li>
<li><strong className="text-gray-900 dark:text-white">Consensus:</strong> If multiple claims exist, P2NS runs consensus algorithm to determine the correct hash</li>
<li><strong className="text-gray-900 dark:text-white">Hash retrieved:</strong> P2NS gets the Holesail hash (e.g., <code className="bg-gray-200 dark:bg-gray-700 px-1.5 py-0.5 rounded">hs://s00084bf87dfa89a...</code>)</li>
<li><strong className="text-gray-900 dark:text-white">Virtual interface:</strong> P2NS assigns/uses a local IP (e.g., <code className="bg-gray-200 dark:bg-gray-700 px-1.5 py-0.5 rounded">192.168.3.2</code>) for this domain</li>
<li><strong className="text-gray-900 dark:text-white">Holesail client:</strong> P2NS creates or reuses a Holesail client connection using the hash</li>
<li><strong className="text-gray-900 dark:text-white">Tunnel established:</strong> The Holesail connection punches through firewalls and establishes a tunnel</li>
<li><strong className="text-gray-900 dark:text-white">TLS proxy:</strong> P2NS sets up an HTTPS proxy using the domain's TLS certificate</li>
<li><strong className="text-gray-900 dark:text-white">Browser connects:</strong> Your browser connects to the P2NS HTTPS proxy (port 443)</li>
<li><strong className="text-gray-900 dark:text-white">Request forwarded:</strong> The proxy forwards your request through the Holesail tunnel to the actual service</li>
<li><strong className="text-gray-900 dark:text-white">Response received:</strong> The service responds, and the response flows back through the tunnel</li>
<li><strong className="text-gray-900 dark:text-white">You see the website:</strong> The response reaches your browser, and you see the content!</li>
</ol>
</div>
<p className="text-gray-600 dark:text-gray-300 mb-6">
All of this happens automatically in milliseconds! The first request might take a bit longer as connections are established,
but subsequent requests are much faster as connections are reused.
</p>
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">Consensus and Voting</h2>
<p className="text-gray-600 dark:text-gray-300 mb-4">
One of the most important aspects of P2NS is how it handles conflicts when multiple people claim the same domain.
The consensus mechanism ensures the network agrees on which service should be associated with each domain.
</p>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4">How Voting Works</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
When a peer sees a domain claim, they can vote for it by creating a vote entry in the ledger. The vote key looks like:
<code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">vote:example.tld:claimant-id:voter-id</code>
</p>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Peers typically vote for the claim they believe is legitimate. This could be based on:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-4">
<li>Who they know and trust</li>
<li>Which claim was made first (timestamp)</li>
<li>Which service they want to use</li>
<li>Automatic voting based on local claims</li>
</ul>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4 mt-8">Quorum Requirements</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
For a domain to be considered "resolved" (consensus reached), it must meet quorum requirements:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-4">
<li><strong className="text-gray-900 dark:text-white">Percentage threshold:</strong> <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">CONSENSUS_QUORUM_THRESHOLD</code> (default 0.5 = 50% of active peers)</li>
<li><strong className="text-gray-900 dark:text-white">Minimum votes:</strong> <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">CONSENSUS_MIN_VOTES</code> (default 2), regardless of peer count</li>
<li><strong className="text-gray-900 dark:text-white">Vote validation:</strong> Votes must reference existing claims (invalid votes are ignored)</li>
</ul>
<p className="text-gray-600 dark:text-gray-300 mb-4">
This ensures that consensus isn't reached by just one or two nodes, but represents actual network agreement.
</p>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4 mt-8">Tie-Breaking Strategies</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
When multiple claimants have the same number of votes, P2NS uses tie-breaking strategies:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-4">
<li><strong className="text-gray-900 dark:text-white">Timestamp:</strong> Prefer the oldest claim (<code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">CONSENSUS_TIE_BREAKER=timestamp</code>, default)</li>
<li><strong className="text-gray-900 dark:text-white">Claimant age:</strong> Prefer the claimant with the longest history in the network</li>
<li><strong className="text-gray-900 dark:text-white">Lexicographic:</strong> Alphabetical ordering of claimant IDs</li>
</ul>
<p className="text-gray-600 dark:text-gray-300 mb-6">
This deterministic approach ensures all nodes reach the same conclusion when resolving ties, maintaining network consistency.
</p>
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">Key Technologies Explained Simply</h2>
<p className="text-gray-600 dark:text-gray-300 mb-4">
P2NS uses several advanced technologies. Here's what each one does in simple terms:
</p>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4">Hyperswarm & HyperDHT</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
<strong className="text-gray-900 dark:text-white">What it does:</strong> Discovers other P2NS nodes on topic <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">sha256(TOPIC_SEED)</code>, coordinates hole punching, and opens encrypted swarm connections.
</p>
<p className="text-gray-600 dark:text-gray-300 mb-6">
<strong className="text-gray-900 dark:text-white">Simple analogy:</strong> A distributed meeting roomeveryone who joins the same topic can find each other without a central directory server.
</p>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4">Protomux / protomux-rpc</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
<strong className="text-gray-900 dark:text-white">What it does:</strong> Multiplexes JSON-RPC methods on each peer connectioncore invites, consensus helpers, and per-plugin protocols.
</p>
<p className="text-gray-600 dark:text-gray-300 mb-6">
<strong className="text-gray-900 dark:text-white">Simple analogy:</strong> Several phone lines over one secure callcore control traffic and plugin apps share the same tunnel without mixing messages.
</p>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4">Corestore & Autopass</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
<strong className="text-gray-900 dark:text-white">What it does:</strong> Corestore holds Hypercore append-only logs; Autopass (<code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">dnsPass</code>) stores claims and votes with invite-gated writers.
</p>
<p className="text-gray-600 dark:text-gray-300 mb-6">
<strong className="text-gray-900 dark:text-white">Simple analogy:</strong> A signed ledger everyone authorized can append toentries are immutable and verifiable by Merkle proofs, not by trusting who sent them.
</p>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4">Holesail</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
<strong className="text-gray-900 dark:text-white">What it does:</strong> Publishes and connects to service tunnels by hash on HyperDHTseparate from the P2NS DNS swarm topic.
</p>
<p className="text-gray-600 dark:text-gray-300 mb-6">
<strong className="text-gray-900 dark:text-white">Simple analogy:</strong> A dedicated address for your web server or game port; DNS consensus points a domain name at that address.
</p>
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">Real-World Example</h2>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Let's walk through a concrete example to see how everything fits together:
</p>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4">Scenario: Alice hosts a blog, Bob wants to read it</h3>
<div className="bg-gray-50 dark:bg-gray-800 p-6 rounded-lg mb-6">
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">Step 1: Alice Sets Up Her Blog (Service Provider)</h4>
<ul className="list-disc pl-6 space-y-2 text-gray-700 dark:text-gray-300 mb-4">
<li>Alice runs a blog server on her home computer (port 80)</li>
<li>She generates a Holesail hash: <code className="bg-gray-200 dark:bg-gray-700 px-1.5 py-0.5 rounded">hs://s00084bf87dfa89a3048fb081c0e6207eb5a</code></li>
<li>She claims the domain <code className="bg-gray-200 dark:bg-gray-700 px-1.5 py-0.5 rounded">alice.blog</code> with this hash</li>
<li>The claim is stored in the P2P network and synced to all peers</li>
</ul>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3 mt-6">Step 2: Bob's Node Joins the Network</h4>
<ul className="list-disc pl-6 space-y-2 text-gray-700 dark:text-gray-300 mb-4">
<li>Bob starts his P2NS node</li>
<li>His node connects to Hyperswarm and discovers other peers</li>
<li>The distributed ledger syncs, and Bob's node now knows about <code className="bg-gray-200 dark:bg-gray-700 px-1.5 py-0.5 rounded">alice.blog</code></li>
</ul>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3 mt-6">Step 3: Bob Accesses the Blog</h4>
<ul className="list-disc pl-6 space-y-2 text-gray-700 dark:text-gray-300 mb-4">
<li>Bob types <code className="bg-gray-200 dark:bg-gray-700 px-1.5 py-0.5 rounded">https://alice.blog</code> in his browser</li>
<li>DNS query goes to P2NS DNS server</li>
<li>P2NS looks up <code className="bg-gray-200 dark:bg-gray-700 px-1.5 py-0.5 rounded">alice.blog</code> in the ledger</li>
<li>Finds Alice's claim and gets the Holesail hash</li>
<li>Assigns local IP <code className="bg-gray-200 dark:bg-gray-700 px-1.5 py-0.5 rounded">192.168.3.2</code> to <code className="bg-gray-200 dark:bg-gray-700 px-1.5 py-0.5 rounded">alice.blog</code></li>
<li>Creates Holesail client connection using the hash</li>
<li>Holesail punches through firewalls and connects to Alice's server</li>
<li>HTTPS proxy routes the request through the tunnel</li>
<li>Alice's blog server responds with the blog content</li>
<li>Response flows back through the tunnel to Bob's browser</li>
<li>Bob sees Alice's blog!</li>
</ul>
</div>
<p className="text-gray-600 dark:text-gray-300 mb-4">
<strong className="text-gray-900 dark:text-white">Timeline:</strong> All of this happens in under a second for the first request.
Subsequent requests are even faster because the Holesail connection is reused.
</p>
<p className="text-gray-600 dark:text-gray-300 mb-6">
<strong className="text-gray-900 dark:text-white">The magic:</strong> Even though Alice and Bob are both behind firewalls and NAT,
they can communicate directly thanks to Holesail's UDP hole-punching. No central server needed, no port forwarding required!
</p>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4 mt-8">Scenario: Service Subscriptions - Multiple Services, Automatic Management</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Service subscriptions allow peers to automatically connect to services hosted by domain owners. This is especially useful when
a domain owner hosts multiple services (like a web server, API, and game server) and wants others to easily access them.
</p>
<div className="bg-gray-50 dark:bg-gray-800 p-6 rounded-lg mb-6">
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">Step 1: Alice Hosts Multiple Services</h4>
<ul className="list-disc pl-6 space-y-2 text-gray-700 dark:text-gray-300 mb-4">
<li>Alice owns the domain <code className="bg-gray-200 dark:bg-gray-700 px-1.5 py-0.5 rounded">alice.services</code></li>
<li>She hosts three services:
<ul className="list-disc pl-6 mt-2 space-y-1">
<li><strong>Web Server:</strong> Port 80, TCP protocol, service name "web"</li>
<li><strong>API Server:</strong> Port 8080, TCP protocol, service name "api"</li>
<li><strong>Game Server:</strong> Port 25565, UDP protocol, service name "game"</li>
</ul>
</li>
<li>Alice opens the P2NS admin panel and navigates to the "Host" tab</li>
<li>For each service, she creates a Holesail hash and uses the "Create Client" button to add it to her domain</li>
<li>When creating each client, she specifies the service name and protocol (TCP or UDP)</li>
<li>The system automatically updates the domain's claim record with a <code className="bg-gray-200 dark:bg-gray-700 px-1.5 py-0.5 rounded">clients</code> array containing all three services</li>
<li>This claim record is automatically synced to all peers in the network</li>
</ul>
<p className="text-gray-600 dark:text-gray-300 mb-4 mt-4">
Example claim record structure:
</p>
<CodeBlock code={'{\n "hash": "original-hash",\n "clients": [\n {\n "name": "web",\n "hash": "hs://s00084bf87dfa89a...",\n "protocol": "tcp"\n },\n {\n "name": "api",\n "hash": "hs://s00091c2e8fa9b0b...",\n "protocol": "tcp"\n },\n {\n "name": "game",\n "hash": "hs://s000a2d3f9b1c2d3...",\n "protocol": "udp"\n }\n ],\n "timestamp": 1234567890\n}'} language="json" />
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3 mt-6">Step 2: Bob Discovers and Subscribes to Services</h4>
<ul className="list-disc pl-6 space-y-2 text-gray-700 dark:text-gray-300 mb-4">
<li>Bob opens the P2NS admin panel and navigates to the "Service Subscription" modal</li>
<li>He searches for <code className="bg-gray-200 dark:bg-gray-700 px-1.5 py-0.5 rounded">alice.services</code> and sees all three available services</li>
<li>Bob has two options:
<ul className="list-disc pl-6 mt-2 space-y-1">
<li><strong>Subscribe to individual services:</strong> He selects just the "web" and "api" services</li>
<li><strong>Subscribe to all:</strong> He enables "Subscribe All" for <code className="bg-gray-200 dark:bg-gray-700 px-1.5 py-0.5 rounded">alice.services</code></li>
</ul>
</li>
<li>Bob chooses "Subscribe All" - this means he'll automatically get all current and future services from Alice</li>
<li>P2NS automatically creates Holesail clients for all three services:
<ul className="list-disc pl-6 mt-2 space-y-1">
<li><code className="bg-gray-200 dark:bg-gray-700 px-1.5 py-0.5 rounded">alice.services_web</code> (TCP client)</li>
<li><code className="bg-gray-200 dark:bg-gray-700 px-1.5 py-0.5 rounded">alice.services_api</code> (TCP client)</li>
<li><code className="bg-gray-200 dark:bg-gray-700 px-1.5 py-0.5 rounded">alice.services_game</code> (UDP client)</li>
</ul>
</li>
<li>Each client establishes a Holesail connection to the corresponding service</li>
<li>Bob&apos;s subscription preferences are saved locally in <code className="bg-gray-200 dark:bg-gray-700 px-1.5 py-0.5 rounded">cache/subscriptions.json</code></li>
</ul>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3 mt-6">Step 3: Dynamic Synchronization - Alice Adds a New Service</h4>
<ul className="list-disc pl-6 space-y-2 text-gray-700 dark:text-gray-300 mb-4">
<li>Later, Alice adds a fourth service: "chat" server on port 9000 (TCP)</li>
<li>She uses the admin panel's "Create Client" button to add the new service to her domain</li>
<li>The system automatically updates her domain's claim record to include the new service</li>
<li>The updated claim record is automatically synced to all peers</li>
<li>Bob's P2NS node detects the change in the claim record (via AutoPass update events)</li>
<li>Since Bob has "Subscribe All" enabled for <code className="bg-gray-200 dark:bg-gray-700 px-1.5 py-0.5 rounded">alice.services</code>, P2NS automatically:
<ul className="list-disc pl-6 mt-2 space-y-1">
<li>Creates a new Holesail client: <code className="bg-gray-200 dark:bg-gray-700 px-1.5 py-0.5 rounded">alice.services_chat</code></li>
<li>Establishes the connection</li>
<li>Updates Bob's subscription list</li>
</ul>
</li>
<li>Bob can now access the chat service without any manual configuration!</li>
</ul>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3 mt-6">Step 4: Dynamic Synchronization - Alice Removes a Service</h4>
<ul className="list-disc pl-6 space-y-2 text-gray-700 dark:text-gray-300 mb-4">
<li>Alice decides to shut down her "game" server</li>
<li>She uses the admin panel to delete the Holesail client for the "game" service</li>
<li>The system automatically removes it from her domain's claim record</li>
<li>The updated claim record syncs to all peers</li>
<li>Bob's P2NS node detects the service was removed</li>
<li>P2NS automatically:
<ul className="list-disc pl-6 mt-2 space-y-1">
<li>Stops and deletes the <code className="bg-gray-200 dark:bg-gray-700 px-1.5 py-0.5 rounded">alice.services_game</code> Holesail client</li>
<li>Frees up the UDP port that was being used</li>
<li>Removes the service from Bob's subscription list</li>
</ul>
</li>
<li>Bob's system is automatically cleaned up - no manual intervention needed!</li>
</ul>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3 mt-6">Step 5: Auto-Subscription on Bootup</h4>
<ul className="list-disc pl-6 space-y-2 text-gray-700 dark:text-gray-300 mb-4">
<li>When Bob restarts his P2NS node, the system loads his saved subscriptions from <code className="bg-gray-200 dark:bg-gray-700 px-1.5 py-0.5 rounded">cache/subscriptions.json</code></li>
<li>For each subscribed service, P2NS automatically:
<ul className="list-disc pl-6 mt-2 space-y-1">
<li>Creates the Holesail client</li>
<li>Establishes the connection</li>
<li>Makes the service available immediately</li>
</ul>
</li>
<li>If "Subscribe All" is enabled for a domain, P2NS also checks the current claim record and subscribes to any new services that were added while Bob's node was offline</li>
<li>Bob doesn't need to manually reconfigure anything - everything just works!</li>
</ul>
</div>
<p className="text-gray-600 dark:text-gray-300 mb-4">
<strong className="text-gray-900 dark:text-white">Key Benefits:</strong>
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-4">
<li><strong className="text-gray-900 dark:text-white">Automatic Management:</strong> Services are automatically added/removed as domain owners update their offerings</li>
<li><strong className="text-gray-900 dark:text-white">Persistent Subscriptions:</strong> Subscriptions survive reboots and are automatically restored</li>
<li><strong className="text-gray-900 dark:text-white">Protocol Support:</strong> Works with both TCP and UDP services</li>
<li><strong className="text-gray-900 dark:text-white">Subscribe All:</strong> Option to automatically get all services from a domain, including future ones</li>
<li><strong className="text-gray-900 dark:text-white">No Manual Configuration:</strong> Once subscribed, everything is managed automatically</li>
</ul>
<p className="text-gray-600 dark:text-gray-300 mb-6">
<strong className="text-gray-900 dark:text-white">The Power:</strong> Service subscriptions make it easy for peers to discover and connect to services across the network.
Domain owners can offer multiple services, and subscribers can automatically access them all with minimal configuration.
The system handles all the complexity of connection management, protocol differences, and dynamic updates.
</p>
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">Related Documentation</h2>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300">
<li><a href="/docs/getting-started" className="text-blue-600 dark:text-blue-400 hover:underline">Getting Started</a> install, genesis/joiner roles, first domain</li>
<li><a href="/docs/architecture" className="text-blue-600 dark:text-blue-400 hover:underline">Architecture</a> modules, Core RPC, plugins, logging</li>
<li><a href="/docs/configuration" className="text-blue-600 dark:text-blue-400 hover:underline">Configuration</a> environment variables and defaults</li>
<li><a href="/docs/upgrading" className="text-blue-600 dark:text-blue-400 hover:underline">Upgrading</a> coordinated upgrades and <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">--clean</code></li>
<li><a href="/docs/plugins" className="text-blue-600 dark:text-blue-400 hover:underline">Built-in Plugins</a> peer.directory, peer.paste, and more</li>
<li><a href="/learn/p2p" className="text-blue-600 dark:text-blue-400 hover:underline">How P2P Works</a> NAT, HyperDHT, and the Holepunch stack</li>
</ul>
</div>
</section>
</div>
);
}