https://github.com/btholt/discord-unifi
Docker container to accept local webhooks from Unifi Protect and send them to Discord
https://github.com/btholt/discord-unifi
Last synced: 10 months ago
JSON representation
Docker container to accept local webhooks from Unifi Protect and send them to Discord
- Host: GitHub
- URL: https://github.com/btholt/discord-unifi
- Owner: btholt
- Created: 2025-07-25T20:28:41.000Z (11 months ago)
- Default Branch: main
- Last Pushed: 2025-07-28T21:18:30.000Z (11 months ago)
- Last Synced: 2025-08-28T15:54:33.718Z (10 months ago)
- Language: JavaScript
- Size: 60.5 KB
- Stars: 5
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Unifi Protect to Discord Webhook Bridge
A lightweight Node.js server that receives webhook posts from Unifi Protect Alarm Manager and forwards them to a Discord webhook. The entire application is containerized using Docker for easy deployment.
## Features
- 🚨 **Real-time Alerts**: Receive and forward Unifi Protect events to Discord
- 🔒 **Security**: Rate limiting, request validation, and data sanitization
- 📊 **Structured Logging**: Comprehensive logging with request tracing
- 🐳 **Docker Ready**: Complete containerization with health checks
- ⚡ **Lightweight**: Optimized for minimal resource usage
- 🔧 **Configurable**: Environment-based configuration
## Quick Start
### Option 1: Using Published Docker Image (Recommended)
The latest Docker image is automatically published to GitHub Container Registry on each release.
```bash
# Pull the latest image
docker pull ghcr.io/btholt/discord-unifi:latest
# Run with environment variables
docker run -d \
--name unifi-discord-bridge \
-p 3000:3000 \
-e DISCORD_WEBHOOK_URL="https://discord.com/api/webhooks/YOUR_WEBHOOK_URL_HERE" \
ghcr.io/btholt/discord-unifi:latest
```
### Option 2: Local Development
#### Prerequisites
- Docker and Docker Compose
- Discord webhook URL
- Unifi Protect system with webhook capability
#### 1. Clone and Setup
```bash
git clone
cd unifi-discord-bridge
cp env.example .env
```
#### 2. Configure Environment
Edit `.env` file with your Discord webhook URL:
```bash
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/YOUR_WEBHOOK_URL_HERE
```
#### 3. Run with Docker Compose
```bash
docker-compose up -d
```
The service will be available at `http://localhost:3000`
## Configuration
### Environment Variables
| Variable | Default | Description |
| --------------------- | ---------------- | -------------------------------------------- |
| `PORT` | `3000` | Server port |
| `DISCORD_WEBHOOK_URL` | **Required** | Discord webhook URL |
| `WEBHOOK_PATH` | `/webhook/unifi` | Endpoint path for Unifi webhooks |
| `LOG_LEVEL` | `info` | Logging level (error, warn, info, debug) |
| `WEBHOOK_SECRET` | - | Optional secret for webhook validation |
| `RATE_LIMIT_WINDOW` | `15` | Rate limiting window in minutes |
| `RATE_LIMIT_MAX` | `100` | Max requests per window |
| `PROTECT_API_KEY` | - | Unifi Protect API key for thumbnail fetching |
| `PROTECT_HOST` | `192.168.1.80` | Unifi Protect host address |
### Discord Webhook Setup
1. Go to your Discord server settings
2. Navigate to Integrations → Webhooks
3. Create a new webhook
4. Copy the webhook URL
5. Set it as `DISCORD_WEBHOOK_URL` in your environment
## API Endpoints
### Webhook Endpoint
- **POST** `/webhook/unifi` - Receive Unifi Protect webhooks
- **GET** `/webhook/unifi/health` - Health check endpoint
### Root Endpoint
- **GET** `/` - Service information
## Unifi Protect Webhook Format
The service expects JSON payloads from Unifi Protect with the following structure:
```json
{
"alarm": {
"name": "Motion Detected",
"sources": [],
"conditions": [
{
"condition": {
"type": "is",
"source": "motion"
}
}
],
"triggers": [
{
"key": "motion",
"device": "74ACB99F4E24"
}
]
},
"timestamp": 1722526793954
}
```
### Supported Event Types
The service automatically detects event types from the `alarm.conditions[].condition.source` field:
- `motion` - Motion detection events
- `alert` - General alerts
- `person` - Person detection
- `vehicle` - Vehicle detection
- `package` - Package detection
- `face_known` - Known person face recognition
- `face_unknown` - Unknown person face recognition
- `unknown` - Fallback for unrecognized event types
## Thumbnail Support
When `PROTECT_API_KEY` is configured, the service automatically:
1. **Fetches Animated Thumbnails**: Downloads GIF thumbnails from Unifi Protect
2. **Uploads to Discord**: Attaches thumbnails to Discord messages
3. **Fallback Gracefully**: Continues without thumbnails if API key is missing
### Thumbnail Configuration
```bash
# Add to your .env file
PROTECT_API_KEY=your_protect_api_key_here
PROTECT_HOST=192.168.1.80 # Optional, defaults to 192.168.1.80
```
### Thumbnail URL Format
The service fetches thumbnails using:
```
http://{PROTECT_HOST}/proxy/protect/api/events/{eventId}/animated-thumbnail?keyFrameOnly=true&speedup=10
```
## Discord Message Format
Events are transformed into rich Discord embeds with:
- Event-specific emojis and colors
- Camera information
- Timestamps
- Structured fields
Example Discord message:
```
🚨 **Motion Detected**
Unifi Protect Alert
Motion detected on camera: Front Door
Camera: Front Door | Event Type: Motion Detection
```
## Development
### Local Development
```bash
# Install dependencies
npm install
# Start development server
npm run dev
```
### Building Docker Image
```bash
# Build image
docker build -t unifi-discord-bridge .
# Run container
docker run -p 3000:3000 -e DISCORD_WEBHOOK_URL=your_url unifi-discord-bridge
```
## Logging
The application uses structured logging with Winston. Log levels:
- `error` - Application errors
- `warn` - Warning messages
- `info` - General information
- `debug` - Detailed debugging information
Each request gets a unique request ID for tracing.
## Security Features
- **Rate Limiting**: Prevents abuse with configurable limits
- **Request Validation**: Validates incoming webhook data
- **Data Sanitization**: Removes sensitive information
- **Helmet**: Security headers
- **CORS**: Cross-origin resource sharing protection
- **Non-root User**: Docker container runs as non-root user
## Health Checks
The application includes health check endpoints for container orchestration:
```bash
curl http://localhost:3000/webhook/unifi/health
```
Response:
```json
{
"status": "healthy",
"timestamp": "2025-01-15T10:30:00.000Z",
"service": "unifi-discord-bridge",
"version": "1.0.0"
}
```
## Troubleshooting
### Common Issues
1. **Discord webhook not working**
- Verify the webhook URL is correct
- Check Discord server permissions
- Ensure the webhook is not disabled
2. **Rate limiting errors**
- Adjust `RATE_LIMIT_MAX` and `RATE_LIMIT_WINDOW` values
- Check if multiple instances are running
3. **Container health check failing**
- Verify the service is running on the correct port
- Check container logs for errors
### Logs
View application logs:
```bash
# Docker Compose
docker-compose logs -f
# Docker container
docker logs unifi-discord-bridge
```
## GitHub Actions & Releases
This project uses GitHub Actions for automated CI/CD:
### 🚀 Automated Releases
When you create a new release tag (e.g., `v1.0.1`), the workflow will:
1. **Build Docker Image** - Multi-platform build (AMD64, ARM64)
2. **Push to GHCR** - Publish to GitHub Container Registry
3. **Create Release** - Generate release notes with usage instructions
4. **Security Scan** - Run vulnerability scanning with Trivy
### 📋 Creating a Release
```bash
# Create and push a new tag
git tag v1.0.1
git push origin v1.0.1
```
Or use the GitHub UI to create a release.
### 🔄 CI/CD Pipeline
- **Pull Requests**: Build and test on every PR
- **Main Branch**: Build and push to GHCR on every push
- **Security**: Automated vulnerability scanning
- **Testing**: Docker image validation
## Deployment
### Production Deployment
#### Option 1: Using Published Image (Recommended)
```bash
# Pull the latest release
docker pull ghcr.io/btholt/discord-unifi:latest
# Run in production
docker run -d \
--name unifi-discord-bridge \
--restart unless-stopped \
-p 3000:3000 \
-e DISCORD_WEBHOOK_URL="your_discord_webhook_url" \
-e LOG_LEVEL="info" \
ghcr.io/btholt/discord-unifi:latest
```
#### Option 2: Local Build
1. **Environment Setup**
```bash
cp env.example .env
# Edit .env with production values
```
2. **Docker Compose**
```bash
docker-compose -f docker-compose.yml up -d
```
3. **Reverse Proxy** (Optional)
Configure nginx or similar to proxy requests to the container.
### Resource Limits
For production deployments, consider setting resource limits:
```yaml
services:
unifi-discord-bridge:
deploy:
resources:
limits:
memory: 256M
cpus: "0.5"
```
## Contributing
1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests if applicable
5. Submit a pull request
## License
MIT License - see LICENSE file for details.
## Support
For issues and questions:
- Check the troubleshooting section
- Review application logs
- Open an issue on GitHub