From 2eb032ecd4f6963d73329a0b2f2d3a0b19a35f94 Mon Sep 17 00:00:00 2001 From: Lukas Date: Fri, 6 Mar 2026 18:57:50 +0100 Subject: [PATCH] Fix backend unable to open fail2ban database in dev compose MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The backend container mounted fail2ban-dev-config as an anonymous named volume, while the fail2ban container used a bind-mount of the same local directory. The backend's /config was therefore always empty, causing sqlite3.OperationalError when ban_service attempted to open the path returned by 'get dbfile' (/config/fail2ban/fail2ban.sqlite3). Change the backend volume declaration from the named volume reference to the same bind-mount used by fail2ban: fail2ban-dev-config:/config:ro → ./fail2ban-dev-config:/config:ro Also removes the now-unused 'fail2ban-dev-config' named-volume entry. Affected endpoints (all returned HTTP 500, now return HTTP 200): GET /api/dashboard/bans GET /api/dashboard/accesses GET /api/dashboard/bans/by-country --- Docker/compose.debug.yml | 4 +- Docs/Tasks.md | 1036 ++++++++++++++++++++++++++++++++++---- 2 files changed, 929 insertions(+), 111 deletions(-) diff --git a/Docker/compose.debug.yml b/Docker/compose.debug.yml index 4e185c0..9c8c465 100644 --- a/Docker/compose.debug.yml +++ b/Docker/compose.debug.yml @@ -65,7 +65,7 @@ services: - ../fail2ban-master:/app/fail2ban-master:ro,z - bangui-dev-data:/data - fail2ban-dev-run:/var/run/fail2ban:ro - - fail2ban-dev-config:/config:ro + - ./fail2ban-dev-config:/config:ro ports: - "${BANGUI_BACKEND_PORT:-8000}:8000" command: @@ -114,8 +114,6 @@ volumes: driver: local frontend-node-modules: driver: local - fail2ban-dev-config: - driver: local fail2ban-dev-run: driver: local diff --git a/Docs/Tasks.md b/Docs/Tasks.md index 99fd2a0..99b04b0 100644 --- a/Docs/Tasks.md +++ b/Docs/Tasks.md @@ -3,123 +3,943 @@ This document breaks the entire BanGUI project into development stages, ordered so that each stage builds on the previous one. Every task is described in prose with enough detail for a developer to begin work. References point to the relevant documentation. --- +1. ✅ DONE — fix ban list 500 error + **Root cause:** `compose.debug.yml` mounted `fail2ban-dev-config` as a named Docker volume + for the backend container, while fail2ban used a bind-mount of the same local directory. + The backend's `/config` was therefore an empty volume and could not open the fail2ban + SQLite database that fail2ban reported via `get dbfile`. + **Fix:** Changed the backend volume entry from `fail2ban-dev-config:/config:ro` to + `./fail2ban-dev-config:/config:ro` (bind-mount), and removed the now-unused named volume. + + ~~1. issue with ban list~~ +client.ts:55 GET http://127.0.0.1:5173/api/dashboard/bans?range=24h&page=1&page_size=100 500 (Internal Server Error) +request @ client.ts:55 +get @ client.ts:88 +fetchBans @ dashboard.ts:43 +(anonymous) @ useBans.ts:68 +(anonymous) @ useBans.ts:90 +commitHookEffectListMount @ react-dom.development.js:23189 +commitPassiveMountOnFiber @ react-dom.development.js:24965 +commitPassiveMountEffects_complete @ react-dom.development.js:24930 +commitPassiveMountEffects_begin @ react-dom.development.js:24917 +commitPassiveMountEffects @ react-dom.development.js:24905 +flushPassiveEffectsImpl @ react-dom.development.js:27078 +flushPassiveEffects @ react-dom.development.js:27023 +(anonymous) @ react-dom.development.js:26808 +workLoop @ scheduler.development.js:266 +flushWork @ scheduler.development.js:239 +performWorkUntilDeadline @ scheduler.development.js:533 +client.ts:55 GET http://127.0.0.1:5173/api/dashboard/bans?range=24h&page=1&page_size=100 500 (Internal Server Error) -## Stage 0 — Fail2ban Dev Test Environment +9110898d07c7 INFO: 10.89.0.3:55926 - "GET /api/dashboard/bans?range=24h&page=1&page_size=100 HTTP/1.1" 500 Internal Server Error +9110898d07c7 ERROR: Exception in ASGI application +9110898d07c7 Traceback (most recent call last): +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/uvicorn/protocols/http/httptools_impl.py", line 416, in run_asgi +9110898d07c7 result = await app( # type: ignore[func-returns-value] +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/uvicorn/middleware/proxy_headers.py", line 60, in __call__ +9110898d07c7 return await self.app(scope, receive, send) +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/applications.py", line 1160, in __call__ +9110898d07c7 await super().__call__(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/applications.py", line 107, in __call__ +9110898d07c7 await self.middleware_stack(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 186, in __call__ +9110898d07c7 raise exc +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 164, in __call__ +9110898d07c7 await self.app(scope, receive, _send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 191, in __call__ +9110898d07c7 with recv_stream, send_stream, collapse_excgroups(): +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/usr/local/lib/python3.12/contextlib.py", line 158, in __exit__ +9110898d07c7 self.gen.throw(value) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/_utils.py", line 87, in collapse_excgroups +9110898d07c7 raise exc +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 193, in __call__ +9110898d07c7 response = await self.dispatch_func(request, call_next) +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/app/app/main.py", line 294, in dispatch +9110898d07c7 return await call_next(request) +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 168, in call_next +9110898d07c7 raise app_exc from app_exc.__cause__ or app_exc.__context__ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 144, in coro +9110898d07c7 await self.app(scope, receive_or_disconnect, send_no_error) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/cors.py", line 87, in __call__ +9110898d07c7 await self.app(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 63, in __call__ +9110898d07c7 await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app +9110898d07c7 raise exc +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app +9110898d07c7 await app(scope, receive, sender) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__ +9110898d07c7 await self.app(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/routing.py", line 716, in __call__ +9110898d07c7 await self.middleware_stack(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/routing.py", line 736, in app +9110898d07c7 await route.handle(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/routing.py", line 290, in handle +9110898d07c7 await self.app(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/routing.py", line 129, in app +9110898d07c7 await wrap_app_handling_exceptions(app, request)(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app +9110898d07c7 raise exc +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app +9110898d07c7 await app(scope, receive, sender) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/routing.py", line 115, in app +9110898d07c7 response = await f(request) +9110898d07c7 ^^^^^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/routing.py", line 630, in app +9110898d07c7 raw_response = await run_endpoint_function( +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/routing.py", line 323, in run_endpoint_function +9110898d07c7 return await dependant.call(**values) +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/app/app/routers/dashboard.py", line 107, in get_dashboard_bans +9110898d07c7 return await ban_service.list_bans( +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/app/app/services/ban_service.py", line 181, in list_bans +9110898d07c7 async with aiosqlite.connect(f"file:{db_path}?mode=ro", uri=True) as f2b_db: +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py", line 181, in __aenter__ +9110898d07c7 return await self +9110898d07c7 ^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py", line 168, in _connect +9110898d07c7 self._connection = await future +9110898d07c7 ^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py", line 63, in _connection_worker_thread +9110898d07c7 result = function() +9110898d07c7 ^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py", line 466, in connector +9110898d07c7 return sqlite3.connect(loc, **kwargs) +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 sqlite3.OperationalError: unable to open database file +9110898d07c7 executing functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) +9110898d07c7 operation functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) +9110898d07c7 operation functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 INFO: 10.89.0.3:55942 - "GET /api/dashboard/status HTTP/1.1" 200 OK +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) +9110898d07c7 operation functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) +9110898d07c7 operation functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 INFO: 10.89.0.3:55946 - "GET /api/dashboard/status HTTP/1.1" 200 OK +9110898d07c7 Looking for jobs to run +9110898d07c7 Next wakeup is due at 2026-03-06 17:47:54.843643+00:00 (in 29.999878 seconds) +9110898d07c7 Running job "_run_probe (trigger: interval[0:00:30], next run at: 2026-03-06 17:47:54 UTC)" (scheduled at 2026-03-06 17:47:24.843643+00:00) +9110898d07c7 {"command": ["ping"], "event": "fail2ban_sending_command", "timestamp": "2026-03-06T17:47:24.843895Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"command": ["ping"], "event": "fail2ban_received_response", "timestamp": "2026-03-06T17:47:24.844510Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"command": ["version"], "event": "fail2ban_sending_command", "timestamp": "2026-03-06T17:47:24.844635Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"command": ["version"], "event": "fail2ban_received_response", "timestamp": "2026-03-06T17:47:24.844940Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"command": ["status"], "event": "fail2ban_sending_command", "timestamp": "2026-03-06T17:47:24.844983Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"command": ["status"], "event": "fail2ban_received_response", "timestamp": "2026-03-06T17:47:24.845150Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"command": ["status", "bangui-sim"], "event": "fail2ban_sending_command", "timestamp": "2026-03-06T17:47:24.845188Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"command": ["status", "bangui-sim"], "event": "fail2ban_received_response", "timestamp": "2026-03-06T17:47:24.845396Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"version": "1.1.0", "active_jails": 1, "total_bans": 0, "total_failures": 0, "event": "fail2ban_probe_ok", "timestamp": "2026-03-06T17:47:24.845437Z", "logger": "app.services.health_service", "level": "debug"} +9110898d07c7 {"online": true, "version": "1.1.0", "active_jails": 1, "event": "health_check_complete", "timestamp": "2026-03-06T17:47:24.845498Z", "logger": "app.tasks.health_check", "level": "debug"} +9110898d07c7 Job "_run_probe (trigger: interval[0:00:30], next run at: 2026-03-06 17:47:54 UTC)" executed successfully +9110898d07c7 INFO: 127.0.0.1:58940 - "GET /api/health HTTP/1.1" 200 OK +9110898d07c7 INFO: 127.0.0.1:41956 - "GET /api/health HTTP/1.1" 200 OK +9110898d07c7 executing functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) +9110898d07c7 operation functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) +9110898d07c7 operation functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 INFO: 10.89.0.3:54778 - "GET /api/dashboard/status HTTP/1.1" 200 OK +9110898d07c7 executing functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) +9110898d07c7 operation functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) +9110898d07c7 operation functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 INFO: 10.89.0.3:54780 - "GET /api/dashboard/status HTTP/1.1" 200 OK +9110898d07c7 executing functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) +9110898d07c7 operation functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) +9110898d07c7 operation functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 INFO: 10.89.0.3:54790 - "GET /api/dashboard/status HTTP/1.1" 200 OK +9110898d07c7 executing functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) +9110898d07c7 operation functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) +9110898d07c7 operation functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 INFO: 10.89.0.3:54804 - "GET /api/dashboard/status HTTP/1.1" 200 OK +9110898d07c7 executing functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) +9110898d07c7 operation functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) +9110898d07c7 operation functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 {"command": ["get", "dbfile"], "event": "fail2ban_sending_command", "timestamp": "2026-03-06T17:47:51.158844Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"command": ["get", "dbfile"], "event": "fail2ban_received_response", "timestamp": "2026-03-06T17:47:51.159260Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"db_path": "/config/fail2ban/fail2ban.sqlite3", "since": 1772732871, "range": "24h", "event": "ban_service_list_accesses", "timestamp": "2026-03-06T17:47:51.159342Z", "logger": "app.services.ban_service", "level": "info"} +9110898d07c7 executing .connector at 0x7abad4a2aac0> +9110898d07c7 returning exception unable to open database file +9110898d07c7 executing .close_and_stop at 0x7abad4a29580> +9110898d07c7 operation .close_and_stop at 0x7abad4a29580> completed +9110898d07c7 {"path": "/api/dashboard/accesses", "method": "GET", "event": "unhandled_exception", "timestamp": "2026-03-06T17:47:51.159773Z", "logger": "app.main", "level": "error", "exception": "Traceback (most recent call last):\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/errors.py\", line 164, in __call__\n await self.app(scope, receive, _send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py\", line 191, in __call__\n with recv_stream, send_stream, collapse_excgroups():\n ^^^^^^^^^^^^^^^^^^^^\n File \"/usr/local/lib/python3.12/contextlib.py\", line 158, in __exit__\n self.gen.throw(value)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/_utils.py\", line 87, in collapse_excgroups\n raise exc\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py\", line 193, in __call__\n response = await self.dispatch_func(request, call_next)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/app/app/main.py\", line 294, in dispatch\n return await call_next(request)\n ^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py\", line 168, in call_next\n raise app_exc from app_exc.__cause__ or app_exc.__context__\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py\", line 144, in coro\n await self.app(scope, receive_or_disconnect, send_no_error)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/cors.py\", line 87, in __call__\n await self.app(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/exceptions.py\", line 63, in __call__\n await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py\", line 53, in wrapped_app\n raise exc\n File \"/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py\", line 42, in wrapped_app\n await app(scope, receive, sender)\n File \"/opt/venv/lib/python3.12/site-packages/fastapi/middleware/asyncexitstack.py\", line 18, in __call__\n await self.app(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/routing.py\", line 716, in __call__\n await self.middleware_stack(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/routing.py\", line 736, in app\n await route.handle(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/routing.py\", line 290, in handle\n await self.app(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/fastapi/routing.py\", line 129, in app\n await wrap_app_handling_exceptions(app, request)(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py\", line 53, in wrapped_app\n raise exc\n File \"/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py\", line 42, in wrapped_app\n await app(scope, receive, sender)\n File \"/opt/venv/lib/python3.12/site-packages/fastapi/routing.py\", line 115, in app\n response = await f(request)\n ^^^^^^^^^^^^^^^^\n File \"/opt/venv/lib/python3.12/site-packages/fastapi/routing.py\", line 630, in app\n raw_response = await run_endpoint_function(\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/opt/venv/lib/python3.12/site-packages/fastapi/routing.py\", line 323, in run_endpoint_function\n return await dependant.call(**values)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/app/app/routers/dashboard.py\", line 152, in get_dashboard_accesses\n return await ban_service.list_accesses(\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/app/app/services/ban_service.py\", line 280, in list_accesses\n async with aiosqlite.connect(f\"file:{db_path}?mode=ro\", uri=True) as f2b_db:\n File \"/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py\", line 181, in __aenter__\n return await self\n ^^^^^^^^^^\n File \"/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py\", line 168, in _connect\n self._connection = await future\n ^^^^^^^^^^^^\n File \"/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py\", line 63, in _connection_worker_thread\n result = function()\n ^^^^^^^^^^\n File \"/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py\", line 466, in connector\n return sqlite3.connect(loc, **kwargs)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nsqlite3.OperationalError: unable to open database file"} +9110898d07c7 INFO: 10.89.0.3:54816 - "GET /api/dashboard/accesses?range=24h&page=1&page_size=100 HTTP/1.1" 500 Internal Server Error +9110898d07c7 ERROR: Exception in ASGI application +9110898d07c7 Traceback (most recent call last): +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/uvicorn/protocols/http/httptools_impl.py", line 416, in run_asgi +9110898d07c7 result = await app( # type: ignore[func-returns-value] +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/uvicorn/middleware/proxy_headers.py", line 60, in __call__ +9110898d07c7 return await self.app(scope, receive, send) +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/applications.py", line 1160, in __call__ +9110898d07c7 await super().__call__(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/applications.py", line 107, in __call__ +9110898d07c7 await self.middleware_stack(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 186, in __call__ +9110898d07c7 raise exc +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 164, in __call__ +9110898d07c7 await self.app(scope, receive, _send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 191, in __call__ +9110898d07c7 with recv_stream, send_stream, collapse_excgroups(): +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/usr/local/lib/python3.12/contextlib.py", line 158, in __exit__ +9110898d07c7 self.gen.throw(value) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/_utils.py", line 87, in collapse_excgroups +9110898d07c7 raise exc +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 193, in __call__ +9110898d07c7 response = await self.dispatch_func(request, call_next) +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/app/app/main.py", line 294, in dispatch +9110898d07c7 return await call_next(request) +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 168, in call_next +9110898d07c7 raise app_exc from app_exc.__cause__ or app_exc.__context__ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 144, in coro +9110898d07c7 await self.app(scope, receive_or_disconnect, send_no_error) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/cors.py", line 87, in __call__ +9110898d07c7 await self.app(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 63, in __call__ +9110898d07c7 await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app +9110898d07c7 raise exc +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app +9110898d07c7 await app(scope, receive, sender) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__ +9110898d07c7 await self.app(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/routing.py", line 716, in __call__ +9110898d07c7 await self.middleware_stack(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/routing.py", line 736, in app +9110898d07c7 await route.handle(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/routing.py", line 290, in handle +9110898d07c7 await self.app(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/routing.py", line 129, in app +9110898d07c7 await wrap_app_handling_exceptions(app, request)(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app +9110898d07c7 raise exc +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app +9110898d07c7 await app(scope, receive, sender) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/routing.py", line 115, in app +9110898d07c7 response = await f(request) +9110898d07c7 ^^^^^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/routing.py", line 630, in app +9110898d07c7 raw_response = await run_endpoint_function( +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/routing.py", line 323, in run_endpoint_function +9110898d07c7 return await dependant.call(**values) +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/app/app/routers/dashboard.py", line 152, in get_dashboard_accesses +9110898d07c7 return await ban_service.list_accesses( +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/app/app/services/ban_service.py", line 280, in list_accesses +9110898d07c7 async with aiosqlite.connect(f"file:{db_path}?mode=ro", uri=True) as f2b_db: +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py", line 181, in __aenter__ +9110898d07c7 return await self +9110898d07c7 ^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py", line 168, in _connect +9110898d07c7 self._connection = await future +9110898d07c7 ^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py", line 63, in _connection_worker_thread +9110898d07c7 result = function() +9110898d07c7 ^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py", line 466, in connector +9110898d07c7 return sqlite3.connect(loc, **kwargs) +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 sqlite3.OperationalError: unable to open database file +9110898d07c7 Looking for jobs to run +9110898d07c7 Next wakeup is due at 2026-03-06 17:48:24.843643+00:00 (in 29.999538 seconds) +9110898d07c7 Running job "_run_probe (trigger: interval[0:00:30], next run at: 2026-03-06 17:48:24 UTC)" (scheduled at 2026-03-06 17:47:54.843643+00:00) +9110898d07c7 {"command": ["ping"], "event": "fail2ban_sending_command", "timestamp": "2026-03-06T17:47:54.844275Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"command": ["ping"], "event": "fail2ban_received_response", "timestamp": "2026-03-06T17:47:54.844782Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"command": ["version"], "event": "fail2ban_sending_command", "timestamp": "2026-03-06T17:47:54.844845Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"command": ["version"], "event": "fail2ban_received_response", "timestamp": "2026-03-06T17:47:54.845117Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"command": ["status"], "event": "fail2ban_sending_command", "timestamp": "2026-03-06T17:47:54.845171Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"command": ["status"], "event": "fail2ban_received_response", "timestamp": "2026-03-06T17:47:54.845424Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"command": ["status", "bangui-sim"], "event": "fail2ban_sending_command", "timestamp": "2026-03-06T17:47:54.845486Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"command": ["status", "bangui-sim"], "event": "fail2ban_received_response", "timestamp": "2026-03-06T17:47:54.845745Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"version": "1.1.0", "active_jails": 1, "total_bans": 0, "total_failures": 0, "event": "fail2ban_probe_ok", "timestamp": "2026-03-06T17:47:54.845805Z", "logger": "app.services.health_service", "level": "debug"} +9110898d07c7 {"online": true, "version": "1.1.0", "active_jails": 1, "event": "health_check_complete", "timestamp": "2026-03-06T17:47:54.845871Z", "logger": "app.tasks.health_check", "level": "debug"} +9110898d07c7 Job "_run_probe (trigger: interval[0:00:30], next run at: 2026-03-06 17:48:24 UTC)" executed successfully +9110898d07c7 INFO: 127.0.0.1:52658 - "GET /api/health HTTP/1.1" 200 OK +9110898d07c7 INFO: 127.0.0.1:42840 - "GET /api/health HTTP/1.1" 200 OK +9110898d07c7 executing functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) +9110898d07c7 operation functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) +9110898d07c7 operation functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 INFO: 10.89.0.3:59946 - "GET /api/dashboard/status HTTP/1.1" 200 OK +9110898d07c7 executing functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) +9110898d07c7 operation functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) +9110898d07c7 operation functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 INFO: 10.89.0.3:59952 - "GET /api/dashboard/status HTTP/1.1" 200 OK +9110898d07c7 Looking for jobs to run +9110898d07c7 Next wakeup is due at 2026-03-06 17:48:54.843643+00:00 (in 29.998906 seconds) +9110898d07c7 Running job "_run_probe (trigger: interval[0:00:30], next run at: 2026-03-06 17:48:54 UTC)" (scheduled at 2026-03-06 17:48:24.843643+00:00) +9110898d07c7 {"command": ["ping"], "event": "fail2ban_sending_command", "timestamp": "2026-03-06T17:48:24.844922Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"command": ["ping"], "event": "fail2ban_received_response", "timestamp": "2026-03-06T17:48:24.845403Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"command": ["version"], "event": "fail2ban_sending_command", "timestamp": "2026-03-06T17:48:24.845477Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"command": ["version"], "event": "fail2ban_received_response", "timestamp": "2026-03-06T17:48:24.845741Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"command": ["status"], "event": "fail2ban_sending_command", "timestamp": "2026-03-06T17:48:24.845783Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"command": ["status"], "event": "fail2ban_received_response", "timestamp": "2026-03-06T17:48:24.846021Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"command": ["status", "bangui-sim"], "event": "fail2ban_sending_command", "timestamp": "2026-03-06T17:48:24.846060Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"command": ["status", "bangui-sim"], "event": "fail2ban_received_response", "timestamp": "2026-03-06T17:48:24.846284Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"version": "1.1.0", "active_jails": 1, "total_bans": 0, "total_failures": 0, "event": "fail2ban_probe_ok", "timestamp": "2026-03-06T17:48:24.846340Z", "logger": "app.services.health_service", "level": "debug"} +9110898d07c7 {"online": true, "version": "1.1.0", "active_jails": 1, "event": "health_check_complete", "timestamp": "2026-03-06T17:48:24.846394Z", "logger": "app.tasks.health_check", "level": "debug"} +9110898d07c7 Job "_run_probe (trigger: interval[0:00:30], next run at: 2026-03-06 17:48:54 UTC)" executed successfully +9110898d07c7 INFO: 127.0.0.1:39434 - "GET /api/health HTTP/1.1" 200 OK +9110898d07c7 INFO: 127.0.0.1:47306 - "GET /api/health HTTP/1.1" 200 OK +9110898d07c7 executing functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) +9110898d07c7 operation functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) +9110898d07c7 operation functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 INFO: 10.89.0.3:44266 - "GET /api/dashboard/status HTTP/1.1" 200 OK +9110898d07c7 executing functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) +9110898d07c7 operation functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) +9110898d07c7 operation functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 INFO: 10.89.0.3:44278 - "GET /api/dashboard/status HTTP/1.1" 200 OK +9110898d07c7 Looking for jobs to run +9110898d07c7 Next wakeup is due at 2026-03-06 17:49:24.843643+00:00 (in 29.999723 seconds) +9110898d07c7 Running job "_run_probe (trigger: interval[0:00:30], next run at: 2026-03-06 17:49:24 UTC)" (scheduled at 2026-03-06 17:48:54.843643+00:00) +9110898d07c7 {"command": ["ping"], "event": "fail2ban_sending_command", "timestamp": "2026-03-06T17:48:54.844056Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"command": ["ping"], "event": "fail2ban_received_response", "timestamp": "2026-03-06T17:48:54.844512Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"command": ["version"], "event": "fail2ban_sending_command", "timestamp": "2026-03-06T17:48:54.844602Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"command": ["version"], "event": "fail2ban_received_response", "timestamp": "2026-03-06T17:48:54.844871Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"command": ["status"], "event": "fail2ban_sending_command", "timestamp": "2026-03-06T17:48:54.844910Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"command": ["status"], "event": "fail2ban_received_response", "timestamp": "2026-03-06T17:48:54.845133Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"command": ["status", "bangui-sim"], "event": "fail2ban_sending_command", "timestamp": "2026-03-06T17:48:54.845172Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"command": ["status", "bangui-sim"], "event": "fail2ban_received_response", "timestamp": "2026-03-06T17:48:54.845364Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"version": "1.1.0", "active_jails": 1, "total_bans": 0, "total_failures": 0, "event": "fail2ban_probe_ok", "timestamp": "2026-03-06T17:48:54.845412Z", "logger": "app.services.health_service", "level": "debug"} +9110898d07c7 {"online": true, "version": "1.1.0", "active_jails": 1, "event": "health_check_complete", "timestamp": "2026-03-06T17:48:54.845463Z", "logger": "app.tasks.health_check", "level": "debug"} +9110898d07c7 Job "_run_probe (trigger: interval[0:00:30], next run at: 2026-03-06 17:49:24 UTC)" executed successfully +9110898d07c7 INFO: 127.0.0.1:57926 - "GET /api/health HTTP/1.1" 200 OK -**Goal:** Set up a self-contained test environment where a script simulates failed login attempts, those attempts are written to a log file in `Docker/logs/`, fail2ban monitors that log and bans the offending IP. This provides a reproducible way to test the ban/unban lifecycle without a real service. -**Status: ✅ Complete** — all tasks 0.1–0.8 implemented. ---- +9110898d07c7 executing functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) +9110898d07c7 operation functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) +9110898d07c7 operation functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 INFO: 10.89.0.3:53218 - "GET /api/dashboard/status HTTP/1.1" 200 OK +9110898d07c7 executing functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) +9110898d07c7 operation functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) +9110898d07c7 operation functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 INFO: 10.89.0.3:53230 - "GET /api/dashboard/status HTTP/1.1" 200 OK +9110898d07c7 executing functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) +9110898d07c7 operation functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) +9110898d07c7 operation functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 {"command": ["get", "dbfile"], "event": "fail2ban_sending_command", "timestamp": "2026-03-06T17:49:14.550932Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"command": ["get", "dbfile"], "event": "fail2ban_received_response", "timestamp": "2026-03-06T17:49:14.551431Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"db_path": "/config/fail2ban/fail2ban.sqlite3", "since": 1772732954, "range": "24h", "event": "ban_service_list_bans", "timestamp": "2026-03-06T17:49:14.551521Z", "logger": "app.services.ban_service", "level": "info"} +9110898d07c7 executing .connector at 0x7abad4a08540> +9110898d07c7 returning exception unable to open database file +9110898d07c7 executing .close_and_stop at 0x7abad4b3ede0> +9110898d07c7 operation .close_and_stop at 0x7abad4b3ede0> completed +9110898d07c7 {"path": "/api/dashboard/bans", "method": "GET", "event": "unhandled_exception", "timestamp": "2026-03-06T17:49:14.552411Z", "logger": "app.main", "level": "error", "exception": "Traceback (most recent call last):\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/errors.py\", line 164, in __call__\n await self.app(scope, receive, _send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py\", line 191, in __call__\n with recv_stream, send_stream, collapse_excgroups():\n ^^^^^^^^^^^^^^^^^^^^\n File \"/usr/local/lib/python3.12/contextlib.py\", line 158, in __exit__\n self.gen.throw(value)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/_utils.py\", line 87, in collapse_excgroups\n raise exc\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py\", line 193, in __call__\n response = await self.dispatch_func(request, call_next)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/app/app/main.py\", line 294, in dispatch\n return await call_next(request)\n ^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py\", line 168, in call_next\n raise app_exc from app_exc.__cause__ or app_exc.__context__\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py\", line 144, in coro\n await self.app(scope, receive_or_disconnect, send_no_error)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/cors.py\", line 87, in __call__\n await self.app(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/exceptions.py\", line 63, in __call__\n await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py\", line 53, in wrapped_app\n raise exc\n File \"/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py\", line 42, in wrapped_app\n await app(scope, receive, sender)\n File \"/opt/venv/lib/python3.12/site-packages/fastapi/middleware/asyncexitstack.py\", line 18, in __call__\n await self.app(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/routing.py\", line 716, in __call__\n await self.middleware_stack(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/routing.py\", line 736, in app\n await route.handle(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/routing.py\", line 290, in handle\n await self.app(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/fastapi/routing.py\", line 129, in app\n await wrap_app_handling_exceptions(app, request)(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py\", line 53, in wrapped_app\n raise exc\n File \"/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py\", line 42, in wrapped_app\n await app(scope, receive, sender)\n File \"/opt/venv/lib/python3.12/site-packages/fastapi/routing.py\", line 115, in app\n response = await f(request)\n ^^^^^^^^^^^^^^^^\n File \"/opt/venv/lib/python3.12/site-packages/fastapi/routing.py\", line 630, in app\n raw_response = await run_endpoint_function(\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/opt/venv/lib/python3.12/site-packages/fastapi/routing.py\", line 323, in run_endpoint_function\n return await dependant.call(**values)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/app/app/routers/dashboard.py\", line 107, in get_dashboard_bans\n return await ban_service.list_bans(\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/app/app/services/ban_service.py\", line 181, in list_bans\n async with aiosqlite.connect(f\"file:{db_path}?mode=ro\", uri=True) as f2b_db:\n File \"/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py\", line 181, in __aenter__\n return await self\n ^^^^^^^^^^\n File \"/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py\", line 168, in _connect\n self._connection = await future\n ^^^^^^^^^^^^\n File \"/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py\", line 63, in _connection_worker_thread\n result = function()\n ^^^^^^^^^^\n File \"/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py\", line 466, in connector\n return sqlite3.connect(loc, **kwargs)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nsqlite3.OperationalError: unable to open database file"} +9110898d07c7 INFO: 10.89.0.3:53234 - "GET /api/dashboard/bans?range=24h&page=1&page_size=100 HTTP/1.1" 500 Internal Server Error +9110898d07c7 ERROR: Exception in ASGI application +9110898d07c7 Traceback (most recent call last): +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/uvicorn/protocols/http/httptools_impl.py", line 416, in run_asgi +9110898d07c7 result = await app( # type: ignore[func-returns-value] +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/uvicorn/middleware/proxy_headers.py", line 60, in __call__ +9110898d07c7 return await self.app(scope, receive, send) +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/applications.py", line 1160, in __call__ +9110898d07c7 await super().__call__(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/applications.py", line 107, in __call__ +9110898d07c7 await self.middleware_stack(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 186, in __call__ +9110898d07c7 raise exc +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 164, in __call__ +9110898d07c7 await self.app(scope, receive, _send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 191, in __call__ +9110898d07c7 with recv_stream, send_stream, collapse_excgroups(): +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/usr/local/lib/python3.12/contextlib.py", line 158, in __exit__ +9110898d07c7 self.gen.throw(value) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/_utils.py", line 87, in collapse_excgroups +9110898d07c7 raise exc +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 193, in __call__ +9110898d07c7 response = await self.dispatch_func(request, call_next) +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/app/app/main.py", line 294, in dispatch +9110898d07c7 return await call_next(request) +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 168, in call_next +9110898d07c7 raise app_exc from app_exc.__cause__ or app_exc.__context__ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 144, in coro +9110898d07c7 await self.app(scope, receive_or_disconnect, send_no_error) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/cors.py", line 87, in __call__ +9110898d07c7 await self.app(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 63, in __call__ +9110898d07c7 await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app +9110898d07c7 raise exc +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app +9110898d07c7 await app(scope, receive, sender) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__ +9110898d07c7 await self.app(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/routing.py", line 716, in __call__ +9110898d07c7 await self.middleware_stack(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/routing.py", line 736, in app +9110898d07c7 await route.handle(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/routing.py", line 290, in handle +9110898d07c7 await self.app(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/routing.py", line 129, in app +9110898d07c7 await wrap_app_handling_exceptions(app, request)(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app +9110898d07c7 raise exc +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app +9110898d07c7 await app(scope, receive, sender) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/routing.py", line 115, in app +9110898d07c7 response = await f(request) +9110898d07c7 ^^^^^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/routing.py", line 630, in app +9110898d07c7 raw_response = await run_endpoint_function( +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/routing.py", line 323, in run_endpoint_function +9110898d07c7 return await dependant.call(**values) +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/app/app/routers/dashboard.py", line 107, in get_dashboard_bans +9110898d07c7 return await ban_service.list_bans( +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/app/app/services/ban_service.py", line 181, in list_bans +9110898d07c7 async with aiosqlite.connect(f"file:{db_path}?mode=ro", uri=True) as f2b_db: +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py", line 181, in __aenter__ +9110898d07c7 return await self +9110898d07c7 ^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py", line 168, in _connect +9110898d07c7 self._connection = await future +9110898d07c7 ^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py", line 63, in _connection_worker_thread +9110898d07c7 result = function() +9110898d07c7 ^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py", line 466, in connector +9110898d07c7 return sqlite3.connect(loc, **kwargs) +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 sqlite3.OperationalError: unable to open database file +9110898d07c7 executing functools.partial( bangui-auth: authentication failure from -``` -The filter file should contain: +9110898d07c7 executing functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) +9110898d07c7 operation functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) +9110898d07c7 operation functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 INFO: 10.89.0.3:51584 - "GET /api/dashboard/status HTTP/1.1" 200 OK +9110898d07c7 executing functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) +9110898d07c7 operation functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) +9110898d07c7 operation functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 INFO: 10.89.0.3:51594 - "GET /api/dashboard/status HTTP/1.1" 200 OK +9110898d07c7 executing functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) +9110898d07c7 operation functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) +9110898d07c7 operation functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 {"command": ["get", "dbfile"], "event": "fail2ban_sending_command", "timestamp": "2026-03-06T17:50:15.290244Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"command": ["get", "dbfile"], "event": "fail2ban_received_response", "timestamp": "2026-03-06T17:50:15.290773Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"db_path": "/config/fail2ban/fail2ban.sqlite3", "since": 1772733015, "range": "24h", "event": "ban_service_list_accesses", "timestamp": "2026-03-06T17:50:15.290865Z", "logger": "app.services.ban_service", "level": "info"} +9110898d07c7 executing .connector at 0x7abad4a08720> +9110898d07c7 returning exception unable to open database file +9110898d07c7 executing .close_and_stop at 0x7abad4a087c0> +9110898d07c7 operation .close_and_stop at 0x7abad4a087c0> completed +9110898d07c7 {"path": "/api/dashboard/accesses", "method": "GET", "event": "unhandled_exception", "timestamp": "2026-03-06T17:50:15.291399Z", "logger": "app.main", "level": "error", "exception": "Traceback (most recent call last):\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/errors.py\", line 164, in __call__\n await self.app(scope, receive, _send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py\", line 191, in __call__\n with recv_stream, send_stream, collapse_excgroups():\n ^^^^^^^^^^^^^^^^^^^^\n File \"/usr/local/lib/python3.12/contextlib.py\", line 158, in __exit__\n self.gen.throw(value)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/_utils.py\", line 87, in collapse_excgroups\n raise exc\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py\", line 193, in __call__\n response = await self.dispatch_func(request, call_next)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/app/app/main.py\", line 294, in dispatch\n return await call_next(request)\n ^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py\", line 168, in call_next\n raise app_exc from app_exc.__cause__ or app_exc.__context__\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py\", line 144, in coro\n await self.app(scope, receive_or_disconnect, send_no_error)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/cors.py\", line 87, in __call__\n await self.app(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/exceptions.py\", line 63, in __call__\n await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py\", line 53, in wrapped_app\n raise exc\n File \"/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py\", line 42, in wrapped_app\n await app(scope, receive, sender)\n File \"/opt/venv/lib/python3.12/site-packages/fastapi/middleware/asyncexitstack.py\", line 18, in __call__\n await self.app(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/routing.py\", line 716, in __call__\n await self.middleware_stack(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/routing.py\", line 736, in app\n await route.handle(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/routing.py\", line 290, in handle\n await self.app(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/fastapi/routing.py\", line 129, in app\n await wrap_app_handling_exceptions(app, request)(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py\", line 53, in wrapped_app\n raise exc\n File \"/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py\", line 42, in wrapped_app\n await app(scope, receive, sender)\n File \"/opt/venv/lib/python3.12/site-packages/fastapi/routing.py\", line 115, in app\n response = await f(request)\n ^^^^^^^^^^^^^^^^\n File \"/opt/venv/lib/python3.12/site-packages/fastapi/routing.py\", line 630, in app\n raw_response = await run_endpoint_function(\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/opt/venv/lib/python3.12/site-packages/fastapi/routing.py\", line 323, in run_endpoint_function\n return await dependant.call(**values)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/app/app/routers/dashboard.py\", line 152, in get_dashboard_accesses\n return await ban_service.list_accesses(\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/app/app/services/ban_service.py\", line 280, in list_accesses\n async with aiosqlite.connect(f\"file:{db_path}?mode=ro\", uri=True) as f2b_db:\n File \"/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py\", line 181, in __aenter__\n return await self\n ^^^^^^^^^^\n File \"/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py\", line 168, in _connect\n self._connection = await future\n ^^^^^^^^^^^^\n File \"/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py\", line 63, in _connection_worker_thread\n result = function()\n ^^^^^^^^^^\n File \"/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py\", line 466, in connector\n return sqlite3.connect(loc, **kwargs)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nsqlite3.OperationalError: unable to open database file"} +9110898d07c7 INFO: 10.89.0.3:51598 - "GET /api/dashboard/accesses?range=24h&page=1&page_size=100 HTTP/1.1" 500 Internal Server Error +9110898d07c7 ERROR: Exception in ASGI application +9110898d07c7 Traceback (most recent call last): +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/uvicorn/protocols/http/httptools_impl.py", line 416, in run_asgi +9110898d07c7 result = await app( # type: ignore[func-returns-value] +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/uvicorn/middleware/proxy_headers.py", line 60, in __call__ +9110898d07c7 return await self.app(scope, receive, send) +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/applications.py", line 1160, in __call__ +9110898d07c7 await super().__call__(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/applications.py", line 107, in __call__ +9110898d07c7 await self.middleware_stack(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 186, in __call__ +9110898d07c7 raise exc +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 164, in __call__ +9110898d07c7 await self.app(scope, receive, _send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 191, in __call__ +9110898d07c7 with recv_stream, send_stream, collapse_excgroups(): +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/usr/local/lib/python3.12/contextlib.py", line 158, in __exit__ +9110898d07c7 self.gen.throw(value) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/_utils.py", line 87, in collapse_excgroups +9110898d07c7 raise exc +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 193, in __call__ +9110898d07c7 response = await self.dispatch_func(request, call_next) +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/app/app/main.py", line 294, in dispatch +9110898d07c7 return await call_next(request) +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 168, in call_next +9110898d07c7 raise app_exc from app_exc.__cause__ or app_exc.__context__ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 144, in coro +9110898d07c7 await self.app(scope, receive_or_disconnect, send_no_error) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/cors.py", line 87, in __call__ +9110898d07c7 await self.app(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 63, in __call__ +9110898d07c7 await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app +9110898d07c7 raise exc +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app +9110898d07c7 await app(scope, receive, sender) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__ +9110898d07c7 await self.app(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/routing.py", line 716, in __call__ +9110898d07c7 await self.middleware_stack(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/routing.py", line 736, in app +9110898d07c7 await route.handle(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/routing.py", line 290, in handle +9110898d07c7 await self.app(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/routing.py", line 129, in app +9110898d07c7 await wrap_app_handling_exceptions(app, request)(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app +9110898d07c7 raise exc +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app +9110898d07c7 await app(scope, receive, sender) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/routing.py", line 115, in app +9110898d07c7 response = await f(request) +9110898d07c7 ^^^^^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/routing.py", line 630, in app +9110898d07c7 raw_response = await run_endpoint_function( +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/routing.py", line 323, in run_endpoint_function +9110898d07c7 return await dependant.call(**values) +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/app/app/routers/dashboard.py", line 152, in get_dashboard_accesses +9110898d07c7 return await ban_service.list_accesses( +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/app/app/services/ban_service.py", line 280, in list_accesses +9110898d07c7 async with aiosqlite.connect(f"file:{db_path}?mode=ro", uri=True) as f2b_db: +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py", line 181, in __aenter__ +9110898d07c7 return await self +9110898d07c7 ^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py", line 168, in _connect +9110898d07c7 self._connection = await future +9110898d07c7 ^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py", line 63, in _connection_worker_thread +9110898d07c7 result = function() +9110898d07c7 ^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py", line 466, in connector +9110898d07c7 return sqlite3.connect(loc, **kwargs) +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 sqlite3.OperationalError: unable to open database file +9110898d07c7 executing functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) +9110898d07c7 operation functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) +9110898d07c7 operation functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 INFO: 10.89.0.3:51600 - "GET /api/dashboard/status HTTP/1.1" 200 OK +9110898d07c7 executing functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) +9110898d07c7 operation functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) +9110898d07c7 operation functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 INFO: 10.89.0.3:51606 - "GET /api/dashboard/status HTTP/1.1" 200 OK +9110898d07c7 INFO: 127.0.0.1:60528 - "GET /api/health HTTP/1.1" 200 OK -- A `[Definition]` section. -- A `failregex` line that captures `` from lines matching the format above (e.g. `^.* bangui-auth: authentication failure from \s*$`). -- An empty `ignoreregex`. +3. World map -**Reference:** existing filters in `Docker/fail2ban-dev-config/fail2ban/filter.d/` for syntax examples. ---- +9110898d07c7 executing functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) +9110898d07c7 operation functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) +9110898d07c7 operation functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 INFO: 10.89.0.3:43234 - "GET /api/dashboard/status HTTP/1.1" 200 OK +9110898d07c7 executing functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) +9110898d07c7 operation functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) +9110898d07c7 operation functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 INFO: 10.89.0.3:43236 - "GET /api/dashboard/status HTTP/1.1" 200 OK +9110898d07c7 executing functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) +9110898d07c7 operation functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) +9110898d07c7 operation functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 {"command": ["get", "dbfile"], "event": "fail2ban_sending_command", "timestamp": "2026-03-06T17:50:59.369697Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"command": ["get", "dbfile"], "event": "fail2ban_received_response", "timestamp": "2026-03-06T17:50:59.370154Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"db_path": "/config/fail2ban/fail2ban.sqlite3", "since": 1772733059, "range": "24h", "event": "ban_service_bans_by_country", "timestamp": "2026-03-06T17:50:59.370213Z", "logger": "app.services.ban_service", "level": "info"} +9110898d07c7 executing .connector at 0x7abad4a2aca0> +9110898d07c7 returning exception unable to open database file +9110898d07c7 executing .close_and_stop at 0x7abad4a2af20> +9110898d07c7 operation .close_and_stop at 0x7abad4a2af20> completed +9110898d07c7 {"path": "/api/dashboard/bans/by-country", "method": "GET", "event": "unhandled_exception", "timestamp": "2026-03-06T17:50:59.370651Z", "logger": "app.main", "level": "error", "exception": "Traceback (most recent call last):\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/errors.py\", line 164, in __call__\n await self.app(scope, receive, _send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py\", line 191, in __call__\n with recv_stream, send_stream, collapse_excgroups():\n ^^^^^^^^^^^^^^^^^^^^\n File \"/usr/local/lib/python3.12/contextlib.py\", line 158, in __exit__\n self.gen.throw(value)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/_utils.py\", line 87, in collapse_excgroups\n raise exc\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py\", line 193, in __call__\n response = await self.dispatch_func(request, call_next)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/app/app/main.py\", line 294, in dispatch\n return await call_next(request)\n ^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py\", line 168, in call_next\n raise app_exc from app_exc.__cause__ or app_exc.__context__\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py\", line 144, in coro\n await self.app(scope, receive_or_disconnect, send_no_error)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/cors.py\", line 87, in __call__\n await self.app(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/exceptions.py\", line 63, in __call__\n await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py\", line 53, in wrapped_app\n raise exc\n File \"/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py\", line 42, in wrapped_app\n await app(scope, receive, sender)\n File \"/opt/venv/lib/python3.12/site-packages/fastapi/middleware/asyncexitstack.py\", line 18, in __call__\n await self.app(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/routing.py\", line 716, in __call__\n await self.middleware_stack(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/routing.py\", line 736, in app\n await route.handle(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/routing.py\", line 290, in handle\n await self.app(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/fastapi/routing.py\", line 129, in app\n await wrap_app_handling_exceptions(app, request)(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py\", line 53, in wrapped_app\n raise exc\n File \"/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py\", line 42, in wrapped_app\n await app(scope, receive, sender)\n File \"/opt/venv/lib/python3.12/site-packages/fastapi/routing.py\", line 115, in app\n response = await f(request)\n ^^^^^^^^^^^^^^^^\n File \"/opt/venv/lib/python3.12/site-packages/fastapi/routing.py\", line 630, in app\n raw_response = await run_endpoint_function(\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/opt/venv/lib/python3.12/site-packages/fastapi/routing.py\", line 323, in run_endpoint_function\n return await dependant.call(**values)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/app/app/routers/dashboard.py\", line 192, in get_bans_by_country\n return await ban_service.bans_by_country(\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/app/app/services/ban_service.py\", line 366, in bans_by_country\n async with aiosqlite.connect(f\"file:{db_path}?mode=ro\", uri=True) as f2b_db:\n File \"/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py\", line 181, in __aenter__\n return await self\n ^^^^^^^^^^\n File \"/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py\", line 168, in _connect\n self._connection = await future\n ^^^^^^^^^^^^\n File \"/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py\", line 63, in _connection_worker_thread\n result = function()\n ^^^^^^^^^^\n File \"/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py\", line 466, in connector\n return sqlite3.connect(loc, **kwargs)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nsqlite3.OperationalError: unable to open database file"} +9110898d07c7 INFO: 10.89.0.3:43246 - "GET /api/dashboard/bans/by-country?range=24h HTTP/1.1" 500 Internal Server Error +9110898d07c7 ERROR: Exception in ASGI application +9110898d07c7 Traceback (most recent call last): +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/uvicorn/protocols/http/httptools_impl.py", line 416, in run_asgi +9110898d07c7 result = await app( # type: ignore[func-returns-value] +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/uvicorn/middleware/proxy_headers.py", line 60, in __call__ +9110898d07c7 return await self.app(scope, receive, send) +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/applications.py", line 1160, in __call__ +9110898d07c7 await super().__call__(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/applications.py", line 107, in __call__ +9110898d07c7 await self.middleware_stack(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 186, in __call__ +9110898d07c7 raise exc +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 164, in __call__ +9110898d07c7 await self.app(scope, receive, _send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 191, in __call__ +9110898d07c7 with recv_stream, send_stream, collapse_excgroups(): +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/usr/local/lib/python3.12/contextlib.py", line 158, in __exit__ +9110898d07c7 self.gen.throw(value) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/_utils.py", line 87, in collapse_excgroups +9110898d07c7 raise exc +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 193, in __call__ +9110898d07c7 response = await self.dispatch_func(request, call_next) +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/app/app/main.py", line 294, in dispatch +9110898d07c7 return await call_next(request) +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 168, in call_next +9110898d07c7 raise app_exc from app_exc.__cause__ or app_exc.__context__ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 144, in coro +9110898d07c7 await self.app(scope, receive_or_disconnect, send_no_error) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/cors.py", line 87, in __call__ +9110898d07c7 await self.app(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 63, in __call__ +9110898d07c7 await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app +9110898d07c7 raise exc +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app +9110898d07c7 await app(scope, receive, sender) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__ +9110898d07c7 await self.app(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/routing.py", line 716, in __call__ +9110898d07c7 await self.middleware_stack(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/routing.py", line 736, in app +9110898d07c7 await route.handle(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/routing.py", line 290, in handle +9110898d07c7 await self.app(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/routing.py", line 129, in app +9110898d07c7 await wrap_app_handling_exceptions(app, request)(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app +9110898d07c7 raise exc +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app +9110898d07c7 await app(scope, receive, sender) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/routing.py", line 115, in app +9110898d07c7 response = await f(request) +9110898d07c7 ^^^^^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/routing.py", line 630, in app +9110898d07c7 raw_response = await run_endpoint_function( +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/routing.py", line 323, in run_endpoint_function +9110898d07c7 return await dependant.call(**values) +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/app/app/routers/dashboard.py", line 192, in get_bans_by_country +9110898d07c7 return await ban_service.bans_by_country( +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/app/app/services/ban_service.py", line 366, in bans_by_country +9110898d07c7 async with aiosqlite.connect(f"file:{db_path}?mode=ro", uri=True) as f2b_db: +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py", line 181, in __aenter__ +9110898d07c7 return await self +9110898d07c7 ^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py", line 168, in _connect +9110898d07c7 self._connection = await future +9110898d07c7 ^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py", line 63, in _connection_worker_thread +9110898d07c7 result = function() +9110898d07c7 ^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py", line 466, in connector +9110898d07c7 return sqlite3.connect(loc, **kwargs) +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 sqlite3.OperationalError: unable to open database file +9110898d07c7 executing functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) +9110898d07c7 operation functools.partial(, 'SELECT value FROM settings WHERE key = ?', ('setup_completed',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) +9110898d07c7 operation functools.partial(, 'SELECT id, token, created_at, expires_at FROM sessions WHERE token = ?', ('e829a2a69e384640c259f069c8574de6b8bb486257f4a7f005a05757260ce832',)) completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 executing functools.partial() +9110898d07c7 operation functools.partial() completed +9110898d07c7 {"command": ["get", "dbfile"], "event": "fail2ban_sending_command", "timestamp": "2026-03-06T17:50:59.377467Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"command": ["get", "dbfile"], "event": "fail2ban_received_response", "timestamp": "2026-03-06T17:50:59.378109Z", "logger": "app.utils.fail2ban_client", "level": "debug"} +9110898d07c7 {"db_path": "/config/fail2ban/fail2ban.sqlite3", "since": 1772733059, "range": "24h", "event": "ban_service_bans_by_country", "timestamp": "2026-03-06T17:50:59.378383Z", "logger": "app.services.ban_service", "level": "info"} +9110898d07c7 executing .connector at 0x7abad4b3e660> +9110898d07c7 returning exception unable to open database file +9110898d07c7 executing .close_and_stop at 0x7abad4b3dda0> +9110898d07c7 operation .close_and_stop at 0x7abad4b3dda0> completed +9110898d07c7 {"path": "/api/dashboard/bans/by-country", "method": "GET", "event": "unhandled_exception", "timestamp": "2026-03-06T17:50:59.380270Z", "logger": "app.main", "level": "error", "exception": "Traceback (most recent call last):\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/errors.py\", line 164, in __call__\n await self.app(scope, receive, _send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py\", line 191, in __call__\n with recv_stream, send_stream, collapse_excgroups():\n ^^^^^^^^^^^^^^^^^^^^\n File \"/usr/local/lib/python3.12/contextlib.py\", line 158, in __exit__\n self.gen.throw(value)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/_utils.py\", line 87, in collapse_excgroups\n raise exc\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py\", line 193, in __call__\n response = await self.dispatch_func(request, call_next)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/app/app/main.py\", line 294, in dispatch\n return await call_next(request)\n ^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py\", line 168, in call_next\n raise app_exc from app_exc.__cause__ or app_exc.__context__\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py\", line 144, in coro\n await self.app(scope, receive_or_disconnect, send_no_error)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/cors.py\", line 87, in __call__\n await self.app(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/middleware/exceptions.py\", line 63, in __call__\n await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py\", line 53, in wrapped_app\n raise exc\n File \"/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py\", line 42, in wrapped_app\n await app(scope, receive, sender)\n File \"/opt/venv/lib/python3.12/site-packages/fastapi/middleware/asyncexitstack.py\", line 18, in __call__\n await self.app(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/routing.py\", line 716, in __call__\n await self.middleware_stack(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/routing.py\", line 736, in app\n await route.handle(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/routing.py\", line 290, in handle\n await self.app(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/fastapi/routing.py\", line 129, in app\n await wrap_app_handling_exceptions(app, request)(scope, receive, send)\n File \"/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py\", line 53, in wrapped_app\n raise exc\n File \"/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py\", line 42, in wrapped_app\n await app(scope, receive, sender)\n File \"/opt/venv/lib/python3.12/site-packages/fastapi/routing.py\", line 115, in app\n response = await f(request)\n ^^^^^^^^^^^^^^^^\n File \"/opt/venv/lib/python3.12/site-packages/fastapi/routing.py\", line 630, in app\n raw_response = await run_endpoint_function(\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/opt/venv/lib/python3.12/site-packages/fastapi/routing.py\", line 323, in run_endpoint_function\n return await dependant.call(**values)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/app/app/routers/dashboard.py\", line 192, in get_bans_by_country\n return await ban_service.bans_by_country(\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/app/app/services/ban_service.py\", line 366, in bans_by_country\n async with aiosqlite.connect(f\"file:{db_path}?mode=ro\", uri=True) as f2b_db:\n File \"/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py\", line 181, in __aenter__\n return await self\n ^^^^^^^^^^\n File \"/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py\", line 168, in _connect\n self._connection = await future\n ^^^^^^^^^^^^\n File \"/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py\", line 63, in _connection_worker_thread\n result = function()\n ^^^^^^^^^^\n File \"/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py\", line 466, in connector\n return sqlite3.connect(loc, **kwargs)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nsqlite3.OperationalError: unable to open database file"} +9110898d07c7 INFO: 10.89.0.3:43258 - "GET /api/dashboard/bans/by-country?range=24h HTTP/1.1" 500 Internal Server Error +9110898d07c7 ERROR: Exception in ASGI application +9110898d07c7 Traceback (most recent call last): +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/uvicorn/protocols/http/httptools_impl.py", line 416, in run_asgi +9110898d07c7 result = await app( # type: ignore[func-returns-value] +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/uvicorn/middleware/proxy_headers.py", line 60, in __call__ +9110898d07c7 return await self.app(scope, receive, send) +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/applications.py", line 1160, in __call__ +9110898d07c7 await super().__call__(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/applications.py", line 107, in __call__ +9110898d07c7 await self.middleware_stack(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 186, in __call__ +9110898d07c7 raise exc +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 164, in __call__ +9110898d07c7 await self.app(scope, receive, _send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 191, in __call__ +9110898d07c7 with recv_stream, send_stream, collapse_excgroups(): +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/usr/local/lib/python3.12/contextlib.py", line 158, in __exit__ +9110898d07c7 self.gen.throw(value) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/_utils.py", line 87, in collapse_excgroups +9110898d07c7 raise exc +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 193, in __call__ +9110898d07c7 response = await self.dispatch_func(request, call_next) +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/app/app/main.py", line 294, in dispatch +9110898d07c7 return await call_next(request) +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 168, in call_next +9110898d07c7 raise app_exc from app_exc.__cause__ or app_exc.__context__ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 144, in coro +9110898d07c7 await self.app(scope, receive_or_disconnect, send_no_error) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/cors.py", line 87, in __call__ +9110898d07c7 await self.app(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 63, in __call__ +9110898d07c7 await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app +9110898d07c7 raise exc +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app +9110898d07c7 await app(scope, receive, sender) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__ +9110898d07c7 await self.app(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/routing.py", line 716, in __call__ +9110898d07c7 await self.middleware_stack(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/routing.py", line 736, in app +9110898d07c7 await route.handle(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/routing.py", line 290, in handle +9110898d07c7 await self.app(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/routing.py", line 129, in app +9110898d07c7 await wrap_app_handling_exceptions(app, request)(scope, receive, send) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app +9110898d07c7 raise exc +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app +9110898d07c7 await app(scope, receive, sender) +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/routing.py", line 115, in app +9110898d07c7 response = await f(request) +9110898d07c7 ^^^^^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/routing.py", line 630, in app +9110898d07c7 raw_response = await run_endpoint_function( +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/fastapi/routing.py", line 323, in run_endpoint_function +9110898d07c7 return await dependant.call(**values) +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/app/app/routers/dashboard.py", line 192, in get_bans_by_country +9110898d07c7 return await ban_service.bans_by_country( +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 File "/app/app/services/ban_service.py", line 366, in bans_by_country +9110898d07c7 async with aiosqlite.connect(f"file:{db_path}?mode=ro", uri=True) as f2b_db: +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py", line 181, in __aenter__ +9110898d07c7 return await self +9110898d07c7 ^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py", line 168, in _connect +9110898d07c7 self._connection = await future +9110898d07c7 ^^^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py", line 63, in _connection_worker_thread +9110898d07c7 result = function() +9110898d07c7 ^^^^^^^^^^ +9110898d07c7 File "/opt/venv/lib/python3.12/site-packages/aiosqlite/core.py", line 466, in connector +9110898d07c7 return sqlite3.connect(loc, **kwargs) +9110898d07c7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +9110898d07c7 sqlite3.OperationalError: unable to open database file +9110898d07c7 INFO: 127.0.0.1:41282 - "GET /api/health HTTP/1.1" 200 OK -### Task 0.2 — Create a jail definition for the simulated service - -Create `Docker/fail2ban-dev-config/fail2ban/jail.d/bangui-sim.conf` (or add to a `.local` file). This jail must: - -- Set `enabled = true`. -- Reference the filter from Task 0.1 (`filter = bangui-sim`). -- Point `logpath` to the log file inside the container. The log file in `Docker/logs/` will be mounted into the fail2ban container; choose a mount target such as `/remotelogs/bangui/auth.log` and set `logpath` accordingly. -- Use a low `maxretry` (e.g. `3`) and a short `bantime` (e.g. `60` seconds) so testing is fast. -- Set `findtime` to something reasonable (e.g. `120` seconds). -- Set `banaction` to `iptables-allports` (or whichever action is appropriate for the container — the linuxserver/fail2ban image supports iptables). -- Optionally set `backend = auto` (pyinotify/polling). - -**Reference:** existing jails in `Docker/fail2ban-dev-config/fail2ban/jail.d/` and `jail.conf`. - ---- - -### Task 0.3 — Mount `Docker/logs/` into the fail2ban container - -Update `Docker/compose.debug.yml` so the fail2ban service mounts the host directory `./logs` into the container at a path that matches the `logpath` configured in Task 0.2 (e.g. `/remotelogs/bangui`). Add an entry like: - -```yaml -volumes: - - ./logs:/remotelogs/bangui -``` - -Make sure the path is consistent with `paths-lsio.conf` (`remote_logs_path = /remotelogs`). If you chose a different mount target, adjust the jail's `logpath` to match. - ---- - -### Task 0.4 — Create the failed-login simulation script - -Create a script at `Docker/simulate_failed_logins.sh` (bash). The script must: - -1. Accept optional arguments: number of failed attempts (default `5`), source IP to simulate (default `192.168.100.99`), and target log file path (default `./logs/auth.log`). -2. Create the log directory if it does not exist. -3. In a loop, append lines to the log file matching the exact format the filter expects, e.g.: - ``` - 2026-03-03 12:00:01 bangui-auth: authentication failure from 192.168.100.99 - ``` - Use the current timestamp for each line (via `date`). Sleep briefly between writes (e.g. 0.5 s) so the timestamps differ. -4. After all lines are written, print a summary: how many failure lines were written, which IP, and which file. -5. Mark the script as executable (`chmod +x`). - -**Reference:** the `failregex` in Task 0.1 — the log format must match exactly. - ---- - -### Task 0.5 — Create a verification / status-check script - -Create `Docker/check_ban_status.sh` that: - -1. Runs `docker exec bangui-fail2ban-dev fail2ban-client status bangui-sim` to show the jail status (current failures, banned IPs). -2. Runs `docker exec bangui-fail2ban-dev fail2ban-client get bangui-sim banip --with-time` (or equivalent) to list banned IPs with timestamps. -3. Accepts an optional `--unban ` flag that calls `docker exec bangui-fail2ban-dev fail2ban-client set bangui-sim unbanip ` so the tester can quickly reset. -4. Mark the script as executable. - ---- - -### Task 0.6 — Add an `ignoreip` safeguard - -In the jail created in Task 0.2, add `ignoreip = 127.0.0.0/8 ::1` (and optionally the Docker bridge subnet) so that the host machine and localhost are never accidentally banned during development. - ---- - -### Task 0.7 — End-to-end manual test & documentation - -Write a brief section in `Docker/fail2ban-dev-config/README.md` that documents: - -1. **Prerequisites:** Docker / Podman running, compose available. -2. **Quick start:** - - `docker compose -f Docker/compose.debug.yml up -d fail2ban` (start only the fail2ban service). - - `bash Docker/simulate_failed_logins.sh` (run the simulation). - - `bash Docker/check_ban_status.sh` (verify the IP was banned). - - `bash Docker/check_ban_status.sh --unban 192.168.100.99` (unban and re-test). -3. **Configuration reference:** where the filter, jail, and log file live; how to change `maxretry`, `bantime`, etc. -4. **Troubleshooting:** common issues (log file not mounted, filter regex mismatch, container not seeing file changes — suggest `backend = polling` if inotify doesn't work inside Docker). - ---- - -### Task 0.8 — (Optional) Add a Makefile target - -Add a `dev-ban-test` target to the top-level `Makefile` that chains the workflow: - -```makefile -dev-ban-test: - docker compose -f Docker/compose.debug.yml up -d fail2ban - sleep 5 - bash Docker/simulate_failed_logins.sh - sleep 3 - bash Docker/check_ban_status.sh -``` - -This lets a developer (or CI) run `make dev-ban-test` for a one-command smoke test of the ban pipeline.