DashCaddy Polish Loop 83d7c65bf2 fix(exec): scope-based authorization + tighten containerId charset (DC-072) [glm-grade=A]
Pre-fix, dashcaddy-api/routes/exec.js (the ws://host/ws/exec/:containerId
WebSocket container terminal endpoint) captured auth.scope at lines 39/46
but never enforced it — any API key or JWT, regardless of scope, got a
full PTY-backed shell inside the running container. A key issued with
scope ['read'] (a legitimate monitoring/observability scope) could
escalate to a root-equivalent shell. Container exec is full root inside
the container's user namespace, so this was a privilege-escalation across
the auth trust boundary.

Fix:
1. assertExecScope(auth) requires scope.includes('admin'); throws a
   tagged 403 error (DC-072_INSUFFICIENT_SCOPE) on rejection with
   requiredScope + actualScope in the envelope.
2. Called BEFORE wss.handleUpgrade so the WS gate cannot be bypassed.
3. 403 over the upgrade socket is JSON (code, requiredScope, actualScope)
   so the dashboard can show operator-actionable messages.
4. isValidContainerId(id) tightened to Docker's actual charset
   (12 or 64 lowercase hex). Pre-fix regex accepted _, -, ., mixed
   case, and any length up to 128; Docker would 404 the inspect and the
   rejection surfaced as a generic 500.
5. Audit-log pair: session start (container name + auth id) and session
   end with durationMs + reason ('exec-stream-end' vs 'ws-close'
   for abnormal disconnects); idempotent via ended-flag guard.
6. Both helpers exported via __test for unit tests (no live WS).

Tests: 20 new tests in __tests__/routes/exec.routes.test.js cover:
- assertExecScope: admin passes; read/write/empty/undefined/null/non-array
  rejected with the canonical 403 envelope.
- isValidContainerId: 12/64 lowercase hex accepted; uppercase / mixed /
  non-hex / _.- / wrong length / null / non-string / padded / CRLF
  payload rejected.

Full suite: 2327/2327 tests passing across 100 suites (zero regressions).

GLM-5.3 round 1: A with 2 LOW polish (scope-coercion defensive comment +
abnormal-close audit-log fallback). Both folded into the same commit.
Round 2: A. Ship.
2026-08-18 14:53:57 -07:00
2026-03-05 02:26:12 -08:00

DashCaddy

Self-hosted dashboard for managing Docker apps with automatic SSL, DNS, and reverse proxy configuration.

Version License

What is DashCaddy?

DashCaddy is an all-in-one solution for self-hosting Docker applications. It combines:

  • 🎨 Beautiful Dashboard - Monitor all your services in one place
  • 🐳 Docker Management - Deploy 50+ pre-configured apps with one click
  • 🔒 Automatic SSL - Internal CA with automatic certificate generation
  • 🌐 DNS Integration - Automatic DNS record creation (Technitium DNS)
  • 🔄 Reverse Proxy - Caddy configuration managed automatically
  • 🔐 Tailscale Support - Secure remote access built-in

Features

Authentication & Security

  • Built-in TOTP two-factor authentication
  • Fine-grained access control per service
  • Secure session management
  • Group-based permissions

Dashboard

  • Real-time service health monitoring
  • Response time tracking
  • Status indicators with visual feedback
  • Weather widget
  • Multiple themes (dark/light/blue)
  • Import/export configuration

App Deployment

  • 50+ pre-configured app templates
  • One-click deployment
  • Automatic DNS + SSL + reverse proxy setup
  • Container health checking
  • Deployment status tracking
  • SSL certificate generation monitoring

Service Management

  • Add/edit/delete services
  • Restart containers
  • View logs
  • Update configurations
  • Silent deletions (no annoying popups)

Developer Tools

  • Error log viewer
  • API endpoints for automation
  • Import/export for testing
  • Comprehensive error logging

Quick Start

Prerequisites

  • Docker & Docker Compose
  • Caddy web server
  • Technitium DNS (optional, for automatic DNS)
  • Node.js 18+ (for API server)

Installation

  1. Clone the repository
git clone https://github.com/yourusername/dashcaddy.git
cd dashcaddy
  1. Install dependencies
cd caddy-api
npm install
  1. Configure environment
