obscura-server 0.3.11

A server for relaying secure messages using the Signal Protocol
Documentation

Obscura Server

Obscura Server is a minimalist, secure relay server for the Signal Protocol. It facilitates end-to-end encrypted asynchronous messaging while knowing nothing about the content of the messages.

Features

  • Zero-Knowledge Architecture: The server stores opaque encrypted blobs. It cannot read message content.
  • Signal Protocol Support: Uses PreKeys (Identity, Signed, One-Time) to enable X3DH key exchanges.
  • Asynchronous Delivery: Stores encrypted messages until the recipient comes online to fetch them.
  • Encrypted Attachments: Supports secure file uploads via S3-compatible storage with automated expiry.
  • Strict Privacy Limits: Automatic garbage collection of old messages and global inbox limits to prevent metadata buildup.
  • OpenTelemetry Native: Built-in support for Traces, Metrics, and Structured Logging via OTLP.
  • Container Native: Built with Docker in mind for easy deployment.
  • Configurable: Fully configurable via command-line flags or environment variables.

Configuration

Obscura Server can be configured using either command-line options or by setting corresponding environment variables. Command-line options take precedence over environment variables.

General Configuration

Option Description Environment Variable Default Required
--database-url PostgreSQL connection string OBSCURA_DATABASE_URL postgres://user:password@localhost/signal_server No
--ttl-days Global days before messages/attachments are auto-deleted OBSCURA_TTL_DAYS 30 No
--jwt-secret Secret key for signing JWTs OBSCURA_JWT_SECRET change_me_in_production No

Server Configuration

Option Description Environment Variable Default
--server-host Interface to bind the server to OBSCURA_HOST 0.0.0.0
--server-port Port to bind the server to OBSCURA_PORT 3000
--mgmt-port Management port for health/metrics OBSCURA_MGMT_PORT 9090
--shutdown-timeout-secs Timeout for background tasks during shutdown OBSCURA_SHUTDOWN_TIMEOUT_SECS 5
--trusted-proxies CIDR ranges of trusted proxies OBSCURA_TRUSTED_PROXIES 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.1/32

Rate Limiting

Option Description Environment Variable Default
--rate-limit-per-second API requests allowed per second OBSCURA_RATE_LIMIT_PER_SECOND 10
--rate-limit-burst Max API burst allowance per IP OBSCURA_RATE_LIMIT_BURST 20
--auth-rate-limit-per-second Auth requests allowed per second OBSCURA_AUTH_RATE_LIMIT_PER_SECOND 1
--auth-rate-limit-burst Auth API burst allowance per IP OBSCURA_AUTH_RATE_LIMIT_BURST 3

Storage Configuration (Attachments)

Option Description Environment Variable Default
--storage-bucket Storage Bucket Name OBSCURA_STORAGE_BUCKET obscura-attachments
--storage-region Storage Region OBSCURA_STORAGE_REGION us-east-1
--storage-endpoint Custom Storage Endpoint (e.g., for MinIO) OBSCURA_STORAGE_ENDPOINT -
--storage-access-key Storage Access Key ID OBSCURA_STORAGE_ACCESS_KEY -
--storage-secret-key Storage Secret Access Key OBSCURA_STORAGE_SECRET_KEY -
--storage-force-path-style Force Path Style (Required for MinIO) OBSCURA_STORAGE_FORCE_PATH_STYLE false
--storage-max-size-bytes Max attachment size in bytes OBSCURA_STORAGE_MAX_SIZE_BYTES 52428800
--storage-cleanup-interval-secs How often to run attachment cleanup OBSCURA_STORAGE_CLEANUP_INTERVAL_SECS 3600
--storage-cleanup-batch-size Max attachments to delete per batch OBSCURA_STORAGE_CLEANUP_BATCH_SIZE 100

Messaging & Notifications

