="UTF-8"> Home Infrastructure — Interactive Diagram { --bg: #0d1117; --bg-card: #161b22; --border: #30363d; --text: #e6edf3; --text-muted: #8b949e; --accent: #58a6ff; --accent-dim: #1f6feb; --green: #3fb950; --orange: #d29922; --red: #f85149; --purple: #bc8cff; } * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif; background: var(--bg); color: var(--text); min-height: 100vh; display: flex; flex-direction: column; } header { background: var(--bg-card); border-bottom: 1px solid var(--border); padding: 16px 24px; display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 12px; } header h1 { font-size: 1.3rem; font-weight: 600; } header .subtitle { color: var(--text-muted); font-size: 0.85rem; margin-top: 2px; } .tabs { display: flex; gap: 4px; } .tab { background: transparent; border: 1px solid var(--border); color: var(--text-muted); padding: 8px 16px; border-radius: 6px; cursor: pointer; font-size: 0.9rem; transition: all 0.2s; } .tab.active { background: var(--accent-dim); color: #fff; border-color: var(--accent-dim); } .tab:hover:not(.active) { background: var(--bg); color: var(--text); } main { flex: 1; display: flex; min-height: 0; } .diagram-panel { flex: 1; padding: 24px; overflow: auto; display: flex; flex-direction: column; align-items: center; min-width: 0; } .diagram-panel > div { width: 100%; max-width: 100%; } .detail-panel { width: 380px; background: var(--bg-card); border-left: 1px solid var(--border); padding: 24px; overflow-y: auto; display: flex; flex-direction: column; gap: 16px; flex-shrink: 0; } .detail-panel .hint { color: var(--text-muted); font-size: 0.85rem; line-height: 1.6; text-align: center; padding: 40px 20px; } .detail-title { font-size: 1.1rem; font-weight: 600; color: var(--accent); display: flex; align-items: center; gap: 8px; } .detail-section { margin-top: 8px; } .detail-section h3 { font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-muted); margin-bottom: 6px; } .detail-section p, .detail-section li { font-size: 0.9rem; line-height: 1.6; color: var(--text); } .detail-section ul { padding-left: 18px; } .detail-section li { margin-bottom: 4px; } .detail-section code { background: var(--bg); padding: 2px 6px; border-radius: 4px; font-size: 0.85em; color: var(--purple); } .tag { display: inline-block; padding: 2px 8px; border-radius: 10px; font-size: 0.75rem; font-weight: 500; margin-right: 4px; margin-bottom: 4px; } .tag.lan { background: #1a3a2a; color: var(--green); } .tag.public { background: #3a2a1a; color: var(--orange); } .tag.ai { background: #2a1a3a; color: var(--purple); } .tag.tls { background: #1a2a3a; color: var(--accent); } .legend { display: flex; gap: 16px; flex-wrap: wrap; padding: 12px 24px; background: var(--bg-card); border-top: 1px solid var(--border); font-size: 0.8rem; color: var(--text-muted); } .legend-item { display: flex; align-items: center; gap: 6px; } .legend-swatch { width: 14px; height: 14px; border-radius: 3px; } .mermaid { text-align: center; width: 100%; } .mermaid svg { max-width: 100%; height: auto; } .loading { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 80px; color: var(--text-muted); gap: 16px; } .spinner { width: 40px; height: 40px; border: 3px solid var(--border); border-top-color: var(--accent); border-radius: 50%; animation: spin 0.8s linear infinite; } @keyframes spin { to { transform: rotate(360deg); } } .error-box { background: #3d1f1f; border: 1px solid var(--red); border-radius: 8px; padding: 20px; max-width: 600px; margin: 40px; color: var(--text); } .error-box h3 { color: var(--red); margin-bottom: 8px; } .error-box p { color: var(--text-muted); line-height: 1.6; font-size: 0.9rem; } .error-box code { background: var(--bg); padding: 2px 6px; border-radius: 4px; font-size: 0.85em; color: var(--purple); } @media (max-width: 900px) { main { flex-direction: column; } .detail-panel { width: 100%; border-left: none; border-top: 1px solid var(--border); max-height: 40vh; } }

Home Infrastructure
plonito.at — Updated 2026-10-11
Loading diagram...
Click on any component in the diagram to see detailed information.
LAN only
Public access
AI / inference
TLS termination
internet: { title: "Internet", tags: ["public"], sections: [ { heading: "External Access", body: "All public traffic enters via the home router (ZTE). The router performs SSL inspection on outgoing traffic, which affects local testing but not the actual proxy chain." } ] }, router: { title: "Home Router (ZTE)", tags: ["public"], sections: [ { heading: "Role", body: "Routes traffic between Internet, LAN (192.168.68.0/24), and handles port forwarding to amore-server for public services." }, { heading: "Note", body: "Performs SSL inspection on outgoing traffic — use curl -k> for local testing." } ] }, pihole: { title: "Pi-hole DNS", tags: ["lan"], sections: [ { heading: "Hardware", body: "Raspberry Pi Zero (separate from both servers, no SSH access)" }, { heading: "Role", body: "Local DNS resolver and ad blocker for the home network. New plonito.at subdomains must be added manually via Pi-hole web admin — without this, local requests are intercepted and never reach the proxy chain." } ] }, wireguard: { title: "WireGuard VPN", tags: ["lan"], sections: [ { heading: "Network", body: "10.10.10.0/24 on UDP 51820 (amore-server at 10.10.10.1)" }, { heading: "Purpose", body: "Secure remote access to all LAN-only services (Grafana, Dozzle, Zigbee2MQTT, pgAdmin, MQTT, databases, etc.) when outside the home network." } ] }, amore: { title: "amore-server", tags: ["public", "lan"], sections: [ { heading: "Host", body: "Debian 13 (trixie), kernel 6.12.111, Ryzen 5 7640HS, ~29 GiB RAM" }, { heading: "Network", body: "192.168.68.131/24 (LAN), 10.10.10.1/24 (WireGuard)" }, { heading: "Storage", body: "908 GB root NVMe, 1.8 TB LUKS /mnt/data (45% used), 1.8 TB /mnt/backups (40% used, unencrypted)" }, { heading: "Role", body: "Central home server and public ingress point. Runs Docker 29.8.2 with 18 active Compose projects." } ] }, edge_proxy: { title: "Edge Proxy (nginx-proxy)", tags: ["tls", "public"], sections: [ { heading: "Stack", body: "/mnt/data/amore-server/projects/proxy/" }, { heading: "Components", body: "proxy-web-autocode> (nginx:1.29-alpine) owns :80/:443 · docker-gen-auto auto-generates config · letsencrypt-auto manages certs" }, { heading: "Routing", body: "Services advertise routes via VIRTUAL_HOST environment variables. Must be on the proxycode> Docker network." }, { heading: "TLS", body: "Let's Encrypt via HTTP-01. SSL policy: Mozilla-Intermediate (TLSv1.2 + TLSv1.3)." } ] }, ai_forwarder: { title: "AI Server Forwarder", tags: ["tls", "public"], sections: [ { heading: "Location", body: "/mnt/data/amore-server/projects/ai-server/" }, { heading: "Image", body: "nginx:1.29-alpine (pinned)" }, { heading: "Purpose", body: "Edge forwarder for ai-server services. Uses VIRTUAL_HOST + LETSENCRYPT_HOST so acme-companion handles certs while pointing to remote host." }, { heading: "Config", body: "Forwards to http://192.168.68.56:80 (ai-server Caddy). WebSocket support + 300s timeouts for LLM streaming." }, { heading: "Current Domains", body: "ai.plonito.at (Open WebUI), diagram.plonito.at (Infrastructure Diagram)" } ] }, ddns: { title: "Hetzner DDNS", tags: ["public"], sections: [ { heading: "Location", body: "/mnt/data/amore-server/projects/hetzner-ddns/stefan_hetzner_ddns.json" }, { heading: "Role", body: "Keeps plonito.at subdomains pointing to current Hetzner public IP. Container: hetzner-ddns-stefan" }, { heading: "Current Records", body: "Includes ai (for ai.plonito.at), diagram (for diagram.plonito.at) plus all main service domains." } ] }, nextcloud: { title: "Nextcloud AIO", tags: ["public"], sections: [ { heading: "Domain", body: "cloud.plonito.at" }, { heading: "Backend", body: "via nginx-nc intermediate proxy → nextcloud-aio-apache:11000" }, { heading: "Legacy", body: "chaoticbits.soon.it → 301 redirect · chaoticcloud.soon.it → proxies to master container" } ] },