Skip to content

Architecture

Overview

The lab has three physical hosts: two Proxmox VE nodes and one Unraid storage and application server. No service ports are published to the internet; remote administration and services are reached through a Tailscale WireGuard mesh. Two AdGuard Home instances provide redundant DNS.

DNS and HTTPS routing are available on the LAN and through the private mesh, with no public port forwarding.

Logical topology

flowchart LR
    C[Client devices<br/>LAN or Tailscale mesh] --> A[AdGuard Home A<br/>primary DNS]
    C --> B[AdGuard Home B<br/>redundant DNS]
    A -. resolves name .-> P[Caddy<br/>HTTPS reverse proxy]
    B -. resolves name .-> P
    C -->|HTTPS| P
    P --> N1[Proxmox node 1<br/>LXC / core services]
    P --> N2[Proxmox node 2<br/>LXC / test workloads]
    P --> U[Unraid<br/>storage / Docker]
    PR[Prometheus<br/>collection] --> G[Grafana<br/>dashboards]
    R[Recovery scripts<br/>health / restart / notify]

Platform inventory

Platform Primary role Workload model
Proxmox node 1 Core infrastructure services LXC-first; VMs as needed
Proxmox node 2 Redundancy and network lab LXC, OpenWrt test VM, backup testing
Unraid server Storage and applications Docker containers

Workload placement rules

Proxmox VE

  • Use LXC for lightweight Linux services.
  • Use a VM when kernel isolation, a full guest OS, or a lab scenario requires it.
  • Keep core DNS and reverse-proxy roles independent from storage applications.

Unraid

  • Use it for storage and Docker-backed applications.
  • Keep persistent application data on managed storage.
  • Use ordered startup where dependencies require a network or tunnel first.

Failure-domain intent

Redundant DNS reduces the impact of a single service failure. Separating DNS, reverse proxy, compute and storage makes troubleshooting direct: name resolution, routing, host state and application state can each be tested independently.

Secure access and split DNS

flowchart LR
    L[LAN client] --> D[Local AdGuard Home]
    D -.->|"rewrite *.example.net"| P[Caddy]
    L -->|HTTPS| P
    P --> S[Internal service]
    R[Remote client] --> T[Tailscale]
    T -->|split DNS: domain queries traverse the mesh| D2[AdGuard Home]
    R -->|HTTPS via mesh| P

A LAN client resolves the service name through the local AdGuard Home, which rewrites *.example.net to Caddy; Caddy terminates HTTPS and proxies to the internal service. A remote client joins through Tailscale, and split DNS sends domain queries across the mesh, so the client reaches the same proxy and service.

Security controls

  • No public port forwarding.
  • Mesh membership required for remote access.
  • HTTPS for service interfaces.
  • Wildcard certificates issued through DNS-01.
  • DNS credentials scoped to the required zone permissions.
  • Secrets kept in protected environment or configuration storage, not source.
  • Internal endpoints on private address space.
  • Administrative interfaces not published to the internet.

Validation sequence

  1. Confirm the client is on the LAN or authenticated to Tailscale.
  2. Resolve the service FQDN and verify it returns the proxy address.
  3. Test TCP 443 to Caddy.
  4. Validate the certificate name and chain.
  5. If routing fails, test the upstream directly from the proxy host.