Option Description Environment Variable Default
--max-inbox-size Max pending messages per user OBSCURA_MAX_INBOX_SIZE 1000
--messaging-cleanup-interval-secs How often to run message cleanup OBSCURA_MESSAGING_CLEANUP_INTERVAL_SECS 300
--batch-limit Max messages sent per DB fetch loop OBSCURA_BATCH_LIMIT 50
--pre-key-refill-threshold Threshold to trigger client refill notification OBSCURA_PRE_KEY_REFILL_THRESHOLD 20
--max-pre-keys Max One-Time PreKeys allowed per user OBSCURA_MAX_PRE_KEYS 100
--gc-interval-secs How often to run notification cleanup OBSCURA_GC_INTERVAL_SECS 60
--channel-capacity Capacity of the notification channel OBSCURA_CHANNEL_CAPACITY 16

WebSocket Configuration

Option Description Environment Variable Default
--ws-outbound-buffer-size WS outbound channel capacity OBSCURA_WS_OUTBOUND_BUFFER_SIZE 32
--ws-ack-buffer-size WS ACK channel capacity OBSCURA_WS_ACK_BUFFER_SIZE 100
--ws-ack-batch-size WS ACK DB batch size OBSCURA_WS_ACK_BATCH_SIZE 50
--ws-ack-flush-interval-ms WS ACK DB flush interval OBSCURA_WS_ACK_FLUSH_INTERVAL_MS 500

Telemetry & Health

Option Description Environment Variable Default
--otlp-endpoint OTLP endpoint for traces/metrics OBSCURA_OTLP_ENDPOINT -
--log-format Log format (text or json) OBSCURA_LOG_FORMAT text
--metrics-export-interval-secs How often to export metrics OBSCURA_TELEMETRY_METRICS_EXPORT_INTERVAL_SECS 60
--export-timeout-secs OTLP export timeout OBSCURA_TELEMETRY_EXPORT_TIMEOUT_SECS 10
--db-timeout-ms Timeout for DB health check OBSCURA_HEALTH_DB_TIMEOUT_MS 2000
--storage-timeout-ms Timeout for storage health check OBSCURA_STORAGE_HEALTH_TIMEOUT_MS 2000

Example

# Using Flags
./obscura-server \
  --database-url postgres://user:pass@localhost/db \
  --jwt-secret my_secret \
  --storage-bucket my-attachments \
  --server-port 8080

# Using Environment Variables
export OBSCURA_DATABASE_URL=postgres://user:pass@localhost/db
export OBSCURA_JWT_SECRET=my_secret
export OBSCURA_STORAGE_BUCKET=my-attachments
./obscura-server

Docker

A Dockerfile is included for easy deployment.

Build and Run

  1. Build the image:

    docker build -t obscura-server .
    
  2. Run with Docker:

    docker build -t obscura-server .
    docker run -d \
      -p 3000:3000 \
      -p 9090:9090 \
      -e OBSCURA_DATABASE_URL="postgres://user:pass@host.docker.internal:5432/obscura" \
      -e OBSCURA_JWT_SECRET="your_secret_key" \
      -e OBSCURA_STORAGE_BUCKET="obscura-attachments" \
      obscura-server
    

Docker Compose

A docker-compose.yml is provided for a complete local stack (Postgres + Server):

docker compose up -d

Development

Prerequisites

  • Rust 1.83+
  • PostgreSQL 16+
  • protoc (Protocol Buffers compiler)

Running Locally

  1. Start Postgres and MinIO:

    docker compose up -d db minio
    
  2. Run the server:

    export OBSCURA_DATABASE_URL=postgres://user:password@localhost/signal_server
    export OBSCURA_JWT_SECRET=test
    export OBSCURA_STORAGE_BUCKET=test
    cargo run
    

    Migrations are applied automatically on startup.

Testing

cargo test

Releasing

Releases are managed via GitHub Actions.

  1. Go to the Actions tab in the GitHub repository.
  2. Select the Bump Version & Tag workflow on the left.
  3. Click Run workflow.
  4. Select the Bump Type from the dropdown (patch, minor, or major).
  5. Click Run workflow.

The system will automatically:

  1. Bump the version in Cargo.toml based on your selection.
  2. Commit and Tag the release.
  3. Trigger the Publish Release workflow to build and publish artifacts to Crates.io and GHCR.

API Documentation

  • REST API: Defined in openapi.yaml.
  • WebSocket: Available at /v1/gateway. Expects Protobuf messages defined in proto/obscura/v1/obscura.proto.

License

Copyright (c) 2026 Nolan Cooper

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/.