diff --git a/README.md b/README.md index 122309f..821004b 100644 --- a/README.md +++ b/README.md @@ -386,6 +386,37 @@ go build -o fail2ban-ui ./cmd/server/main.go ### Configuration +#### Fail2Ban Callback URL + +The **Fail2Ban Callback URL** is a critical setting that determines how Fail2Ban instances send ban alerts back to Fail2Ban UI. This URL is embedded in a custom Fail2Ban action file that gets deployed to all managed Fail2Ban instances (local, SSH, and API agent connections). + +**How it works:** +- When a Fail2Ban instance bans an IP, it executes the custom action which sends a POST request to the callback URL (`/api/ban` endpoint) +- Fail2Ban UI receives these notifications and stores them in the database for monitoring and analysis +- The callback URL is automatically synchronized with the server port when using the default localhost pattern + +**Configuration Guidelines:** + +1. **Local Deployments:** + - Use the same port as Fail2Ban UI: `http://127.0.0.1:8080` (or your configured port) + - The callback URL automatically updates when you change the server port + - Example: If Fail2Ban UI runs on port `3080`, use `http://127.0.0.1:3080` + +2. **Reverse Proxy Setups:** + - Use your TLS-encrypted endpoint: `https://fail2ban.example.com` + - Ensure the reverse proxy forwards requests to the correct Fail2Ban UI port + - The callback URL must be accessible from all Fail2Ban instances (local and remote) + +3. **Port Changes:** + - When you change the Fail2Ban UI port (via `PORT` environment variable or UI settings), the callback URL automatically updates if it's using the default localhost pattern + - For custom callback URLs (e.g., reverse proxy or custom IP), you must manually update them to match your setup + +**Important Notes:** +- The callback URL must be accessible from all Fail2Ban instances that need to send alerts +- For remote Fail2Ban instances, ensure network connectivity to the callback URL +- If using a reverse proxy, configure it to forward `/api/ban` requests to Fail2Ban UI +- The callback URL is stored in `/etc/fail2ban/action.d/ui-custom-action.conf` on each managed Fail2Ban instance + #### Adding a Local Server The local connector allows managing Fail2Ban on the same host where Fail2Ban UI runs. diff --git a/deployment/container/README.md b/deployment/container/README.md index caeb0af..01bee80 100644 --- a/deployment/container/README.md +++ b/deployment/container/README.md @@ -242,12 +242,18 @@ After starting the container, access the web interface and configure your first - **Remote Server**: Add via SSH or API agent connection 3. **Configure Settings** + - **Fail2Ban Callback URL**: This URL is used by all Fail2Ban instances to send ban alerts back to Fail2Ban UI + - For local deployments: Use the same port as Fail2Ban UI (e.g., `http://127.0.0.1:8080` or your configured port) + - For reverse proxy setups: Use your TLS-encrypted endpoint (e.g., `https://fail2ban.example.com`) + - The callback URL automatically updates when you change the server port (if using the default localhost pattern) - Set up email alerts (optional) - Configure language preferences - Adjust security settings > **Note:** The local Fail2Ban service is optional. Fail2Ban UI can manage remote Fail2Ban servers via SSH or API agents without requiring a local Fail2Ban installation in the container. +> **Important:** The Fail2Ban Callback URL must be accessible from all Fail2Ban instances (local and remote) that need to send alerts. If you change the Fail2Ban UI port, ensure the callback URL is updated accordingly. + --- ## Docker Compose diff --git a/internal/config/settings.go b/internal/config/settings.go index f60d298..50caf9c 100644 --- a/internal/config/settings.go +++ b/internal/config/settings.go @@ -495,8 +495,15 @@ func setDefaultsLocked() { } else if currentSettings.Port == 0 { currentSettings.Port = 8080 } + // Auto-update callback URL if it's empty or still using the old default localhost pattern if currentSettings.CallbackURL == "" { currentSettings.CallbackURL = fmt.Sprintf("http://127.0.0.1:%d", currentSettings.Port) + } else { + // If callback URL matches the old default pattern, update it to match the current port + oldPattern := regexp.MustCompile(`^http://127\.0\.0\.1:\d+$`) + if oldPattern.MatchString(currentSettings.CallbackURL) { + currentSettings.CallbackURL = fmt.Sprintf("http://127.0.0.1:%d", currentSettings.Port) + } } if currentSettings.AlertCountries == nil { currentSettings.AlertCountries = []string{"ALL"} @@ -1190,6 +1197,18 @@ func UpdateSettings(new AppSettings) (AppSettings, error) { } new.CallbackURL = strings.TrimSpace(new.CallbackURL) + + // Auto-update callback URL if port changed and callback URL is still using default localhost pattern + oldPort := currentSettings.Port + if new.Port != oldPort && new.Port > 0 { + // Check if callback URL matches the default localhost pattern + oldPattern := regexp.MustCompile(`^http://127\.0\.0\.1:\d+$`) + if oldPattern.MatchString(new.CallbackURL) || new.CallbackURL == "" { + // Update to match new port + new.CallbackURL = fmt.Sprintf("http://127.0.0.1:%d", new.Port) + } + } + if len(new.Servers) == 0 && len(currentSettings.Servers) > 0 { new.Servers = make([]Fail2banServer, len(currentSettings.Servers)) for i, srv := range currentSettings.Servers { diff --git a/internal/locales/de.json b/internal/locales/de.json index c7160a9..09a3e33 100644 --- a/internal/locales/de.json +++ b/internal/locales/de.json @@ -102,6 +102,7 @@ "settings.alert": "Alarm-Einstellungen", "settings.callback_url": "Fail2ban Callback-URL", "settings.callback_url_placeholder": "http://127.0.0.1:8080", + "settings.callback_url_hint": "Diese URL wird von allen Fail2Ban-Instanzen verwendet, um die Ban-Payloads an Fail2Ban UI zu senden. Für lokale Installationen verwenden Sie denselben Port wie Fail2Ban UI (z.B. http://127.0.0.1:8080). Für Reverse-Proxy-Setups verwenden Sie falls möglich den TLS-verschlüsselten Endpunkt (z.B. https://fail2ban.example.com).", "settings.destination_email": "Ziel-E-Mail (Alarmempfänger)", "settings.destination_email_placeholder": "alerts@swissmakers.ch", "settings.alert_countries": "Alarm-Länder", diff --git a/internal/locales/de_ch.json b/internal/locales/de_ch.json index a89c973..2e40586 100644 --- a/internal/locales/de_ch.json +++ b/internal/locales/de_ch.json @@ -102,6 +102,7 @@ "settings.alert": "Alarm-Istellige", "settings.callback_url": "Fail2ban Callback-URL", "settings.callback_url_placeholder": "http://127.0.0.1:8080", + "settings.callback_url_hint": "Diä URL wird vo aune Fail2Ban-Instanze brucht, zum Ban-Payloads a Fail2Ban UI z sende. Für lokali Installatione bruchts de gliich Port wie z Fail2Ban UI (z.B. http://127.0.0.1:8080). Für Reverse-Proxy-Setups sött dr TLS-verschlüssleti Endpunkt wenn müglech brücht wärde (auso z.B. https://fail2ban.example.com).", "settings.destination_email": "Ziiu-Email (Alarmempfänger)", "settings.destination_email_placeholder": "alerts@swissmakers.ch", "settings.alert_countries": "Alarm-Länder", diff --git a/internal/locales/en.json b/internal/locales/en.json index a514824..cd04e50 100644 --- a/internal/locales/en.json +++ b/internal/locales/en.json @@ -102,6 +102,7 @@ "settings.alert": "Alert Settings", "settings.callback_url": "Fail2ban Callback URL", "settings.callback_url_placeholder": "http://127.0.0.1:8080", + "settings.callback_url_hint": "This URL is used by all Fail2Ban instances to send ban alerts back to Fail2Ban UI. For local deployments, use the same port as Fail2Ban UI (e.g., http://127.0.0.1:8080). For reverse proxy setups, use your TLS-encrypted endpoint (e.g., https://fail2ban.example.com).", "settings.destination_email": "Destination Email (Alerts Receiver)", "settings.destination_email_placeholder": "alerts@swissmakers.ch", "settings.alert_countries": "Alert Countries", diff --git a/internal/locales/es.json b/internal/locales/es.json index 4a5cb95..591933e 100644 --- a/internal/locales/es.json +++ b/internal/locales/es.json @@ -102,6 +102,7 @@ "settings.alert": "Configuración de alertas", "settings.callback_url": "URL de retorno de Fail2ban", "settings.callback_url_placeholder": "http://127.0.0.1:8080", + "settings.callback_url_hint": "Esta URL es utilizada por todas las instancias de Fail2Ban para enviar alertas de bloqueo a Fail2Ban UI. Para implementaciones locales, use el mismo puerto que Fail2Ban UI (ej. http://127.0.0.1:8080). Para configuraciones de proxy inverso, use su endpoint cifrado TLS (ej. https://fail2ban.example.com).", "settings.destination_email": "Correo electrónico de destino (receptor de alertas)", "settings.destination_email_placeholder": "alerts@swissmakers.ch", "settings.alert_countries": "Países para alerta", diff --git a/internal/locales/fr.json b/internal/locales/fr.json index 0d1d1b1..17afb11 100644 --- a/internal/locales/fr.json +++ b/internal/locales/fr.json @@ -102,6 +102,7 @@ "settings.alert": "Paramètres d'alerte", "settings.callback_url": "URL de rappel Fail2ban", "settings.callback_url_placeholder": "http://127.0.0.1:8080", + "settings.callback_url_hint": "Cette URL est utilisée par toutes les instances Fail2Ban pour envoyer les alertes de bannissement à Fail2Ban UI. Pour les déploiements locaux, utilisez le même port que Fail2Ban UI (p. ex. http://127.0.0.1:8080). Pour les configurations de reverse proxy, utilisez votre point de terminaison chiffré TLS (p. ex. https://fail2ban.example.com).", "settings.destination_email": "Email de destination (récepteur des alertes)", "settings.destination_email_placeholder": "alerts@swissmakers.ch", "settings.alert_countries": "Pays d'alerte", diff --git a/internal/locales/it.json b/internal/locales/it.json index c199cf2..2d16e75 100644 --- a/internal/locales/it.json +++ b/internal/locales/it.json @@ -102,6 +102,7 @@ "settings.alert": "Impostazioni di allarme", "settings.callback_url": "URL di callback Fail2ban", "settings.callback_url_placeholder": "http://127.0.0.1:8080", + "settings.callback_url_hint": "Questo URL viene utilizzato da tutte le istanze Fail2Ban per inviare gli avvisi di ban a Fail2Ban UI. Per le distribuzioni locali, utilizzare la stessa porta di Fail2Ban UI (es. http://127.0.0.1:8080). Per le configurazioni di reverse proxy, utilizzare il proprio endpoint crittografato TLS (es. https://fail2ban.example.com).", "settings.destination_email": "Email di destinazione (ricevente allarmi)", "settings.destination_email_placeholder": "alerts@swissmakers.ch", "settings.alert_countries": "Paesi per allarme", diff --git a/pkg/web/static/fail2ban-ui.css b/pkg/web/static/fail2ban-ui.css new file mode 100644 index 0000000..1cda009 --- /dev/null +++ b/pkg/web/static/fail2ban-ui.css @@ -0,0 +1,157 @@ +/* Loading overlay styling */ +#loading-overlay { + display: none; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0,0,0,0.5); + z-index: 9999; + align-items: center; + justify-content: center; + backdrop-filter: blur(4px); + -webkit-backdrop-filter: blur(4px); + opacity: 0; + transition: opacity 0.4s ease; +} + +#loading-overlay.show { + display: flex; + opacity: 1; +} + +/* Restart banner */ +#restartBanner { + display: none; +} + +/* Custom scrollbar */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: #f1f1f1; +} + +::-webkit-scrollbar-thumb { + background: #888; + border-radius: 4px; +} + +::-webkit-scrollbar-thumb:hover { + background: #555; +} + +/* Custom select2 styling to match Tailwind */ +.select2-container--default .select2-selection--multiple { + border: 1px solid #d1d5db; + border-radius: 0.375rem; + padding: 0.25rem 0.5rem; + min-height: 42px; +} + +.select2-container--default .select2-selection--multiple .select2-selection__choice { + background-color: #3b82f6; + border: 1px solid #3b82f6; + color: white; + border-radius: 0.25rem; + padding: 0 0.5rem; +} + +.select2-container--default .select2-selection--multiple .select2-selection__choice__remove { + color: white; + margin-right: 0.25rem; +} + +/* Custom modal styling */ +.modal-content { + box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); +} + +body.modal-open { + overflow: hidden !important; +} + +/* Custom tooltip styling */ +.tooltip { + position: relative; + display: inline-block; +} + +.tooltip .tooltip-text { + visibility: hidden; + width: 200px; + background-color: #333; + color: #fff; + text-align: center; + border-radius: 6px; + padding: 5px; + position: absolute; + z-index: 1; + bottom: 125%; + left: 50%; + margin-left: -100px; + opacity: 0; + transition: opacity 0.3s; +} + +.tooltip:hover .tooltip-text { + visibility: visible; + opacity: 1; +} + +/* Custom mark styling for search highlights */ +mark { + background-color: #fef08a; + padding: 0.1em 0em 0.1em 0.2em; + border-radius: 0.25em; +} + +/* Toast notifications */ +#toast-container { + position: fixed; + top: 1.5rem; + right: 1.5rem; + display: flex; + flex-direction: column; + gap: 0.5rem; + z-index: 10000; + pointer-events: none; +} + +.toast { + min-width: 240px; + max-width: 360px; + padding: 0.75rem 1rem; + border-radius: 0.5rem; + color: #fff; + font-weight: 500; + box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); + opacity: 0; + transform: translateY(-6px); + transition: opacity 0.25s ease, transform 0.25s ease; +} + +.toast.show { + opacity: 1; + transform: translateY(0); +} + +.toast-success { + background-color: #047857; +} + +.toast-error { + background-color: #b91c1c; +} + +.toast-info { + background-color: #1d4ed8; +} + +#advancedMikrotikFields, #advancedPfSenseFields { + padding: 10px; +} \ No newline at end of file diff --git a/pkg/web/templates/index.html b/pkg/web/templates/index.html index bd1a9b3..4c99b91 100644 --- a/pkg/web/templates/index.html +++ b/pkg/web/templates/index.html @@ -33,162 +33,9 @@ - - + + + @@ -344,18 +191,20 @@ - +
+

This URL is used by all Fail2Ban instances to send ban alerts back to Fail2Ban UI. For local deployments, use the same port as Fail2Ban UI (e.g., http://127.0.0.1:8080). For reverse proxy setups, use your TLS-encrypted endpoint (e.g., https://fail2ban.example.com).

-
+
@@ -396,7 +245,7 @@

Choose where permanent bans should be synchronized.

-