Overpush is a self-hosted, drop-in replacement for Pushover that can use XMPP, as well as a wide variety of other services (see below) as the delivery method while maintaining full compatibility with the Pushover API and also offering a flexible HTTP webhooks endpoint. This allows existing setups to continue functioning with minimal changes, while allowing more complex setups further down the road.
Think of Overpush as a bridge between HTTP requests (webhooks) and various target services, such as XMPP, Matrix, Signal, and others:
┌────────────────┐
│ │
│ HTTP REQUEST │
│ │
└────────┬───────┘
│
│
│
┌────────▼───────┐
│ │
│ OVERPUSH API │
│ │
│────────────────│
│ REDIS │
│────────────────│
│ │
│ WORKER │
│ │
└────────┬───────┘
│
┌────────────────────┼──────────────────┐
│ │ │
┌───────▼────────┐ ┌────────▼───────┐ ┌───────▼────────┐
│ │ │ │ │ │
│ SIGNAL │ │ XMPP │ │ MATRIX │
│ │ │ │ │ │
└────────────────┘ └────────────────┘ └────────────────┘
The Overpush API accepts HTTP POST
requests in multiple formats, including:
application/x-www-form-urlencoded
multipart/form-data
application/json
application/xml
/text/xml
The configuration file allows you to define custom
templates using Go's text/template
syntax to extract and transform data from
webhook payloads.
Internally, Overpush uses asynq
to queue
messages for processing by a background worker. This requires a Redis-compatible
server as a backend. You can run your own instance (e.g. Redis, Valkey, KeyDB,
DragonflyDB) or use the free Essentials plan from
Redis Cloud, which is reliable and sufficient for
most use cases.
The Overpush worker has native support for XMPP as a target. For other
services, it integrates with Apprise,
requiring the apprise
CLI tool to be available on the same host.
To build Overpush, simply clone this repository and run the following command inside your local copy:
$ go build
The Overpush configuration is organized into four main sections:
[Server]
: Specifies server settings, like the IP address and port on which Overpush should run.[Redis]
: Configures the connection to a Redis server or cluster.[Users]
: Defines individual users and their settings.[Targets]
: Sets up message targets (or destinations) for each user.
Overpush will try to read the overpush.toml
file from one of the following
paths:
/etc/overpush.toml
$XDG_CONFIG_HOME/overpush.toml
$HOME/.config/overpush.toml
$HOME/overpush.toml
$PWD/overpush.toml
Every configuration key available in the example
overpush.toml
can be exported as environment
variable, by separating scopes using _
and prepend OVERPUSH
to it.
The Overpush API accepts requests to the legacy /1/messages.json
endpoint used
by Pushover, which allows you to simply flip the host/domain in your
configurations to drop in Overpush instead of Pushover. In addition, Overpush
offers a flexible HTTP POST
endpoint on /:token
(where :token
is an
Application
's Token
), which can be used to retrieve various different
webhook formats.
The official Pushover API documentation
shows how to submit a message to the /1/messages.json
endpoint. Replacing
Pushover with Overpush only requires your tooling to support changing the
endpoint URL to your own server. Enable = true
You can find an example script here that serves as a command-line API client for both Pushover and Overpush to submit notifications. Since Overpush does not yet offer 100% feature parity with Pushover, some features are not available.
Overpush can handle a wide variety of custom webhooks by configuring dedicated
Applications
in its config. Here are some
examples:
Add the following application to your Overpush config:
[[Users.Applications]]
Enable = true
Token = "XXX"
Name = "CrowdSec"
IconPath = ""
Target = "your_target"
TargetArgs.Destination = "[email protected]"
Format = "custom"
CustomFormat.Message = '{{ webhook "body.alerts.0.message" }}'
CustomFormat.Title = 'CrowdSec: {{ webhook "body.alerts.0.scenario" }}'
Edit the CrowdSec config notifications/http.yaml
(under
/etc/crowdsec/notifications/http.yaml
or
/usr/local/etc/crowdsec/notifications/http.yaml
) as follows:
type: http
name: http_default
log_level: info
format: |
{"alerts":{{.|toJson}}}
url: https://my.overpush.net/XXX
method: POST
headers:
Content-Type: application/json
# skip_tls_verification: true
Set XXX
to the unique token of the Overpush application.
Add the following application to your Overpush config:
[[Users.Applications]]
Enable = true
Token = "XXX"
Name = "Grafana"
IconPath = ""
Target = "your_target"
TargetArgs.Destination = "[email protected]"
Format = "custom"
CustomFormat.Message = '{{ webhook "body.message" }}'
CustomFormat.Title = '{{ webhook "body.title" }}'
CustomFormat.URL = '{{ webhook "body.externalURL" }}'
Create a new contact point in your Grafana under
/alerting/notifications/receivers/new
, choose the Webhook integration add
set your Overpush instance:
https://my.overpush.net/XXX
Set XXX
to the unique token of the Overpush application.
Targets are the target services that messages should be routed to. Overpush supports XMPP out of the box, but can use Apprise to forward messages to a wide range of different services.
Each Application
must specify a Target
. Multiple Application
configurations might use the same target.
Overpush supports XMPP (without OTR/OMEMO) out of the box, without any additional software. The configuration for the XMPP target might look like this:
[[Targets]]
Enable = true
ID = "your_target"
Type = "xmpp"
[Targets.Args]
server = "conversations.im"
tls = "true"
username = "[email protected]"
password = "hunter2"
To use this target, specify its ID inside an Application
configuration:
...
Target = "your_target"
TargetArgs.Destination = "[email protected]"
...
Overpush supports the following platforms via Apprise:
- AWS SES
- Bark
- BlueSky
- Chanify
- Discord
- Emby
- Enigma2
- FCM
- Feishu
- Flock
- Google Chat
- Gotify
- Growl
- Guilded
- Home Assistant
- IFTTT
- Join
- KODI
- Kumulos
- LaMetric Time
- Line
- LunaSea
- Mailgun
- Mastodon
- Matrix
- Mattermost
- Microsoft Power Automate / Workflows (MSTeams)
- Microsoft Teams
- Misskey
- MQTT
- Nextcloud
- NextcloudTalk
- Notica
- Notifiarr
- Notifico
- ntfy
- Office 365
- OneSignal
- Opsgenie
- PagerDuty
- PagerTree
- ParsePlatform
- PopcornNotify
- Prowl
- PushBullet
- Pushjet
- Push (Techulus)
- Pushed
- PushMe
- Pushover
- PushSafer
- Pushy
- PushDeer
- Resend
- Revolt
- Rocket.Chat
- RSyslog
- Ryver
- SendGrid
- ServerChan
- Signal API
- SimplePush
- Slack
- SMTP2Go
- SparkPost
- Splunk
- Streamlabs
- Synology Chat
- Syslog
- Telegram
- Twist
- Webex Teams (Cisco)
- WeCom Bot
- WxPusher
- XBMC
- Zulip Chat
- Africas Talking
- Automated Packet Reporting System (ARPS)
- AWS SNS
- BulkSMS
- BulkVS
- Burst SMS
- ClickSend
- DAPNET
- D7 Networks
- DingTalk
- Free-Mobile
- httpSMS
- Kavenegar
- MessageBird
- MSG91
- Plivo
- Seven
- Société Française du Radiotéléphone (SFR)
- Signal API
- Sinch
- SMSEagle
- SMS Manager
- Threema Gateway
- Twilio
- Voipms
- Vonage (formerly Nexmo)
- ... and many more
The configuration for the Matrix target might look like this:
[[Targets]]
Enable = true
ID = "your_target"
Type = "apprise"
[Targets.Args]
apprise = "/home/you/.local/share/pyenv/bin/apprise"
connection = 'matrixs://your_bot:[email protected]:443/{{ arg "destination" }}?format=markdown'
To use this target, specify its ID inside an Application
configuration:
...
Target = "your_target"
TargetArgs.Destination = "!xXxXxXxXXXxxxXXXxX:matrix.org"
...
Overpush serves internal endpoints under /_internal/
. These endpoints are not
to be made available publicly/for clients. Make sure your reverse proxy blocks
access to every URL starting with /_internal/
. Hosting Overpush without a
reverse proxy is not supported.
Overpush provides the following URLs for health checks:
/_internal/health/livez
: Checks if the server is up and running./_internal/health/readyz
: Assesses if the application is ready to handle requests./_internal/health/startupz
: Checks if the application has completed its startup sequence and is ready to proceed with initialization and readiness checks.
These endpoints can return the following HTTP status codes:
200
OK503
Service Unavailable
All that's needed is a configuration and Overpush can be launched:
$ overpush
To run Overpush via supervisord
, create a config like this inside
/etc/supervisord.conf
or /etc/supervisor/conf.d/overpush.ini
. See
this example.
Note: It is advisable to run Overpush under its own, dedicated daemon user.
Make sure to either adjust directory
as well as user
.
As before, create a configuration file under /etc/overpush.toml
.
Then copy the example rc.d script to
/etc/rc.d/overpush
and copy the binary to e.g. /usr/local/bin/overpush
. Last
but not least, update the /etc/rc.conf.local
file to contain the following
line:
overpush_user="_overpush"
It is advisable to run Overpush as a dedicated user, hence create the
_overpush
daemon account or adjust the line above according to your setup.
You can now run Overpush by enabling and starting the service:
$ rcctl enable overpush
$ rcctl start overpush
As before, create a configuration file under /etc/overpush.toml
.
Then copy the
example systemd service to
/etc/systemd/system/overpush.service
and copy the binary to e.g.
/usr/local/bin/overpush
. Ensure the overpush
user and group exist, or change
them to something appropriate.
Then, as root, reload systemd and enable the service:
# systemctl daemon-reload
# systemctl enable --now overpush
If you'd rather prefer running Overpush as a user-level service, put the service
file in ~/.config/systemd/user/overpush.service
and reload and enable the
service as user:
$ systemctl --user daemon-reload
$ systemctl --user enable --now overpush
$ podman run \
-d \
--name overpush \
--network podman \
-v "$(pwd)/overpush.toml:/etc/overpush.toml:ro" \
-p 8080:8080 \
ghcr.io/mrusme/overpush:latest
Info: apprise
inside the Docker container is available at
/usr/bin/apprise
; Make sure to set the apprise = "/usr/bin/apprise"
flag
inside apprise
targets.
$ docker run \
-d \
--name overpush \
-v "$(pwd)/overpush.toml:/etc/overpush.toml:ro" \
-p 8080:8080 \
ghcr.io/mrusme/overpush:latest
Info: apprise
inside the Docker container is available at
/usr/bin/apprise
; Make sure to set the apprise = "/usr/bin/apprise"
flag
inside apprise
targets.
TODO
TODO
TODO
Nope, none of those. The XMPP ecosystem is a bit of a can of worms in this regard. First, when using modern languages like Go, there are very few XMPP libraries available. The ones that do exist generally don't support OTR or OMEMO. Adding support would require either implementing these protocols from scratch or interfacing with a low-level C library.
Even if someone were willing to go through that effort, they'd run into the second major issue with XMPP: fragmentation. For example, if someone were to implement OMEMO in Go today, they would likely choose OMEMO 0.8.3 or newer. Unfortunately, many XMPP clients are still stuck on version 0.3.0, which uses AES-128-GCM -- an encryption algorithm considered weaker by modern standards (e.g., compared to what Matrix.org or Signal use). As a result, most implementations would have to fall back to a significantly older and less secure version of OMEMO.
For notifications that require content encryption, good old GPG can be used:
curl -s \
--form-string "token=$OP_TOKEN" \
--form-string "user=$OP_USER" \
--form-string "message=$(gpg -e -r KEY_ID --armor -o - file_to_encrypt)" \
"$OP_URL"
On the receiving end, for example, Android running Conversations, the message can be shared to OpenKeychain using the standard Android sharing popup. OpenKeychain will then decrypt and display the message content.
This is the simplest way to enable encrypted notifications without relying on XMPP clients to support modern encryption standards.
Nope. Use the aforementioned workaround.