Files
ntfy-discord/README.md
Billy D. f97ad0e7cb
Some checks failed
Build and Push / build (push) Failing after 4m36s
Build and Push / test (push) Has been cancelled
feat: implement ntfy-discord bridge in Go
- SSE subscription to ntfy with auto-reconnect
- Discord webhook integration with embed formatting
- Priority to color mapping, tag to emoji conversion
- Native HashiCorp Vault support (Kubernetes + token auth)
- Hot reload secrets via fsnotify or Vault polling
- Prometheus metrics (/metrics endpoint)
- Health/ready endpoints for Kubernetes probes
- Comprehensive unit tests and fuzz tests
- Multi-stage Docker build (~10MB scratch image)
- CI/CD pipeline for Gitea Actions
2026-02-02 18:13:55 -05:00

102 lines
3.2 KiB
Markdown

# ntfy-discord
A lightweight Go bridge that forwards [ntfy](https://ntfy.sh/) notifications to Discord webhooks.
## Features
- **SSE Subscription**: Real-time message streaming from ntfy
- **Auto-reconnection**: Exponential backoff on connection failures
- **Hot Reload**: Watches mounted secrets for changes (no pod restart needed)
- **Native Vault Support**: Direct HashiCorp Vault integration with Kubernetes auth
- **Message Transformation**: Converts ntfy format to Discord embeds
- **Priority Mapping**: ntfy priorities → Discord embed colors
- **Tag → Emoji**: Converts common ntfy tags to Discord-friendly emojis
- **Prometheus Metrics**: `/metrics` endpoint for observability
- **Tiny Footprint**: ~10MB image, 16-32MB memory
## Configuration
### Core Settings
| Environment Variable | Description | Default |
|---------------------|-------------|---------|
| `NTFY_URL` | ntfy server URL | `http://ntfy.observability.svc.cluster.local` |
| `NTFY_TOPICS` | Comma-separated topics to subscribe to | (required) |
| `HTTP_PORT` | Port for health/metrics endpoints | `8080` |
| `LOG_LEVEL` | Log level (`info` or `debug`) | `info` |
### Secret Sources (Priority Order)
The bridge loads the Discord webhook URL from the first available source:
1. **Vault** (if `VAULT_ENABLED=true`)
2. **Mounted Secret** (if `SECRETS_PATH` is set)
3. **Environment Variable** (`DISCORD_WEBHOOK_URL`)
### Vault Configuration
| Environment Variable | Description | Default |
|---------------------|-------------|---------|
| `VAULT_ENABLED` | Enable Vault integration | `false` |
| `VAULT_ADDR` | Vault server address | `http://vault.vault.svc.cluster.local:8200` |
| `VAULT_AUTH_METHOD` | Auth method: `kubernetes` or `token` | `kubernetes` |
| `VAULT_ROLE` | Vault role for Kubernetes auth | `ntfy-discord` |
| `VAULT_MOUNT_PATH` | Secrets engine mount path | `secret` |
| `VAULT_SECRET_PATH` | Path within the mount | `ntfy-discord` |
| `VAULT_TOKEN_PATH` | SA token path (for K8s auth) | `/var/run/secrets/kubernetes.io/serviceaccount/token` |
Expected Vault secret structure (KV v2):
```
secret/data/ntfy-discord
├── webhook-url: https://discord.com/api/webhooks/...
```
### File-Based Secrets
| Environment Variable | Description | Default |
|---------------------|-------------|---------|
| `SECRETS_PATH` | Path to mounted secrets directory | (optional) |
| `DISCORD_WEBHOOK_URL` | Discord webhook URL (fallback) | (optional) |
When using `SECRETS_PATH`, the bridge expects:
- `webhook-url` - Discord webhook URL
The bridge watches for file changes and reloads automatically.
## Endpoints
| Path | Description |
|------|-------------|
| `/health` | Health check (webhook configured?) |
| `/ready` | Readiness check (connected to ntfy?) |
| `/metrics` | Prometheus metrics |
## Priority → Color Mapping
| Priority | Name | Color |
|----------|------|-------|
| 5 | Max/Urgent | 🔴 Red |
| 4 | High | 🟠 Orange |
| 3 | Default | 🔵 Blue |
| 2 | Low | ⚪ Gray |
| 1 | Min | ⚪ Light Gray |
## Building
```bash
# Build binary
go build -o ntfy-discord .
# Build container
docker build -t ntfy-discord .
```
## Kubernetes Deployment
See [homelab-k8s2](https://github.com/Billy-Davies-2/homelab-k8s2) for deployment manifests.
## License
MIT