Svyazist is a small self-hosted PWA for private video calls between family members.
Pure JavaScript, WebRTC - no installation required for end users, no accounts.
Live demo: https://call.wiredgeese.com/
The product is developed together with the OpenAI Codex agent using the ADSM methodology
(Agent-Driven Software Methodology, a context-driven programming approach).
The user interface and the full cognitive-context documentation are in Russian;
see AGENTS.md as the entry point.
This guide describes how to deploy a self-hosted instance of Svyazist using:
- Linux server
- Apache
- HTTPS via Certbot
- Node.js backend (WebSocket signaling)
- Public STUN server (
stun.l.google.com:19302)
TURN is not required in the minimal installation.
Reference version: 0.1.0.
- Linux server with SSH access
- Apache web server with HTTPS support
- Domain name pointing to the server
- Node.js 20+
- Free local port for WebSocket signaling
- Directory for application files
- Ability to download the GitHub release
- Available STUN server (public STUN is sufficient)
- Web server: Apache
- Domain: call.example.com
- HTTPS port: 443
- WebSocket port: 4444
- Installation path:
/home/user/app/svyazist - Application version: 0.1.0
- STUN:
stun.l.google.com:19302
Clone the stable release:
git clone --branch 0.1.0 https://github.com/flancer64/pwa-home-call /home/user/app/svyazistCreate environment file:
cp /home/user/app/svyazist/.env.example /home/user/app/svyazist/.envSet WebSocket signaling port:
WS_PORT=4444
Install backend dependencies:
cd /home/user/app/svyazist
npm ciStart backend to verify installation:
npm startExpected output:
[INFO] Svyazist backend starting.
[INFO] [Signal] WebSocket signaling server started.
[INFO] Svyazist backend started.
Check that the signaling port is open:
ss -tlnp | grep 4444You should see a listener on 0.0.0.0:4444.
Set document root and domain:
DocumentRoot /home/user/app/svyazist/web
ServerName call.example.comRequest TLS certificate:
sudo certbot --apache -d call.example.comAfter successful configuration:
https://call.example.com/should serveindex.html- Browser should show a valid HTTPS certificate
apachectl -Smust show a VirtualHost forcall.example.com:443
Local WebSocket signaling runs on port 4444, public endpoint must be:
wss://call.example.com/signal
Add proxy routes:
ProxyPass "/signal" "ws://127.0.0.1:4444/signal"
ProxyPassReverse "/signal" "ws://127.0.0.1:4444/signal"Enable required modules:
sudo a2enmod proxy proxy_http proxy_wstunnel
sudo systemctl restart apache2Checking modules:
apachectl -M | grep proxyThe WebSocket request should return 101 Switching Protocols.
ICE configuration is located in web/app/Rtc/Peer.mjs:
Default configuration:
iceServers: [{ urls: "stun:stun.l.google.com:19302" }];TURN servers are not used in this setup.
- Open
https://call.example.com/on two devices - Confirm WebSocket signaling works correctly
- Check SDP and ICE candidate exchange (DevTools → Network → WS)
- Initiate a test call and confirm that a direct media connection is established
If no ICE candidates are received, clients may be behind restrictive NAT or blocked UDP traffic. In this case, deploy your own STUN/TURN server (e.g., coturn) to ensure connectivity.
Apache-2.0