Hosting your own Chat Relay
Chat relays are used to deliver channel messages in SimpleX Network. Read more about channels in this whitepaper and this blog post.
A chat relay is the SimpleX Chat CLI (simplex-chat) running in relay mode (--relay). It has its own profile (a display name and a picture), its own address, and in addition to delivering messages, it can generate data for web previews of the channels it delivers.
This guide explains how to set up a chat relay on a Linux server, how to run it, and (optionally) how to configure Caddy to serve data for channel web previews.
Please note: This guide applies only to SimpleX Chat v7.0.0-beta.4 and later.
Table of Contents
Install the CLI
The relay is the standard simplex-chat CLI binary. Install or update it with the install script:
curl -o- https://raw.githubusercontent.com/simplex-chat/simplex-chat/stable/install.sh | bash
Other options (manual binary download, building from source) are in the CLI guide.
Copy the installed simplex-chat binary to /usr/local/bin/simplex-chat-relay. The guide uses that name so the relay is separate from any interactive simplex-chat you also run on the server.
Create a dedicated user for the relay (called relay below), so it does not run as root and keeps its database in one place:
sudo useradd -m relay
The useradd -m flag creates its home directory /home/relay, where the guide keeps the database and picture. Run the relay commands (the -e commands below) as this user, for example with sudo -u relay ...; run the systemd and Caddy steps as root.
Run the relay
Run the relay as a systemd service. With --headless it starts without any interactive prompts. It creates its profile and address on the first start, and writes its output to the journal.
Create a run script /usr/local/bin/relay-run:
#!/bin/sh
exec /usr/local/bin/simplex-chat-relay \
--relay \
--headless \
--user-display-name "My Relay" \
--user-image-file /home/relay/avatar.png \
-d /home/relay/relay
chmod +x /usr/local/bin/relay-run
Create /etc/systemd/system/simplex-relay.service:
[Unit]
Description=SimpleX Chat relay
After=network.target
[Service]
User=relay
ExecStart=/usr/local/bin/relay-run
Restart=always
StandardInput=null
[Install]
WantedBy=multi-user.target
Enable and start it:
systemctl daemon-reload
systemctl enable --now simplex-relay
The first start creates the relay profile (with the given name and picture) and its address; later starts reuse them. Both are written to the journal:
Current user: My Relay
Chat relay address is created:
https://smp4.simplex.im/r#73iEnnvCqPTVGArCAWUcRaj5hxRb7TbPCSZ2JY2VjCQ
Relay options
| Option | Purpose |
|---|---|
--relay |
Run as a chat relay. Required. |
--headless |
Don't ask interactive questions; create the profile and address automatically. On first start it also needs --user-display-name. |
--user-display-name NAME |
The relay's display name. Creates the profile on first start; on later starts it must match the existing profile. |
--user-image-file FILE |
The relay's picture, from a .png, .jpg or .jpeg file. Applied only when the profile is created; ignored afterwards. |
--relay-address-server SERVER |
Create the relay address on a specific SMP server, e.g. smp://<fingerprint>@smp.example.com. By default a preset server is used. Requires --relay. |
Get the relay address
The address is created and logged on the first start. Read it from the journal at any time:
journalctl -u simplex-relay | grep -A1 "address is created"
Run relay commands
The service runs headless, so there is no attached terminal to type into. To run a one-off command, stop the service, run the command against the relay's database with -e, then start it again. For example, to change the picture (--user-image-file only sets it when the profile is first created):
systemctl stop simplex-relay
simplex-chat-relay -d /home/relay/relay -e "/set profile image file /home/relay/new-avatar.png"
systemctl start simplex-relay
Channel web previews
Chat relays can render recent messages of its public channels as JSON files, which can be served over HTTPS using a web server to create channel web previews. This is optional.
Relay web options
Add these to the run script (--relay-web-domain and --relay-web-dir must be given together):
--relay-web-domain relay.example.com \
--relay-web-dir /var/www/relay-web-channels/channel \
--relay-web-cors-file /var/www/relay-web-channels/cors.conf \
--relay-web-interval 30 \
| Option | Purpose |
|---|---|
--relay-web-domain DOMAIN |
Domain the previews are served from. |
--relay-web-dir DIR |
Directory the relay writes channel JSON files to. |
--relay-web-cors-file FILE |
File the relay writes the generated Caddy CORS config to. |
--relay-web-interval SECONDS |
How often previews are regenerated (default 300). |
--relay-web-item-count COUNT |
Recent messages per channel preview (default 50). |
Create the web directory, owned by the relay user:
mkdir -p /var/www/relay-web-channels/channel
chmod 0755 /var/www/relay-web-channels
chown -R relay:relay /var/www/relay-web-channels
Restart the relay so the new flags take effect:
systemctl restart simplex-relay
Serve the previews with Caddy
This section uses Caddy as the web server. Install it (Debian/Ubuntu):
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl &&\
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg &&\
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list &&\
sudo apt update && sudo apt install caddy
The relay writes files to /var/www/relay-web-channels/channel/<id>.json. Serve them, and import the relay's generated CORS rules, in your Caddyfile:
relay.example.com {
encode zstd gzip
handle /channel/* {
root * /var/www/relay-web-channels # files resolve to .../channel/<id>.json
file_server
import /etc/caddy/simplex-cors.conf
}
}
Keep root at the parent directory with a non-stripping handle. That is what makes /channel/<id>.json resolve to .../channel/<id>.json. Do not point root at the channel subdirectory: the relay's generated CORS matchers are /channel/*.json, which only match when the prefix is kept.
touch /etc/caddy/simplex-cors.conf # so the import doesn't fail before the first write
usermod -aG relay caddy # let caddy read the relay user's files
systemctl restart caddy # restart (not reload) to pick up the group
Reload CORS automatically
The relay updates its CORS file as channels change. Copy it into Caddy's config and reload Caddy whenever it changes.
Create /usr/local/bin/simplex-cors-sync.sh:
#!/bin/sh
set -eu
SRC=/var/www/relay-web-channels/cors.conf
DST=/etc/caddy/simplex-cors.conf
[ -f "$SRC" ] || exit 0
cmp -s "$SRC" "$DST" 2>/dev/null && exit 0
install -m 0644 "$SRC" "$DST"
systemctl reload caddy
logger -t simplex-cors "reloaded caddy"
Create /etc/systemd/system/simplex-cors-sync.service:
[Unit]
Description=Sync SimpleX relay CORS config to Caddy
StartLimitIntervalSec=30
StartLimitBurst=10
[Service]
Type=oneshot
ExecStartPre=/bin/sleep 2
ExecStart=/usr/local/bin/simplex-cors-sync.sh
Create /etc/systemd/system/simplex-cors-sync.path to run the service whenever the relay's CORS file changes:
[Unit]
Description=Watch SimpleX relay CORS config
After=caddy.service
[Path]
PathChanged=/var/www/relay-web-channels/cors.conf
Unit=simplex-cors-sync.service
[Install]
WantedBy=multi-user.target
Enable it:
chmod +x /usr/local/bin/simplex-cors-sync.sh
systemctl daemon-reload
systemctl enable --now simplex-cors-sync.path
Verify
systemctl status simplex-cors-sync.path # active (waiting)
ls /var/www/relay-web-channels/channel # a JSON file appears once a public channel renders
curl -sI https://relay.example.com/channel/<id>.json | grep -i access-control
The curl should return access-control-* headers, and the channel link should open a web preview in a browser.