diff --git a/src/app/docs/catalog/actual-budget/page.tsx b/src/app/docs/catalog/actual-budget/page.tsx index fe40fee..888307c 100644 --- a/src/app/docs/catalog/actual-budget/page.tsx +++ b/src/app/docs/catalog/actual-budget/page.tsx @@ -16,111 +16,111 @@ export default function actualBudgetDocsPage() { intro="Privacy-focused budgeting app with envelope budgeting" >
actualbudget/actual-server:latest
- actualbudget/actual-server:latest
+
- Privacy-focused budgeting app with envelope budgeting
-Actual Budget ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Actual Budget, not installing it.
+Privacy-focused budgeting app with envelope budgeting
+Actual Budget ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Actual Budget, not installing it.
-https://status.sami; configurable via the dashboardHost setting in config.json).POST /api/v1/auth/keys to create one).https://status.sami (or your host's dashboard URL).actualbudget/actual-server:latest image.budget.<your-domain>./) to pass.https://status.sami (or your host's dashboard URL).budget), host port (default: 5006)./) to pass.{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.If you script deployments or use the MCP / AI Intent Router, install with:
-curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "actual-budget",
- "host": "local",
- "subdomain": "budget",
- "port": "{{PORT}}",
-
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "actual-budget",
+ "config": {
+ "subdomain": "budget",
+ "port": 5006
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Actual Budget on my home host and expose it at budget.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Actual Budget on my home host and expose it at budget.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Create your first budget in the web interface
- - Import transactions from your bank (OFX, QFX, CSV)
- - Set up envelope categories for spending control
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull actualbudget/actual-server:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Create your first budget in the web interface
+ - Import transactions from your bank (OFX, QFX, CSV)
+ - Set up envelope categories for spending control
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/actual-budget/data:/data
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+None. The container runs with its upstream defaults.
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/actual-budget/data:/data
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull actualbudget/actual-server:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- None. The container runs with its upstream defaults.
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull actualbudget/actual-server:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Actual Budget → Update.
-
- Backups
- The config volume for Actual Budget is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Actual Budget:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Actual Budget is in the Productivity category. Common pairings:
-
- - Nextcloud
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: actual-budget. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Actual Budget:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: actual-budget. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/adminer/page.tsx b/src/app/docs/catalog/adminer/page.tsx
index 9ae0cf9..fc1bad6 100644
--- a/src/app/docs/catalog/adminer/page.tsx
+++ b/src/app/docs/catalog/adminer/page.tsx
@@ -16,112 +16,112 @@ export default function adminerDocsPage() {
intro="Lightweight database management in single PHP file"
>
- Category: Database
- Difficulty: Easy
- Docker image: adminer:latest
-
+ Category: Database
+ Difficulty: Easy
+ Docker image: adminer:latest
+
- What is Adminer?
- Lightweight database management in single PHP file
- Adminer ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Adminer, not installing it.
+What is Adminer?
+Lightweight database management in single PHP file
+Adminer ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Adminer, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Adminer from the Database category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
adminer:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
adminer.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Adminer from the Database category.
+ - Fill in the deployment form: subdomain (default suggestion:
adminer), host port (default: 8087).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "adminer",
- "host": "local",
- "subdomain": "adminer",
- "port": "{{PORT}}",
- "environment": {
- "ADMINER_DEFAULT_SERVER": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "adminer",
+ "config": {
+ "subdomain": "adminer",
+ "port": 8087
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Adminer on my home host and expose it at adminer.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Adminer on my home host and expose it at adminer.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Connect to your database servers
- - Supports MySQL, PostgreSQL, SQLite, etc.
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull adminer:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Connect to your database servers
+ - Supports MySQL, PostgreSQL, SQLite, etc.
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/adminer:/var/www/html
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ ADMINER_DEFAULT_SERVER
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/adminer:/var/www/html
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull adminer:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- ADMINER_DEFAULT_SERVER
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull adminer:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Adminer → Update.
-
- Backups
- The config volume for Adminer is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Adminer:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Adminer is in the Database category. Common pairings:
-
- - Adminer
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: adminer. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Adminer:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: adminer. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/airsonic/page.tsx b/src/app/docs/catalog/airsonic/page.tsx
index f1e57d2..9541cc4 100644
--- a/src/app/docs/catalog/airsonic/page.tsx
+++ b/src/app/docs/catalog/airsonic/page.tsx
@@ -16,119 +16,117 @@ export default function airsonicDocsPage() {
intro="Free web-based media streamer"
>
- Category: Media
- Difficulty: Easy
- Docker image: linuxserver/airsonic-advanced:latest
-
+ Category: Media
+ Difficulty: Easy
+ Docker image: linuxserver/airsonic-advanced:latest
+
- What is Airsonic Advanced?
- Free web-based media streamer
- Airsonic Advanced ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Airsonic Advanced, not installing it.
+What is Airsonic Advanced?
+Free web-based media streamer
+Airsonic Advanced ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Airsonic Advanced, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Airsonic Advanced from the Media category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
linuxserver/airsonic-advanced:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
airsonic.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Airsonic Advanced from the Media category.
+ - Fill in the deployment form: subdomain (default suggestion:
airsonic), host port (default: 4040).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "airsonic",
- "host": "local",
- "subdomain": "airsonic",
- "port": "{{PORT}}",
- "environment": {
- "PUID": "",
- "PGID": "",
- "TZ": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "airsonic",
+ "config": {
+ "subdomain": "airsonic",
+ "port": 4040
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Airsonic Advanced on my home host and expose it at airsonic.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Airsonic Advanced on my home host and expose it at airsonic.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Default login: admin/admin
- - Configure media folders
- - Set up transcoding
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull linuxserver/airsonic-advanced:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Default login: admin/admin
+ - Configure media folders
+ - Set up transcoding
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/airsonic/config:/config
+/music:/music
+/podcasts:/podcasts
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ PUID
+ PGID
+ TZ
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/airsonic/config:/config
- /music:/music
- /podcasts:/podcasts
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull linuxserver/airsonic-advanced:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- PUID
- PGID
- TZ
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull linuxserver/airsonic-advanced:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Airsonic Advanced → Update.
-
- Backups
- The config volume for Airsonic Advanced is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Airsonic Advanced:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Airsonic Advanced is in the Media category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: airsonic. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Airsonic Advanced:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: airsonic. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/audiobookshelf/page.tsx b/src/app/docs/catalog/audiobookshelf/page.tsx
index 4b6b9fc..17e763c 100644
--- a/src/app/docs/catalog/audiobookshelf/page.tsx
+++ b/src/app/docs/catalog/audiobookshelf/page.tsx
@@ -16,119 +16,121 @@ export default function audiobookshelfDocsPage() {
intro="Self-hosted audiobook and podcast server"
>
- Category: Media
- Difficulty: Easy
- Docker image: ghcr.io/advplyr/audiobookshelf:latest
-
+ Category: Media
+ Difficulty: Easy
+ Docker image: ghcr.io/advplyr/audiobookshelf:latest
+
- What is Audiobookshelf?
- Self-hosted audiobook and podcast server
- Audiobookshelf ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Audiobookshelf, not installing it.
+What is Audiobookshelf?
+Self-hosted audiobook and podcast server
+Audiobookshelf ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Audiobookshelf, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - A host path to mount as the media library (default:
/media/audiobooks).
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - A host path containing your media. Default suggestion:
/media/audiobooks. The deploy form / API payload config.mediaPath must be readable by the container UID (usually 1000).
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Audiobookshelf from the Media category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
ghcr.io/advplyr/audiobookshelf:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
audiobooks.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Audiobookshelf from the Media category.
+ - Fill in the deployment form: subdomain (default suggestion:
audiobooks), host port (default: 13378), and the media library path.
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "audiobookshelf",
- "host": "local",
- "subdomain": "audiobooks",
- "port": "{{PORT}}",
-
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "audiobookshelf",
+ "config": {
+ "subdomain": "audiobooks",
+ "port": 13378,
+ "mediaPath": "/media/audiobooks"
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Audiobookshelf on my home host and expose it at audiobooks.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Audiobookshelf on my home host and expose it at audiobooks.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Create your account on first access
- - Add your audiobook library folders
- - Download the mobile app for offline listening
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull ghcr.io/advplyr/audiobookshelf:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
- Media library path notes
- The media mount path you set at deploy time is what Audiobookshelf will see as /audiobooks. For multi-library setups (movies + TV + music), bind the parent folder and let Audiobookshelf discover subfolders automatically.
-
- - Permissions: Audiobookshelf runs as a non-root user. Make sure your media files are readable by UID
1000 (or whichever the container expects — check the Logs tab on first run).
- - Performance: Put the media library on the same storage pool as DashCaddy itself; cross-pool mounts add 10–30% latency on first scan.
-
+Post-install: first-run checklist
+
+ - Create your account on first access
+ - Add your audiobook library folders
+ - Download the mobile app for offline listening
+
+Media library path notes
+The media mount path you pass as mediaPath in the deploy payload is mounted as /audiobooks inside the container. Bind a host directory containing your media library (movies, TV shows, music, etc.).
+
+ - UID/GID: Audiobookshelf runs as a non-root user. If you see permission errors in the dashboard Logs tab, run
chown -R 1000:1000 /media/audiobooks on the host.
+ - Multi-library: bind the parent folder and let Audiobookshelf discover subfolders.
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/audiobookshelf/config:/config
+/opt/audiobookshelf/metadata:/metadata
+MEDIA_PATH:/audiobooks
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+None. The container runs with its upstream defaults.
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/audiobookshelf/config:/config
- /opt/audiobookshelf/metadata:/metadata
- MEDIA_PATH:/audiobooks
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull ghcr.io/advplyr/audiobookshelf:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- None. The container runs with its upstream defaults.
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull ghcr.io/advplyr/audiobookshelf:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Audiobookshelf → Update.
-
- Backups
- The config volume for Audiobookshelf is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Audiobookshelf:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
- - Library shows empty: confirm the media mount path is readable by the container UID and that the directory contains the file extensions Audiobookshelf indexes.
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Audiobookshelf is in the Media category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: audiobookshelf. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Audiobookshelf:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - Library shows empty: confirm
mediaPath is readable by the container UID and that the directory contains the file extensions Audiobookshelf indexes.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: audiobookshelf. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/authentik/page.tsx b/src/app/docs/catalog/authentik/page.tsx
index 4e01638..76af239 100644
--- a/src/app/docs/catalog/authentik/page.tsx
+++ b/src/app/docs/catalog/authentik/page.tsx
@@ -16,118 +16,116 @@ export default function authentikDocsPage() {
intro="Identity provider and single sign-on platform"
>
- Category: Security
- Difficulty: Advanced
- Docker image: ghcr.io/goauthentik/server:latest
-
+ Category: Security
+ Difficulty: Advanced
+ Docker image: ghcr.io/goauthentik/server:latest
+
- What is Authentik?
- Identity provider and single sign-on platform
- Authentik ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Authentik, not installing it.
+What is Authentik?
+Identity provider and single sign-on platform
+Authentik ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Authentik, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Authentik from the Security category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
ghcr.io/goauthentik/server:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
auth.<your-domain>.
- - Wait for the container health check (
/-/health/live/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Authentik from the Security category.
+ - Fill in the deployment form: subdomain (default suggestion:
auth), host port (default: 9010).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/-/health/live/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "authentik",
- "host": "local",
- "subdomain": "auth",
- "port": "{{PORT}}",
- "environment": {
- "AUTHENTIK_SECRET_KEY": "",
- "AUTHENTIK_ERROR_REPORTING__ENABLED": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "authentik",
+ "config": {
+ "subdomain": "auth",
+ "port": 9010
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Authentik on my home host and expose it at auth.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Authentik on my home host and expose it at auth.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Requires a PostgreSQL database and Redis instance
- - Consider deploying via the Dev Environment recipe for full stack
- - Set up flows for authentication, enrollment, and recovery
- - Configure OAuth2/OIDC providers for SSO with other apps
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull ghcr.io/goauthentik/server:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Requires a PostgreSQL database and Redis instance
+ - Consider deploying via the Dev Environment recipe for full stack
+ - Set up flows for authentication, enrollment, and recovery
+ - Configure OAuth2/OIDC providers for SSO with other apps
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/authentik/media:/media
+/opt/authentik/templates:/templates
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ AUTHENTIK_SECRET_KEY
+ AUTHENTIK_ERROR_REPORTING__ENABLED
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/authentik/media:/media
- /opt/authentik/templates:/templates
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull ghcr.io/goauthentik/server:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- AUTHENTIK_SECRET_KEY
- AUTHENTIK_ERROR_REPORTING__ENABLED
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull ghcr.io/goauthentik/server:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Authentik → Update.
-
- Backups
- The config volume for Authentik is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Authentik:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Authentik is in the Security category. Common pairings:
-
- - Vaultwarden
- - DashCA
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: authentik. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Authentik:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/-/health/live/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: authentik. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/bazarr/page.tsx b/src/app/docs/catalog/bazarr/page.tsx
index 1dc0232..82b42a2 100644
--- a/src/app/docs/catalog/bazarr/page.tsx
+++ b/src/app/docs/catalog/bazarr/page.tsx
@@ -16,121 +16,117 @@ export default function bazarrDocsPage() {
intro="Automatic subtitle downloader for Sonarr and Radarr"
>
- Category: Media Management
- Difficulty: Easy
- Docker image: linuxserver/bazarr:latest
-
+ Category: Media Management
+ Difficulty: Easy
+ Docker image: linuxserver/bazarr:latest
+
- What is Bazarr?
- Automatic subtitle downloader for Sonarr and Radarr
- Bazarr ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Bazarr, not installing it.
+What is Bazarr?
+Automatic subtitle downloader for Sonarr and Radarr
+Bazarr ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Bazarr, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Bazarr from the Media Management category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
linuxserver/bazarr:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
bazarr.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Bazarr from the Media Management category.
+ - Fill in the deployment form: subdomain (default suggestion:
bazarr), host port (default: 6767).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "bazarr",
- "host": "local",
- "subdomain": "bazarr",
- "port": "{{PORT}}",
- "environment": {
- "PUID": "",
- "PGID": "",
- "TZ": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "bazarr",
+ "config": {
+ "subdomain": "bazarr",
+ "port": 6767
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Bazarr on my home host and expose it at bazarr.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Bazarr on my home host and expose it at bazarr.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Connect to Sonarr and Radarr
- - Configure subtitle providers
- - Set language preferences
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull linuxserver/bazarr:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Connect to Sonarr and Radarr
+ - Configure subtitle providers
+ - Set language preferences
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/bazarr/config:/config
+/movies:/movies
+/tv:/tv
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ PUID
+ PGID
+ TZ
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/bazarr/config:/config
- /movies:/movies
- /tv:/tv
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull linuxserver/bazarr:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- PUID
- PGID
- TZ
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull linuxserver/bazarr:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Bazarr → Update.
-
- Backups
- The config volume for Bazarr is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Bazarr:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Bazarr is in the Media Management category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: bazarr. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Bazarr:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: bazarr. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/bind9/page.tsx b/src/app/docs/catalog/bind9/page.tsx
index 7c325d3..5395e31 100644
--- a/src/app/docs/catalog/bind9/page.tsx
+++ b/src/app/docs/catalog/bind9/page.tsx
@@ -16,119 +16,118 @@ export default function bind9DocsPage() {
intro="Industry-standard DNS server - powerful and flexible"
>
- Category: DNS
- Difficulty: Advanced
- Docker image: ubuntu/bind9:latest
-
+ Category: DNS
+ Difficulty: Advanced
+ Docker image: ubuntu/bind9:latest
+
- What is BIND9 DNS Server?
- Industry-standard DNS server - powerful and flexible
- BIND9 DNS Server ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using BIND9 DNS Server, not installing it.
+What is BIND9 DNS Server?
+Industry-standard DNS server - powerful and flexible
+BIND9 DNS Server ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using BIND9 DNS Server, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select BIND9 DNS Server from the DNS category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
ubuntu/bind9:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
dns2.<your-domain>.
- - Wait for the container health check (
tcp://localhost:53) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick BIND9 DNS Server from the DNS category.
+ - Fill in the deployment form: subdomain (default suggestion:
dns2), host port (default: 953).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
tcp://localhost:53) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "bind9",
- "host": "local",
- "subdomain": "dns2",
- "port": "{{PORT}}",
- "environment": {
- "BIND9_USER": "",
- "TZ": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "bind9",
+ "config": {
+ "subdomain": "dns2",
+ "port": 953
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy BIND9 DNS Server on my home host and expose it at dns2.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy BIND9 DNS Server on my home host and expose it at dns2.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Configure zone files in /opt/bind9/config/
- - Create named.conf.local for your .sami zone
- - Add zone file: /opt/bind9/records/db.sami
- - Restart container to apply changes
- - Test with: dig @localhost sami
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull ubuntu/bind9:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Configure zone files in /opt/bind9/config/
+ - Create named.conf.local for your .sami zone
+ - Add zone file: /opt/bind9/records/db.sami
+ - Restart container to apply changes
+ - Test with: dig @localhost sami
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/bind9/config:/etc/bind
+/opt/bind9/cache:/var/cache/bind
+/opt/bind9/records:/var/lib/bind
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ BIND9_USER
+ TZ
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/bind9/config:/etc/bind
- /opt/bind9/cache:/var/cache/bind
- /opt/bind9/records:/var/lib/bind
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull ubuntu/bind9:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- BIND9_USER
- TZ
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull ubuntu/bind9:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → BIND9 DNS Server → Update.
-
- Backups
- The config volume for BIND9 DNS Server is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with BIND9 DNS Server:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- BIND9 DNS Server is in the DNS category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: bind9. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with BIND9 DNS Server:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
tcp://localhost:53 is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: bind9. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/bookstack/page.tsx b/src/app/docs/catalog/bookstack/page.tsx
index 7704928..574d8e6 100644
--- a/src/app/docs/catalog/bookstack/page.tsx
+++ b/src/app/docs/catalog/bookstack/page.tsx
@@ -16,125 +16,119 @@ export default function bookstackDocsPage() {
intro="Simple wiki and documentation platform"
>
- Category: Productivity
- Difficulty: Intermediate
- Docker image: linuxserver/bookstack:latest
-
+ Category: Productivity
+ Difficulty: Intermediate
+ Docker image: linuxserver/bookstack:latest
+
- What is BookStack?
- Simple wiki and documentation platform
- BookStack ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using BookStack, not installing it.
+What is BookStack?
+Simple wiki and documentation platform
+BookStack ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using BookStack, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select BookStack from the Productivity category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
linuxserver/bookstack:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
wiki.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick BookStack from the Productivity category.
+ - Fill in the deployment form: subdomain (default suggestion:
wiki), host port (default: 8091).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "bookstack",
- "host": "local",
- "subdomain": "wiki",
- "port": "{{PORT}}",
- "environment": {
- "PUID": "",
- "PGID": "",
- "APP_URL": "",
- "DB_HOST": "",
- "DB_DATABASE": "",
- "DB_USERNAME": "",
- "DB_PASSWORD": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "bookstack",
+ "config": {
+ "subdomain": "wiki",
+ "port": 8091
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy BookStack on my home host and expose it at wiki.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy BookStack on my home host and expose it at wiki.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Requires MariaDB/MySQL database
- - Default login: admin@admin.com / password
- - Change default credentials
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull linuxserver/bookstack:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Requires MariaDB/MySQL database
+ - Default login: admin@admin.com / password
+ - Change default credentials
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/bookstack/config:/config
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ PUID
+ PGID
+ APP_URL
+ DB_HOST
+ DB_DATABASE
+ DB_USERNAME
+ DB_PASSWORD
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/bookstack/config:/config
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull linuxserver/bookstack:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- PUID
- PGID
- APP_URL
- DB_HOST
- DB_DATABASE
- DB_USERNAME
- DB_PASSWORD
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull linuxserver/bookstack:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → BookStack → Update.
-
- Backups
- The config volume for BookStack is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with BookStack:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- BookStack is in the Productivity category. Common pairings:
-
- - Nextcloud
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: bookstack. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with BookStack:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: bookstack. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/calibre-web/page.tsx b/src/app/docs/catalog/calibre-web/page.tsx
index f26a2c8..be985d4 100644
--- a/src/app/docs/catalog/calibre-web/page.tsx
+++ b/src/app/docs/catalog/calibre-web/page.tsx
@@ -16,124 +16,124 @@ export default function calibreWebDocsPage() {
intro="Web-based ebook manager and reader"
>
- Category: Media
- Difficulty: Intermediate
- Docker image: lscr.io/linuxserver/calibre-web:latest
-
+ Category: Media
+ Difficulty: Intermediate
+ Docker image: lscr.io/linuxserver/calibre-web:latest
+
- What is Calibre-Web?
- Web-based ebook manager and reader
- Calibre-Web ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Calibre-Web, not installing it.
+What is Calibre-Web?
+Web-based ebook manager and reader
+Calibre-Web ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Calibre-Web, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - A host path to mount as the media library (default:
/media/books).
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - A host path containing your media. Default suggestion:
/media/books. The deploy form / API payload config.mediaPath must be readable by the container UID (usually 1000).
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Calibre-Web from the Media category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
lscr.io/linuxserver/calibre-web:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
books.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Calibre-Web from the Media category.
+ - Fill in the deployment form: subdomain (default suggestion:
books), host port (default: 8083), and the media library path.
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "calibre-web",
- "host": "local",
- "subdomain": "books",
- "port": "{{PORT}}",
- "environment": {
- "PUID": "",
- "PGID": "",
- "TZ": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "calibre-web",
+ "config": {
+ "subdomain": "books",
+ "port": 8083,
+ "mediaPath": "/media/books"
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Calibre-Web on my home host and expose it at books.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Calibre-Web on my home host and expose it at books.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Default login: admin / admin123
- - Point to your Calibre database location on first setup
- - Supports EPUB, PDF, MOBI, and more formats
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull lscr.io/linuxserver/calibre-web:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
- Media library path notes
- The media mount path you set at deploy time is what Calibre-Web will see as /books. For multi-library setups (movies + TV + music), bind the parent folder and let Calibre-Web discover subfolders automatically.
-
- - Permissions: Calibre-Web runs as a non-root user. Make sure your media files are readable by UID
1000 (or whichever the container expects — check the Logs tab on first run).
- - Performance: Put the media library on the same storage pool as DashCaddy itself; cross-pool mounts add 10–30% latency on first scan.
-
+Post-install: first-run checklist
+
+ - Default login: admin / admin123
+ - Point to your Calibre database location on first setup
+ - Supports EPUB, PDF, MOBI, and more formats
+
+Media library path notes
+The media mount path you pass as mediaPath in the deploy payload is mounted as /books inside the container. Bind a host directory containing your media library (movies, TV shows, music, etc.).
+
+ - UID/GID: Calibre-Web runs as a non-root user. If you see permission errors in the dashboard Logs tab, run
chown -R 1000:1000 /media/books on the host.
+ - Multi-library: bind the parent folder and let Calibre-Web discover subfolders.
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/calibre-web/config:/config
+MEDIA_PATH:/books
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ PUID
+ PGID
+ TZ
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/calibre-web/config:/config
- MEDIA_PATH:/books
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull lscr.io/linuxserver/calibre-web:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- PUID
- PGID
- TZ
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull lscr.io/linuxserver/calibre-web:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Calibre-Web → Update.
-
- Backups
- The config volume for Calibre-Web is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Calibre-Web:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
- - Library shows empty: confirm the media mount path is readable by the container UID and that the directory contains the file extensions Calibre-Web indexes.
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Calibre-Web is in the Media category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: calibre-web. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Calibre-Web:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - Library shows empty: confirm
mediaPath is readable by the container UID and that the directory contains the file extensions Calibre-Web indexes.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: calibre-web. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/changedetection/page.tsx b/src/app/docs/catalog/changedetection/page.tsx
index e56beab..e450e39 100644
--- a/src/app/docs/catalog/changedetection/page.tsx
+++ b/src/app/docs/catalog/changedetection/page.tsx
@@ -16,111 +16,111 @@ export default function changedetectionDocsPage() {
intro="Monitor websites for changes"
>
- Category: Utilities
- Difficulty: Easy
- Docker image: ghcr.io/dgtlmoon/changedetection.io:latest
-
+ Category: Utilities
+ Difficulty: Easy
+ Docker image: ghcr.io/dgtlmoon/changedetection.io:latest
+
- What is Change Detection?
- Monitor websites for changes
- Change Detection ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Change Detection, not installing it.
+What is Change Detection?
+Monitor websites for changes
+Change Detection ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Change Detection, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Change Detection from the Utilities category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
ghcr.io/dgtlmoon/changedetection.io:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
watch.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Change Detection from the Utilities category.
+ - Fill in the deployment form: subdomain (default suggestion:
watch), host port (default: 5001).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "changedetection",
- "host": "local",
- "subdomain": "watch",
- "port": "{{PORT}}",
-
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "changedetection",
+ "config": {
+ "subdomain": "watch",
+ "port": 5001
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Change Detection on my home host and expose it at watch.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Change Detection on my home host and expose it at watch.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Add URLs to monitor
- - Configure check frequency
- - Set up notifications
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull ghcr.io/dgtlmoon/changedetection.io:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Add URLs to monitor
+ - Configure check frequency
+ - Set up notifications
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/changedetection/data:/datastore
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+None. The container runs with its upstream defaults.
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/changedetection/data:/datastore
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull ghcr.io/dgtlmoon/changedetection.io:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- None. The container runs with its upstream defaults.
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull ghcr.io/dgtlmoon/changedetection.io:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Change Detection → Update.
-
- Backups
- The config volume for Change Detection is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Change Detection:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Change Detection is in the Utilities category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: changedetection. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Change Detection:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: changedetection. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/coredns/page.tsx b/src/app/docs/catalog/coredns/page.tsx
index 0015f05..bdbac79 100644
--- a/src/app/docs/catalog/coredns/page.tsx
+++ b/src/app/docs/catalog/coredns/page.tsx
@@ -16,113 +16,113 @@ export default function corednsDocsPage() {
intro="Cloud-native DNS server - lightweight and flexible"
>
- Category: DNS
- Difficulty: Intermediate
- Docker image: coredns/coredns:latest
-
+ Category: DNS
+ Difficulty: Intermediate
+ Docker image: coredns/coredns:latest
+
- What is CoreDNS?
- Cloud-native DNS server - lightweight and flexible
- CoreDNS ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using CoreDNS, not installing it.
+What is CoreDNS?
+Cloud-native DNS server - lightweight and flexible
+CoreDNS ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using CoreDNS, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select CoreDNS from the DNS category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
coredns/coredns:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
dns4.<your-domain>.
- - Wait for the container health check (
tcp://localhost:53) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick CoreDNS from the DNS category.
+ - Fill in the deployment form: subdomain (default suggestion:
dns4), host port (default: 53).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
tcp://localhost:53) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "coredns",
- "host": "local",
- "subdomain": "dns4",
- "port": "{{PORT}}",
-
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "coredns",
+ "config": {
+ "subdomain": "dns4",
+ "port": 53
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy CoreDNS on my home host and expose it at dns4.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy CoreDNS on my home host and expose it at dns4.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Create Corefile in /opt/coredns/config/
- - Define .sami zone with file plugin
- - Create zone file with your records
- - Restart container to load config
- - Test with: dig @localhost test.sami
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull coredns/coredns:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Create Corefile in /opt/coredns/config/
+ - Define .sami zone with file plugin
+ - Create zone file with your records
+ - Restart container to load config
+ - Test with: dig @localhost test.sami
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/coredns/config:/etc/coredns
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+None. The container runs with its upstream defaults.
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/coredns/config:/etc/coredns
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull coredns/coredns:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- None. The container runs with its upstream defaults.
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull coredns/coredns:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → CoreDNS → Update.
-
- Backups
- The config volume for CoreDNS is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with CoreDNS:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- CoreDNS is in the DNS category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: coredns. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with CoreDNS:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
tcp://localhost:53 is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: coredns. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/crowdsec/page.tsx b/src/app/docs/catalog/crowdsec/page.tsx
index 8fd90cd..9832efb 100644
--- a/src/app/docs/catalog/crowdsec/page.tsx
+++ b/src/app/docs/catalog/crowdsec/page.tsx
@@ -16,114 +16,113 @@ export default function crowdsecDocsPage() {
intro="Collaborative intrusion prevention system"
>
- Category: Security
- Difficulty: Intermediate
- Docker image: crowdsecurity/crowdsec:latest
-
+ Category: Security
+ Difficulty: Intermediate
+ Docker image: crowdsecurity/crowdsec:latest
+
- What is CrowdSec?
- Collaborative intrusion prevention system
- CrowdSec ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using CrowdSec, not installing it.
+What is CrowdSec?
+Collaborative intrusion prevention system
+CrowdSec ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using CrowdSec, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select CrowdSec from the Security category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
crowdsecurity/crowdsec:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
crowdsec.<your-domain>.
- - Wait for the container health check (
/health) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick CrowdSec from the Security category.
+ - Fill in the deployment form: subdomain (default suggestion:
crowdsec), host port (default: 8091).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/health) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "crowdsec",
- "host": "local",
- "subdomain": "crowdsec",
- "port": "{{PORT}}",
-
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "crowdsec",
+ "config": {
+ "subdomain": "crowdsec",
+ "port": 8091
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy CrowdSec on my home host and expose it at crowdsec.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy CrowdSec on my home host and expose it at crowdsec.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Register at app.crowdsec.net for community threat intelligence
- - Install bouncers on your reverse proxy for active blocking
- - CrowdSec analyzes logs and shares threat data with the community
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull crowdsecurity/crowdsec:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Register at app.crowdsec.net for community threat intelligence
+ - Install bouncers on your reverse proxy for active blocking
+ - CrowdSec analyzes logs and shares threat data with the community
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/crowdsec/config:/etc/crowdsec
+/opt/crowdsec/data:/var/lib/crowdsec/data
+/var/log:/var/log:ro
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+None. The container runs with its upstream defaults.
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/crowdsec/config:/etc/crowdsec
- /opt/crowdsec/data:/var/lib/crowdsec/data
- /var/log:/var/log:ro
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull crowdsecurity/crowdsec:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- None. The container runs with its upstream defaults.
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull crowdsecurity/crowdsec:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → CrowdSec → Update.
-
- Backups
- The config volume for CrowdSec is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with CrowdSec:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- CrowdSec is in the Security category. Common pairings:
-
- - Vaultwarden
- - DashCA
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: crowdsec. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with CrowdSec:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/health is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: crowdsec. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/dashca/page.tsx b/src/app/docs/catalog/dashca/page.tsx
index 7d181c4..3adfbbc 100644
--- a/src/app/docs/catalog/dashca/page.tsx
+++ b/src/app/docs/catalog/dashca/page.tsx
@@ -16,113 +16,112 @@ export default function dashcaDocsPage() {
intro="One-click root CA certificate installer for your network"
>
- Category: Security
- Difficulty: Easy
- Docker image: N/A
-
+ Category: Security
+ Difficulty: Easy
+ Docker image: N/A
+
- What is DashCA?
- One-click root CA certificate installer for your network
- DashCA ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using DashCA, not installing it.
+What is DashCA?
+One-click root CA certificate installer for your network
+DashCA ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using DashCA, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select DashCA from the Security category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
N/A image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
ca.<your-domain>.
- - Wait for the container health check (
/healthz) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick DashCA from the Security category.
+ - Fill in the deployment form: subdomain (default suggestion:
ca), host port (default: 32400).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/healthz) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "dashca",
- "host": "local",
- "subdomain": "ca",
- "port": "{{PORT}}",
-
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "dashca",
+ "config": {
+ "subdomain": "ca",
+ "port": 32400
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy DashCA on my home host and expose it at ca.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy DashCA on my home host and expose it at ca.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - New devices: visit http://ca.sami (HTTP, no certificate needed)
- - Click the 'Install Certificate' button for your platform
- - Follow platform-specific instructions
- - Verify all *.sami domains now show secure connections
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull N/A and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - New devices: visit http://ca.sami (HTTP, no certificate needed)
+ - Click the 'Install Certificate' button for your platform
+ - Follow platform-specific instructions
+ - Verify all *.sami domains now show secure connections
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
-
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Environment variables
+None. The container runs with its upstream defaults.
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Environment variables
- None. The container runs with its upstream defaults.
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull N/A.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Updating
- DashCaddy's built-in Watchtower integration will pull N/A every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → DashCA → Update.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Backups
- The config volume for DashCA is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with DashCA:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- DashCA is in the Security category. Common pairings:
-
- - Vaultwarden
- - DashCA
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: dashca. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with DashCA:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/healthz is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: dashca. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/digital-clock/page.tsx b/src/app/docs/catalog/digital-clock/page.tsx
index 526e44a..269e3e5 100644
--- a/src/app/docs/catalog/digital-clock/page.tsx
+++ b/src/app/docs/catalog/digital-clock/page.tsx
@@ -16,110 +16,110 @@ export default function digitalClockDocsPage() {
intro="Live digital clock with time, date, and day of week"
>
- Category: Utilities
- Difficulty: Easy
- Docker image: N/A
-
+ Category: Utilities
+ Difficulty: Easy
+ Docker image: N/A
+
- What is Digital Clock?
- Live digital clock with time, date, and day of week
- Digital Clock ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Digital Clock, not installing it.
+What is Digital Clock?
+Live digital clock with time, date, and day of week
+Digital Clock ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Digital Clock, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Digital Clock from the Utilities category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
N/A image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
digital-clock.<your-domain>.
- - Wait for the container health check (
/healthz) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Digital Clock from the Utilities category.
+ - Fill in the deployment form: subdomain (default suggestion:
digital-clock), host port (default: 32400).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/healthz) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "digital-clock",
- "host": "local",
- "subdomain": "digital-clock",
- "port": "{{PORT}}",
-
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "digital-clock",
+ "config": {
+ "subdomain": "digital-clock",
+ "port": 32400
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Digital Clock on my home host and expose it at digital-clock.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Digital Clock on my home host and expose it at digital-clock.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Clock appears in the top bar to the right of the weather widget
- - No configuration needed — runs automatically
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull N/A and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Clock appears in the top bar to the right of the weather widget
+ - No configuration needed — runs automatically
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
-
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Environment variables
+None. The container runs with its upstream defaults.
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Environment variables
- None. The container runs with its upstream defaults.
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull N/A.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Updating
- DashCaddy's built-in Watchtower integration will pull N/A every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Digital Clock → Update.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Backups
- The config volume for Digital Clock is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Digital Clock:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Digital Clock is in the Utilities category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: digital-clock. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Digital Clock:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/healthz is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: digital-clock. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/dozzle/page.tsx b/src/app/docs/catalog/dozzle/page.tsx
index a6e5aa3..c0281c4 100644
--- a/src/app/docs/catalog/dozzle/page.tsx
+++ b/src/app/docs/catalog/dozzle/page.tsx
@@ -16,112 +16,111 @@ export default function dozzleDocsPage() {
intro="Real-time Docker container log viewer"
>
- Category: Monitoring
- Difficulty: Easy
- Docker image: amir20/dozzle:latest
-
+ Category: Monitoring
+ Difficulty: Easy
+ Docker image: amir20/dozzle:latest
+
- What is Dozzle?
- Real-time Docker container log viewer
- Dozzle ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Dozzle, not installing it.
+What is Dozzle?
+Real-time Docker container log viewer
+Dozzle ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Dozzle, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Dozzle from the Monitoring category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
amir20/dozzle:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
logs.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Dozzle from the Monitoring category.
+ - Fill in the deployment form: subdomain (default suggestion:
logs), host port (default: 8088).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "dozzle",
- "host": "local",
- "subdomain": "logs",
- "port": "{{PORT}}",
-
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "dozzle",
+ "config": {
+ "subdomain": "logs",
+ "port": 8088
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Dozzle on my home host and expose it at logs.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Dozzle on my home host and expose it at logs.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - View real-time logs from all running containers
- - Filter and search across container logs
- - No configuration needed - auto-discovers containers
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull amir20/dozzle:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - View real-time logs from all running containers
+ - Filter and search across container logs
+ - No configuration needed - auto-discovers containers
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/var/run/docker.sock:/var/run/docker.sock:ro
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+None. The container runs with its upstream defaults.
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /var/run/docker.sock:/var/run/docker.sock:ro
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull amir20/dozzle:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- None. The container runs with its upstream defaults.
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull amir20/dozzle:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Dozzle → Update.
-
- Backups
- The config volume for Dozzle is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Dozzle:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Dozzle is in the Monitoring category. Common pairings:
-
- - Uptime Kuma
- - Dozzle
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: dozzle. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Dozzle:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: dozzle. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/drone/page.tsx b/src/app/docs/catalog/drone/page.tsx
index c38e2d6..884cc8e 100644
--- a/src/app/docs/catalog/drone/page.tsx
+++ b/src/app/docs/catalog/drone/page.tsx
@@ -16,119 +16,116 @@ export default function droneDocsPage() {
intro="Container-native continuous delivery platform"
>
- Category: Development
- Difficulty: Intermediate
- Docker image: drone/drone:latest
-
+ Category: Development
+ Difficulty: Intermediate
+ Docker image: drone/drone:latest
+
- What is Drone CI?
- Container-native continuous delivery platform
- Drone CI ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Drone CI, not installing it.
+What is Drone CI?
+Container-native continuous delivery platform
+Drone CI ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Drone CI, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Drone CI from the Development category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
drone/drone:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
drone.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Drone CI from the Development category.
+ - Fill in the deployment form: subdomain (default suggestion:
drone), host port (default: 8090).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "drone",
- "host": "local",
- "subdomain": "drone",
- "port": "{{PORT}}",
- "environment": {
- "DRONE_GITEA_SERVER": "",
- "DRONE_RPC_SECRET": "",
- "DRONE_SERVER_HOST": "",
- "DRONE_SERVER_PROTO": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "drone",
+ "config": {
+ "subdomain": "drone",
+ "port": 8090
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Drone CI on my home host and expose it at drone.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Drone CI on my home host and expose it at drone.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Configure Git provider integration
- - Set up shared secret
- - Deploy Drone runners
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull drone/drone:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Configure Git provider integration
+ - Set up shared secret
+ - Deploy Drone runners
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/drone/data:/data
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ DRONE_GITEA_SERVER
+ DRONE_RPC_SECRET
+ DRONE_SERVER_HOST
+ DRONE_SERVER_PROTO
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/drone/data:/data
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull drone/drone:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- DRONE_GITEA_SERVER
- DRONE_RPC_SECRET
- DRONE_SERVER_HOST
- DRONE_SERVER_PROTO
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull drone/drone:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Drone CI → Update.
-
- Backups
- The config volume for Drone CI is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Drone CI:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Drone CI is in the Development category. Common pairings:
-
- - Gitea
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: drone. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Drone CI:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: drone. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/emby/page.tsx b/src/app/docs/catalog/emby/page.tsx
index 86de5a7..21a9b68 100644
--- a/src/app/docs/catalog/emby/page.tsx
+++ b/src/app/docs/catalog/emby/page.tsx
@@ -16,124 +16,125 @@ export default function embyDocsPage() {
intro="Personal media server with apps for all devices"
>
- Category: Media
- Difficulty: Easy
- Docker image: emby/embyserver:latest
-
+ Category: Media
+ Difficulty: Easy
+ Docker image: emby/embyserver:latest
+
- What is Emby?
- Personal media server with apps for all devices
- Emby ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Emby, not installing it.
+What is Emby?
+Personal media server with apps for all devices
+Emby ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Emby, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - A host path to mount as the media library (default:
/media).
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - A host path containing your media. Default suggestion:
/media. The deploy form / API payload config.mediaPath must be readable by the container UID (usually 1000).
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Emby from the Media category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
emby/embyserver:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
emby.<your-domain>.
- - Wait for the container health check (
/emby/web/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Emby from the Media category.
+ - Fill in the deployment form: subdomain (default suggestion:
emby), host port (default: 8096), and the media library path.
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/emby/web/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "emby",
- "host": "local",
- "subdomain": "emby",
- "port": "{{PORT}}",
- "environment": {
- "UID": "",
- "GID": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "emby",
+ "config": {
+ "subdomain": "emby",
+ "port": 8096,
+ "mediaPath": "/media"
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Emby on my home host and expose it at emby.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Emby on my home host and expose it at emby.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Complete the initial setup wizard at the web interface
- - Add your media libraries (Movies, TV Shows, Music)
- - Configure user accounts and permissions
- - Install Emby apps on your devices for remote access
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull emby/embyserver:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
- Media library path notes
- The media mount path you set at deploy time is what Emby will see as /media. For multi-library setups (movies + TV + music), bind the parent folder and let Emby discover subfolders automatically.
-
- - Permissions: Emby runs as a non-root user. Make sure your media files are readable by UID
1000 (or whichever the container expects — check the Logs tab on first run).
- - Performance: Put the media library on the same storage pool as DashCaddy itself; cross-pool mounts add 10–30% latency on first scan.
-
+Post-install: first-run checklist
+
+ - Complete the initial setup wizard at the web interface
+ - Add your media libraries (Movies, TV Shows, Music)
+ - Configure user accounts and permissions
+ - Install Emby apps on your devices for remote access
+
+Media library path notes
+The media mount path you pass as mediaPath in the deploy payload is mounted as /media inside the container. Bind a host directory containing your media library (movies, TV shows, music, etc.).
+
+ - UID/GID: Emby runs as a non-root user. If you see permission errors in the dashboard Logs tab, run
chown -R 1000:1000 /media on the host.
+ - Multi-library: bind the parent folder and let Emby discover subfolders.
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/emby/config:/config
+/opt/emby/cache:/cache
+MEDIA_PATH:/media
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ UID
+ GID
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/emby/config:/config
- /opt/emby/cache:/cache
- MEDIA_PATH:/media
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull emby/embyserver:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- UID
- GID
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull emby/embyserver:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Emby → Update.
-
- Backups
- The config volume for Emby is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Emby:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
- - Library shows empty: confirm the media mount path is readable by the container UID and that the directory contains the file extensions Emby indexes.
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Emby is in the Media category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: emby. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Emby:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - Library shows empty: confirm
mediaPath is readable by the container UID and that the directory contains the file extensions Emby indexes.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/emby/web/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: emby. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/excalidraw/page.tsx b/src/app/docs/catalog/excalidraw/page.tsx
index 21fdd25..8b44c87 100644
--- a/src/app/docs/catalog/excalidraw/page.tsx
+++ b/src/app/docs/catalog/excalidraw/page.tsx
@@ -16,111 +16,111 @@ export default function excalidrawDocsPage() {
intro="Collaborative virtual whiteboard for sketching and diagrams"
>
- Category: Productivity
- Difficulty: Easy
- Docker image: excalidraw/excalidraw:latest
-
+ Category: Productivity
+ Difficulty: Easy
+ Docker image: excalidraw/excalidraw:latest
+
- What is Excalidraw?
- Collaborative virtual whiteboard for sketching and diagrams
- Excalidraw ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Excalidraw, not installing it.
+What is Excalidraw?
+Collaborative virtual whiteboard for sketching and diagrams
+Excalidraw ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Excalidraw, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Excalidraw from the Productivity category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
excalidraw/excalidraw:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
draw.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Excalidraw from the Productivity category.
+ - Fill in the deployment form: subdomain (default suggestion:
draw), host port (default: 8086).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "excalidraw",
- "host": "local",
- "subdomain": "draw",
- "port": "{{PORT}}",
-
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "excalidraw",
+ "config": {
+ "subdomain": "draw",
+ "port": 8086
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Excalidraw on my home host and expose it at draw.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Excalidraw on my home host and expose it at draw.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Start drawing immediately - no account needed
- - Share drawings via link for real-time collaboration
- - Export as PNG, SVG, or Excalidraw file
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull excalidraw/excalidraw:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Start drawing immediately - no account needed
+ - Share drawings via link for real-time collaboration
+ - Export as PNG, SVG, or Excalidraw file
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/excalidraw/data:/var/lib/excalidraw
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+None. The container runs with its upstream defaults.
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/excalidraw/data:/var/lib/excalidraw
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull excalidraw/excalidraw:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- None. The container runs with its upstream defaults.
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull excalidraw/excalidraw:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Excalidraw → Update.
-
- Backups
- The config volume for Excalidraw is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Excalidraw:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Excalidraw is in the Productivity category. Common pairings:
-
- - Nextcloud
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: excalidraw. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Excalidraw:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: excalidraw. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/filebrowser/page.tsx b/src/app/docs/catalog/filebrowser/page.tsx
index ae19b3b..98fc6d2 100644
--- a/src/app/docs/catalog/filebrowser/page.tsx
+++ b/src/app/docs/catalog/filebrowser/page.tsx
@@ -16,112 +16,112 @@ export default function filebrowserDocsPage() {
intro="Web-based file manager with sharing capabilities"
>
- Category: Files
- Difficulty: Easy
- Docker image: filebrowser/filebrowser:latest
-
+ Category: Files
+ Difficulty: Easy
+ Docker image: filebrowser/filebrowser:latest
+
- What is FileBrowser?
- Web-based file manager with sharing capabilities
- FileBrowser ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using FileBrowser, not installing it.
+What is FileBrowser?
+Web-based file manager with sharing capabilities
+FileBrowser ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using FileBrowser, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select FileBrowser from the Files category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
filebrowser/filebrowser:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
files.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick FileBrowser from the Files category.
+ - Fill in the deployment form: subdomain (default suggestion:
files), host port (default: 8085).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "filebrowser",
- "host": "local",
- "subdomain": "files",
- "port": "{{PORT}}",
-
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "filebrowser",
+ "config": {
+ "subdomain": "files",
+ "port": 8085
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy FileBrowser on my home host and expose it at files.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy FileBrowser on my home host and expose it at files.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Default login: admin/admin
- - Change default password immediately
- - Configure user permissions and shares
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull filebrowser/filebrowser:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Default login: admin/admin
+ - Change default password immediately
+ - Configure user permissions and shares
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/filebrowser/data:/srv
+/opt/filebrowser/database:/database
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+None. The container runs with its upstream defaults.
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/filebrowser/data:/srv
- /opt/filebrowser/database:/database
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull filebrowser/filebrowser:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- None. The container runs with its upstream defaults.
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull filebrowser/filebrowser:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → FileBrowser → Update.
-
- Backups
- The config volume for FileBrowser is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with FileBrowser:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- FileBrowser is in the Files category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: filebrowser. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with FileBrowser:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: filebrowser. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/gitea/page.tsx b/src/app/docs/catalog/gitea/page.tsx
index 0c55243..b0f7a46 100644
--- a/src/app/docs/catalog/gitea/page.tsx
+++ b/src/app/docs/catalog/gitea/page.tsx
@@ -16,118 +16,116 @@ export default function giteaDocsPage() {
intro="Lightweight self-hosted Git service"
>
- Category: Development
- Difficulty: Easy
- Docker image: gitea/gitea:latest
-
+ Category: Development
+ Difficulty: Easy
+ Docker image: gitea/gitea:latest
+
- What is Gitea?
- Lightweight self-hosted Git service
- Gitea ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Gitea, not installing it.
+What is Gitea?
+Lightweight self-hosted Git service
+Gitea ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Gitea, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Gitea from the Development category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
gitea/gitea:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
gitea.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Gitea from the Development category.
+ - Fill in the deployment form: subdomain (default suggestion:
gitea), host port (default: 3005).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "gitea",
- "host": "local",
- "subdomain": "gitea",
- "port": "{{PORT}}",
- "environment": {
- "USER_UID": "",
- "USER_GID": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "gitea",
+ "config": {
+ "subdomain": "gitea",
+ "port": 3005
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Gitea on my home host and expose it at gitea.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Gitea on my home host and expose it at gitea.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Complete initial setup wizard
- - Create admin account
- - Configure SSH access
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull gitea/gitea:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Complete initial setup wizard
+ - Create admin account
+ - Configure SSH access
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/gitea/data:/data
+/etc/timezone:/etc/timezone:ro
+/etc/localtime:/etc/localtime:ro
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ USER_UID
+ USER_GID
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/gitea/data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull gitea/gitea:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- USER_UID
- USER_GID
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull gitea/gitea:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Gitea → Update.
-
- Backups
- The config volume for Gitea is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Gitea:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Gitea is in the Development category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: gitea. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Gitea:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: gitea. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/grafana/page.tsx b/src/app/docs/catalog/grafana/page.tsx
index 7a588c1..1e20161 100644
--- a/src/app/docs/catalog/grafana/page.tsx
+++ b/src/app/docs/catalog/grafana/page.tsx
@@ -16,114 +16,113 @@ export default function grafanaDocsPage() {
intro="Analytics and interactive visualization platform"
>
- Category: Monitoring
- Difficulty: Advanced
- Docker image: grafana/grafana:latest
-
+ Category: Monitoring
+ Difficulty: Advanced
+ Docker image: grafana/grafana:latest
+
- What is Grafana?
- Analytics and interactive visualization platform
- Grafana ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Grafana, not installing it.
+What is Grafana?
+Analytics and interactive visualization platform
+Grafana ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Grafana, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Grafana from the Monitoring category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
grafana/grafana:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
grafana.<your-domain>.
- - Wait for the container health check (
/api/health) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Grafana from the Monitoring category.
+ - Fill in the deployment form: subdomain (default suggestion:
grafana), host port (default: 3000).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/api/health) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "grafana",
- "host": "local",
- "subdomain": "grafana",
- "port": "{{PORT}}",
- "environment": {
- "GF_SECURITY_ADMIN_PASSWORD": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "grafana",
+ "config": {
+ "subdomain": "grafana",
+ "port": 3000
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Grafana on my home host and expose it at grafana.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Grafana on my home host and expose it at grafana.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Open the new
grafana.<your-domain> URL.
- - Complete the upstream Grafana setup wizard (create admin user, accept EULA, etc.).
- - Configure backups from Settings → Backups — the default daily snapshot will capture the data volume.
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull grafana/grafana:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Open the deployed URL (returned in the response as
url, or visible in the dashboard).
+ - Complete the upstream Grafana setup wizard (admin account, library paths, EULA).
+ - Restore from a backup if one exists:
POST /api/v1/apps/{appId}/restore with the backup ID from GET /api/v1/backups/history.
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/grafana/data:/var/lib/grafana
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ GF_SECURITY_ADMIN_PASSWORD
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/grafana/data:/var/lib/grafana
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull grafana/grafana:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- GF_SECURITY_ADMIN_PASSWORD
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull grafana/grafana:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Grafana → Update.
-
- Backups
- The config volume for Grafana is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Grafana:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Grafana is in the Monitoring category. Common pairings:
-
- - Uptime Kuma
- - Dozzle
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: grafana. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Grafana:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/api/health is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: grafana. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/homarr/page.tsx b/src/app/docs/catalog/homarr/page.tsx
index c71088b..143fcd7 100644
--- a/src/app/docs/catalog/homarr/page.tsx
+++ b/src/app/docs/catalog/homarr/page.tsx
@@ -16,113 +16,113 @@ export default function homarrDocsPage() {
intro="Sleek dashboard for all your services"
>
- Category: Utilities
- Difficulty: Easy
- Docker image: ghcr.io/ajnart/homarr:latest
-
+ Category: Utilities
+ Difficulty: Easy
+ Docker image: ghcr.io/ajnart/homarr:latest
+
- What is Homarr?
- Sleek dashboard for all your services
- Homarr ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Homarr, not installing it.
+What is Homarr?
+Sleek dashboard for all your services
+Homarr ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Homarr, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Homarr from the Utilities category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
ghcr.io/ajnart/homarr:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
homarr.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Homarr from the Utilities category.
+ - Fill in the deployment form: subdomain (default suggestion:
homarr), host port (default: 7575).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "homarr",
- "host": "local",
- "subdomain": "homarr",
- "port": "{{PORT}}",
-
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "homarr",
+ "config": {
+ "subdomain": "homarr",
+ "port": 7575
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Homarr on my home host and expose it at homarr.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Homarr on my home host and expose it at homarr.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Add your services via UI
- - Configure integrations
- - Customize layout and appearance
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull ghcr.io/ajnart/homarr:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Add your services via UI
+ - Configure integrations
+ - Customize layout and appearance
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/homarr/configs:/app/data/configs
+/opt/homarr/icons:/app/public/icons
+/var/run/docker.sock:/var/run/docker.sock:ro
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+None. The container runs with its upstream defaults.
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/homarr/configs:/app/data/configs
- /opt/homarr/icons:/app/public/icons
- /var/run/docker.sock:/var/run/docker.sock:ro
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull ghcr.io/ajnart/homarr:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- None. The container runs with its upstream defaults.
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull ghcr.io/ajnart/homarr:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Homarr → Update.
-
- Backups
- The config volume for Homarr is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Homarr:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Homarr is in the Utilities category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: homarr. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Homarr:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: homarr. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/homeassistant/page.tsx b/src/app/docs/catalog/homeassistant/page.tsx
index a4490e7..94d6f3e 100644
--- a/src/app/docs/catalog/homeassistant/page.tsx
+++ b/src/app/docs/catalog/homeassistant/page.tsx
@@ -16,114 +16,114 @@ export default function homeassistantDocsPage() {
intro="Open source home automation platform"
>
- Category: Home Automation
- Difficulty: Intermediate
- Docker image: homeassistant/home-assistant:stable
-
+ Category: Home Automation
+ Difficulty: Intermediate
+ Docker image: homeassistant/home-assistant:stable
+
- What is Home Assistant?
- Open source home automation platform
- Home Assistant ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Home Assistant, not installing it.
+What is Home Assistant?
+Open source home automation platform
+Home Assistant ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Home Assistant, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Home Assistant from the Home Automation category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
homeassistant/home-assistant:stable image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
home.<your-domain>.
- - Wait for the container health check (
/api/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Home Assistant from the Home Automation category.
+ - Fill in the deployment form: subdomain (default suggestion:
home), host port (default: 8123).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/api/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "homeassistant",
- "host": "local",
- "subdomain": "home",
- "port": "{{PORT}}",
- "environment": {
- "TZ": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "homeassistant",
+ "config": {
+ "subdomain": "home",
+ "port": 8123
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Home Assistant on my home host and expose it at home.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Home Assistant on my home host and expose it at home.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Complete onboarding wizard
- - Add integrations for your smart devices
- - Create automations and dashboards
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull homeassistant/home-assistant:stable and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Complete onboarding wizard
+ - Add integrations for your smart devices
+ - Create automations and dashboards
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/homeassistant/config:/config
+/etc/localtime:/etc/localtime:ro
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ TZ
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/homeassistant/config:/config
- /etc/localtime:/etc/localtime:ro
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull homeassistant/home-assistant:stable.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- TZ
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull homeassistant/home-assistant:stable every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Home Assistant → Update.
-
- Backups
- The config volume for Home Assistant is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Home Assistant:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Home Assistant is in the Home Automation category. Common pairings:
-
- - Node-RED (automation)
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: homeassistant. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Home Assistant:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/api/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: homeassistant. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/homepage/page.tsx b/src/app/docs/catalog/homepage/page.tsx
index e9a4ac2..e4ffcda 100644
--- a/src/app/docs/catalog/homepage/page.tsx
+++ b/src/app/docs/catalog/homepage/page.tsx
@@ -16,112 +16,112 @@ export default function homepageDocsPage() {
intro="Highly customizable application dashboard"
>
- Category: Utilities
- Difficulty: Easy
- Docker image: ghcr.io/gethomepage/homepage:latest
-
+ Category: Utilities
+ Difficulty: Easy
+ Docker image: ghcr.io/gethomepage/homepage:latest
+
- What is Homepage?
- Highly customizable application dashboard
- Homepage ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Homepage, not installing it.
+What is Homepage?
+Highly customizable application dashboard
+Homepage ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Homepage, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Homepage from the Utilities category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
ghcr.io/gethomepage/homepage:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
dashboard.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Homepage from the Utilities category.
+ - Fill in the deployment form: subdomain (default suggestion:
dashboard), host port (default: 3008).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "homepage",
- "host": "local",
- "subdomain": "dashboard",
- "port": "{{PORT}}",
-
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "homepage",
+ "config": {
+ "subdomain": "dashboard",
+ "port": 3008
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Homepage on my home host and expose it at dashboard.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Homepage on my home host and expose it at dashboard.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Edit config files to add services
- - Configure widgets
- - Customize appearance
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull ghcr.io/gethomepage/homepage:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Edit config files to add services
+ - Configure widgets
+ - Customize appearance
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/homepage/config:/app/config
+/var/run/docker.sock:/var/run/docker.sock:ro
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+None. The container runs with its upstream defaults.
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/homepage/config:/app/config
- /var/run/docker.sock:/var/run/docker.sock:ro
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull ghcr.io/gethomepage/homepage:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- None. The container runs with its upstream defaults.
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull ghcr.io/gethomepage/homepage:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Homepage → Update.
-
- Backups
- The config volume for Homepage is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Homepage:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Homepage is in the Utilities category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: homepage. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Homepage:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: homepage. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/immich/page.tsx b/src/app/docs/catalog/immich/page.tsx
index f9578bb..09701ab 100644
--- a/src/app/docs/catalog/immich/page.tsx
+++ b/src/app/docs/catalog/immich/page.tsx
@@ -16,123 +16,118 @@ export default function immichDocsPage() {
intro="Self-hosted Google Photos alternative"
>
- Category: Photos
- Difficulty: Intermediate
- Docker image: ghcr.io/immich-app/immich-server:latest
-
+ Category: Photos
+ Difficulty: Intermediate
+ Docker image: ghcr.io/immich-app/immich-server:latest
+
- What is Immich?
- Self-hosted Google Photos alternative
- Immich ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Immich, not installing it.
+What is Immich?
+Self-hosted Google Photos alternative
+Immich ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Immich, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Immich from the Photos category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
ghcr.io/immich-app/immich-server:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
photos.<your-domain>.
- - Wait for the container health check (
/api/server-info/ping) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Immich from the Photos category.
+ - Fill in the deployment form: subdomain (default suggestion:
photos), host port (default: 2283).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/api/server-info/ping) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "immich",
- "host": "local",
- "subdomain": "photos",
- "port": "{{PORT}}",
- "environment": {
- "DB_HOSTNAME": "",
- "DB_USERNAME": "",
- "DB_PASSWORD": "",
- "DB_DATABASE_NAME": "",
- "REDIS_HOSTNAME": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "immich",
+ "config": {
+ "subdomain": "photos",
+ "port": 2283
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Immich on my home host and expose it at photos.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Immich on my home host and expose it at photos.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Requires PostgreSQL and Redis
- - Install mobile apps for backup
- - Configure machine learning for face detection
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull ghcr.io/immich-app/immich-server:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Requires PostgreSQL and Redis
+ - Install mobile apps for backup
+ - Configure machine learning for face detection
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/immich/upload:/usr/src/app/upload
+/opt/immich/library:/usr/src/app/library
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ DB_HOSTNAME
+ DB_USERNAME
+ DB_PASSWORD
+ DB_DATABASE_NAME
+ REDIS_HOSTNAME
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/immich/upload:/usr/src/app/upload
- /opt/immich/library:/usr/src/app/library
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull ghcr.io/immich-app/immich-server:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- DB_HOSTNAME
- DB_USERNAME
- DB_PASSWORD
- DB_DATABASE_NAME
- REDIS_HOSTNAME
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull ghcr.io/immich-app/immich-server:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Immich → Update.
-
- Backups
- The config volume for Immich is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Immich:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Immich is in the Photos category. Common pairings:
-
- - PhotoPrism (alternative)
- - PostgreSQL (external DB)
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: immich. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Immich:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/api/server-info/ping is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: immich. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/it-tools/page.tsx b/src/app/docs/catalog/it-tools/page.tsx
index 5944ee1..735766b 100644
--- a/src/app/docs/catalog/it-tools/page.tsx
+++ b/src/app/docs/catalog/it-tools/page.tsx
@@ -16,111 +16,111 @@ export default function itToolsDocsPage() {
intro="Collection of handy developer and IT tools in one place"
>
- Category: Utilities
- Difficulty: Easy
- Docker image: corentinth/it-tools:latest
-
+ Category: Utilities
+ Difficulty: Easy
+ Docker image: corentinth/it-tools:latest
+
- What is IT Tools?
- Collection of handy developer and IT tools in one place
- IT Tools ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using IT Tools, not installing it.
+What is IT Tools?
+Collection of handy developer and IT tools in one place
+IT Tools ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using IT Tools, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select IT Tools from the Utilities category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
corentinth/it-tools:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
tools.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick IT Tools from the Utilities category.
+ - Fill in the deployment form: subdomain (default suggestion:
tools), host port (default: 8087).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "it-tools",
- "host": "local",
- "subdomain": "tools",
- "port": "{{PORT}}",
-
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "it-tools",
+ "config": {
+ "subdomain": "tools",
+ "port": 8087
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy IT Tools on my home host and expose it at tools.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy IT Tools on my home host and expose it at tools.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Access the web interface for instant tools access
- - Includes: hash generators, UUID, JWT decoder, base64, regex tester, and 70+ more
- - No configuration needed
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull corentinth/it-tools:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Access the web interface for instant tools access
+ - Includes: hash generators, UUID, JWT decoder, base64, regex tester, and 70+ more
+ - No configuration needed
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/it-tools/config:/config
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+None. The container runs with its upstream defaults.
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/it-tools/config:/config
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull corentinth/it-tools:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- None. The container runs with its upstream defaults.
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull corentinth/it-tools:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → IT Tools → Update.
-
- Backups
- The config volume for IT Tools is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with IT Tools:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- IT Tools is in the Utilities category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: it-tools. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with IT Tools:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: it-tools. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/jdownloader/page.tsx b/src/app/docs/catalog/jdownloader/page.tsx
index de7d80e..163f86e 100644
--- a/src/app/docs/catalog/jdownloader/page.tsx
+++ b/src/app/docs/catalog/jdownloader/page.tsx
@@ -16,113 +16,112 @@ export default function jdownloaderDocsPage() {
intro="Download manager for file hosting sites"
>
- Category: Downloads
- Difficulty: Easy
- Docker image: jlesage/jdownloader-2:latest
-
+ Category: Downloads
+ Difficulty: Easy
+ Docker image: jlesage/jdownloader-2:latest
+
- What is JDownloader 2?
- Download manager for file hosting sites
- JDownloader 2 ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using JDownloader 2, not installing it.
+What is JDownloader 2?
+Download manager for file hosting sites
+JDownloader 2 ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using JDownloader 2, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select JDownloader 2 from the Downloads category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
jlesage/jdownloader-2:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
jdownloader.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick JDownloader 2 from the Downloads category.
+ - Fill in the deployment form: subdomain (default suggestion:
jdownloader), host port (default: 5800).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "jdownloader",
- "host": "local",
- "subdomain": "jdownloader",
- "port": "{{PORT}}",
-
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "jdownloader",
+ "config": {
+ "subdomain": "jdownloader",
+ "port": 5800
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy JDownloader 2 on my home host and expose it at jdownloader.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy JDownloader 2 on my home host and expose it at jdownloader.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Access web interface to configure
- - Link to MyJDownloader account
- - Configure download paths
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull jlesage/jdownloader-2:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Access web interface to configure
+ - Link to MyJDownloader account
+ - Configure download paths
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/jdownloader/config:/config
+/downloads:/output
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+None. The container runs with its upstream defaults.
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/jdownloader/config:/config
- /downloads:/output
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull jlesage/jdownloader-2:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- None. The container runs with its upstream defaults.
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull jlesage/jdownloader-2:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → JDownloader 2 → Update.
-
- Backups
- The config volume for JDownloader 2 is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with JDownloader 2:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- JDownloader 2 is in the Downloads category. Common pairings:
-
- - qBittorrent
- - SABnzbd
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: jdownloader. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with JDownloader 2:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: jdownloader. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/jellyfin/page.tsx b/src/app/docs/catalog/jellyfin/page.tsx
index 38a98d8..d0f4c30 100644
--- a/src/app/docs/catalog/jellyfin/page.tsx
+++ b/src/app/docs/catalog/jellyfin/page.tsx
@@ -16,122 +16,123 @@ export default function jellyfinDocsPage() {
intro="Free software media system - alternative to Plex"
>
- Category: Media
- Difficulty: Easy
- Docker image: jellyfin/jellyfin:latest
-
+ Category: Media
+ Difficulty: Easy
+ Docker image: jellyfin/jellyfin:latest
+
- What is Jellyfin?
- Free software media system - alternative to Plex
- Jellyfin ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Jellyfin, not installing it.
+What is Jellyfin?
+Free software media system - alternative to Plex
+Jellyfin ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Jellyfin, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - A host path to mount as the media library (default:
/media).
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - A host path containing your media. Default suggestion:
/media. The deploy form / API payload config.mediaPath must be readable by the container UID (usually 1000).
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Jellyfin from the Media category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
jellyfin/jellyfin:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
jellyfin.<your-domain>.
- - Wait for the container health check (
/health) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Jellyfin from the Media category.
+ - Fill in the deployment form: subdomain (default suggestion:
jellyfin), host port (default: 8096), and the media library path.
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/health) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "jellyfin",
- "host": "local",
- "subdomain": "jellyfin",
- "port": "{{PORT}}",
- "environment": {
- "JELLYFIN_PublishedServerUrl": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "jellyfin",
+ "config": {
+ "subdomain": "jellyfin",
+ "port": 8096,
+ "mediaPath": "/media"
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Jellyfin on my home host and expose it at jellyfin.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Jellyfin on my home host and expose it at jellyfin.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Complete the initial setup wizard
- - Add your media libraries
- - Configure user accounts and permissions
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull jellyfin/jellyfin:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
- Media library path notes
- The media mount path you set at deploy time is what Jellyfin will see as /media. For multi-library setups (movies + TV + music), bind the parent folder and let Jellyfin discover subfolders automatically.
-
- - Permissions: Jellyfin runs as a non-root user. Make sure your media files are readable by UID
1000 (or whichever the container expects — check the Logs tab on first run).
- - Performance: Put the media library on the same storage pool as DashCaddy itself; cross-pool mounts add 10–30% latency on first scan.
-
+Post-install: first-run checklist
+
+ - Complete the initial setup wizard
+ - Add your media libraries
+ - Configure user accounts and permissions
+
+Media library path notes
+The media mount path you pass as mediaPath in the deploy payload is mounted as /media inside the container. Bind a host directory containing your media library (movies, TV shows, music, etc.).
+
+ - UID/GID: Jellyfin runs as a non-root user. If you see permission errors in the dashboard Logs tab, run
chown -R 1000:1000 /media on the host.
+ - Multi-library: bind the parent folder and let Jellyfin discover subfolders.
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/jellyfin/config:/config
+/opt/jellyfin/cache:/cache
+MEDIA_PATH:/media
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ JELLYFIN_PublishedServerUrl
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/jellyfin/config:/config
- /opt/jellyfin/cache:/cache
- MEDIA_PATH:/media
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull jellyfin/jellyfin:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- JELLYFIN_PublishedServerUrl
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull jellyfin/jellyfin:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Jellyfin → Update.
-
- Backups
- The config volume for Jellyfin is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Jellyfin:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
- - Library shows empty: confirm the media mount path is readable by the container UID and that the directory contains the file extensions Jellyfin indexes.
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Jellyfin is in the Media category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: jellyfin. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Jellyfin:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - Library shows empty: confirm
mediaPath is readable by the container UID and that the directory contains the file extensions Jellyfin indexes.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/health is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: jellyfin. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/jenkins/page.tsx b/src/app/docs/catalog/jenkins/page.tsx
index 7fd9eed..87aa7a4 100644
--- a/src/app/docs/catalog/jenkins/page.tsx
+++ b/src/app/docs/catalog/jenkins/page.tsx
@@ -16,111 +16,111 @@ export default function jenkinsDocsPage() {
intro="Automation server for CI/CD pipelines"
>
- Category: Development
- Difficulty: Advanced
- Docker image: jenkins/jenkins:lts
-
+ Category: Development
+ Difficulty: Advanced
+ Docker image: jenkins/jenkins:lts
+
- What is Jenkins?
- Automation server for CI/CD pipelines
- Jenkins ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Jenkins, not installing it.
+What is Jenkins?
+Automation server for CI/CD pipelines
+Jenkins ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Jenkins, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Jenkins from the Development category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
jenkins/jenkins:lts image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
jenkins.<your-domain>.
- - Wait for the container health check (
/login) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Jenkins from the Development category.
+ - Fill in the deployment form: subdomain (default suggestion:
jenkins), host port (default: 8089).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/login) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "jenkins",
- "host": "local",
- "subdomain": "jenkins",
- "port": "{{PORT}}",
-
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "jenkins",
+ "config": {
+ "subdomain": "jenkins",
+ "port": 8089
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Jenkins on my home host and expose it at jenkins.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Jenkins on my home host and expose it at jenkins.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Get initial admin password from logs
- - Install suggested plugins
- - Create admin user
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull jenkins/jenkins:lts and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Get initial admin password from logs
+ - Install suggested plugins
+ - Create admin user
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/jenkins/data:/var/jenkins_home
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+None. The container runs with its upstream defaults.
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/jenkins/data:/var/jenkins_home
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull jenkins/jenkins:lts.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- None. The container runs with its upstream defaults.
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull jenkins/jenkins:lts every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Jenkins → Update.
-
- Backups
- The config volume for Jenkins is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Jenkins:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Jenkins is in the Development category. Common pairings:
-
- - Gitea
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: jenkins. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Jenkins:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/login is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: jenkins. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/kavita/page.tsx b/src/app/docs/catalog/kavita/page.tsx
index e583f33..17ffe02 100644
--- a/src/app/docs/catalog/kavita/page.tsx
+++ b/src/app/docs/catalog/kavita/page.tsx
@@ -16,118 +16,120 @@ export default function kavitaDocsPage() {
intro="Digital reading platform for manga, comics, and books"
>
- Category: Media
- Difficulty: Easy
- Docker image: jvmilazz0/kavita:latest
-
+ Category: Media
+ Difficulty: Easy
+ Docker image: jvmilazz0/kavita:latest
+
- What is Kavita?
- Digital reading platform for manga, comics, and books
- Kavita ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Kavita, not installing it.
+What is Kavita?
+Digital reading platform for manga, comics, and books
+Kavita ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Kavita, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - A host path to mount as the media library (default:
/media/reading).
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - A host path containing your media. Default suggestion:
/media/reading. The deploy form / API payload config.mediaPath must be readable by the container UID (usually 1000).
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Kavita from the Media category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
jvmilazz0/kavita:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
kavita.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Kavita from the Media category.
+ - Fill in the deployment form: subdomain (default suggestion:
kavita), host port (default: 5004), and the media library path.
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "kavita",
- "host": "local",
- "subdomain": "kavita",
- "port": "{{PORT}}",
-
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "kavita",
+ "config": {
+ "subdomain": "kavita",
+ "port": 5004,
+ "mediaPath": "/media/reading"
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Kavita on my home host and expose it at kavita.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Kavita on my home host and expose it at kavita.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Create admin account on first access
- - Add library folders for manga, comics, or books
- - Supports EPUB, PDF, CBZ, CBR formats
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull jvmilazz0/kavita:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
- Media library path notes
- The media mount path you set at deploy time is what Kavita will see as /data. For multi-library setups (movies + TV + music), bind the parent folder and let Kavita discover subfolders automatically.
-
- - Permissions: Kavita runs as a non-root user. Make sure your media files are readable by UID
1000 (or whichever the container expects — check the Logs tab on first run).
- - Performance: Put the media library on the same storage pool as DashCaddy itself; cross-pool mounts add 10–30% latency on first scan.
-
+Post-install: first-run checklist
+
+ - Create admin account on first access
+ - Add library folders for manga, comics, or books
+ - Supports EPUB, PDF, CBZ, CBR formats
+
+Media library path notes
+The media mount path you pass as mediaPath in the deploy payload is mounted as /data inside the container. Bind a host directory containing your media library (movies, TV shows, music, etc.).
+
+ - UID/GID: Kavita runs as a non-root user. If you see permission errors in the dashboard Logs tab, run
chown -R 1000:1000 /media/reading on the host.
+ - Multi-library: bind the parent folder and let Kavita discover subfolders.
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/kavita/config:/kavita/config
+MEDIA_PATH:/data
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+None. The container runs with its upstream defaults.
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/kavita/config:/kavita/config
- MEDIA_PATH:/data
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull jvmilazz0/kavita:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- None. The container runs with its upstream defaults.
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull jvmilazz0/kavita:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Kavita → Update.
-
- Backups
- The config volume for Kavita is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Kavita:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
- - Library shows empty: confirm the media mount path is readable by the container UID and that the directory contains the file extensions Kavita indexes.
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Kavita is in the Media category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: kavita. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Kavita:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - Library shows empty: confirm
mediaPath is readable by the container UID and that the directory contains the file extensions Kavita indexes.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: kavita. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/komga/page.tsx b/src/app/docs/catalog/komga/page.tsx
index 5cbc0e2..5996405 100644
--- a/src/app/docs/catalog/komga/page.tsx
+++ b/src/app/docs/catalog/komga/page.tsx
@@ -16,120 +16,122 @@ export default function komgaDocsPage() {
intro="Comic and manga media server with web reader"
>
- Category: Media
- Difficulty: Easy
- Docker image: gotson/komga:latest
-
+ Category: Media
+ Difficulty: Easy
+ Docker image: gotson/komga:latest
+
- What is Komga?
- Comic and manga media server with web reader
- Komga ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Komga, not installing it.
+What is Komga?
+Comic and manga media server with web reader
+Komga ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Komga, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - A host path to mount as the media library (default:
/media/comics).
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - A host path containing your media. Default suggestion:
/media/comics. The deploy form / API payload config.mediaPath must be readable by the container UID (usually 1000).
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Komga from the Media category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
gotson/komga:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
komga.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Komga from the Media category.
+ - Fill in the deployment form: subdomain (default suggestion:
komga), host port (default: 25600), and the media library path.
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "komga",
- "host": "local",
- "subdomain": "komga",
- "port": "{{PORT}}",
- "environment": {
- "TZ": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "komga",
+ "config": {
+ "subdomain": "komga",
+ "port": 25600,
+ "mediaPath": "/media/comics"
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Komga on my home host and expose it at komga.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Komga on my home host and expose it at komga.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Create admin account on first access
- - Add your comic libraries (CBZ, CBR, PDF supported)
- - Use OPDS for third-party reader apps
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull gotson/komga:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
- Media library path notes
- The media mount path you set at deploy time is what Komga will see as /data. For multi-library setups (movies + TV + music), bind the parent folder and let Komga discover subfolders automatically.
-
- - Permissions: Komga runs as a non-root user. Make sure your media files are readable by UID
1000 (or whichever the container expects — check the Logs tab on first run).
- - Performance: Put the media library on the same storage pool as DashCaddy itself; cross-pool mounts add 10–30% latency on first scan.
-
+Post-install: first-run checklist
+
+ - Create admin account on first access
+ - Add your comic libraries (CBZ, CBR, PDF supported)
+ - Use OPDS for third-party reader apps
+
+Media library path notes
+The media mount path you pass as mediaPath in the deploy payload is mounted as /data inside the container. Bind a host directory containing your media library (movies, TV shows, music, etc.).
+
+ - UID/GID: Komga runs as a non-root user. If you see permission errors in the dashboard Logs tab, run
chown -R 1000:1000 /media/comics on the host.
+ - Multi-library: bind the parent folder and let Komga discover subfolders.
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/komga/config:/config
+MEDIA_PATH:/data
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ TZ
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/komga/config:/config
- MEDIA_PATH:/data
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull gotson/komga:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- TZ
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull gotson/komga:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Komga → Update.
-
- Backups
- The config volume for Komga is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Komga:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
- - Library shows empty: confirm the media mount path is readable by the container UID and that the directory contains the file extensions Komga indexes.
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Komga is in the Media category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: komga. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Komga:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - Library shows empty: confirm
mediaPath is readable by the container UID and that the directory contains the file extensions Komga indexes.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: komga. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/lidarr/page.tsx b/src/app/docs/catalog/lidarr/page.tsx
index 557726f..6040dcb 100644
--- a/src/app/docs/catalog/lidarr/page.tsx
+++ b/src/app/docs/catalog/lidarr/page.tsx
@@ -16,121 +16,117 @@ export default function lidarrDocsPage() {
intro="Music collection manager for Usenet and BitTorrent"
>
- Category: Media Management
- Difficulty: Intermediate
- Docker image: linuxserver/lidarr:latest
-
+ Category: Media Management
+ Difficulty: Intermediate
+ Docker image: linuxserver/lidarr:latest
+
- What is Lidarr?
- Music collection manager for Usenet and BitTorrent
- Lidarr ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Lidarr, not installing it.
+What is Lidarr?
+Music collection manager for Usenet and BitTorrent
+Lidarr ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Lidarr, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Lidarr from the Media Management category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
linuxserver/lidarr:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
lidarr.<your-domain>.
- - Wait for the container health check (
/api/v1/system/status) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Lidarr from the Media Management category.
+ - Fill in the deployment form: subdomain (default suggestion:
lidarr), host port (default: 8686).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/api/v1/system/status) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "lidarr",
- "host": "local",
- "subdomain": "lidarr",
- "port": "{{PORT}}",
- "environment": {
- "PUID": "",
- "PGID": "",
- "TZ": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "lidarr",
+ "config": {
+ "subdomain": "lidarr",
+ "port": 8686
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Lidarr on my home host and expose it at lidarr.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Lidarr on my home host and expose it at lidarr.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Configure download clients
- - Add indexers
- - Set up root folders for music
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull linuxserver/lidarr:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Configure download clients
+ - Add indexers
+ - Set up root folders for music
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/lidarr/config:/config
+/downloads:/downloads
+/music:/music
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ PUID
+ PGID
+ TZ
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/lidarr/config:/config
- /downloads:/downloads
- /music:/music
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull linuxserver/lidarr:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- PUID
- PGID
- TZ
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull linuxserver/lidarr:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Lidarr → Update.
-
- Backups
- The config volume for Lidarr is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Lidarr:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Lidarr is in the Media Management category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: lidarr. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Lidarr:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/api/v1/system/status is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: lidarr. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/mailserver/page.tsx b/src/app/docs/catalog/mailserver/page.tsx
index 93c3b05..689b985 100644
--- a/src/app/docs/catalog/mailserver/page.tsx
+++ b/src/app/docs/catalog/mailserver/page.tsx
@@ -16,124 +16,120 @@ export default function mailserverDocsPage() {
intro="Full-featured email server with SMTP, IMAP, spam filtering"
>
- Category: Communication
- Difficulty: Advanced
- Docker image: mailserver/docker-mailserver:latest
-
+ Category: Communication
+ Difficulty: Advanced
+ Docker image: mailserver/docker-mailserver:latest
+
- What is Docker Mailserver?
- Full-featured email server with SMTP, IMAP, spam filtering
- Docker Mailserver ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Docker Mailserver, not installing it.
+What is Docker Mailserver?
+Full-featured email server with SMTP, IMAP, spam filtering
+Docker Mailserver ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Docker Mailserver, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Docker Mailserver from the Communication category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
mailserver/docker-mailserver:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
mail.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Docker Mailserver from the Communication category.
+ - Fill in the deployment form: subdomain (default suggestion:
mail), host port (default: 25).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "mailserver",
- "host": "local",
- "subdomain": "mail",
- "port": "{{PORT}}",
- "environment": {
- "ENABLE_SPAMASSASSIN": "",
- "ENABLE_CLAMAV": "",
- "ENABLE_FAIL2BAN": "",
- "ONE_DIR": "",
- "TZ": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "mailserver",
+ "config": {
+ "subdomain": "mail",
+ "port": 25
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Docker Mailserver on my home host and expose it at mail.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Docker Mailserver on my home host and expose it at mail.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Configure DNS records (MX, SPF, DKIM, DMARC)
- - Create email accounts using setup.sh
- - Set up SSL certificates for secure connections
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull mailserver/docker-mailserver:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Configure DNS records (MX, SPF, DKIM, DMARC)
+ - Create email accounts using setup.sh
+ - Set up SSL certificates for secure connections
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/mailserver/data:/var/mail
+/opt/mailserver/state:/var/mail-state
+/opt/mailserver/logs:/var/log/mail
+/opt/mailserver/config:/tmp/docker-mailserver
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ ENABLE_SPAMASSASSIN
+ ENABLE_CLAMAV
+ ENABLE_FAIL2BAN
+ ONE_DIR
+ TZ
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/mailserver/data:/var/mail
- /opt/mailserver/state:/var/mail-state
- /opt/mailserver/logs:/var/log/mail
- /opt/mailserver/config:/tmp/docker-mailserver
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull mailserver/docker-mailserver:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- ENABLE_SPAMASSASSIN
- ENABLE_CLAMAV
- ENABLE_FAIL2BAN
- ONE_DIR
- TZ
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull mailserver/docker-mailserver:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Docker Mailserver → Update.
-
- Backups
- The config volume for Docker Mailserver is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Docker Mailserver:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Docker Mailserver is in the Communication category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: mailserver. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Docker Mailserver:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: mailserver. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/matrix/page.tsx b/src/app/docs/catalog/matrix/page.tsx
index ee7bd42..4919bec 100644
--- a/src/app/docs/catalog/matrix/page.tsx
+++ b/src/app/docs/catalog/matrix/page.tsx
@@ -16,115 +16,114 @@ export default function matrixDocsPage() {
intro="Decentralized, secure messaging and collaboration"
>
- Category: Communication
- Difficulty: Advanced
- Docker image: matrixdotorg/synapse:latest
-
+ Category: Communication
+ Difficulty: Advanced
+ Docker image: matrixdotorg/synapse:latest
+
- What is Matrix Synapse?
- Decentralized, secure messaging and collaboration
- Matrix Synapse ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Matrix Synapse, not installing it.
+What is Matrix Synapse?
+Decentralized, secure messaging and collaboration
+Matrix Synapse ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Matrix Synapse, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Matrix Synapse from the Communication category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
matrixdotorg/synapse:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
matrix.<your-domain>.
- - Wait for the container health check (
/_matrix/client/versions) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Matrix Synapse from the Communication category.
+ - Fill in the deployment form: subdomain (default suggestion:
matrix), host port (default: 8008).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/_matrix/client/versions) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "matrix",
- "host": "local",
- "subdomain": "matrix",
- "port": "{{PORT}}",
- "environment": {
- "SYNAPSE_SERVER_NAME": "",
- "SYNAPSE_REPORT_STATS": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "matrix",
+ "config": {
+ "subdomain": "matrix",
+ "port": 8008
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Matrix Synapse on my home host and expose it at matrix.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Matrix Synapse on my home host and expose it at matrix.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Generate initial config with --generate
- - Configure homeserver.yaml
- - Set up federation if needed
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull matrixdotorg/synapse:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Generate initial config with --generate
+ - Configure homeserver.yaml
+ - Set up federation if needed
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/matrix/data:/data
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ SYNAPSE_SERVER_NAME
+ SYNAPSE_REPORT_STATS
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/matrix/data:/data
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull matrixdotorg/synapse:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- SYNAPSE_SERVER_NAME
- SYNAPSE_REPORT_STATS
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull matrixdotorg/synapse:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Matrix Synapse → Update.
-
- Backups
- The config volume for Matrix Synapse is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Matrix Synapse:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Matrix Synapse is in the Communication category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: matrix. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Matrix Synapse:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/_matrix/client/versions is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: matrix. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/mealie/page.tsx b/src/app/docs/catalog/mealie/page.tsx
index 3669f0c..fb13a95 100644
--- a/src/app/docs/catalog/mealie/page.tsx
+++ b/src/app/docs/catalog/mealie/page.tsx
@@ -16,119 +16,116 @@ export default function mealieDocsPage() {
intro="Recipe manager and meal planner with grocery lists"
>
- Category: Productivity
- Difficulty: Easy
- Docker image: ghcr.io/mealie-recipes/mealie:latest
-
+ Category: Productivity
+ Difficulty: Easy
+ Docker image: ghcr.io/mealie-recipes/mealie:latest
+
- What is Mealie?
- Recipe manager and meal planner with grocery lists
- Mealie ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Mealie, not installing it.
+What is Mealie?
+Recipe manager and meal planner with grocery lists
+Mealie ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Mealie, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Mealie from the Productivity category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
ghcr.io/mealie-recipes/mealie:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
mealie.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Mealie from the Productivity category.
+ - Fill in the deployment form: subdomain (default suggestion:
mealie), host port (default: 9925).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "mealie",
- "host": "local",
- "subdomain": "mealie",
- "port": "{{PORT}}",
- "environment": {
- "ALLOW_SIGNUP": "",
- "MAX_WORKERS": "",
- "WEB_CONCURRENCY": "",
- "BASE_URL": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "mealie",
+ "config": {
+ "subdomain": "mealie",
+ "port": 9925
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Mealie on my home host and expose it at mealie.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Mealie on my home host and expose it at mealie.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Default login: changeme@example.com / MyPassword
- - Import recipes from URLs or add them manually
- - Create meal plans and generate shopping lists
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull ghcr.io/mealie-recipes/mealie:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Default login: changeme@example.com / MyPassword
+ - Import recipes from URLs or add them manually
+ - Create meal plans and generate shopping lists
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/mealie/data:/app/data
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ ALLOW_SIGNUP
+ MAX_WORKERS
+ WEB_CONCURRENCY
+ BASE_URL
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/mealie/data:/app/data
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull ghcr.io/mealie-recipes/mealie:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- ALLOW_SIGNUP
- MAX_WORKERS
- WEB_CONCURRENCY
- BASE_URL
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull ghcr.io/mealie-recipes/mealie:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Mealie → Update.
-
- Backups
- The config volume for Mealie is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Mealie:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Mealie is in the Productivity category. Common pairings:
-
- - Nextcloud
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: mealie. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Mealie:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: mealie. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/minecraft/page.tsx b/src/app/docs/catalog/minecraft/page.tsx
index 4634645..0402b1c 100644
--- a/src/app/docs/catalog/minecraft/page.tsx
+++ b/src/app/docs/catalog/minecraft/page.tsx
@@ -16,124 +16,119 @@ export default function minecraftDocsPage() {
intro="Minecraft Java Edition dedicated server"
>
- Category: Gaming
- Difficulty: Easy
- Docker image: itzg/minecraft-server:latest
-
+ Category: Gaming
+ Difficulty: Easy
+ Docker image: itzg/minecraft-server:latest
+
- What is Minecraft Server?
- Minecraft Java Edition dedicated server
- Minecraft Server ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Minecraft Server, not installing it.
+What is Minecraft Server?
+Minecraft Java Edition dedicated server
+Minecraft Server ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Minecraft Server, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Minecraft Server from the Gaming category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
itzg/minecraft-server:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
mc.<your-domain>.
- - Wait for the container health check (
tcp://localhost:25565) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Minecraft Server from the Gaming category.
+ - Fill in the deployment form: subdomain (default suggestion:
mc), host port (default: 25565).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
tcp://localhost:25565) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "minecraft",
- "host": "local",
- "subdomain": "mc",
- "port": "{{PORT}}",
- "environment": {
- "EULA": "",
- "TYPE": "",
- "VERSION": "",
- "MEMORY": "",
- "MAX_PLAYERS": "",
- "MOTD": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "minecraft",
+ "config": {
+ "subdomain": "mc",
+ "port": 25565
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Minecraft Server on my home host and expose it at mc.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Minecraft Server on my home host and expose it at mc.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Server accepts the Minecraft EULA automatically
- - Connect with your Minecraft client to the server IP:port
- - Configure server.properties in the data volume for customization
- - Supports Vanilla, Paper, Forge, Fabric via TYPE environment variable
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull itzg/minecraft-server:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Server accepts the Minecraft EULA automatically
+ - Connect with your Minecraft client to the server IP:port
+ - Configure server.properties in the data volume for customization
+ - Supports Vanilla, Paper, Forge, Fabric via TYPE environment variable
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/minecraft/data:/data
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ EULA
+ TYPE
+ VERSION
+ MEMORY
+ MAX_PLAYERS
+ MOTD
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/minecraft/data:/data
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull itzg/minecraft-server:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- EULA
- TYPE
- VERSION
- MEMORY
- MAX_PLAYERS
- MOTD
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull itzg/minecraft-server:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Minecraft Server → Update.
-
- Backups
- The config volume for Minecraft Server is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Minecraft Server:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Minecraft Server is in the Gaming category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: minecraft. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Minecraft Server:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
tcp://localhost:25565 is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: minecraft. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/mongodb/page.tsx b/src/app/docs/catalog/mongodb/page.tsx
index 3fda59c..dbb10d6 100644
--- a/src/app/docs/catalog/mongodb/page.tsx
+++ b/src/app/docs/catalog/mongodb/page.tsx
@@ -16,115 +16,114 @@ export default function mongodbDocsPage() {
intro="Document-oriented NoSQL database"
>
- Category: Database
- Difficulty: Intermediate
- Docker image: mongo:latest
-
+ Category: Database
+ Difficulty: Intermediate
+ Docker image: mongo:latest
+
- What is MongoDB?
- Document-oriented NoSQL database
- MongoDB ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using MongoDB, not installing it.
+What is MongoDB?
+Document-oriented NoSQL database
+MongoDB ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using MongoDB, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select MongoDB from the Database category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
mongo:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
mongo.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick MongoDB from the Database category.
+ - Fill in the deployment form: subdomain (default suggestion:
mongo), host port (default: 27017).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "mongodb",
- "host": "local",
- "subdomain": "mongo",
- "port": "{{PORT}}",
- "environment": {
- "MONGO_INITDB_ROOT_USERNAME": "",
- "MONGO_INITDB_ROOT_PASSWORD": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "mongodb",
+ "config": {
+ "subdomain": "mongo",
+ "port": 27017
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy MongoDB on my home host and expose it at mongo.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy MongoDB on my home host and expose it at mongo.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Change default admin password
- - Create application databases and users
- - Configure replica set if needed
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull mongo:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Change default admin password
+ - Create application databases and users
+ - Configure replica set if needed
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/mongodb/data:/data/db
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ MONGO_INITDB_ROOT_USERNAME
+ MONGO_INITDB_ROOT_PASSWORD
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/mongodb/data:/data/db
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull mongo:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- MONGO_INITDB_ROOT_USERNAME
- MONGO_INITDB_ROOT_PASSWORD
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull mongo:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → MongoDB → Update.
-
- Backups
- The config volume for MongoDB is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with MongoDB:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- MongoDB is in the Database category. Common pairings:
-
- - Adminer
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: mongodb. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with MongoDB:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: mongodb. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/navidrome/page.tsx b/src/app/docs/catalog/navidrome/page.tsx
index 82ec940..67fc2d6 100644
--- a/src/app/docs/catalog/navidrome/page.tsx
+++ b/src/app/docs/catalog/navidrome/page.tsx
@@ -16,116 +16,115 @@ export default function navidromeDocsPage() {
intro="Modern music server and streamer"
>
- Category: Media
- Difficulty: Easy
- Docker image: deluan/navidrome:latest
-
+ Category: Media
+ Difficulty: Easy
+ Docker image: deluan/navidrome:latest
+
- What is Navidrome?
- Modern music server and streamer
- Navidrome ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Navidrome, not installing it.
+What is Navidrome?
+Modern music server and streamer
+Navidrome ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Navidrome, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Navidrome from the Media category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
deluan/navidrome:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
music.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Navidrome from the Media category.
+ - Fill in the deployment form: subdomain (default suggestion:
music), host port (default: 4533).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "navidrome",
- "host": "local",
- "subdomain": "music",
- "port": "{{PORT}}",
- "environment": {
- "ND_SCANSCHEDULE": "",
- "ND_LOGLEVEL": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "navidrome",
+ "config": {
+ "subdomain": "music",
+ "port": 4533
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Navidrome on my home host and expose it at music.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Navidrome on my home host and expose it at music.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Point to your music library
- - Create user accounts
- - Install Subsonic-compatible apps
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull deluan/navidrome:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Point to your music library
+ - Create user accounts
+ - Install Subsonic-compatible apps
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/navidrome/data:/data
+/music:/music:ro
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ ND_SCANSCHEDULE
+ ND_LOGLEVEL
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/navidrome/data:/data
- /music:/music:ro
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull deluan/navidrome:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- ND_SCANSCHEDULE
- ND_LOGLEVEL
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull deluan/navidrome:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Navidrome → Update.
-
- Backups
- The config volume for Navidrome is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Navidrome:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Navidrome is in the Media category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: navidrome. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Navidrome:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: navidrome. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/nextcloud/page.tsx b/src/app/docs/catalog/nextcloud/page.tsx
index 244ad1e..b6ee8b6 100644
--- a/src/app/docs/catalog/nextcloud/page.tsx
+++ b/src/app/docs/catalog/nextcloud/page.tsx
@@ -16,119 +16,116 @@ export default function nextcloudDocsPage() {
intro="Self-hosted productivity platform and file sync"
>
- Category: Productivity
- Difficulty: Intermediate
- Docker image: nextcloud:latest
-
+ Category: Productivity
+ Difficulty: Intermediate
+ Docker image: nextcloud:latest
+
- What is Nextcloud?
- Self-hosted productivity platform and file sync
- Nextcloud ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Nextcloud, not installing it.
+What is Nextcloud?
+Self-hosted productivity platform and file sync
+Nextcloud ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Nextcloud, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Nextcloud from the Productivity category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
nextcloud:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
cloud.<your-domain>.
- - Wait for the container health check (
/status.php) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Nextcloud from the Productivity category.
+ - Fill in the deployment form: subdomain (default suggestion:
cloud), host port (default: 8080).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/status.php) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "nextcloud",
- "host": "local",
- "subdomain": "cloud",
- "port": "{{PORT}}",
- "environment": {
- "NEXTCLOUD_ADMIN_USER": "",
- "NEXTCLOUD_ADMIN_PASSWORD": "",
- "NEXTCLOUD_TRUSTED_DOMAINS": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "nextcloud",
+ "config": {
+ "subdomain": "cloud",
+ "port": 8080
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Nextcloud on my home host and expose it at cloud.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Nextcloud on my home host and expose it at cloud.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Change the default admin password
- - Configure trusted domains
- - Install recommended apps
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull nextcloud:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Change the default admin password
+ - Configure trusted domains
+ - Install recommended apps
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/nextcloud/html:/var/www/html
+/opt/nextcloud/data:/var/www/html/data
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ NEXTCLOUD_ADMIN_USER
+ NEXTCLOUD_ADMIN_PASSWORD
+ NEXTCLOUD_TRUSTED_DOMAINS
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/nextcloud/html:/var/www/html
- /opt/nextcloud/data:/var/www/html/data
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull nextcloud:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- NEXTCLOUD_ADMIN_USER
- NEXTCLOUD_ADMIN_PASSWORD
- NEXTCLOUD_TRUSTED_DOMAINS
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull nextcloud:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Nextcloud → Update.
-
- Backups
- The config volume for Nextcloud is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Nextcloud:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Nextcloud is in the Productivity category. Common pairings:
-
- - Adminer (DB admin)
- - PostgreSQL (external DB)
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: nextcloud. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Nextcloud:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/status.php is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: nextcloud. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/nodered/page.tsx b/src/app/docs/catalog/nodered/page.tsx
index 4dcf869..4dcf6ce 100644
--- a/src/app/docs/catalog/nodered/page.tsx
+++ b/src/app/docs/catalog/nodered/page.tsx
@@ -16,113 +16,113 @@ export default function noderedDocsPage() {
intro="Flow-based programming for IoT and automation"
>
- Category: Home Automation
- Difficulty: Intermediate
- Docker image: nodered/node-red:latest
-
+ Category: Home Automation
+ Difficulty: Intermediate
+ Docker image: nodered/node-red:latest
+
- What is Node-RED?
- Flow-based programming for IoT and automation
- Node-RED ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Node-RED, not installing it.
+What is Node-RED?
+Flow-based programming for IoT and automation
+Node-RED ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Node-RED, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Node-RED from the Home Automation category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
nodered/node-red:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
nodered.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Node-RED from the Home Automation category.
+ - Fill in the deployment form: subdomain (default suggestion:
nodered), host port (default: 1880).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "nodered",
- "host": "local",
- "subdomain": "nodered",
- "port": "{{PORT}}",
- "environment": {
- "TZ": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "nodered",
+ "config": {
+ "subdomain": "nodered",
+ "port": 1880
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Node-RED on my home host and expose it at nodered.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Node-RED on my home host and expose it at nodered.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Install additional nodes from palette
- - Create flows for automation
- - Connect to Home Assistant or MQTT
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull nodered/node-red:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Install additional nodes from palette
+ - Create flows for automation
+ - Connect to Home Assistant or MQTT
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/nodered/data:/data
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ TZ
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/nodered/data:/data
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull nodered/node-red:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- TZ
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull nodered/node-red:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Node-RED → Update.
-
- Backups
- The config volume for Node-RED is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Node-RED:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Node-RED is in the Home Automation category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: nodered. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Node-RED:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: nodered. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/nzbget/page.tsx b/src/app/docs/catalog/nzbget/page.tsx
index e222237..0a657ab 100644
--- a/src/app/docs/catalog/nzbget/page.tsx
+++ b/src/app/docs/catalog/nzbget/page.tsx
@@ -16,119 +16,116 @@ export default function nzbgetDocsPage() {
intro="Efficient Usenet downloader"
>
- Category: Downloads
- Difficulty: Intermediate
- Docker image: linuxserver/nzbget:latest
-
+ Category: Downloads
+ Difficulty: Intermediate
+ Docker image: linuxserver/nzbget:latest
+
- What is NZBGet?
- Efficient Usenet downloader
- NZBGet ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using NZBGet, not installing it.
+What is NZBGet?
+Efficient Usenet downloader
+NZBGet ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using NZBGet, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select NZBGet from the Downloads category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
linuxserver/nzbget:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
nzbget.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick NZBGet from the Downloads category.
+ - Fill in the deployment form: subdomain (default suggestion:
nzbget), host port (default: 6789).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "nzbget",
- "host": "local",
- "subdomain": "nzbget",
- "port": "{{PORT}}",
- "environment": {
- "PUID": "",
- "PGID": "",
- "TZ": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "nzbget",
+ "config": {
+ "subdomain": "nzbget",
+ "port": 6789
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy NZBGet on my home host and expose it at nzbget.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy NZBGet on my home host and expose it at nzbget.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Default login: nzbget/tegbzn6789
- - Configure news servers
- - Set up categories and paths
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull linuxserver/nzbget:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Default login: nzbget/tegbzn6789
+ - Configure news servers
+ - Set up categories and paths
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/nzbget/config:/config
+/downloads:/downloads
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ PUID
+ PGID
+ TZ
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/nzbget/config:/config
- /downloads:/downloads
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull linuxserver/nzbget:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- PUID
- PGID
- TZ
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull linuxserver/nzbget:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → NZBGet → Update.
-
- Backups
- The config volume for NZBGet is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with NZBGet:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- NZBGet is in the Downloads category. Common pairings:
-
- - qBittorrent
- - SABnzbd
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: nzbget. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with NZBGet:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: nzbget. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/outline/page.tsx b/src/app/docs/catalog/outline/page.tsx
index bbd64c3..36f57d5 100644
--- a/src/app/docs/catalog/outline/page.tsx
+++ b/src/app/docs/catalog/outline/page.tsx
@@ -16,117 +16,115 @@ export default function outlineDocsPage() {
intro="Modern team knowledge base and wiki"
>
- Category: Productivity
- Difficulty: Advanced
- Docker image: outlinewiki/outline:latest
-
+ Category: Productivity
+ Difficulty: Advanced
+ Docker image: outlinewiki/outline:latest
+
- What is Outline?
- Modern team knowledge base and wiki
- Outline ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Outline, not installing it.
+What is Outline?
+Modern team knowledge base and wiki
+Outline ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Outline, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Outline from the Productivity category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
outlinewiki/outline:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
outline.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Outline from the Productivity category.
+ - Fill in the deployment form: subdomain (default suggestion:
outline), host port (default: 3006).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "outline",
- "host": "local",
- "subdomain": "outline",
- "port": "{{PORT}}",
- "environment": {
- "URL": "",
- "SECRET_KEY": "",
- "DATABASE_URL": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "outline",
+ "config": {
+ "subdomain": "outline",
+ "port": 3006
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Outline on my home host and expose it at outline.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Outline on my home host and expose it at outline.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Requires PostgreSQL and Redis
- - Configure OAuth provider
- - Set up S3-compatible storage
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull outlinewiki/outline:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Requires PostgreSQL and Redis
+ - Configure OAuth provider
+ - Set up S3-compatible storage
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/outline/data:/var/lib/outline/data
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ URL
+ SECRET_KEY
+ DATABASE_URL
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/outline/data:/var/lib/outline/data
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull outlinewiki/outline:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- URL
- SECRET_KEY
- DATABASE_URL
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull outlinewiki/outline:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Outline → Update.
-
- Backups
- The config volume for Outline is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Outline:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Outline is in the Productivity category. Common pairings:
-
- - Nextcloud
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: outline. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Outline:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: outline. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/page.tsx b/src/app/docs/catalog/page.tsx
index 65d3869..644c5d5 100644
--- a/src/app/docs/catalog/page.tsx
+++ b/src/app/docs/catalog/page.tsx
@@ -13,11 +13,11 @@ export default function DocsCatalogPage() {
- 77 apps across 17 categories. New templates are added whenever the upstream Docker image gains traction. The canonical source is dashcaddy-api/src/docker/app-templates.js.
+ 77 apps across 17 categories. The canonical source is dashcaddy-api/src/docker/app-templates.js; regenerate these pages with scripts/regenerate-catalog-docs.sh after editing.
@@ -630,7 +630,7 @@ export default function DocsCatalogPage() {
Adding your own template
- DashCaddy accepts custom templates via the same REST API used to deploy the built-in ones. Submit a template JSON via POST /api/v1/apps/templates with the schema documented in the API guide, or fork dashcaddy-api/src/docker/app-templates.js and add your template to the catalog for everyone.
+ Add an entry to APP_TEMPLATES in dashcaddy-api/src/docker/app-templates.js with the required fields (name, description, category, docker.image, ports, volumes), then re-run scripts/regenerate-catalog-docs.sh. The template will appear in the dashboard App Selector automatically.
diff --git a/src/app/docs/catalog/paperless-ngx/page.tsx b/src/app/docs/catalog/paperless-ngx/page.tsx
index a7451f8..7b08924 100644
--- a/src/app/docs/catalog/paperless-ngx/page.tsx
+++ b/src/app/docs/catalog/paperless-ngx/page.tsx
@@ -16,125 +16,120 @@ export default function paperlessNgxDocsPage() {
intro="Document management system - scan, organize, and search documents"
>
- Category: Productivity
- Difficulty: Intermediate
- Docker image: ghcr.io/paperless-ngx/paperless-ngx:latest
-
+ Category: Productivity
+ Difficulty: Intermediate
+ Docker image: ghcr.io/paperless-ngx/paperless-ngx:latest
+
- What is Paperless-ngx?
- Document management system - scan, organize, and search documents
- Paperless-ngx ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Paperless-ngx, not installing it.
+What is Paperless-ngx?
+Document management system - scan, organize, and search documents
+Paperless-ngx ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Paperless-ngx, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Paperless-ngx from the Productivity category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
ghcr.io/paperless-ngx/paperless-ngx:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
paperless.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Paperless-ngx from the Productivity category.
+ - Fill in the deployment form: subdomain (default suggestion:
paperless), host port (default: 8095).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "paperless-ngx",
- "host": "local",
- "subdomain": "paperless",
- "port": "{{PORT}}",
- "environment": {
- "PAPERLESS_URL": "",
- "USERMAP_UID": "",
- "USERMAP_GID": "",
- "PAPERLESS_TIME_ZONE": "",
- "PAPERLESS_OCR_LANGUAGE": "",
- "PAPERLESS_SECRET_KEY": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "paperless-ngx",
+ "config": {
+ "subdomain": "paperless",
+ "port": 8095
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Paperless-ngx on my home host and expose it at paperless.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Paperless-ngx on my home host and expose it at paperless.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Create admin account via: docker exec -it <container> python3 manage.py createsuperuser
- - Drop documents into the consume folder for automatic import
- - Configure tags and correspondents for organization
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull ghcr.io/paperless-ngx/paperless-ngx:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Create admin account via: docker exec -it <container> python3 manage.py createsuperuser
+ - Drop documents into the consume folder for automatic import
+ - Configure tags and correspondents for organization
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/paperless/data:/usr/src/paperless/data
+/opt/paperless/media:/usr/src/paperless/media
+/opt/paperless/consume:/usr/src/paperless/consume
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ PAPERLESS_URL
+ USERMAP_UID
+ USERMAP_GID
+ PAPERLESS_TIME_ZONE
+ PAPERLESS_OCR_LANGUAGE
+ PAPERLESS_SECRET_KEY
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/paperless/data:/usr/src/paperless/data
- /opt/paperless/media:/usr/src/paperless/media
- /opt/paperless/consume:/usr/src/paperless/consume
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull ghcr.io/paperless-ngx/paperless-ngx:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- PAPERLESS_URL
- USERMAP_UID
- USERMAP_GID
- PAPERLESS_TIME_ZONE
- PAPERLESS_OCR_LANGUAGE
- PAPERLESS_SECRET_KEY
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull ghcr.io/paperless-ngx/paperless-ngx:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Paperless-ngx → Update.
-
- Backups
- The config volume for Paperless-ngx is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Paperless-ngx:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Paperless-ngx is in the Productivity category. Common pairings:
-
- - Nextcloud
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: paperless-ngx. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Paperless-ngx:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: paperless-ngx. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/photoprism/page.tsx b/src/app/docs/catalog/photoprism/page.tsx
index 4b4abc6..bca5a93 100644
--- a/src/app/docs/catalog/photoprism/page.tsx
+++ b/src/app/docs/catalog/photoprism/page.tsx
@@ -16,118 +16,116 @@ export default function photoprismDocsPage() {
intro="AI-powered photo management"
>
- Category: Photos
- Difficulty: Intermediate
- Docker image: photoprism/photoprism:latest
-
+ Category: Photos
+ Difficulty: Intermediate
+ Docker image: photoprism/photoprism:latest
+
- What is PhotoPrism?
- AI-powered photo management
- PhotoPrism ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using PhotoPrism, not installing it.
+What is PhotoPrism?
+AI-powered photo management
+PhotoPrism ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using PhotoPrism, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select PhotoPrism from the Photos category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
photoprism/photoprism:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
gallery.<your-domain>.
- - Wait for the container health check (
/api/v1/status) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick PhotoPrism from the Photos category.
+ - Fill in the deployment form: subdomain (default suggestion:
gallery), host port (default: 2342).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/api/v1/status) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "photoprism",
- "host": "local",
- "subdomain": "gallery",
- "port": "{{PORT}}",
- "environment": {
- "PHOTOPRISM_ADMIN_PASSWORD": "",
- "PHOTOPRISM_SITE_URL": "",
- "PHOTOPRISM_DATABASE_DRIVER": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "photoprism",
+ "config": {
+ "subdomain": "gallery",
+ "port": 2342
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy PhotoPrism on my home host and expose it at gallery.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy PhotoPrism on my home host and expose it at gallery.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Change admin password
- - Import your photos
- - Run indexing for AI features
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull photoprism/photoprism:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Change admin password
+ - Import your photos
+ - Run indexing for AI features
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/photoprism/storage:/photoprism/storage
+/opt/photoprism/originals:/photoprism/originals
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ PHOTOPRISM_ADMIN_PASSWORD
+ PHOTOPRISM_SITE_URL
+ PHOTOPRISM_DATABASE_DRIVER
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/photoprism/storage:/photoprism/storage
- /opt/photoprism/originals:/photoprism/originals
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull photoprism/photoprism:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- PHOTOPRISM_ADMIN_PASSWORD
- PHOTOPRISM_SITE_URL
- PHOTOPRISM_DATABASE_DRIVER
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull photoprism/photoprism:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → PhotoPrism → Update.
-
- Backups
- The config volume for PhotoPrism is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with PhotoPrism:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- PhotoPrism is in the Photos category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: photoprism. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with PhotoPrism:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/api/v1/status is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: photoprism. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/pihole/page.tsx b/src/app/docs/catalog/pihole/page.tsx
index a37d658..0a4ca01 100644
--- a/src/app/docs/catalog/pihole/page.tsx
+++ b/src/app/docs/catalog/pihole/page.tsx
@@ -16,117 +16,115 @@ export default function piholeDocsPage() {
intro="Network-wide ad blocker and DNS sinkhole"
>
- Category: Networking
- Difficulty: Intermediate
- Docker image: pihole/pihole:latest
-
+ Category: Networking
+ Difficulty: Intermediate
+ Docker image: pihole/pihole:latest
+
- What is Pi-hole?
- Network-wide ad blocker and DNS sinkhole
- Pi-hole ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Pi-hole, not installing it.
+What is Pi-hole?
+Network-wide ad blocker and DNS sinkhole
+Pi-hole ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Pi-hole, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Pi-hole from the Networking category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
pihole/pihole:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
pihole.<your-domain>.
- - Wait for the container health check (
/admin/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Pi-hole from the Networking category.
+ - Fill in the deployment form: subdomain (default suggestion:
pihole), host port (default: 80).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/admin/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "pihole",
- "host": "local",
- "subdomain": "pihole",
- "port": "{{PORT}}",
- "environment": {
- "WEBPASSWORD": "",
- "TZ": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "pihole",
+ "config": {
+ "subdomain": "pihole",
+ "port": 80
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Pi-hole on my home host and expose it at pihole.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Pi-hole on my home host and expose it at pihole.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Open the new
pihole.<your-domain> URL.
- - Complete the upstream Pi-hole setup wizard (create admin user, accept EULA, etc.).
- - Configure backups from Settings → Backups — the default daily snapshot will capture the data volume.
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull pihole/pihole:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Open the deployed URL (returned in the response as
url, or visible in the dashboard).
+ - Complete the upstream Pi-hole setup wizard (admin account, library paths, EULA).
+ - Restore from a backup if one exists:
POST /api/v1/apps/{appId}/restore with the backup ID from GET /api/v1/backups/history.
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/pihole/etc:/etc/pihole
+/opt/pihole/dnsmasq:/etc/dnsmasq.d
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ WEBPASSWORD
+ TZ
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/pihole/etc:/etc/pihole
- /opt/pihole/dnsmasq:/etc/dnsmasq.d
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull pihole/pihole:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- WEBPASSWORD
- TZ
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull pihole/pihole:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Pi-hole → Update.
-
- Backups
- The config volume for Pi-hole is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Pi-hole:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Pi-hole is in the Networking category. Common pairings:
-
- - Technitium DNS (more powerful DNS)
- - WireGuard (private DNS over VPN)
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: pihole. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Pi-hole:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/admin/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: pihole. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/plex/page.tsx b/src/app/docs/catalog/plex/page.tsx
index f65f706..b727a3d 100644
--- a/src/app/docs/catalog/plex/page.tsx
+++ b/src/app/docs/catalog/plex/page.tsx
@@ -16,138 +16,137 @@ export default function plexDocsPage() {
intro="Stream your personal media collection anywhere"
>
- Category: Media
- Difficulty: Easy
- Docker image: plexinc/pms-docker:latest
-
+ Category: Media
+ Difficulty: Easy
+ Docker image: plexinc/pms-docker:latest
+
- What is Plex?
- Stream your personal media collection anywhere
- Plex ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Plex, not installing it.
+What is Plex?
+Stream your personal media collection anywhere
+Plex ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Plex, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - A host path to mount as the media library (default:
/media).
- - A Plex Claim Token — get one from https://plex.tv/claim before you start.
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - A host path containing your media. Default suggestion:
/media. The deploy form / API payload config.mediaPath must be readable by the container UID (usually 1000).
+ - A Plex Claim Token — get one from https://plex.tv/claim right before you click Deploy.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Plex from the Media category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
plexinc/pms-docker:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
plex.<your-domain>.
- - Wait for the container health check (
/web/index.html) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Plex from the Media category.
+ - Fill in the deployment form: subdomain (default suggestion:
plex), host port (default: 32400), and the media library path, and the claim token.
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/web/index.html) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "plex",
- "host": "local",
- "subdomain": "plex",
- "port": "{{PORT}}",
- "environment": {
- "PLEX_CLAIM": "",
- "ADVERTISE_IP": "",
- "PLEX_UID": "",
- "PLEX_GID": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "plex",
+ "config": {
+ "subdomain": "plex",
+ "port": 32400,
+ "mediaPath": "/media",
+ "plexClaimToken": "<get fresh token from https://plex.tv/claim>"
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Plex on my home host and expose it at plex.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Plex on my home host and expose it at plex.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Get your claim token from https://plex.tv/claim
- - Add your media libraries in the web interface
- - Configure remote access settings
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull plexinc/pms-docker:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
- Media library path notes
- The media mount path you set at deploy time is what Plex will see as /data. For multi-library setups (movies + TV + music), bind the parent folder and let Plex discover subfolders automatically.
-
- - Permissions: Plex runs as a non-root user. Make sure your media files are readable by UID
1000 (or whichever the container expects — check the Logs tab on first run).
- - Performance: Put the media library on the same storage pool as DashCaddy itself; cross-pool mounts add 10–30% latency on first scan.
-
+Post-install: first-run checklist
+
+ - Get your claim token from https://plex.tv/claim
+ - Add your media libraries in the web interface
+ - Configure remote access settings
+
+Media library path notes
+The media mount path you pass as mediaPath in the deploy payload is mounted as /data inside the container. Bind a host directory containing your media library (movies, TV shows, music, etc.).
+
+ - UID/GID: Plex runs as a non-root user. If you see permission errors in the dashboard Logs tab, run
chown -R 1000:1000 /media on the host.
+ - Multi-library: bind the parent folder and let Plex discover subfolders.
+
+Plex Claim Token
+Get from https://plex.tv/claim - expires in 4 minutes!
+Pass it as plexClaimToken inside the config object of the deploy payload (NOT as an environment variable).
+
+ Heads up: Plex Claim Token expires within minutes. Get a fresh one from
+ https://plex.tv/claim
+ right before you click Deploy.
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/plex/config:/config
+/opt/plex/transcode:/transcode
+MEDIA_PATH:/data
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
- Plex Claim Token
- Get from https://plex.tv/claim - expires in 4 minutes!
-
-
- Heads up: Plex Claim Token expires after a few minutes. Get a fresh one from
- https://plex.tv/claim
- right before you click Deploy.
-
-
+Environment variables
+
+ PLEX_CLAIM
+ ADVERTISE_IP
+ PLEX_UID
+ PLEX_GID
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/plex/config:/config
- /opt/plex/transcode:/transcode
- MEDIA_PATH:/data
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull plexinc/pms-docker:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- PLEX_CLAIM
- ADVERTISE_IP
- PLEX_UID
- PLEX_GID
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull plexinc/pms-docker:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Plex → Update.
-
- Backups
- The config volume for Plex is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Plex:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
- - Library shows empty: confirm the media mount path is readable by the container UID and that the directory contains the file extensions Plex indexes.
- - Account linking fails: your claim token probably expired. Get a new one and re-deploy.
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Plex is in the Media category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: plex. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Plex:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - Library shows empty: confirm
mediaPath is readable by the container UID and that the directory contains the file extensions Plex indexes.
+ - Account linking fails: your claim token probably expired. Get a new one and redeploy.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/web/index.html is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: plex. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/portainer/page.tsx b/src/app/docs/catalog/portainer/page.tsx
index fd96908..4135af6 100644
--- a/src/app/docs/catalog/portainer/page.tsx
+++ b/src/app/docs/catalog/portainer/page.tsx
@@ -16,112 +16,112 @@ export default function portainerDocsPage() {
intro="Docker container management UI"
>
- Category: Management
- Difficulty: Easy
- Docker image: portainer/portainer-ce:latest
-
+ Category: Management
+ Difficulty: Easy
+ Docker image: portainer/portainer-ce:latest
+
- What is Portainer?
- Docker container management UI
- Portainer ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Portainer, not installing it.
+What is Portainer?
+Docker container management UI
+Portainer ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Portainer, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Portainer from the Management category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
portainer/portainer-ce:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
portainer.<your-domain>.
- - Wait for the container health check (
/api/status) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Portainer from the Management category.
+ - Fill in the deployment form: subdomain (default suggestion:
portainer), host port (default: 9000).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/api/status) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "portainer",
- "host": "local",
- "subdomain": "portainer",
- "port": "{{PORT}}",
-
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "portainer",
+ "config": {
+ "subdomain": "portainer",
+ "port": 9000
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Portainer on my home host and expose it at portainer.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Portainer on my home host and expose it at portainer.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Open the new
portainer.<your-domain> URL.
- - Complete the upstream Portainer setup wizard (create admin user, accept EULA, etc.).
- - Configure backups from Settings → Backups — the default daily snapshot will capture the data volume.
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull portainer/portainer-ce:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Open the deployed URL (returned in the response as
url, or visible in the dashboard).
+ - Complete the upstream Portainer setup wizard (admin account, library paths, EULA).
+ - Restore from a backup if one exists:
POST /api/v1/apps/{appId}/restore with the backup ID from GET /api/v1/backups/history.
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/var/run/docker.sock:/var/run/docker.sock
+/opt/portainer/data:/data
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+None. The container runs with its upstream defaults.
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /var/run/docker.sock:/var/run/docker.sock
- /opt/portainer/data:/data
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull portainer/portainer-ce:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- None. The container runs with its upstream defaults.
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull portainer/portainer-ce:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Portainer → Update.
-
- Backups
- The config volume for Portainer is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Portainer:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Portainer is in the Management category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: portainer. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Portainer:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/api/status is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: portainer. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/postgres/page.tsx b/src/app/docs/catalog/postgres/page.tsx
index 48948c5..b6f51d0 100644
--- a/src/app/docs/catalog/postgres/page.tsx
+++ b/src/app/docs/catalog/postgres/page.tsx
@@ -16,117 +16,115 @@ export default function postgresDocsPage() {
intro="Advanced open-source relational database"
>
- Category: Database
- Difficulty: Intermediate
- Docker image: postgres:16-alpine
-
+ Category: Database
+ Difficulty: Intermediate
+ Docker image: postgres:16-alpine
+
- What is PostgreSQL?
- Advanced open-source relational database
- PostgreSQL ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using PostgreSQL, not installing it.
+What is PostgreSQL?
+Advanced open-source relational database
+PostgreSQL ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using PostgreSQL, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select PostgreSQL from the Database category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
postgres:16-alpine image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
postgres.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick PostgreSQL from the Database category.
+ - Fill in the deployment form: subdomain (default suggestion:
postgres), host port (default: 5432).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "postgres",
- "host": "local",
- "subdomain": "postgres",
- "port": "{{PORT}}",
- "environment": {
- "POSTGRES_USER": "",
- "POSTGRES_PASSWORD": "",
- "POSTGRES_DB": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "postgres",
+ "config": {
+ "subdomain": "postgres",
+ "port": 5432
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy PostgreSQL on my home host and expose it at postgres.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy PostgreSQL on my home host and expose it at postgres.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Change default password immediately
- - Create databases and users as needed
- - Configure pg_hba.conf for remote access
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull postgres:16-alpine and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Change default password immediately
+ - Create databases and users as needed
+ - Configure pg_hba.conf for remote access
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/postgres/data:/var/lib/postgresql/data
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ POSTGRES_USER
+ POSTGRES_PASSWORD
+ POSTGRES_DB
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/postgres/data:/var/lib/postgresql/data
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull postgres:16-alpine.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- POSTGRES_USER
- POSTGRES_PASSWORD
- POSTGRES_DB
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull postgres:16-alpine every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → PostgreSQL → Update.
-
- Backups
- The config volume for PostgreSQL is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with PostgreSQL:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- PostgreSQL is in the Database category. Common pairings:
-
- - Adminer
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: postgres. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with PostgreSQL:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: postgres. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/powerdns/page.tsx b/src/app/docs/catalog/powerdns/page.tsx
index feb586c..e90b1fc 100644
--- a/src/app/docs/catalog/powerdns/page.tsx
+++ b/src/app/docs/catalog/powerdns/page.tsx
@@ -16,125 +16,120 @@ export default function powerdnsDocsPage() {
intro="High-performance DNS server with SQL backend"
>
- Category: DNS
- Difficulty: Intermediate
- Docker image: pschiffe/pdns-mysql:latest
-
+ Category: DNS
+ Difficulty: Intermediate
+ Docker image: pschiffe/pdns-mysql:latest
+
- What is PowerDNS?
- High-performance DNS server with SQL backend
- PowerDNS ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using PowerDNS, not installing it.
+What is PowerDNS?
+High-performance DNS server with SQL backend
+PowerDNS ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using PowerDNS, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select PowerDNS from the DNS category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
pschiffe/pdns-mysql:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
dns3.<your-domain>.
- - Wait for the container health check (
/api/v1/servers) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick PowerDNS from the DNS category.
+ - Fill in the deployment form: subdomain (default suggestion:
dns3), host port (default: 8081).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/api/v1/servers) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "powerdns",
- "host": "local",
- "subdomain": "dns3",
- "port": "{{PORT}}",
- "environment": {
- "PDNS_api": "",
- "PDNS_api_key": "",
- "PDNS_webserver": "",
- "PDNS_webserver_address": "",
- "PDNS_webserver_allow_from": "",
- "MYSQL_ROOT_PASSWORD": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "powerdns",
+ "config": {
+ "subdomain": "dns3",
+ "port": 8081
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy PowerDNS on my home host and expose it at dns3.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy PowerDNS on my home host and expose it at dns3.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Access API at https://dns3.sami:8081
- - Use API key for authentication
- - Create zone via API or PowerDNS Admin
- - Add records for your .sami domain
- - Configure devices to use DNS server
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull pschiffe/pdns-mysql:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Access API at https://dns3.sami:8081
+ - Use API key for authentication
+ - Create zone via API or PowerDNS Admin
+ - Add records for your .sami domain
+ - Configure devices to use DNS server
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/powerdns/data:/var/lib/mysql
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ PDNS_api
+ PDNS_api_key
+ PDNS_webserver
+ PDNS_webserver_address
+ PDNS_webserver_allow_from
+ MYSQL_ROOT_PASSWORD
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/powerdns/data:/var/lib/mysql
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull pschiffe/pdns-mysql:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- PDNS_api
- PDNS_api_key
- PDNS_webserver
- PDNS_webserver_address
- PDNS_webserver_allow_from
- MYSQL_ROOT_PASSWORD
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull pschiffe/pdns-mysql:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → PowerDNS → Update.
-
- Backups
- The config volume for PowerDNS is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with PowerDNS:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- PowerDNS is in the DNS category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: powerdns. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with PowerDNS:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/api/v1/servers is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: powerdns. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/prowlarr/page.tsx b/src/app/docs/catalog/prowlarr/page.tsx
index fe219d4..7de9d94 100644
--- a/src/app/docs/catalog/prowlarr/page.tsx
+++ b/src/app/docs/catalog/prowlarr/page.tsx
@@ -16,119 +16,115 @@ export default function prowlarrDocsPage() {
intro="Indexer manager/proxy for *arr applications"
>
- Category: Media Management
- Difficulty: Advanced
- Docker image: linuxserver/prowlarr:latest
-
+ Category: Media Management
+ Difficulty: Advanced
+ Docker image: linuxserver/prowlarr:latest
+
- What is Prowlarr?
- Indexer manager/proxy for *arr applications
- Prowlarr ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Prowlarr, not installing it.
+What is Prowlarr?
+Indexer manager/proxy for *arr applications
+Prowlarr ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Prowlarr, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Prowlarr from the Media Management category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
linuxserver/prowlarr:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
prowlarr.<your-domain>.
- - Wait for the container health check (
/api/v1/system/status) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Prowlarr from the Media Management category.
+ - Fill in the deployment form: subdomain (default suggestion:
prowlarr), host port (default: 9696).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/api/v1/system/status) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "prowlarr",
- "host": "local",
- "subdomain": "prowlarr",
- "port": "{{PORT}}",
- "environment": {
- "PUID": "",
- "PGID": "",
- "TZ": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "prowlarr",
+ "config": {
+ "subdomain": "prowlarr",
+ "port": 9696
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Prowlarr on my home host and expose it at prowlarr.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Prowlarr on my home host and expose it at prowlarr.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Open the new
prowlarr.<your-domain> URL.
- - Complete the upstream Prowlarr setup wizard (create admin user, accept EULA, etc.).
- - Configure backups from Settings → Backups — the default daily snapshot will capture the data volume.
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull linuxserver/prowlarr:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Open the deployed URL (returned in the response as
url, or visible in the dashboard).
+ - Complete the upstream Prowlarr setup wizard (admin account, library paths, EULA).
+ - Restore from a backup if one exists:
POST /api/v1/apps/{appId}/restore with the backup ID from GET /api/v1/backups/history.
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/prowlarr/config:/config
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ PUID
+ PGID
+ TZ
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/prowlarr/config:/config
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull linuxserver/prowlarr:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- PUID
- PGID
- TZ
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull linuxserver/prowlarr:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Prowlarr → Update.
-
- Backups
- The config volume for Prowlarr is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Prowlarr:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Prowlarr is in the Media Management category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: prowlarr. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Prowlarr:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/api/v1/system/status is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: prowlarr. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/qbittorrent/page.tsx b/src/app/docs/catalog/qbittorrent/page.tsx
index 5db0832..ed8ed50 100644
--- a/src/app/docs/catalog/qbittorrent/page.tsx
+++ b/src/app/docs/catalog/qbittorrent/page.tsx
@@ -16,121 +16,117 @@ export default function qbittorrentDocsPage() {
intro="Lightweight BitTorrent client with web UI"
>
- Category: Downloads
- Difficulty: Easy
- Docker image: linuxserver/qbittorrent:latest
-
+ Category: Downloads
+ Difficulty: Easy
+ Docker image: linuxserver/qbittorrent:latest
+
- What is qBittorrent?
- Lightweight BitTorrent client with web UI
- qBittorrent ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using qBittorrent, not installing it.
+What is qBittorrent?
+Lightweight BitTorrent client with web UI
+qBittorrent ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using qBittorrent, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select qBittorrent from the Downloads category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
linuxserver/qbittorrent:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
torrent.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick qBittorrent from the Downloads category.
+ - Fill in the deployment form: subdomain (default suggestion:
torrent), host port (default: 8080).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "qbittorrent",
- "host": "local",
- "subdomain": "torrent",
- "port": "{{PORT}}",
- "environment": {
- "PUID": "",
- "PGID": "",
- "TZ": "",
- "WEBUI_PORT": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "qbittorrent",
+ "config": {
+ "subdomain": "torrent",
+ "port": 8080
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy qBittorrent on my home host and expose it at torrent.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy qBittorrent on my home host and expose it at torrent.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Default login: admin/adminadmin
- - Change default password immediately
- - Configure download paths
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull linuxserver/qbittorrent:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Default login: admin/adminadmin
+ - Change default password immediately
+ - Configure download paths
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/qbittorrent/config:/config
+/downloads:/downloads
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ PUID
+ PGID
+ TZ
+ WEBUI_PORT
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/qbittorrent/config:/config
- /downloads:/downloads
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull linuxserver/qbittorrent:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- PUID
- PGID
- TZ
- WEBUI_PORT
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull linuxserver/qbittorrent:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → qBittorrent → Update.
-
- Backups
- The config volume for qBittorrent is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with qBittorrent:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- qBittorrent is in the Downloads category. Common pairings:
-
- - qBittorrent
- - SABnzbd
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: qbittorrent. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with qBittorrent:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: qbittorrent. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/radarr/page.tsx b/src/app/docs/catalog/radarr/page.tsx
index 00c0257..a3f05f2 100644
--- a/src/app/docs/catalog/radarr/page.tsx
+++ b/src/app/docs/catalog/radarr/page.tsx
@@ -16,121 +16,117 @@ export default function radarrDocsPage() {
intro="Movie collection manager for Usenet and BitTorrent"
>
- Category: Media Management
- Difficulty: Intermediate
- Docker image: linuxserver/radarr:latest
-
+ Category: Media Management
+ Difficulty: Intermediate
+ Docker image: linuxserver/radarr:latest
+
- What is Radarr?
- Movie collection manager for Usenet and BitTorrent
- Radarr ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Radarr, not installing it.
+What is Radarr?
+Movie collection manager for Usenet and BitTorrent
+Radarr ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Radarr, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Radarr from the Media Management category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
linuxserver/radarr:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
radarr.<your-domain>.
- - Wait for the container health check (
/api/v3/system/status) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Radarr from the Media Management category.
+ - Fill in the deployment form: subdomain (default suggestion:
radarr), host port (default: 7878).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/api/v3/system/status) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "radarr",
- "host": "local",
- "subdomain": "radarr",
- "port": "{{PORT}}",
- "environment": {
- "PUID": "",
- "PGID": "",
- "TZ": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "radarr",
+ "config": {
+ "subdomain": "radarr",
+ "port": 7878
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Radarr on my home host and expose it at radarr.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Radarr on my home host and expose it at radarr.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Open the new
radarr.<your-domain> URL.
- - Complete the upstream Radarr setup wizard (create admin user, accept EULA, etc.).
- - Configure backups from Settings → Backups — the default daily snapshot will capture the data volume.
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull linuxserver/radarr:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Open the deployed URL (returned in the response as
url, or visible in the dashboard).
+ - Complete the upstream Radarr setup wizard (admin account, library paths, EULA).
+ - Restore from a backup if one exists:
POST /api/v1/apps/{appId}/restore with the backup ID from GET /api/v1/backups/history.
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/radarr/config:/config
+/downloads:/downloads
+/movies:/movies
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ PUID
+ PGID
+ TZ
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/radarr/config:/config
- /downloads:/downloads
- /movies:/movies
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull linuxserver/radarr:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- PUID
- PGID
- TZ
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull linuxserver/radarr:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Radarr → Update.
-
- Backups
- The config volume for Radarr is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Radarr:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Radarr is in the Media Management category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: radarr. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Radarr:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/api/v3/system/status is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: radarr. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/readarr/page.tsx b/src/app/docs/catalog/readarr/page.tsx
index 08910d6..2b0e05a 100644
--- a/src/app/docs/catalog/readarr/page.tsx
+++ b/src/app/docs/catalog/readarr/page.tsx
@@ -16,121 +16,117 @@ export default function readarrDocsPage() {
intro="Book and audiobook collection manager"
>
- Category: Media Management
- Difficulty: Intermediate
- Docker image: linuxserver/readarr:develop
-
+ Category: Media Management
+ Difficulty: Intermediate
+ Docker image: linuxserver/readarr:develop
+
- What is Readarr?
- Book and audiobook collection manager
- Readarr ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Readarr, not installing it.
+What is Readarr?
+Book and audiobook collection manager
+Readarr ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Readarr, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Readarr from the Media Management category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
linuxserver/readarr:develop image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
readarr.<your-domain>.
- - Wait for the container health check (
/api/v1/system/status) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Readarr from the Media Management category.
+ - Fill in the deployment form: subdomain (default suggestion:
readarr), host port (default: 8787).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/api/v1/system/status) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "readarr",
- "host": "local",
- "subdomain": "readarr",
- "port": "{{PORT}}",
- "environment": {
- "PUID": "",
- "PGID": "",
- "TZ": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "readarr",
+ "config": {
+ "subdomain": "readarr",
+ "port": 8787
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Readarr on my home host and expose it at readarr.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Readarr on my home host and expose it at readarr.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Configure download clients
- - Add indexers for books
- - Set up root folders
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull linuxserver/readarr:develop and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Configure download clients
+ - Add indexers for books
+ - Set up root folders
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/readarr/config:/config
+/downloads:/downloads
+/books:/books
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ PUID
+ PGID
+ TZ
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/readarr/config:/config
- /downloads:/downloads
- /books:/books
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull linuxserver/readarr:develop.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- PUID
- PGID
- TZ
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull linuxserver/readarr:develop every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Readarr → Update.
-
- Backups
- The config volume for Readarr is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Readarr:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Readarr is in the Media Management category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: readarr. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Readarr:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/api/v1/system/status is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: readarr. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/redis/page.tsx b/src/app/docs/catalog/redis/page.tsx
index 0989ff0..acdefe0 100644
--- a/src/app/docs/catalog/redis/page.tsx
+++ b/src/app/docs/catalog/redis/page.tsx
@@ -16,111 +16,111 @@ export default function redisDocsPage() {
intro="In-memory data structure store and cache"
>
- Category: Database
- Difficulty: Easy
- Docker image: redis:alpine
-
+ Category: Database
+ Difficulty: Easy
+ Docker image: redis:alpine
+
- What is Redis?
- In-memory data structure store and cache
- Redis ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Redis, not installing it.
+What is Redis?
+In-memory data structure store and cache
+Redis ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Redis, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Redis from the Database category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
redis:alpine image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
redis.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Redis from the Database category.
+ - Fill in the deployment form: subdomain (default suggestion:
redis), host port (default: 6379).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "redis",
- "host": "local",
- "subdomain": "redis",
- "port": "{{PORT}}",
-
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "redis",
+ "config": {
+ "subdomain": "redis",
+ "port": 6379
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Redis on my home host and expose it at redis.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Redis on my home host and expose it at redis.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Configure redis.conf for persistence
- - Set up authentication if needed
- - Configure maxmemory policy
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull redis:alpine and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Configure redis.conf for persistence
+ - Set up authentication if needed
+ - Configure maxmemory policy
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/redis/data:/data
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+None. The container runs with its upstream defaults.
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/redis/data:/data
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull redis:alpine.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- None. The container runs with its upstream defaults.
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull redis:alpine every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Redis → Update.
-
- Backups
- The config volume for Redis is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Redis:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Redis is in the Database category. Common pairings:
-
- - Adminer
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: redis. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Redis:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: redis. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/rocketchat/page.tsx b/src/app/docs/catalog/rocketchat/page.tsx
index b5d06c3..b3c8ea7 100644
--- a/src/app/docs/catalog/rocketchat/page.tsx
+++ b/src/app/docs/catalog/rocketchat/page.tsx
@@ -16,115 +16,114 @@ export default function rocketchatDocsPage() {
intro="Team collaboration platform like Slack"
>
- Category: Communication
- Difficulty: Intermediate
- Docker image: rocket.chat:latest
-
+ Category: Communication
+ Difficulty: Intermediate
+ Docker image: rocket.chat:latest
+
- What is Rocket.Chat?
- Team collaboration platform like Slack
- Rocket.Chat ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Rocket.Chat, not installing it.
+What is Rocket.Chat?
+Team collaboration platform like Slack
+Rocket.Chat ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Rocket.Chat, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Rocket.Chat from the Communication category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
rocket.chat:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
chat.<your-domain>.
- - Wait for the container health check (
/api/info) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Rocket.Chat from the Communication category.
+ - Fill in the deployment form: subdomain (default suggestion:
chat), host port (default: 3004).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/api/info) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "rocketchat",
- "host": "local",
- "subdomain": "chat",
- "port": "{{PORT}}",
- "environment": {
- "ROOT_URL": "",
- "MONGO_URL": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "rocketchat",
+ "config": {
+ "subdomain": "chat",
+ "port": 3004
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Rocket.Chat on my home host and expose it at chat.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Rocket.Chat on my home host and expose it at chat.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Requires MongoDB - deploy mongo container first
- - Complete admin setup wizard
- - Configure OAuth and integrations
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull rocket.chat:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Requires MongoDB - deploy mongo container first
+ - Complete admin setup wizard
+ - Configure OAuth and integrations
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/rocketchat/uploads:/app/uploads
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ ROOT_URL
+ MONGO_URL
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/rocketchat/uploads:/app/uploads
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull rocket.chat:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- ROOT_URL
- MONGO_URL
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull rocket.chat:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Rocket.Chat → Update.
-
- Backups
- The config volume for Rocket.Chat is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Rocket.Chat:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Rocket.Chat is in the Communication category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: rocketchat. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Rocket.Chat:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/api/info is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: rocketchat. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/roundcube/page.tsx b/src/app/docs/catalog/roundcube/page.tsx
index a3c3496..dff8697 100644
--- a/src/app/docs/catalog/roundcube/page.tsx
+++ b/src/app/docs/catalog/roundcube/page.tsx
@@ -16,116 +16,115 @@ export default function roundcubeDocsPage() {
intro="Modern webmail client with rich features"
>
- Category: Communication
- Difficulty: Intermediate
- Docker image: roundcube/roundcubemail:latest
-
+ Category: Communication
+ Difficulty: Intermediate
+ Docker image: roundcube/roundcubemail:latest
+
- What is Roundcube?
- Modern webmail client with rich features
- Roundcube ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Roundcube, not installing it.
+What is Roundcube?
+Modern webmail client with rich features
+Roundcube ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Roundcube, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Roundcube from the Communication category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
roundcube/roundcubemail:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
webmail.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Roundcube from the Communication category.
+ - Fill in the deployment form: subdomain (default suggestion:
webmail), host port (default: 8086).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "roundcube",
- "host": "local",
- "subdomain": "webmail",
- "port": "{{PORT}}",
- "environment": {
- "ROUNDCUBEMAIL_DEFAULT_HOST": "",
- "ROUNDCUBEMAIL_SMTP_SERVER": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "roundcube",
+ "config": {
+ "subdomain": "webmail",
+ "port": 8086
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Roundcube on my home host and expose it at webmail.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Roundcube on my home host and expose it at webmail.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Configure IMAP/SMTP server settings
- - Set up database connection
- - Customize appearance and plugins
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull roundcube/roundcubemail:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Configure IMAP/SMTP server settings
+ - Set up database connection
+ - Customize appearance and plugins
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/roundcube/config:/var/roundcube/config
+/opt/roundcube/db:/var/roundcube/db
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ ROUNDCUBEMAIL_DEFAULT_HOST
+ ROUNDCUBEMAIL_SMTP_SERVER
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/roundcube/config:/var/roundcube/config
- /opt/roundcube/db:/var/roundcube/db
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull roundcube/roundcubemail:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- ROUNDCUBEMAIL_DEFAULT_HOST
- ROUNDCUBEMAIL_SMTP_SERVER
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull roundcube/roundcubemail:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Roundcube → Update.
-
- Backups
- The config volume for Roundcube is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Roundcube:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Roundcube is in the Communication category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: roundcube. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Roundcube:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: roundcube. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/sabnzbd/page.tsx b/src/app/docs/catalog/sabnzbd/page.tsx
index 487b607..7f31fe7 100644
--- a/src/app/docs/catalog/sabnzbd/page.tsx
+++ b/src/app/docs/catalog/sabnzbd/page.tsx
@@ -16,119 +16,116 @@ export default function sabnzbdDocsPage() {
intro="Binary newsreader for Usenet downloads"
>
- Category: Downloads
- Difficulty: Intermediate
- Docker image: linuxserver/sabnzbd:latest
-
+ Category: Downloads
+ Difficulty: Intermediate
+ Docker image: linuxserver/sabnzbd:latest
+
- What is SABnzbd?
- Binary newsreader for Usenet downloads
- SABnzbd ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using SABnzbd, not installing it.
+What is SABnzbd?
+Binary newsreader for Usenet downloads
+SABnzbd ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using SABnzbd, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select SABnzbd from the Downloads category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
linuxserver/sabnzbd:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
sabnzbd.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick SABnzbd from the Downloads category.
+ - Fill in the deployment form: subdomain (default suggestion:
sabnzbd), host port (default: 8092).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "sabnzbd",
- "host": "local",
- "subdomain": "sabnzbd",
- "port": "{{PORT}}",
- "environment": {
- "PUID": "",
- "PGID": "",
- "TZ": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "sabnzbd",
+ "config": {
+ "subdomain": "sabnzbd",
+ "port": 8092
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy SABnzbd on my home host and expose it at sabnzbd.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy SABnzbd on my home host and expose it at sabnzbd.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Configure Usenet server credentials
- - Set up download categories
- - Configure post-processing scripts
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull linuxserver/sabnzbd:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Configure Usenet server credentials
+ - Set up download categories
+ - Configure post-processing scripts
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/sabnzbd/config:/config
+/downloads:/downloads
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ PUID
+ PGID
+ TZ
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/sabnzbd/config:/config
- /downloads:/downloads
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull linuxserver/sabnzbd:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- PUID
- PGID
- TZ
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull linuxserver/sabnzbd:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → SABnzbd → Update.
-
- Backups
- The config volume for SABnzbd is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with SABnzbd:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- SABnzbd is in the Downloads category. Common pairings:
-
- - qBittorrent
- - SABnzbd
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: sabnzbd. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with SABnzbd:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: sabnzbd. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/sami-files/page.tsx b/src/app/docs/catalog/sami-files/page.tsx
index 380223e..dbcad35 100644
--- a/src/app/docs/catalog/sami-files/page.tsx
+++ b/src/app/docs/catalog/sami-files/page.tsx
@@ -16,116 +16,116 @@ export default function samiFilesDocsPage() {
intro="Multi-server SSH file manager — browse, edit, upload, and exec across all your machines from one browser tab"
>
- Category: Files
- Difficulty: Intermediate
- Docker image: N/A
-
+ Category: Files
+ Difficulty: Intermediate
+ Docker image: N/A
+
- What is Sami Files?
- Multi-server SSH file manager — browse, edit, upload, and exec across all your machines from one browser tab
- Sami Files ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Sami Files, not installing it.
+What is Sami Files?
+Multi-server SSH file manager — browse, edit, upload, and exec across all your machines from one browser tab
+Sami Files ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Sami Files, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Sami Files from the Files category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
N/A image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
files.<your-domain>.
- - Wait for the container health check (
http://127.0.0.1:8765/api/health) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Sami Files from the Files category.
+ - Fill in the deployment form: subdomain (default suggestion:
files), host port (default: 8765).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
http://127.0.0.1:8765/api/health) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "sami-files",
- "host": "local",
- "subdomain": "files",
- "port": "{{PORT}}",
-
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "sami-files",
+ "config": {
+ "subdomain": "files",
+ "port": 8765
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Sami Files on my home host and expose it at files.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Sami Files on my home host and expose it at files.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Clone the repo: git clone http://100.81.59.99:3030/sami7777/sami-files.git /opt/sami-files
- - Create venv and install deps: /usr/local/lib/hermes-agent/venv/bin/pip install fastapi uvicorn asyncssh pyyaml python-multipart
- - Copy deploy/sami-files.service to /etc/systemd/system/ and `systemctl daemon-reload`
- - Enable + start: systemctl enable --now sami-files.service
- - Edit /opt/sami-files/config/servers.yaml to add your SSH targets
- - Add the Caddy snippet (above) to your Caddyfile and reload Caddy
- - Mount the log dir into DashCaddy: add `-v /opt/sami-files/logs:/opt/sami-files/logs:ro` to start.sh, then recreate the container
- - Browse to https://files.sami — log in via DashCaddy SSO
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull N/A and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Clone the repo: git clone http://100.81.59.99:3030/sami7777/sami-files.git /opt/sami-files
+ - Create venv and install deps: /usr/local/lib/hermes-agent/venv/bin/pip install fastapi uvicorn asyncssh pyyaml python-multipart
+ - Copy deploy/sami-files.service to /etc/systemd/system/ and `systemctl daemon-reload`
+ - Enable + start: systemctl enable --now sami-files.service
+ - Edit /opt/sami-files/config/servers.yaml to add your SSH targets
+ - Add the Caddy snippet (above) to your Caddyfile and reload Caddy
+ - Mount the log dir into DashCaddy: add `-v /opt/sami-files/logs:/opt/sami-files/logs:ro` to start.sh, then recreate the container
+ - Browse to https://files.sami — log in via DashCaddy SSO
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
-
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Environment variables
+None. The container runs with its upstream defaults.
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Environment variables
- None. The container runs with its upstream defaults.
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull N/A.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Updating
- DashCaddy's built-in Watchtower integration will pull N/A every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Sami Files → Update.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Backups
- The config volume for Sami Files is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Sami Files:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Sami Files is in the Files category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: sami-files. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Sami Files:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
http://127.0.0.1:8765/api/health is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: sami-files. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/seerr/page.tsx b/src/app/docs/catalog/seerr/page.tsx
index 54c2d01..cb0c345 100644
--- a/src/app/docs/catalog/seerr/page.tsx
+++ b/src/app/docs/catalog/seerr/page.tsx
@@ -16,115 +16,113 @@ export default function seerrDocsPage() {
intro="Media request and discovery manager for Plex, Jellyfin, and Emby"
>
- Category: Media Management
- Difficulty: Easy
- Docker image: ghcr.io/seerr-team/seerr:latest
-
+ Category: Media Management
+ Difficulty: Easy
+ Docker image: ghcr.io/seerr-team/seerr:latest
+
- What is Seerr?
- Media request and discovery manager for Plex, Jellyfin, and Emby
- Seerr ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Seerr, not installing it.
+What is Seerr?
+Media request and discovery manager for Plex, Jellyfin, and Emby
+Seerr ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Seerr, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Seerr from the Media Management category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
ghcr.io/seerr-team/seerr:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
requests.<your-domain>.
- - Wait for the container health check (
/api/v1/status) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Seerr from the Media Management category.
+ - Fill in the deployment form: subdomain (default suggestion:
requests), host port (default: 5055).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/api/v1/status) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "seerr",
- "host": "local",
- "subdomain": "requests",
- "port": "{{PORT}}",
- "environment": {
- "TZ": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "seerr",
+ "config": {
+ "subdomain": "requests",
+ "port": 5055
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Seerr on my home host and expose it at requests.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Seerr on my home host and expose it at requests.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Connect to Plex, Jellyfin, or Emby server
- - Link Sonarr and Radarr
- - Configure user permissions
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull ghcr.io/seerr-team/seerr:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Connect to Plex, Jellyfin, or Emby server
+ - Link Sonarr and Radarr
+ - Configure user permissions
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/seerr/config:/app/config
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ TZ
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/seerr/config:/app/config
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull ghcr.io/seerr-team/seerr:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- TZ
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull ghcr.io/seerr-team/seerr:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Seerr → Update.
-
- Backups
- The config volume for Seerr is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Seerr:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Seerr is in the Media Management category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: seerr. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Seerr:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/api/v1/status is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: seerr. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/sonarr/page.tsx b/src/app/docs/catalog/sonarr/page.tsx
index 8cb36fb..62b7dfd 100644
--- a/src/app/docs/catalog/sonarr/page.tsx
+++ b/src/app/docs/catalog/sonarr/page.tsx
@@ -16,121 +16,117 @@ export default function sonarrDocsPage() {
intro="Smart PVR for newsgroup and bittorrent users"
>
- Category: Media Management
- Difficulty: Intermediate
- Docker image: linuxserver/sonarr:latest
-
+ Category: Media Management
+ Difficulty: Intermediate
+ Docker image: linuxserver/sonarr:latest
+
- What is Sonarr?
- Smart PVR for newsgroup and bittorrent users
- Sonarr ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Sonarr, not installing it.
+What is Sonarr?
+Smart PVR for newsgroup and bittorrent users
+Sonarr ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Sonarr, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Sonarr from the Media Management category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
linuxserver/sonarr:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
sonarr.<your-domain>.
- - Wait for the container health check (
/api/v3/system/status) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Sonarr from the Media Management category.
+ - Fill in the deployment form: subdomain (default suggestion:
sonarr), host port (default: 8989).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/api/v3/system/status) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "sonarr",
- "host": "local",
- "subdomain": "sonarr",
- "port": "{{PORT}}",
- "environment": {
- "PUID": "",
- "PGID": "",
- "TZ": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "sonarr",
+ "config": {
+ "subdomain": "sonarr",
+ "port": 8989
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Sonarr on my home host and expose it at sonarr.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Sonarr on my home host and expose it at sonarr.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Configure download clients (qBittorrent, etc.)
- - Add indexers for content discovery
- - Set up root folders for TV shows
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull linuxserver/sonarr:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Configure download clients (qBittorrent, etc.)
+ - Add indexers for content discovery
+ - Set up root folders for TV shows
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/sonarr/config:/config
+/downloads:/downloads
+/tv:/tv
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ PUID
+ PGID
+ TZ
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/sonarr/config:/config
- /downloads:/downloads
- /tv:/tv
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull linuxserver/sonarr:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- PUID
- PGID
- TZ
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull linuxserver/sonarr:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Sonarr → Update.
-
- Backups
- The config volume for Sonarr is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Sonarr:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Sonarr is in the Media Management category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: sonarr. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Sonarr:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/api/v3/system/status is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: sonarr. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/speedtest/page.tsx b/src/app/docs/catalog/speedtest/page.tsx
index 8c453ac..869a91a 100644
--- a/src/app/docs/catalog/speedtest/page.tsx
+++ b/src/app/docs/catalog/speedtest/page.tsx
@@ -16,118 +16,115 @@ export default function speedtestDocsPage() {
intro="Internet speed monitoring over time"
>
- Category: Monitoring
- Difficulty: Easy
- Docker image: ghcr.io/alexjustesen/speedtest-tracker:latest
-
+ Category: Monitoring
+ Difficulty: Easy
+ Docker image: ghcr.io/alexjustesen/speedtest-tracker:latest
+
- What is Speedtest Tracker?
- Internet speed monitoring over time
- Speedtest Tracker ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Speedtest Tracker, not installing it.
+What is Speedtest Tracker?
+Internet speed monitoring over time
+Speedtest Tracker ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Speedtest Tracker, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Speedtest Tracker from the Monitoring category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
ghcr.io/alexjustesen/speedtest-tracker:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
speedtest.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Speedtest Tracker from the Monitoring category.
+ - Fill in the deployment form: subdomain (default suggestion:
speedtest), host port (default: 8093).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "speedtest",
- "host": "local",
- "subdomain": "speedtest",
- "port": "{{PORT}}",
- "environment": {
- "PUID": "",
- "PGID": "",
- "DB_CONNECTION": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "speedtest",
+ "config": {
+ "subdomain": "speedtest",
+ "port": 8093
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Speedtest Tracker on my home host and expose it at speedtest.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Speedtest Tracker on my home host and expose it at speedtest.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Configure test schedule
- - View historical data
- - Set up notifications for slow speeds
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull ghcr.io/alexjustesen/speedtest-tracker:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Configure test schedule
+ - View historical data
+ - Set up notifications for slow speeds
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/speedtest/config:/config
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ PUID
+ PGID
+ DB_CONNECTION
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/speedtest/config:/config
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull ghcr.io/alexjustesen/speedtest-tracker:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- PUID
- PGID
- DB_CONNECTION
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull ghcr.io/alexjustesen/speedtest-tracker:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Speedtest Tracker → Update.
-
- Backups
- The config volume for Speedtest Tracker is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Speedtest Tracker:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Speedtest Tracker is in the Monitoring category. Common pairings:
-
- - Uptime Kuma
- - Dozzle
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: speedtest. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Speedtest Tracker:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: speedtest. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/standardnotes/page.tsx b/src/app/docs/catalog/standardnotes/page.tsx
index bc4b28b..e30b4e4 100644
--- a/src/app/docs/catalog/standardnotes/page.tsx
+++ b/src/app/docs/catalog/standardnotes/page.tsx
@@ -16,113 +16,113 @@ export default function standardnotesDocsPage() {
intro="End-to-end encrypted notes app"
>
- Category: Productivity
- Difficulty: Intermediate
- Docker image: standardnotes/server:latest
-
+ Category: Productivity
+ Difficulty: Intermediate
+ Docker image: standardnotes/server:latest
+
- What is Standard Notes?
- End-to-end encrypted notes app
- Standard Notes ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Standard Notes, not installing it.
+What is Standard Notes?
+End-to-end encrypted notes app
+Standard Notes ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Standard Notes, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Standard Notes from the Productivity category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
standardnotes/server:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
notes.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Standard Notes from the Productivity category.
+ - Fill in the deployment form: subdomain (default suggestion:
notes), host port (default: 3007).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "standardnotes",
- "host": "local",
- "subdomain": "notes",
- "port": "{{PORT}}",
- "environment": {
- "RAILS_ENV": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "standardnotes",
+ "config": {
+ "subdomain": "notes",
+ "port": 3007
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Standard Notes on my home host and expose it at notes.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Standard Notes on my home host and expose it at notes.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Configure environment variables
- - Set up database connection
- - Install Standard Notes apps
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull standardnotes/server:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Configure environment variables
+ - Set up database connection
+ - Install Standard Notes apps
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/standardnotes/data:/var/lib/server
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ RAILS_ENV
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/standardnotes/data:/var/lib/server
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull standardnotes/server:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- RAILS_ENV
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull standardnotes/server:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Standard Notes → Update.
-
- Backups
- The config volume for Standard Notes is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Standard Notes:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Standard Notes is in the Productivity category. Common pairings:
-
- - Nextcloud
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: standardnotes. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Standard Notes:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: standardnotes. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/stirling-pdf/page.tsx b/src/app/docs/catalog/stirling-pdf/page.tsx
index cd554fa..27593e2 100644
--- a/src/app/docs/catalog/stirling-pdf/page.tsx
+++ b/src/app/docs/catalog/stirling-pdf/page.tsx
@@ -16,114 +16,114 @@ export default function stirlingPdfDocsPage() {
intro="Self-hosted PDF manipulation tool - merge, split, convert, and more"
>
- Category: Utilities
- Difficulty: Easy
- Docker image: frooodle/s-pdf:latest
-
+ Category: Utilities
+ Difficulty: Easy
+ Docker image: frooodle/s-pdf:latest
+
- What is Stirling PDF?
- Self-hosted PDF manipulation tool - merge, split, convert, and more
- Stirling PDF ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Stirling PDF, not installing it.
+What is Stirling PDF?
+Self-hosted PDF manipulation tool - merge, split, convert, and more
+Stirling PDF ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Stirling PDF, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Stirling PDF from the Utilities category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
frooodle/s-pdf:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
pdf.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Stirling PDF from the Utilities category.
+ - Fill in the deployment form: subdomain (default suggestion:
pdf), host port (default: 8084).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "stirling-pdf",
- "host": "local",
- "subdomain": "pdf",
- "port": "{{PORT}}",
- "environment": {
- "DOCKER_ENABLE_SECURITY": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "stirling-pdf",
+ "config": {
+ "subdomain": "pdf",
+ "port": 8084
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Stirling PDF on my home host and expose it at pdf.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Stirling PDF on my home host and expose it at pdf.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Access the web interface to start manipulating PDFs
- - Supports merge, split, rotate, convert, compress, and more
- - Optional OCR support via Tesseract
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull frooodle/s-pdf:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Access the web interface to start manipulating PDFs
+ - Supports merge, split, rotate, convert, compress, and more
+ - Optional OCR support via Tesseract
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/stirling-pdf/data:/usr/share/tessdata
+/opt/stirling-pdf/config:/configs
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ DOCKER_ENABLE_SECURITY
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/stirling-pdf/data:/usr/share/tessdata
- /opt/stirling-pdf/config:/configs
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull frooodle/s-pdf:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- DOCKER_ENABLE_SECURITY
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull frooodle/s-pdf:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Stirling PDF → Update.
-
- Backups
- The config volume for Stirling PDF is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Stirling PDF:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Stirling PDF is in the Utilities category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: stirling-pdf. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Stirling PDF:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: stirling-pdf. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/syncthing/page.tsx b/src/app/docs/catalog/syncthing/page.tsx
index eec7a99..9b6da15 100644
--- a/src/app/docs/catalog/syncthing/page.tsx
+++ b/src/app/docs/catalog/syncthing/page.tsx
@@ -16,118 +16,116 @@ export default function syncthingDocsPage() {
intro="Continuous file synchronization between devices"
>
- Category: Files
- Difficulty: Easy
- Docker image: linuxserver/syncthing:latest
-
+ Category: Files
+ Difficulty: Easy
+ Docker image: linuxserver/syncthing:latest
+
- What is Syncthing?
- Continuous file synchronization between devices
- Syncthing ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Syncthing, not installing it.
+What is Syncthing?
+Continuous file synchronization between devices
+Syncthing ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Syncthing, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Syncthing from the Files category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
linuxserver/syncthing:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
sync.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Syncthing from the Files category.
+ - Fill in the deployment form: subdomain (default suggestion:
sync), host port (default: 8384).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "syncthing",
- "host": "local",
- "subdomain": "sync",
- "port": "{{PORT}}",
- "environment": {
- "PUID": "",
- "PGID": "",
- "TZ": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "syncthing",
+ "config": {
+ "subdomain": "sync",
+ "port": 8384
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Syncthing on my home host and expose it at sync.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Syncthing on my home host and expose it at sync.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Add devices using their Device IDs
- - Configure shared folders
- - Set up folder synchronization
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull linuxserver/syncthing:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Add devices using their Device IDs
+ - Configure shared folders
+ - Set up folder synchronization
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/syncthing/config:/config
+/opt/syncthing/data:/data
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ PUID
+ PGID
+ TZ
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/syncthing/config:/config
- /opt/syncthing/data:/data
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull linuxserver/syncthing:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- PUID
- PGID
- TZ
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull linuxserver/syncthing:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Syncthing → Update.
-
- Backups
- The config volume for Syncthing is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Syncthing:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Syncthing is in the Files category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: syncthing. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Syncthing:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: syncthing. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/tautulli/page.tsx b/src/app/docs/catalog/tautulli/page.tsx
index 06662ca..74fe84d 100644
--- a/src/app/docs/catalog/tautulli/page.tsx
+++ b/src/app/docs/catalog/tautulli/page.tsx
@@ -16,119 +16,115 @@ export default function tautulliDocsPage() {
intro="Plex media server monitoring and statistics"
>
- Category: Media Management
- Difficulty: Easy
- Docker image: linuxserver/tautulli:latest
-
+ Category: Media Management
+ Difficulty: Easy
+ Docker image: linuxserver/tautulli:latest
+
- What is Tautulli?
- Plex media server monitoring and statistics
- Tautulli ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Tautulli, not installing it.
+What is Tautulli?
+Plex media server monitoring and statistics
+Tautulli ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Tautulli, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Tautulli from the Media Management category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
linuxserver/tautulli:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
tautulli.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Tautulli from the Media Management category.
+ - Fill in the deployment form: subdomain (default suggestion:
tautulli), host port (default: 8181).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "tautulli",
- "host": "local",
- "subdomain": "tautulli",
- "port": "{{PORT}}",
- "environment": {
- "PUID": "",
- "PGID": "",
- "TZ": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "tautulli",
+ "config": {
+ "subdomain": "tautulli",
+ "port": 8181
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Tautulli on my home host and expose it at tautulli.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Tautulli on my home host and expose it at tautulli.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Connect to Plex server
- - Configure notifications
- - Set up newsletters
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull linuxserver/tautulli:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Connect to Plex server
+ - Configure notifications
+ - Set up newsletters
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/tautulli/config:/config
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ PUID
+ PGID
+ TZ
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/tautulli/config:/config
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull linuxserver/tautulli:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- PUID
- PGID
- TZ
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull linuxserver/tautulli:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Tautulli → Update.
-
- Backups
- The config volume for Tautulli is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Tautulli:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Tautulli is in the Media Management category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: tautulli. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Tautulli:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: tautulli. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/technitium/page.tsx b/src/app/docs/catalog/technitium/page.tsx
index 774e9ea..5de8d17 100644
--- a/src/app/docs/catalog/technitium/page.tsx
+++ b/src/app/docs/catalog/technitium/page.tsx
@@ -16,117 +16,116 @@ export default function technitiumDocsPage() {
intro="Modern DNS server with web UI for managing private zones"
>
- Category: DNS
- Difficulty: Easy
- Docker image: technitium/dns-server:latest
-
+ Category: DNS
+ Difficulty: Easy
+ Docker image: technitium/dns-server:latest
+
- What is Technitium DNS Server?
- Modern DNS server with web UI for managing private zones
- Technitium DNS Server ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Technitium DNS Server, not installing it.
+What is Technitium DNS Server?
+Modern DNS server with web UI for managing private zones
+Technitium DNS Server ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Technitium DNS Server, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Technitium DNS Server from the DNS category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
technitium/dns-server:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
dns1.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Technitium DNS Server from the DNS category.
+ - Fill in the deployment form: subdomain (default suggestion:
dns1), host port (default: 5380).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "technitium",
- "host": "local",
- "subdomain": "dns1",
- "port": "{{PORT}}",
- "environment": {
- "DNS_SERVER_DOMAIN": "",
- "DNS_SERVER_ADMIN_PASSWORD": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "technitium",
+ "config": {
+ "subdomain": "dns1",
+ "port": 5380
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Technitium DNS Server on my home host and expose it at dns1.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Technitium DNS Server on my home host and expose it at dns1.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Access web interface at https://dns1.sami
- - Login with admin credentials
- - Create a primary zone for 'sami' domain
- - Add A records for your services (e.g., plex.sami -> 192.168.1.100)
- - Configure your devices to use this DNS server
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull technitium/dns-server:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Access web interface at https://dns1.sami
+ - Login with admin credentials
+ - Create a primary zone for 'sami' domain
+ - Add A records for your services (e.g., plex.sami -> 192.168.1.100)
+ - Configure your devices to use this DNS server
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/technitium/config:/etc/dns
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ DNS_SERVER_DOMAIN
+ DNS_SERVER_ADMIN_PASSWORD
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/technitium/config:/etc/dns
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull technitium/dns-server:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- DNS_SERVER_DOMAIN
- DNS_SERVER_ADMIN_PASSWORD
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull technitium/dns-server:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Technitium DNS Server → Update.
-
- Backups
- The config volume for Technitium DNS Server is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Technitium DNS Server:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Technitium DNS Server is in the DNS category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: technitium. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Technitium DNS Server:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: technitium. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/transmission/page.tsx b/src/app/docs/catalog/transmission/page.tsx
index 3d84e82..27cf767 100644
--- a/src/app/docs/catalog/transmission/page.tsx
+++ b/src/app/docs/catalog/transmission/page.tsx
@@ -16,119 +16,116 @@ export default function transmissionDocsPage() {
intro="Lightweight BitTorrent client"
>
- Category: Downloads
- Difficulty: Easy
- Docker image: linuxserver/transmission:latest
-
+ Category: Downloads
+ Difficulty: Easy
+ Docker image: linuxserver/transmission:latest
+
- What is Transmission?
- Lightweight BitTorrent client
- Transmission ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Transmission, not installing it.
+What is Transmission?
+Lightweight BitTorrent client
+Transmission ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Transmission, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Transmission from the Downloads category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
linuxserver/transmission:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
transmission.<your-domain>.
- - Wait for the container health check (
/transmission/web/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Transmission from the Downloads category.
+ - Fill in the deployment form: subdomain (default suggestion:
transmission), host port (default: 9092).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/transmission/web/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "transmission",
- "host": "local",
- "subdomain": "transmission",
- "port": "{{PORT}}",
- "environment": {
- "PUID": "",
- "PGID": "",
- "TZ": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "transmission",
+ "config": {
+ "subdomain": "transmission",
+ "port": 9092
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Transmission on my home host and expose it at transmission.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Transmission on my home host and expose it at transmission.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Configure download paths
- - Set bandwidth limits
- - Configure blocklists if needed
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull linuxserver/transmission:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Configure download paths
+ - Set bandwidth limits
+ - Configure blocklists if needed
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/transmission/config:/config
+/downloads:/downloads
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ PUID
+ PGID
+ TZ
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/transmission/config:/config
- /downloads:/downloads
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull linuxserver/transmission:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- PUID
- PGID
- TZ
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull linuxserver/transmission:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Transmission → Update.
-
- Backups
- The config volume for Transmission is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Transmission:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Transmission is in the Downloads category. Common pairings:
-
- - qBittorrent
- - SABnzbd
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: transmission. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Transmission:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/transmission/web/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: transmission. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/trilium/page.tsx b/src/app/docs/catalog/trilium/page.tsx
index f6f1a06..a120fde 100644
--- a/src/app/docs/catalog/trilium/page.tsx
+++ b/src/app/docs/catalog/trilium/page.tsx
@@ -16,111 +16,111 @@ export default function triliumDocsPage() {
intro="Hierarchical knowledge base and note-taking app"
>
- Category: Productivity
- Difficulty: Easy
- Docker image: zadam/trilium:latest
-
+ Category: Productivity
+ Difficulty: Easy
+ Docker image: zadam/trilium:latest
+
- What is Trilium Notes?
- Hierarchical knowledge base and note-taking app
- Trilium Notes ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Trilium Notes, not installing it.
+What is Trilium Notes?
+Hierarchical knowledge base and note-taking app
+Trilium Notes ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Trilium Notes, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Trilium Notes from the Productivity category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
zadam/trilium:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
notes.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Trilium Notes from the Productivity category.
+ - Fill in the deployment form: subdomain (default suggestion:
notes), host port (default: 8085).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "trilium",
- "host": "local",
- "subdomain": "notes",
- "port": "{{PORT}}",
-
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "trilium",
+ "config": {
+ "subdomain": "notes",
+ "port": 8085
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Trilium Notes on my home host and expose it at notes.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Trilium Notes on my home host and expose it at notes.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Set your password on first access
- - Organize notes in a tree hierarchy
- - Supports rich text, code blocks, math equations, and diagrams
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull zadam/trilium:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Set your password on first access
+ - Organize notes in a tree hierarchy
+ - Supports rich text, code blocks, math equations, and diagrams
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/trilium/data:/home/node/trilium-data
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+None. The container runs with its upstream defaults.
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/trilium/data:/home/node/trilium-data
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull zadam/trilium:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- None. The container runs with its upstream defaults.
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull zadam/trilium:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Trilium Notes → Update.
-
- Backups
- The config volume for Trilium Notes is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Trilium Notes:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Trilium Notes is in the Productivity category. Common pairings:
-
- - Nextcloud
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: trilium. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Trilium Notes:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: trilium. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/uptime-kuma/page.tsx b/src/app/docs/catalog/uptime-kuma/page.tsx
index 07c7752..5ce3cd7 100644
--- a/src/app/docs/catalog/uptime-kuma/page.tsx
+++ b/src/app/docs/catalog/uptime-kuma/page.tsx
@@ -16,112 +16,111 @@ export default function uptimeKumaDocsPage() {
intro="Self-hosted monitoring tool like Uptime Robot"
>
- Category: Monitoring
- Difficulty: Easy
- Docker image: louislam/uptime-kuma:latest
-
+ Category: Monitoring
+ Difficulty: Easy
+ Docker image: louislam/uptime-kuma:latest
+
- What is Uptime Kuma?
- Self-hosted monitoring tool like Uptime Robot
- Uptime Kuma ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Uptime Kuma, not installing it.
+What is Uptime Kuma?
+Self-hosted monitoring tool like Uptime Robot
+Uptime Kuma ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Uptime Kuma, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Uptime Kuma from the Monitoring category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
louislam/uptime-kuma:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
uptime.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Uptime Kuma from the Monitoring category.
+ - Fill in the deployment form: subdomain (default suggestion:
uptime), host port (default: 3002).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "uptime-kuma",
- "host": "local",
- "subdomain": "uptime",
- "port": "{{PORT}}",
-
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "uptime-kuma",
+ "config": {
+ "subdomain": "uptime",
+ "port": 3002
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Uptime Kuma on my home host and expose it at uptime.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Uptime Kuma on my home host and expose it at uptime.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Open the new
uptime.<your-domain> URL.
- - Complete the upstream Uptime Kuma setup wizard (create admin user, accept EULA, etc.).
- - Configure backups from Settings → Backups — the default daily snapshot will capture the data volume.
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull louislam/uptime-kuma:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Open the deployed URL (returned in the response as
url, or visible in the dashboard).
+ - Complete the upstream Uptime Kuma setup wizard (admin account, library paths, EULA).
+ - Restore from a backup if one exists:
POST /api/v1/apps/{appId}/restore with the backup ID from GET /api/v1/backups/history.
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/uptime-kuma:/app/data
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+None. The container runs with its upstream defaults.
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/uptime-kuma:/app/data
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull louislam/uptime-kuma:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- None. The container runs with its upstream defaults.
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull louislam/uptime-kuma:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Uptime Kuma → Update.
-
- Backups
- The config volume for Uptime Kuma is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Uptime Kuma:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Uptime Kuma is in the Monitoring category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: uptime-kuma. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Uptime Kuma:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: uptime-kuma. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/valheim/page.tsx b/src/app/docs/catalog/valheim/page.tsx
index aa967a3..bcf0426 100644
--- a/src/app/docs/catalog/valheim/page.tsx
+++ b/src/app/docs/catalog/valheim/page.tsx
@@ -16,121 +16,118 @@ export default function valheimDocsPage() {
intro="Valheim dedicated server for multiplayer Viking adventures"
>
- Category: Gaming
- Difficulty: Easy
- Docker image: lloesche/valheim-server:latest
-
+ Category: Gaming
+ Difficulty: Easy
+ Docker image: lloesche/valheim-server:latest
+
- What is Valheim Server?
- Valheim dedicated server for multiplayer Viking adventures
- Valheim Server ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Valheim Server, not installing it.
+What is Valheim Server?
+Valheim dedicated server for multiplayer Viking adventures
+Valheim Server ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Valheim Server, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Valheim Server from the Gaming category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
lloesche/valheim-server:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
valheim.<your-domain>.
- - Wait for the container health check (
tcp://localhost:2456) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Valheim Server from the Gaming category.
+ - Fill in the deployment form: subdomain (default suggestion:
valheim), host port (default: 2456).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
tcp://localhost:2456) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "valheim",
- "host": "local",
- "subdomain": "valheim",
- "port": "{{PORT}}",
- "environment": {
- "SERVER_NAME": "",
- "WORLD_NAME": "",
- "SERVER_PASS": "",
- "SERVER_PUBLIC": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "valheim",
+ "config": {
+ "subdomain": "valheim",
+ "port": 2456
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Valheim Server on my home host and expose it at valheim.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Valheim Server on my home host and expose it at valheim.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Connect via Steam: Add Server > IP:2456
- - Default server password is auto-generated (check environment variables)
- - World data is persisted in the data volume
- - Requires at least 4GB RAM for smooth operation
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull lloesche/valheim-server:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Connect via Steam: Add Server > IP:2456
+ - Default server password is auto-generated (check environment variables)
+ - World data is persisted in the data volume
+ - Requires at least 4GB RAM for smooth operation
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/valheim/config:/config
+/opt/valheim/data:/opt/valheim
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ SERVER_NAME
+ WORLD_NAME
+ SERVER_PASS
+ SERVER_PUBLIC
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/valheim/config:/config
- /opt/valheim/data:/opt/valheim
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull lloesche/valheim-server:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- SERVER_NAME
- WORLD_NAME
- SERVER_PASS
- SERVER_PUBLIC
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull lloesche/valheim-server:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Valheim Server → Update.
-
- Backups
- The config volume for Valheim Server is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Valheim Server:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Valheim Server is in the Gaming category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: valheim. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Valheim Server:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
tcp://localhost:2456 is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: valheim. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/vaultwarden/page.tsx b/src/app/docs/catalog/vaultwarden/page.tsx
index 1c092a0..5b154a1 100644
--- a/src/app/docs/catalog/vaultwarden/page.tsx
+++ b/src/app/docs/catalog/vaultwarden/page.tsx
@@ -16,116 +16,114 @@ export default function vaultwardenDocsPage() {
intro="Lightweight Bitwarden-compatible password manager"
>
- Category: Security
- Difficulty: Easy
- Docker image: vaultwarden/server:latest
-
+ Category: Security
+ Difficulty: Easy
+ Docker image: vaultwarden/server:latest
+
- What is Vaultwarden?
- Lightweight Bitwarden-compatible password manager
- Vaultwarden ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Vaultwarden, not installing it.
+What is Vaultwarden?
+Lightweight Bitwarden-compatible password manager
+Vaultwarden ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Vaultwarden, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Vaultwarden from the Security category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
vaultwarden/server:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
vault.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Vaultwarden from the Security category.
+ - Fill in the deployment form: subdomain (default suggestion:
vault), host port (default: 8088).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "vaultwarden",
- "host": "local",
- "subdomain": "vault",
- "port": "{{PORT}}",
- "environment": {
- "DOMAIN": "",
- "ADMIN_TOKEN": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "vaultwarden",
+ "config": {
+ "subdomain": "vault",
+ "port": 8088
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Vaultwarden on my home host and expose it at vault.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Vaultwarden on my home host and expose it at vault.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Change admin token immediately
- - Create your account
- - Install browser extensions and mobile apps
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull vaultwarden/server:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Change admin token immediately
+ - Create your account
+ - Install browser extensions and mobile apps
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/vaultwarden/data:/data
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ DOMAIN
+ ADMIN_TOKEN
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/vaultwarden/data:/data
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull vaultwarden/server:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- DOMAIN
- ADMIN_TOKEN
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull vaultwarden/server:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Vaultwarden → Update.
-
- Backups
- The config volume for Vaultwarden is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Vaultwarden:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Vaultwarden is in the Security category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: vaultwarden. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Vaultwarden:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: vaultwarden. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/vintage-radio/page.tsx b/src/app/docs/catalog/vintage-radio/page.tsx
index caa1efd..ad64d85 100644
--- a/src/app/docs/catalog/vintage-radio/page.tsx
+++ b/src/app/docs/catalog/vintage-radio/page.tsx
@@ -16,113 +16,113 @@ export default function vintageRadioDocsPage() {
intro="Glass-front console stereo that tunes curated real internet stations (SomaFM, KEXP, Radio Paradise, and more) through a beautiful analog UI"
>
- Category: Media
- Difficulty: Easy
- Docker image: nginx:alpine
-
+ Category: Media
+ Difficulty: Easy
+ Docker image: nginx:alpine
+
- What is Vintage Stereo?
- Glass-front console stereo that tunes curated real internet stations (SomaFM, KEXP, Radio Paradise, and more) through a beautiful analog UI
- Vintage Stereo ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Vintage Stereo, not installing it.
+What is Vintage Stereo?
+Glass-front console stereo that tunes curated real internet stations (SomaFM, KEXP, Radio Paradise, and more) through a beautiful analog UI
+Vintage Stereo ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Vintage Stereo, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Vintage Stereo from the Media category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
nginx:alpine image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
radio.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Vintage Stereo from the Media category.
+ - Fill in the deployment form: subdomain (default suggestion:
radio), host port (default: 8090).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "vintage-radio",
- "host": "local",
- "subdomain": "radio",
- "port": "{{PORT}}",
-
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "vintage-radio",
+ "config": {
+ "subdomain": "radio",
+ "port": 8090
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Vintage Stereo on my home host and expose it at radio.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Vintage Stereo on my home host and expose it at radio.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Run `bash /usr/local/bin/vintage-radio-install.sh` once before starting the container — copies the bundled web assets (index.html, radio.css, radio.js, stations.json) from the DashCaddy repo (dashcaddy-api/static-sites/vintage-radio/web) into /opt/vintage-radio/web
- - Open radio.sami (or your configured subdomain)
- - Press the PWR knob, drag the dial or click a station card
- - Cycle the MODE knob to filter by genre (ALL / AMBIENT / ROCK / MIXED)
- - To add stations, edit /opt/vintage-radio/web/stations.json on the host and restart the container
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull nginx:alpine and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Run `bash /usr/local/bin/vintage-radio-install.sh` once before starting the container — copies the bundled web assets (index.html, radio.css, radio.js, stations.json) from the DashCaddy repo (dashcaddy-api/static-sites/vintage-radio/web) into /opt/vintage-radio/web
+ - Open radio.sami (or your configured subdomain)
+ - Press the PWR knob, drag the dial or click a station card
+ - Cycle the MODE knob to filter by genre (ALL / AMBIENT / ROCK / MIXED)
+ - To add stations, edit /opt/vintage-radio/web/stations.json on the host and restart the container
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/vintage-radio/web:/usr/share/nginx/html:ro
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+None. The container runs with its upstream defaults.
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/vintage-radio/web:/usr/share/nginx/html:ro
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull nginx:alpine.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- None. The container runs with its upstream defaults.
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull nginx:alpine every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Vintage Stereo → Update.
-
- Backups
- The config volume for Vintage Stereo is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Vintage Stereo:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Vintage Stereo is in the Media category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: vintage-radio. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Vintage Stereo:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: vintage-radio. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/vscode-server/page.tsx b/src/app/docs/catalog/vscode-server/page.tsx
index 337d460..2352acd 100644
--- a/src/app/docs/catalog/vscode-server/page.tsx
+++ b/src/app/docs/catalog/vscode-server/page.tsx
@@ -16,114 +16,114 @@ export default function vscodeServerDocsPage() {
intro="Visual Studio Code in your browser"
>
- Category: Development
- Difficulty: Easy
- Docker image: codercom/code-server:latest
-
+ Category: Development
+ Difficulty: Easy
+ Docker image: codercom/code-server:latest
+
- What is VS Code Server?
- Visual Studio Code in your browser
- VS Code Server ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using VS Code Server, not installing it.
+What is VS Code Server?
+Visual Studio Code in your browser
+VS Code Server ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using VS Code Server, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select VS Code Server from the Development category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
codercom/code-server:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
code.<your-domain>.
- - Wait for the container health check (
/healthz) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick VS Code Server from the Development category.
+ - Fill in the deployment form: subdomain (default suggestion:
code), host port (default: 8443).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/healthz) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "vscode-server",
- "host": "local",
- "subdomain": "code",
- "port": "{{PORT}}",
- "environment": {
- "PASSWORD": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "vscode-server",
+ "config": {
+ "subdomain": "code",
+ "port": 8443
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy VS Code Server on my home host and expose it at code.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy VS Code Server on my home host and expose it at code.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Open the new
code.<your-domain> URL.
- - Complete the upstream VS Code Server setup wizard (create admin user, accept EULA, etc.).
- - Configure backups from Settings → Backups — the default daily snapshot will capture the data volume.
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull codercom/code-server:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Open the deployed URL (returned in the response as
url, or visible in the dashboard).
+ - Complete the upstream VS Code Server setup wizard (admin account, library paths, EULA).
+ - Restore from a backup if one exists:
POST /api/v1/apps/{appId}/restore with the backup ID from GET /api/v1/backups/history.
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/vscode/config:/home/coder/.config
+/opt/vscode/projects:/home/coder/projects
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ PASSWORD
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/vscode/config:/home/coder/.config
- /opt/vscode/projects:/home/coder/projects
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull codercom/code-server:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- PASSWORD
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull codercom/code-server:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → VS Code Server → Update.
-
- Backups
- The config volume for VS Code Server is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with VS Code Server:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- VS Code Server is in the Development category. Common pairings:
-
- - Gitea
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: vscode-server. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with VS Code Server:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/healthz is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: vscode-server. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/watchtower/page.tsx b/src/app/docs/catalog/watchtower/page.tsx
index 685f8ce..1e7a3b2 100644
--- a/src/app/docs/catalog/watchtower/page.tsx
+++ b/src/app/docs/catalog/watchtower/page.tsx
@@ -16,119 +16,116 @@ export default function watchtowerDocsPage() {
intro="Automatic Docker container image updates"
>
- Category: Management
- Difficulty: Easy
- Docker image: containrrr/watchtower:latest
-
+ Category: Management
+ Difficulty: Easy
+ Docker image: containrrr/watchtower:latest
+
- What is Watchtower?
- Automatic Docker container image updates
- Watchtower ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Watchtower, not installing it.
+What is Watchtower?
+Automatic Docker container image updates
+Watchtower ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Watchtower, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Watchtower from the Management category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
containrrr/watchtower:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
watchtower.<your-domain>.
- - Wait for the container health check (
/v1/update) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Watchtower from the Management category.
+ - Fill in the deployment form: subdomain (default suggestion:
watchtower), host port (default: 8089).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/v1/update) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "watchtower",
- "host": "local",
- "subdomain": "watchtower",
- "port": "{{PORT}}",
- "environment": {
- "WATCHTOWER_CLEANUP": "",
- "WATCHTOWER_SCHEDULE": "",
- "WATCHTOWER_HTTP_API_METRICS": "",
- "WATCHTOWER_HTTP_API_TOKEN": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "watchtower",
+ "config": {
+ "subdomain": "watchtower",
+ "port": 8089
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Watchtower on my home host and expose it at watchtower.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Watchtower on my home host and expose it at watchtower.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Watchtower checks for image updates daily at 4 AM by default
- - Customize schedule via WATCHTOWER_SCHEDULE (cron format)
- - Add labels to exclude specific containers from updates
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull containrrr/watchtower:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Watchtower checks for image updates daily at 4 AM by default
+ - Customize schedule via WATCHTOWER_SCHEDULE (cron format)
+ - Add labels to exclude specific containers from updates
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/var/run/docker.sock:/var/run/docker.sock
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ WATCHTOWER_CLEANUP
+ WATCHTOWER_SCHEDULE
+ WATCHTOWER_HTTP_API_METRICS
+ WATCHTOWER_HTTP_API_TOKEN
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /var/run/docker.sock:/var/run/docker.sock
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull containrrr/watchtower:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- WATCHTOWER_CLEANUP
- WATCHTOWER_SCHEDULE
- WATCHTOWER_HTTP_API_METRICS
- WATCHTOWER_HTTP_API_TOKEN
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull containrrr/watchtower:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Watchtower → Update.
-
- Backups
- The config volume for Watchtower is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Watchtower:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Watchtower is in the Management category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: watchtower. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Watchtower:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/v1/update is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: watchtower. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/weather/page.tsx b/src/app/docs/catalog/weather/page.tsx
index ac22799..c533663 100644
--- a/src/app/docs/catalog/weather/page.tsx
+++ b/src/app/docs/catalog/weather/page.tsx
@@ -16,110 +16,110 @@ export default function weatherDocsPage() {
intro="Live weather widget with temperature, conditions, and wind"
>
- Category: Utilities
- Difficulty: Easy
- Docker image: N/A
-
+ Category: Utilities
+ Difficulty: Easy
+ Docker image: N/A
+
- What is Weather?
- Live weather widget with temperature, conditions, and wind
- Weather ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Weather, not installing it.
+What is Weather?
+Live weather widget with temperature, conditions, and wind
+Weather ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Weather, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Weather from the Utilities category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
N/A image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
weather.<your-domain>.
- - Wait for the container health check (
/healthz) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Weather from the Utilities category.
+ - Fill in the deployment form: subdomain (default suggestion:
weather), host port (default: 32400).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/healthz) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "weather",
- "host": "local",
- "subdomain": "weather",
- "port": "{{PORT}}",
-
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "weather",
+ "config": {
+ "subdomain": "weather",
+ "port": 32400
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Weather on my home host and expose it at weather.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Weather on my home host and expose it at weather.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Click the gear icon on the widget to set your ZIP code
- - Weather appears in the top bar next to the logo
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull N/A and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Click the gear icon on the widget to set your ZIP code
+ - Weather appears in the top bar next to the logo
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
-
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Environment variables
+None. The container runs with its upstream defaults.
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Environment variables
- None. The container runs with its upstream defaults.
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull N/A.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Updating
- DashCaddy's built-in Watchtower integration will pull N/A every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Weather → Update.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Backups
- The config volume for Weather is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Weather:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Weather is in the Utilities category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: weather. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Weather:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/healthz is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: weather. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/whoami/page.tsx b/src/app/docs/catalog/whoami/page.tsx
index 76b88cb..0e0e0f1 100644
--- a/src/app/docs/catalog/whoami/page.tsx
+++ b/src/app/docs/catalog/whoami/page.tsx
@@ -16,110 +16,110 @@ export default function whoamiDocsPage() {
intro="Simple HTTP request debugging service"
>
- Category: Utilities
- Difficulty: Easy
- Docker image: traefik/whoami:latest
-
+ Category: Utilities
+ Difficulty: Easy
+ Docker image: traefik/whoami:latest
+
- What is Whoami?
- Simple HTTP request debugging service
- Whoami ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using Whoami, not installing it.
+What is Whoami?
+Simple HTTP request debugging service
+Whoami ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Whoami, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select Whoami from the Utilities category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
traefik/whoami:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
whoami.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick Whoami from the Utilities category.
+ - Fill in the deployment form: subdomain (default suggestion:
whoami), host port (default: 8094).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "whoami",
- "host": "local",
- "subdomain": "whoami",
- "port": "{{PORT}}",
-
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "whoami",
+ "config": {
+ "subdomain": "whoami",
+ "port": 8094
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy Whoami on my home host and expose it at whoami.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy Whoami on my home host and expose it at whoami.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Useful for testing reverse proxy setup
- - Shows request headers and info
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull traefik/whoami:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Useful for testing reverse proxy setup
+ - Shows request headers and info
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/whoami/config:/config
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+None. The container runs with its upstream defaults.
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/whoami/config:/config
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull traefik/whoami:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- None. The container runs with its upstream defaults.
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull traefik/whoami:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → Whoami → Update.
-
- Backups
- The config volume for Whoami is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with Whoami:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- Whoami is in the Utilities category. Common pairings:
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: whoami. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with Whoami:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: whoami. Source: dashcaddy-api/src/docker/app-templates.js.
+
diff --git a/src/app/docs/catalog/wireguard/page.tsx b/src/app/docs/catalog/wireguard/page.tsx
index 51d2a2a..940da07 100644
--- a/src/app/docs/catalog/wireguard/page.tsx
+++ b/src/app/docs/catalog/wireguard/page.tsx
@@ -16,124 +16,118 @@ export default function wireguardDocsPage() {
intro="Fast, modern, secure VPN tunnel"
>
- Category: Networking
- Difficulty: Advanced
- Docker image: linuxserver/wireguard:latest
-
+ Category: Networking
+ Difficulty: Advanced
+ Docker image: linuxserver/wireguard:latest
+
- What is WireGuard VPN?
- Fast, modern, secure VPN tunnel
- WireGuard VPN ships as a self-contained Docker image that DashCaddy provisions with one click. The platform handles the container lifecycle, DNS, reverse proxy, HTTPS certificate, and persistent storage so you can focus on using WireGuard VPN, not installing it.
+What is WireGuard VPN?
+Fast, modern, secure VPN tunnel
+WireGuard VPN ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using WireGuard VPN, not installing it.
- Prerequisites
-
- - A running DashCaddy host with the dashboard accessible.
- - No special host paths required.
-
- - If you want a stable subdomain: Technitium DNS recommended (otherwise DashCaddy will use direct IP access).
-
+Prerequisites
+
+ - A running DashCaddy host with the dashboard accessible (default URL:
https://status.sami; configurable via the dashboardHost setting in config.json).
+ - You must be signed in to the dashboard with an admin session, or have an API key with admin scope (
POST /api/v1/auth/keys to create one).
+ - No special host paths required.
+ - For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.
+
- Install via the DashCaddy dashboard
-
- - Sign in at
https://status.sami (or your host's dashboard URL).
- - Open Apps → Catalog and select WireGuard VPN from the Networking category.
- - Choose your host (or pick Local if you have one host).
- - Fill in any required fields (notably the media library path and any claim token).
- - Click Deploy. DashCaddy will:
-
- - Pull the
linuxserver/wireguard:latest image.
- - Create persistent volumes for config and data.
- - Reserve a host port and wire it through Caddy.
- - Issue a Let's Encrypt certificate for
vpn.<your-domain>.
- - Wait for the container health check (
/) to pass.
-
-
- - After ~30–60 seconds the dashboard will turn the row Running and the URL will become clickable.
-
+Install via the DashCaddy dashboard
+
+ - Sign in at
https://status.sami (or your host's dashboard URL).
+ - Click the 📱 App Selector button on the dashboard home page.
+ - Pick WireGuard VPN from the Networking category.
+ - Fill in the deployment form: subdomain (default suggestion:
vpn), host port (default: 51820).
+ - Click Deploy. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (
/) to pass.
+ - When the dashboard shows the service as Running, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with
{success, containerId, url, message, setupInstructions} — there is no separate status-poll endpoint; the dashboard updates live.
+
- Install via the REST API
- If you script deployments or use the MCP / AI Intent Router, install with:
- curl -X POST https://your-dashcaddy-host/api/v1/apps/deploy \\
- -H "Authorization: Bearer $DASHCADDY_API_TOKEN" \\
+Install via the REST API
+Authenticate with an API key (or a JWT minted via POST /api/v1/auth/jwt). Send as X-API-Key: dk_... or Authorization: Bearer <jwt>.
+curl -X POST https://status.sami/api/v1/apps/deploy \\
+ -H "X-API-Key: dk_your_api_key" \\
-H "Content-Type: application/json" \\
-d '{
- "template": "wireguard",
- "host": "local",
- "subdomain": "vpn",
- "port": "{{PORT}}",
- "environment": {
- "PUID": "",
- "PGID": "",
- "TZ": "",
- "SERVERURL": "",
- "SERVERPORT": "",
- "PEERS": ""
- },
- "labels": { "managed-by": "dashcaddy" }
+ "appId": "wireguard",
+ "config": {
+ "subdomain": "vpn",
+ "port": 51820
+ }
}'
- Response returns a deployment ID. Poll GET /api/v1/apps/{id}/status until state === "running".
+The full body schema is in src/utilities/validate.js (Joi schema appDeploy). All config.* fields except subdomain are optional. Notable options:
+
+ config.port — host port (1–65535). Defaults to the template's defaultPort.
+ config.mediaPath — host directory to mount as the media library.
+ config.plexClaimToken — Plex claim token (when the upstream service needs one).
+ config.useExisting: true + existingContainerId — attach DashCaddy metadata to an already-running container instead of pulling a new image.
+ config.tailscaleOnly: true — restrict the reverse-proxy entry to your Tailscale network.
+ config.allowedIPs — array of CIDR ranges allowed past the reverse proxy.
+ config.createDns: false — skip DNS record creation (use when the subdomain already resolves).
+ config.resources — {memory, cpus} limits applied to the container.
+
- Install via the AI Intent Router
- From any chat surface wired to DashCaddy's MCP server, just say:
-
- "Deploy WireGuard VPN on my home host and expose it at vpn.sami"
-
- The Intent Router will pick the right template, prompt you for any missing fields, and start the deployment.
+Install via the AI Intent Router (returns a structured intent)
+The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:
+curl -X POST https://status.sami/api/v1/ai/intent \\
+ -H "X-API-Key: dk_your_api_key" \\
+ -H "Content-Type: application/json" \\
+ -d '{ "message": "Deploy WireGuard VPN on my home host and expose it at vpn.sami" }'
+The response includes intent, action, parameters, and followup — your client (or the MCP server) must then call POST /api/v1/apps/deploy with those parameters to actually provision the container.
- Post-install: first-run checklist
-
- - Configure your external IP/domain
- - Set up port forwarding on router
- - Download client configs from /config/peer1/
-
+Install via the MCP Server
+For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (src/mcp/mcp-server.js) with:
+DASHCADDY_URL=https://status.sami:3001 # internal API URL, may differ from dashboard URL
+DASHCADDY_API_KEY=dk_your_api_key
+The server exposes dashcaddy_deploy_app. Note: this tool writes the Caddy route and creates the services.json entry, but it does NOT pull the Docker image or start the container. You must run docker pull linuxserver/wireguard:latest and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call POST /api/v1/apps/deploy directly from your agent.
+Post-install: first-run checklist
+
+ - Configure your external IP/domain
+ - Set up port forwarding on router
+ - Download client configs from /config/peer1/
+
+Volumes and persistent data
+DashCaddy creates these volume mounts in the container spec:
+
+/opt/wireguard/config:/config
+
+All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass config.useExisting: false AND wipe the volume. Bind mounts use the host-path conventions above (e.g. /opt/plex/config becomes a bind mount to the host directory of the same path).
+Environment variables
+
+ PUID
+ PGID
+ TZ
+ SERVERURL
+ SERVERPORT
+ PEERS
+
These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in dashcaddy-api/src/docker/app-templates.js.
- Volumes and persistent data
- DashCaddy creates these volume mounts:
-
- /opt/wireguard/config:/config
-
- All paths are absolute host paths; the left side is the container-side mount. Restarting the container never deletes the data; reinstalling the template preserves it unless you explicitly check Wipe data on the deploy form.
+Updating the image
+There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:
+
+ - SSH into the DashCaddy host and run
docker pull linuxserver/wireguard:latest.
+ - Restart the container:
docker restart <containerId> (find the ID via GET /api/v1/services or the dashboard).
+ - Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule
0 0 4 * * * = 04:00 daily).
+
- Environment variables
- PUID
- PGID
- TZ
- SERVERURL
- SERVERPORT
- PEERS
- Override any of these from the deploy form's Environment panel, or programmatically in the API environment object.
+Backups
+The default backup policy includes the entire /app/data/ directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via backup-config.json — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call POST /api/v1/apps/{appId}/restore with a backup ID from GET /api/v1/backups/history.
- Updating
- DashCaddy's built-in Watchtower integration will pull linuxserver/wireguard:latest every 24 hours and restart your container with zero downtime if the image digest changes. To force an update immediately, click Apps → WireGuard VPN → Update.
-
- Backups
- The config volume for WireGuard VPN is included in DashCaddy's default nightly snapshot. To restore on a fresh host, redeploy the same template and DashCaddy will prompt to restore from the most recent snapshot during install.
-
- Troubleshooting
- Common issues with WireGuard VPN:
-
- - Container won't start: check the dashboard's Logs tab. Most startup failures are permission errors on the media/config volume.
-
-
- - Slow first scan: expected for large libraries on first run. Subsequent restarts are fast.
-
- For layer-by-layer diagnostics, see the Troubleshooting guide.
-
- Related services
- WireGuard VPN is in the Networking category. Common pairings:
-
- - Pi-hole (private DNS)
- - Technitium DNS
-
-
-
-
- Last reviewed against DashCaddy product version in dashcaddy-api/src/docker/app-templates.js.
- Template ID: wireguard. If anything here looks wrong, edit the file and the change will appear in the next docs rebuild.
-
+Troubleshooting
+Common issues with WireGuard VPN:
+
+ - Container won't start: check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.
+ - URL not reachable after deploy: the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check
GET /api/v1/dns/records and systemctl status caddy on the host.
+ - Health check timeout (deploy returns 30s after start): the container is starting but
/ is not returning 200. Inspect docker logs <containerId> directly.
+
+For layer-by-layer diagnostics, see the Troubleshooting guide.
+
+
+Template ID: wireguard. Source: dashcaddy-api/src/docker/app-templates.js.
+