DC-044 Add X-DashCaddy-HealthCheck marker to batch probe endpoint
The dashboard polls /api/v1/services/status (not /probe/:id) for its refresh loop. routes/services.js's requestStatusCode() didn't set the X-DashCaddy-HealthCheck: 1 marker, so the batch endpoint hit the forward_auth gate, got rate-limited by authLimiter (429), and reported 7 services (router, chat, sync, torrent, sonarr, radarr, prowlarr, requests) as down. Same fix in src/app.js /probe/:id (the single-service endpoint) for consistency. Without the marker, every probe from the container IP trips authLimiter within 20 requests and the rest of the batch fails. health-checker.js background poll was already setting the marker correctly, which is why the cached health view showed 15/15 while the live dashboard showed 8/15.
This commit is contained in:
@@ -86,13 +86,21 @@ module.exports = function({
|
|||||||
reject(new Error('Timeout'));
|
reject(new Error('Timeout'));
|
||||||
}, PROBE_TIMEOUT);
|
}, PROBE_TIMEOUT);
|
||||||
|
|
||||||
|
// X-DashCaddy-HealthCheck: 1 — Caddy's (dashcaddy_auth) block matches this
|
||||||
|
// header (from local container IPs) to bypass the forward_auth gate.
|
||||||
|
// Without it, every probe hits authLimiter → 429 → marked TIMEOUT.
|
||||||
|
// See /etc/caddy/Caddyfile (dashcaddy_auth) and the matching logic in
|
||||||
|
// src/monitoring/health-checker.js (which sets the same marker).
|
||||||
const req = lib.request({
|
const req = lib.request({
|
||||||
hostname: parsed.hostname,
|
hostname: parsed.hostname,
|
||||||
port: parsed.port || (isHttps ? 443 : 80),
|
port: parsed.port || (isHttps ? 443 : 80),
|
||||||
path: parsed.pathname + parsed.search,
|
path: parsed.pathname + parsed.search,
|
||||||
method,
|
method,
|
||||||
agent: isHttps ? probeHttpsAgent : undefined,
|
agent: isHttps ? probeHttpsAgent : undefined,
|
||||||
headers: { 'User-Agent': APP.USER_AGENTS.PROBE },
|
headers: {
|
||||||
|
'User-Agent': APP.USER_AGENTS.PROBE,
|
||||||
|
'X-DashCaddy-HealthCheck': '1',
|
||||||
|
},
|
||||||
}, (response) => {
|
}, (response) => {
|
||||||
clearTimeout(timer);
|
clearTimeout(timer);
|
||||||
response.resume();
|
response.resume();
|
||||||
@@ -111,8 +119,13 @@ module.exports = function({
|
|||||||
const pylonConfig = siteConfig?.pylon;
|
const pylonConfig = siteConfig?.pylon;
|
||||||
if (!pylonConfig?.url) return null;
|
if (!pylonConfig?.url) return null;
|
||||||
try {
|
try {
|
||||||
|
// Forward healthcheck marker to the remote pylon relay in case its Caddy
|
||||||
|
// is configured to bypass forward_auth on the same header.
|
||||||
const probeUrl = `${pylonConfig.url}/probe?url=${encodeURIComponent(targetUrl)}`;
|
const probeUrl = `${pylonConfig.url}/probe?url=${encodeURIComponent(targetUrl)}`;
|
||||||
const headers = {};
|
const headers = {
|
||||||
|
'User-Agent': APP.USER_AGENTS.PROBE,
|
||||||
|
'X-DashCaddy-HealthCheck': '1',
|
||||||
|
};
|
||||||
if (pylonConfig.key) headers['x-pylon-key'] = pylonConfig.key;
|
if (pylonConfig.key) headers['x-pylon-key'] = pylonConfig.key;
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
const timeout = setTimeout(() => controller.abort(), TIMEOUTS.HTTP_DEFAULT);
|
const timeout = setTimeout(() => controller.abort(), TIMEOUTS.HTTP_DEFAULT);
|
||||||
|
|||||||
@@ -799,14 +799,22 @@ async function createApp() {
|
|||||||
const isHttps = parsed.protocol === 'https:';
|
const isHttps = parsed.protocol === 'https:';
|
||||||
const lib = isHttps ? https : require('http');
|
const lib = isHttps ? https : require('http');
|
||||||
|
|
||||||
|
// X-DashCaddy-HealthCheck: 1 — Caddy's (dashcaddy_auth) block matches
|
||||||
|
// this header (from local container IPs) to bypass the forward_auth gate.
|
||||||
|
// Without it, every probe hits authLimiter → 429 → marked TIMEOUT.
|
||||||
|
// See /etc/caddy/Caddyfile (dashcaddy_auth) and the matching logic in
|
||||||
|
// src/monitoring/health-checker.js (which sets the same marker).
|
||||||
const options = {
|
const options = {
|
||||||
hostname: parsed.hostname,
|
hostname: parsed.hostname,
|
||||||
port: parsed.port || (isHttps ? 443 : 80),
|
port: parsed.port || (isHttps ? 443 : 80),
|
||||||
path: parsed.pathname + parsed.search,
|
path: parsed.pathname + parsed.search,
|
||||||
method: 'HEAD',
|
method: 'HEAD',
|
||||||
timeout: 5000,
|
timeout: 8000,
|
||||||
agent: isHttps ? httpsAgent : undefined,
|
agent: isHttps ? httpsAgent : undefined,
|
||||||
headers: { 'User-Agent': APP.USER_AGENTS.PROBE },
|
headers: {
|
||||||
|
'User-Agent': APP.USER_AGENTS.PROBE,
|
||||||
|
'X-DashCaddy-HealthCheck': '1',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const makeRequest = (method) => new Promise((resolve, reject) => {
|
const makeRequest = (method) => new Promise((resolve, reject) => {
|
||||||
@@ -832,7 +840,12 @@ async function createApp() {
|
|||||||
if (pylonConfig?.url) {
|
if (pylonConfig?.url) {
|
||||||
try {
|
try {
|
||||||
const pylonUrl = `${pylonConfig.url}/probe?url=${encodeURIComponent(url)}`;
|
const pylonUrl = `${pylonConfig.url}/probe?url=${encodeURIComponent(url)}`;
|
||||||
const headers = { 'User-Agent': APP.USER_AGENTS.PROBE };
|
// Forward healthcheck marker to the remote pylon relay in case its Caddy
|
||||||
|
// is configured to bypass forward_auth on the same header.
|
||||||
|
const headers = {
|
||||||
|
'User-Agent': APP.USER_AGENTS.PROBE,
|
||||||
|
'X-DashCaddy-HealthCheck': '1',
|
||||||
|
};
|
||||||
if (pylonConfig.key) headers['x-pylon-key'] = pylonConfig.key;
|
if (pylonConfig.key) headers['x-pylon-key'] = pylonConfig.key;
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
const pylonTimeout = setTimeout(() => controller.abort(), 8000);
|
const pylonTimeout = setTimeout(() => controller.abort(), 8000);
|
||||||
@@ -857,9 +870,12 @@ async function createApp() {
|
|||||||
port: 443,
|
port: 443,
|
||||||
path: '/',
|
path: '/',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
timeout: 5000,
|
timeout: 8000,
|
||||||
agent: httpsAgent,
|
agent: httpsAgent,
|
||||||
headers: { 'User-Agent': APP.USER_AGENTS.PROBE }
|
headers: {
|
||||||
|
'User-Agent': APP.USER_AGENTS.PROBE,
|
||||||
|
'X-DashCaddy-HealthCheck': '1',
|
||||||
|
}
|
||||||
}, (fRes) => {
|
}, (fRes) => {
|
||||||
fRes.resume();
|
fRes.resume();
|
||||||
resolve(fRes.statusCode);
|
resolve(fRes.statusCode);
|
||||||
|
|||||||
Reference in New Issue
Block a user