Proxy: setup progress stream, self-healing, uninstall, health check cron

- ProxyManager::runSetupOnRemote() — generator yields step-by-step
  progress; drives SSE stream from /api/proxy/setup-remote POST
- ProxyManager::uninstall(bool) — removes configs from remote or local;
  optionally apt-get removes nginx and sets mode=disabled
- ProxyManager::healthCheck() — called every 5 min from collect-stats.php;
  restarts nginx on remote if found stopped
- proxy.php: POST /api/proxy/setup-remote (SSE stream), DELETE /api/proxy/uninstall
- admin.js: proxyRunSetup() streams output to a live log modal;
  proxyUninstall() with configs-only vs full removal choice;
  'Run Setup on Remote VM' / 'Uninstall' buttons in page header

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-09 10:23:02 +00:00
parent 6b95571548
commit ed552cd5a6
4 changed files with 148 additions and 0 deletions
+27
View File
@@ -141,6 +141,33 @@ try {
$action === 'test-remote' && $method === 'POST' =>
Response::json(['success' => true, 'data' => ProxyManager::testRemote()]),
// POST setup-remote — run nginx setup on remote VM, stream output via SSE
($action === 'setup-remote') && $method === 'POST' => (function() {
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('X-Accel-Buffering: no');
ob_implicit_flush(true);
while (ob_get_level() > 0) ob_end_flush();
foreach (ProxyManager::runSetupOnRemote() as $line) {
echo 'data: ' . json_encode(['line' => $line]) . "\n\n";
flush();
}
echo "data: " . json_encode(['done' => true]) . "\n\n";
flush();
exit;
})(),
// DELETE uninstall — remove proxy configs (and optionally nginx)
$action === 'uninstall' && $method === 'DELETE' => (function() use ($body) {
$removeNginx = !empty($body['remove_nginx']);
$result = ProxyManager::uninstall($removeNginx);
if ($removeNginx) {
$db = DB::getInstance();
$db->execute("INSERT INTO settings (`key`, value) VALUES ('proxy_mode','disabled') ON DUPLICATE KEY UPDATE value='disabled'");
}
Response::json(['success' => true, 'data' => ['result' => $result]]);
})(),
default => Response::error('Not found', 404),
};