- Go 92.3%
- Makefile 5.4%
- Dockerfile 2.3%
|
All checks were successful
client_golang pre-registers Go and process collectors on DefaultRegisterer; skip re-registering them in production and cover the nil-registerer path. Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|---|---|---|
| .github/workflows | ||
| config | ||
| .gitignore | ||
| .goreleaser.yml | ||
| AGENTS.md | ||
| config.go | ||
| Containerfile | ||
| Containerfile.dev | ||
| docker-compose.yml | ||
| go.mod | ||
| go.sum | ||
| logger.go | ||
| main.go | ||
| main_test.go | ||
| Makefile | ||
| metrics.go | ||
| metrics_test.go | ||
| proxy.go | ||
| README.md | ||
| router.go | ||
| router_test.go | ||
| sentry.go | ||
| sentry_test.go | ||
| server.go | ||
| server_test.go | ||
| spec.md | ||
Mattermost Push Proxy Router
A small, stateless Go service that routes Mattermost push notifications by mobile client platform prefix. It lets a single PushNotificationServer URL serve both a custom mobile app (e.g. Bubbles) and the official Mattermost mobile apps on the same server.
Why
Mattermost allows only one push notification server URL per instance. The stock push proxy routes by platform prefix (apple_rn, android_rn, …) and drops anything it cannot handle. A custom client registers under its own prefix (e.g. apple_bubbles:<token>) and needs its own APNs key/topic — but official app users on the same server still need HPNS.
This router sits in front of unmodified backends:
Mattermost server
└─ PushNotificationServer
└─ [router :8066]
├─ apple_bubbles:* → your mattermost-push-proxy (custom APNs key)
└─ apple_rn:* / android_rn:* → HPNS relay
Features
- Implements the Mattermost push proxy API (
/api/v1/send_push,/api/v1/ack) - Routes by
platformprefix extracted from the JSON payload - Relays official app traffic to HPNS unchanged
- Forwards custom app traffic to a stock
mattermost-push-proxyinstance - Single static binary with TOML-based configuration
- Docker and GoReleaser ready
- Prometheus metrics at
/metrics
Quick Start
Prerequisites
- Go 1.26+
- A running mattermost-push-proxy for your custom app (with your APNs
.p8key)
Run locally
cp config/router.toml.example config/router.toml
# Edit config/router.toml with your route prefixes and backend URLs
make build
CONFIG_FILE=config/router.toml ./mattermost-push-proxy-router
Point your Mattermost server's EmailSettings.PushNotificationServer at http://<router-host>:8066.
Docker Compose
The included docker-compose.yml runs the router plus a placeholder push-proxy backend:
cp config/router.toml.example config/router.toml
cp config/mattermost-push-proxy.json.example config/mattermost-push-proxy.json
# Edit both config files for your deployment
docker compose up -d
Configuration
Routes are defined in a TOML config file — there are no built-in prefix defaults.
Set CONFIG_FILE to a TOML file:
listen = ":8066"
request_timeout_sec = 60
[[routes]]
prefixes = ["apple_bubbles"]
url = "http://bubbles-proxy:8067"
[[routes]]
prefixes = ["apple_rn", "android_rn"]
url = "https://push.mattermost.com"
See config/router.toml.example.
| Variable | Description |
|---|---|
CONFIG_FILE |
Path to router TOML config (required) |
PORT |
Overrides listen from the config file |
REQUEST_TIMEOUT_SEC |
Overrides upstream timeout |
SENTRY_DSN |
Enables Sentry error reporting and tracing |
SENTRY_ENVIRONMENT |
Sentry environment name |
SENTRY_RELEASE |
Sentry release identifier (defaults to the build version) |
SENTRY_TRACES_SAMPLE_RATE |
Performance trace sampling rate (default: 0.1; set to 0 to disable) |
SENTRY_ATTACH_STACKTRACE |
Attach stack traces to Sentry events (default: true) |
SENTRY_DEBUG |
Enable Sentry SDK debug output (default: false) |
API
Compatible with the Mattermost push notification service protocol:
| Endpoint | Method | Description |
|---|---|---|
/api/v1/send_push |
POST | Route a push notification to the correct backend |
/api/v1/ack |
POST | Route a delivery acknowledgement |
/version |
GET | Service version |
/health |
GET | Health check |
/metrics |
GET | Prometheus metrics |
Example
curl http://127.0.0.1:8066/api/v1/send_push \
-X POST \
-H "Content-Type: application/json" \
-d '{
"type": "message",
"platform": "apple_bubbles",
"server_id": "YOUR_DIAGNOSTIC_ID",
"device_id": "YOUR_APNS_TOKEN",
"channel_id": "CHANNEL_ID",
"post_id": "POST_ID",
"is_id_loaded": true
}'
Building
make help # Show all targets
make build # Production binary
make test # Unit tests
make format # Format Go source
make lint # Run linter
make build-snapshot # Cross-platform builds via goreleaser
Mattermost Server Setup
MM_EMAILSETTINGS_SENDPUSHNOTIFICATIONS=true
MM_EMAILSETTINGS_PUSHNOTIFICATIONCONTENTS=id_loaded
MM_EMAILSETTINGS_PUSHNOTIFICATIONSERVER=http://router-host:8066
License
MIT