feat(monitoring): add automatic restart of unreachable customer containers

Some customers only regain access to their NetBird web UI after a manual
container restart, and until now that required someone to notice and do it
by hand. The scheduler now optionally probes each customer's actual
dashboard URL over HTTP(S) every poll interval (not just Docker container
state, since a container can be "running" while the web UI behind it still
doesn't respond) and restarts that customer's containers if it doesn't
answer, gated by a per-deployment cooldown to avoid restart loops on a
persistently broken customer.

New system setting "Automatic Restart of Unreachable Containers" (default
off) with a configurable cooldown. Every automatic restart is logged in the
affected customer's own log, same as a manual restart.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
2026-09-23 13:20:40 +02:00
co-authored by Claude Sonnet 5
parent 75357b0633
commit 189c49d505
9 changed files with 156 additions and 1 deletions
+18
View File
@@ -669,6 +669,24 @@
</div>
</form>
<hr>
<h6 data-i18n="monitoring.autoRestartTitle">Automatic Restart of Unreachable Containers</h6>
<p class="text-muted small" data-i18n="monitoring.autoRestartHint">Some customers only regain access to their NetBird web UI after a container restart. When enabled, the scheduler periodically checks whether each customer's dashboard actually responds and restarts their containers if it doesn't, logging the action in the customer's log.</p>
<form id="settings-auto-restart-form">
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" id="cfg-auto-restart-enabled">
<label class="form-check-label" for="cfg-auto-restart-enabled" data-i18n="monitoring.autoRestartEnabled">Automatically restart unreachable customer containers</label>
</div>
<div class="row g-3 align-items-end">
<div class="col-md-3">
<label class="form-label" data-i18n="monitoring.autoRestartCooldown">Cooldown between restarts (minutes)</label>
<input type="number" class="form-control" id="cfg-auto-restart-cooldown" min="1" max="1440" value="30">
</div>
</div>
<div class="mt-3">
<button type="submit" class="btn btn-primary btn-sm"><i class="bi bi-save me-1"></i><span data-i18n="monitoring.saveAutoRestartSettings">Save Automation</span></button>
</div>
</form>
<hr>
<h6 data-i18n="customer.nbuMasterTitle">NetBird Client Auto-Updates (all customers)</h6>
<p class="text-muted small" data-i18n="customer.nbuMasterHint">Controls the "Automatic Updates" setting inside every customer's own NetBird dashboard (Settings &gt; Clients). Set the default here, then push it to all customers at once. Individual customers can still be overridden from their detail page.</p>
<form id="settings-nbu-master-form">
+17
View File
@@ -1096,6 +1096,9 @@ async function loadSettings() {
? new Date(cfg.auto_update_last_run_at).toLocaleString()
: t('monitoring.autoUpdateNever');
document.getElementById('cfg-auto-restart-enabled').checked = cfg.auto_restart_unreachable_enabled || false;
document.getElementById('cfg-auto-restart-cooldown').value = cfg.auto_restart_cooldown_minutes || 30;
const nbuVersion = cfg.netbird_client_auto_update_version || 'disabled';
const nbuIsCustom = nbuVersion !== 'disabled' && nbuVersion !== 'latest';
document.getElementById('cfg-nbu-version-select').value = nbuIsCustom ? 'custom' : nbuVersion;
@@ -1236,6 +1239,20 @@ document.getElementById('settings-auto-update-form').addEventListener('submit',
}
});
// Automatic restart of unreachable customer containers
document.getElementById('settings-auto-restart-form').addEventListener('submit', async (e) => {
e.preventDefault();
try {
await api('PUT', '/settings/system', {
auto_restart_unreachable_enabled: document.getElementById('cfg-auto-restart-enabled').checked,
auto_restart_cooldown_minutes: parseInt(document.getElementById('cfg-auto-restart-cooldown').value, 10) || 30,
});
showSettingsAlert('success', t('messages.imageSettingsSaved'));
} catch (err) {
showSettingsAlert('danger', t('errors.failed', { error: err.message }));
}
});
function _readNbuMasterForm() {
const select = document.getElementById('cfg-nbu-version-select').value;
const version = select === 'custom' ? document.getElementById('cfg-nbu-custom-version').value.trim() : select;
+5
View File
@@ -455,6 +455,11 @@
"autoUpdateLastRun": "Letzte automatische Prüfung",
"autoUpdateNever": "Noch nie ausgeführt",
"saveAutoUpdateSettings": "Automatisierung speichern",
"autoRestartTitle": "Automatischer Neustart nicht erreichbarer Container",
"autoRestartHint": "Manche Kunden erhalten den Zugriff auf ihre NetBird-Weboberfläche erst nach einem Container-Neustart zurück. Wenn aktiviert, prüft der Scheduler regelmäßig, ob die Weboberfläche jedes Kunden tatsächlich antwortet, und startet die Container bei Bedarf neu — mit Protokollierung im Kunden-Log.",
"autoRestartEnabled": "Nicht erreichbare Kunden-Container automatisch neu starten",
"autoRestartCooldown": "Wartezeit zwischen Neustarts (Minuten)",
"saveAutoRestartSettings": "Automatisierung speichern",
"updateLogTitle": "Update-Verlauf",
"noUpdateLogs": "Noch keine Update-Läufe protokolliert.",
"logTypeScheduled": "Automatisch",
+5
View File
@@ -362,6 +362,11 @@
"autoUpdateLastRun": "Last automatic check",
"autoUpdateNever": "Never run",
"saveAutoUpdateSettings": "Save Automation",
"autoRestartTitle": "Automatic Restart of Unreachable Containers",
"autoRestartHint": "Some customers only regain access to their NetBird web UI after a container restart. When enabled, the scheduler periodically checks whether each customer's dashboard actually responds and restarts their containers if it doesn't, logging the action in the customer's log.",
"autoRestartEnabled": "Automatically restart unreachable customer containers",
"autoRestartCooldown": "Cooldown between restarts (minutes)",
"saveAutoRestartSettings": "Save Automation",
"updateLogTitle": "Update Log",
"noUpdateLogs": "No update runs logged yet.",
"logTypeScheduled": "Automatic",