Skip to content

Commit 2e4eea5

Browse files
windcbfclaude
andcommitted
Demo: add architecture diagram of the 7-host NHP demo environment
Adds an interactive SVG diagram to the demo page showing how agent, reg, stealth-dns, relay, server, server2, ac, and ac2 relate: which paths are exposed vs. fully invisible, which boxes link to their source code, and a #architecture anchor for direct linking. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent ee23e0b commit 2e4eea5

1 file changed

Lines changed: 150 additions & 0 deletions

File tree

content/en/demo.html

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,156 @@ <h3 style="margin-bottom: var(--spacing-md); font-size: 1.1rem; font-weight: 500
354354
</div>
355355
</section>
356356

357+
<!-- Demo Architecture -->
358+
<section class="section" id="architecture" style="background: var(--bg-secondary);">
359+
<div class="container container--narrow">
360+
<div class="section-header">
361+
<span class="section-header__label">Under the Hood</span>
362+
<h2 class="section-header__title">
363+
How the Demo Environment Is Wired
364+
<a href="#architecture" aria-label="Link to this section" style="color: var(--text-muted); text-decoration: none; font-size: 0.65em; margin-left: 0.4rem; vertical-align: middle;">#</a>
365+
</h2>
366+
<p class="section-header__desc">
367+
Seven hosts, three roles. Click any box to view its source code.
368+
</p>
369+
</div>
370+
371+
<div class="card" style="padding: var(--spacing-lg); overflow-x: auto;">
372+
<svg viewBox="0 0 960 760" style="width: 100%; min-width: 720px; height: auto; display: block;" xmlns="http://www.w3.org/2000/svg">
373+
<style>
374+
.arch-node { cursor: pointer; transition: opacity 0.15s ease, filter 0.15s ease; }
375+
.arch-node:hover { opacity: 0.85; filter: brightness(1.25); }
376+
.arch-node:hover rect { stroke-width: 2.5; }
377+
</style>
378+
<defs>
379+
<marker id="archArrow" markerWidth="9" markerHeight="7" refX="8" refY="3.5" orient="auto">
380+
<polygon points="0 0, 9 3.5, 0 7" fill="var(--text-muted)"/>
381+
</marker>
382+
</defs>
383+
384+
<!-- ===== connecting lines (drawn first, under boxes) ===== -->
385+
<!-- Browser -> server (direct) -->
386+
<line x1="125" y1="120" x2="125" y2="300" stroke="#06b6d4" stroke-width="2" marker-end="url(#archArrow)"/>
387+
<!-- stealth-dns -> server (direct) -->
388+
<line x1="355" y1="120" x2="355" y2="300" stroke="#06b6d4" stroke-width="2" stroke-dasharray="5,4" marker-end="url(#archArrow)"/>
389+
<!-- stealth-dns -> server2 (direct, ducks under relay) -->
390+
<path d="M 380 120 L 380 253 L 520 253 L 520 300" fill="none" stroke="#06b6d4" stroke-width="2" stroke-dasharray="5,4" marker-end="url(#archArrow)"/>
391+
<!-- agent -> relay -->
392+
<line x1="605" y1="120" x2="605" y2="150" stroke="#06b6d4" stroke-width="2" marker-end="url(#archArrow)"/>
393+
<!-- reg -> relay -->
394+
<line x1="835" y1="120" x2="835" y2="150" stroke="#06b6d4" stroke-width="2" marker-end="url(#archArrow)"/>
395+
<!-- relay -> server2 -->
396+
<line x1="720" y1="230" x2="720" y2="300" stroke="#f59e0b" stroke-width="2" stroke-dasharray="5,4" marker-end="url(#archArrow)"/>
397+
<!-- relay -> server (also reachable) -->
398+
<path d="M 600 230 L 600 277 L 400 277 L 400 300" fill="none" stroke="#f59e0b" stroke-width="2" stroke-dasharray="5,4" marker-end="url(#archArrow)"/>
399+
<!-- server -> ac -->
400+
<line x1="240" y1="400" x2="240" y2="430" stroke="#00ff9d" stroke-width="2" marker-end="url(#archArrow)"/>
401+
<!-- server2 -> ac2 -->
402+
<line x1="720" y1="400" x2="720" y2="430" stroke="#00ff9d" stroke-width="2" stroke-dasharray="5,4" marker-end="url(#archArrow)"/>
403+
<!-- ac -> resource -->
404+
<path d="M 260 520 L 260 535 L 400 535 L 400 550" fill="none" stroke="#a855f7" stroke-width="2" stroke-dasharray="5,4" marker-end="url(#archArrow)"/>
405+
<!-- ac2 -> resource -->
406+
<path d="M 700 520 L 700 535 L 560 535 L 560 550" fill="none" stroke="#a855f7" stroke-width="2" stroke-dasharray="5,4" marker-end="url(#archArrow)"/>
407+
408+
<!-- ===== Row A: clients ===== -->
409+
<a href="https://github.com/OpenNHP/opennhp/tree/main/examples/server_plugin/basic" target="_blank" rel="noopener" class="arch-node">
410+
<rect x="20" y="30" width="210" height="90" rx="10" fill="rgba(6,182,212,0.08)" stroke="#06b6d4" stroke-width="1.5"/>
411+
<text x="125" y="60" text-anchor="middle" fill="var(--text-primary)" font-size="16" font-weight="700" text-decoration="underline">Browser / User</text>
412+
<text x="125" y="85" text-anchor="middle" fill="var(--text-muted)" font-size="14">opens auth page directly</text>
413+
<text x="125" y="108" text-anchor="middle" fill="var(--text-muted)" font-size="13">not an NHP component</text>
414+
</a>
415+
416+
<a href="https://github.com/OpenNHP/stealth-dns" target="_blank" rel="noopener" class="arch-node">
417+
<rect x="250" y="30" width="210" height="90" rx="10" fill="rgba(6,182,212,0.08)" stroke="#06b6d4" stroke-width="1.5"/>
418+
<text x="355" y="60" text-anchor="middle" fill="var(--text-primary)" font-size="16" font-weight="700" text-decoration="underline">stealth-dns</text>
419+
<text x="355" y="85" text-anchor="middle" fill="var(--text-muted)" font-size="14">NHP-Agent</text>
420+
<text x="355" y="108" text-anchor="middle" fill="var(--text-muted)" font-size="13">talks to both Servers, no relay</text>
421+
</a>
422+
423+
<a href="https://github.com/OpenNHP/opennhp/blob/main/endpoints/js-agent/examples/relay-test.html" target="_blank" rel="noopener" class="arch-node">
424+
<rect x="500" y="30" width="210" height="90" rx="10" fill="rgba(6,182,212,0.08)" stroke="#06b6d4" stroke-width="1.5"/>
425+
<text x="605" y="60" text-anchor="middle" fill="var(--text-primary)" font-size="16" font-weight="700" text-decoration="underline">agent.opennhp.org</text>
426+
<text x="605" y="85" text-anchor="middle" fill="var(--text-muted)" font-size="14">NHP-Agent</text>
427+
<text x="605" y="108" text-anchor="middle" fill="var(--text-muted)" font-size="13">sends the NHP knock</text>
428+
</a>
429+
430+
<a href="https://github.com/OpenNHP/opennhp/blob/main/endpoints/js-agent/examples/reg.html" target="_blank" rel="noopener" class="arch-node">
431+
<rect x="730" y="30" width="210" height="90" rx="10" fill="rgba(6,182,212,0.08)" stroke="#06b6d4" stroke-width="1.5"/>
432+
<text x="835" y="60" text-anchor="middle" fill="var(--text-primary)" font-size="16" font-weight="700" text-decoration="underline">reg.opennhp.org</text>
433+
<text x="835" y="85" text-anchor="middle" fill="var(--text-muted)" font-size="14">NHP-Agent</text>
434+
<text x="835" y="108" text-anchor="middle" fill="var(--text-muted)" font-size="13">sends registration messages</text>
435+
</a>
436+
437+
<!-- ===== Row B: relay ===== -->
438+
<a href="https://github.com/OpenNHP/opennhp/tree/main/endpoints/relay" target="_blank" rel="noopener" class="arch-node">
439+
<rect x="500" y="150" width="440" height="80" rx="10" fill="rgba(245,158,11,0.08)" stroke="#f59e0b" stroke-width="1.5"/>
440+
<text x="720" y="184" text-anchor="middle" fill="var(--text-primary)" font-size="16" font-weight="700" text-decoration="underline">relay.opennhp.org — NHP-Relay</text>
441+
<text x="720" y="210" text-anchor="middle" fill="var(--text-muted)" font-size="14">translates HTTP requests into NHP UDP messages</text>
442+
</a>
443+
444+
<!-- ===== Row C: servers ===== -->
445+
<a href="https://github.com/OpenNHP/opennhp/tree/main/endpoints/server" target="_blank" rel="noopener" class="arch-node">
446+
<rect x="20" y="300" width="440" height="100" rx="10" fill="rgba(0,255,157,0.07)" stroke="#00ff9d" stroke-width="1.5"/>
447+
<text x="240" y="334" text-anchor="middle" fill="var(--text-primary)" font-size="17" font-weight="700" text-decoration="underline">server.opennhp.org</text>
448+
<text x="240" y="360" text-anchor="middle" fill="var(--text-secondary)" font-size="14.5">NHP-Server · plugin auth</text>
449+
<text x="240" y="383" text-anchor="middle" fill="var(--text-muted)" font-size="13.5">HTTPS exposed — reachable directly</text>
450+
</a>
451+
452+
<a href="https://github.com/OpenNHP/opennhp/tree/main/endpoints/server" target="_blank" rel="noopener" class="arch-node">
453+
<rect x="500" y="300" width="440" height="100" rx="10" fill="rgba(0,255,157,0.05)" stroke="#00ff9d" stroke-width="1.5" stroke-dasharray="6,4"/>
454+
<text x="720" y="334" text-anchor="middle" fill="var(--text-primary)" font-size="17" font-weight="700" text-decoration="underline">server2.opennhp.org</text>
455+
<text x="720" y="360" text-anchor="middle" fill="var(--text-secondary)" font-size="14.5">NHP-Server · NHP knock only</text>
456+
<text x="720" y="383" text-anchor="middle" fill="var(--text-muted)" font-size="13.5">fully invisible — no exposed surface</text>
457+
</a>
458+
459+
<!-- ===== Row D: access controllers ===== -->
460+
<a href="https://github.com/OpenNHP/opennhp/tree/main/endpoints/ac" target="_blank" rel="noopener" class="arch-node">
461+
<rect x="20" y="430" width="440" height="90" rx="10" fill="rgba(168,85,247,0.07)" stroke="#a855f7" stroke-width="1.5" stroke-dasharray="6,4"/>
462+
<text x="240" y="466" text-anchor="middle" fill="var(--text-primary)" font-size="17" font-weight="700" text-decoration="underline">ac.opennhp.org</text>
463+
<text x="240" y="492" text-anchor="middle" fill="var(--text-muted)" font-size="14">NHP-AC · invisible · controlled by server</text>
464+
</a>
465+
466+
<a href="https://github.com/OpenNHP/opennhp/tree/main/endpoints/ac" target="_blank" rel="noopener" class="arch-node">
467+
<rect x="500" y="430" width="440" height="90" rx="10" fill="rgba(168,85,247,0.07)" stroke="#a855f7" stroke-width="1.5" stroke-dasharray="6,4"/>
468+
<text x="720" y="466" text-anchor="middle" fill="var(--text-primary)" font-size="17" font-weight="700" text-decoration="underline">ac2.opennhp.org</text>
469+
<text x="720" y="492" text-anchor="middle" fill="var(--text-muted)" font-size="14">NHP-AC · invisible · controlled by server2</text>
470+
</a>
471+
472+
<!-- ===== Row E: shared protected resource ===== -->
473+
<a href="https://github.com/OpenNHP/opennhp/blob/main/examples/server_plugin/basic/templates/example_acdemo.html" target="_blank" rel="noopener" class="arch-node">
474+
<rect x="270" y="550" width="420" height="110" rx="10" fill="rgba(59,130,246,0.1)" stroke="#3b82f6" stroke-width="2"/>
475+
<text x="480" y="592" text-anchor="middle" fill="var(--text-primary)" font-size="17" font-weight="700" text-decoration="underline">Protected Demo Page</text>
476+
<text x="480" y="624" text-anchor="middle" fill="var(--text-muted)" font-size="16">shared by ac and ac2 — behind the invisible doors</text>
477+
</a>
478+
479+
<!-- ===== Legend ===== -->
480+
<g transform="translate(20, 700)">
481+
<circle cx="6" cy="0" r="5" fill="none" stroke="#06b6d4" stroke-width="2"/>
482+
<text x="18" y="4" fill="var(--text-secondary)" font-size="14.5">NHP-Agent</text>
483+
<circle cx="126" cy="0" r="5" fill="none" stroke="#f59e0b" stroke-width="2"/>
484+
<text x="138" y="4" fill="var(--text-secondary)" font-size="14.5">NHP-Relay</text>
485+
<circle cx="246" cy="0" r="5" fill="none" stroke="#00ff9d" stroke-width="2"/>
486+
<text x="258" y="4" fill="var(--text-secondary)" font-size="14.5">NHP-Server</text>
487+
<circle cx="378" cy="0" r="5" fill="none" stroke="#a855f7" stroke-width="2"/>
488+
<text x="390" y="4" fill="var(--text-secondary)" font-size="14.5">NHP-AC</text>
489+
<circle cx="470" cy="0" r="5" fill="none" stroke="#3b82f6" stroke-width="2"/>
490+
<text x="482" y="4" fill="var(--text-secondary)" font-size="14.5">Protected Resource</text>
491+
<line x1="660" y1="0" x2="690" y2="0" stroke="var(--text-muted)" stroke-width="2" stroke-dasharray="5,4"/>
492+
<text x="696" y="4" fill="var(--text-secondary)" font-size="14.5">invisible pre-auth</text>
493+
</g>
494+
</svg>
495+
</div>
496+
497+
<div style="display: flex; flex-direction: column; gap: 0.6rem; margin-top: var(--spacing-lg); color: var(--text-secondary); font-size: 0.92rem; line-height: 1.7;">
498+
<p style="margin: 0;"><strong style="color: var(--text-primary);">1.</strong> For the plugin-auth path, a person opens <span style="color: var(--accent-primary);">server</span>'s browser auth page directly — no Agent or relay involved at all.</p>
499+
<p style="margin: 0;"><strong style="color: var(--text-primary);">2.</strong> <code style="background: rgba(255,255,255,0.06); padding: 0.1rem 0.4rem; border-radius: 4px; font-family: var(--font-mono); font-size: 0.9em;">stealth-dns</code> is a third NHP-Agent instance that reaches <strong>both</strong> <span style="color: var(--accent-primary);">server</span> and <span style="color: var(--accent-primary);">server2</span> directly, bypassing <span style="color: #f59e0b;">relay</span> entirely.</p>
500+
<p style="margin: 0;"><strong style="color: var(--text-primary);">3.</strong> <code style="background: rgba(255,255,255,0.06); padding: 0.1rem 0.4rem; border-radius: 4px; font-family: var(--font-mono); font-size: 0.9em;">agent</code> (knock) and <code style="background: rgba(255,255,255,0.06); padding: 0.1rem 0.4rem; border-radius: 4px; font-family: var(--font-mono); font-size: 0.9em;">reg</code> (registration) go through <span style="color: #f59e0b;">relay</span>, which translates their HTTP requests into NHP UDP messages and can reach either <span style="color: var(--accent-primary);">server</span> or the fully-invisible <span style="color: var(--accent-primary);">server2</span>.</p>
501+
<p style="margin: 0;"><strong style="color: var(--text-primary);">4.</strong> Each Server controls its own <span style="color: #a855f7;">NHP-AC</span><code style="background: rgba(255,255,255,0.06); padding: 0.1rem 0.4rem; border-radius: 4px; font-family: var(--font-mono); font-size: 0.9em;">server → ac</code>, <code style="background: rgba(255,255,255,0.06); padding: 0.1rem 0.4rem; border-radius: 4px; font-family: var(--font-mono); font-size: 0.9em;">server2 → ac2</code>. Both ACs are invisible regardless of which path was used to authenticate.</p>
502+
<p style="margin: 0;"><strong style="color: var(--text-primary);">5.</strong> <code style="background: rgba(255,255,255,0.06); padding: 0.1rem 0.4rem; border-radius: 4px; font-family: var(--font-mono); font-size: 0.9em;">ac</code> and <code style="background: rgba(255,255,255,0.06); padding: 0.1rem 0.4rem; border-radius: 4px; font-family: var(--font-mono); font-size: 0.9em;">ac2</code> both reveal the <strong>same</strong> protected demo page — two independent, invisible doors into one resource, not two separate resources.</p>
503+
</div>
504+
</div>
505+
</section>
506+
357507
<!-- Hiding Server Ports -->
358508
<section class="section" style="background: var(--bg-secondary);">
359509
<div class="container">

0 commit comments

Comments
 (0)