292 lines
18 KiB
TypeScript
292 lines
18 KiB
TypeScript
import Navbar from '@/components/Navbar';
|
|
import Footer from '@/components/Footer';
|
|
import DocsLayout from '@/components/docs/DocsLayout';
|
|
|
|
export default function DocsInstallationPage() {
|
|
return (
|
|
<div className="flex min-h-screen flex-col bg-surface-950 text-surface-50">
|
|
<Navbar />
|
|
<DocsLayout
|
|
title="Installation Guide"
|
|
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>Before you start</h2>
|
|
<p>
|
|
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 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'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>Option A — A real domain you own (recommended)</h3>
|
|
<p>
|
|
If you own <code>example.com</code>, register <code>dashcaddy.example.com</code> as a DNS A record pointing at
|
|
your host'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's Encrypt
|
|
certificate on first launch — no certificate warnings, no client setup.
|
|
</p>
|
|
|
|
<h3>Option B — A custom TLD on your home network</h3>
|
|
<p>
|
|
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>
|
|
<ul>
|
|
<li><strong>Router DNS</strong> — most home routers let you add a local DNS entry. Point <code>*.dashcaddy.home</code> at your server'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>
|
|
Custom TLDs require installing DashCaddy'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'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>
|
|
|
|
<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">No port forwarding?</strong> If your ISP puts you behind CGNAT or you
|
|
don'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's origin, then run the installer
|
|
with <code>--no-caddy</code> and let the tunnel handle HTTPS termination.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<h2>Run the installer</h2>
|
|
<p>
|
|
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><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>
|
|
|
|
<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'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'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 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'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'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 “Always Trust”</li>
|
|
<li><strong>Windows</strong> — double-click the <code>.crt</code>, install to “Trusted Root Certification Authorities”</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'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'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'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'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">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">Installer says “Docker not found”</td>
|
|
<td className="py-3 pr-4">Docker Engine isn't installed or you'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">Installer fails on “port 80/443 already in use”</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">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">Browser shows “Your connection is not private”</td>
|
|
<td className="py-3 pr-4">Custom-TLD install with no DashCA trust, OR the domain doesn'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's public IP.</td>
|
|
</tr>
|
|
<tr className="border-b border-surface-800">
|
|
<td className="py-3 pr-4">Let's Encrypt certificate never issues</td>
|
|
<td className="py-3 pr-4">Domain doesn'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're on CGNAT, switch to Tailscale Funnel or Cloudflare Tunnel.</td>
|
|
</tr>
|
|
<tr>
|
|
<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>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
|
|
|
|
# Remove everything including config and data (irreversible)
|
|
curl -fsSL https://get.dashcaddy.net | bash -s -- --uninstall --purge`}</code></pre>
|
|
|
|
<h2>Next steps</h2>
|
|
<p>
|
|
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 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 />
|
|
</div>
|
|
);
|
|
}
|