|
|
vor 1 Monat | |
|---|---|---|
| README.md | vor 1 Monat | |
| app.py | vor 1 Monat | |
| dis2hook.initd | vor 1 Monat | |
| index.html | vor 1 Monat | |
| install.sh | vor 1 Monat | |
| update.sh | vor 1 Monat |
Dis2Hook receives webhooks from anything that can send an HTTP POST — Gitea, Gogs, Proxmox notifications, Uptime Kuma, home-automation scripts — formats them as Markdown, and relays them into Discord channels through the Discord Bot API (not Discord's incoming webhooks, so one bot identity serves every channel).
It is built to live in a small Alpine Linux LXC on Proxmox and is configured entirely from a built-in web UI.
source A ──▶ POST /hook/gitea-ci ──┐
source B ──▶ POST /hook/kuma ──────┼──▶ Dis2Hook ──▶ Discord Bot API ──▶ #channels
source C ──▶ POST /hook/backup ────┘
{dotted.path[0]} placeholders resolved from the incoming JSON payload; leave
the template empty to relay the raw payload as a pretty-printed JSON block.equals / contains / exists on any
payload path) so only the events you care about reach Discord.http://192.168.x.x/… (Dis2Hook fetches it and uploads it as an
attachment, since Discord can't reach your LAN), or base64 image data /
data-URIs (decoded and attached). JPEG/PNG/GIF/WebP, up to 8 MB.token.json
generated at install time; it is never pulled from, nor pushed to, this repo.app.py / index.html straight from the
repo, validates them, backs up the old ones, and restarts the service.Run this inside an existing Alpine LXC — never on the Proxmox host. The installer refuses to run if it detects Proxmox VE.
pct enter <ctid>Run the one-liner:
wget -qO- https://gogs.av2x.dev/av2x/Dis2Hook/raw/master/install.sh | ash
The installer will:
python3, py3-flask, py3-requests via apk,app.py, index.html, update.sh, and the OpenRC service script
directly from this repo,/opt/dis2hook/token.json (mode 600) with the token and a fresh
random admin key, printed once at the end — save it,dis2hook OpenRC service.Non-interactive install:
DISCORD_BOT_TOKEN=xxxxx wget -qO- https://gogs.av2x.dev/av2x/Dis2Hook/raw/master/install.sh | ash
Optional environment overrides: D2H_BRANCH (defaults to master, auto-falls
back to main), D2H_DIR (default /opt/dis2hook), D2H_PORT (default 8823).
bot).http://<container-ip>:8823/, unlock with the admin key, add a source,
paste the channel ID, save, and hit Send test message.X-Hook-Secret header (or ?secret= query, or a Bearer token).curl -X POST "http://<container-ip>:8823/hook/gitea-ci" \
-H "Content-Type: application/json" \
-H "X-Hook-Secret: <source secret>" \
-d '{"action":"opened","repository":{"full_name":"av2x/Dis2Hook"}}'
🔔 **{repository.full_name}** — {pusher.name} pushed to `{ref}`
> {commits[0].message}
{commits[0].url}
Unresolved placeholders render as empty strings; objects/lists render as compact JSON. Messages are truncated to Discord's 2000-character limit.
Once a source has received at least one webhook, open its strip in the UI:
under the template you'll find "Payload keys from the last received event"
— every key/value pair from that event as a chip. Drag chips into the template
(or click them) to insert {path} placeholders at the cursor; hover a chip to
preview its value. Hit ↻ refresh after new events arrive. Blue chips are
values that look like images.
Set a source's Image — payload path to the field holding the picture (drag a blue chip into it), and pick a delivery mode:
data: image data, and uploads it to Discord as an attachment.
Use this for LAN URLs (e.g. http://192.168.51.234:8000/...) and base64
fields — Discord's servers can never reach your LAN directly.Example for a Bambu Lab print notifier: template
🖨️ **{printer}** — {title}\n\{filename}` after {duration}with image path
image(base64 snapshot) orfinish_photo_url` (LAN URL) in fetch & upload mode.
Pull the latest app.py and index.html directly from the repo and restart:
/opt/dis2hook/update.sh # app.py + index.html
/opt/dis2hook/update.sh --all # also refresh update.sh and the service script
Downloads are validated (version marker + compile check) before they replace
anything, previous files are kept as *.bak, and token.json and
config.json are never touched.
| Path | Purpose | In repo? |
|---|---|---|
/opt/dis2hook/app.py |
relay service (Flask) | yes |
/opt/dis2hook/index.html |
web UI | yes |
/opt/dis2hook/update.sh |
updater | yes |
/etc/init.d/dis2hook |
OpenRC service (dis2hook.initd) |
yes |
/opt/dis2hook/token.json |
bot token + admin key — generated at install, mode 600 | never |
/opt/dis2hook/config.json |
sources & settings, managed by the web UI | never |
/var/log/dis2hook.log |
service log | — |
rc-service dis2hook status|start|stop|restart
tail -f /var/log/dis2hook.log
token.json is generated locally, chmod 600, and listed in .gitignore;
treat the admin key like a password — it is the only credential for the UI/API.401.@everyone.config.json and restart if
you need to, so a bad save can never lock you out.Discohook is a superb editor for Discord's incoming webhooks — you compose a message and Discord hosts the endpoint. Dis2Hook is the opposite direction: it hosts the endpoint, accepts webhooks from your own services, filters and reformats them, and delivers via a bot token — so one self-hosted relay fans out many sources to many servers and channels, with heartbeat and uptime status built in.
rc-service dis2hook stop; rc-update del dis2hook default
rm -rf /opt/dis2hook /etc/init.d/dis2hook /var/log/dis2hook.log