Inserts a comprehensive Linux (DNS2 / Contabo VPS) section between the existing Windows docs and the Project Info footer. The new section documents: - Production paths (/opt/dashcaddy/, /var/www/dashcaddy-status/, /etc/dashcaddy/) - Container mount points with the /app/data/ auto-resolve fallback - The three-filesystem frontend trap (source vs live vs build-context) - Common admin commands (Caddyfile reload, logs, rebuild, services.json) - Windows-vs-Linux differences table - Four Linux-specific gotchas (Caddy network_mode host, credentials.json perms, CORS_ORIGINS, TS_AUTHKEY) Also corrects the stale 'Version: 1.0' field to current 1.13.4 and adds the Linux-side default TLD (.home). All existing Windows content preserved verbatim per the LITERAL COPY RULE.
13 KiB
DashCaddy Project Guidelines for AI Assistants
HARD RULE: Docker Storage on E: Drive
ALL Docker container data, volumes, bind mounts, and app configs MUST use E:/dockerdata/ via bind mounts or CIFS volumes. No exceptions.
- E: is a network share (
\\Sami-pc\e_share) shared across all home network computers - The ONLY thing allowed on C: is the Docker Desktop WSL engine VHD (
C:/dockerdata/DockerDesktopWSL/) — this is the absolute bare minimum WSL2 requires (local NTFS). WSL2 cannot create VHDs on network shares. - Keep C: Docker usage under 5GB
- When deploying new containers, always use
E:/dockerdata/<app-name>/for bind mount paths - For CIFS volumes in docker-compose, use
//Sami-pc/e_share/dockerdata/...as the device path
CRITICAL: Production vs Development Paths
Production Files (LIVE - what actually runs)
C:/caddy/
├── Caddyfile # Active Caddy configuration
├── services.json # Services shown on dashboard
├── dns-credentials.json # DNS API credentials
├── config.json # DashCaddy configuration
└── sites/
└── status/ # Dashboard frontend files
└── assets/ # Logos, fonts, icons
Development Files (for editing/testing)
e:/CaddyCerts/sites/
├── caddy-api/
│ ├── server.js # API server source code
│ ├── app-templates.js # Docker app templates (52+ apps)
│ ├── services.json # DEV ONLY - not used in production!
│ └── ...
└── status/
└── index.html # Dashboard UI source
Docker Container Mount Points
The caddy-api container mounts production files:
| Container Path | Host Path (Production) |
|---|---|
/app/services.json |
C:/caddy/services.json |
/app/dns-credentials.json |
C:/caddy/dns-credentials.json |
/caddyfile |
C:/caddy/Caddyfile |
/app/assets |
C:/caddy/sites/status/assets |
When Making Changes
To add/remove services from dashboard:
Edit C:/caddy/services.json (NOT e:/CaddyCerts/sites/caddy-api/services.json)
To modify Caddy reverse proxy rules:
Edit C:/caddy/Caddyfile, then reload via:
curl -X POST http://localhost:2019/load -H "Content-Type: text/caddyfile" --data-binary @"C:/caddy/Caddyfile"
To modify API server code:
Edit e:/CaddyCerts/sites/caddy-api/server.js, then:
- Copy to production:
C:/caddy/sites/caddy-api/ - Restart container:
docker restart caddy-api
To modify app templates:
Edit e:/CaddyCerts/sites/caddy-api/app-templates.js
(Templates are loaded at runtime, changes require container restart)
To modify dashboard UI:
Edit e:/CaddyCerts/sites/status/index.html
Copy to C:/caddy/sites/status/ for production
To modify DashCA (CA certificate distribution):
Edit files in e:/CaddyCerts/sites/ca/, then:
- Regenerate certificate formats:
cd e:/CaddyCerts/sites/ca/scripts && bash generate-all.sh - Copy to production:
cp -r e:/CaddyCerts/sites/ca/* C:/caddy/sites/ca/ - Reload Caddy if Caddyfile changes were made
DashCA - Certificate Authority Distribution
Purpose: Provides a one-click installation page for the root CA certificate, allowing users to easily trust *.sami domains on any device.
Access: https://ca.sami (or https://ca.yourdomain for other installations)
File Locations
Development (for editing):
e:/CaddyCerts/sites/ca/
├── index.html # Landing page
├── root.crt, root.der # Certificate formats
├── root.mobileconfig # Apple profile
├── intermediate.crt # Intermediate CA
├── cert-info.json # Certificate metadata
├── scripts/
│ ├── install.ps1 # Windows installer
│ ├── install.sh # Linux/macOS installer
│ ├── generate-cert-info.js # Extract cert metadata
│ ├── generate-mobileconfig.js # Generate Apple profile
│ └── generate-all.sh # Regenerate all formats
└── assets/ # Icons, logos
Production (served by Caddy):
C:/caddy/sites/ca/
├── index.html
├── root.crt, root.der
├── root.mobileconfig
├── install.ps1, install.sh
└── assets/
Certificate Source
Caddy's built-in PKI generates certificates at:
- Root CA:
C:/caddy/certs/pki/authorities/local/root.crt - Intermediate CA:
C:/caddy/certs/pki/authorities/local/intermediate.crt
Certificate Info:
- CN: Sami Home Network Root CA
- Algorithm: ECDSA P-256 with SHA-256
- Valid Until: Dec 22, 2034 (~10 years)
- Fingerprint:
08:98:A5:63:F5:A1:A2:58:5F:02:D7:A8:A2:54:87:E6:BC:33:96:21:29:0E
Deployment
DashCA is a static site (not Docker-based), deployed via the app selector:
- Navigate to App Selector in dashboard
- Find "DashCA" in Security category
- Click Deploy
- System automatically:
- Creates
C:/caddy/sites/ca/directory - Copies files from development directory
- Generates certificate formats (DER, mobileconfig)
- Adds ca.sami block to Caddyfile
- Reloads Caddy configuration
- Registers service in
services.json
- Creates
Updating Certificates
When Caddy's CA certificate is renewed (every ~10 years):
# 1. Regenerate all certificate formats
cd e:/CaddyCerts/sites/ca/scripts
bash generate-all.sh
# 2. Update fingerprint in installation scripts
# Edit install.ps1 - update $ExpectedFingerprint
# Edit install.sh - update EXPECTED_FP
# 3. Copy to production
cp -r e:/CaddyCerts/sites/ca/* C:/caddy/sites/ca/
# 4. Notify users via dashboard or email
API Endpoints
- GET /api/ca/info - Returns certificate metadata (name, fingerprint, expiration, etc.)
- GET /api/health/ca - Returns CA expiration health status
healthy: >90 days remainingwarning: 30-90 days remainingcritical: <30 days remaining
Caddyfile Configuration
DashCA's Caddyfile block (auto-generated on deployment):
- Root:
C:/caddy/sites/ca - TLS: Internal (uses Caddy's local CA)
- MIME Types: Proper headers for .crt, .der, .mobileconfig, .ps1, .sh files
- SPA Fallback: Rewrites non-file requests to /index.html
- Cache Control: Certificates cached for 24h, HTML not cached
Supported Platforms
- Windows: PowerShell installer (installs to LocalMachine\Root store)
- macOS: .mobileconfig profile or command-line installer
- Linux: Shell installer (Debian, RedHat, Arch)
- iOS: .mobileconfig profile (requires manual trust in Settings)
- Android: Direct .crt download (installs as user certificate)
Landing Page Features
- Automatic OS detection
- QR code for mobile access
- Certificate info display (loaded from
/api/ca/info) - Platform-specific installation instructions
- Copy-to-clipboard for fingerprint and commands
- Download links for all certificate formats
Troubleshooting
Issue: Certificate fingerprint mismatch during installation Cause: CA certificate was renewed Solution: Regenerate certificates and update fingerprints in install scripts
Issue: *.sami sites still show warnings after CA install Cause: Browser may have cached the untrusted state Solution: Clear browser cache, restart browser, or visit site in incognito mode
Issue: iOS doesn't trust certificate after profile install Cause: iOS requires manual trust enablement Solution: Settings → General → About → Certificate Trust Settings → Enable trust
Key Services
| Service | Port | Description |
|---|---|---|
| Caddy (HTTPS) | 443 | Reverse proxy |
| Caddy Admin | 2019 | Caddy API (note: NOT 2021) |
| DashCaddy API | 3001 | Dashboard backend |
| DNS2 (Primary) | 100.74.102.61:5380 | Technitium DNS |
| DNS1 (Secondary) | 192.168.254.204:5380 | Technitium DNS |
Common Mistakes to Avoid
- Wrong services.json: The API container reads from
C:/caddy/services.json, not the development copy - Caddy admin port: It's 2019, not 2021 (check with
netstatif unsure) - DNS server: DNS2 (100.74.102.61) is PRIMARY, DNS1 is secondary
- Caddyfile not reloaded: After editing, must POST to /load endpoint or restart Caddy
Linux Deployment (DNS2 / Contabo VPS)
The Windows path sections above describe the SAMI-PC deployment. DashCaddy also runs as a Docker container on Linux (DNS2 = 194.233.88.206 / Tailscale 100.121.150.22). The Linux deployment uses a different layout driven by start.sh and docker run bind mounts.
Production paths (Linux)
/opt/dashcaddy/
├── dashcaddy-api/ # Built image source (rebuilt on update)
│ ├── Dockerfile
│ └── ...
├── status/ # Dashboard frontend SOURCE (build context)
├── credentials.json # Encrypted credentials (mounted to /app/data)
├── .encryption-key # AES key (mounted to /app/data)
└── services.json # Live service list (mounted to /app/data)
/var/www/dashcaddy-status/ # Dashboard frontend LIVE (served by Caddy)
# Built bundle output from status/ — NOT the source
# tree, NOT the docker build context
/etc/dashcaddy/
└── Caddyfile # Active Caddy configuration
/root/.dashcaddy/ # Per-user state, credentials backup, license
Container mount points (Linux)
| Container path | Host path |
|---|---|
/app/data/credentials.json |
/opt/dashcaddy/credentials.json |
/app/data/.encryption-key |
/opt/dashcaddy/.encryption-key |
/app/data/services.json |
/opt/dashcaddy/services.json |
/caddyfile |
/etc/dashcaddy/Caddyfile |
Note: the app must auto-resolve both /app/data/... AND the older /app/... layout (where files mounted directly to /app/). The credential-manager.js and crypto-utils.js modules handle this fallback. This is intentional — fresh installs get /app/data/, legacy installs keep working without env-var overrides.
Three-filesystem frontend trap (Linux)
The dashboard frontend lives on three separate paths that get confused:
- Source —
/opt/dashcaddy/status/— what you edit - Live —
/var/www/dashcaddy-status/— what Caddy serves to browsers - Build context —
/opt/dashcaddy/dashcaddy-api/— whatdocker builduses
Editing /opt/dashcaddy/status/index.html and restarting the container does nothing visible until you run the build (which writes to /var/www/dashcaddy-status/). Always rebuild + container-recreate together. See the dashcaddy skill § Deploy cycle for the exact sequence.
Common commands (Linux)
# Edit Caddyfile then reload (no restart needed)
curl -X POST http://localhost:2019/load \
-H "Content-Type: text/caddyfile" \
--data-binary @/etc/dashcaddy/Caddyfile
# View container logs
docker logs dashcaddy-api --tail 200
# Rebuild + restart after API code change
cd /opt/dashcaddy && git pull
cd /opt/dashcaddy/dashcaddy-api && docker build -t dashcaddy-api:local .
docker stop dashcaddy-api && docker rm dashcaddy-api
# (then re-run the container with the mount table above)
# Edit a service in the live list
vi /opt/dashcaddy/services.json # live-reloaded by the watcher
Differences from Windows
| Concern | Windows (SAMI-PC) | Linux (DNS2) |
|---|---|---|
| Drive letter | C:/, E:/ |
/opt/, /etc/, /var/www/ |
| Network share for state | \\Sami-pc\e_share |
(none — all local) |
| Docker engine | Docker Desktop on WSL2 | Docker Engine on host |
| Backend admin | PowerShell | bash + curl |
| Caddyfile reload | POST to localhost:2019/load |
POST to localhost:2019/load (same) |
| Caddy admin port | 2019 | 2019 |
| Self-update | host-side PowerShell updater | host-side bash updater (start.sh) |
| Tailscale | Same 100.x.x.x magic DNS |
Same |
| DNS server | DNS2 (100.74.102.61) primary | DNS2 (100.121.150.22 / 194.233.88.206) — is the primary |
Linux-specific gotchas
- Caddy needs
network_mode: host(or--network host) so it can bind :80 and :443 directly. Bridge mode + port mapping also works, butnetwork_mode: hostis simpler for a single-host setup. credentials.jsonpermissions matter — file mode0600, owned by the same UID the container runs as. If the host root creates it but the container runs asnode(uid 1000), the API will fail to read it. Eitherchown 1000:1000or run the container as--user 0.- Don't use
localhostin the API's CORS_ORIGINS — it conflicts with the Tailscale IP. Use the actualhttps://dashcaddy<your-tld>URL. - Tailscale cert provisioning — set
TS_AUTHKEYin/etc/dashcaddy/tailscale.env(mode 0600) before first start. Without it, the magic DNS hostname will resolve but TLS will fail.
Project Info
- Name: DashCaddy
- Version: 1.13.4 (current; CHANGELOG.md
[Unreleased]tracks the next bump) - Purpose: Unified management for Docker + Caddy + DNS
- Local TLD (Windows):
.sami - Local TLD (Linux, DNS2):
.home(default; configurable viasiteConfig.tld)