Deploying

trueseal-relay ships as a single binary. Deployment requires three things: a keypair, a config, and a storage backend.

Source: github.com/julianbonomini/trueseal-relay — binary releases on the repo’s Releases page.

Keypair Generation

The relay identity is a long-term X25519 keypair. Generate it once at setup:

trueseal-relay -genkey -keyout keypair.hex

This writes the hex-encoded private key to keypair.hex (mode 0600) and prints the public key to stdout:

keypair written to keypair.hex
relay public key (share with clients): a1b2c3d4...

Guard the private key. Anyone with it can impersonate your relay — devices verify the relay’s identity via this key on every handshake. The public key is safe to share freely — bake it into your client binary, publish it on your landing page, or include it in your self-hosting README.

Note: Relay impersonation does not compromise data security. All blobs are end-to-end encrypted before they reach the relay — an impersonator receives ciphertext they cannot decrypt. The impact is limited to delivery: blobs pushed to a rogue relay will not reach their recipients. No data is exposed.

Configuration

trueseal-relay reads config from a TOML file (default relay.toml) with optional environment variable overrides. All TRUESEAL_RELAY_* env vars take precedence over the file.

Minimal relay.toml:

[relay]
keypair_path = "/etc/trueseal-relay/keypair.hex"

[store]
type = "sqlite"
sqlite_path = "/var/lib/trueseal-relay/inbox.db"

Full reference:

FieldEnv varDefaultDescription
relay.keypair_pathTRUESEAL_RELAY_KEYPAIR_PATHPath to hex-encoded private key. Required.
relay.listen_pushTRUESEAL_RELAY_LISTEN_PUSH:7701Push Session listener address.
relay.listen_receiveTRUESEAL_RELAY_LISTEN_RECEIVE:7700Receive Session listener address.
relay.ttlTRUESEAL_RELAY_TTL720h (30 days)Blob TTL before reaping.
relay.reap_intervalTRUESEAL_RELAY_REAP_INTERVAL1hHow often the reaper runs.
relay.max_envelope_bytesTRUESEAL_RELAY_MAX_ENVELOPE_BYTES1048576 (1 MiB)Max envelope size. Blobs exceeding this are rejected with Error.
store.typeTRUESEAL_RELAY_STORE_TYPEsqliteStorage backend: sqlite or postgres.
store.sqlite_pathTRUESEAL_RELAY_STORE_SQLITE_PATHSQLite database file path. Required when store.type = sqlite.

Single-Node Deployment

The default and recommended setup for self-hosted instances. Uses SQLite — no external dependencies.

trueseal-relay -config relay.toml

Or Docker-friendly with no config file:

trueseal-relay -no-config

With -no-config, all settings must be provided via environment variables.

Example docker-compose.yml:

services:
  trueseal-relay:
    image: trueseal-relay:latest
    command: ["-no-config"]
    environment:
      TRUESEAL_RELAY_KEYPAIR_PATH: /secrets/keypair.hex
      TRUESEAL_RELAY_STORE_SQLITE_PATH: /data/inbox.db
    volumes:
      - ./keypair.hex:/secrets/keypair.hex:ro
      - relay-data:/data
    ports:
      - "7700:7700"
      - "7701:7701"

volumes:
  relay-data:

Graceful Shutdown

trueseal-relay handles SIGINT and SIGTERM. On signal, it stops accepting new connections and waits up to 30 seconds for active sessions to drain cleanly before exiting.

Operational Notes

  • Firewall. Open TCP ports 7700 (receive) and 7701 (push) to the internet. Devices connect outbound — no inbound connections from the relay.
  • Disk. Size SQLite storage based on your expected group size, blob size, and TTL. A conservative estimate: (devices × blobs_per_day × avg_blob_bytes × ttl_days).
  • Logs. trueseal-relay logs connection events and public keys only. It never logs envelope content. Do not add content logging — it would break the zero-knowledge property.