Files
dashcaddy.net/src/app/docs/integrations/page.tsx
T
Krystie a707816668 [pending-judge] docs(site): DC-165 uniformity — counts 77->78, internal-identifier sweep, advertise workflows/scheduled-backups/calendar/Connect AI, capabilities pointer for LLMs
Product-code half (fleet gate, capabilities endpoint, offline feature
migration, PREMIUM_FEATURES completion) lives in the dashcaddy repo, branch
dc/DC-165-uniformity — judged as one bundle.

Site edits (all claims verified against product source, see EVIDENCE [9]):
- template count 77 -> 78 EVERYWHERE (page.tsx, features, pricing, docs,
  blog bodies + manifest.ts frontmatter per three-way consistency rule,
  AppShowcase, DocsLayout, FaqSection). Source of truth:
  APP_TEMPLATES keys == 78.
- internal-identifier leak sweep: 85 occurrences of *.sami (internal TLD),
  an internal Git host URL, a private venv path, and a server-local repo
  path in pricing comment -> replaced with the documented .home style /
  generic wording. status.sami replaced by dashcaddy.local (product default
  dashboardHost). Verified ZERO remaining in rebuilt out/.
- advertise as Premium (owner decision 2026-10-09): pricing premium list +
  FAQ + docs/premium table + two new deep-dive sections (Workflow
  Automation: the five bundled ids from bundled-workflows.js; Scheduled
  Backups: schedule fields from the /backups/schedule schema, manual
  one-click + DR explicitly noted as free).
- calendar widget + hosted-Radicale auto-wiring advertised (features page
  chip + new docs/catalog/radicale install guide following house template
  structure; syncthing page mirrored for the placeholder conventions).
- Connect AI one-click key flow advertised (features chip).
- MCP card softened: 'entire infrastructure' -> the real tool scope +
  pointer to GET /api/v1/capabilities (public ground-truth manifest).
- llms.txt: capabilities endpoint pointer + 'prefer it over static prose'
  + MCP tool examples + premium gate list; robots.txt gains LLMs-Txt line.
- NOTE: a parked unrelated work-in-progress (dc-seo-r8 blog edits) was
  stashed before the build and is NOT in this commit.

Build gate: rm -rf .next out && npm run build -> clean, 123 static pages,
out/ greps zero stale counts/leaks.
2026-10-09 02:06:06 -07:00

300 lines
16 KiB
TypeScript

