Publishes to online platforms (Gmail, X, Telegram and more) from content sent by SMS, so people can post without an internet connection.
- How it works
- Requirements
- Install on a server
- Manage the services
- Run with Docker
- Development
- Configuration
- Platform adapters
- Gateway clients
- Credentials
- Documentation
- License
- A user links an account (Gmail, X, ...) through the gRPC API, which stores its token encrypted.
- Offline, the user's app encrypts the content and sends it by SMS to a gateway client: a phone number that relays SMS to this server.
- The payload arrives over REST, the Twilio webhook or SMTP and is queued.
- A Celery worker decrypts it and publishes it through the platform's adapter.
- Ubuntu 24.04 or Debian 13
- Python 3.12 or newer
- A database: SQLite (the default), MySQL 8.0.28 or newer, MariaDB, or PostgreSQL 12 or newer
The installer sets up everything else, including the system packages and Rust.
-
Run the installer. It installs to
/opt/relaysms/relaysms-publisher, generates the encryption keys and starts the services under systemd:curl -fsSL https://raw.githubusercontent.com/smswithoutborders/RelaySMS-Publisher/main/install.sh | sudo bashWith no flags it asks about each option. To choose up front, pass flags after
bash -s --:curl -fsSL https://raw.githubusercontent.com/smswithoutborders/RelaySMS-Publisher/main/install.sh | \ sudo bash -s -- --site-name publisher.example.com --setup-db postgresFlag Does --site-name DOMAINPuts nginx with a Let's Encrypt certificate in front; --skip-nginxskips it--setup-db mysql|postgresInstalls the database server and writes its details to .env(details)--setup-broker rabbitmqUses RabbitMQ instead of SQLite as the Celery broker, for heavier load (details) --setup-observabilityAdds SigNoz and Uptime Kuma (details) --install-dir PATH,--instance-name NAMEInstalls elsewhere, or a second copy on the same host (details) install.sh --helplists every flag. -
Go to the install directory and check the configuration:
cd /opt/relaysms/relaysms-publisher sudo ./manage.sh check -
Create an administrator credential for the REST API:
./publisher.sh creds create --username ops --administrator
[!IMPORTANT] The password is printed once. Store it before closing the terminal.
-
Add the platform adapters you want to offer, then follow each adapter's README to configure it:
./publisher.sh platforms add https://github.com/smswithoutborders/gmail-oauth2-adapter
-
Register the gateway clients that relay SMS to this server:
./publisher.sh gateway-clients create --msisdn +237123456789 --protocols https
-
Check that the services are up:
sudo ./manage.sh status curl http://127.0.0.1:16000/health
INSTALL.md covers installing by hand and every setting.
From the install directory:
| Command | Does |
|---|---|
sudo ./manage.sh status |
Show each service's state |
sudo ./manage.sh logs |
Follow the service logs |
sudo ./manage.sh start, stop, restart |
Control every service together |
sudo ./manage.sh enable, disable |
Start the services on boot, or stop doing so |
sudo ./manage.sh update |
Pull the latest code, rebuild and restart; add --migrate when the release has migrations |
sudo ./manage.sh migrate |
Apply database migrations |
sudo ./manage.sh check |
Report every missing or invalid setting |
sudo ./manage.sh nginx [DOMAIN] |
Re-render the nginx site and reattach or obtain its certificate |
sudo ./manage.sh uninstall |
Remove the services and the install directory |
See Service Management for log filters and what update and nginx do.
-
Clone the repository with its submodule:
git clone --recurse-submodules https://github.com/smswithoutborders/RelaySMS-Publisher.git cd RelaySMS-Publisher -
Create
.envwith fresh encryption keys:cp template.env .env for key in DATABASE_ENCRYPTION_KEY DATABASE_FIELD_ENCRYPTION_KEY DATA_ENCRYPTION_KEY; do sed -i "s/^$key=$/$key=$(openssl rand -hex 32)/" .env done
-
Build and start:
docker compose up -d --build
The container applies pending migrations, then starts every service. It listens on PORT (16000) and GRPC_PORT (6000) from .env, and keeps its data in ./data.
Caution
Back up .env with ./data: its encryption keys are the only way to read the data.
CONTRIBUTING.md walks through setting up, running the services locally, testing and making common changes. In short:
git clone --recurse-submodules https://github.com/smswithoutborders/RelaySMS-Publisher.git
cd RelaySMS-Publisher
python3 -m venv venv && source venv/bin/activate
pip install -r requirements-dev.txt
pre-commit install --install-hooks
make buildThen follow Run locally. To fill a local database with sample data:
python -m publisher seed stats --count 5000 --days 90 # publication stats
python -m publisher seed creds --count 5 # credentials; prints their passwords
python -m publisher seed platforms # adapter rows, without their files
python -m publisher seed gateway-clients --count 10 # gateway clients, some disabledSettings live in .env. template.env lists every setting with its default and what it does, and python -m publisher config check (or sudo ./manage.sh check on a server) reports any that are missing or invalid.
| Settings | Documented in |
|---|---|
| Server, database, encryption, Celery, adapters | INSTALL.md |
REST API login and sessions (AUTH_*) |
REST API |
SMTP transport (SMTP_*) |
SMTP Transport |
Twilio SMS transport (TWILIO_*) |
The comments in template.env |
Tracing, metrics and logs (OTEL_*) |
Observability |
Offline publishing (OFFLINE_PUBLISH_*) |
Below |
Offline payloads are tagged with the protocol they arrived on: https for REST /publications, smtp for the SMTP transport and sms for the Twilio webhook.
OFFLINE_PUBLISH_ALLOWED_PROTOCOLS=smtp # comma-separated; empty allows every protocol
OFFLINE_PUBLISH_SHARED_SECRET= # 64-char hex; empty disables the checkOffline payloads from a protocol not in OFFLINE_PUBLISH_ALLOWED_PROTOCOLS are discarded. When OFFLINE_PUBLISH_SHARED_SECRET is set, offline payloads over https must carry it in the request's tag field.
Warning
https is unauthenticated, so anyone can send to it. The SMTP and Twilio listeners authenticate the sender (DKIM and an allowlist for smtp, Twilio's signature for sms), which is why template.env allows only smtp.
Each platform is served by an adapter installed from its own repository. GET /v1/platforms lists the enabled ones.
docs/platforms.md covers adding, updating, disabling and removing adapters. Each adapter's README covers its own settings.
Gateway clients are the phone numbers that relay SMS to this server. GET /v1/gateway-clients lists the enabled ones, and docs/gateway-clients.md covers managing them.
Credentials log in to the REST API, each with its own scopes. One holding every scope is an administrator. They can also be managed over the REST API.
./publisher.sh creds scopes # list scopes
./publisher.sh creds create --username ops --administrator # prints the password once
./publisher.sh creds create --username analyst --scope stats:publications:read
./publisher.sh creds set-scopes --username analyst --scope stats:publications:read --scope stats:publications:reasons
./publisher.sh creds list
./publisher.sh creds reset-password --username analyst
./publisher.sh creds disable --username analyst
./publisher.sh creds enable --username analyst
./publisher.sh creds revoke-sessions --username analyst
./publisher.sh creds delete --username analyst- Installation Guide: installing by hand and every setting
- REST API: publishing, authentication and the OpenAPI reference
- gRPC API: linking accounts and syncing keys
- SMTP Transport: publishing payloads sent by email
- Platform Adapters: installing and managing adapters
- Gateway Clients: managing gateway clients
- Observability: tracing, metrics, logs and uptime monitoring
- Reference Client: exercising the gRPC and REST flows by hand
- Contributing: setup, workflow, conventions and testing
Licensed under the GNU General Public License v3. See LICENSE.