Skip to Content
DeploymentSignaling server

Deploying the signaling server

The server is a single statically-linkable Rust binary. Deployment is “get the binary onto a host and put TLS in front of it.”

Build

cd server cargo build --release # → target/release/omnicall-signaling (LTO, 1 codegen unit, stripped)

For a fully static musl binary (portable across distros):

rustup target add x86_64-unknown-linux-musl cargo build --release --target x86_64-unknown-linux-musl

Building on Windows

The Windows dev machine has a link.exe collision - GNU coreutils link shadows the MSVC linker - so the server is built on the Linux host, not the dev laptop. If you hit this, prepend the MSVC toolchain’s bin directory to PATH or build in WSL.

Run

./omnicall-signaling # ========================================= # WebRTC Signaling Server Running (Rust) # Bound Address: 0.0.0.0:8080 # =========================================

Environment:

VarDefaultNotes
HOST0.0.0.0Bind address. Set to 127.0.0.1 when a reverse proxy is on the same host.
PORT8080
RUST_LOGinfo,tower_http=warndebug logs every relayed frame.

The process handles SIGINT (Ctrl-C) with a graceful shutdown.

systemd unit

# /etc/systemd/system/omnicall.service [Unit] Description=Viora signaling server After=network.target [Service] Type=simple User=omnicall Environment=HOST=127.0.0.1 Environment=PORT=8080 Environment=RUST_LOG=info ExecStart=/opt/omnicall/omnicall-signaling Restart=on-failure RestartSec=2 # hardening - the process needs nothing but a socket NoNewPrivileges=true ProtectSystem=strict ProtectHome=true PrivateTmp=true [Install] WantedBy=multi-user.target
sudo systemctl enable --now omnicall

TLS + WebSocket proxy

The Android app connects with wss:// - you must terminate TLS in front of the binary. The proxy has to pass the WebSocket Upgrade/Connection headers through.

call.example.com { reverse_proxy 127.0.0.1:8080 }

Caddy handles the certificate and WebSocket upgrade automatically. This is the whole config.

Point the app at it

Settings → Server → Signaling server URL:

wss://call.example.com/

The trailing / matters - the client connects to the server root, which is where the upgrade is served.

Verify

# from the server host curl -i http://127.0.0.1:8080/ # → 404 Not Found (correct - not an upgrade) # WebSocket smoke test (needs websocat or wscat) websocat wss://call.example.com/ > {"type":"join","roomId":"test","peerId":"a","payload":{"name":"A"}} < {"type":"room-joined","roomId":"test","peerId":"a","peers":[]}

Resource footprint

  • Memory: a few MB idle; each room is a HashMap entry plus one unbounded channel per peer. A handful of concurrent calls is kilobytes.
  • CPU: effectively zero - it copies small JSON frames between channels.
  • Network: signaling only. Media never touches the server, so bandwidth is negligible regardless of call resolution.
  • Disk: none. No logs are written unless you redirect them; no state is persisted.

A $5/month VPS runs this comfortably for any number of pairs you’d realistically have.

What is not handled

  • No rate limiting. A malicious client can spam frames. Put it behind a proxy with connection limits if that matters.
  • No auth. Anyone who knows a room code and your server URL can join that room. Use unguessable room codes.
  • No horizontal scaling. State is in-process. Two server instances don’t share rooms. For Viora’s scale (pairs of people you know) this is fine.