Overpush


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.
Build
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.
Sources
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.
Pushover clients
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.
Custom HTTP Webhooks
Overpush can handle a wide variety of custom webhooks by configuring dedicated
Applications
in its config. Here are some
examples:
CrowdSec
Add the following application to your Overpush config:
[[Users.Applications]]
Enable = true
Token = "XXX"
Name = "CrowdSec"
IconPath = ""
Target = "your_target"
TargetArgs.Destination = "you@your-xmpp-server.im"
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.
Grafana
Add the following application to your Overpush config:
[[Users.Applications]]
Enable = true
Token = "XXX"
Name = "Grafana"
IconPath = ""
Target = "your_target"
TargetArgs.Destination = "you@your-xmpp-server.im"
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
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.
XMPP (built-in)
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 = "my_bot@conversations.im"
password = "hunter2"
To use this target, specify its ID inside an Application
configuration:
...
Target = "your_target"
TargetArgs.Destination = "you@your-xmpp-server.im"
...
Apprise
Overpush supports the following platforms via
Apprise:
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:hunter2@matrix.org:443/{{ arg "destination" }}?format=markdown'
To use this target, specify its ID inside an Application
configuration:
...
Target = "your_target"
TargetArgs.Destination = "!xXxXxXxXXXxxxXXXxX:matrix.org"
...
Internal Endpoints
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.
Health Check
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
OK
503
Service Unavailable
Run
All that's needed is a configuration and Overpush can be launched:
$ overpush
Supervisor
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
.
OpenBSD rc
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
systemd
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
$ 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
$ 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.
Kubernetes
TODO
Amazon Web Services Lambda Function
TODO
Google Cloud Function
TODO
FAQ
Why?
That's why.
XMPP? Without OTR? Or OMEMO?
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.
Workaround
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.
But Matrix is E2EE, right?
Nope. Use the aforementioned
workaround.