You've already forked caddy-opnsense-blocker
98 lines
3.0 KiB
Markdown
98 lines
3.0 KiB
Markdown
# caddy-opnsense-blocker
|
|
|
|
`caddy-opnsense-blocker` is a local-first daemon that ingests Caddy access logs in their default JSON format, evaluates suspicious requests, keeps persistent local state in SQLite, provides a lightweight web UI for review, and blocks or unblocks IP addresses through an OPNsense alias.
|
|
|
|
## Features
|
|
|
|
- Real-time ingestion of multiple Caddy JSON log files.
|
|
- One heuristic profile per log source.
|
|
- Persistent local state in SQLite.
|
|
- Local-only web UI for reviewing events and IPs.
|
|
- Manual block, unblock, and override reset actions.
|
|
- OPNsense alias backend with automatic alias creation.
|
|
- Concurrent polling across multiple log files.
|
|
|
|
## Current scope
|
|
|
|
This first version is intentionally strong on ingestion, persistence, UI, and OPNsense integration.
|
|
The decision engine is deliberately simple and deterministic for now:
|
|
|
|
- suspicious path prefixes
|
|
- unexpected `POST` requests
|
|
- `.php` path detection
|
|
- explicit known-agent allow/deny rules
|
|
- excluded CIDR ranges
|
|
- manual overrides
|
|
|
|
This keeps the application usable immediately while leaving room for a more advanced network-intelligence engine later.
|
|
|
|
## Architecture
|
|
|
|
- `internal/caddylog`: parses default Caddy JSON access logs
|
|
- `internal/engine`: evaluates requests against a profile
|
|
- `internal/store`: persists events, IP state, manual decisions, backend actions, and source offsets
|
|
- `internal/opnsense`: manages the target OPNsense alias through its API
|
|
- `internal/service`: runs concurrent log followers and applies automatic decisions
|
|
- `internal/web`: serves the local review UI and JSON API
|
|
|
|
## Quick start
|
|
|
|
1. Generate or provision OPNsense API credentials.
|
|
2. Copy `config.example.yaml` to `config.yaml` and adapt it.
|
|
3. Start the daemon:
|
|
|
|
```bash
|
|
CGO_ENABLED=0 go run ./cmd/caddy-opnsense-blocker -config ./config.yaml
|
|
```
|
|
|
|
4. Open the local UI on the configured address, for example `http://127.0.0.1:9080`.
|
|
|
|
## Example configuration
|
|
|
|
See `config.example.yaml`.
|
|
|
|
Important points:
|
|
|
|
- Each source points to one Caddy log file.
|
|
- Each source references exactly one profile.
|
|
- `initial_position: end` means “start following new lines only” on first boot.
|
|
- The web UI should stay bound to a local address such as `127.0.0.1:9080`.
|
|
|
|
## Web UI and API
|
|
|
|
The web UI is intentionally small and server-rendered.
|
|
It refreshes through lightweight JSON polling and exposes these endpoints:
|
|
|
|
- `GET /healthz`
|
|
- `GET /api/overview`
|
|
- `GET /api/events`
|
|
- `GET /api/ips`
|
|
- `GET /api/ips/{ip}`
|
|
- `POST /api/ips/{ip}/block`
|
|
- `POST /api/ips/{ip}/unblock`
|
|
- `POST /api/ips/{ip}/reset`
|
|
|
|
## Development
|
|
|
|
Run the test suite:
|
|
|
|
```bash
|
|
CGO_ENABLED=0 go test ./...
|
|
```
|
|
|
|
Build the daemon:
|
|
|
|
```bash
|
|
CGO_ENABLED=0 go build ./cmd/caddy-opnsense-blocker
|
|
```
|
|
|
|
`CGO_ENABLED=0` is useful on systems without a C toolchain. The application itself only relies on pure-Go dependencies.
|
|
|
|
## Roadmap
|
|
|
|
- richer decision engine
|
|
- asynchronous DNS / RDAP / ASN enrichment
|
|
- richer review filters in the UI
|
|
- alternative blocking backends besides OPNsense
|
|
- direct streaming ingestion targets in addition to file polling
|