cp .env.example .env
# Edit .env with your settings
  1. Start the API server
npm start
  1. Configure Caddy Add to your Caddyfile:
status.yourdomain.com {
    root * /path/to/dashcaddy/status
    file_server
    reverse_proxy /api/* localhost:3001
}
  1. Access the dashboard Open https://status.yourdomain.com in your browser

Health Probes

DashCaddy exposes Kubernetes/Docker-standard health endpoints for container orchestration. No auth required — these are designed for orchestration tooling to poll.

Path Purpose Returns
/healthz or /health/live Liveness — is the Node.js process alive? 200 with {status: "alive", uptime: <seconds>}
/readyz or /health/ready Readiness — are critical deps reachable? (config file, services file, Docker daemon, Caddy admin API) 200 if all OK, 503 if any dep fails (with details in the checks object)
/health Backwards-compat alias for /healthz Same as /healthz

When to use which:

  • Use /healthz / /health/live in a livenessProbe — should the container be restarted?
  • Use /readyz / /health/ready in a readinessProbe — should traffic be routed to this instance?

Docker Compose healthcheck

Copy-paste this into your DashCaddy docker-compose.yml:

services:
  dashcaddy-api:
    image: ghcr.io/samiahmed7777/dashcaddy-api:latest
    # ... your existing config ...
    healthcheck:
      test: ["CMD", "node", "-e", "require('http').get('http://localhost:3001/readyz', r => process.exit(r.statusCode === 200 ? 0 : 1)).on('error', () => process.exit(1))"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 30s

Kubernetes probes

livenessProbe:
  httpGet:
    path: /healthz
    port: 3001
  initialDelaySeconds: 30
  periodSeconds: 30
readinessProbe:
  httpGet:
    path: /readyz
    port: 3001
  initialDelaySeconds: 10
  periodSeconds: 10

Both endpoints return JSON. Liveness is cheap (no I/O, no deps). Readiness touches the Docker daemon and Caddy admin API with a 3-second timeout each, so it's safe to poll every 10s without load concerns.

Configuration

Environment Variables

Create a .env file in the caddy-api directory:

# Caddy Configuration
CADDYFILE_PATH=/path/to/Caddyfile
CADDY_ADMIN_URL=http://localhost:2019

# DNS Configuration (optional)
DNS_SERVER=192.168.1.1
DNS_TOKEN=your-dns-token

# File Paths
SERVICES_FILE=/path/to/services.json
ERROR_LOG_FILE=/path/to/dashcaddy-errors.log

DNS Integration

DashCaddy works with Technitium DNS for automatic DNS record creation:

  1. Install Technitium DNS
  2. Create an API token with DNS management permissions
  3. Configure DNS credentials in dashboard (🔑 Tokens button)

Tailscale Integration

For secure remote access:

  1. Install Tailscale on your server
  2. Services can be restricted to Tailscale-only access
  3. Configure in deployment settings

Usage

Deploying an App

  1. Click "App Selector" button
  2. Choose an app from the template library
  3. Configure:
    • Subdomain (e.g., jellyfinjellyfin.yourdomain.com)
    • Port (auto-suggested)
    • IP address (defaults to localhost)
    • Tailscale-only access (optional)
  4. Click "Deploy"
  5. Wait for SSL certificate generation (30-60 seconds)
  6. Access your app!

Managing Services

  • View Status: Cards show real-time health and response times
  • Open Service: Click "Open" button
  • Restart: Click restart button (for Docker containers)
  • Delete: Click delete button (removes everything: container, DNS, Caddy config)
  • Edit: Click settings button to modify configuration

Viewing Error Logs

  1. Click "📋 Logs" button in toolbar
  2. View all errors with timestamps and context
  3. Refresh to see latest errors
  4. Clear logs when resolved

Backup & Restore

Export Configuration:

  1. Click "📤 Export" button
  2. JSON file downloads with all your services
  3. Save safely

Import Configuration:

  1. Click "📥 Import" button
  2. Select your backup JSON file
  3. Confirm import
  4. Dashboard reloads with restored configuration

Note: API tokens are not exported for security. Reconfigure after import.

App Templates

DashCaddy includes 50+ pre-configured templates:

Media & Entertainment

  • Plex, Jellyfin, Emby
  • Navidrome, Airsonic
  • Tautulli, Overseerr

Downloads

  • Sonarr, Radarr, Lidarr, Readarr
  • Prowlarr, Bazarr
  • qBittorrent, Transmission
  • SABnzbd, NZBGet

Productivity

  • Nextcloud
  • Paperless-ngx
  • BookStack, Outline
  • Standard Notes

Management

  • Portainer
  • Homepage, Homarr
  • Uptime Kuma
  • Grafana

Security & Authentication

  • Vaultwarden (Password Manager)

Development

  • Gitea
  • VS Code Server
  • Jenkins, Drone CI

And many more!

API Endpoints

Services

  • GET /api/services - List all services
  • POST /api/services - Add service
  • PUT /api/services - Bulk import services
  • DELETE /api/services/:id - Remove service

App Deployment

  • GET /api/apps/templates - List app templates
  • POST /api/apps/deploy - Deploy new app
  • DELETE /api/apps/:id - Remove deployed app

Error Logs

  • GET /api/error-logs - Get error logs
  • DELETE /api/error-logs - Clear error logs

DNS Management

  • POST /api/dns/record - Create DNS record
  • DELETE /api/dns/record - Delete DNS record

Caddy Management

  • GET /api/caddy/config - Get Caddyfile content
  • POST /api/caddy/reload - Reload Caddy configuration

Troubleshooting

SSL Certificate Errors

Problem: "Secure Connection Failed" when accessing new service

Solution:

  • Wait 30-60 seconds for certificate generation
  • Check dashboard notification for SSL status
  • Manually reload Caddy: caddy reload --config /path/to/Caddyfile
  • Check error logs in dashboard

DNS Not Resolving

Problem: Service URL doesn't resolve

Solution:

  • Verify DNS server is running
  • Check DNS credentials in 🔑 Tokens menu
  • Manually add DNS record in Technitium DNS
  • Flush DNS cache: ipconfig /flushdns (Windows) or sudo systemd-resolve --flush-caches (Linux)

Container Won't Start

Problem: Deployment succeeds but service is offline

Solution:

  • Check Docker logs: docker logs [container-id]
  • Verify port isn't already in use
  • Check container resource limits
  • View error logs in dashboard

Import/Export Issues

Problem: Import fails or data is incomplete

Solution:

  • Validate JSON format
  • Check file has version and services fields
  • Reconfigure API tokens after import
  • Check error logs for details

Development

Project Structure

dashcaddy/
├── status/                 # Dashboard frontend
│   ├── index.html         # Main dashboard
│   └── assets/            # Logos, icons, fonts
├── caddy-api/             # API backend
│   ├── server.js          # Express server
│   ├── app-templates.js   # App template definitions
│   └── package.json       # Dependencies
├── dashcaddy-installer/   # Electron installer (WIP)
└── docs/                  # Documentation

Adding Custom App Templates

Edit caddy-api/app-templates.js:

"myapp": {
  name: "My App",
  description: "Description of my app",
  icon: "🚀",
  logo: "https://cdn.example.com/logo.png",
  category: "Productivity",
  docker: {
    image: "myapp/myapp:latest",
    ports: ["{{PORT}}:8080"],
    volumes: ["/opt/myapp:/data"],
    environment: {
      "APP_ENV": "production"
    }
  },
  subdomain: "myapp",
  defaultPort: 8080,
  healthCheck: "/health"
}

Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Test thoroughly
  5. Submit a pull request

Roadmap

  • Service groups/categories
  • Container log viewer
  • DNS management UI
  • Backup automation
  • Multi-user support
  • Mobile app
  • Analytics dashboard
  • Template marketplace

License

Proprietary software. All rights reserved. See LICENSE for the End-User License Agreement (EULA).

Credits

Support

Acknowledgments

Built with ❤️ for the self-hosting community.


DashCaddy - Making self-hosting beautiful and effortless.

S
Description
DashCaddy — self-hosted Docker/DNS/Caddy dashboard
Readme
36 MiB
2026-09-01 13:00:36 +02:00
Languages
JavaScript 88.9%
HTML 4.1%
Shell 3.9%
CSS 2.7%
PowerShell 0.3%