A monitoring and security application that automatically protects your web resources by analyzing access logs from Pangolin API and automatically banning suspicious IPs based on configurable rules.
- Automated Log Monitoring: Continuously polls Pangolin API for new access logs
- Rule-Based IP Blocking: Define custom rules to automatically ban IPs based on access patterns
- Web Dashboard: User-friendly web interface built with Blazor and MudBlazor
- Real-time Monitoring: View active bans, ban history, and system statistics
- Flexible Configuration:
- Global rules that apply to all resources (with optional exclusions)
- Resource-specific rules for targeted protection
- Pattern matching with regex or exact string matching
- Automatic Ban Management: Temporary bans with configurable durations
- Docker Support: Easy deployment with Docker and Docker Compose
- SQLite Database: Lightweight data persistence for configuration and ban history
- Log Monitoring: The background worker continuously polls the Pangolin API for new access logs
- Rule Evaluation: Each log entry is evaluated against active watchdog rules
- Automatic Banning: When a log matches a rule, the IP is automatically banned via Pangolin API. The service adds new block IP rules with last + 1 priority (see Priority Management with MinPriority and MaxPriority below)
- Ban Tracking: All bans are recorded in the local database with expiration times
- Dashboard Updates: The web dashboard displays real-time statistics and ban history
- Pangolin Integration API enabled
- Refer to Pangolin documentation: https://docs.pangolin.net/manage/integration-api
- For Community Edition: https://docs.pangolin.net/self-host/advanced/integration-api
- Pangolin Root API Key (created in "server admin" panel, org key won't work) with appropriate permissions
- List organizations
- Get organizations
- List organizations domains
- Get site
- List sites
- Get resource
- List resources
- Create resource rule
- Delete resource rule
- List resource rules
- (Logs) Allow all
- Docker
- Docker Compose
- .NET 9.0 SDK
- SQLite (included with .NET)
The application is available as a pre-built Docker image on Docker Hub: https://hub.docker.com/r/kacper1263/pangolin-watchdog
Download current compose.yaml file and change env variables (make sure to set latest image version)
docker compose up -dOpen your browser and navigate to: http://localhost:8855
Default login password: watchdogadmin (change it via ADMIN_PASSWORD environment variable)
docker run -d \
--name pangolin-watchdog \
--restart unless-stopped \
-p 8855:8080 \
-v ./data:/app/data \
-e ADMIN_PASSWORD=watchdogadmin \
-e TZ=Europe/Warsaw \
kacper1263/pangolin-watchdog:v1.5.0change v1.5.0 to current version
- Log in to the web dashboard
- Navigate to Configuration page
- Configure Pangolin API Settings:
- API URL: Your Pangolin API endpoint (e.g.,
https://api.pangolin.example.com/v1) - Organization ID: Your Pangolin organization ID (name - visible in top left corner in your Pangolin dashboard)
- API Token: Your Pangolin API authentication token
- Log Polling Interval: How often to check for new logs (in seconds)
- Ban Cleanup Interval: How often to check for expired bans (in minutes)
- Default Ban Duration: Default duration for IP bans (in minutes)
- API URL: Your Pangolin API endpoint (e.g.,
- Sync your resources list via "refresh resources list" button
Rules define which access patterns should trigger automatic IP bans.
Rule Types:
- Global Rules: Apply to all resources (with optional exclusions)
- Resource-Specific Rules: Target specific resources
Pattern Matching:
- Exact Match: Match exact URL paths
- Regex: Use regular expressions for flexible pattern matching
Example Rules:
- Block access to admin panels: Pattern
/adminor/wp-admin - Block SQL injection attempts: Regex
.*(\bunion\b|\bselect\b).* - Block specific file types: Regex
.*\.(php|asp|jsp)$
data folder before updating. First stop docker container and after that backup your folder
If you are using docker compose, just bump version number and use docker compose up -d (docker will automaticly pull new image and recreate your container)
If you use global "allow" rules in Pangolin (e.g., Allow Country X with high priority), the default strategy of always creating new block rules at last + 1 can conflict with those allow rules. To handle this, watchdog rules support optional MinPriority and MaxPriority settings that control where new block rules will be created.
| MinPriority | MaxPriority | Behavior |
|---|---|---|
| ❌ Not set | ❌ Not set | Legacy behavior: Always adds new rules at the end (Max + 1). Does not fill gaps. |
| ❌ Not set | ✅ Set (e.g., 100) |
Legacy with limit: Adds at the end until reaching the limit. Rule disabled when limit reached. |
✅ Set (e.g., 10) |
✅ Set (e.g., 100) |
Smart gap filling: Fills gaps in range [10, 100) first, then disables rule when no space left. |
✅ Set (e.g., 30000) |
❌ Not set | Smart with fallback: Searches for gaps in range [30000, 40000) (MinPriority + 10000), then adds at the end if no gaps found. |
Scenario:
- You have a global "allow" rule for country X at priority
100in Pangolin - You want watchdog to use priorities
10-99for ban rules - Existing Pangolin rules:
[1, 2, ..., 9, 90, 91, ..., 99, 100, 101, 102]
Configuration:
MinPriority: 10
MaxPriority: 100
Result:
- ban → Priority
10(fills gap) - ban → Priority
11(fills gap) - ...
- ban → Priority
81(fills gap) - Priority 11 gets freed up (expired/deleted)
- ban → Priority
11(fills freed gap) - ban → Priority
82(fills gap) - ...
- When all slots
10-99are occupied → ❌ Rule disabled, problem notification created
Why this is useful:
- Prevents your watchdog from creating rules beyond priority 100
- Ensures allow rules at priority ≥100 always take precedence
- Efficiently fills gaps left by expired/deleted bans
Scenario:
- You want watchdog to start at priority
30000 - You don't have strict upper limits
Configuration:
MinPriority: 30000
MaxPriority: (not set)
Result:
- System searches for gaps in range
[30000, 40000)(performance optimization) - If gaps found → fills them
- If no gaps in search range → adds at
Max + 1as usual - Example: If priorities
[30005, 30006, 30007]are taken, next ban uses30000, then30001, etc.
Configuration:
MinPriority: (not set)
MaxPriority: (not set)
Result:
- Always adds new rules at
last + 1 - Gaps are never filled
- Example: If you have
[1, 2, 3, 90], next ban is91, not4
- Per-Resource Evaluation: Priority management is evaluated independently for each resource in Pangolin
- Gap Detection: The system only fills gaps when
MinPriorityis set - Performance: When using
MinPrioritywithoutMaxPriority, gap search is limited to a range of 10,000 priorities to prevent performance issues - Automatic Disable: When
MaxPriorityis set and reached, the rule automatically disables and creates a problem notification
- Framework: .NET 9.0
- UI: Blazor Server with MudBlazor components
- Database: SQLite with Entity Framework Core
- Authentication: Cookie-based authentication
- Background Processing: Hosted Services (IHostedService)
- Containerization: Docker
- Authentication Required: All pages except login require authentication
- Secure API Integration: Bearer token authentication with Pangolin API
- Password Protection: Admin access protected by environment variable password
- Cookie-based Sessions: 7-day session expiration
Set the ADMIN_PASSWORD environment variable:
Docker:
environment:
- ADMIN_PASSWORD=your_secure_passwordLocal Development:
export ADMIN_PASSWORD=your_secure_password
dotnet run- Docker:
./data/watchdog.db - Local:
<app_directory>/data/watchdog.db
Application logs are written to the console with the following levels:
- INFO: General application events
- WARNING: Ban events and important notices
- ERROR: API failures and critical errors
Configure logging in appsettings.json.
git clone https://github.com/Kacper1263/pangolin-watchdog.git
cd pangolin-watchdogdotnet restore
dotnet runThe application will start and display the listening address (typically http://localhost:5000).
docker build -t pangolin-watchdog:custom .Then update the image field in docker-compose.yml to use your custom image.