import Navbar from '@/components/Navbar';
import Footer from '@/components/Footer';
import DocsLayout from '@/components/docs/DocsLayout';
export default function DocsIntegrationsPage() {
return (
<div className="flex min-h-screen flex-col bg-surface-950 text-surface-50">
<Navbar />
<DocsLayout
title="Infrastructure Integrations"
intro="DashCaddy is most valuable when its supporting integrations are healthy. This guide explains each layer it expects to work with, what it does, and how the pieces fit together into a single control plane."
>
<p>
DashCaddy is not a monolith. It is an orchestration layer that drives several independent infrastructure
components — a container runtime, a reverse proxy, a DNS server, a certificate authority, a private network,
a metrics pipeline, and an AI surface. Each integration is swappable, observable, and independently debuggable.
When you understand what each layer is responsible for, you can pinpoint failures in minutes instead of guessing.
</p>
<p>
This guide walks every integration in depth: what it does, how DashCaddy talks to it, the configuration it
expects, and a code example where relevant. Read it end-to-end once, then come back to specific sections when
something goes wrong. For a quick diagnostic flow, see the <a href="/docs/troubleshooting">Troubleshooting</a> guide.
</p>
<h2>Docker — container runtime</h2>
<p>
Docker (and Docker Compose) is the runtime foundation for every deployment workflow, container lifecycle action,
service discovery sweep, and template-based launch. DashCaddy communicates with the Docker daemon over the
Unix socket (<code>/var/run/docker.sock</code>) to start, stop, restart, inspect, and adopt containers, and to
deploy the <strong>78 one-click application templates</strong> from the catalog.
</p>
<p>
The daemon connection is established at startup. If the socket is missing or permissioned for a different user,
DashCaddy&apos;s <code>/readyz</code> probe will fail immediately — a fast signal that the runtime layer is broken.
During the <strong>Smart Defaults Wizard</strong>, DashCaddy probes the socket, reports the Docker version, and
suggests socket paths if the default is not found.
</p>
<p>
Optional <strong>Docker Swarm</strong> support (Premium) extends the same model across multiple nodes. When
Swarm mode is enabled, DashCaddy switches from single-container operations to service-level operations, managing
placement, replicas, and rolling updates across the cluster. See <a href="/docs/premium">Premium Features</a>.
</p>
<pre className="mt-4 overflow-x-auto rounded-lg border border-surface-700/50 bg-surface-950/80 p-4 text-sm"><code>{`# Verify the Docker socket DashCaddy will use
docker version
ls -l /var/run/docker.sock
# The DashCaddy container needs the socket mounted:
docker run -d \\
-v /var/run/docker.sock:/var/run/docker.sock \\
-p 3000:3000 \\
ghcr.io/dashcaddy/dashcaddy:latest`}</code></pre>
<blockquote className="border-l-4 border-brand-500/50 bg-brand-500/5 p-4 rounded-r-lg">
<p className="text-surface-300">
<strong className="text-brand-400">Note:</strong> Mounting the Docker socket grants full container control.
In production, run DashCaddy behind Tailscale or a firewall so the dashboard is not exposed to the public
internet.
</p>
</blockquote>
<h2>Caddy — reverse proxy &amp; automatic HTTPS</h2>
<p>
Caddy is the reverse proxy and automatic HTTPS layer. Every service you publish through DashCaddy gets a Caddy
route that terminates TLS and proxies traffic to the upstream container. DashCaddy communicates with the
<strong> Caddy Admin API</strong> (default <code>localhost:2019</code>) to create, update, and remove routes,
and to trigger certificate issuance on demand.
</p>
<p>
Caddy&apos;s built-in internal CA auto-generates and renews certificates for every published service. For
public domains, Caddy can also use ACME (Let&apos;s Encrypt / ZeroSSL) automatically. The choice between
internal and public CA is made per-service at publish time, so you can mix internet-facing and lab services
on the same host without conflict.
</p>
<h3>Caddyfile-as-Code</h3>
<p>
Instead of hand-editing Caddyfiles, DashCaddy exposes a <strong>visual Caddyfile-as-Code builder</strong>. You
describe the desired route — hostname, upstream, TLS options, headers, redirects, compression — and DashCaddy
generates the valid Caddy configuration and applies it atomically through the Admin API. Configuration is
versioned and reviewable, so every change is auditable and reversible.
</p>
<p>
The generated config is rendered in the service&apos;s <strong>Caddyfile-as-Code view</strong>, so you can
inspect exactly what Caddy will receive before it is applied. If a route misbehaves, compare the rendered config
against your expectation. Invalid configs are rejected before they reach Caddy, preventing the proxy from
reloading into a broken state.
</p>
<pre className="mt-4 overflow-x-auto rounded-lg border border-surface-700/50 bg-surface-950/80 p-4 text-sm"><code>{`# Example generated Caddyfile (internal CA, lab hostname)
media.lab {
tls internal
encode zstd gzip
reverse_proxy localhost:8096 {
header_up X-Forwarded-Host {host}
header_up X-Real-IP {remote_host}
}
header {
Strict-Transport-Security "max-age=31536000"
X-Content-Type-Options nosniff
}
}`}</code></pre>
<h2>Technitium DNS — DNS automation</h2>
<p>
Technitium DNS is the DNS automation target for record creation and removal. When you deploy or adopt a service,
DashCaddy creates the corresponding A or CNAME record through the Technitium REST API so the new hostname
resolves immediately. Removing a service cleans up the record automatically — no orphaned DNS entries.
</p>
<p>
DashCaddy needs three pieces of information to drive Technitium: the server URL, an API token with write access
to the target zone, and the zone name itself. All three are configured during the Smart Defaults Wizard or
later under <strong>Settings → DNS</strong>. A common failure mode is a token with the wrong scope — it can
read records but not create them — which fails silently. Always verify the token can write to the zone you
intend to use.
</p>
<p>
Internal zones (e.g. <code>.lab</code>) only resolve if the client uses Technitium as its resolver. Public
resolvers like 8.8.8.8 will not know about them. For remote clients, either point their DNS at Technitium
directly or use <strong>Tailscale</strong> with a MagicDNS / split-DNS setup.
</p>
<pre className="mt-4 overflow-x-auto rounded-lg border border-surface-700/50 bg-surface-950/80 p-4 text-sm"><code>{`# Create a record directly via the Technitium API (debugging)
curl -X POST "http://technitium-host:5380/api/zones/records/add" \\
-d "token=***" \\
-d "zone=lab" \\
-d "domain=media.lab" \\
-d "type=A" \\
-d "ipAddress=192.168.1.50"
# Verify the record resolves through Technitium
dig @technitium-host media.lab +short`}</code></pre>
<h2>DashCA — internal certificate authority</h2>
<p>
DashCA is the certificate distribution system that makes internal HTTPS practical. Caddy&apos;s internal CA
issues certificates automatically for <code>.lab</code> and other private hostnames; DashCA provides the
distribution page where you download the root certificate and install it as a trusted CA across your devices.
Once trusted, every internal service is served over valid HTTPS with no browser warnings.
</p>
<p>
The root certificate must be installed on <strong>each client device</strong> that will access internal
services — not just the server. A macOS laptop, a Windows desktop, and an Android phone each need the cert
installed separately. The DashCA page includes per-platform instructions (macOS Keychain, Windows certmgr,
Linux <code>update-ca-certificates</code>, and mobile profiles) to make this straightforward.
</p>
<p>
After installing the root CA, restart your browser or clear its certificate cache. Chrome and Firefox maintain
separate trust stores on some platforms; Firefox may need the import done from within its own settings.
</p>
<h2>Tailscale — private access</h2>
<p>
DashCaddy fits naturally into private access patterns with <strong>Tailscale</strong>. Services can be published
only on a Tailnet, keeping them off the public internet while still benefiting from DashCaddy&apos;s DNS, proxy,
and TLS automation. This is ideal for home labs, internal team tools, and any service that should never be
internet-facing.
</p>
<p>
The typical setup runs Tailscale on the DashCaddy host, advertises the host on the Tailnet, and optionally
enables MagicDNS so Tailnet hostnames resolve without a separate DNS server. Combine with Technitium split-DNS
for the most seamless experience: Technitium handles <code>.lab</code> zones for Tailnet clients, while public
domains resolve normally.
</p>
<pre className="mt-4 overflow-x-auto rounded-lg border border-surface-700/50 bg-surface-950/80 p-4 text-sm"><code>{`# Install and authenticate Tailscale on the DashCaddy host
curl -fsSL https://tailscale.com/install.sh | sh
tailscale up --advertise-routes=192.168.1.0/24 --accept-routes
# Verify the host is on the Tailnet
tailscale status
tailscale ip
# From another Tailnet device, reach the service directly
curl -k https://dashcaddy-host.tailnet-name.ts.net/media.lab`}</code></pre>
<blockquote className="border-l-4 border-brand-500/50 bg-brand-500/5 p-4 rounded-r-lg">
<p className="text-surface-300">
<strong className="text-brand-400">Tip:</strong> If you publish services only on the Tailnet, set Caddy to
bind to the Tailscale interface IP rather than <code>0.0.0.0</code>. This guarantees the service is
unreachable from the LAN even if the firewall is misconfigured.
</p>
</blockquote>
<h2>Prometheus &amp; Grafana — metrics &amp; observability</h2>
<p>
DashCaddy exports metrics in Prometheus format at <code>/metrics</code>, including service health, container
status, request counts, certificate expiry, and system resource indicators. Point your Prometheus scraper at
the endpoint and build Grafana dashboards on top for long-term observability, capacity planning, and alerting.
</p>
<p>
The metrics endpoint is unauthenticated by default for internal scraping. If your Prometheus instance is on a
different host or network, place it behind the same Tailscale Tailnet or restrict access with a reverse-proxy
basic-auth rule in Caddy.
</p>
<pre className="mt-4 overflow-x-auto rounded-lg border border-surface-700/50 bg-surface-950/80 p-4 text-sm"><code>{`# prometheus.yml — scrape DashCaddy
scrape_configs:
- job_name: 'dashcaddy'
metrics_path: /metrics
static_configs:
- targets: ['dashcaddy-host:3000']
# Optional: increase scrape frequency for faster alerting
scrape_interval: 15s
scrape_timeout: 10s`}</code></pre>
<p>
Useful PromQL starters once data is flowing: <code>dashcaddy_service_health == 0</code> (unhealthy services),
<code> rate(dashcaddy_http_requests_total[5m])</code> (request throughput), and
<code>dashcaddy_cert_expiry_days &lt; 14</code> (certificates expiring soon).
</p>
<h2>MCP Server &amp; AI assistants</h2>
<p>
The built-in <strong>MCP (Model Context Protocol) Server</strong> exposes DashCaddy operations to AI assistants
and external automation. Combined with the <strong>AI Intent Router</strong>, you can issue natural-language
commands — &ldquo;restart the media server&rdquo;, &ldquo;deploy the postgres template&rdquo;, &ldquo;is the
database healthy?&rdquo; — and have DashCaddy execute the real infrastructure action through the standard MCP
tool interface.
</p>
<p>
This turns DashCaddy into an AI-operable control plane: the same operations available in the dashboard are
available as MCP tools, so an assistant like Claude or GPT can inspect and manage your infrastructure directly.
Full setup instructions, the tool catalog, and intent examples are in the <a href="/docs/api">API and Automation</a> guide.
</p>
<h2>How the layers fit together</h2>
<p>
The table below maps each integration to the layer it provides and the DashCaddy feature that consumes it.
When a service fails, locate the row whose symptom matches, then debug that integration directly.
</p>
<table>
<thead>
<tr>
<th>Layer</th>
<th>Integration</th>
<th>DashCaddy feature that uses it</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Runtime</strong></td>
<td>Docker / Docker Compose</td>
<td>Deploy, adopt, lifecycle, templates, service discovery</td>
</tr>
<tr>
<td><strong>Proxy</strong></td>
<td>Caddy (Admin API)</td>
<td>Reverse proxy routes, Caddyfile-as-Code, auto HTTPS</td>
</tr>
<tr>
<td><strong>DNS</strong></td>
<td>Technitium DNS</td>
<td>Automatic A/CNAME record creation &amp; cleanup</td>
</tr>
<tr>
<td><strong>Trust</strong></td>
<td>DashCA (internal CA)</td>
<td>Root certificate distribution for internal HTTPS</td>
</tr>
<tr>
<td><strong>Access</strong></td>
<td>Tailscale</td>
<td>Private networking, Tailnet-only publishing</td>
</tr>
<tr>
<td><strong>Observe</strong></td>
<td>Prometheus / Grafana</td>
<td>Metrics export, alerting, long-term dashboards</td>
</tr>
<tr>
<td><strong>Automate</strong></td>
<td>MCP Server + AI Intent Router</td>
<td>Natural-language ops, AI assistant tool surface</td>
</tr>
<tr>
<td><strong>Secure</strong></td>
<td>Security Center + audit log</td>
<td>Event aggregation, change auditing, RBAC</td>
</tr>
</tbody>
</table>
<h2>Operational flow: deploy to observe</h2>
<p>
When everything is wired correctly, a single service publish triggers the full chain automatically:
</p>
<ol>
<li><strong>Deploy / Adopt</strong> — Docker runs the container (or adopts an existing one).</li>
<li><strong>Publish</strong> — Caddy creates the reverse-proxy route and requests a TLS certificate.</li>
<li><strong>Resolve</strong> — Technitium DNS creates the hostname record so the domain resolves.</li>
<li><strong>Trust</strong> — DashCA distributes the root CA so clients accept the internal cert.</li>
<li><strong>Observe</strong> — health checks, Prometheus metrics, and WebSocket live updates report state.</li>
<li><strong>Secure</strong> — Security Center aggregates events; audit logging records every change.</li>
</ol>
<p>
Each step is independently observable. If a service is unreachable, walk the chain in order — the first broken
step is your failure. For the full diagnostic procedure, see <a href="/docs/troubleshooting">Troubleshooting</a>.
</p>
</DocsLayout>
<Footer />
</div>
);
}