No description
  • Go 92.3%
  • Makefile 5.4%
  • Dockerfile 2.3%
Find a file
Felipe M. c01b4e2c00
All checks were successful
CI / goreleaser-lint (push) Successful in 5s
CI / format (push) Successful in 2m45s
CI / lint (push) Successful in 3m49s
CI / test (push) Successful in 3m23s
CI / build (push) Successful in 3m52s
Release / release (push) Successful in 3m36s
fix: avoid duplicate Prometheus collector registration on startup
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>
2026-07-30 12:01:02 +02:00
.github/workflows feat: add Mattermost push proxy prefix router 2026-07-26 10:03:43 +02:00
config feat: add Mattermost push proxy prefix router 2026-07-26 10:03:43 +02:00
.gitignore feat: add Mattermost push proxy prefix router 2026-07-26 10:03:43 +02:00
.goreleaser.yml feat: add Mattermost push proxy prefix router 2026-07-26 10:03:43 +02:00
AGENTS.md feat: include Go runtime and process metrics on /metrics 2026-07-27 08:39:11 +02:00
config.go feat: add Sentry observability 2026-07-28 18:16:24 +02:00
Containerfile feat: add Mattermost push proxy prefix router 2026-07-26 10:03:43 +02:00
Containerfile.dev feat: add Mattermost push proxy prefix router 2026-07-26 10:03:43 +02:00
docker-compose.yml feat: add Mattermost push proxy prefix router 2026-07-26 10:03:43 +02:00
go.mod feat: add Sentry observability 2026-07-28 18:16:24 +02:00
go.sum feat: add Sentry observability 2026-07-28 18:16:24 +02:00
logger.go feat: add Sentry observability 2026-07-28 18:16:24 +02:00
main.go fix: report startup and listen panics to Sentry 2026-07-30 11:33:12 +02:00
main_test.go fix: report startup and listen panics to Sentry 2026-07-30 11:33:12 +02:00
Makefile feat: add Mattermost push proxy prefix router 2026-07-26 10:03:43 +02:00
metrics.go fix: avoid duplicate Prometheus collector registration on startup 2026-07-30 12:01:02 +02:00
metrics_test.go fix: avoid duplicate Prometheus collector registration on startup 2026-07-30 12:01:02 +02:00
proxy.go feat: add Sentry observability 2026-07-28 18:16:24 +02:00
README.md feat: add Sentry observability 2026-07-28 18:16:24 +02:00
router.go feat: add Mattermost push proxy prefix router 2026-07-26 10:03:43 +02:00
router_test.go feat: add Mattermost push proxy prefix router 2026-07-26 10:03:43 +02:00
sentry.go fix: report startup and listen panics to Sentry 2026-07-30 11:33:12 +02:00
sentry_test.go feat: add Sentry observability 2026-07-28 18:16:24 +02:00
server.go fix: report startup and listen panics to Sentry 2026-07-30 11:33:12 +02:00
server_test.go fix: report startup and listen panics to Sentry 2026-07-30 11:33:12 +02:00
spec.md feat: add Mattermost push proxy prefix router 2026-07-26 10:03:43 +02:00

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 platform prefix extracted from the JSON payload
  • Relays official app traffic to HPNS unchanged
  • Forwards custom app traffic to a stock mattermost-push-proxy instance
  • Single static binary with TOML-based configuration
  • Docker and GoReleaser ready
  • Prometheus metrics at /metrics

Quick Start

Prerequisites

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