Initial commit: SSL proxy / firewall appliance

Flask WebUI behind nginx reverse proxy with zone-based firewall, DHCP,
WireGuard, and ACME certificate management.
This commit is contained in:
2026-05-07 22:24:24 +00:00
commit e2f56b8cc8
56 changed files with 10013 additions and 0 deletions
+106
View File
@@ -0,0 +1,106 @@
{% extends "base.html" %}
{% block title %}Logs - Vacuum Wall{% endblock %}
{% block content %}
<div class="page-header">
<div>
<h1>System Logs</h1>
<div class="subtitle">Service logs and journal output</div>
</div>
<div class="flex items-center gap-2">
<span class="text-sm text-muted">Auto-refresh</span>
<label class="switch">
<input type="checkbox" id="auto-refresh-toggle" onchange="toggleAutoRefresh()">
<span class="slider"></span>
</label>
<span class="htmx-indicator text-sm" style="color:var(--accent);">
<span id="refresh-indicator" style="display:none;">Refreshing...</span>
</span>
</div>
</div>
<div class="tabs">
<button class="tab active" data-tab="journal" onclick="switchTab('journal')">Journal</button>
<button class="tab" data-tab="nginx-access" onclick="switchTab('nginx-access')">Nginx Access</button>
<button class="tab" data-tab="nginx-error" onclick="switchTab('nginx-error')">Nginx Error</button>
<button class="tab" data-tab="dnsmasq" onclick="switchTab('dnsmasq')">Dnsmasq</button>
</div>
<div id="tab-journal" class="tab-content active">
<div class="card" style="padding:0;overflow:hidden;">
<div class="log-viewer" id="log-journal"
hx-get="/api/logs/journal"
hx-trigger="every {{ (refresh_interval | default(15)) }}s"
hx-swap="innerHTML"
hx-indicator="#refresh-indicator">
Loading journal entries...
</div>
</div>
</div>
<div id="tab-nginx-access" class="tab-content">
<div class="card" style="padding:0;overflow:hidden;">
<div class="log-viewer" id="log-nginx-access"
hx-get="/api/logs/nginx/access"
hx-trigger="every {{ (refresh_interval | default(15)) }}s"
hx-swap="innerHTML"
hx-indicator="#refresh-indicator">
Loading Nginx access log...
</div>
</div>
</div>
<div id="tab-nginx-error" class="tab-content">
<div class="card" style="padding:0;overflow:hidden;">
<div class="log-viewer" id="log-nginx-error"
hx-get="/api/logs/nginx/error"
hx-trigger="every {{ (refresh_interval | default(15)) }}s"
hx-swap="innerHTML"
hx-indicator="#refresh-indicator">
Loading Nginx error log...
</div>
</div>
</div>
<div id="tab-dnsmasq" class="tab-content">
<div class="card" style="padding:0;overflow:hidden;">
<div class="log-viewer" id="log-dnsmasq"
hx-get="/api/logs/dnsmasq"
hx-trigger="every {{ (refresh_interval | default(15)) }}s"
hx-swap="innerHTML"
hx-indicator="#refresh-indicator">
Loading dnsmasq log...
</div>
</div>
</div>
<script>
var autoRefreshTimer = null;
function toggleAutoRefresh() {
var toggle = document.getElementById('auto-refresh-toggle');
var indicators = document.querySelectorAll('.log-viewer');
if (toggle.checked) {
indicators.forEach(function(el) {
el.setAttribute('hx-trigger', 'every 15s');
hx.trigger(el, 'htmx:refresh');
});
} else {
indicators.forEach(function(el) {
el.setAttribute('hx-trigger', 'never');
});
}
}
document.addEventListener('htmx:beforeRequest', function(evt) {
if (evt.detail && evt.detail.path && evt.detail.path.startsWith('/api/logs')) {
document.getElementById('refresh-indicator').style.display = 'inline';
}
});
document.addEventListener('htmx:afterRequest', function(evt) {
document.getElementById('refresh-indicator').style.display = 'none';
});
</script>
{% endblock %}