Full codebase including API server (32 modules + routes), dashboard frontend, DashCA certificate distribution, installer script, and deployment skills.
488 lines
16 KiB
HTML
488 lines
16 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<title>DashCaddy - Troubleshooting</title>
|
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
|
<link rel="icon" href="/assets/dashcaddy-favicon.ico" sizes="any">
|
|
<style>
|
|
:root {
|
|
--bg: #0b0f1a;
|
|
--fg: #e8ecf5;
|
|
--muted: #9aa6bf;
|
|
--card-base: #121826;
|
|
--border: #263552;
|
|
--accent: #8FD6FF;
|
|
--accent-strong: #1F7BFF;
|
|
--ok-bg: #0c2430;
|
|
--ok-fg: #7ef2ff;
|
|
--bad-bg: #2a121a;
|
|
--bad-fg: #ff9aa3;
|
|
--radius: 12px;
|
|
}
|
|
|
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
background: var(--bg);
|
|
color: var(--fg);
|
|
line-height: 1.6;
|
|
padding: 24px;
|
|
max-width: 900px;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 16px;
|
|
margin-bottom: 32px;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
header h1 {
|
|
font-size: 1.8rem;
|
|
font-weight: 700;
|
|
color: var(--accent);
|
|
}
|
|
|
|
header a {
|
|
color: var(--muted);
|
|
text-decoration: none;
|
|
font-size: 0.9rem;
|
|
margin-left: auto;
|
|
}
|
|
header a:hover { color: var(--accent); }
|
|
|
|
.search-box {
|
|
width: 100%;
|
|
padding: 12px 16px;
|
|
border-radius: var(--radius);
|
|
border: 1px solid var(--border);
|
|
background: var(--card-base);
|
|
color: var(--fg);
|
|
font-size: 1rem;
|
|
outline: none;
|
|
margin-bottom: 24px;
|
|
}
|
|
.search-box:focus { border-color: var(--accent); }
|
|
.search-box::placeholder { color: var(--muted); }
|
|
|
|
.category {
|
|
margin-bottom: 32px;
|
|
}
|
|
|
|
.category h2 {
|
|
font-size: 1.1rem;
|
|
font-weight: 600;
|
|
color: var(--accent);
|
|
margin-bottom: 12px;
|
|
padding-bottom: 8px;
|
|
border-bottom: 1px solid var(--border);
|
|
}
|
|
|
|
.error-card {
|
|
background: var(--card-base);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius);
|
|
padding: 16px 20px;
|
|
margin-bottom: 10px;
|
|
transition: border-color 0.2s;
|
|
}
|
|
.error-card.highlight {
|
|
border-color: var(--accent);
|
|
box-shadow: 0 0 12px rgba(143, 214, 255, 0.15);
|
|
}
|
|
|
|
.error-header {
|
|
display: flex;
|
|
align-items: baseline;
|
|
gap: 12px;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.error-code {
|
|
font-family: 'Courier New', monospace;
|
|
font-weight: 700;
|
|
font-size: 0.95rem;
|
|
color: var(--bad-fg);
|
|
background: var(--bad-bg);
|
|
padding: 2px 8px;
|
|
border-radius: 6px;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.error-message {
|
|
font-weight: 500;
|
|
color: var(--fg);
|
|
}
|
|
|
|
.error-details {
|
|
display: grid;
|
|
grid-template-columns: auto 1fr;
|
|
gap: 4px 12px;
|
|
font-size: 0.9rem;
|
|
margin-top: 8px;
|
|
}
|
|
|
|
.error-details dt {
|
|
color: var(--muted);
|
|
font-weight: 500;
|
|
}
|
|
|
|
.error-details dd {
|
|
color: var(--fg);
|
|
}
|
|
|
|
.fix {
|
|
color: var(--ok-fg);
|
|
background: var(--ok-bg);
|
|
padding: 2px 6px;
|
|
border-radius: 4px;
|
|
font-size: 0.85rem;
|
|
}
|
|
|
|
.no-results {
|
|
text-align: center;
|
|
color: var(--muted);
|
|
padding: 40px 0;
|
|
display: none;
|
|
}
|
|
|
|
footer {
|
|
text-align: center;
|
|
color: var(--muted);
|
|
font-size: 0.8rem;
|
|
margin-top: 40px;
|
|
padding-top: 20px;
|
|
border-top: 1px solid var(--border);
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<header>
|
|
<h1>Troubleshooting</h1>
|
|
<a href="/">← Back to Dashboard</a>
|
|
</header>
|
|
|
|
<input type="text" class="search-box" id="search" placeholder="Search by error code (e.g. DC-200) or keyword..." autofocus />
|
|
|
|
<div id="no-results" class="no-results">No matching errors found.</div>
|
|
|
|
<div id="error-list">
|
|
|
|
<!-- Authentication & CSRF -->
|
|
<div class="category" data-category="auth">
|
|
<h2>Authentication & CSRF (DC-1xx)</h2>
|
|
|
|
<div class="error-card" data-code="DC-100">
|
|
<div class="error-header">
|
|
<span class="error-code">DC-100</span>
|
|
<span class="error-message">CSRF token missing</span>
|
|
</div>
|
|
<dl class="error-details">
|
|
<dt>Cause</dt>
|
|
<dd>Your browser cookie expired or was blocked. This often happens after the browser has been idle for a long time.</dd>
|
|
<dt>Fix</dt>
|
|
<dd><span class="fix">Hard refresh the page with Ctrl+Shift+R (or Cmd+Shift+R on Mac), then try again.</span></dd>
|
|
</dl>
|
|
</div>
|
|
|
|
<div class="error-card" data-code="DC-101">
|
|
<div class="error-header">
|
|
<span class="error-code">DC-101</span>
|
|
<span class="error-message">CSRF token invalid</span>
|
|
</div>
|
|
<dl class="error-details">
|
|
<dt>Cause</dt>
|
|
<dd>The security token in your browser doesn't match the one the server expects. This can happen after long idle periods or if you have multiple tabs open.</dd>
|
|
<dt>Fix</dt>
|
|
<dd><span class="fix">Refresh the page and try the action again.</span></dd>
|
|
</dl>
|
|
</div>
|
|
|
|
<div class="error-card" data-code="DC-110">
|
|
<div class="error-header">
|
|
<span class="error-code">DC-110</span>
|
|
<span class="error-message">Authentication required</span>
|
|
</div>
|
|
<dl class="error-details">
|
|
<dt>Cause</dt>
|
|
<dd>Your TOTP session has expired. Sessions last for the duration configured in your TOTP settings (default: 24 hours).</dd>
|
|
<dt>Fix</dt>
|
|
<dd><span class="fix">Enter your TOTP code from your authenticator app to re-authenticate.</span></dd>
|
|
</dl>
|
|
</div>
|
|
|
|
<div class="error-card" data-code="DC-111">
|
|
<div class="error-header">
|
|
<span class="error-code">DC-111</span>
|
|
<span class="error-message">Invalid code</span>
|
|
</div>
|
|
<dl class="error-details">
|
|
<dt>Cause</dt>
|
|
<dd>The TOTP code you entered is incorrect or has already expired. Codes refresh every 30 seconds.</dd>
|
|
<dt>Fix</dt>
|
|
<dd><span class="fix">Check your authenticator app for the current code. Wait for a fresh code if the current one is about to expire.</span></dd>
|
|
</dl>
|
|
</div>
|
|
|
|
<div class="error-card" data-code="DC-120">
|
|
<div class="error-header">
|
|
<span class="error-code">DC-120</span>
|
|
<span class="error-message">Access denied - Tailscale required</span>
|
|
</div>
|
|
<dl class="error-details">
|
|
<dt>Cause</dt>
|
|
<dd>The dashboard is configured to require a Tailscale VPN connection, and you're not currently connected.</dd>
|
|
<dt>Fix</dt>
|
|
<dd><span class="fix">Connect to Tailscale VPN first, then try accessing the dashboard again.</span></dd>
|
|
</dl>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Deployment & Containers -->
|
|
<div class="category" data-category="deploy">
|
|
<h2>Deployment & Containers (DC-2xx)</h2>
|
|
|
|
<div class="error-card" data-code="DC-200">
|
|
<div class="error-header">
|
|
<span class="error-code">DC-200</span>
|
|
<span class="error-message">Port is already in use</span>
|
|
</div>
|
|
<dl class="error-details">
|
|
<dt>Cause</dt>
|
|
<dd>Another container or process on the host is already using the port you selected. This sometimes happens after a failed deploy leaves a stale container behind.</dd>
|
|
<dt>Fix</dt>
|
|
<dd><span class="fix">Use a different port in Advanced Options, or stop the conflicting service first. Check the Monitor panel to see which container is using the port.</span></dd>
|
|
</dl>
|
|
</div>
|
|
|
|
<div class="error-card" data-code="DC-201">
|
|
<div class="error-header">
|
|
<span class="error-code">DC-201</span>
|
|
<span class="error-message">Failed to pull image</span>
|
|
</div>
|
|
<dl class="error-details">
|
|
<dt>Cause</dt>
|
|
<dd>Docker couldn't download the container image. This is usually a network issue, or the image name/tag doesn't exist on Docker Hub.</dd>
|
|
<dt>Fix</dt>
|
|
<dd><span class="fix">Check your internet connection. If using a custom image, verify the image name and tag are correct.</span></dd>
|
|
</dl>
|
|
</div>
|
|
|
|
<div class="error-card" data-code="DC-202">
|
|
<div class="error-header">
|
|
<span class="error-code">DC-202</span>
|
|
<span class="error-message">Container failed to start</span>
|
|
</div>
|
|
<dl class="error-details">
|
|
<dt>Cause</dt>
|
|
<dd>The container was created but couldn't start or become healthy. Common reasons include misconfigured environment variables, missing volume mounts, or insufficient resources.</dd>
|
|
<dt>Fix</dt>
|
|
<dd><span class="fix">Check the Logs panel for container-specific error messages. Try redeploying with default settings.</span></dd>
|
|
</dl>
|
|
</div>
|
|
|
|
<div class="error-card" data-code="DC-203">
|
|
<div class="error-header">
|
|
<span class="error-code">DC-203</span>
|
|
<span class="error-message">Port conflict with another service</span>
|
|
</div>
|
|
<dl class="error-details">
|
|
<dt>Cause</dt>
|
|
<dd>Another DashCaddy-managed service is already using the port you specified. DashCaddy checks for this before deploying to prevent conflicts.</dd>
|
|
<dt>Fix</dt>
|
|
<dd><span class="fix">Choose a different port in Advanced Options, or remove the conflicting service first.</span></dd>
|
|
</dl>
|
|
</div>
|
|
|
|
<div class="error-card" data-code="DC-210">
|
|
<div class="error-header">
|
|
<span class="error-code">DC-210</span>
|
|
<span class="error-message">Invalid IP address</span>
|
|
</div>
|
|
<dl class="error-details">
|
|
<dt>Cause</dt>
|
|
<dd>The IP address field contains an invalid value. It must be a valid IPv4 or IPv6 address, or one of the allowed hostnames.</dd>
|
|
<dt>Fix</dt>
|
|
<dd><span class="fix">Use a valid IP address (e.g., 192.168.1.100) or "localhost". Leave blank to use the default.</span></dd>
|
|
</dl>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- DNS & Caddy Configuration -->
|
|
<div class="category" data-category="caddy">
|
|
<h2>DNS & Caddy Configuration (DC-3xx)</h2>
|
|
|
|
<div class="error-card" data-code="DC-300">
|
|
<div class="error-header">
|
|
<span class="error-code">DC-300</span>
|
|
<span class="error-message">DNS token unavailable</span>
|
|
</div>
|
|
<dl class="error-details">
|
|
<dt>Cause</dt>
|
|
<dd>The DNS server credentials have expired or are missing. DashCaddy needs valid DNS credentials to create and manage DNS records.</dd>
|
|
<dt>Fix</dt>
|
|
<dd><span class="fix">Go to Tokens in the toolbar, select DNS, and re-enter your DNS server credentials.</span></dd>
|
|
</dl>
|
|
</div>
|
|
|
|
<div class="error-card" data-code="DC-301">
|
|
<div class="error-header">
|
|
<span class="error-code">DC-301</span>
|
|
<span class="error-message">Invalid domain/subdomain format</span>
|
|
</div>
|
|
<dl class="error-details">
|
|
<dt>Cause</dt>
|
|
<dd>The domain or subdomain name contains invalid characters. Domain names can only contain lowercase letters, numbers, hyphens, and dots.</dd>
|
|
<dt>Fix</dt>
|
|
<dd><span class="fix">Use only letters (a-z), numbers (0-9), hyphens (-), and dots (.) in your domain name.</span></dd>
|
|
</dl>
|
|
</div>
|
|
|
|
<div class="error-card" data-code="DC-302">
|
|
<div class="error-header">
|
|
<span class="error-code">DC-302</span>
|
|
<span class="error-message">Site already exists in Caddyfile</span>
|
|
</div>
|
|
<dl class="error-details">
|
|
<dt>Cause</dt>
|
|
<dd>A site block for this domain is already present in the Caddy configuration file. You can't create a duplicate entry.</dd>
|
|
<dt>Fix</dt>
|
|
<dd><span class="fix">Edit the existing site configuration, or remove it first before creating a new one.</span></dd>
|
|
</dl>
|
|
</div>
|
|
|
|
<div class="error-card" data-code="DC-303">
|
|
<div class="error-header">
|
|
<span class="error-code">DC-303</span>
|
|
<span class="error-message">Caddy reload failed</span>
|
|
</div>
|
|
<dl class="error-details">
|
|
<dt>Cause</dt>
|
|
<dd>Caddy couldn't reload its configuration. This usually means there's a syntax error in the Caddyfile, or Caddy's admin API is unreachable.</dd>
|
|
<dt>Fix</dt>
|
|
<dd><span class="fix">Check the Logs panel for the specific Caddy error. The Caddyfile change was automatically rolled back. If the problem persists, verify Caddy is running.</span></dd>
|
|
</dl>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Service Management -->
|
|
<div class="category" data-category="services">
|
|
<h2>Service Management (DC-4xx)</h2>
|
|
|
|
<div class="error-card" data-code="DC-400">
|
|
<div class="error-header">
|
|
<span class="error-code">DC-400</span>
|
|
<span class="error-message">Container not found</span>
|
|
</div>
|
|
<dl class="error-details">
|
|
<dt>Cause</dt>
|
|
<dd>The Docker container was removed outside of DashCaddy (e.g., via Docker Desktop or the CLI). DashCaddy still has it registered but can't find it.</dd>
|
|
<dt>Fix</dt>
|
|
<dd><span class="fix">Delete the service card from DashCaddy, then redeploy the app from the App Selector.</span></dd>
|
|
</dl>
|
|
</div>
|
|
|
|
<div class="error-card" data-code="DC-401">
|
|
<div class="error-header">
|
|
<span class="error-code">DC-401</span>
|
|
<span class="error-message">Update failed</span>
|
|
</div>
|
|
<dl class="error-details">
|
|
<dt>Cause</dt>
|
|
<dd>The container update process failed during image pull, container recreation, or startup. The old container may have been removed but the new one couldn't start.</dd>
|
|
<dt>Fix</dt>
|
|
<dd><span class="fix">Check the Logs panel for details. If the container is gone, redeploy the app from the App Selector.</span></dd>
|
|
</dl>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Credentials & Auto-Login -->
|
|
<div class="category" data-category="creds">
|
|
<h2>Credentials & Auto-Login (DC-5xx)</h2>
|
|
|
|
<div class="error-card" data-code="DC-500">
|
|
<div class="error-header">
|
|
<span class="error-code">DC-500</span>
|
|
<span class="error-message">No credentials stored</span>
|
|
</div>
|
|
<dl class="error-details">
|
|
<dt>Cause</dt>
|
|
<dd>Auto-login was attempted but no username/password is saved for this service. DashCaddy needs stored credentials to log you in automatically.</dd>
|
|
<dt>Fix</dt>
|
|
<dd><span class="fix">Click the key icon (🔑) on the service card to add your credentials for auto-login.</span></dd>
|
|
</dl>
|
|
</div>
|
|
|
|
<div class="error-card" data-code="DC-501">
|
|
<div class="error-header">
|
|
<span class="error-code">DC-501</span>
|
|
<span class="error-message">Login failed</span>
|
|
</div>
|
|
<dl class="error-details">
|
|
<dt>Cause</dt>
|
|
<dd>The stored credentials were rejected by the service. The username or password may be incorrect, or the service's auth endpoint may have changed.</dd>
|
|
<dt>Fix</dt>
|
|
<dd><span class="fix">Click the key icon (🔑) on the service card to update your credentials. Verify the username and password are correct by logging into the service directly first.</span></dd>
|
|
</dl>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<footer>
|
|
DashCaddy v0.95 · Error codes help you quickly find solutions. Search by code or keyword above.
|
|
</footer>
|
|
|
|
<script>
|
|
(function() {
|
|
const search = document.getElementById('search');
|
|
const cards = document.querySelectorAll('.error-card');
|
|
const categories = document.querySelectorAll('.category');
|
|
const noResults = document.getElementById('no-results');
|
|
|
|
search.addEventListener('input', function() {
|
|
const q = this.value.trim().toLowerCase();
|
|
|
|
if (!q) {
|
|
cards.forEach(c => { c.style.display = ''; c.classList.remove('highlight'); });
|
|
categories.forEach(c => c.style.display = '');
|
|
noResults.style.display = 'none';
|
|
return;
|
|
}
|
|
|
|
let found = 0;
|
|
cards.forEach(card => {
|
|
const text = card.textContent.toLowerCase();
|
|
const code = card.dataset.code.toLowerCase();
|
|
const match = text.includes(q) || code.includes(q);
|
|
card.style.display = match ? '' : 'none';
|
|
card.classList.toggle('highlight', match && q.startsWith('dc-'));
|
|
if (match) found++;
|
|
});
|
|
|
|
// Hide categories with no visible cards
|
|
categories.forEach(cat => {
|
|
const visible = cat.querySelectorAll('.error-card:not([style*="display: none"])');
|
|
cat.style.display = visible.length ? '' : 'none';
|
|
});
|
|
|
|
noResults.style.display = found === 0 ? '' : 'none';
|
|
});
|
|
|
|
// Auto-search if URL has hash (e.g., help-errors.html#DC-200)
|
|
if (location.hash) {
|
|
const code = decodeURIComponent(location.hash.slice(1));
|
|
search.value = code;
|
|
search.dispatchEvent(new Event('input'));
|
|
}
|
|
})();
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|