{"id":47695323,"url":"https://github.com/bogdanpricop/docker-dash","last_synced_at":"2026-06-17T21:01:17.651Z","repository":{"id":347314653,"uuid":"1193358915","full_name":"bogdanpricop/docker-dash","owner":"bogdanpricop","description":"Self-hosted Docker management dashboard — runs standalone (zero deps) or in HA mode (Redis). In-app observability wizard (Prometheus+Grafana). Multi-host SSH/TCP, Trivy+Grype+Scout vuln scan, GitOps+Webhooks, RBAC+MFA+LDAP, Docker Swarm, CIS Benchmark, audit log, 11 languages. ~50MB RAM.","archived":false,"fork":false,"pushed_at":"2026-06-16T07:59:49.000Z","size":22110,"stargazers_count":6,"open_issues_count":9,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-06-16T09:28:08.988Z","etag":null,"topics":["container","container-management","dashboard","devops","docker","docker-management","gitops","grafana","high-availability","nodejs","observability","portainer-alternative","prometheus","rbac","redis","sandbox","self-hosted","sqlite","vanilla-js","vulnerability-scanning"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bogdanpricop.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-27T06:15:44.000Z","updated_at":"2026-06-16T07:59:55.000Z","dependencies_parsed_at":"2026-04-05T23:01:40.146Z","dependency_job_id":null,"html_url":"https://github.com/bogdanpricop/docker-dash","commit_stats":null,"previous_names":["bogdanpricop/docker-dash"],"tags_count":109,"template":false,"template_full_name":null,"purl":"pkg:github/bogdanpricop/docker-dash","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bogdanpricop%2Fdocker-dash","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bogdanpricop%2Fdocker-dash/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bogdanpricop%2Fdocker-dash/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bogdanpricop%2Fdocker-dash/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bogdanpricop","download_url":"https://codeload.github.com/bogdanpricop/docker-dash/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bogdanpricop%2Fdocker-dash/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34465322,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-17T02:00:05.408Z","response_time":127,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["container","container-management","dashboard","devops","docker","docker-management","gitops","grafana","high-availability","nodejs","observability","portainer-alternative","prometheus","rbac","redis","sandbox","self-hosted","sqlite","vanilla-js","vulnerability-scanning"],"created_at":"2026-04-02T16:23:01.930Z","updated_at":"2026-06-17T21:01:17.632Z","avatar_url":"https://github.com/bogdanpricop.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003ch1 align=\"center\"\u003e🐳 Docker Dash\u003c/h1\u003e\n  \u003cp align=\"center\"\u003e\n    A full-featured Docker management dashboard that runs in two modes:\u003cbr\u003e\n    \u003cstrong\u003eStandalone\u003c/strong\u003e for homelab and small teams · \u003cstrong\u003eHA\u003c/strong\u003e for corporate always-on deploys.\u003cbr\u003e\n    Same codebase, same binary, zero vendor lock-in.\n  \u003c/p\u003e\n  \u003cp align=\"center\"\u003e\n    \u003ca href=\"https://github.com/bogdanpricop/docker-dash/actions/workflows/ci.yml\"\u003e\u003cimg src=\"https://github.com/bogdanpricop/docker-dash/actions/workflows/ci.yml/badge.svg\" alt=\"CI\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/bogdanpricop/docker-dash/releases/latest\"\u003e\u003cimg src=\"https://img.shields.io/github/v/release/bogdanpricop/docker-dash?color=blue\" alt=\"Release\"\u003e\u003c/a\u003e\n    \u003ca href=\"LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/github/license/bogdanpricop/docker-dash\" alt=\"License\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/bogdanpricop/docker-dash/actions/workflows/ci.yml\"\u003e\u003cimg src=\"https://img.shields.io/badge/tests-1398%20passing%20(100%25)-brightgreen\" alt=\"Tests\"\u003e\u003c/a\u003e\n    \u003cimg src=\"https://img.shields.io/badge/version-8.2.0-blue\" alt=\"Version\"\u003e\n    \u003ca href=\"SECURITY.md#security-audit-history\"\u003e\u003cimg src=\"https://img.shields.io/badge/production%20readiness-9.9%2F10-brightgreen\" alt=\"Production Readiness\"\u003e\u003c/a\u003e\n    \u003ca href=\"SECURITY.md\"\u003e\u003cimg src=\"https://img.shields.io/badge/security-audited-brightgreen\" alt=\"Security Audited\"\u003e\u003c/a\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Docker-~180MB-blue\" alt=\"Image Size\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/RAM-~50MB-blue\" alt=\"RAM Usage\"\u003e\n  \u003c/p\u003e\n  \u003cp align=\"center\"\u003e\n    \u003ca href=\"#deployment-modes\"\u003e\u003cstrong\u003eDeployment modes\u003c/strong\u003e\u003c/a\u003e \u0026bull;\n    \u003ca href=\"#target-audience\"\u003eTarget audience\u003c/a\u003e \u0026bull;\n    \u003ca href=\"#quick-start\"\u003eQuick Start\u003c/a\u003e \u0026bull;\n    \u003ca href=\"#features\"\u003eFeatures\u003c/a\u003e \u0026bull;\n    \u003ca href=\"#screenshots\"\u003eScreenshots\u003c/a\u003e \u0026bull;\n    \u003ca href=\"#comparison\"\u003eComparison\u003c/a\u003e \u0026bull;\n    \u003ca href=\"#troubleshooting-install\"\u003eTroubleshooting\u003c/a\u003e \u0026bull;\n    \u003ca href=\"#contributing\"\u003eContributing\u003c/a\u003e\n  \u003c/p\u003e\n  \u003cp align=\"center\"\u003e\n    \u003ca href=\"https://github.com/bogdanpricop/docker-dash/discussions\"\u003e💬 Discussions\u003c/a\u003e \u0026bull;\n    \u003ca href=\"https://github.com/bogdanpricop/docker-dash/issues\"\u003e🐞 Issues\u003c/a\u003e \u0026bull;\n    \u003ca href=\"https://github.com/bogdanpricop/docker-dash/releases\"\u003e📦 Releases\u003c/a\u003e \u0026bull;\n    \u003ca href=\"docs/comparisons/\"\u003e⚖️ Comparisons\u003c/a\u003e\n  \u003c/p\u003e\n\u003c/p\u003e\n\n## Deployment modes\n\nDocker Dash runs in two modes from a single codebase. Pick based on your needs:\n\n|  | **Standalone** (default) | **HA** (opt-in, v7.0.0+) · **Observability** (opt-in, v7.1.0+) |\n|---|---|---|\n| **Dependencies** | Just Docker | Docker + Redis + sticky-session load balancer |\n| **Replicas** | 1 | 2–5 (production-validated) |\n| **Failover** | Restart on crash (Docker restart policy) | Automatic — leader lock in Redis, ~30s worst case, milliseconds on graceful restart |\n| **Cross-replica events** | N/A | Redis pub/sub (loop-safe, sub-ms delivery) |\n| **Rate limiter** | In-process sliding window | Redis `INCR` fixed window, shared across replicas |\n| **Sessions** | SQLite (works in both modes) | SQLite (single-writer on leader) |\n| **Best for** | Homelab · dev/staging · SMB · single-office | Corporate dashboards · on-prem K8s · always-on infrastructure panels |\n| **Complexity** | 1 container, zero config beyond `.env` | 3+ containers, LB config, failover runbook |\n| **Operational overhead** | None | Prometheus monitoring recommended (cluster health alerts) |\n\n**`DD_MODE` is the only switch.** Unset (default) = standalone, identical to every prior v6.x release. `DD_MODE=ha` + `REDIS_URL` = HA mode.\n\n**Feature parity:** every feature works in both modes. HA doesn't unlock \"enterprise\" features — it just adds redundancy.\n\n**Fully backwards-compatible.** An existing standalone deployment upgrades to HA without migration, and downgrades back without data loss. Your SQLite volume carries over.\n\nDeep reading: [HA Mode reference](docs/features/ha-mode.md) · [Failover runbook](docs/features/ha-failover-runbook.md) · [LB configs (Caddy/Traefik/HAProxy/nginx)](docs/features/ha-lb-configs.md)\n\n## Target audience\n\n**Good fit for Docker Dash:**\n\n| You are… | Use mode | Why |\n|---|---|---|\n| Homelab enthusiast · self-hosting Plex/*arr/Nextcloud | Standalone | Single-host, simple, no build step, no database to babysit |\n| Small team running a shared dev environment | Standalone (+ `--profile tls` Caddy) | HTTPS + SSO without fighting certificates manually |\n| SMB with 1–3 Docker hosts, shared ops role | Standalone + multi-host SSH tunnel | Manage multiple hosts from one UI, no agent to deploy |\n| NAS user (Synology · Unraid · TrueNAS · QNAP · OMV) | Standalone | Platform auto-detection, tailored How-To guides, works with Container Manager |\n| VPS user (Hetzner · DO · EC2 · GCE · Azure · Linode · Vultr) | Standalone + DMI cloud detection | Cloud vendor badges, generic VPS How-To guide |\n| Corporate team with 99.9% uptime SLA | **HA mode** (2–3 replicas) | Leader election + failover + shared rate limiter + cross-replica WS |\n| On-prem Kubernetes with Docker Dash as internal tool | **HA mode** (StatefulSet, sticky session Ingress) | Survives pod restarts, rolling deploys with no dashboard downtime |\n\n**Not a good fit:**\n\n- **Kubernetes-native production workloads** — use [Rancher](https://rancher.com/) or [Portainer BE](https://www.portainer.io/business) instead. Docker Dash targets the Docker daemon directly; it doesn't manage K8s objects.\n- **Geographic distribution across regions** — SQLite single-writer limits you to same-AZ HA. If you need multi-region active-active, you need a different tool (or wait for a hypothetical Docker Dash Postgres backend, which is not on the roadmap).\n- **Multi-tenant SaaS** — Docker Dash assumes one organization per instance. RBAC works within that instance but there's no tenant isolation layer.\n- **CI/CD pipeline orchestration** — Docker Dash manages running containers, not build pipelines. Use GitHub Actions, GitLab CI, Jenkins, etc. for that. Docker Dash's GitOps feature is for *deploying* from Git, not building.\n- **Image registry** — Docker Dash *uses* registries (Docker Hub, GHCR, GitLab) but is not a registry itself. For self-hosted registry, use [Harbor](https://goharbor.io/) or [distribution/distribution](https://distribution.github.io/distribution/).\n\n## Screenshots\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003cstrong\u003eDashboard (Dark)\u003c/strong\u003e\u003cbr\u003e\u003cimg src=\"docs/screenshots/dashboard.png\" alt=\"Dashboard\" width=\"400\"\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003cstrong\u003eDashboard (Light)\u003c/strong\u003e\u003cbr\u003e\u003cimg src=\"docs/screenshots/dashboard-light.png\" alt=\"Dashboard Light\" width=\"400\"\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003cstrong\u003eContainers\u003c/strong\u003e\u003cbr\u003e\u003cimg src=\"docs/screenshots/containers.png\" alt=\"Containers\" width=\"400\"\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003cstrong\u003eContainer Detail\u003c/strong\u003e\u003cbr\u003e\u003cimg src=\"docs/screenshots/container-detail.png\" alt=\"Container Detail\" width=\"400\"\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003cstrong\u003eTerminal (xterm.js)\u003c/strong\u003e\u003cbr\u003e\u003cimg src=\"docs/screenshots/terminal.png\" alt=\"Terminal\" width=\"400\"\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003cstrong\u003eImages\u003c/strong\u003e\u003cbr\u003e\u003cimg src=\"docs/screenshots/images.png\" alt=\"Images\" width=\"400\"\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003cstrong\u003eVolumes\u003c/strong\u003e\u003cbr\u003e\u003cimg src=\"docs/screenshots/volumes.png\" alt=\"Volumes\" width=\"400\"\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003cstrong\u003eNetworks\u003c/strong\u003e\u003cbr\u003e\u003cimg src=\"docs/screenshots/networks.png\" alt=\"Networks\" width=\"400\"\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003cstrong\u003eMulti-Host Overview\u003c/strong\u003e\u003cbr\u003e\u003cimg src=\"docs/screenshots/multi-host.png\" alt=\"Multi-Host\" width=\"400\"\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003cstrong\u003eStacks\u003c/strong\u003e\u003cbr\u003e\u003cimg src=\"docs/screenshots/stacks.png\" alt=\"Stacks\" width=\"400\"\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003cstrong\u003eSecurity Scanning\u003c/strong\u003e\u003cbr\u003e\u003cimg src=\"docs/screenshots/security.png\" alt=\"Security\" width=\"400\"\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003cstrong\u003eLog Explorer\u003c/strong\u003e\u003cbr\u003e\u003cimg src=\"docs/screenshots/log-explorer.png\" alt=\"Log Explorer\" width=\"400\"\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003cstrong\u003eEvent Timeline\u003c/strong\u003e\u003cbr\u003e\u003cimg src=\"docs/screenshots/timeline.png\" alt=\"Timeline\" width=\"400\"\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003cstrong\u003eNetwork Topology\u003c/strong\u003e\u003cbr\u003e\u003cimg src=\"docs/screenshots/topology.png\" alt=\"Network Topology\" width=\"400\"\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003cstrong\u003eDependency Map\u003c/strong\u003e\u003cbr\u003e\u003cimg src=\"docs/screenshots/dependency-map.png\" alt=\"Dependency Map\" width=\"400\"\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003cstrong\u003eCost Optimizer\u003c/strong\u003e\u003cbr\u003e\u003cimg src=\"docs/screenshots/cost-optimizer.png\" alt=\"Cost Optimizer\" width=\"400\"\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003cstrong\u003eInsights\u003c/strong\u003e\u003cbr\u003e\u003cimg src=\"docs/screenshots/insights.png\" alt=\"Insights\" width=\"400\"\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003cstrong\u003eAlerts\u003c/strong\u003e\u003cbr\u003e\u003cimg src=\"docs/screenshots/alerts.png\" alt=\"Alerts\" width=\"400\"\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003cstrong\u003eSystem Tools\u003c/strong\u003e\u003cbr\u003e\u003cimg src=\"docs/screenshots/system-tools.png\" alt=\"System Tools\" width=\"400\"\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003cstrong\u003eHow-To Guides\u003c/strong\u003e\u003cbr\u003e\u003cimg src=\"docs/screenshots/howto.png\" alt=\"How-To\" width=\"400\"\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003cstrong\u003eFeature Comparison\u003c/strong\u003e\u003cbr\u003e\u003cimg src=\"docs/screenshots/compare.png\" alt=\"Compare\" width=\"400\"\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003cstrong\u003eEnterprise Mode\u003c/strong\u003e\u003cbr\u003e\u003cimg src=\"docs/screenshots/enterprise.png\" alt=\"Enterprise\" width=\"400\"\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003cstrong\u003eAPI Playground\u003c/strong\u003e\u003cbr\u003e\u003cimg src=\"docs/screenshots/api-playground.png\" alt=\"API Playground\" width=\"400\"\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003cstrong\u003eWhat's New\u003c/strong\u003e\u003cbr\u003e\u003cimg src=\"docs/screenshots/whatsnew.png\" alt=\"What's New\" width=\"400\"\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003cstrong\u003eRegistry Browser (v7.5.0–v8.1.0)\u003c/strong\u003e\u003cbr\u003e\u003cimg src=\"docs/screenshots/registry-browse.png\" alt=\"Registry Browser\" width=\"400\"\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003cstrong\u003eObservability Wizard (v7.2.0)\u003c/strong\u003e\u003cbr\u003e\u003cimg src=\"docs/screenshots/observability-wizard.png\" alt=\"Observability Wizard\" width=\"400\"\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003cstrong\u003eAI Audit NL Search (v8.0.0)\u003c/strong\u003e\u003cbr\u003e\u003cimg src=\"docs/screenshots/ai-audit-search.png\" alt=\"AI Audit NL Search\" width=\"400\"\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003cstrong\u003epCloud Backup (v8.2.0)\u003c/strong\u003e\u003cbr\u003e\u003cimg src=\"docs/screenshots/pcloud-backup.png\" alt=\"pCloud Backup\" width=\"400\"\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n## Features\n\n### Core\n- **Container Management** — Start, stop, restart, pause, kill, remove, clone, rename, update/recreate\n- **Image Management** — Pull with streaming progress, remove, tag, import/export, build from Dockerfile\n- **Volume Management** — Create, remove, inspect with real disk usage sizes\n- **Network Management** — Create, remove, connect/disconnect containers, inspect IPAM config\n- **Bulk Actions** — Checkbox selection + floating bar for batch start/stop/restart/remove\n- **One-click Port Access** — Each exposed TCP port shows a clickable link to open `http://host:port` directly\n- **Keyboard Navigation** — Arrow keys to navigate container rows, `r` to restart, `s` to stop/start, `Enter` to open detail, `l` for logs\n- **Live CPU/RAM Mini-bars** — Two 4px color-coded progress bars per running container, updated every 5 seconds\n- **Container File Browser** — Navigate, view, upload, and download files inside running containers\n- **Container Diff** — See filesystem changes vs base image with color-coded entries\n- **Image Picker** — Browse 20 popular images (nginx, postgres, redis, etc.) when creating containers\n- **CIS Hardened Creation** — One-click CIS benchmark hardening: cap_drop ALL, read-only rootfs, no-new-privileges, resource limits\n- **Log Time Filter** — Filter container logs by time range: last 1h, 6h, 24h, 7 days\n\n### Monitoring \u0026 Intelligence\n- **Real-time Dashboard** — Customizable live CPU/memory charts (WebSocket, 10s interval, toggle widgets)\n- **Container Health Score** — Composite 0-100 score with color dots in list view + summary bar\n- **Resource Trends \u0026 Forecasting** — 7-day linear regression with 24h CPU/memory projection\n- **Memory Exhaustion Prediction** — \"will exceed limit in N hours\" warning\n- **Plain-English Status** — Exit codes mapped to messages (137=OOM, 143=SIGTERM, etc.)\n- **Network Topology** — Interactive canvas map with drag, zoom, pan, hover highlighting\n- **Dependency Map** — Interactive graph showing container relationships (env vars, networks, links)\n- **Uptime Reports** — Per-container uptime %, restart count, first/last seen\n- **Cost Optimizer** — Per-container cost breakdown, idle detection, savings recommendations\n- **Image Freshness Dashboard** — Freshness score based on age + vulnerability count\n- **Audit Log Analytics** — Top users, top actions, activity heatmap by hour/day\n- **Notifications Center** — Dedicated page with filters, pagination, bulk mark-read/delete\n\n### Security\n- **Vulnerability Scanning** — Trivy + Grype + Docker Scout with automatic detection and fallback\n- **Safe-Pull Updates** — Pull new image → scan for vulns → only swap if clean (blocks critical CVEs)\n- **Deployment Pipelines** — Staged pull → scan → swap → verify → notify with full history\n- **Security Dashboard** — Scan history, per-image status, AI-assisted remediation prompts\n- **AI Container Doctor** — Diagnostics + 30 log pattern matchers + Ask AI (OpenAI/Ollama) directly from modal\n- **Guided Troubleshooting** — 8-step diagnostic wizard (state, health, logs, ports, volumes, resources)\n- **Container Rollback** — One-click revert to previous image with version history\n- **First-login Setup Wizard** — Forces password change, recommends disabling default admin\n- **Outbound Network Filter** (v6.7) — Per-container egress policy sidecar with TLS-SNI + HTTP-Host peek. Allowlist-based, blocks IMDS by default, logs denied connections. No TLS decryption\n- **Per-container Security tab** (v6.10) — 2×2 grid combining Secrets score, Egress reachability + filter state, CIS findings, and Image Vulnerabilities on every container's detail page\n- **Stack-level Security Audits** (v6.9.3) — One-click Secrets Audit + Egress Audit buttons on every stack, matching Security Scan + CIS Benchmark. Drill down to Fix via Remediation Wizard\n- **Remediation Wizard drill-down** (v6.9.4) — Image-centric security findings now link to running containers using that image, then open Fix scoped to the container\n- **Error-response sanitization** (v6.14.1) — Central error middleware scrubs `/home/` and `/data/` paths, redacts URL credentials, replaces raw error messages with `\"Internal server error\"` on 5xx. Closes an accidental info-leak from the pre-Express-5 try/catch pattern\n\n### Git Integration (GitOps)\n- **Deploy from Git** — Clone repos, select branch, compose file path, deploy with one click\n- **Auto-Deploy** — Webhook receiver (GitHub, GitLab, Gitea, Bitbucket) + polling-based updates\n- **Deployment History** — Full audit trail with commit hash, trigger type, duration, rollback\n- **Diff View** — See exactly what changed before redeploying\n- **Push to Git** — Edit compose in UI, commit and push back to repository\n- **Git Credentials** — Token, basic auth, SSH key (AES-256-GCM encrypted)\n- **Multi-file Compose** — Multiple YAML override files per stack\n- **Environment Overrides** — Per-stack env vars with sensitive value encryption\n\n### Multi-Host\n- **TCP + TLS** — Connect remote Docker hosts over the network with mutual TLS\n- **SSH Tunnel** — Secure tunnel via SSH (no need to expose Docker API). v6.8 adds a full exec / fileExists / readFile / writeFile channel so the Remediation Wizard Apply mode works end-to-end on remote hosts\n- **Docker Desktop** — Connect to Windows/Mac Docker Desktop instances\n- **Podman Compatible** — Works with Podman via Docker-compatible API socket\n- **Host Selector** — Switch between hosts from the sidebar dropdown\n- **NAS support** (v6.12) — Auto-detects Synology DSM, Unraid, TrueNAS SCALE, QNAP QTS/QuTS hero, OpenMediaVault from `docker info`. No SSH probes, no SDKs. Dedicated per-platform How-To guides cover the platform-specific quirks (Container Manager socket, User Home Service, ix-* managed containers, variable QTS socket path, omv-extras Docker plugin, etc.)\n- **Cloud vendor badges** (v6.12.1) — Optional DMI probe (`/sys/class/dmi/id/sys_vendor` + `product_name`) identifies AWS EC2, Google Cloud, Azure VM, DigitalOcean, Hetzner, Linode, Vultr, Oracle Cloud, Scaleway, OVHcloud, plus on-prem hypervisors (VMware, VirtualBox, KVM/QEMU, Xen, Parallels). Renders as a second colored pill on the Multi-Host card\n\n### Operations\n- **Stacks Page** — Unified Compose + Git stacks management with actions (up/down/restart/pull)\n- **Docker Swarm Mode** — Full UI for Nodes, Services, Tasks; init/leave swarm, scale services, drain nodes, join tokens\n- **Docker Compose Editor** — Edit, validate, save \u0026 deploy compose configs inline\n- **Terminal** — Full xterm.js terminal with shell selection (`sh`, `bash`, `zsh`, `ash`)\n- **Alerts** — CPU/memory threshold rules with 7 notification channels\n- **Notifications** — Discord, Slack, Telegram, Ntfy, Gotify, Email (SMTP), Custom Webhook\n- **Workflow Automation** — IF-THEN rules (CPU high → restart, container crash → notify, etc.)\n- **Scheduled Actions** — Cron-based container actions with presets, history, run-now, enable/disable\n- **Maintenance Windows** — Scheduled pull/scan/update with block-on-critical\n- **Firewall** — View and manage UFW rules (Linux)\n- **Container Groups** — User-defined grouping with colors, beyond Docker Compose projects\n\n### Sandbox Mode\n- **Ephemeral Sandbox** — Launch a container with auto-delete on stop + optional TTL (30m / 1h / 4h); perfect for testing images risk-free\n- **Persistent Sandbox** — Isolated container with resource limits that survives stop/restart\n- **Project Source (GitHub)** — Paste a GitHub repo URL; Docker Dash downloads the tarball, auto-detects the tech stack (Node/Python/Go/Ruby/static), installs dependencies, and starts the app\n- **Project Source (Upload)** — Upload a .tar/.tar.gz archive; same auto-detect + auto-run flow\n- **Auto-detect Stack** — Recognizes package.json, requirements.txt, go.mod, Gemfile, index.html and selects the right base image (node:20-alpine, python:3.12-alpine, etc.)\n- **Security Defaults** — Sandbox containers run with `no-new-privileges`, dedicated internal `dd-sandbox` network, resource limits, restart: no\n- **TTL Auto-cleanup** — Background timer removes expired sandboxes every 30 seconds with WebSocket notification\n- **Visual Badges** — `EPHEMERAL` (red + countdown) or `SANDBOX` (yellow) badges in containers list, detail card with Extend +1h / Remove buttons\n\n### Developer Tools\n- **API Playground** — Browse and test 450+ API endpoints from the UI with response viewer\n- **docker run → Compose** — Paste any docker run command, get docker-compose YAML\n- **Dual AI Provider** — Container Doctor supports OpenAI API and local Ollama; provider/model/key selector + inline response\n- **AI Log Analysis** — Generate diagnostic prompts for ChatGPT/Claude from container logs\n- **Generate Compose from GitHub** — Paste a public repo URL, AI (OpenAI or Ollama) generates a production-ready docker-compose.yml\n- **Traefik/Caddy Labels** — Generate reverse proxy labels from domain + port\n- **App Templates** — 47 built-in + custom templates with CRUD, preview, Template Configurator and modification tracking. **AI Workload Pack** (v8.0.1): 12 curated AI/ML templates — Ollama, Open WebUI, RAG stack (Ollama+Qdrant+Open WebUI), vLLM, Stable Diffusion WebUI, ComfyUI, Whisper, Langflow, AnythingLLM, n8n, LiteLLM Proxy, Flowise (GPU passthrough block ready, commented for CPU compat)\n- **Image Layer Visualization** — View all layers of any image with command, size, and relative-size bar per layer\n- **Deploy Preview** — Check for image updates via digest comparison before pulling\n- **Resource Limits Editor** — Visual sliders with presets for CPU and memory\n- **Resource Recommendations** — Smart advice: over-provisioned, memory pressure, idle containers\n\n### Security \u0026 Compliance\n- **Enterprise Security Mode** — `SECURITY_MODE=strict`: cookie-only auth, 8h sessions, password expiry, WS query-string auth disabled\n- **TOTP / MFA** — Two-factor auth with RFC 6238 TOTP, encrypted secrets, 10 recovery codes\n- **LDAP / Active Directory** — Two-bind authentication, group filter, attribute mapping, auto-provision local accounts\n- **CIS Docker Benchmark** — 18 automated checks (daemon + container), scored report with remediation guidance\n- **Immutable Audit Log** — SHA-256 hash-chained, tamper detection, JSON/CSV/Syslog export\n- **Security Alerts** — 5 default rules (brute force, admin created, MFA disabled), threshold detection\n\n### Knowledge Base\n- **How-To Guides** — 84 built-in bilingual guides (EN + RO) covering Docker basics, Linux, networking, security, Compose, Swarm, troubleshooting, backup, performance — plus dedicated platform setups for Synology DSM, Unraid, TrueNAS SCALE, QNAP, OpenMediaVault, Generic VPS (Hetzner/DO/EC2/GCE/Azure/Linode/Vultr), an SSH key auth guide with per-platform public-key placement instructions, and an **AI category** (v8.0.1) covering Ollama on CPU/GPU, NVIDIA GPU passthrough to Docker, and a self-hosted RAG stack walkthrough\n- **Guide Editor** — Admins can create, edit, and delete custom guides with HTML content in both languages\n- **Search \u0026 Categories** — Filter by 9 categories, difficulty level, and free-text search across all guides\n\n### Platform\n- **Multi-user** — Admin, operator, viewer roles with session management\n- **SSO Authentication** — Authelia, Authentik, Caddy forward_auth, Traefik (header-based)\n- **SSL Zero-Config** — Caddy sidecar auto-reload via shared volume; enable HTTPS from UI with one click\n- **Audit Log** — Every action logged with user, timestamp, IP address\n- **Public Status Page** — Unauthenticated status page for selected services\n- **Container Metadata** — Custom labels, descriptions, links, categories, owner, notes\n- **Dark/Light Theme** — Per-user sync across devices, system-aware toggle, mobile responsive\n- **i18n** — 11 languages: English (complete), Romanian (~77%), German / Italian / French / Spanish / Portuguese / Chinese / Japanese / Korean / Klingon (~66% each — fall back to English for missing keys). [Add yours](public/js/i18n/README.md). The Translations tab below closes the gap without code changes.\n- **Translations tab** (v6.11) — Built-in Google Translate + DeepL integration for the missing keys in non-EN locales. Per-provider monthly quota tracking (500k chars each free tier), auto-accept toggle, chunked batch with progress bar + cancel, runtime DB overrides applied on login (no file download / git commit / container rebuild). AES-GCM encrypted API keys, hash-chained audit trail\n- **Klingon Easter Egg** — Full activation animation with sound, dagger cursor, red theme\n- **Command Palette** — Ctrl+K quick navigation with keyboard shortcuts\n- **Watchtower Detection** — Auto-detect and migrate from Watchtower to native safe-pull\n- **Prometheus Metrics** — `/api/metrics` endpoint for Grafana integration\n- **Self-Reporting Footprint** — Docker Dash memory, uptime, DB size at `/api/footprint`\n- **Let's Encrypt Wizard** — 3-step UI for issuing certs via DNS-01 (Cloudflare, Route53, DigitalOcean, Hetzner, Linode) or HTTP-01. Encrypted credential vault, auto-renewal via Caddy, hash-chained audit trail. Open source — no other Docker UI ships this\n- **Container Remediation Wizard** — 3-step UI that turns Secrets Audit + CIS Benchmark findings into actionable fixes. 20-entry catalog, 4 live-updatable (zero downtime), 16 with compose-recreate + auto-rollback. Git-PR mode for git-backed stacks. No other OSS Docker UI ships this\n- **1398 Tests** — 83 test suites covering 10 critical-path services with ≥15 dedicated cases each (auth, audit, docker, registry, ssl, ldap, ssh-tunnel, stackBundle, securityAlerts, webhooks) + 3 v8.2.x scaffold modules (telemetry, howto-loader, template-verification with migration 065), plus RBAC, security, ACME + remediation orchestrators, platform detection, DMI cloud detection, translations, Prometheus metrics, settings CRUD, security alert rule evaluation + cooldown, event notifier dispatch, cluster abstraction (HA mode), rate-limiter memory + Redis paths, registry retention + provenance pure-evaluators, AI redactor + service abstraction, pCloud client + backup orchestration + audit dump (hash-chain integrity verified). 100% passing.\n\n### AI (v8.0.0+) — opt-in, BYOK, off by default\n\nThe first feature category that introduces optional outbound traffic to non-user-controlled hosts. Designed strategy-first ([deep-spec](plans/deep-spec-ai-features.md), [spikes](plans/spikes-ai-features.md)). One sentence to defend: **AI in Docker Dash exists to translate noisy data into ranked, explainable decisions — never to take actions on the user's behalf.** Read-only or read-then-suggest. No always-on chat sidebar. No auto-remediation agent.\n\n- **Provider abstraction** — Anthropic Claude, OpenAI, Ollama. **BYOK** — Docker Dash ships zero API keys. Off by default until operator configures + enables in Settings → AI tab.\n- **Privacy-first redactor** — strips secrets/PII before any payload leaves the host. Built-in patterns cover Bearer auth, env-style assignments (incl. `STRIPE_SECRET_KEY`-style prefixes), connection-string credentials (13 schemes), high-entropy tokens, IPs, emails. Validated 100/100 on a 27-case corpus. Bad custom regex aborts the call (privacy beats utility).\n- **Compliance-grade audit** — every AI call logged with provider, model, token counts, redaction counts, SHA-256 payload hash. Operators can prove \"did this exact text get sent?\" without storing the prompt.\n- **Audit log NL search (v8.0.0)** — System → Audit page → magic-wand search box. Type *\"who deleted containers in the last 7 days\"* → translates to a structured filter via the AI provider, runs through existing audit query path. Never NL→SQL — only structured fields conforming to a JSON schema with a 174-entry action enum.\n- **Ollama is first-class** for sovereignty-critical deployments — zero outbound traffic. Recommended local model: `qwen2.5-coder:7b` (≈6 GB RAM, $0/month).\n- **Cost example** for cloud providers: 100 NL searches/day ≈ **$1.50/month** on Claude Haiku 4.5, **$0.30/month** on GPT-4o-mini.\n- **Roadmap**: AI vulnerability triage (rank scan results by real exploitability via EPSS + LLM reasoning) and AI incident triage (container restart-loop diagnosis from inspect + logs + stats) remain gated on production signal from v8.0.0 audit search — need ≥2 weeks of uptime, ≥1 real redactor catch, zero compliance issues. Until then, v8.x has prioritized adjacent value: registry hygiene (v8.1.0) and off-site backup (v8.2.0).\n\nSee [`docs/features/ai.md`](docs/features/ai.md) for the full setup walkthrough, provider tradeoffs, redactor reference, and programmatic API.\n\n### Feature Reference\n\nDedicated reference docs for the deeper features, in [docs/features/](docs/features/):\n\n- **[Prometheus Metrics](docs/features/prometheus-metrics.md)** — `/api/metrics` endpoint reference, metric names + types + labels, sample Grafana queries, cardinality notes\n- **[Platform Detection](docs/features/platform-detection.md)** — NAS + cloud + hypervisor detection logic; complete signature list; how to extend\n- **[Translations Tooling](docs/features/translations-tooling.md)** — Google Translate + DeepL integration, quota tracking, review workflow, runtime DB overrides\n- **[HA Mode](docs/features/ha-mode.md)** — optional Redis-backed redundancy (production-ready in v7.0.0); architecture, trade-offs, when NOT to use it\n- **[HA Failover Runbook](docs/features/ha-failover-runbook.md)** — operator procedures: leader death, rolling restart, Redis failure, split-brain detection, recovery checklist\n- **[HA Load Balancer Configs](docs/features/ha-lb-configs.md)** — copy-paste examples for Caddy + Traefik + HAProxy + nginx with sticky-session + WS upgrade + health checks\n- **[Observability Stack (v7.1.0)](docs/features/observability.md)** — opt-in Prometheus + Grafana via `docker compose --profile observability up -d`, 8-panel dashboard auto-provisioned, recommended alerts, integration with existing Prometheus/Grafana\n- **[Observability Wizard (v7.2.0)](docs/features/observability.md#1a-in-app-wizard-v720)** — admin UI at **System → Observability**. Detects existing Prometheus/Grafana on the host and offers 3 UX branches: integrate (both found → copy scrape snippet + one-click dashboard import via Grafana API), partial deploy, or full deploy with copy-paste instructions. Admin-only, audit-logged, token never persisted\n- **[Image Registry (v7.5.0–v8.1.0)](docs/features/registry.md)** — Distribution one-click template + push from Images page (SSE progress stream) + Browse page (catalog + tags + manifest inspect) + delete-by-digest with two-step confirmation gate + **Registry Hygiene Pack (v8.1.0)**: build provenance panel surfacing OCI annotations + cosign presence, retention policies with dry-run + 5-layer safety (default-disabled, min-3-tags floor, default protected patterns latest/v\\*/main/master/prod-\\*/stable, server cap 200/run, audit per delete), and JFrog-style local/remote/virtual repo taxonomy via Distribution proxy config (Docker Hub rate-limit relief + offline operation)\n- **[AI Features (v8.0.0)](docs/features/ai.md)** — opt-in, BYOK, off by default. Provider abstraction across Anthropic / OpenAI / Ollama. Privacy-first redactor (validated 100/100 on a hand-built corpus). SHA-256 payload hash in audit log for compliance evidence. Audit NL search (System → Audit) ships first; AI vulnerability triage + incident triage gated on production signal from v8.0.0\n- **[pCloud Backup (v8.2.0)](docs/features/pcloud-backup.md)** — third backup target alongside local + S3. Pushes the daily DB, weekly stack bundles, and monthly hash-chain-preserving audit log dumps to a pCloud free-tier account (10 GB, EU Switzerland default). Direct token auth (no OAuth dance), AES-256-GCM token storage, quota-aware uploads (95% threshold + 50 MB safety margin), per-artifact retention. Anti-features deliberately NOT shipped: pCloud Crypto, Drive mount, public sharing, restore-from-pCloud UI, the abandoned pcloud-sdk-js\n\n## Where to start\n\nThree short reads, each tailored to a different background. Pick the one that matches you.\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"33%\" valign=\"top\"\u003e\n      \u003ch3\u003e🚀 New to Docker?\u003c/h3\u003e\n      \u003cp\u003eThe recipe-and-kitchen metaphor, why containers fix \u003cem\u003e\"works on my machine\"\u003c/em\u003e, what you see in the first 30 seconds of opening Docker Dash, and what you can do in your first hour. No jargon.\u003c/p\u003e\n      \u003cp\u003e\u003cstrong\u003e\u003ca href=\"docs/guides/why-docker-dash-beginners.md\"\u003eRead: Beginner's Guide →\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n    \u003c/td\u003e\n    \u003ctd width=\"33%\" valign=\"top\"\u003e\n      \u003ch3\u003e⎇ Developer using Git?\u003c/h3\u003e\n      \u003cp\u003eThe git → Docker mental bridge (\u003ccode\u003ecommit\u003c/code\u003e = image, \u003ccode\u003epackage.json\u003c/code\u003e = compose), the 5 places dev-with-git gets stuck, and how Docker Dash compares against Portainer / Dockge / bash scripts. With a GitOps workflow.\u003c/p\u003e\n      \u003cp\u003e\u003cstrong\u003e\u003ca href=\"docs/guides/why-docker-dash-developers.md\"\u003eRead: Developers Using Git →\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n    \u003c/td\u003e\n    \u003ctd width=\"34%\" valign=\"top\"\u003e\n      \u003ch3\u003e🛠 Ops / SRE evaluating HA?\u003c/h3\u003e\n      \u003cp\u003eWhen to flip \u003ccode\u003eDD_MODE=ha\u003c/code\u003e, when to stay standalone, failover mechanics (Redis \u003ccode\u003eSET NX PX\u003c/code\u003e, leader lock TTL, Lua \u003ccode\u003eDEL-if-owned\u003c/code\u003e graceful handover), operational runbook covering 6 failure scenarios, and copy-paste LB configs for Caddy/Traefik/HAProxy/nginx.\u003c/p\u003e\n      \u003cp\u003e\u003cstrong\u003e\u003ca href=\"docs/features/ha-mode.md\"\u003eRead: HA Mode →\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n      \u003cp\u003e↳ \u003ca href=\"docs/features/ha-failover-runbook.md\"\u003eFailover Runbook\u003c/a\u003e · \u003ca href=\"docs/features/ha-lb-configs.md\"\u003eLB Configs\u003c/a\u003e\u003c/p\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n\u003e The first two guides are also available inside the app under \u003cstrong\u003eHow-To Guides\u003c/strong\u003e with bilingual EN/RO content and surfaced as buttons in the page header. HA docs are operator-facing and live in the repo / docs only.\n\n## Quick Start\n\n### One-Line Install (recommended)\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/bogdanpricop/docker-dash/main/install.sh | bash\n```\n\nThis will detect your OS, check Docker, generate secure secrets, and start Docker Dash. Works on Ubuntu, Debian, CentOS, Fedora, and macOS (amd64/arm64).\n\nSet a custom install directory: `DOCKER_DASH_DIR=/opt/docker-dash curl -fsSL ... | bash`\n\nFor an unattended-secure install with a random admin password (instead of `admin/admin`-then-change): `FORCE_RANDOM_ADMIN_PASSWORD=1 curl -fsSL ... | bash` — the generated password is printed once at the end.\n\n\u003e **Install didn't work?** Jump to [Troubleshooting Install](#troubleshooting-install) — covers restart loops, build failures, port conflicts, permission issues, and the diagnostic one-liner that surfaces 95% of failure modes.\n\n\u003e **Specific setup?** See [`examples/deployments/`](examples/deployments/README.md) — ready-to-customize compose files for Caddy auto-HTTPS, Traefik v3, Nginx Proxy Manager, Docker Swarm, HA mode (2 replicas + Redis), and Synology DSM. Or open **System → Tools → Deployment Configurator** in the running app for a live wizard that emits the YAML for your environment.\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/bogdanpricop/docker-dash.git\ncd docker-dash\n\n# Copy and configure environment\ncp .env.example .env\n# Edit .env — at minimum change APP_SECRET and ADMIN_PASSWORD\n\n# Start with Docker Compose\ndocker compose up -d\n\n# Open in browser\nopen http://localhost:8101\n```\n\nDefault credentials: `admin` / `admin` — on first login, a **security setup wizard** will require you to change the password.\n\n### Enabling HA mode\n\nOnce standalone works, switching to HA is a flag flip:\n\n```bash\n# .env\nDD_MODE=ha\nREDIS_URL=redis://redis:6379\n\n# Bring up Redis alongside Docker Dash\ndocker compose --profile ha up -d\n\n# Then scale to multiple replicas behind a sticky-session LB (see LB configs doc)\n```\n\nSee the [HA Mode reference](docs/features/ha-mode.md) for the full enablement procedure, [Failover runbook](docs/features/ha-failover-runbook.md) for operational scenarios, and [LB configs](docs/features/ha-lb-configs.md) for production-ready Caddy/Traefik/HAProxy/nginx configurations.\n\n## Requirements\n\n### Standalone\n\n- Docker Engine 20.10+ (or Docker Desktop 4.x+)\n- Docker Compose v2\n- ~50MB RAM, minimal CPU, ~180MB disk for the image (includes Trivy + Grype + Docker Scout binaries for built-in vulnerability scanning)\n\n### HA mode (additional)\n\n- Redis 7+ (ships as `redis:7-alpine` in the `--profile ha` compose profile; ~30MB image, ~5-15MB RAM)\n- Sticky-session-capable load balancer for 2+ replica deploys (Caddy, Traefik, HAProxy, nginx — [configs provided](docs/features/ha-lb-configs.md))\n- Shared volume for SQLite (Docker named volume works on same host; K8s `ReadWriteMany` PVC for multi-node)\n- Operator familiarity with Redis basics (single instance is fine — Sentinel only needed for Redis HA separately)\n\n## Troubleshooting Install\n\nIf `curl ... | bash` finishes but the container won't stay up, the Docker container exits immediately, or you see `restarting` in `docker ps` over and over — work through this section in order. It covers the bugs we've actually seen reported, with the diagnostic commands to confirm each and the exact fix for each.\n\n### Step 1 — Triage in one command\n\nRun this from inside the install directory (default `~/docker-dash`):\n\n```bash\ncd ~/docker-dash 2\u003e/dev/null || cd /opt/docker-dash 2\u003e/dev/null\necho \"=== container state ===\"\ndocker inspect docker-dash --format 'exitCode={{.State.ExitCode}} error={{.State.Error}} restartCount={{.RestartCount}} status={{.State.Status}}'\necho \"=== last 50 log lines ===\"\ndocker logs docker-dash --tail 50 2\u003e\u00261\necho \"=== env (no secrets) ===\"\ngrep -E '^(APP_ENV|APP_PORT|ADMIN_PASSWORD|ALLOW_DEFAULT_ADMIN|DD_MODE|DOCKER_SOCKET)' .env 2\u003e/dev/null\necho \"=== image in use ===\"\ndocker inspect docker-dash --format '{{.Config.Image}} (created {{.Created}})'\necho \"=== compose file ===\"\nhead -25 docker-compose.yml\necho \"=== disk space ===\"\ndf -h / /var/lib/docker 2\u003e/dev/null | head -3\n```\n\nThe output is enough to identify 95% of install failures. Map the symptom to the section below.\n\n### Step 2 — Match the symptom\n\n#### A. Logs end with `FATAL: ADMIN_PASSWORD is \"admin\" in production`\n\nYour `.env` has `ADMIN_PASSWORD=admin` but no `ALLOW_DEFAULT_ADMIN=true`. Server refuses to boot in production mode with the default password unless you opt in. Two fixes:\n\n```bash\n# Option 1 — keep admin/admin (forced password change on first login)\necho 'ALLOW_DEFAULT_ADMIN=true' \u003e\u003e .env\ndocker compose up -d\n\n# Option 2 — set a random strong admin password\nNEW_PW=$(openssl rand -base64 24 | tr -d '/+=' | head -c 20)\nsed -i \"s|^ADMIN_PASSWORD=.*|ADMIN_PASSWORD=$NEW_PW|\" .env\ndocker compose up -d\necho \"Your new admin password: $NEW_PW\"\n```\n\nRe-run from a fresh installer (recommended path — picks up all the install.sh fixes shipped after this bug was first reported):\n\n```bash\ndocker compose down\nmv .env .env.backup\ncurl -fsSL https://raw.githubusercontent.com/bogdanpricop/docker-dash/main/install.sh | bash\n```\n\n#### B. Logs end with `FATAL: APP_SECRET is weak or default` or `ENCRYPTION_KEY is weak or default`\n\n`.env` has placeholder values for one of those. Generate strong replacements:\n\n```bash\nAPP_SECRET=$(openssl rand -hex 48)\nENCRYPTION_KEY=$(openssl rand -hex 32)\nsed -i \"s|^APP_SECRET=.*|APP_SECRET=$APP_SECRET|\" .env\nsed -i \"s|^ENCRYPTION_KEY=.*|ENCRYPTION_KEY=$ENCRYPTION_KEY|\" .env\ndocker compose up -d\n```\n\n#### C. `failed to compute cache key` or `COPY ... not found` during build\n\nThe local-build fallback got a sparse build context (some required files weren't cloned). The fix: use the pre-built image instead.\n\n```bash\ndocker compose down\ndocker pull ghcr.io/bogdanpricop/docker-dash:latest\n# Edit docker-compose.yml: replace the entire `build:` block with:\n#   image: ghcr.io/bogdanpricop/docker-dash:latest\n# Then:\ndocker compose up -d\n```\n\nOr run the latest installer, which now uses the GHCR image first by default:\n\n```bash\nmv ~/docker-dash ~/docker-dash.broken\ncurl -fsSL https://raw.githubusercontent.com/bogdanpricop/docker-dash/main/install.sh | bash\n```\n\n#### D. Logs show `EACCES`, `permission denied`, or SQLite write errors on `/data`\n\nVolume mount can't be written by the container's UID. Most common on bind-mounted host directories with stale ownership.\n\n```bash\n# If using the default named volume (recommended) — recreate it:\ndocker compose down\ndocker volume rm docker-dash-data\ndocker compose up -d\n\n# If you bind-mounted a host path, fix ownership:\nsudo chown -R 1000:1000 /path/to/your/data/dir\ndocker compose up -d\n```\n\n#### E. Logs show `EADDRINUSE` or container exits with `port is already allocated`\n\nPort 8101 (or whichever you set) is taken by another process. Either change the port or stop the conflicting process.\n\n```bash\n# Find what's on 8101\nsudo ss -tlnp | grep ':8101'\n\n# Either kill it, or edit .env to use a different port:\nsed -i 's|^APP_PORT=.*|APP_PORT=8201|' .env\ndocker compose up -d\n```\n\n#### F. `docker info` fails / `Cannot connect to the Docker daemon`\n\nDocker daemon isn't running, or your user isn't in the `docker` group.\n\n```bash\n# Start the daemon:\nsudo systemctl start docker\nsudo systemctl enable docker\n\n# Add yourself to the docker group (then log out and back in):\nsudo usermod -aG docker $USER\n# Confirm with:\ndocker info\n```\n\n#### G. `Cannot connect to /var/run/docker.sock` from inside the container\n\nContainer needs read-only socket access. The default compose file mounts it. If you have AppArmor or SELinux enforcing strict policies (Ubuntu 24.04+, RHEL 9+), the mount might be blocked.\n\n```bash\n# Confirm the mount is there:\ndocker inspect docker-dash --format '{{range .Mounts}}{{.Source}} -\u003e {{.Destination}} ({{.Mode}}){{\"\\n\"}}{{end}}'\n\n# On SELinux, add the :z label:\n# In docker-compose.yml change:\n#   - /var/run/docker.sock:/var/run/docker.sock:ro\n# to:\n#   - /var/run/docker.sock:/var/run/docker.sock:ro,z\n```\n\n#### H. `no space left on device`\n\nDisk is full — most often the Docker storage on `/var/lib/docker`.\n\n```bash\n# Reclaim space:\ndocker system prune -a --volumes  # destructive — review what gets removed first\ndf -h /var/lib/docker\n```\n\n#### I. Pull from GHCR fails with 404 or auth error\n\nMost common reason: the package was made private or temporarily unavailable. Use the local-build path:\n\n```bash\ncd ~/docker-dash\ngit clone --depth 1 https://github.com/bogdanpricop/docker-dash.git .src\ncp -r .src/Dockerfile .src/src .src/public .src/scripts .src/entrypoint.sh \\\n      .src/package.json .src/package-lock.json .src/README.md .src/LICENSE \\\n      .src/CONTRIBUTING.md .src/.gitignore .src/.dockerignore .\nrm -rf .src\ndocker compose build app\ndocker compose up -d\n```\n\n#### J. Container says `(healthy)` but the UI returns 502 / connection refused\n\nThe reverse-proxy in front (Caddy, Nginx, Traefik) isn't routing to the container's port. Test the container directly first:\n\n```bash\ncurl http://localhost:8101/api/health\n# Should return: {\"status\":\"ok\",\"version\":\"8.2.x\",...}\n\n# If that works, the issue is upstream — check your proxy config.\n# If it doesn't work, see Steps A-F above.\n```\n\n### Step 3 — Clean reinstall (last resort)\n\nIf you've debugged enough and just want a known-good state — and you're OK losing local Docker Dash data (audit log, custom templates, registries you added):\n\n```bash\ncd ~/docker-dash\ndocker compose down -v  # -v also removes the data volume\ncd ..\nrm -rf ~/docker-dash\ncurl -fsSL https://raw.githubusercontent.com/bogdanpricop/docker-dash/main/install.sh | bash\n```\n\nTo preserve data, replace `down -v` with `down`, and don't delete the directory — the named volume `docker-dash-data` persists.\n\n### Step 4 — Still stuck?\n\nOpen a [Discussion](https://github.com/bogdanpricop/docker-dash/discussions) with the **full Step 1 triage output**. Include:\n\n- OS + version (`uname -a` and `lsb_release -a` on Ubuntu)\n- Docker version (`docker --version`)\n- Docker Compose version (`docker compose version`)\n- Whether you used the `curl | bash` installer or `git clone + docker compose up`\n- The triage output from Step 1 (redact secrets — APP_SECRET / ENCRYPTION_KEY / passwords)\n\nFor confirmed bugs, [open an Issue](https://github.com/bogdanpricop/docker-dash/issues/new) with the same info plus reproduction steps.\n\n### What changed in v8.2.x to make installs more reliable\n\nThe install path was hardened in v8.2.x after a user reported a restart-loop on Ubuntu 25.10:\n\n- **GHCR `:latest` tag now exists** — `install.sh` pulls a known-good pre-built image instead of falling back to git-clone+local-build.\n- **`install.sh` adds `ALLOW_DEFAULT_ADMIN=true` to `.env` by default** — admin/admin works for first login (forced password change after); `FORCE_RANDOM_ADMIN_PASSWORD=1` opt-in generates a random password and prints it once.\n- **`install.sh` git-clone fallback now copies all 12 files** the production Dockerfile stage requires, plus drops placeholders for any missing optional files.\n- **`install.sh` patches `docker-compose.yml` with `target: production`** when the local-build fallback runs, so BuildKit doesn't waste time on the dev stage in parallel.\n\nIf you installed before these fixes landed and you're still seeing trouble, the cleanest path is **Step 3 — clean reinstall** above. The new installer picks up all the fixes.\n\n## Architecture\n\n### Standalone mode (default)\n\n```\n┌─────────────────┐     ┌───────────────────┐\n│   Browser SPA   │────▸│  Node.js/Express  │\n│  (vanilla JS)   │◂────│   REST + WebSocket│\n└─────────────────┘     └────────┬──────────┘\n                                 │\n                    ┌────────────┼────────────┐\n                    │            │            │\n              ┌─────┴──────┐ ┌───┴────┐ ┌─────┴─────┐\n              │  SQLite    │ │ Docker │ │  Docker   │\n              │ (embedded) │ │ Local  │ │  Remote   │\n              │ WAL mode   │ │ Socket │ │ TCP/SSH   │\n              └────────────┘ └────────┘ └───────────┘\n```\n\n### HA mode (opt-in)\n\n```\n                  ┌─────────────────────────────────┐\n                  │  Sticky-session Load Balancer   │\n                  │  (Caddy / Traefik / HAProxy /   │\n                  │   nginx — configs provided)     │\n                  └─────────────────┬───────────────┘\n                                    │\n                  ┌─────────────────┼─────────────────┐\n                  │                 │                 │\n            ┌─────▼─────┐     ┌─────▼─────┐     ┌─────▼─────┐\n            │ replica A │     │ replica B │     │ replica C │\n            │  LEADER   │     │  reader   │     │  reader   │\n            │ cron+WS   │     │ HTTP only │     │ HTTP only │\n            │ event-    │     │           │     │           │\n            │ stream    │     │           │     │           │\n            └─────┬─────┘     └─────┬─────┘     └─────┬─────┘\n                  │                 │                 │\n                  │    ┌────────────┴────────────┐    │\n                  │    │                         │    │\n                  └────┤   shared SQLite volume  ├────┘\n                       │  (single-writer: leader)│\n                       └─────────────────────────┘\n                  ┌────────────────────────────────────┐\n                  │           Redis 7-alpine           │\n                  │  ┌───────────┐  ┌──────────────┐  │\n                  │  │ leader    │  │ rate-limit   │  │\n                  │  │ lock +    │  │ INCR + PX    │  │\n                  │  │ heartbeat │  │              │  │\n                  │  └───────────┘  └──────────────┘  │\n                  │  ┌────────────────────────────┐   │\n                  │  │ ddash:pubsub (WS events)   │   │\n                  │  └────────────────────────────┘   │\n                  └────────────────────────────────────┘\n```\n\nOne replica holds the Redis `leader` lock (30s TTL + 10s heartbeat). Leader runs cron jobs, Docker event stream, git polling. Readers serve HTTP + deliver WS events from pub/sub. Graceful handover on `docker stop` via Lua `DEL-if-owned` — failover in milliseconds. Ungraceful leader death — next heartbeat reader wins (≤30s worst case).\n\nSSH tunnels run per-replica (readers need them to serve HTTP reads). No active-active write scale-out — SQLite stays single-writer.\n\n| Layer | Technology |\n|-------|-----------|\n| Backend | Node.js 20, Express 5, dockerode, better-sqlite3, ws, ssh2, ldapts |\n| Frontend | Vanilla JavaScript SPA, Chart.js, xterm.js, Font Awesome (CDN) |\n| Database | SQLite with WAL mode, auto-aggregation, configurable retention |\n| Security | bcrypt, Helmet CSP, rate limiting, session-based auth, Bearer token fallback |\n| Scanning | Trivy (OSS), Grype (Anchore), Docker Scout (SARIF format) |\n\n**Zero build step** — no webpack, no bundler, no transpiler. Frontend files are served as-is.\n\n## Multi-Host\n\nDocker Dash can manage multiple Docker hosts from a single instance:\n\n| Method | Use Case | Requirements |\n|--------|----------|-------------|\n| **TCP + TLS** | Remote Linux servers | Docker API exposed on port 2376 + TLS certificates |\n| **Docker Desktop** | Windows / Mac | \"Expose daemon on TCP\" enabled in DD Settings |\n| **SSH Tunnel** | Secure remote (no API exposure) | SSH access + `socat` installed + user in `docker` group |\n| **SSH to NAS** | Synology / Unraid / TrueNAS SCALE / QNAP / OMV | SSH access + admin in `docker` group. Platform auto-detected from `docker info` — dedicated How-To guide per platform |\n| **Unix Socket** | Local (default) | Docker socket mounted (automatic) |\n\nThe app includes a **built-in setup guide** (Hosts page) with step-by-step instructions for each method, including TLS certificate generation, per-OS `socat` installation commands, SSH key authentication setup, and a 9-item Synology DSM 7.x security hardening checklist (added in v6.14.3).\n\n## Podman Support\n\nDocker Dash works with **Podman** via its Docker-compatible API. No code changes needed.\n\n```bash\n# 1. Enable the Podman socket\nsystemctl --user enable --now podman.socket    # rootless\n# or\nsudo systemctl enable --now podman.socket      # rootful\n\n# 2. Set the socket path in .env\necho 'DOCKER_SOCKET=/run/podman/podman.sock' \u003e\u003e .env   # rootful\n# or\necho 'DOCKER_SOCKET=/run/user/1000/podman/podman.sock' \u003e\u003e .env  # rootless\n\n# 3. Start Docker Dash\ndocker compose up -d   # or podman-compose up -d\n```\n\n**Known differences:** Podman lacks Docker Compose labels (`com.docker.compose.project`), so containers won't auto-group into stacks. Use Docker Dash's Container Groups feature instead.\n\n## Configuration\n\nAll config via environment variables. See [`.env.example`](.env.example) for the full list.\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `APP_PORT` | `8101` | HTTP port |\n| `APP_SECRET` | — | **Required.** Session signing key |\n| `ADMIN_PASSWORD` | `admin` | Initial admin password (first launch only) |\n| `ENCRYPTION_KEY` | — | Encrypt registry credentials at rest |\n| `STATS_INTERVAL_MS` | `10000` | Stats collection interval (ms) |\n| `STATS_RAW_RETENTION_HOURS` | `24` | Keep raw stats for N hours |\n| `EVENT_RETENTION_DAYS` | `7` | Keep Docker events for N days |\n| `ENABLE_EXEC` | `true` | Allow terminal exec into containers |\n| `READ_ONLY_MODE` | `false` | Disable all write operations |\n| `DD_MODE` | *(unset — standalone)* | Set to `ha` to enable HA mode. Requires `REDIS_URL`. |\n| `REDIS_URL` | `redis://localhost:6379` | Redis connection URL. Only consulted when `DD_MODE=ha`. |\n| `TRUST_PROXY` | `loopback` (prod) / `true` (dev) | Trusted proxy range for `X-Forwarded-*` headers. Set to your load balancer's IP/CIDR in HA. |\n| `COOKIE_SECURE` | `false` | Set `true` when behind HTTPS. Required for sticky-session cookies over TLS-terminating LBs. |\n\n## Development\n\n```bash\n# Install dependencies\nnpm install\n\n# Start in development mode (auto-reload on file changes)\nnpm run dev\n\n# Open http://localhost:8101\n```\n\nNo build step needed. Edit any `.js` or `.css` file and refresh the browser.\n\n## Adding a Language\n\nDocker Dash uses a modular i18n system. To add a new language:\n\n1. Copy `public/js/i18n/TEMPLATE.js` to `public/js/i18n/{code}.js`\n2. Translate the values (keys stay in English)\n3. Add one `\u003cscript\u003e` tag in `index.html`\n\nThat's it — the language appears automatically in the selector. See [`public/js/i18n/README.md`](public/js/i18n/README.md) for full instructions.\n\nCurrently supported: **English**, **Romanian**, **German**, **Italian**, **French**, **Spanish**, **Portuguese**, **Chinese**, **Japanese**, **Korean**, **Klingon** (11 languages).\n\n## Project Structure\n\n```\ndocker-dash/\n├── src/\n│   ├── config/          # Environment-based configuration\n│   ├── db/              # SQLite setup + 64 auto-migrations\n│   ├── middleware/       # Auth, rate limiting, hostId extraction\n│   ├── routes/          # REST API (containers, images, volumes, networks, swarm, hosts, ...)\n│   ├── services/        # Business logic (docker, stats, alerts, ssh-tunnel, registry, ldap, cis-benchmark, ssl)\n│   ├── ws/              # WebSocket server (exec, live logs, live stats)\n│   └── utils/           # Logger, helpers\n├── public/\n│   ├── js/\n│   │   ├── i18n/        # Language files (11 languages + TEMPLATE.js)\n│   │   ├── pages/       # SPA pages (dashboard, containers, images, security, swarm, hosts, ...)\n│   │   ├── components/  # Reusable UI (modal, toast, data table)\n│   │   ├── api.js       # HTTP client with auto host-context\n│   │   ├── ws.js        # WebSocket client with reconnect\n│   │   └── app.js       # Router, auth, sidebar, command palette\n│   └── css/app.css      # Single stylesheet, CSS variables, dark/light themes\n├── docs/\n│   └── screenshots/     # UI screenshots for README\n├── Dockerfile           # Multi-stage: base → deps → production\n├── docker-compose.yml   # Production-ready with health check\n└── .env.example         # All variables documented\n```\n\n## Comparison\n\n**60 features compared across 8 tools.** See the interactive comparison at `#/compare` in the app, or via `GET /api/compare`.\n\n| Feature | **Docker Dash** | Portainer CE | Portainer BE | Coolify | Yacht | Rancher | Dockge | Dockhand |\n|---------|:-----------:|:------------:|:------------:|:-------:|:-----:|:-------:|:------:|:--------:|\n| Container CRUD | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | Compose only | ✅ |\n| Image / Volume / Network | ✅ | ✅ | ✅ | ✅ | partial | ✅ | No | ✅ |\n| **Network Topology** | ✅ | — | — | — | — | — | — | — |\n| **Dependency Map** | ✅ | — | — | — | — | — | — | — |\n| Real-time Stats | ✅ | ✅ | ✅ | ✅ | basic | ✅ | basic | ✅ |\n| Terminal (xterm.js) | ✅ | ✅ | ✅ | ✅ | — | ✅ | ✅ | ✅ |\n| Vulnerability Scanning | Trivy + Grype + Scout | — | — | — | — | NeuVector | — | Grype + Trivy |\n| **Safe-Pull + Pipeline** | **5-stage** | — | — | — | — | — | — | basic |\n| **Container Rollback** | ✅ | — | — | ✅ | — | ✅ | — | — |\n| Multi-Host (agentless) | ✅ | agent req. | agent req. | agent | — | ✅ | agent | ✅ |\n| **Optional HA mode (no vendor lock-in)** | **✅ v7.0.0** | — | commercial tier | — | — | K8s-based | — | — |\n| **Bundled Prometheus + Grafana + wizard** | **✅ v7.2.0** | — | — | — | — | — | — | — |\n| Git Integration | ✅ | BE only | ✅ | ✅ | — | Fleet | — | — |\n| Webhooks + Polling | ✅ | BE only | ✅ | ✅ | — | ✅ | — | — |\n| **Docker Swarm Mode** | ✅ | ✅ | ✅ | — | — | K8s focus | — | — |\n| Audit Log | ✅ | BE only | ✅ | basic | — | ✅ | — | — |\n| **Alerts (7 channels)** | ✅ | BE only | ✅ | ✅ | — | ✅ | — | — |\n| SSO / LDAP / OAuth | ✅ | BE only | ✅ | ✅ | — | ✅ | — | — |\n| **CIS Docker Benchmark** | ✅ | — | — | — | — | partial | — | — |\n| **Health Score (0-100)** | ✅ | — | — | — | — | — | — | — |\n| **AI Container Doctor** | ✅ | — | — | — | — | — | — | — |\n| **Resource Forecasting** | ✅ | — | — | — | — | basic | — | — |\n| **Cost Optimizer** | ✅ | — | — | — | — | basic | — | — |\n| **Insights Dashboard** | ✅ | — | — | — | — | basic | — | — |\n| **Workflow Automation** | ✅ | — | — | — | — | — | — | — |\n| **Scheduled Actions** | ✅ | — | — | — | — | — | — | — |\n| **Cross-Host Migration** | zero-downtime | — | — | — | — | ✅ | — | — |\n| **Public Status Page** | ✅ | — | — | ✅ | — | — | — | — |\n| **Maintenance Windows** | ✅ | — | — | — | — | — | — | — |\n| **API Playground** | ✅ | Swagger ($) | ✅ | ✅ | — | ✅ | — | — |\n| App Templates | 33 + custom | 500+ community | 500+ | many | basic | Helm | — | — |\n| i18n | **11 languages** | partial | partial | partial | — | ✅ | — | — |\n| Command Palette | ✅ | — | — | — | — | — | — | — |\n| Mobile Responsive | ✅ | ✅ | ✅ | ✅ | ✅ | partial | ✅ | ✅ |\n| Build Step | **None** | Angular | Angular | required | none | none | required | required |\n| Container Size | **~180MB** (incl. Trivy + Grype + Scout) | ~250MB | ~250MB | ~200MB | ~100MB | ~500MB+ | ~100MB | ~80MB |\n| RAM Usage | **~50MB** | ~200MB | ~200MB | ~150MB | ~50MB | ~500MB+ | ~50MB | ~60MB |\n| License | **MIT** | Zlib | commercial | Apache 2.0 | MIT | Apache 2.0 | MIT | BSL 1.1 |\n\n\u003e The comparison table flags **20+ rows** where Docker Dash ships a feature no compared free tool has — Container Doctor, Container Cloning, AI workload templates, Let's Encrypt wizard, CIS benchmark UI, registry hygiene pack with provenance + retention dry-run, hash-chained off-site audit dumps, etc. Coverage gaps cut both ways: Portainer wins on Kubernetes ergonomics, Komodo wins on multi-server orchestration UX. Pick the tool that fits *your* workflow.\n\u003e\n\u003e Features Portainer Business locks behind paid license are **free** in Docker Dash.\n\u003e Rancher / K3s targets Kubernetes clusters; Docker Dash targets single-host and small multi-host Docker deployments.\n\n### Targeted comparisons\n\nFor a deeper one-on-one breakdown of \"Pick X if Y, pick Docker Dash if Z\":\n\n- **[Docker Dash vs Portainer](docs/comparisons/vs-portainer.md)** — the dominant Docker UI; free CE (BSL 1.1) vs paid Business\n- **[Docker Dash vs Dockge](docs/comparisons/vs-dockge.md)** — minimal Compose-focused alternative\n- **[Docker Dash vs Komodo](docs/comparisons/vs-komodo.md)** — fleet GitOps multi-server vs single-host depth\n\nIndex: [`docs/comparisons/`](docs/comparisons/).\n\n## License\n\n[MIT](LICENSE) — free for personal and commercial use.\n\n## Security\n\nDocker Dash takes security seriously. See [SECURITY.md](SECURITY.md) for our full security policy.\n\n### Docker Socket Access\n\nDocker Dash requires access to the Docker socket (`/var/run/docker.sock`). This is **equivalent to root access** on the host. This is the same requirement as Portainer, Dockge, and all other Docker management UIs.\n\n**Mitigations in place:**\n- Socket mounted **read-only** (`:ro`) in production docker-compose\n- `no-new-privileges` security option enabled\n- Role-based access control (admin/operator/viewer)\n- Feature flags to disable dangerous operations (`ENABLE_EXEC=false`, `READ_ONLY_MODE=true`)\n- Audit log for every action with user, timestamp, and IP\n- Rate limiting on all API endpoints\n- Session-based auth with bcrypt + SHA-256 hashed tokens\n\n**Recommendations for production:**\n- Deploy behind HTTPS reverse proxy (Caddy config included)\n- Set strong `APP_SECRET` and `ENCRYPTION_KEY` (app refuses to start without them)\n- Set `COOKIE_SECURE=true` when behind HTTPS\n- Disable exec terminal if not needed (`ENABLE_EXEC=false`)\n- Use read-only mode for monitoring-only deployments (`READ_ONLY_MODE=true`)\n- Restrict network access to trusted IPs\n- Consider [docker-socket-proxy](https://github.com/Tecnativa/docker-socket-proxy) to limit API access (allow only read operations)\n- Review [SECURITY.md](SECURITY.md) for responsible disclosure process\n\n### Security Audit Results\n\n| Audit | Date | Score | Critical Issues |\n|-------|------|-------|----------------|\n| Tech Debt Scan | 2026-03-27 | 33 items found | All 4 CRITICAL fixed |\n| Production Readiness v5 | 2026-03-28 | 8.05/10 weighted (claimed 9.2) | All P0+P1 resolved |\n| Shell Injection | 2026-03-28 | 0 vectors | All execSync eliminated |\n| Production Readiness v6.15.1 | 2026-04-22 | 9.1/10 (defensible weighted) | v5 gaps closed: error-response sanitization on all 500s (v6.14.1), expanded Prometheus metrics with job counters populated (v6.15.0–v6.15.1), setInterval leak fixed, CI test count dynamic, X-Frame-Options: DENY + Permissions-Policy, 0 lint warnings |\n| Production Readiness v6.16.0 | 2026-04-22 | 9.5/10 | Phase 2 shipped: `containers.js` (5774 lines, largest JS file) split into list-eager (3226 lines) + detail-lazy (2595 lines loaded on first `/containers/:id` navigation via script injection). Performance category 7 → 9, initial JS payload −45% for users not visiting a container detail page. 757 tests unchanged |\n| Production Readiness v6.16.1 | 2026-04-22 | **9.7/10** | Testing 8.5 → 9.5 (+86 tests across 4 previously-untested services: permissions RBAC, settings CRUD, security-alerts rule evaluation, event-notifier dispatch). Documentation 9 → 9.5 (3 new feature reference docs under `docs/features/`: Prometheus metrics, platform detection, translations tooling). Residual: Docker-in-Docker integration tests (v7), Redis HA mode (v7), external 3rd-party audit (v7) — 10/10 requires all three |\n| Production Readiness v7.0.0 | 2026-04-22 | **9.8/10** | HA mode production-ready: opt-in `DD_MODE=ha` + Redis. 4-phase rollout (v6.17.0 rate limiter, v6.17.1 WS pub/sub, v6.17.2 leader election, v7.0.0 observability + operator runbook + LB configs). Standalone default unchanged. Staging soak verified: 3-replica deploy with lock acquire, graceful leader handover, Redis restart recovery. `/api/cluster/status` + 4 Prometheus gauges. BACKLOG F30 closed. Residual gap to 10: external 3rd-party security audit (budget + vendor coordination) |\n| v7.1.0–v7.2.0 | 2026-04-22 | **9.8/10** | Observability bundle shipped: opt-in Prometheus + Grafana compose profile with 8-panel auto-provisioned dashboard (v7.1.0), then in-app wizard at **System → Observability** that detects existing monitoring stacks and offers integrate/deploy/hybrid paths with one-click dashboard import via Grafana API (v7.2.0). Admin-only, 10s outbound timeout, tokens never persisted. 28 new tests. No production-readiness score change — UX layer on top of v7.0.0's foundation |\n| v7.3.0–v7.7.0 | 2026-04-25 | **9.8/10** | UX + workflow shipped: in-app update notifications via GitHub releases polling (v7.3.0), session-expiry recovery (v7.3.1), Express 5 + path-to-regexp v8 migration (v7.3.x), sample plugin + CONTRIBUTING.md (v7.4.0), image registry workflow — push/browse/template (v7.5.0), registry delete-by-digest with two-step confirmation (v7.6.0), CI lint enforcement (v7.7.0). All admin-gated, all audited |\n| v8.0.0 — AI features (BYOK) | 2026-04-27 | **9.8/10** | First feature category with optional outbound traffic to non-user-controlled hosts. Strategy-first deep-spec + 5 spikes ran before code; redactor S4 validated 100/100 on 27-case corpus before integration. Provider abstraction (Anthropic / OpenAI / Ollama), BYOK only, off by default. Audit log NL search ships first; vulnerability + incident triage gated on production signal. Every AI call writes audit entry with provider, model, token counts, redaction counts per pattern, SHA-256 payload hash. 63 new tests |\n| v8.1.0 — Registry Hygiene Pack | 2026-04-29 | **9.8/10** | Build provenance panel surfacing OCI annotations + cosign signature presence (read-only, zero new state). Retention policies with five safety layers: default-disabled (dry-run only), min-3-tags hard floor, default protected patterns latest/v\\*/main/master/prod-\\*/stable, server cap 200 deletions/run, audit per delete. Remote/virtual repos via Distribution proxy (Docker Hub rate-limit relief + offline operation). 58 new tests, all 5 safety layers regression-tested |\n| v8.2.0 — pCloud backup + off-site archives | 2026-05-05 | **9.8/10** | Third backup target alongside local + S3. AES-256-GCM encrypted token storage. Quota-aware uploads (95% pre-flight check + 50 MB safety margin). Hash-chained audit log monthly dumps preserve `entry_hash`/`prev_hash` row-for-row across months — consecutive dumps form a continuous off-site witness if the live DB is later tampered. Streaming export via `stmt.iterate()` handles 50k+ row months without buffer growth. 40 new tests including end-to-end gzip → upload → download → gunzip → chain-walk verification |\n| v8.2.x — Post-release brutal audit + full remediation | 2026-05-05 | **9.9/10** | Honest re-audit of production-readiness after v8.2.0 ship. 22 issues identified, ALL CLOSED in 8 waves. Highlights: 14 services now with ≥15 dedicated tests each (1122 → 1356 = +234 tests, 70 → 80 suites); 84 built-in How-To guides extracted from SQL migrations to 132 markdown files via auto-extraction script; **dockerode 4 → 5 migration** (zero-vulnerability install — was tracked as deferred CVE in audit §7); **all third-party CDN dependencies eliminated** — Chart.js + xterm.js + xterm-addon-fit + FontAwesome (CSS + 8 webfont files) all served from `/lib/` and `/webfonts/`, CSP tightened to strict `'self'` (no third-party origins allowed); ESLint rule banning inline `onclick=` enforced (9 historical violations refactored to delegated handlers); `system.js` 6011 → 5594 LOC (Egress section extracted to `system-egress.js` 462 LOC, merged via `Object.assign`); **a11y at component level** — Modal (role=dialog + aria-modal + aria-labelledby + focus restore on close + Escape key) + Toast (role=alert/status with aria-live=assertive/polite per severity + aria-atomic) — every modal and toast in the app benefits at once; CLAUDE.md at repo root; 3 targeted vs-product comparison pages (Portainer/Dockge/Komodo); template `verified_at` + `deprecated_in_favor_of` trust signals; telemetry scaffold (off by default); Grafana + Prometheus observability profile live on the public VPS at `:3015` (eat own dog food). |\n\n### Known Security Tradeoffs\n\nThese are conscious design decisions documented in [SECURITY.md](SECURITY.md):\n\n1. **CSP allows `unsafe-eval`** (but NOT `unsafe-inline`) — `unsafe-eval` required by Chart.js. All 67 inline handlers were converted to addEventListener in v5.0. XSS mitigated by output escaping on all user content (400+ `escapeHtml()` calls).\n2. **WebSocket accepts token via query string** — fallback for browsers that block cookies (Edge Tracking Prevention). Cookie-based auth is always preferred. Usage is logged.\n3. **Mixed auth model (cookie + Bearer + API key)** — cookies for browser UI, Bearer for API/CLI, API keys for integrations. All validate against the same session store.\n\n### Test Coverage\n\n- **1398 tests** across **83 test suites** (100% passing — 4 skipped are live-CF ACME integration tests gated on a CI secret)\n- Unit tests: crypto, helpers, validation, git patterns, platform detection, DMI cloud detection, translations, filter escape, metrics rendering, AI redactor (33 cases), audit-actions enum extraction, retention pure-evaluator (27 cases), provenance parser (15 cases), pCloud HTTP client (16 cases)\n- Integration tests: auth flow, API endpoints, RBAC, security, ACME + remediation orchestrators, registry push + browse + delete + retention apply, AI provider abstraction with MockAiProvider, pCloud backup orchestration (14 cases), audit-log monthly dump with hash-chain integrity round-trip (gzip → upload → download → gunzip → chain-walk)\n- Service tests: permissions RBAC filtering, settings key-value CRUD, security alert rule evaluation (threshold + windowed), event notifier dispatch + cooldown, cluster abstraction (HA mode), rate-limiter memory + Redis paths, registry repos CRUD\n- CI runs on every push via GitHub Actions (pinned to Node 24 actions as of v6.13.1; test count reported dynamically in the CI summary as of v6.15.0; lint enforcement added in v7.7.0 — fails on any warning or error)\n\n## Contributing\n\nContributions are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for:\n- Development setup\n- Architecture principles (no build step, no framework)\n- How to add pages, API endpoints, database migrations\n- How to add a language translation\n- Pull request checklist\n\n## Acknowledgments\n\nBuilt with:\n- [dockerode](https://github.com/apocas/dockerode) — Docker API client\n- [better-sqlite3](https://github.com/WiseLibs/better-sqlite3) — SQLite driver\n- [xterm.js](https://xtermjs.org/) — Terminal emulator\n- [Chart.js](https://www.chartjs.org/) — Charts\n- [Trivy](https://trivy.dev/) — Vulnerability scanner\n- [Grype](https://github.com/anchore/grype) — Vulnerability scanner by Anchore\n- [ssh2](https://github.com/mscdex/ssh2) — SSH client\n- [Font Awesome](https://fontawesome.com/) — Icons\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbogdanpricop%2Fdocker-dash","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbogdanpricop%2Fdocker-dash","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbogdanpricop%2Fdocker-dash/lists"}