Initial commit — GuacPanel v1.0
All-in-one installer za Apache Guacamole s Nginx reverse proxy, fail2ban, SSL (Let's Encrypt / Self-signed), GeoIP blokiranjem i Flask web GUI za upravljanje. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block title %}fail2ban – Guacamole Manager{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h4 class="mb-4"><i class="bi bi-shield-x me-2"></i>fail2ban</h4>
|
||||
|
||||
<div class="row g-4">
|
||||
|
||||
<!-- Zabanjeni IP-ovi -->
|
||||
<div class="col-md-8">
|
||||
{% for jail, ips in banned.items() %}
|
||||
<div class="card mb-3">
|
||||
<div class="card-header d-flex justify-content-between">
|
||||
<span class="fw-semibold">{{ jail }}</span>
|
||||
<span class="badge {{ 'bg-danger' if ips else 'bg-secondary' }}">
|
||||
{{ ips|length }} zabanjeno
|
||||
</span>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
{% if ips %}
|
||||
<table class="table table-sm mb-0" style="border-color:#30363d">
|
||||
<thead class="table-dark">
|
||||
<tr>
|
||||
<th>IP adresa</th>
|
||||
<th class="text-end">Akcija</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for ip in ips %}
|
||||
<tr>
|
||||
<td class="font-monospace">{{ ip }}</td>
|
||||
<td class="text-end">
|
||||
<button class="btn btn-outline-success btn-sm"
|
||||
onclick="unban('{{ ip }}', '{{ jail }}')">
|
||||
<i class="bi bi-check-circle"></i> Odbani
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<p class="text-muted small p-3 mb-0">Nema zabanjenih IP-ova</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<!-- Akcije i postavke -->
|
||||
<div class="col-md-4">
|
||||
<!-- Ručni ban -->
|
||||
<div class="card mb-3">
|
||||
<div class="card-header fw-semibold">
|
||||
<i class="bi bi-shield-plus me-1"></i> Ručni ban
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-2">
|
||||
<input id="ban-ip" type="text" class="form-control form-control-sm"
|
||||
placeholder="192.168.1.100">
|
||||
</div>
|
||||
<select id="ban-jail" class="form-select form-select-sm mb-2">
|
||||
{% for j in banned.keys() %}
|
||||
<option>{{ j }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<button class="btn btn-danger btn-sm w-100" onclick="banIP()">
|
||||
<i class="bi bi-ban"></i> Baniraj IP
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Postavke -->
|
||||
<div class="card">
|
||||
<div class="card-header fw-semibold">
|
||||
<i class="bi bi-sliders me-1"></i> Postavke
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-2">
|
||||
<label class="form-label small text-muted">Max pokušaja (maxretry)</label>
|
||||
<input id="maxretry" type="number" class="form-control form-control-sm"
|
||||
value="{{ cfg.get('maxretry', 5) }}" min="1" max="20">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label small text-muted">Trajanje bana (sekunde)</label>
|
||||
<input id="bantime" type="number" class="form-control form-control-sm"
|
||||
value="{{ cfg.get('bantime', 3600) }}" min="60">
|
||||
<small class="text-muted">3600=1h · 86400=1dan · 604800=1tjedan</small>
|
||||
</div>
|
||||
<button class="btn btn-primary btn-sm w-100" onclick="saveSettings()">
|
||||
<i class="bi bi-floppy"></i> Spremi
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
async function unban(ip, jail) {
|
||||
const r = await api('/api/fail2ban/unban', {ip, jail});
|
||||
showToast(r.msg, r.ok);
|
||||
if (r.ok) setTimeout(() => location.reload(), 1000);
|
||||
}
|
||||
|
||||
async function banIP() {
|
||||
const ip = document.getElementById('ban-ip').value.trim();
|
||||
const jail = document.getElementById('ban-jail').value;
|
||||
if (!ip) return showToast('Unesite IP adresu', false);
|
||||
const r = await api('/api/fail2ban/ban', {ip, jail});
|
||||
showToast(r.msg, r.ok);
|
||||
if (r.ok) setTimeout(() => location.reload(), 1000);
|
||||
}
|
||||
|
||||
async function saveSettings() {
|
||||
const r = await api('/api/fail2ban/settings', {
|
||||
maxretry: document.getElementById('maxretry').value,
|
||||
bantime: document.getElementById('bantime').value
|
||||
});
|
||||
showToast(r.msg, r.ok);
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user