diff --git a/src/app/docs/api/page.tsx b/src/app/docs/api/page.tsx index 1a9c11b..a93891f 100644 --- a/src/app/docs/api/page.tsx +++ b/src/app/docs/api/page.tsx @@ -10,32 +10,98 @@ export default function DocsApiPage() { title="API and Automation" intro="DashCaddy is more than a dashboard — it exposes a real API and automation surface so you can drive deployments, DNS, proxy, certificates, monitoring, and operations programmatically or through AI." > +
+ Every action available in the DashCaddy UI is also available through a programmatic surface: a versioned REST + API, a typed JavaScript SDK, an AI Intent Router for natural-language commands, an MCP Server for AI assistant + integration, a WebSocket channel for real-time events, a Prometheus endpoint for metrics, and a plugin system + for extending the platform. This guide covers each surface with concrete examples. +
++ Whether you are wiring DashCaddy into a CI/CD pipeline, building a custom dashboard, or letting an AI assistant + manage your infrastructure, the automation layer is designed to be the primary interface — the web UI is just + one consumer of it. +
+
- All platform operations are available under /api/v1/. The API covers service management,
- app deployment, DNS automation, Caddy reverse-proxy integration, certificate workflows, health and status
- reporting, user/admin operations, and backup/restore. The repository ships with an OpenAPI definition so the
- public contract can mature into a full reference.
+ All platform operations are available under /api/v1/. The API covers service management, app
+ deployment, DNS automation, Caddy reverse-proxy integration, certificate workflows, health and status
+ reporting, user and admin operations, backup/restore, and more. The repository ships with an OpenAPI definition
+ so the public contract can mature into a full reference.
+
+ Requests and responses are JSON. The base URL is your DashCaddy host — for example
+ https://dashcaddy-host/api/v1/services. All endpoints require authentication (see below) and
+ return structured error codes rather than opaque messages.
{`# List all services
-curl -H "Authorization: Bearer $TOKEN" \\
+curl -H "Authorization: Bearer ***" \\
https://dashcaddy-host/api/v1/services
# Deploy from a template
-curl -X POST -H "Authorization: Bearer $TOKEN" \\
+curl -X POST -H "Authorization: Bearer ***" \\
-H "Content-Type: application/json" \\
- -d '{"template":" jellyfin","name":"media","hostname":"media.lab"}' \\
- https://dashcaddy-host/api/v1/services`}
+ -d '{"template":"jellyfin","name":"media","hostname":"media.lab"}' \\
+ https://dashcaddy-host/api/v1/services
+
+# Restart a service
+curl -X POST -H "Authorization: Bearer ***" \\
+ https://dashcaddy-host/api/v1/services/media/restart`}
+
+ + DashCaddy supports two authentication methods, chosen by how you access the API: +
++ The web dashboard authenticates with a session cookie set after login (email magic link or username/password + with optional TOTP 2FA). API calls made from the browser carry the cookie automatically. This is the right + method for in-dashboard automation and userscripts. +
+
+ For server-to-server automation, scripts, and the SDK, use an API key. Generate keys from
+ Settings → API Keys. Keys are bearer tokens — pass them in the Authorization
+ header on every request:
+
{`Authorization: Bearer dc_live_xxxxxxxxxxxxxxxxxxxx`}
+ ++ ++ Security: API keys grant the same permissions as the user who + created them, scoped by RBAC role. Store keys in a secret manager — never commit them to source control. + Rotate keys immediately if one is leaked. +
+
+ The API applies per-token rate limiting to protect the platform from runaway scripts and abusive clients.
+ Limits are generous for normal operation: interactive dashboard usage will never hit them. If a client exceeds
+ the limit, the API responds with 429 Too Many Requests and a Retry-After header
+ indicating when to retry. Back off and retry — do not hammer the endpoint.
+
+ For high-volume automation (e.g. polling service status in a tight loop), prefer the WebSocket + channel or the Prometheus endpoint over repeated REST polling. Both are designed for + frequent reads and do not count against the REST rate limit. +
For programmatic automation, DashCaddy ships a typed JavaScript SDK with 39 methods and full TypeScript types. It mirrors the REST API and handles authentication, retries, and structured - error handling for you. + error handling for you. Install it from npm and use it in Node.js, Deno, Bun, or the browser.
+{`# Install
+npm install @dashcaddy/sdk
+# or
+pnpm add @dashcaddy/sdk`}
{`import { DashCaddy } from '@dashcaddy/sdk';
-const dc = new DashCaddy({ baseUrl: 'https://dashcaddy-host', token: process.env.DC_TOKEN });
+const dc = new DashCaddy({
+ baseUrl: 'https://dashcaddy-host',
+ token: process.env.DC_TOKEN,
+});
// List services
const services = await dc.services.list();
@@ -48,60 +114,215 @@ const svc = await dc.services.deploy({
});
// Adopt a discovered container
-await dc.services.adopt({ containerId: 'abc123', hostname: 'wiki.lab' });`}
+await dc.services.adopt({ containerId: 'abc123', hostname: 'wiki.lab' });
-
- The API and SDK return 80 structured error codes rather than opaque messages, so your
- automation can branch on specific failure conditions (DNS token invalid, Caddy unreachable, license expired,
- etc.) instead of parsing strings.
+ Every SDK method returns a typed result or throws a structured DashCaddyError carrying the error
+ code, HTTP status, and message — so your automation can branch on specific failure conditions.
The AI Intent Router accepts natural-language commands and translates them into real - infrastructure actions through the same API. This turns ad-hoc operator requests into reproducible, logged - operations. + infrastructure actions through the same API. This turns ad-hoc operator requests (“restart the media + server”, “is postgres up?”, “deploy redis”) into reproducible, logged operations + — no need to remember endpoint paths or parameter names. +
++ The router parses intent, maps it to the correct API call, executes it, and returns both a human-readable + summary and the raw API result. Every intent execution is recorded in the audit log just like a manual action.
{`# Natural-language operation
POST /api/v1/ai/intent
-{ "message": "Restart the media server and check its health" }`}
+{
+ "message": "Restart the media server and check its health"
+}
+
+# Response
+{
+ "summary": "Restarted 'media' and confirmed health: healthy",
+ "actions": [
+ { "method": "POST", "path": "/api/v1/services/media/restart", "status": 200 },
+ { "method": "GET", "path": "/api/v1/services/media/health", "status": 200 }
+ ]
+}`}
+
+ Example intents: “deploy the postgres template as db on db.lab”,
+ “list all unhealthy services”, “rotate the TLS cert for wiki.lab”,
+ “create a DNS record for api.lab pointing at 10.0.0.5”.
+
The built-in MCP (Model Context Protocol) Server exposes DashCaddy operations as tools that AI assistants and external automation can call directly. Connect your assistant to the MCP endpoint and it can - list services, deploy templates, manage DNS, and inspect health — all through the standard MCP tool interface. + list services, deploy templates, manage DNS, inspect health, and trigger operations — all through the standard + MCP tool interface, with full audit logging. +
++ To connect Claude Desktop, GPT, or another MCP-compatible assistant, add the DashCaddy MCP server to your + client's MCP configuration: +
+{`{
+ "mcpServers": {
+ "dashcaddy": {
+ "url": "https://dashcaddy-host/mcp",
+ "headers": {
+ "Authorization": "Bearer dc_live_xxxxxxxxxxxxxxxxxxxx"
+ }
+ }
+ }
+}`}
+ + Once connected, the assistant discovers DashCaddy's tools automatically and can invoke them in response to + your requests — “ask DashCaddy which services are down”, “have DashCaddy deploy Grafana”, + etc. This is the most natural way to operate infrastructure through conversation.
-The dashboard subscribes to a WebSocket channel for live updates: service health changes, - container starts/stops, deployment progress, and fleet events arrive in real time without polling. You can - consume the same channel in your own dashboards or automation. + container starts and stops, deployment progress, DNS changes, and fleet events arrive in real time without + polling. You can consume the same channel in your own dashboards, chatops bots, or automation.
+{`const ws = new WebSocket('wss://dashcaddy-host/api/v1/events', {
+ headers: { Authorization: 'Bearer ' + process.env.DC_TOKEN },
+});
+
+ws.on('message', (data) => {
+ const event = JSON.parse(data);
+ console.log(event.type, event.payload);
+});`}
+ + Common event types you will see on the channel: +
+| Event type | +Emitted when | +
|---|---|
service.health | A service transitions between healthy / unhealthy / down |
service.started | A container starts successfully |
service.stopped | A container stops (graceful or crash) |
deploy.progress | A template deployment advances through its stages |
deploy.complete | A deployment finishes (success or failure) |
dns.changed | A DNS record is created, updated, or removed |
proxy.updated | A Caddy route is applied or removed |
cert.issued | A TLS certificate is issued or renewed |
fleet.host | A fleet host changes state (Premium) |
audit.event | A user or API action is logged for audit |
DashCaddy exposes a Prometheus-format metrics endpoint at /metrics for service health, container
- status, request counts, and system indicators. Scrape it with Prometheus and visualize in Grafana.
+ status, request counts, certificate expiry, and system indicators. Scrape it with Prometheus and visualize in
+ Grafana. See Integrations for a full scrape config.
{`# Health and readiness probes
-GET /healthz # liveness — is the process up?
-GET /readyz # readiness — is it ready to serve (deps connected)?`}
+ {`# Scrape config (prometheus.yml)
+scrape_configs:
+ - job_name: 'dashcaddy'
+ metrics_path: /metrics
+ static_configs:
+ - targets: ['dashcaddy-host:3000']
- Plugin & extension hooks
+# Sample exported metrics
+dashcaddy_service_health{service="media"} 1
+dashcaddy_container_running{container="db"} 1
+dashcaddy_http_requests_total{service="wiki",code="200"} 48213
+dashcaddy_cert_expiry_days{domain="media.lab"} 87`}
+
+ + Two lightweight probes let orchestrators and load balancers check DashCaddy itself: +
+{`# Liveness — is the process up?
+GET /healthz
+
+# Readiness — can it serve (Docker, Caddy, DNS connected)?
+GET /readyz`}
+
+ Use /healthz for container restart policies and /readyz for traffic gating. If
+ /readyz fails but /healthz passes, a dependency (Docker socket, Caddy Admin API, or
+ Technitium DNS) is unreachable — see Troubleshooting.
+
DashCaddy includes a plugin/extension system with hooks into the deployment, DNS, proxy, and monitoring pipelines. Write extensions to react to service lifecycle events, inject custom Caddy directives, emit additional metrics, or integrate third-party tools — without forking the core.
+
+ Plugins register for lifecycle hooks (e.g. onServiceDeployed, onDnsRecordCreated,
+ onProxyRouteApplied) and receive a context object they can act on. A plugin can modify the
+ generated Caddyfile before it is applied, push a notification when a service goes unhealthy, or export custom
+ metrics alongside the built-in ones. Plugins are loaded at startup and run in the same process.
+
+ The API and SDK return 80 structured error codes across 12 modules rather + than opaque messages, so your automation can branch on specific failure conditions — DNS token invalid, Caddy + unreachable, license expired, rate limited — instead of parsing strings. Every error response includes the + machine-readable code, the HTTP status, and a human-readable message. +
+| Module | +Example error codes | +
|---|---|
| auth | AUTH_INVALID_TOKEN, AUTH_PERMISSION_DENIED, AUTH_2FA_REQUIRED |
| service | SERVICE_NOT_FOUND, SERVICE_ALREADY_EXISTS, SERVICE_UNHEALTHY |
| deploy | DEPLOY_TEMPLATE_INVALID, DEPLOY_PORT_CONFLICT, DEPLOY_FAILED |
| dns | DNS_TOKEN_INVALID, DNS_ZONE_NOT_FOUND, DNS_RECORD_EXISTS |
| proxy | PROXY_CADDY_UNREACHABLE, PROXY_CONFIG_INVALID, PROXY_UPSTREAM_TIMEOUT |
| cert | CERT_ISSUANCE_FAILED, CERT_EXPIRED, CERT_NOT_TRUSTED |
| license | LICENSE_EXPIRED, LICENSE_INVALID, LICENSE_MACHINE_LIMIT |
| user | USER_NOT_FOUND, USER_ALREADY_EXISTS, USER_INVITE_EXPIRED |
| backup | BACKUP_FAILED, BACKUP_CORRUPT, RESTORE_CONFLICT |
| recipe | RECIPE_INVALID, RECIPE_COMPONENT_FAILED (Premium) |
| swarm | SWARM_NOT_INITIALIZED, SWARM_NODE_UNREACHABLE (Premium) |
| fleet | FLEET_HOST_OFFLINE, FLEET_DEPLOY_PLAN_FAILED (Premium) |
+ Handle errors by code in your automation: +
+{`try {
+ await dc.services.deploy({ template: 'postgres', name: 'db', hostname: 'db.lab' });
+} catch (err) {
+ if (err.code === 'DEPLOY_PORT_CONFLICT') {
+ // pick a different port and retry
+ } else if (err.code === 'LICENSE_EXPIRED') {
+ // alert ops to renew
+ } else {
+ throw err; // unknown — surface to the operator
+ }
+}`}
- DashCaddy can execute the full infrastructure chain around a service, not just report its state after the
- fact. Between the REST API, the JS SDK, the AI Intent Router, MCP, WebSockets, Prometheus, and the plugin
- system, you have every surface you need to make DashCaddy a first-class citizen of your automation stack.
+ DashCaddy can execute the full infrastructure chain around a service, not just report its state after the fact.
+ Between the REST API, the JS SDK, the AI Intent Router, MCP, WebSockets, Prometheus, and the plugin system, you
+ have every surface you need to make DashCaddy a first-class citizen of your automation stack. Start with a
+ simple curl call, graduate to the SDK, and add AI and event-driven flows as your needs grow.
+
+ For the infrastructure that backs all of this, see Integrations. When things go + wrong, the Troubleshooting guide walks each layer with commands and fixes.
diff --git a/src/app/docs/premium/page.tsx b/src/app/docs/premium/page.tsx index 0464fd9..496c870 100644 --- a/src/app/docs/premium/page.tsx +++ b/src/app/docs/premium/page.tsx @@ -10,71 +10,270 @@ export default function DocsPremiumPage() { title="Premium Features" intro="DashCaddy keeps its Premium model intentionally narrow. The core platform — deployment, DNS, reverse proxy, HTTPS, monitoring, templates, service discovery, and the API — is fully useful without a license. Premium unlocks a focused set of advanced orchestration features." > -+ DashCaddy's philosophy is that the day-to-day platform should be free forever. Everything you need to run + a single host — the dashboard, the full template catalog, Caddy + DNS + TLS automation, real-time monitoring, + Prometheus metrics, multi-user accounts with 2FA and RBAC, the Security Center, the AI Intent Router, the MCP + Server, the JS SDK, and backup/restore — works without a license. Premium adds four capabilities aimed at + teams and multi-host operators who need single sign-on, multi-container stacks, cluster orchestration, or + fleet-wide management. +
++ This guide explains exactly what each Premium feature does, how it differs from the free tier, how to set it + up, and how pricing and licensing work. If you only ever run one host, you may never need Premium — and + that's by design. +
-+ The comparison table below covers every major capability. “Free” means available on an unlicensed + install; “Premium” means the feature requires an active license. +
+| Capability | +Free | +Premium | +
|---|---|---|
| Dashboard & web UI | ✓ | ✓ |
| 76+ application templates | ✓ | ✓ |
| Caddy reverse proxy + auto HTTPS | ✓ | ✓ |
| Caddyfile-as-Code builder | ✓ | ✓ |
| Technitium DNS automation | ✓ | ✓ |
| DashCA internal certificate authority | ✓ | ✓ |
| Service Discovery | ✓ | ✓ |
| Real-time monitoring + WebSocket updates | ✓ | ✓ |
| Prometheus metrics endpoint | ✓ | ✓ |
| Multi-user accounts (invites, email magic link) | ✓ | ✓ |
| TOTP 2FA & RBAC roles | ✓ | ✓ |
| Encrypted credential storage | ✓ | ✓ |
| Security Center & audit logging | ✓ | ✓ |
| AI Intent Router & MCP Server | ✓ | ✓ |
| JavaScript SDK (39 methods) | ✓ | ✓ |
| Backup / restore & Disaster Recovery | ✓ | ✓ |
| Internationalization (5 languages) | ✓ | ✓ |
| Plugin & extension system | ✓ | ✓ |
| Smart Defaults Wizard | ✓ | ✓ |
| Auto-Login SSO | — | ✓ |
| Recipes (multi-container stacks) | — | ✓ |
| Docker Swarm orchestration | — | ✓ |
| Multi-Host Fleet Management | — | ✓ |
| Priority support | — | ✓ |
+ Auto-Login SSO provides single sign-on across all services published through DashCaddy, so an + authenticated DashCaddy user reaches their apps without logging in again to each one. Once you sign into the + DashCaddy dashboard, SSO forwards a signed token to participating services that auto-authenticates the session. + This creates a seamless internal portal experience — ideal for teams that want one front door to every tool. +
++ SSO integrates with services that accept a shared authentication header or token exchange. Supported targets + include apps that read a configurable auth header (common in self-hosted dashboards, wikis, and admin panels) + as well as services that expose a login callback URL. The exact wiring is per-service: in the publish dialog, + enable SSO and provide the header name or callback endpoint the target expects. DashCaddy + handles token signing, rotation, and revocation. +
++ SSO respects your existing RBAC roles. A user with read-only access in DashCaddy will be passed through to + services as a read-only identity where the target supports role mapping. Revoking a user in DashCaddy + immediately invalidates their SSO sessions across all linked services. +
+++ ++ Note: SSO is a pass-through convenience layer, not a replacement + for per-service authentication. Services that require their own login (e.g. a database admin tool) will still + prompt unless they explicitly support header/token SSO. +
+
+ Recipes let you deploy multi-container application stacks as a single coordinated unit. A + Recipe bundles several templates together with pre-wired networking, shared volumes, environment variable + links, and startup ordering, so a complex stack comes up in one click instead of a dozen manual steps. +
++ Typical Recipe stacks include an application plus its dependencies: a web app + PostgreSQL + Redis, a media + suite with its transcoder and metadata store, an analytics pipeline with a database and dashboard, or a + development environment with a code server, language runtime, and database. Each Recipe declares its components, + the network connections between them, and any secrets or config the stack needs at launch. +
+
+ You can also create your own Recipes. Define the component templates, wire the internal
+ network (e.g. app → db:5432), set environment variable references, and save the Recipe to your
+ catalog. Custom Recipes are versioned and shareable, so a team can standardize on the same stack definition
+ across hosts.
+
{`# Deploy a Recipe via the API
+curl -X POST -H "Authorization: Bearer ***" \\
+ -H "Content-Type: application/json" \\
+ -d '{"recipe":"analytics-stack","name":"analytics"}' \\
+ https://dashcaddy-host/api/v1/recipes/deploy`}
+
+ + Docker Swarm support extends DashCaddy's deployment model from a single host to a cluster. + Run services across a Swarm cluster instead of one machine, with DashCaddy managing placement, replicas, + rolling updates, routing, and TLS across every node. This is the right feature when a single host can no longer + carry the load or when you need redundancy for critical services. +
+
+ Multi-node setup follows Docker's standard Swarm workflow: initialize the manager
+ (docker swarm init), join workers (docker swarm join --token ... <manager-ip>),
+ then enable Swarm mode in DashCaddy under Settings → Cluster. DashCaddy detects the cluster
+ and switches from single-container operations to service-level operations — deploy, scale, update, and rollback
+ all operate on Swarm services rather than individual containers.
+
+ Routing and TLS are handled cluster-wide: Caddy's ingress mesh routes traffic to the correct node, and + certificates are issued per published hostname regardless of which node the container lands on. DashCaddy's + service discovery tracks placement changes as the scheduler rebalances containers. +
+ ++ Multi-Host Fleet Management lets you manage DashCaddy deployments across multiple hosts from + one control plane. Instead of opening a separate dashboard per server, you register every host in a single + fleet view and deploy, monitor, and operate services across the entire fleet with unified visibility. This is + designed for operators running DashCaddy on several physical boxes, VPSes, or edge locations. +
++ The fleet workflow has three parts. Register hosts by installing the DashCaddy agent on each + machine and pairing it with your control plane — each host reports its resources, running services, and health. + Health probes poll every host on an interval and surface failures (container down, disk full, + cert expiring) in a unified alert feed. Deploy plans let you target a service or Recipe at a + specific host or a group of hosts, so you can place the media stack on the box with GPU and the database on the + box with SSD without switching dashboards. +
++ Fleet Management is distinct from Swarm: Swarm orchestrates containers across a single logical cluster, while + Fleet Management orchestrates DashCaddy instances across independent hosts. You can use both together — a fleet + of hosts, some of which are themselves Swarm clusters. +
One Premium tier, subscription billing, no hidden upsells:
-- Longer commitments are rewarded: the 12-month plan works out to roughly $8.25/month versus $25/month for a - single month. + 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. +
+| Duration | +Price | +Effective monthly rate | +
|---|---|---|
| 30 days | $20 | ~$20.00 / month |
| 90 days | $50 | ~$16.67 / month |
| 180 days | $70 | ~$11.67 / month |
| 365 days | $99 | ~$8.25 / month |
+ The 365-day plan offers the best value at roughly $8.25/month equivalent — about 59% off the 30-day rate. + All durations unlock the identical Premium feature set; only the length and per-month cost differ.
- DashCaddy's licensing is built around an external validation and deactivation service, - not unlimited static license reuse. On launch and periodically thereafter, the platform validates the license - against the licensing server. This keeps licenses tied to a single active machine and supports clean - deactivation when you move hosts. + A license moves through a defined lifecycle from purchase to deactivation. Understanding this flow helps you + renew on time, move between hosts, and recover from validation failures.
+++ Important: The one-active-machine limit is enforced by the + licensing server. If you reinstall the OS or replace the host without deactivating first, contact support to + release the stale binding. +
+
+ No. Running services are never stopped by a license expiry. During the 7-day grace period everything keeps + running; Premium features become read-only. After grace, Premium-only features are disabled but the free tier + (including all your deployed services) continues to operate. +
++ No — each license is bound to one active machine at a time. To move a license, deactivate it on the current + host and activate it on the new one. For managing multiple hosts simultaneously, use Fleet Management, + which is itself a Premium feature requiring a license per host you want under centralized control. +
++ No. The free tier is permanent and feature-rich — you can evaluate the entire core platform without paying. + Premium adds orchestration features that you likely already know you need (SSO, Recipes, Swarm, Fleet). +
++ They keep running under the grace period and continue to run as ordinary services after that. You lose the + ability to modify them through Premium tooling (e.g. redeploying a Recipe or scaling a Swarm service) + until you renew, but the workloads themselves are not destroyed. +
++ DashCaddy contacts an external licensing server on launch and periodically thereafter. The host must be able + to reach the licensing server for validation to succeed. If the server is temporarily unreachable, the grace + period covers the gap. +
++ Ready to upgrade? Head to Settings → Licensing in your dashboard, or learn more about the + platform in the Product Overview and Integrations guides. +
diff --git a/src/app/docs/troubleshooting/page.tsx b/src/app/docs/troubleshooting/page.tsx index 5d2393c..392aefa 100644 --- a/src/app/docs/troubleshooting/page.tsx +++ b/src/app/docs/troubleshooting/page.tsx @@ -10,86 +10,302 @@ export default function DocsTroubleshootingPage() { title="Troubleshooting" intro="Because DashCaddy sits across runtime, DNS, reverse proxy, certificates, and dashboard state, the fastest way to debug it is layer by layer instead of guessing. This guide walks each layer with the common failures and fixes." > -- Start every investigation with the built-in probes — they tell you whether the platform itself is healthy and - whether its dependencies are wired up: + DashCaddy orchestrates several independent layers — a container runtime, a DNS server, a reverse proxy, a + certificate authority, and its own API and dashboard. When a service is unreachable, the failure is almost + always in exactly one of these layers while the others are healthy. This guide gives you a structured, + layer-by-layer diagnostic procedure with the exact commands to run and the fixes to apply. +
++ The single most important habit: localize before you fix. Resist the urge to restart + everything. Use the health endpoints to narrow down which layer is broken, then dig into that layer with the + commands below. You will solve problems far faster than by reloading the whole stack. +
+ ++ Every investigation begins with the built-in probes. They tell you whether the DashCaddy process itself is + healthy and whether its dependencies are wired up, in two seconds:
/healthz — liveness. Returns 200 if the DashCaddy process is up./readyz — readiness. Returns 200 only when DashCaddy can serve traffic, including connectivity to Docker, Caddy, and DNS where configured.{`curl -s -o /dev/null -w "%{http_code}" https://dashcaddy-host/healthz
-curl -s -o /dev/null -w "%{http_code}" https://dashcaddy-host/readyz`}
+ {`# Print just the HTTP status codes
+curl -s -o /dev/null -w "healthz: %{http_code}\\n" https://dashcaddy-host/healthz
+curl -s -o /dev/null -w "readyz: %{http_code}\\n" https://dashcaddy-host/readyz`}
- If /healthz fails, the DashCaddy process itself is down. If /healthz passes but
- /readyz fails, a dependency (Docker socket, Caddy Admin API, or Technitium DNS) is unreachable.
+ Interpret the result:
+
/healthz 200, /readyz fails — the process is up but a dependency is unreachable: Docker socket, Caddy Admin API, or Technitium DNS. Read the /readyz body for which dependency failed./healthz fails — the DashCaddy process itself is down. Check docker ps and docker logs dashcaddy.+ When a specific service is unreachable, walk the stack from the container outward to the client. Each step + depends on the one before it, so the first failing step is your root cause: +
+docker ps, docker logs)curl localhost:port)dig, nslookup)openssl s_client, browser cert store)+ The sections below cover each layer in detail with the commands and fixes for the most common failures.
-Work bottom-up through the stack so you isolate the failing layer:
-+ DNS problems show up as “hostname does not resolve” or “resolves to the wrong address.” + Because DashCaddy uses Technitium for internal zones, the most common cause is a client using a public resolver + that does not know about your private zones. +
.lab zones. Point the client's DNS at Technitium, or use Tailscale MagicDNS / split-DNS for remote clients.lab vs lab. is a different zone.{`# Verify resolution against the Technitium resolver directly
-dig @technitium-host media.lab
-nslookup media.lab technitium-host`}
+ {`# Query Technitium directly (bypass the client's resolver)
+dig @technitium-host media.lab +short
+nslookup media.lab technitium-host
+
+# Check what the client's resolver returns (may differ)
+dig media.lab +short
+
+# Trace the full resolution path
+dig media.lab +trace`}
+
+ If dig @technitium-host returns the right IP but dig media.lab does not, the client
+ is not using Technitium. If Technitium itself returns nothing, the record was never created — check the token
+ and zone, then recreate it.
+
NET::ERR_CERT_AUTHORITY_INVALID.
+ Certificate problems show up as browser warnings (NET::ERR_CERT_AUTHORITY_INVALID) or TLS
+ handshake failures. There are two distinct causes, and the fix is different for each.
+
+ For internal (.lab) services, Caddy uses its internal CA and DashCA distributes the root
+ certificate. The root cert must be installed as a trusted CA on each client device — not just
+ the server. Download it from the DashCA page and follow the per-platform instructions (macOS
+ Keychain, Windows certmgr, Linux update-ca-certificates, mobile profiles).
+
+ If Caddy could not reach its CA at deploy time (internal CA down, or ACME unreachable for public domains), no + certificate is issued and the TLS handshake fails outright. Confirm the Caddy Admin API is reachable, then + redeploy or re-trigger TLS for the service. +
+{`# Inspect the certificate a server presents
+echo | openssl s_client -connect media.lab:443 -servername media.lab 2>/dev/null \\
+ | openssl x509 -noout -issuer -subject -dates
+
+# Verify the chain against a specific CA bundle
+openssl s_client -connect media.lab:443 -CAfile /path/to/dashca-root.crt
+
+ If openssl s_client shows the issuer is Caddy's internal CA and your browser still warns,
+ the root cert is not installed on that client. If s_client shows no certificate at all, issuance
+ failed — check Caddy.
+
++ Tip: After installing the root CA, restart the browser. Chrome + and Firefox maintain separate trust stores on some platforms — Firefox may need the import done from its own + settings rather than the OS store. +
+
+ If the service is up, the port is reachable, and DNS resolves, but the URL returns 502, 504, or does not route, + the problem is in the Caddy layer. DashCaddy drives Caddy through its Admin API, so two things can go wrong: + the Admin API is unreachable, or the generated config is wrong. +
docker logs caddy or your Caddy service logs — for upstream connection errors.curl localhost:2019/config/ on the host)docker logs caddy or your Caddy service logs — for upstream connection errors and reload failures.{`# Query the live Caddy config via the Admin API
+curl -s localhost:2019/config/ | jq
+
+# Find the route for a specific hostname
+curl -s localhost:2019/config/ | jq '.. | .match? // empty | select(.host[]? | contains("media.lab"))'
+
+# Tail Caddy logs for upstream errors
+docker logs caddy --tail 50 -f`}
+ If a service shows Unhealthy or Down on the dashboard, the problem is the container itself. + Go straight to Docker. +
docker ps -a and docker logs <container> for crash loops or misconfiguration.docker ps -a — is the container running, restarting, or exited?docker logs <container> — look for crash loops, missing files, bad config, or auth failures.{`# List all containers including stopped ones
+docker ps -a --filter "name=media"
- Common gotchas
+# Tail recent logs
+docker logs media --tail 100
+
+# Inspect the healthcheck status and exit codes
+docker inspect media --format '{{.State.Health.Status}} {{.State.ExitCode}}'
+
+# Check resource usage if the container is OOM-killing
+docker stats --no-stream media`}
+
+ + If DashCaddy itself is slow or unresponsive, the cause is usually resource pressure on the host or an + overloaded dependency. +
htop, free -h, and df -h. DashCaddy is lightweight, but a host running dozens of containers can starve it.iostat -x 1 for high %util.docker info and systemctl status docker reveal daemon-level issues.{`# Quick host health snapshot
+free -h && df -h | grep -E "^/dev|Filesystem"
+docker stats --no-stream
+uptime`}
+
+ + The table maps the most frequently seen errors to their likely cause and fix. For the full catalog of + structured error codes across all modules, see the API guide. +
+| Error | +Likely cause | +Fix | +
|---|---|---|
NET::ERR_CERT_AUTHORITY_INVALID |
+ Client does not trust the DashCA root certificate | +Install the root CA from the DashCA page on the client device | +
502 Bad Gateway |
+ Caddy route points at a wrong/unreachable upstream port | +Check the Caddyfile-as-Code view; fix the upstream host:port; re-apply | +
504 Gateway Timeout |
+ Upstream is up but too slow to respond within the proxy timeout | +Inspect container logs; increase Caddy proxy timeout if the app legitimately needs more time | +
| Hostname does not resolve | +Client is not using Technitium as its resolver, or the record was not created | +Point client DNS at Technitium; verify the record exists; re-run DNS step | +
DNS_TOKEN_INVALID |
+ Technitium API token expired or revoked | +Regenerate the token in Technitium; update it under Settings → DNS | +
PROXY_CADDY_UNREACHABLE |
+ Caddy Admin API (localhost:2019) is down or firewalled | +Restart Caddy; confirm the Admin API port is open to DashCaddy | +
DEPLOY_PORT_CONFLICT |
+ Another container already holds the requested host port | +Stop the conflicting container or choose a different port | +
LICENSE_EXPIRED |
+ Premium license expired past the 7-day grace period | +Renew from Settings → Licensing; free-tier features remain available | +
LICENSE_MACHINE_LIMIT |
+ License already bound to another machine | +Deactivate on the old host before activating on the new one | +
AUTH_PERMISSION_DENIED |
+ User/API key lacks the RBAC role for the action | +Assign the needed role in Settings → Users | +
| WebSocket updates stall | +A reverse proxy or firewall is dropping the WS upgrade | +Allow WebSocket upgrades on the DashCaddy route in Caddy/firewall | +
429 Too Many Requests |
+ API client exceeded the per-token rate limit | +Back off and retry after Retry-After; switch polling to WS/Prometheus |
+
+ When the standard checks do not reveal the problem, enable debug logging for verbose output from every layer.
+ Set the LOG_LEVEL environment variable to debug and restart DashCaddy:
+
{`# Enable debug logging (docker run)
+docker run -d \\
+ -e LOG_LEVEL=debug \\
+ -v /var/run/docker.sock:/var/run/docker.sock \\
+ -p 3000:3000 \\
+ ghcr.io/dashcaddy/dashcaddy:latest
+
+# Or in docker-compose.yml
+services:
+ dashcaddy:
+ environment:
+ - LOG_LEVEL=debug
+
+# Then tail the logs
+docker logs dashcaddy -f --tail 200`}
+ + Debug mode emits detailed logs for Docker operations, Caddy Admin API calls, DNS requests, certificate + workflows, and the AI/MCP layer. Reproduce the problem while debug logging is on, then grep the logs for the + relevant module. Disable debug mode when done — it is verbose and not recommended for long-term production use. +
+ ++ If you have worked through the layers above and are still stuck, the following resources can help: +
+Most DashCaddy problems are really one dependency layer failing while the others are healthy. Use the health - endpoints to localize, then walk the debug order. Fixing the right layer first is always faster than - reloading the whole stack. + endpoints to localize, then walk the debug order from the container outward. Fixing the right layer first is + always faster than reloading the whole stack. When in doubt, enable debug mode, reproduce the issue, and read + the logs for the failing module — the answer is almost always there.
diff --git a/src/app/pricing/page.tsx b/src/app/pricing/page.tsx index b4466b8..6fb6007 100644 --- a/src/app/pricing/page.tsx +++ b/src/app/pricing/page.tsx @@ -16,10 +16,10 @@ import Footer from '@/components/Footer'; // pro-365d → $99, 365-day license (one-time payment) // ───────────────────────────────────────────────────────────────────── const STRIPE_LINKS: Record