Using Signal for Zabbix Alerts with signal-cli
Overview
This document explains how to send Zabbix alerts using Signal by integrating the signal-cli command line client. The method relies on a dedicated Signal account on the server and a simple alert script executed by Zabbix.
Characteristics of this setup:
- End-to-end encrypted alert delivery
- No external SaaS notification provider
- Fully self-hosted
- Suitable for infrastructure alerts with low to moderate volume
Environment assumed:
- Ubuntu 22.04 (Jammy)
- Zabbix Server
- signal-cli native binary
- Python alert script
Architecture
Alert flow:
- Zabbix trigger fires
- Zabbix executes an alert script
- The alert script calls
signal-cli signal-clisends a Signal message
Typical layout:
signal-cli binary
/usr/local/bin/signal-cli
Signal account data
/var/lib/zabbix/.local/share/signal-cli/
Zabbix alert scripts
/usr/lib/zabbix/alertscripts/
Important Notes
signal-cli is not an official Signal client
signal-cli is a third-party implementation of the Signal protocol.
Implications:
- no official support
- protocol changes may require upgrades
- the binary should be periodically updated
Use a dedicated Signal number
Recommended practice:
- register a phone number dedicated to alerting
Advantages:
- separation from personal chats
- simpler operational management
- easier to re-register if needed
Signal account state is user-specific
Signal account data is stored under the home directory of the user running signal-cli.
For the Zabbix user this will be:
/var/lib/zabbix/.local/share/signal-cli/
The binary itself can remain owned by root.
Requirements
Server requirements:
- Zabbix server installed
- root shell access
- outbound internet access
External requirements:
- phone number capable of receiving SMS
- Signal installed on the receiving device
Recommended:
- dedicated alerting number
- cron enabled
- regular backups of the Signal account directory
Installing signal-cli
Use the native binary build on Ubuntu 22.04 to avoid Java runtime issues.
Install:
cd /opt
VERSION=$(curl -Ls -o /dev/null -w %{url_effective} https://github.com/AsamK/signal-cli/releases/latest | sed -e 's/^.*\/v//')
curl -L -O https://github.com/AsamK/signal-cli/releases/download/v"${VERSION}"/signal-cli-"${VERSION}"-Linux-native.tar.gz
tar xf signal-cli-"${VERSION}"-Linux-native.tar.gz -C /opt
ln -sf /opt/signal-cli /usr/local/bin/signal-cli
Verify:
signal-cli --version
Example output:
signal-cli 0.14.0
Registering the Signal Account
Register the sending phone number.
Example:
signal-cli -a +37212345678 register
CAPTCHA Registration
Signal often requires CAPTCHA verification when registering from servers.
Generate a token at:
https://signalcaptchas.org/registration/generate.html
After solving the CAPTCHA you will receive a redirect URI:
signalcaptcha://signal-hcaptcha.<TOKEN>
Extract only the token portion:
signal-hcaptcha.<TOKEN>
Register using:
signal-cli -a +37212345678 register --captcha signal-hcaptcha.<TOKEN>
Verify the SMS Code
When the verification SMS arrives:
signal-cli -a +37212345678 verify 123456
If successful the Signal account is registered.
Optional Profile Name
Set a profile name:
signal-cli -a +37212345678 updateProfile --name "Zabbix Alerts"
Moving the Signal Account to the Zabbix User
If registration was done as root, the account will exist under:
/root/.local/share/signal-cli/
Move it to the Zabbix home directory.
Create directories:
mkdir -p /var/lib/zabbix/.local/share
Move data:
mv /root/.local/share/signal-cli /var/lib/zabbix/.local/share/
Fix permissions:
chown -R zabbix:zabbix /var/lib/zabbix/.local
Testing signal-cli as the Zabbix User
Send a test message:
sudo -u zabbix env HOME=/var/lib/zabbix signal-cli \
-a +37212345678 send \
-m "Test from zabbix user" \
+37298765432
If the message arrives the account migration is correct.
Sending to a Signal Group
The sending account must be a member of the group.
List groups:
signal-cli -a +37212345678 listGroups
Example output:
Id: 9a3c9c5b2f2f4e1e8d5c2e
Name: Zabbix Alerts
Send to group:
signal-cli -a +37212345678 send \
-m "Alert message" \
-g 9a3c9c5b2f2f4e1e8d5c2e
Periodic Receive
Signal expects devices to occasionally receive messages.
If the client only sends messages, logs may show:
INFO AccountHelper - The Signal protocol expects that incoming messages are regularly received.
Run periodic receive jobs.
Manual test:
signal-cli -a +37212345678 receive
Cron example:
*/30 * * * * sudo -u zabbix env HOME=/var/lib/zabbix signal-cli -a +37212345678 receive >/dev/null 2>&1
Creating the Zabbix Alert Script
Create the script:
/usr/lib/zabbix/alertscripts/signal.py
Example:
#!/usr/bin/env python3
import os
import sys
import subprocess
os.environ["HOME"]="/var/lib/zabbix"
SIGNAL_ACCOUNT="+37212345678"
TO_NUMBER="+37298765432"
def main():
if len(sys.argv) < 4:
return 1
host=sys.argv[1]
alert_message=sys.argv[2]
event_name=sys.argv[3]
message=f"{event_name}\nHost: {host}\n\n{alert_message}"
cmd=[
"/usr/local/bin/signal-cli",
"-a",SIGNAL_ACCOUNT,
"send",
"-m",message,
TO_NUMBER
]
result=subprocess.run(cmd,capture_output=True,text=True)
return result.returncode
if __name__=="__main__":
sys.exit(main())
Make executable:
chmod +x /usr/lib/zabbix/alertscripts/signal.py
Testing the Script
Manual test:
sudo -u zabbix /usr/lib/zabbix/alertscripts/signal.py \
"TestHost" \
"This is a test alert" \
"TEST ALERT"
Creating the Zabbix Media Type
In the Zabbix web interface:
Administration → Media Types → Create
Settings:
Name: Signal
Type: Script
Script name: signal.py
Script parameters:
{HOST.NAME}
{ALERT.MESSAGE}
{EVENT.NAME}
Assigning the Media to a User
In the Zabbix UI:
Users → Media → Add
Example:
Type: Signal
Send to: signal
When active: 1-7,00:00-24:00
Severity: all
The “Send to” field can contain any placeholder value if the script ignores it.
Adding Signal to an Action
Configuration → Actions → Trigger Actions
Add operation:
Send to users: target user
Send only to: Signal
Updating signal-cli Automatically
Create:
/usr/local/sbin/update-signal-cli.sh
Script:
#!/usr/bin/env bash
set -euo pipefail
INSTALL_PATH="/opt/signal-cli"
BIN_LINK="/usr/local/bin/signal-cli"
TMPDIR=$(mktemp -d)
trap "rm -rf $TMPDIR" EXIT
VERSION=$(curl -Ls -o /dev/null -w %{url_effective} https://github.com/AsamK/signal-cli/releases/latest | sed -e 's/^.*\/v//')
cd "$TMPDIR"
curl -L -O https://github.com/AsamK/signal-cli/releases/download/v${VERSION}/signal-cli-${VERSION}-Linux-native.tar.gz
tar xf signal-cli-${VERSION}-Linux-native.tar.gz -C /opt
ln -sf "$INSTALL_PATH" "$BIN_LINK"
signal-cli --version
Make executable:
chmod +x /usr/local/sbin/update-signal-cli.sh
Test:
/usr/local/sbin/update-signal-cli.sh
Cron example:
15 4 * * 0 /usr/local/sbin/update-signal-cli.sh >> /var/log/update-signal-cli.log 2>&1
Backing Up the Signal Account
Critical directory:
/var/lib/zabbix/.local/share/signal-cli/
Backup example:
tar czf /root/signal-cli-backup.tar.gz -C /var/lib/zabbix/.local/share signal-cli
Restoring this directory restores the Signal identity.
Common Problems
UnsupportedClassVersionError
Cause:
Using Java build without the required Java version.
Fix:
Use the native binary release.
failed to read local accounts list
Cause:
Incorrect permissions or wrong HOME directory.
Fix:
Ensure ownership:
chown -R zabbix:zabbix /var/lib/zabbix/.local
Ensure scripts set:
HOME=/var/lib/zabbix
Messages send manually but not from Zabbix
Common causes:
- wrong script parameter order
- script not executable
- media type not used by action
- severity filter mismatch
Cannot send to group
Cause:
The sending account is not a member of the group.
Solution:
Add the sending number to the Signal group.
Security Considerations
Signal provides:
- strong end-to-end encryption
- reliable message delivery
However:
signal-climust be kept updated- backups of the Signal account directory are critical
- if the account directory is lost the identity may need re-registration