d1ab717c0f
- Fix WireGuard private key leak in API responses and config updates - Update systemd service to serve from repo root with adjusted sandbox - Add CLI flags, idempotency, and dev mode to install.sh - Extract common utilities to lib/common.py and webui/api/common.py - Migrate frontend to htmx for simpler, more maintainable UI - Update docs to reflect current architecture and deployment model - Vendor htmx dependencies per project requirements
152 lines
7.7 KiB
HTML
152 lines
7.7 KiB
HTML
{% extends "base.html" %}
|
|
{% block title %}Proxy - Vacuum Wall{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="page-header">
|
|
<div>
|
|
<h1>SSL Proxy Domains</h1>
|
|
<div class="subtitle">Reverse proxy and SSL termination managed by Nginx</div>
|
|
</div>
|
|
<div class="flex gap-2">
|
|
<button class="btn btn-primary" onclick="openModal('add-domain-modal')">+ Add Domain</button>
|
|
<button class="btn btn-outline" hx-post="/api/proxy/ssl-apply" hx-swap="none" hx-on::after-request="if(evt.detail.successful) showSuccessToast('SSL settings applied')">Apply SSL Settings</button>
|
|
<button class="btn btn-outline" hx-post="/api/proxy/apply" hx-swap="none" hx-on::after-request="if(evt.detail.successful) showSuccessToast('Nginx reloaded')">Apply Changes (Reload Nginx)</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Domain</th>
|
|
<th>Backend Host</th>
|
|
<th>Backend Port</th>
|
|
<th>Protocol</th>
|
|
<th>Certificate</th>
|
|
<th style="width:140px;">Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="domain-rows">
|
|
{% for domain in (domains or []) %}
|
|
<tr>
|
|
<td><strong>{{ domain.get('domain', 'unknown') }}</strong></td>
|
|
<td>{{ domain.get('backend_host', '-') }}</td>
|
|
<td>{{ domain.get('backend_port', '-') }}</td>
|
|
<td><span class="badge badge-info">{{ domain.get('protocol', 'http') }}</span></td>
|
|
<td>
|
|
{% set matched_cert = None %}
|
|
{% if certs %}
|
|
{% for cert in certs %}
|
|
{% if cert.get('domain') == domain.get('domain') %}
|
|
{% set matched_cert = cert %}
|
|
{% endif %}
|
|
{% endfor %}
|
|
{% endif %}
|
|
{% if matched_cert %}
|
|
{% if matched_cert.get('expired') %}
|
|
<span class="badge badge-danger">Expired</span>
|
|
{% elif matched_cert.get('days_remaining') is not none and matched_cert.days_remaining <= 30 %}
|
|
<span class="badge badge-warning">{{ matched_cert.days_remaining }}d</span>
|
|
{% else %}
|
|
<span class="badge badge-success">Valid</span>
|
|
{% endif %}
|
|
{% else %}
|
|
<span class="badge badge-danger">No cert</span>
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
<div class="flex gap-2">
|
|
<button class="btn btn-sm btn-outline" onclick='openEditDomainModal('{{ domain.get("domain", "") }}', {{ domain | tojson | safe }})'>Edit</button>
|
|
<form hx-delete="/api/proxy/domains/{{ domain.get('domain', '') }}" hx-swap="none" hx-confirm="Remove proxy for {{ domain.domain }}?" hx-on::after-request="if(evt.detail.successful){ refreshTable('/api/proxy/domains', document.getElementById('domain-rows'), renderDomains); showSuccessToast('Domain removed'); }">
|
|
<button type="submit" class="btn btn-sm btn-danger">Delete</button>
|
|
</form>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
{% if not (domains or []) %}
|
|
<tr>
|
|
<td colspan="6" class="text-muted text-sm">No proxy domains configured. Add a domain to start terminating SSL.</td>
|
|
</tr>
|
|
{% endif %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Add Domain Modal -->
|
|
<div class="modal-overlay" id="add-domain-modal" onclick="if(event.target===this) closeModal('add-domain-modal')">
|
|
<div class="modal">
|
|
<h2>Add Proxy Domain</h2>
|
|
<form hx-post="/api/proxy/domains" hx-encoding="json" hx-swap="none" hx-on::after-request="if(evt.detail.successful){ closeModal('add-domain-modal'); refreshTable('/api/proxy/domains', document.getElementById('domain-rows'), renderDomains); showSuccessToast('Domain added'); }">
|
|
<div class="form-group">
|
|
<label for="new-domain">Domain</label>
|
|
<input type="text" id="new-domain" name="domain" placeholder="example.com" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="new-backend-host">Backend Host</label>
|
|
<input type="text" id="new-backend-host" name="backend_host" placeholder="127.0.0.1" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="new-backend-port">Backend Port</label>
|
|
<input type="number" id="new-backend-port" name="backend_port" placeholder="8080" min="1" max="65535" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="new-protocol">Backend Protocol</label>
|
|
<select id="new-protocol" name="protocol">
|
|
<option value="http">HTTP</option>
|
|
<option value="https">HTTPS</option>
|
|
</select>
|
|
</div>
|
|
<div class="modal-actions">
|
|
<button type="button" class="btn btn-outline" onclick="closeModal('add-domain-modal')">Cancel</button>
|
|
<button type="submit" class="btn btn-primary">Add Domain</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Edit Domain Modal -->
|
|
<div class="modal-overlay" id="edit-domain-modal" onclick="if(event.target===this) closeModal('edit-domain-modal')">
|
|
<div class="modal">
|
|
<h2>Edit Proxy Domain</h2>
|
|
<form id="edit-domain-form" hx-post="/api/proxy/domains" hx-swap="none" hx-encoding="json" hx-on::after-request="if(evt.detail.successful){ closeModal('edit-domain-modal'); refreshTable('/api/proxy/domains', document.getElementById('domain-rows'), renderDomains); showSuccessToast('Domain updated'); }">
|
|
<input type="hidden" id="edit-original-domain" name="original_domain">
|
|
<div class="form-group">
|
|
<label for="edit-domain">Domain</label>
|
|
<input type="text" id="edit-domain" name="domain" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="edit-backend-host">Backend Host</label>
|
|
<input type="text" id="edit-backend-host" name="backend_host" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="edit-backend-port">Backend Port</label>
|
|
<input type="number" id="edit-backend-port" name="backend_port" min="1" max="65535" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="edit-protocol">Backend Protocol</label>
|
|
<select id="edit-protocol" name="protocol">
|
|
<option value="http">HTTP</option>
|
|
<option value="https">HTTPS</option>
|
|
</select>
|
|
</div>
|
|
<div class="modal-actions">
|
|
<button type="button" class="btn btn-outline" onclick="closeModal('edit-domain-modal')">Cancel</button>
|
|
<button type="submit" class="btn btn-primary">Save Changes</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function openEditDomainModal(domainName, d) {
|
|
document.getElementById('edit-original-domain').value = d.domain;
|
|
document.getElementById('edit-domain').value = d.domain;
|
|
document.getElementById('edit-backend-host').value = d.backend_host || '';
|
|
document.getElementById('edit-backend-port').value = d.backend_port || '';
|
|
document.getElementById('edit-protocol').value = d.protocol || 'http';
|
|
openModal('edit-domain-modal');
|
|
}
|
|
</script>
|
|
{% endblock %}
|