[grade=B] Align premium marketing and documentation

This commit is contained in:
Krystie
2026-08-22 19:08:01 -07:00
parent e58130756e
commit ac2feb5ab7
13 changed files with 2114 additions and 1727 deletions
+2 -2
View File
@@ -34,7 +34,7 @@ export default function DocsFirstServicePage() {
<h2>Three ways to add a service</h2>
<h3>1. Pick from 93 one-click templates</h3>
<h3>1. Pick from 77 one-click templates</h3>
<p>
The template library covers the most popular self-hosted applications media servers, dashboards,
databases, note apps, automation tools, and more. Each template bundles sane defaults for ports,
@@ -62,7 +62,7 @@ export default function DocsFirstServicePage() {
<h3>Step 1: Open the template library</h3>
<p>
From the dashboard sidebar, click <strong>New Service From Template</strong>. The template library
opens with a searchable grid of 93 applications.
opens with a searchable grid of 77 applications.
</p>
<h3>Step 2: Find Plex</h3>
+223 -317
View File
@@ -8,375 +8,281 @@ export default function DocsInstallationPage() {
<Navbar />
<DocsLayout
title="Installation Guide"
intro="DashCaddy ships as a Docker-based deployment with a guided installer that handles dependency checks, configuration generation, and first launch. This guide covers prerequisites, the installer flow, and what to expect on first run."
intro="DashCaddy installs in three commands on any Linux box — a desktop, a NUC, a Raspberry Pi 5, or a VPS. The installer handles Docker, Caddy, data volumes, the setup wizard, and your first login. This guide walks you through picking a hostname, running the installer, what the wizard does, and how to harden the host right after."
>
<h2>System requirements</h2>
<p>Before installing DashCaddy, verify that your host meets these minimum requirements:</p>
<div className="overflow-x-auto">
<table className="w-full text-left text-sm">
<thead>
<tr className="border-b border-surface-700">
<th className="py-3 pr-4 font-semibold text-surface-200">Component</th>
<th className="py-3 pr-4 font-semibold text-surface-200">Minimum</th>
<th className="py-3 font-semibold text-surface-200">Recommended</th>
</tr>
</thead>
<tbody className="text-surface-300">
<tr className="border-b border-surface-800">
<td className="py-3 pr-4">Operating System</td>
<td className="py-3 pr-4">Linux (Ubuntu 20.04+, Debian 11+, CentOS 8+)</td>
<td className="py-3">Ubuntu 22.04 LTS or Debian 12</td>
</tr>
<tr className="border-b border-surface-800">
<td className="py-3 pr-4">CPU</td>
<td className="py-3 pr-4">2 cores</td>
<td className="py-3">4+ cores</td>
</tr>
<tr className="border-b border-surface-800">
<td className="py-3 pr-4">RAM</td>
<td className="py-3 pr-4">2 GB</td>
<td className="py-3">4+ GB (8 GB for 20+ services)</td>
</tr>
<tr className="border-b border-surface-800">
<td className="py-3 pr-4">Disk</td>
<td className="py-3 pr-4">10 GB free</td>
<td className="py-3">50+ GB SSD</td>
</tr>
<tr className="border-b border-surface-800">
<td className="py-3 pr-4">Docker</td>
<td className="py-3 pr-4">20.10+</td>
<td className="py-3">Latest stable</td>
</tr>
<tr className="border-b border-surface-800">
<td className="py-3 pr-4">Docker Compose</td>
<td className="py-3 pr-4">v2.0+</td>
<td className="py-3">Latest stable</td>
</tr>
<tr className="border-b border-surface-800">
<td className="py-3 pr-4">Node.js</td>
<td className="py-3 pr-4">20.x LTS</td>
<td className="py-3">20.x LTS or 22.x LTS</td>
</tr>
<tr className="border-b border-surface-800">
<td className="py-3 pr-4">Caddy</td>
<td className="py-3 pr-4">2.6+ with Admin API</td>
<td className="py-3">Latest stable</td>
</tr>
<tr>
<td className="py-3 pr-4">Technitium DNS</td>
<td className="py-3 pr-4">Optional</td>
<td className="py-3">Latest stable (for auto DNS)</td>
</tr>
</tbody>
</table>
</div>
<h2>Quick start with start.sh</h2>
<h2>Before you start</h2>
<p>
The fastest path to a running DashCaddy is the bundled <code>start.sh</code> script. It performs environment
checks, pulls the required containers, generates configuration, and brings the stack up in a single command.
You only need three things to install DashCaddy:
</p>
<ul>
<li><strong>A Linux host that stays on</strong> Ubuntu 22.04 LTS, Debian 12, or any recent Linux distribution. 2&nbsp;GB RAM and a few GB of disk are enough to start.</li>
<li><strong>Root or sudo access</strong> the installer writes to <code>/etc/dashcaddy</code>, <code>/opt/dockerdata</code>, and the system Docker daemon.</li>
<li><strong>A hostname</strong> a domain you own, a custom-TLD like <code>dashcaddy.home</code>, or just your machine&apos;s IP for local-only use.</li>
</ul>
<h2>Pick your hostname</h2>
<p>
DashCaddy uses a single base hostname and creates subdomains under it for every service you add (for example
<code> plex.dashcaddy.home</code>, <code>homeassistant.dashcaddy.home</code>). Choose the option that matches
your situation:
</p>
<h3>Step 1: Clone the repository</h3>
<pre className="mt-4 overflow-x-auto rounded-lg border border-surface-700/50 bg-surface-950/80 p-4 text-sm"><code>{`curl -fsSL https://get.dashcaddy.net | bash
cd dashcaddy`}</code></pre>
<h3>Step 2: Make the launcher executable</h3>
<pre className="mt-4 overflow-x-auto rounded-lg border border-surface-700/50 bg-surface-950/80 p-4 text-sm"><code>{`chmod +x start.sh`}</code></pre>
<h3>Step 3: Run the installer</h3>
<pre className="mt-4 overflow-x-auto rounded-lg border border-surface-700/50 bg-surface-950/80 p-4 text-sm"><code>{`./start.sh`}</code></pre>
<h3>Option A A real domain you own (recommended)</h3>
<p>
The script is idempotent re-running it will reconcile the stack rather than clobber an existing install.
If DashCaddy is already running, <code>start.sh</code> detects this and offers to update configuration or
restart services instead of reinstalling from scratch.
If you own <code>example.com</code>, register <code>dashcaddy.example.com</code> as a DNS A record pointing at
your host&apos;s public IP. You can buy a domain for about $10/year from any registrar (Namecheap, Cloudflare,
Porkbun, Google Domains). With a real domain, DashCaddy automatically gets a trusted Let&apos;s Encrypt
certificate on first launch no certificate warnings, no client setup.
</p>
<h3>What start.sh does</h3>
<p>Under the hood, the script performs these steps:</p>
<ol>
<li><strong>Dependency validation</strong> checks for Docker, Docker Compose, Node.js, and Caddy</li>
<li><strong>Port availability check</strong> verifies ports 80, 443, and 2019 (Caddy Admin API) are free</li>
<li><strong>Configuration generation</strong> creates <code>.env</code> file with sensible defaults</li>
<li><strong>Docker image pull</strong> fetches the DashCaddy API and dashboard images</li>
<li><strong>Container startup</strong> launches the stack via Docker Compose</li>
<li><strong>Health check</strong> waits for the API to respond on <code>/healthz</code></li>
<li><strong>Dashboard URL display</strong> prints the access URL and initial admin credentials</li>
</ol>
<h2>Docker Compose configuration</h2>
<h3>Option B A custom TLD on your home network</h3>
<p>
If you prefer to inspect or customize the Docker Compose configuration before launching, here's the
default <code>docker-compose.yml</code> that <code>start.sh</code> generates:
Use a domain like <code>dashcaddy.home</code>, <code>dashcaddy.lan</code>, or <code>dashcaddy.local</code>.
These will not resolve on the public internet, which is exactly what you want for a home server. Two ways to
make them resolve:
</p>
<pre className="mt-4 overflow-x-auto rounded-lg border border-surface-700/50 bg-surface-950/80 p-4 text-sm"><code>{`version: '3.8'
services:
dashcaddy-api:
image: samiahmed7777/dashcaddy-api:latest
container_name: dashcaddy-api
restart: unless-stopped
ports:
- "3001:3001" # API port
volumes:
- ./data:/app/data
- ./config:/app/config
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
- NODE_ENV=production
- DASHCADDY_PORT=3001
- CADDY_ADMIN_URL=http://caddy:2019
- TECHNITIUM_API_URL=http://technitium:5380
- TECHNITIUM_API_TOKEN=\${TECHNITIUM_API_TOKEN}
- JWT_SECRET=\${JWT_SECRET}
- DASHCA_ENABLED=true
depends_on:
- caddy
- technitium
networks:
- dashcaddy-net
dashcaddy-dashboard:
image: samiahmed7777/dashcaddy-dashboard:latest
container_name: dashcaddy-dashboard
restart: unless-stopped
ports:
- "3000:3000" # Dashboard port
environment:
- NEXT_PUBLIC_API_URL=http://localhost:3001
depends_on:
- dashcaddy-api
networks:
- dashcaddy-net
caddy:
image: caddy:2-alpine
container_name: caddy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "2019:2019" # Admin API
volumes:
- ./caddy/Caddyfile:/etc/caddy/Caddyfile
- ./caddy/data:/data
- ./caddy/config:/config
networks:
- dashcaddy-net
technitium:
image: technitium/dns-server:latest
container_name: technitium
restart: unless-stopped
ports:
- "5380:5380" # Web console
- "53:53/udp"
- "53:53/tcp"
volumes:
- ./technitium:/etc/dns
environment:
- DNS_SERVER_DOMAIN=local
networks:
- dashcaddy-net
networks:
dashcaddy-net:
driver: bridge`}</code></pre>
<h2>Environment variables reference</h2>
<ul>
<li><strong>Router DNS</strong> most home routers let you add a local DNS entry. Point <code>*.dashcaddy.home</code> at your server&apos;s LAN IP. All devices on your network pick it up automatically.</li>
<li><strong>Tailscale MagicDNS</strong> install Tailscale on the host and your devices. Their MagicDNS gives every machine a stable <code>name.tailnet.ts.net</code> name, no DNS editing needed.</li>
</ul>
<p>
DashCaddy's behavior is controlled through environment variables in the <code>.env</code> file. Here's
a complete reference:
Custom TLDs require installing DashCaddy&apos;s internal CA certificate (DashCA) on each device that connects.
The setup wizard walks you through this on first run.
</p>
<h3>Option C A direct IP address</h3>
<p>
If you don&apos;t want to set up DNS at all, you can reach DashCaddy at <code>https://192.168.x.x:port</code>.
This works for a single machine on a LAN, but the URL changes when the host gets a new IP and you lose
subdomain support. Useful for a quick test, not a permanent setup.
</p>
<div className="overflow-x-auto">
<table className="w-full text-left text-sm">
<thead>
<tr className="border-b border-surface-700">
<th className="py-3 pr-4 font-semibold text-surface-200">Variable</th>
<th className="py-3 pr-4 font-semibold text-surface-200">Default</th>
<th className="py-3 font-semibold text-surface-200">Description</th>
</tr>
</thead>
<tbody className="text-surface-300">
<tr className="border-b border-surface-800">
<td className="py-3 pr-4 font-mono text-xs">NODE_ENV</td>
<td className="py-3 pr-4">production</td>
<td className="py-3">Runtime environment (development or production)</td>
</tr>
<tr className="border-b border-surface-800">
<td className="py-3 pr-4 font-mono text-xs">DASHCADDY_PORT</td>
<td className="py-3 pr-4">3001</td>
<td className="py-3">Port for the DashCaddy API server</td>
</tr>
<tr className="border-b border-surface-800">
<td className="py-3 pr-4 font-mono text-xs">CADDY_ADMIN_URL</td>
<td className="py-3 pr-4">http://caddy:2019</td>
<td className="py-3">Caddy Admin API endpoint</td>
</tr>
<tr className="border-b border-surface-800">
<td className="py-3 pr-4 font-mono text-xs">TECHNITIUM_API_URL</td>
<td className="py-3 pr-4">http://technitium:5380</td>
<td className="py-3">Technitium DNS API endpoint</td>
</tr>
<tr className="border-b border-surface-800">
<td className="py-3 pr-4 font-mono text-xs">TECHNITIUM_API_TOKEN</td>
<td className="py-3 pr-4">(required)</td>
<td className="py-3">API token for Technitium DNS authentication</td>
</tr>
<tr className="border-b border-surface-800">
<td className="py-3 pr-4 font-mono text-xs">JWT_SECRET</td>
<td className="py-3 pr-4">(auto-generated)</td>
<td className="py-3">Secret key for JWT token signing</td>
</tr>
<tr className="border-b border-surface-800">
<td className="py-3 pr-4 font-mono text-xs">DASHCA_ENABLED</td>
<td className="py-3 pr-4">true</td>
<td className="py-3">Enable internal certificate authority</td>
</tr>
<tr className="border-b border-surface-800">
<td className="py-3 pr-4 font-mono text-xs">BASE_DOMAIN</td>
<td className="py-3 pr-4">local</td>
<td className="py-3">Base domain for service hostnames</td>
</tr>
<tr className="border-b border-surface-800">
<td className="py-3 pr-4 font-mono text-xs">PROMETHEUS_ENABLED</td>
<td className="py-3 pr-4">true</td>
<td className="py-3">Expose Prometheus metrics at /metrics</td>
</tr>
<tr className="border-b border-surface-800">
<td className="py-3 pr-4 font-mono text-xs">LOG_LEVEL</td>
<td className="py-3 pr-4">info</td>
<td className="py-3">Logging verbosity (debug, info, warn, error)</td>
</tr>
<tr>
<td className="py-3 pr-4 font-mono text-xs">DATA_DIR</td>
<td className="py-3 pr-4">./data</td>
<td className="py-3">Path for persistent state storage</td>
</tr>
</tbody>
</table>
</div>
<h2>The Smart Defaults Wizard</h2>
<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">Smart Defaults Wizard:</strong> On first launch, the dashboard opens to the Smart Defaults Wizard. It surveys your host and pre-fills sensible choices so you can go from install to a working deployment in minutes. Every default is editable — the wizard simply gives you a known-good starting point instead of a blank slate.
<strong className="text-brand-400">No port forwarding?</strong> If your ISP puts you behind CGNAT or you
don&apos;t want to open ports 80 and 443, DashCaddy works fine behind a Tailscale tunnel or Cloudflare
Tunnel. Set up the tunnel first, point your hostname at the tunnel&apos;s origin, then run the installer
with <code>--no-caddy</code> and let the tunnel handle HTTPS termination.
</p>
</blockquote>
<p>The wizard performs these tasks automatically:</p>
<ul>
<li><strong>Caddy detection</strong> — detects the Caddy Admin API endpoint and validates connectivity</li>
<li><strong>Technitium detection</strong> — detects Technitium DNS (if installed) and configures the API token and zone</li>
<li><strong>Domain suggestion</strong> — proposes a base domain and naming convention for new services</li>
<li><strong>DashCA initialization</strong> — initializes the internal certificate authority and offers the root certificate for download</li>
<li><strong>Admin account creation</strong> — creates the initial admin account and offers TOTP 2FA enrollment</li>
<li><strong>Network scanning</strong> — scans for existing Docker containers and offers to adopt them via Service Discovery</li>
</ul>
<h2>Manual setup</h2>
<h2>Run the installer</h2>
<p>
If you want direct control over paths, services, Caddy, and DNS integration, you can deploy manually
instead of using <code>start.sh</code>:
Open a terminal on the host you want to install DashCaddy on and run one of these:
</p>
<h3>Three-command install (most users)</h3>
<pre className="mt-4 overflow-x-auto rounded-lg border border-surface-700/50 bg-surface-950/80 p-4 text-sm"><code>{`# 1. Download and run the installer
curl -fsSL https://get.dashcaddy.net | bash
# 2. Answer the prompts (domain, install location, storage size)
# Defaults are sensible — just press Enter to accept.
# 3. Open the URL the installer prints at the end`}</code></pre>
<h3>Two-keystroke install (no typing)</h3>
<pre className="mt-4 overflow-x-auto rounded-lg border border-surface-700/50 bg-surface-950/80 p-4 text-sm"><code>{`# Install with a public domain — only thing you type is the domain
curl -fsSL https://get.dashcaddy.net | bash -s -- --domain dashcaddy.example.com
# Or use a custom TLD (your router / Tailscale handles DNS)
curl -fsSL https://get.dashcaddy.net | bash -s -- --domain dashcaddy.home
# Or skip DNS entirely and use a local address (good for a first test)
curl -fsSL https://get.dashcaddy.net | bash -s -- quick`}</code></pre>
<h3>What the installer does</h3>
<p>
The installer is a single shell script that runs in seven steps, all idempotent re-running it on an existing
install reconciles the stack rather than clobbering your config:
</p>
<ol>
<li>Run the installer: <code>curl -fsSL https://get.dashcaddy.net | bash</code></li>
<li>Install the API dependencies: <code>cd dashcaddy && npm ci</code></li>
<li>Prepare Caddy and confirm the Admin API is reachable on port 2019</li>
<li>Prepare Technitium DNS if you want automatic DNS changes (optional)</li>
<li>Copy <code>.env.example</code> to <code>.env</code> and configure environment variables</li>
<li>Start the DashCaddy API: <code>npm run start</code> (or use your process manager like systemd or PM2)</li>
<li>Serve the dashboard through Caddy by adding a reverse proxy rule to your Caddyfile</li>
<li><strong>Detect your environment</strong> operating system, package manager, free disk space, available memory, public and LAN IP addresses</li>
<li><strong>Install prerequisites</strong> Docker Engine and the Docker Compose plugin if missing</li>
<li><strong>Write configuration</strong> generates <code>/etc/dashcaddy/</code>, <code>/opt/dockerdata/</code>, and the DashCaddy config file with sensible defaults</li>
<li><strong>Pull the DashCaddy container image</strong> fetches the latest release from the public registry</li>
<li><strong>Start the DashCaddy container</strong> launches <code>dashcaddy-api</code> on port 3001, mounts persistent data volumes</li>
<li><strong>Health check</strong> waits for the API to respond on <code>/healthz</code> before continuing</li>
<li><strong>Print the access URL</strong> shows the dashboard address and any follow-up commands</li>
</ol>
<h2>Common installation issues</h2>
<p>If you encounter problems during installation, check this troubleshooting table:</p>
<p>
If the installer ever hits a problem, it stops at the step that failed and tells you exactly which command to
re-run to retry. It does not silently leave a half-installed state behind.
</p>
<h2>The first-run setup wizard</h2>
<p>
When you open the dashboard URL the installer printed, you land on the setup wizard. It runs once and writes
your configuration to disk every choice is editable later from the settings page.
</p>
<p>The wizard walks through these screens:</p>
<ol>
<li><strong>Pick a configuration profile</strong> <em>Professional Home Lab</em> (recommended for most users), <em>Simple</em> (minimal config), or <em>Public</em> (for VPS deployments exposed to the internet)</li>
<li><strong>Configure your network</strong> your domain, the LAN IP that&apos;ll be used for service routing, and whether you want to use Tailscale for remote access</li>
<li><strong>Set storage limits</strong> max disk usage for Docker data and how much headroom to keep free</li>
<li><strong>Review your choices</strong> a summary screen with the resolved values so you can sanity-check before saving</li>
<li><strong>Disk-safety confirmation</strong> confirms you understand that bound storage will be created and what happens on uninstall</li>
</ol>
<p>
After the wizard saves, you&apos;re asked to create the first admin account. Pick a strong password this
account controls every service DashCaddy manages.
</p>
<h2>Set up two-factor authentication</h2>
<p>
Right after creating your admin account, the dashboard prompts you to enroll a TOTP authenticator
(Google Authenticator, Authy, 1Password, or any RFC&nbsp;6238 app). Scan the QR code with your phone, enter the
6-digit code to confirm, and store the recovery codes somewhere safe they are the only way back into your
account if you lose your phone.
</p>
<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">Don&apos;t skip 2FA.</strong> DashCaddy can manage DNS records, start and
stop containers, and read credentials for the services it deploys. A leaked password without a second
factor is a full compromise. A leaked password with 2FA is just a login screen.
</p>
</blockquote>
<h2>Install the DashCA root certificate (custom-TLD installs only)</h2>
<p>
If you chose Option B (a custom TLD like <code>dashcaddy.home</code>) or Option C (a direct IP), your browser
will warn that the certificate is not trusted because it isn&apos;t, to anyone outside your network. DashCaddy
ships an internal certificate authority called <strong>DashCA</strong> so internal hostnames get a real TLS
certificate instead of self-signed warnings.
</p>
<p>
Visit the <strong>DashCA</strong> page in the dashboard and follow the per-platform instructions:
</p>
<ul>
<li><strong>macOS</strong> open the downloaded <code>.crt</code>, add it to the System keychain, set it to &ldquo;Always Trust&rdquo;</li>
<li><strong>Windows</strong> double-click the <code>.crt</code>, install to &ldquo;Trusted Root Certification Authorities&rdquo;</li>
<li><strong>Linux</strong> copy to <code>/usr/local/share/ca-certificates/</code> and run <code>sudo update-ca-certificates</code></li>
<li><strong>iOS / Android</strong> download the profile, install it via Settings, then enable full trust for the CA</li>
</ul>
<p>
You need to install the root certificate on every device that connects to your DashCaddy services, not just
the server. There&apos;s no way around this for custom-TLD installs TLS is what keeps your traffic private.
</p>
<h2>Harden the host right after install</h2>
<p>
DashCaddy protects the services it manages, but it runs on top of a normal Linux box that&apos;s still exposed
on your network. Spend five minutes on these four steps:
</p>
<h3>1. Enable the firewall</h3>
<pre className="mt-4 overflow-x-auto rounded-lg border border-surface-700/50 bg-surface-950/80 p-4 text-sm"><code>{`# UFW (Ubuntu / Debian)
sudo ufw default deny incoming
sudo ufw allow ssh # if you SSH in
sudo ufw allow 80/tcp # HTTP (Let's Encrypt + redirect)
sudo ufw allow 443/tcp # HTTPS
sudo ufw enable
# If you put DashCaddy behind a tunnel (Tailscale / Cloudflare), skip 80/443 above
# and only allow the tunnel interface — see your tunnel provider's docs`}</code></pre>
<h3>2. Disable password SSH login</h3>
<pre className="mt-4 overflow-x-auto rounded-lg border border-surface-700/50 bg-surface-950/80 p-4 text-sm"><code>{`# Edit /etc/ssh/sshd_config and set:
PasswordAuthentication no
PermitRootLogin prohibit-password # or "no" if you use a sudo user
sudo systemctl restart sshd`}</code></pre>
<h3>3. Turn on automatic security updates</h3>
<pre className="mt-4 overflow-x-auto rounded-lg border border-surface-700/50 bg-surface-950/80 p-4 text-sm"><code>{`# Debian / Ubuntu
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades # answer "Yes"`}</code></pre>
<h3>4. Set up backups</h3>
<p>
All your DashCaddy state services, config, encrypted credentials, DashCA lives in
<code> /opt/dockerdata</code> and <code>/etc/dashcaddy</code>. Snapshot those two directories somewhere off
the host. Any tool works: <code>rsync</code> to a NAS, <code>restic</code> to Backblaze B2, a systemd timer
that tars them up nightly. The dashboard&apos;s Backup button exports a single JSON file you can store
anywhere if you want a no-setup option.
</p>
<h2>Verify the install</h2>
<p>
After the wizard finishes and you&apos;ve logged in, run through this checklist to confirm everything is wired
up correctly:
</p>
<ol>
<li><strong>Container is running</strong> <code>docker ps</code> should show <code>dashcaddy-api</code> with status <code>Up</code></li>
<li><strong>API is healthy</strong> from the host, <code>curl http://localhost:3001/healthz</code> returns <code>{`{"status":"alive"}`}</code> and <code>/readyz</code> returns 200 with all checks passing</li>
<li><strong>Dashboard responds</strong> opening the URL the installer printed shows the dashboard, not a browser error</li>
<li><strong>TLS works</strong> the address bar shows a padlock with no warnings (a real cert if you used Option A; trusted if you used Option B with DashCA installed)</li>
<li><strong>2FA works</strong> log out and back in with your password + TOTP code</li>
<li><strong>Updates work</strong> the dashboard shows the current version in the footer and the update button is enabled</li>
</ol>
<h2>Troubleshooting a fresh install</h2>
<div className="overflow-x-auto">
<table className="w-full text-left text-sm">
<thead>
<tr className="border-b border-surface-700">
<th className="py-3 pr-4 font-semibold text-surface-200">Symptom</th>
<th className="py-3 pr-4 font-semibold text-surface-200">Cause</th>
<th className="py-3 font-semibold text-surface-200">Solution</th>
<th className="py-3 pr-4 font-semibold text-surface-200">Likely cause</th>
<th className="py-3 font-semibold text-surface-200">Fix</th>
</tr>
</thead>
<tbody className="text-surface-300">
<tr className="border-b border-surface-800">
<td className="py-3 pr-4">Port 80 or 443 already in use</td>
<td className="py-3 pr-4">Another web server (nginx, Apache) is running</td>
<td className="py-3">Stop the conflicting service or change Caddy's ports in docker-compose.yml</td>
<td className="py-3 pr-4">Installer says &ldquo;Docker not found&rdquo;</td>
<td className="py-3 pr-4">Docker Engine isn&apos;t installed or you&apos;re not in the docker group</td>
<td className="py-3">Run <code>sudo usermod -aG docker $USER</code>, log out, log back in. Re-run the installer.</td>
</tr>
<tr className="border-b border-surface-800">
<td className="py-3 pr-4">Docker permission denied</td>
<td className="py-3 pr-4">Current user not in docker group</td>
<td className="py-3">Run <code>sudo usermod -aG docker $USER</code> and log out/in</td>
<td className="py-3 pr-4">Installer fails on &ldquo;port 80/443 already in use&rdquo;</td>
<td className="py-3 pr-4">Another web server (nginx, Apache, another Caddy) is bound to those ports</td>
<td className="py-3">Stop the conflicting service, or move it to different ports and re-run the installer</td>
</tr>
<tr className="border-b border-surface-800">
<td className="py-3 pr-4">Caddy Admin API unreachable</td>
<td className="py-3 pr-4">Caddy not running or Admin API disabled</td>
<td className="py-3">Ensure Caddy is running with <code>admin :2019</code> in its config</td>
<td className="py-3 pr-4">Dashboard URL gives a connection refused</td>
<td className="py-3 pr-4">Container failed to start, or the host firewall is blocking the port</td>
<td className="py-3"><code>docker ps</code> if the container exited, <code>docker logs dashcaddy-api</code> shows why. If running, check the firewall.</td>
</tr>
<tr className="border-b border-surface-800">
<td className="py-3 pr-4">Technitium API token invalid</td>
<td className="py-3 pr-4">Token not set or expired</td>
<td className="py-3">Generate a new token in Technitium web console and update .env</td>
<td className="py-3 pr-4">Browser shows &ldquo;Your connection is not private&rdquo;</td>
<td className="py-3 pr-4">Custom-TLD install with no DashCA trust, OR the domain doesn&apos;t point at this host</td>
<td className="py-3">For custom TLDs, install the DashCA root certificate. For real domains, check DNS: <code>dig +short your-hostname</code> should return the host&apos;s public IP.</td>
</tr>
<tr className="border-b border-surface-800">
<td className="py-3 pr-4">Dashboard shows 502 Bad Gateway</td>
<td className="py-3 pr-4">API server not responding</td>
<td className="py-3">Check <code>docker logs dashcaddy-api</code> for errors</td>
</tr>
<tr className="border-b border-surface-800">
<td className="py-3 pr-4">Out of memory during deployment</td>
<td className="py-3 pr-4">Insufficient RAM for container workloads</td>
<td className="py-3">Increase host RAM or reduce concurrent service deployments</td>
<td className="py-3 pr-4">Let&apos;s Encrypt certificate never issues</td>
<td className="py-3 pr-4">Domain doesn&apos;t resolve publicly, OR port 80 is blocked by your ISP</td>
<td className="py-3">Verify the A record with <code>dig</code>. If you&apos;re on CGNAT, switch to Tailscale Funnel or Cloudflare Tunnel.</td>
</tr>
<tr>
<td className="py-3 pr-4">Certificate trust errors in browser</td>
<td className="py-3 pr-4">DashCA root cert not installed on client</td>
<td className="py-3">Download root cert from DashCA page and install on client device</td>
<td className="py-3 pr-4">Setup wizard loops back to step 1</td>
<td className="py-3 pr-4">Browser stored a stale config from a previous install</td>
<td className="py-3">Open DevTools Application Local Storage clear the <code>dashcaddy-setup</code> key, then reload</td>
</tr>
</tbody>
</table>
</div>
<h2>Post-install verification</h2>
<p>After the stack is up, verify each layer with these commands:</p>
<h2>Uninstall</h2>
<p>
If you want to remove DashCaddy cleanly, the installer has an uninstall mode that stops the container,
removes the systemd unit, and (optionally) deletes the data volumes:
</p>
<pre className="mt-4 overflow-x-auto rounded-lg border border-surface-700/50 bg-surface-950/80 p-4 text-sm"><code>{`# Remove DashCaddy but keep your config and data (you can reinstall later)
curl -fsSL https://get.dashcaddy.net | bash -s -- --uninstall
<h3>1. Check container status</h3>
<pre className="mt-4 overflow-x-auto rounded-lg border border-surface-700/50 bg-surface-950/80 p-4 text-sm"><code>{`docker ps --filter "name=dashcaddy"
# Expected: dashcaddy-api, dashcaddy-dashboard, caddy, technitium all running`}</code></pre>
<h3>2. Verify API health</h3>
<pre className="mt-4 overflow-x-auto rounded-lg border border-surface-700/50 bg-surface-950/80 p-4 text-sm"><code>{`curl http://localhost:3001/healthz
# Expected: {"status":"ok","version":"1.0.0"}
curl http://localhost:3001/readyz
# Expected: {"status":"ready","checks":{"caddy":true,"technitium":true}}`}</code></pre>
<h3>3. Test Caddy Admin API</h3>
<pre className="mt-4 overflow-x-auto rounded-lg border border-surface-700/50 bg-surface-950/80 p-4 text-sm"><code>{`curl http://localhost:2019/config/
# Expected: JSON configuration object`}</code></pre>
<h3>4. Verify Technitium DNS</h3>
<pre className="mt-4 overflow-x-auto rounded-lg border border-surface-700/50 bg-surface-950/80 p-4 text-sm"><code>{`curl http://localhost:5380/api/dns/zones/list?token=YOUR_TOKEN
# Expected: List of DNS zones`}</code></pre>
<h3>5. Check Prometheus metrics</h3>
<pre className="mt-4 overflow-x-auto rounded-lg border border-surface-700/50 bg-surface-950/80 p-4 text-sm"><code>{`curl http://localhost:3001/metrics
# Expected: Prometheus-formatted metrics output`}</code></pre>
<h3>6. Access the dashboard</h3>
<p>Open your browser and navigate to <code>http://localhost:3000</code> (or your configured domain). You should see the DashCaddy dashboard login screen.</p>
# Remove everything including config and data (irreversible)
curl -fsSL https://get.dashcaddy.net | bash -s -- --uninstall --purge`}</code></pre>
<h2>Next steps</h2>
<p>
Once install checks pass, head to the <a href="/docs/first-service" className="text-brand-400 hover:text-brand-300 underline">Deploy Your First Service</a> guide to
bring your first application online.
With DashCaddy installed and hardened, head to the <a href="/docs/first-service" className="text-brand-400 hover:text-brand-300 underline">Deploy Your First Service</a> guide
to bring an application online through the App Selector.
</p>
<p>
If you need to understand the architecture in more depth, see the <a href="/docs/overview" className="text-brand-400 hover:text-brand-300 underline">Product Overview</a>.
If you want to understand the architecture before adding services, see the <a href="/docs/overview" className="text-brand-400 hover:text-brand-300 underline">Product Overview</a>.
For problems during or after install, the <a href="/docs/troubleshooting" className="text-brand-400 hover:text-brand-300 underline">Troubleshooting</a> page
walks each layer bottom-up.
</p>
</DocsLayout>
<Footer />
+1 -1
View File
@@ -27,7 +27,7 @@ export default function DocsIntegrationsPage() {
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>93 one-click application templates</strong> from the catalog.
deploy the <strong>77 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,
+4 -4
View File
@@ -162,7 +162,7 @@ export default function DocsOverviewPage() {
<tr className="border-b border-surface-800">
<td className="py-3 pr-4">Docker deployment</td>
<td className="py-3 pr-4">Manual compose files</td>
<td className="py-3 pr-4">93 one-click templates</td>
<td className="py-3 pr-4">77 one-click templates</td>
<td className="py-3">Templates + Recipes</td>
</tr>
<tr className="border-b border-surface-800">
@@ -217,7 +217,7 @@ export default function DocsOverviewPage() {
<td className="py-3 pr-4">Pricing</td>
<td className="py-3 pr-4">Time + complexity</td>
<td className="py-3 pr-4">Free forever</td>
<td className="py-3">$20$99 one-time</td>
<td className="py-3">$20$99 / license duration</td>
</tr>
</tbody>
</table>
@@ -250,8 +250,8 @@ export default function DocsOverviewPage() {
<h2>Premium licensing</h2>
<p>
DashCaddy Premium is a one-time purchase (not a subscription) that unlocks advanced orchestration
features. Pricing tiers:
DashCaddy Premium is a fixed-duration license. You buy the duration you want; Premium features unlock
for that duration and deactivate when it expires. You purchase a new license to renew. Pricing tiers:
</p>
<ul>
<li><strong>$20</strong> 30-day license</li>
+6 -4
View File
@@ -39,7 +39,7 @@ export default function DocsPremiumPage() {
</thead>
<tbody>
<tr><td>Dashboard &amp; web UI</td><td></td><td></td></tr>
<tr><td>93 application templates</td><td></td><td></td></tr>
<tr><td>77 application templates</td><td></td><td></td></tr>
<tr><td>Caddy reverse proxy + auto HTTPS</td><td></td><td></td></tr>
<tr><td>Caddyfile-as-Code builder</td><td></td><td></td></tr>
<tr><td>Technitium DNS automation</td><td></td><td></td></tr>
@@ -161,8 +161,10 @@ curl -X POST -H "Authorization: Bearer ***" \\
<h2>Pricing</h2>
<p>
Premium is sold as one-time payments for fixed license durations. There is a single Premium tier no ladder
of plans to navigate. Longer durations are discounted relative to the monthly rate.
Premium is sold as a fixed-duration license. You pick the duration that fits your needs; the license unlocks
Premium features for that period and then expires. You manually purchase a new license when the current
one expires. There is a single Premium tier no ladder of plans to navigate. Longer durations are
discounted relative to the short-term rate.
</p>
<table>
<thead>
@@ -186,7 +188,7 @@ curl -X POST -H "Authorization: Bearer ***" \\
<h2>Plan terms</h2>
<ul>
<li><strong>One-time payments</strong> no auto-renewing subscription; your license runs for the purchased duration and then expires.</li>
<li><strong>Fixed-duration license</strong> your license runs for the purchased duration and then expires. You re-purchase manually when you want to renew.</li>
<li><strong>One Premium tier</strong> every duration unlocks the same features.</li>
<li><strong>One active machine per license</strong> a license is bound to a single host at a time.</li>
<li><strong>7-day grace period</strong> after expiry services keep running while you renew; Premium features are read-only during grace.</li>