670 lines
57 KiB
TypeScript
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 "I own example.tld and it should point to this Holesail hash."
|
|
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'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/{domain}/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 room—everyone 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 connection—core 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 call—core 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 to—entries 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 HyperDHT—separate 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'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>
|
|
);
|
|
}
|
|
|