A containerized service that monitors UniFi network logs and delivers plain-English security reports via email or file.
- Log Collection: Fetches events and alarms from UniFi Controller API with WebSocket support for UniFi 10.x+
- Smart Analysis: Categorizes issues by severity (low, medium, severe) with deduplication
- Plain English Reports: Generates human-readable explanations with remediation steps
- IPS/IDS Analysis: Translates Suricata signatures into plain English with threat context (includes MongoDB fallback for UDM Pro)
- Cybersecure Integration: Identifies threats detected by Proofpoint ET PRO enhanced signatures
- Device Health Monitoring: Tracks temperature, CPU, memory, and PoE status across devices
- Cloudflare Integration: Optional WAF events, DNS analytics, and tunnel status monitoring
- Flexible Delivery: Email (BCC recipients, severity-aware subjects) or file output
- Scheduled Execution: Cron expressions, presets (daily_8am, weekly_monday_8am), or one-shot mode
- Docker Ready: Multi-stage build with health checks and non-root user
The scanner generates HTML email reports like this:
|
Executive Summary
π΄ SEVERE: IPS Alert - Malware Communication Detected Blocked connection attempt to known malware command & control server from device 192.168.1.105. Signature: ET MALWARE Win32/Emotet CnC Activity
π΄ SEVERE: Access Point Temperature Critical U6-Pro (Office) temperature is 92Β°C, exceeding critical threshold of 85Β°C.
π MEDIUM: Client Roaming Excessively iPhone-John roamed between access points 8 times in the last hour, indicating possible coverage gaps or interference.
Security Threat Summary β 4 blocked threats from 3 unique IPs
Cloudflare Security β WAF blocked 12 requests, DNS filtered 847 queries
Tunnel Status
Device Health Summary β 1 critical, 2 warnings across 8 devices
Generated by UniFi Scanner v0.6.1b
|
# Create secrets
mkdir -p secrets
echo "your-unifi-password" > secrets/unifi_password.txt
echo "your-smtp-password" > secrets/smtp_password.txt
# Configure environment
cat > .env << 'ENVEOF'
UNIFI_HOST=192.168.1.1
UNIFI_USERNAME=admin
UNIFI_SCHEDULE_PRESET=daily_8am
UNIFI_SCHEDULE_TIMEZONE=America/New_York
ENVEOF
# Run
docker-compose up -ddocker pull ghcr.io/trek-e/unifi-security-report:latestpip install -e .
unifi-scanner --helpAll settings use the UNIFI_ prefix as environment variables. Configuration is loaded in this order (highest priority first):
- Environment variables (
UNIFI_*) - Docker secrets (
UNIFI_*_FILEpointing to a file) - YAML config file (set
CONFIG_PATH=/path/to/config.yml) - Default values
| Variable | Description | Default |
|---|---|---|
UNIFI_HOST |
Controller hostname or IP address | Required |
UNIFI_USERNAME |
Admin username (must be a local account, not cloud SSO) | Required |
UNIFI_PASSWORD |
Admin password (or use UNIFI_PASSWORD_FILE for Docker secrets) |
Required |
UNIFI_PORT |
Controller port | Auto-detect (tries 443, 8443, 11443) |
UNIFI_VERIFY_SSL |
Verify SSL certificates (set false for self-signed certs) |
true |
UNIFI_SITE |
UniFi site name | Auto-detect |
UNIFI_CONNECT_TIMEOUT |
Connection timeout in seconds | 10 |
UNIFI_MAX_RETRIES |
Retry attempts on connection failure | 5 |
| Variable | Description | Default |
|---|---|---|
UNIFI_SCHEDULE_PRESET |
Preset: daily_8am, daily_6pm, weekly_monday_8am, weekly_friday_5pm |
None |
UNIFI_SCHEDULE_CRON |
Custom cron expression (5-field: min hour day month weekday) |
None |
UNIFI_SCHEDULE_TIMEZONE |
Timezone for schedule (IANA format) | UTC |
UNIFI_POLL_INTERVAL |
Polling interval in seconds (used between report cycles) | 300 |
UNIFI_INITIAL_LOOKBACK_HOURS |
Hours of history to process on first run (1-720) | 24 |
| Variable | Description | Default |
|---|---|---|
UNIFI_EMAIL_ENABLED |
Enable email delivery | false |
UNIFI_SMTP_HOST |
SMTP server hostname | Required when email enabled |
UNIFI_SMTP_PORT |
SMTP port (587 for STARTTLS, 465 for implicit TLS) |
587 |
UNIFI_SMTP_USER |
SMTP auth username | None |
UNIFI_SMTP_PASSWORD |
SMTP auth password | None |
UNIFI_SMTP_USE_TLS |
Enable TLS encryption | true |
UNIFI_EMAIL_FROM |
Sender address | unifi-scanner@localhost |
UNIFI_EMAIL_RECIPIENTS |
Comma-separated recipient addresses (all sent via BCC) | None |
UNIFI_TIMEZONE |
Timezone for report timestamps and email subjects | UTC |
Example β Gmail with app password:
UNIFI_EMAIL_ENABLED: "true"
UNIFI_SMTP_HOST: smtp.gmail.com
UNIFI_SMTP_PORT: "587"
UNIFI_SMTP_USER: you@gmail.com
UNIFI_SMTP_PASSWORD: your-app-password
UNIFI_EMAIL_FROM: you@gmail.com
UNIFI_EMAIL_RECIPIENTS: admin@example.com,backup@example.comExample β Local relay (no auth):
UNIFI_EMAIL_ENABLED: "true"
UNIFI_SMTP_HOST: 192.168.1.50
UNIFI_SMTP_PORT: "25"
UNIFI_SMTP_USE_TLS: "false"
UNIFI_EMAIL_FROM: scanner@home.local
UNIFI_EMAIL_RECIPIENTS: you@example.com| Variable | Description | Default |
|---|---|---|
UNIFI_FILE_ENABLED |
Enable file output | false |
UNIFI_FILE_OUTPUT_DIR |
Directory for report files | Required when file enabled |
UNIFI_FILE_FORMAT |
Format: html, text, or both |
both |
UNIFI_FILE_RETENTION_DAYS |
Days to retain report files (0 = keep forever) | 30 |
The UniFi Network API does not expose IPS/threat events. To collect blocked threat data, the scanner can SSH into UDM Pro devices and query MongoDB directly. This requires SSH key authentication (password auth is disabled on UDM Pro).
| Variable | Description | Default |
|---|---|---|
UNIFI_SSH_ENABLED |
Enable SSH fallback for logs/IPS | true |
UNIFI_SSH_KEY_PATH |
Path to SSH private key file | None |
UNIFI_SSH_KEY_PASSPHRASE |
Passphrase for encrypted key | None |
UNIFI_SSH_USERNAME |
SSH username | root |
UNIFI_SSH_PASSWORD |
SSH password (if not using key auth) | None |
UNIFI_SSH_TIMEOUT |
SSH command timeout in seconds (5-300) | 30 |
Setup SSH key authentication:
# Generate key pair (if needed)
ssh-keygen -t ed25519 -f ~/.ssh/unifi_key
# Copy public key to UDM Pro
cat ~/.ssh/unifi_key.pub | ssh root@192.168.1.1 "cat >> ~/.ssh/authorized_keys"
# Configure scanner
export UNIFI_SSH_KEY_PATH=~/.ssh/unifi_keyNote: MongoDB alerts contain limited data (source IP, destination IP, severity, timestamp). Signature names and categories shown in UniFi's UI are enriched from encrypted rule databases and are not available via MongoDB.
| Variable | Description | Default |
|---|---|---|
UNIFI_WEBSOCKET_ENABLED |
Enable WebSocket for real-time WiFi events | true |
UNIFI_WEBSOCKET_BUFFER_SIZE |
Max events to buffer between reports (100-100000) | 10000 |
WebSocket is required for UniFi Network 10.x+ where the
/stat/eventREST endpoint was deprecated.
| Variable | Description | Default |
|---|---|---|
UNIFI_LOG_LEVEL |
Log level: DEBUG, INFO, WARNING, ERROR |
INFO |
UNIFI_LOG_FORMAT |
Output format: json (production) or text (development) |
json |
| Variable | Description | Default |
|---|---|---|
UNIFI_CLOUDFLARE_API_TOKEN |
Cloudflare API token for WAF, DNS, and tunnel data | None |
UNIFI_CLOUDFLARE_ACCOUNT_ID |
Cloudflare account ID (auto-discovered from zones if not set) | None |
Cybersecure: No configuration needed. ET PRO signatures (SID 2800000-2899999) are automatically detected when your UniFi device has an active Cybersecure subscription.
Any setting can be loaded from a file using the _FILE suffix pattern:
environment:
UNIFI_PASSWORD_FILE: /run/secrets/unifi_password
UNIFI_SMTP_PASSWORD_FILE: /run/secrets/smtp_password
secrets:
unifi_password:
file: ./secrets/unifi_password.txt
smtp_password:
file: ./secrets/smtp_password.txtSet CONFIG_PATH to load settings from a YAML file instead of environment variables:
# config.yml
host: 192.168.1.1
username: admin
password: your-password
verify_ssl: false
schedule_preset: daily_8am
schedule_timezone: America/New_York
email_enabled: true
smtp_host: smtp.gmail.com
smtp_port: 587
smtp_user: you@gmail.com
smtp_password: your-app-password
email_from: you@gmail.com
email_recipients: admin@example.com
file_enabled: true
file_output_dir: /app/reportsdocker run -v ./config.yml:/app/config.yml -e CONFIG_PATH=/app/config.yml ghcr.io/trek-e/unifi-security-reportEnvironment variables override YAML values when both are set.
| Version | Phase | Features |
|---|---|---|
| v0.6.1b | - | API call efficiency: eliminate duplicate IPS/integration calls, IPS endpoint caching |
| v0.6.0b | - | MongoDB IPS report improvements (IP-based grouping, better display), Docker healthcheck fix |
| v0.5.5b | 14 | MongoDB IPS collection via SSH (workaround for missing API) |
| v0.4.0a1 | 12 | Cybersecure integration (ET PRO signature detection, badges) |
| v0.3.15a1 | 13 | WebSocket support for UniFi Network 10.x+ |
| v0.3.5a1 | 11 | Cloudflare integration (WAF, DNS analytics, tunnels) |
| v0.3.4a1 | 10 | Integration infrastructure for external services |
| v0.3.3a1 | 9 | Device health monitoring (temperature, CPU, memory, PoE) |
| v0.3.2a1 | 8 | Enhanced IPS/IDS analysis with remediation guidance |
| v0.3.1a1 | 7 | Extended wireless analysis (roaming, DFS, RSSI) |
| v0.3.0a1 | 6 | State persistence to prevent duplicate reports |
| v0.2.0a1 | 1-5 | Production-ready containerized service |
MIT