Setup: Signal
Llamenos supports Signal messaging via a self-hosted signal-cli-rest-api bridge. Signal offers the strongest privacy guarantees of any messaging channel, making it ideal for sensitive crisis response scenarios.
Prerequisites
- A Linux server or VM for the bridge (can be the same server as Asterisk, or separate)
- Docker installed on the bridge server
- A dedicated phone number for Signal registration
- Network access from the bridge to your Llamenos server
Architecture
flowchart LR
User["Signal User"] --> Servers["Signal Servers"]
Servers --> Bridge["signal-cli bridge<br/>(self-hosted)"]
Bridge --> Server["Llamenos Server"]
The signal-cli bridge runs on your infrastructure and forwards messages to your server via HTTP webhooks. This means you control the entire message path from Signal to your application.
1. Deploy the signal-cli bridge
Run the signal-cli-rest-api Docker container:
docker run -d \
--name signal-cli \
--restart unless-stopped \
-p 8080:8080 \
-v signal-cli-data:/home/.local/share/signal-cli \
-e MODE=json-rpc \
bbernhard/signal-cli-rest-api:latest
2. Register a phone number
Register the bridge with a dedicated phone number:
# Request a verification code via SMS
curl -X POST http://localhost:8080/v1/register/+1234567890
# Verify with the code you received
curl -X POST http://localhost:8080/v1/register/+1234567890/verify/123456
3. Configure webhook forwarding
Set up the bridge to forward incoming messages to your server:
curl -X PUT http://localhost:8080/v1/about \
-H "Content-Type: application/json" \
-d '{
"webhook": {
"url": "https://your-domain.com/api/messaging/signal/webhook",
"headers": {
"Authorization": "Bearer your-webhook-secret"
}
}
}'
4. Enable Signal in admin settings
Navigate to Admin Settings > Messaging Channels (or use the setup wizard) and toggle Signal on.
Enter the following:
- Bridge URL — the URL of your signal-cli bridge (e.g.,
https://signal-bridge.example.com:8080) - Bridge API Key — a bearer token for authenticating requests to the bridge
- Webhook Secret — the secret used to validate incoming webhooks (must match what you configured in step 3)
- Registered Number — the phone number registered with Signal
5. Test
Send a Signal message to your registered phone number. The conversation should appear in the Conversations tab.
Health monitoring
Llamenos monitors the signal-cli bridge health:
- Periodic health checks to the bridge’s
/v1/aboutendpoint - Graceful degradation if the bridge is unreachable — other channels continue working
- Admin alerts when the bridge goes down
Voice message transcription
Signal voice messages can be transcribed directly in the volunteer’s browser using client-side Whisper (WASM via @huggingface/transformers). Audio never leaves the device — the transcript is encrypted and stored alongside the voice message in the conversation view. Volunteers can enable or disable transcription in their personal settings.
Security notes
- Signal provides end-to-end encryption between the user and the signal-cli bridge
- The bridge decrypts messages to forward them as webhooks — the bridge server has plaintext access
- Webhook authentication uses bearer tokens with constant-time comparison
- Keep the bridge on the same network as your Asterisk server (if applicable) for minimal exposure
- The bridge stores message history locally in its Docker volume — consider encryption at rest
- For maximum privacy: self-host both Asterisk (voice) and signal-cli (messaging) on your own infrastructure
Troubleshooting
- Bridge not receiving messages: Check that the phone number is correctly registered with
GET /v1/about - Webhook delivery failures: Verify the webhook URL is reachable from the bridge server and the authorization header matches
- Registration issues: Some phone numbers may need to be unlinked from an existing Signal account first