mirror of
https://github.com/swissmakers/fail2ban-ui.git
synced 2026-04-01 06:07:02 +02:00
Update docs and write troubleshooting steps to debug no reciving ban/unban events
This commit is contained in:
108
docs/api.md
108
docs/api.md
@@ -4,8 +4,12 @@ This is a short index for operators. The UI primarily uses these endpoints. Path
|
||||
|
||||
## Authentication
|
||||
|
||||
- When OIDC is enabled, most `/api/*` endpoints require an authenticated session.
|
||||
- Callback endpoints are authenticated using `X-Callback-Secret`.
|
||||
- When OIDC is enabled, all `/api/*` endpoints (including WebSocket) require an authenticated session, except the callback endpoints.
|
||||
- Callback endpoints (`/api/ban`, `/api/unban`) are authenticated using `X-Callback-Secret`.
|
||||
|
||||
## Input validation
|
||||
|
||||
All endpoints that accept IP addresses validate them server-side using Go's `net.ParseIP` / `net.ParseCIDR`. Requests with invalid IPs receive a `400 Bad Request` response. This applies to ban/unban callbacks, manual ban/unban from the dashboard, and the advanced actions test endpoint.
|
||||
|
||||
## Common headers
|
||||
|
||||
@@ -14,49 +18,79 @@ This is a short index for operators. The UI primarily uses these endpoints. Path
|
||||
|
||||
## Endpoints
|
||||
|
||||
Server management
|
||||
- `GET /api/servers`
|
||||
- `POST /api/servers`
|
||||
- `DELETE /api/servers/:id`
|
||||
- `POST /api/servers/:id/test`
|
||||
### Server management
|
||||
- `GET /api/servers` -> List configured servers
|
||||
- `POST /api/servers` -> Create or update a server
|
||||
- `DELETE /api/servers/:id` -> Delete a server
|
||||
- `POST /api/servers/:id/default` -> Set server as default
|
||||
- `POST /api/servers/:id/test` -> Test server connectivity
|
||||
- `GET /api/ssh/keys` -> List available SSH keys
|
||||
|
||||
Jails and configuration
|
||||
- `GET /api/summary`
|
||||
- `GET /api/jails/manage`
|
||||
- `POST /api/jails/manage`
|
||||
- `GET /api/jails/:jail/config`
|
||||
- `POST /api/jails/:jail/config`
|
||||
- `POST /api/jails/:jail/unban/:ip`
|
||||
- `POST /api/jails/:jail/ban/:ip`
|
||||
### Jails and configuration
|
||||
- `GET /api/summary` -> Dashboard summary (jails, banned IPs per server)
|
||||
- `GET /api/jails/manage` -> List jails with enabled/disabled status
|
||||
- `POST /api/jails/manage` -> Update jail enabled/disabled state
|
||||
- `POST /api/jails` -> Create a new jail
|
||||
- `DELETE /api/jails/:jail` -> Delete a jail
|
||||
- `GET /api/jails/:jail/config` -> Get jail/filter configuration
|
||||
- `POST /api/jails/:jail/config` -> Update jail/filter configuration
|
||||
- `POST /api/jails/:jail/logpath/test` -> Test log path accessibility
|
||||
- `POST /api/jails/:jail/unban/:ip` -> Unban an IP from a jail
|
||||
- `POST /api/jails/:jail/ban/:ip` -> Ban an IP in a jail
|
||||
|
||||
Events and analytics
|
||||
- `GET /api/events/bans`
|
||||
- `GET /api/events/bans/stats`
|
||||
- `GET /api/events/bans/insights`
|
||||
### Events and analytics
|
||||
- `GET /api/events/bans` -> List ban/unban events (paginated, filterable)
|
||||
- `DELETE /api/events/bans` -> Delete all stored ban events
|
||||
- `GET /api/events/bans/stats` -> Ban statistics (counts, timeseries)
|
||||
- `GET /api/events/bans/insights` -> Ban insights (countries, top IPs, top jails)
|
||||
|
||||
Settings
|
||||
- `GET /api/settings`
|
||||
- `POST /api/settings`
|
||||
- `POST /api/settings/test-email`
|
||||
### Advanced actions
|
||||
- `GET /api/advanced-actions/blocks` -> List permanent block records
|
||||
- `DELETE /api/advanced-actions/blocks` -> Delete all permanent block records
|
||||
- `POST /api/advanced-actions/test` -> Manually test block/unblock on configured integration
|
||||
|
||||
Filter debugging
|
||||
- `GET /api/filters`
|
||||
- `POST /api/filters/test`
|
||||
### Settings
|
||||
- `GET /api/settings` -> Get current application settings
|
||||
- `POST /api/settings` -> Update application settings
|
||||
- `POST /api/settings/test-email` -> Send a test email
|
||||
|
||||
Service control
|
||||
- `POST /api/fail2ban/restart`
|
||||
### Filter management
|
||||
- `GET /api/filters` -> List available filters
|
||||
- `GET /api/filters/:filter/content` -> Get filter file content
|
||||
- `POST /api/filters` -> Create a new filter
|
||||
- `POST /api/filters/test` -> Test filter regex against log lines
|
||||
- `DELETE /api/filters/:filter` -> Delete a filter
|
||||
|
||||
Callbacks (Fail2Ban actions)
|
||||
- `POST /api/ban`
|
||||
- `POST /api/unban`
|
||||
### Service control
|
||||
- `POST /api/fail2ban/restart` -> Restart / Reloads the Fail2Ban service
|
||||
|
||||
### Version
|
||||
- `GET /api/version` -> Get running version and optional update check
|
||||
|
||||
### WebSocket
|
||||
- `GET /api/ws` -> WebSocket endpoint (upgrade)
|
||||
|
||||
The WebSocket connection streams, real-time events to the frontend:
|
||||
- `heartbeat` -> periodic health check (~30s)
|
||||
- `console_log` -> debug console log lines (when debug mode is enabled)
|
||||
- `ban_event` -> real-time ban event broadcast
|
||||
- `unban_event` -> real-time unban event broadcast
|
||||
|
||||
The WebSocket enforces same-origin policy via the `Origin` header and requires authentication when OIDC is enabled.
|
||||
|
||||
### Callbacks (Fail2Ban actions)
|
||||
- `POST /api/ban` -> Receive ban notification from Fail2Ban
|
||||
- `POST /api/unban` -> Receive unban notification from Fail2Ban
|
||||
|
||||
Callbacks require:
|
||||
- Header: `X-Callback-Secret: <secret>`
|
||||
- JSON body fields (typical): `serverId`, `ip`, `jail`, `hostname`, `failures`, `logs`
|
||||
|
||||
Authentication routes (OIDC)
|
||||
- `GET /auth/login`
|
||||
- `GET /auth/callback`
|
||||
- `GET /auth/logout`
|
||||
- `GET /auth/status`
|
||||
- `GET /auth/user`
|
||||
All IPs in callback payloads are validated before processing.
|
||||
|
||||
### Authentication routes (OIDC)
|
||||
- `GET /auth/login` -> Initiate OIDC login flow
|
||||
- `GET /auth/callback` -> OIDC provider callback
|
||||
- `GET /auth/logout` -> Logout and clear session
|
||||
- `GET /auth/status` -> Check authentication status
|
||||
- `GET /auth/user` -> Get current user info
|
||||
@@ -23,9 +23,11 @@ Fail2Ban UI consists of :
|
||||
|
||||
## Components (high level)
|
||||
|
||||
- REST API: server management, jail/filter config read/write, ban/unban actions, settings
|
||||
- WebSocket hub: streams ban/unban events and (optional) debug console logs
|
||||
- REST API: server management, jail/filter config read/write, ban/unban actions, settings, data management (clear events/blocks)
|
||||
- WebSocket hub: streams real-time ban/unban events and (optional) debug console logs, protected by origin validation and session auth
|
||||
- Storage: server definitions, settings, ban history, permanent block records
|
||||
- Integrations: MikroTik (SSH), pfSense (REST API), OPNsense (REST API) with input validation on all parameters
|
||||
- Ban Insights: country-level analytics with interactive 3D threat globe visualization
|
||||
|
||||
Additional resources:
|
||||
- Container deployment guide: `deployment/container/README.md`
|
||||
@@ -62,11 +64,11 @@ Additional resources:
|
||||
│ │ • /auth/login | /auth/callback | /auth/logout │ │ │ e
|
||||
│ │ • /auth/status | /auth/user │ │ │ t
|
||||
│ │ • POST /api/ban | POST /api/unban ← Fail2ban callbacks (a valid Callback │ │ │
|
||||
│ │ • GET /api/ws (WebSocket) Secret is needed) │ │ │
|
||||
│ │ • /static/* | /locales/* │ │----┘
|
||||
│ │ • /static/* | /locales/* Secret is needed) │ │----┘
|
||||
│ └───────────────────────────────────────────────────────────────────────────┘ │
|
||||
│ ┌───────────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ PROTECTED (when OIDC enabled): GET / | GET and POST to all other /api/* │ │
|
||||
│ │ PROTECTED (when OIDC enabled): │ │
|
||||
│ │ GET / | all other /api/* | GET /api/ws (WebSocket, same-origin only) │ │
|
||||
│ └───────────────────────────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
@@ -84,16 +86,19 @@ Additional resources:
|
||||
│ │ • POST /jails/:jail/unban/:ip • POST /jails/:jail/ban/:ip │ │
|
||||
│ │ • GET /settings • POST /settings │ │
|
||||
│ │ • GET /events/bans • GET /events/bans/stats | /insights │ │
|
||||
│ │ • DELETE /events/bans • DELETE /advanced-actions/blocks │ │
|
||||
│ │ • GET /version (optional GitHub request if UPDATE_CHECK) │ │
|
||||
│ │ • GET /servers | POST/DELETE /servers | POST /servers/:id/test │ │
|
||||
│ │ • GET /filters/* • POST /filters/test | POST/DELETE /filters │ │
|
||||
│ │ • POST /fail2ban/restart • GET/POST /advanced-actions/* │ │
|
||||
│ │ • POST /ban (callback) • POST /unban (callback) │ │
|
||||
│ │ All IP inputs validated via net.ParseIP / net.ParseCIDR │ │
|
||||
│ └────────────────────────────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌─────────────────────────────────┴──────────────────────────────────────────┐ │
|
||||
│ │ WebSocket Hub (GET /api/ws) │ │
|
||||
│ │ WebSocket Hub (GET /api/ws — same-origin, auth required with OIDC) │ │
|
||||
│ │ • register / unregister clients │ │
|
||||
│ │ • Origin header validated against Host (rejects cross-site connections) │ │
|
||||
│ │ • broadcast to all clients: │ │
|
||||
│ │ - type: "heartbeat" (every ~30s) │ │
|
||||
│ │ - type: "console_log" (debug console lines) │ │
|
||||
@@ -110,8 +115,10 @@ Additional resources:
|
||||
│ │ Connector Manager │ │ Integrations + Email │ │
|
||||
│ │ • Local (fail2ban.sock) │ │ • Mikrotik / pfSense / │ │
|
||||
│ │ • SSH (exec on remote) │ │ OPNsense (block/unblock)│ │
|
||||
│ │ • Agent (HTTP to agent) │ │ • SMTP alert emails │ │
|
||||
│ │ • New server init: ensure │ └────────────────────────────┘ │
|
||||
│ │ • Agent (HTTP to agent) │ │ • Input validated (IP + │ │
|
||||
│ │ • New server init: ensure │ │ identifiers sanitized) │ │
|
||||
│ │ │ │ • SMTP alert emails │ │
|
||||
│ │ │ └────────────────────────────┘ │
|
||||
│ │ action.d (ui-custom- │ │
|
||||
│ │ action.conf) │ │
|
||||
│ └────────────────────────────┘ │
|
||||
|
||||
@@ -12,6 +12,24 @@ This project can perform security-sensitive operations (bans, configuration chan
|
||||
|
||||
If you must publish it, put it behind TLS and an authentication layer, and restrict source IPs.
|
||||
|
||||
## Input validation
|
||||
|
||||
All user-supplied IP addresses are validated using Go's `net.ParseIP` and `net.ParseCIDR` before they are passed to any integration, command, or database query. This applies to:
|
||||
|
||||
- Ban/Unban callbacks (`/api/ban`, `/api/unban`)
|
||||
- Manual ban/unban actions from the dashboard
|
||||
- Advanced action test endpoint (`/api/advanced-actions/test`)
|
||||
- All integration connectors (MikroTik, pfSense, OPNsense)
|
||||
|
||||
Integration-specific identifiers (address list names, alias names) are validated against a strict alphanumeric pattern (`[a-zA-Z0-9._-]`) to prevent injection in both SSH commands and API payloads.
|
||||
|
||||
## WebSocket security
|
||||
|
||||
The WebSocket endpoint (`/api/ws`) is protected by:
|
||||
|
||||
- **Origin validation**: The upgrade handshake verifies that the `Origin` header matches the request's `Host` header (same-origin policy). Cross-origin WebSocket connections are rejected. This prevents cross-site WebSocket hijacking attacks.
|
||||
- **Authentication**: When OIDC is enabled, the WebSocket endpoint requires a valid session.
|
||||
|
||||
## Callback endpoint protection
|
||||
|
||||
The fail2ban callback endpoints (`/api/ban`, `/api/unban`) are only reachable with a correct `CALLBACK_SECRET`. This secret must be atleast 20 characters long. If not specified a secure secret, will be automatically genereated on first start. It can be further protected by:
|
||||
@@ -30,6 +48,14 @@ For SSH-managed hosts:
|
||||
- Restrict sudo to the minimum set of commands required to operate Fail2Ban (typically `fail2ban-client` and optionally `systemctl restart fail2ban`).
|
||||
- Use filesystem ACLs for `/etc/fail2ban` rather than broad permissions to allow full modification capabilities for the specific user.
|
||||
|
||||
## Integration connector hardening
|
||||
|
||||
When using external firewall integrations (MikroTik, pfSense, OPNsense):
|
||||
|
||||
- Use a dedicated service account on the firewall device with the minimum permissions needed (address-list management only on MikroTik; alias management only on pfSense/OPNsense).
|
||||
- For pfSense/OPNsense: use a dedicated API token with limited scope.
|
||||
- Restrict network access so the Fail2ban-UI host is the only source allowed to reach the firewall management interface.
|
||||
|
||||
## Least privilege and file access
|
||||
|
||||
Local connector deployments typically require access to:
|
||||
|
||||
@@ -65,6 +65,195 @@ getfacl /etc/fail2ban
|
||||
sudo podman exec -it fail2ban-ui ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o BatchMode=yes -i /config/.ssh/id_rsa -p 2222 testuser@127.0.0.1
|
||||
```
|
||||
|
||||
## Ban/unban notifications not showing up in the UI
|
||||
|
||||
This is one of the most common issues. The UI receives ban/unban events from Fail2Ban via HTTP callbacks. If nothing appears in the dashboard or "Recent stored events", the callback chain is broken somewhere. Follow these steps systematically.
|
||||
|
||||
### Step 1: Verify the action file exists and is correct
|
||||
|
||||
Fail2ban-UI creates a custom action file at `/etc/fail2ban/action.d/ui-custom-action.conf` on each managed host. This file contains `curl` commands that notify the UI when bans/unbans happen.
|
||||
|
||||
```bash
|
||||
# Check if the action file exists:
|
||||
cat /etc/fail2ban/action.d/ui-custom-action.conf
|
||||
|
||||
# You should see actionban and actionunban sections with curl commands pointing
|
||||
# to your Fail2ban-UI callback URL (e.g. http://10.88.0.1:8080/api/ban)
|
||||
```
|
||||
|
||||
If the file does not exist or looks wrong, go to Settings → Manage Servers in the UI, select the server, and click "Test connection". The UI will re-deploy the action file automatically for local connectors.
|
||||
|
||||
### Step 2: Verify jail.local references the action
|
||||
|
||||
Fail2ban-UI writes a `jail.local` that uses the custom action. Check that it is in place:
|
||||
|
||||
```bash
|
||||
cat /etc/fail2ban/jail.local | head -30
|
||||
|
||||
# Look for the lines like:
|
||||
# action = %(action_mwlg)s
|
||||
# and a definition of action_mwlg that references ui-custom-action
|
||||
```
|
||||
|
||||
If your `jail.local` was created manually or by another tool, the `ui-custom-action` might not be referenced. The easiest fix: let the UI manage `jail.local` by removing your manual version and restarting from the UI.
|
||||
|
||||
### Step 3: Check network connectivity from Fail2Ban host to the UI
|
||||
|
||||
The `curl` command in the action file must be able to reach the UI's callback URL. Test this from the Fail2Ban host (or from inside the container if Fail2Ban runs in one):
|
||||
|
||||
```bash
|
||||
# Replace with your actual Fail2ban-UI address:
|
||||
curl -s -o /dev/null -w "%{http_code}" http://10.88.0.1:8080/api/version
|
||||
|
||||
# Expected: 200
|
||||
# If you get connection refused, timeout, or another error,
|
||||
# fix network/firewall rules first.
|
||||
```
|
||||
|
||||
Common issues:
|
||||
- Container using bridge networking but callback URL points to `127.0.0.1` (use the host IP or `--network=host`)
|
||||
- Firewall on the UI host blocks the port
|
||||
|
||||
### Step 4: Verify the callback secret
|
||||
|
||||
Every callback must include the header `X-Callback-Secret`. The value must match what the UI expects. You can find the current secret in Settings → General Settings → Callback Secret (or check the container environment).
|
||||
|
||||
```bash
|
||||
# Check what secret the action file uses:
|
||||
grep "X-Callback-Secret" /etc/fail2ban/action.d/ui-custom-action.conf
|
||||
|
||||
# Compare with the UI's expected secret (from the settings page or env var)
|
||||
```
|
||||
|
||||
If they do not match, re-deploy the action file via "Test connection" from the UI, or manually update the secret in the action file and restart Fail2Ban.
|
||||
|
||||
### Step 5: Simulate a ban notification with curl
|
||||
|
||||
This is the most direct way to test the full callback chain. Run this from any host that can reach the UI:
|
||||
|
||||
```bash
|
||||
FAIL2BAN_UI_HOST="your_fail2ban_host"
|
||||
SECRET="your_secret"
|
||||
|
||||
curl -v -X POST http://$FAIL2BAN_UI_HOST:8080/api/ban \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-Callback-Secret: $SECRET" \
|
||||
-d '{
|
||||
"serverId": "local",
|
||||
"ip": "203.0.113.42",
|
||||
"jail": "sshd",
|
||||
"hostname": "testhost",
|
||||
"failures": "5",
|
||||
"logs": "Jun 15 12:00:00 testhost sshd: Failed password for root from 203.0.113.42"
|
||||
}'
|
||||
```
|
||||
|
||||
Expected response:
|
||||
```json
|
||||
{"message":"Ban notification processed successfully"}
|
||||
```
|
||||
|
||||
If it works, you should immediately see:
|
||||
- A new entry in "Recent stored events" on the dashboard
|
||||
- A real-time WebSocket update (the entry appears without refreshing)
|
||||
|
||||
Common error responses:
|
||||
- `401 Unauthorized` with `"Callback secret not configured"` → Secret not set in UI settings
|
||||
- `401 Unauthorized` with `"Invalid callback secret"` → Secret mismatch
|
||||
- `400 Bad Request` with `"invalid IP"` → The IP address in the payload is malformed
|
||||
- `400 Bad Request` with `"Invalid request"` → JSON parsing failed (check `ip` and `jail` fields are present)
|
||||
|
||||
To simulate an unban:
|
||||
|
||||
```bash
|
||||
curl -v -X POST http://$FAIL2BAN_UI_HOST:8080/api/unban \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-Callback-Secret: $SECRET" \
|
||||
-d '{
|
||||
"serverId": "local",
|
||||
"ip": "203.0.113.42",
|
||||
"jail": "sshd",
|
||||
"hostname": "testhost"
|
||||
}'
|
||||
```
|
||||
|
||||
### Step 6: Check what Fail2Ban is actually sending
|
||||
|
||||
If the curl test above works but real bans still don't show up, Fail2Ban itself might not be executing the action correctly. Check:
|
||||
|
||||
```bash
|
||||
# Trigger a real ban (use a test jail or ban a test IP):
|
||||
fail2ban-client set sshd banip 198.51.100.1
|
||||
|
||||
# Watch the Fail2Ban log for errors:
|
||||
tail -f /var/log/fail2ban.log
|
||||
|
||||
# Look for lines like:
|
||||
# ERROR ... Action ... failed
|
||||
# WARNING ... Command ... failed
|
||||
```
|
||||
|
||||
You can also manually run the exact `curl` command from the action file to see what happens. Extract it from the action file and run it in your shell (replace the Fail2Ban variables like `<ip>`, `<name>`, etc. with real values):
|
||||
|
||||
```bash
|
||||
# Extract and run the actionban command manually:
|
||||
grep -A5 "actionban" /etc/fail2ban/action.d/ui-custom-action.conf
|
||||
|
||||
# Then execute the curl command with real values substituted.
|
||||
# This reveals whether jq is missing, curl has TLS issues, etc.
|
||||
```
|
||||
|
||||
Common issues at this stage:
|
||||
- **`jq` not installed**: The action file uses `jq` to build JSON. Install it: `dnf install jq` or `apt install jq`
|
||||
- **TLS certificate issues**: If the callback URL uses HTTPS with a self-signed cert, the action file needs the `-k` flag (Fail2ban-UI adds this automatically when the callback URL starts with `https://`)
|
||||
- **Fail2Ban not restarted**: After the action file is deployed, Fail2Ban must be restarted to pick up changes: `systemctl restart fail2ban`
|
||||
|
||||
### Step 7: Check the Fail2ban-UI logs
|
||||
|
||||
The UI logs every incoming callback with details. Check the container or service logs:
|
||||
|
||||
```bash
|
||||
# Container:
|
||||
podman logs -f fail2ban-ui
|
||||
|
||||
# systemd:
|
||||
journalctl -u fail2ban-ui -f
|
||||
|
||||
# Look for lines like:
|
||||
# ✅ Parsed ban request - IP: ..., Jail: ...
|
||||
# ⚠️ Invalid callback secret ...
|
||||
# ❌ JSON parsing error ...
|
||||
```
|
||||
|
||||
If you enabled debug mode in the UI settings, you will also see the raw JSON body of every incoming callback.
|
||||
|
||||
### Step 8: Verify the `serverId` resolves
|
||||
|
||||
The callback payload includes a `serverId`. The UI uses this to match the event to a configured server. If neither matches any known server, the UI will reject the callback.
|
||||
|
||||
Check that the `serverId` in the action file matches the server ID shown in Settings → Manage Servers. You can see the configured server IDs via:
|
||||
|
||||
```bash
|
||||
curl -s http://$FAIL2BAN_UI_HOST:8080/api/servers \
|
||||
-H "X-F2B-Server: default" | jq '.servers[] | {id, name, hostname}'
|
||||
```
|
||||
|
||||
### Quick reference: end-to-end callback flow
|
||||
|
||||
```
|
||||
Fail2Ban detects intrusion
|
||||
→ triggers actionban in ui-custom-action.conf
|
||||
→ curl POST /api/ban with JSON payload + X-Callback-Secret header
|
||||
→ Fail2ban-UI validates secret
|
||||
→ Fail2ban-UI validates IP format
|
||||
→ Fail2ban-UI resolves server (by serverId)
|
||||
→ Stores event in SQLite (ban_events table)
|
||||
→ Broadcasts via WebSocket to all connected browsers
|
||||
→ Optional: sends email alert, evaluates advanced actions
|
||||
```
|
||||
|
||||
If any step fails, the chain stops and the event will not appear in the UI.
|
||||
|
||||
## Bans fail due to firewall backend (nftables / firewalld)
|
||||
|
||||
Symptoms often mention `iptables (nf_tables)` or action startup errors.
|
||||
@@ -92,6 +281,34 @@ podman logs fail2ban-ui
|
||||
# Also enable debug logging over env or over the webUI
|
||||
```
|
||||
|
||||
## WebSocket not connecting
|
||||
|
||||
If the real-time dashboard updates (ban/unban events appearing without page refresh) are not working:
|
||||
|
||||
Check:
|
||||
|
||||
* Browser console for WebSocket errors (F12 → Console tab)
|
||||
* The WebSocket status indicator in the UI footer
|
||||
* If using a reverse proxy, ensure it supports WebSocket upgrades
|
||||
|
||||
Common issues:
|
||||
|
||||
* **Reverse proxy not forwarding WebSocket**: Nginx requires explicit WebSocket upgrade configuration:
|
||||
```nginx
|
||||
location /api/ws {
|
||||
proxy_pass http://127.0.0.1:8080;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
}
|
||||
```
|
||||
|
||||
* **Origin mismatch**: The WebSocket endpoint validates that the `Origin` header matches the `Host` header. If your reverse proxy rewrites the `Host` header but not the `Origin`, the connection will be rejected. Ensure both headers are consistent.
|
||||
|
||||
* **OIDC session expired**: When OIDC is enabled, the WebSocket requires a valid session. If the session expires, the WebSocket connection will fail with a 302 redirect or 401 error. Re-login to the UI to fix this.
|
||||
|
||||
## Database issues
|
||||
|
||||
Check:
|
||||
|
||||
Reference in New Issue
Block a user