Files
netbird-selfhosted/caddy-netbird-diagram.html
2026-04-21 16:19:55 +08:00

332 lines
15 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Caddy 反向代理架構</title>
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@500;700&family=Space+Grotesk:wght@500;700&display=swap" rel="stylesheet">
<style>
:root {
--bg: #0f1419;
--bg-2: #1a2129;
--border: #2d3942;
--text: #e6edf3;
--text-muted: #8b98a5;
--caddy: #1dd1a1;
--yellow: #ffd166;
--cyan: #5ec9d6;
--purple: #a29bfe;
--pink: #ff6b9d;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: 'Space Grotesk', sans-serif;
background: radial-gradient(ellipse at top, #1a2129 0%, #0f1419 60%);
color: var(--text);
padding: 20px;
min-height: 100vh;
}
.container { max-width: 1100px; margin: 0 auto; }
h1 {
font-size: clamp(1.4rem, 4vw, 2rem);
font-weight: 700;
letter-spacing: -0.02em;
margin-bottom: 4px;
}
.sub {
font-family: 'JetBrains Mono', monospace;
color: var(--text-muted);
font-size: 0.85rem;
margin-bottom: 20px;
}
.sub .ip { color: var(--cyan); }
.diagram-wrap {
background: var(--bg-2);
border: 1px solid var(--border);
border-radius: 16px;
padding: 16px;
position: relative;
overflow: hidden;
}
.diagram-wrap::before {
content: '';
position: absolute;
inset: 0;
background-image:
linear-gradient(rgba(94,201,214,0.04) 1px, transparent 1px),
linear-gradient(90deg, rgba(94,201,214,0.04) 1px, transparent 1px);
background-size: 24px 24px;
pointer-events: none;
}
svg { display: block; width: 100%; height: auto; position: relative; z-index: 1; }
.legend {
display: flex;
gap: 18px;
flex-wrap: wrap;
margin-top: 16px;
padding-top: 14px;
border-top: 1px dashed var(--border);
font-family: 'JetBrains Mono', monospace;
font-size: 0.78rem;
color: var(--text-muted);
}
.legend-item { display: flex; align-items: center; gap: 6px; }
.legend-dot { width: 10px; height: 10px; border-radius: 50%; }
</style>
</head>
<body>
<div class="container">
<h1>Caddy 反向代理架構</h1>
<div class="sub">host: <span class="ip">192.168.42.127</span></div>
<div class="diagram-wrap">
<svg viewBox="0 0 1020 620" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="ar-y" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#ffd166"/>
</marker>
<marker id="ar-c" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#5ec9d6"/>
</marker>
<marker id="ar-p" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#a29bfe"/>
</marker>
<marker id="ar-pk" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#ff6b9d"/>
</marker>
<filter id="glow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur stdDeviation="2.5" result="blur"/>
<feMerge>
<feMergeNode in="blur"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
<linearGradient id="caddy-grad" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="#1dd1a1" stop-opacity="0.22"/>
<stop offset="100%" stop-color="#1dd1a1" stop-opacity="0.06"/>
</linearGradient>
<linearGradient id="host-grad" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#2d3942"/>
<stop offset="100%" stop-color="#1e2730"/>
</linearGradient>
<linearGradient id="nb-title-grad" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="#5ec9d6" stop-opacity="0.12"/>
<stop offset="100%" stop-color="#5ec9d6" stop-opacity="0"/>
</linearGradient>
</defs>
<!-- ===== Left port labels (with padding) ===== -->
<g font-family="JetBrains Mono, monospace">
<rect x="20" y="174" width="48" height="26" rx="5"
fill="#0f1419" stroke="#ffd166" stroke-width="1.4"/>
<text x="44" y="192" text-anchor="middle" font-size="12" font-weight="700" fill="#ffd166">:80</text>
<rect x="10" y="475" width="80" height="26" rx="5"
fill="#0f1419" stroke="#ff6b9d" stroke-width="1.4"/>
<text x="50" y="493" text-anchor="middle" font-size="11" font-weight="700" fill="#ff6b9d">:3478/udp</text>
</g>
<!-- ===== HOST boundary ===== -->
<rect x="110" y="60" width="560" height="520" rx="14"
fill="url(#host-grad)" stroke="#3a4a58" stroke-width="1.5" stroke-dasharray="6 4"/>
<text x="130" y="88" font-family="JetBrains Mono, monospace" font-size="13"
fill="#5ec9d6" font-weight="700">host · 192.168.42.127</text>
<!-- ===== Caddy box ===== -->
<g>
<rect x="140" y="125" width="330" height="285" rx="10"
fill="url(#caddy-grad)" stroke="#1dd1a1" stroke-width="1.8"/>
<text x="160" y="153" font-family="Space Grotesk" font-size="15" font-weight="700" fill="#1dd1a1">Caddy</text>
<text x="213" y="153" font-family="Space Grotesk" font-size="13" font-weight="500" fill="#8b98a5">反向代理</text>
<circle cx="285" cy="148" r="5" fill="#1dd1a1" opacity="0.8">
<animate attributeName="r" values="5;11;5" dur="2s" repeatCount="indefinite"/>
<animate attributeName="opacity" values="0.8;0;0.8" dur="2s" repeatCount="indefinite"/>
</circle>
<circle cx="285" cy="148" r="3.5" fill="#1dd1a1"/>
<g font-family="JetBrains Mono, monospace" font-size="12.5">
<!-- / at y=186 (→ dashboard) -->
<g>
<rect x="160" y="170" width="290" height="32" rx="6" fill="#0f1419" stroke="#2d3942"/>
<text x="176" y="191" fill="#ffd166" font-weight="700">/</text>
<text x="438" y="191" text-anchor="end" fill="#8b98a5">→ dashboard</text>
</g>
<!-- Dashed divider between dashboard routes and netbird routes -->
<line x1="170" y1="222" x2="440" y2="222" stroke="#2d3942" stroke-width="1" stroke-dasharray="3 4"/>
<!-- /api/* at y=265 -->
<g>
<rect x="160" y="249" width="290" height="32" rx="6" fill="#0f1419" stroke="#2d3942"/>
<text x="176" y="270" fill="#ffd166" font-weight="700">/api/*</text>
<text x="438" y="270" text-anchor="end" fill="#8b98a5">→ netbird-server</text>
</g>
<!-- /oauth2/* at y=303 -->
<g>
<rect x="160" y="287" width="290" height="32" rx="6" fill="#0f1419" stroke="#2d3942"/>
<text x="176" y="308" fill="#ffd166" font-weight="700">/oauth2/*</text>
<text x="438" y="308" text-anchor="end" fill="#8b98a5">→ netbird-server</text>
</g>
<!-- /relay* at y=341 -->
<g>
<rect x="160" y="325" width="290" height="32" rx="6" fill="#0f1419" stroke="#2d3942"/>
<text x="176" y="346" fill="#ffd166" font-weight="700">/relay*</text>
<text x="438" y="346" text-anchor="end" fill="#8b98a5">→ netbird-server</text>
</g>
<!-- gRPC at y=379 -->
<g>
<rect x="160" y="363" width="290" height="32" rx="6" fill="#0f1419" stroke="#a29bfe"/>
<text x="176" y="384" fill="#a29bfe" font-weight="700">gRPC</text>
<text x="438" y="384" text-anchor="end" fill="#8b98a5">→ netbird-server</text>
</g>
</g>
</g>
<!-- ===== dashboard target ===== -->
<g>
<rect x="720" y="156" width="280" height="60" rx="10"
fill="#1e2730" stroke="#ffd166" stroke-width="1.6"/>
<!-- window icon -->
<g transform="translate(740, 170)">
<rect x="0" y="0" width="32" height="26" rx="3" fill="none" stroke="#ffd166" stroke-width="1.4"/>
<line x1="0" y1="7" x2="32" y2="7" stroke="#ffd166" stroke-width="1.2"/>
<circle cx="4" cy="3.5" r="1" fill="#ffd166"/>
<circle cx="8" cy="3.5" r="1" fill="#ffd166"/>
<circle cx="12" cy="3.5" r="1" fill="#ffd166"/>
</g>
<text x="790" y="182" font-family="Space Grotesk" font-size="14" font-weight="700" fill="#e6edf3">dashboard</text>
<text x="790" y="202" font-family="JetBrains Mono, monospace" font-size="11" fill="#8b98a5">Web UI</text>
</g>
<!-- ===== netbird-server target ===== -->
<g>
<!-- Outer box -->
<rect x="720" y="222" width="280" height="248" rx="10"
fill="#1e2730" stroke="#5ec9d6" stroke-width="1.6"/>
<!-- Title band at top (clearly separated from entries) -->
<rect x="720" y="222" width="280" height="30" rx="10"
fill="url(#nb-title-grad)"/>
<!-- mask bottom corners of title bg so only top rounded -->
<rect x="720" y="240" width="280" height="12" fill="url(#nb-title-grad)"/>
<!-- Server stack icon (small, inside title band) -->
<g transform="translate(734, 230)" stroke="#5ec9d6" stroke-width="1.3" fill="none">
<rect x="0" y="0" width="22" height="5" rx="1"/>
<rect x="0" y="7" width="22" height="5" rx="1"/>
<rect x="0" y="14" width="22" height="5" rx="1"/>
<circle cx="3" cy="2.5" r="0.7" fill="#5ec9d6" stroke="none"/>
<circle cx="3" cy="9.5" r="0.7" fill="#5ec9d6" stroke="none"/>
<circle cx="3" cy="16.5" r="0.7" fill="#5ec9d6" stroke="none"/>
</g>
<text x="765" y="242" font-family="Space Grotesk" font-size="14" font-weight="700" fill="#e6edf3">netbird-server</text>
<!-- Divider under title -->
<line x1="730" y1="254" x2="990" y2="254" stroke="#2d3942" stroke-width="1"/>
<!-- Entries (well below title, aligned with Caddy row centers) -->
<g font-family="JetBrains Mono, monospace" font-size="11.5">
<!-- HTTP API at y=265 -->
<circle cx="730" cy="265" r="3" fill="#5ec9d6"/>
<text x="742" y="269" fill="#8b98a5">HTTP API</text>
<!-- OAuth2 at y=303 -->
<circle cx="730" cy="303" r="3" fill="#5ec9d6"/>
<text x="742" y="307" fill="#8b98a5">OAuth2</text>
<!-- Relay at y=341 -->
<circle cx="730" cy="341" r="3" fill="#5ec9d6"/>
<text x="742" y="345" fill="#8b98a5">Relay</text>
<!-- gRPC at y=379 -->
<circle cx="730" cy="379" r="3" fill="#a29bfe"/>
<text x="742" y="383" fill="#8b98a5">gRPC</text>
<!-- STUN at y=440 -->
<circle cx="730" cy="440" r="3" fill="#ff6b9d"/>
<text x="742" y="444" fill="#ff6b9d" font-weight="700">STUN (:3478/udp)</text>
</g>
</g>
<!-- ===== Paths (all orthogonal) ===== -->
<!-- :80 → Caddy -->
<path id="p-in" d="M 68 187 L 140 187"
stroke="#ffd166" stroke-width="2" fill="none" marker-end="url(#ar-y)"/>
<!-- / → dashboard (straight horizontal) -->
<path id="p-dash" d="M 470 186 L 720 186"
stroke="#ffd166" stroke-width="1.8" fill="none" stroke-opacity="0.55" marker-end="url(#ar-y)"/>
<!-- /api/* → HTTP API (straight) -->
<path id="p-api" d="M 470 265 L 720 265"
stroke="#5ec9d6" stroke-width="1.8" fill="none" stroke-opacity="0.55" marker-end="url(#ar-c)"/>
<!-- /oauth2/* → OAuth2 (straight) -->
<path id="p-oauth" d="M 470 303 L 720 303"
stroke="#5ec9d6" stroke-width="1.8" fill="none" stroke-opacity="0.55" marker-end="url(#ar-c)"/>
<!-- /relay* → Relay (straight) -->
<path id="p-relay" d="M 470 341 L 720 341"
stroke="#5ec9d6" stroke-width="1.8" fill="none" stroke-opacity="0.55" marker-end="url(#ar-c)"/>
<!-- gRPC → gRPC (straight) -->
<path id="p-grpc" d="M 470 379 L 720 379"
stroke="#a29bfe" stroke-width="1.8" fill="none" stroke-opacity="0.65" marker-end="url(#ar-p)"/>
<!-- :3478/udp → netbird STUN (L-shape) -->
<path id="p-stun" d="M 90 488 L 690 488 L 690 440 L 720 440"
stroke="#ff6b9d" stroke-width="2" fill="none" stroke-dasharray="6 4" marker-end="url(#ar-pk)"/>
<text x="360" y="512" font-family="JetBrains Mono, monospace" font-size="11"
fill="#ff6b9d" font-weight="700">STUN · 直送,不經 Caddy</text>
<!-- ===== Flow dots ===== -->
<circle r="4" fill="#ffd166" filter="url(#glow)">
<animateMotion dur="1.4s" repeatCount="indefinite"><mpath href="#p-in"/></animateMotion>
</circle>
<circle r="4" fill="#ffd166" filter="url(#glow)">
<animateMotion dur="1.4s" begin="-0.7s" repeatCount="indefinite"><mpath href="#p-in"/></animateMotion>
</circle>
<circle r="4" fill="#ffd166" filter="url(#glow)">
<animateMotion dur="1.8s" repeatCount="indefinite"><mpath href="#p-dash"/></animateMotion>
</circle>
<circle r="4" fill="#5ec9d6" filter="url(#glow)">
<animateMotion dur="1.8s" begin="-0.3s" repeatCount="indefinite"><mpath href="#p-api"/></animateMotion>
</circle>
<circle r="4" fill="#5ec9d6" filter="url(#glow)">
<animateMotion dur="1.8s" begin="-0.6s" repeatCount="indefinite"><mpath href="#p-oauth"/></animateMotion>
</circle>
<circle r="4" fill="#5ec9d6" filter="url(#glow)">
<animateMotion dur="1.8s" begin="-0.9s" repeatCount="indefinite"><mpath href="#p-relay"/></animateMotion>
</circle>
<circle r="4" fill="#a29bfe" filter="url(#glow)">
<animateMotion dur="1.8s" begin="-1.2s" repeatCount="indefinite"><mpath href="#p-grpc"/></animateMotion>
</circle>
<circle r="4" fill="#ff6b9d" filter="url(#glow)">
<animateMotion dur="2.4s" repeatCount="indefinite"><mpath href="#p-stun"/></animateMotion>
</circle>
<circle r="4" fill="#ff6b9d" filter="url(#glow)">
<animateMotion dur="2.4s" begin="-1.2s" repeatCount="indefinite"><mpath href="#p-stun"/></animateMotion>
</circle>
</svg>
<div class="legend">
<div class="legend-item"><span class="legend-dot" style="background:#ffd166"></span>HTTP (/) → dashboard</div>
<div class="legend-item"><span class="legend-dot" style="background:#5ec9d6"></span>HTTP (/api, /oauth2, /relay) → netbird-server</div>
<div class="legend-item"><span class="legend-dot" style="background:#a29bfe"></span>gRPC → netbird-server</div>
<div class="legend-item"><span class="legend-dot" style="background:#ff6b9d"></span>UDP :3478 STUN直送</div>
</div>
</div>
</div>
</body>
</html>