crm-calls

Jitsi Meet для Tvorymo CRM: https://crm-calls.tes.gd

Розгортання: Coolify (сервер storage, 192.168.50.73), застосунок crm-calls, build pack dockercompose, файл docker-compose.yml. Основа: офіційний docker-jitsi-meet, образи stable-11248.

Сервіси

Сервіс Що робить Як доступний ззовні
web nginx + веб-застосунок Jitsi HTTPS 443 через Traefik (Coolify) → web:8000
prosody XMPP-сервер лише wss://crm-calls.tes.gd/xmpp-websocket (проксі через web)
jicofo фокус конференцій ззовні не доступний
jvb відеоміст (медіа) UDP 10000 напряму, повз Traefik

Colibri-websocket у цій версії Jitsi не використовується: канал «клієнт ↔ JVB» іде через SCTP усередині того самого медіа-з'єднання (UDP 10000). Тому через 443 ходять лише веб і XMPP.

Змінні оточення (Coolify)

Секрети задаються лише в env застосунку в Coolify, у репозиторії їх немає:

  • JICOFO_AUTH_PASSWORD — пароль jicofo у prosody
  • JVB_AUTH_PASSWORD — пароль jvb у prosody

Мережеві (задані в Coolify env, змінюються без правок у репозиторії):

  • JVB_PORT — UDP-порт JVB, публікується на хості storage (зараз 10000)
  • JVB_ADVERTISE_IPS — адреси, які JVB повідомляє клієнтам, через кому (зараз 192.168.50.73, тобто лише LAN — публічний UDP-шлях ще не вибрано)

Інші: PUBLIC_URL (https://crm-calls.tes.gd), TZ (Europe/Kyiv), DEFAULT_LANGUAGE (uk), JITSI_IMAGE_VERSION (stable-11248).

Після зміни env — Redeploy застосунку в Coolify.

Мережа

  • 46.101.119.200 — VPS у DigitalOcean (туди веде *.tes.gd), відкриті лише TCP 22/80/443, TCP 443 прозоро передається на Traefik на storage (сертифікати Let's Encrypt видає Traefik на storage).
  • storage — 192.168.50.73, вихід в інтернет через Netia 195.128.172.198, вхідні порти закриті.

Веб і XMPP (TCP 443) уже працюють. Для медіа JVB потрібен вхідний UDP до 192.168.50.73:$JVB_PORT. Без нього сторінка й кімната відкриваються, але звуку/відео в конференції через JVB не буде (дзвінок удвох іноді працює P2P напряму між браузерами).

Варіант треба вибрати один (або A/B + C як запасний для корпоративних мереж).

Варіант A — проброс на роутері Netia (найкраща якість)

  1. Переконатися, що 195.128.172.198 — статична «біла» адреса саме на WAN роутера (не CGNAT): WAN IP у панелі роутера має збігатися з 195.128.172.198. Якщо ні — замовити в Netia статичну публічну IP.
  2. На роутері: port forwarding UDP 10000 з WAN 195.128.172.198:10000 → 192.168.50.73:10000.
  3. Якщо на storage є ufw/iptables — дозволити вхідний UDP 10000.
  4. У Coolify env: JVB_ADVERTISE_IPS=195.128.172.198,192.168.50.73 → Redeploy.

Варіант B — UDP через VPS 46.101.119.200 і WireGuard

Storage сам підключається до VPS (вихідне з'єднання, вхідні порти на Netia не потрібні).

  1. DigitalOcean Cloud Firewall + ufw на VPS: відкрити вхідні UDP 10000 і UDP 51820 (WireGuard).
  2. WireGuard: VPS 10.88.0.1/24 (ListenPort 51820), storage 10.88.0.2/24, у storage Endpoint = 46.101.119.200:51820, PersistentKeepalive = 25, AllowedIPs = 10.88.0.1/32.
  3. На VPS:
    sysctl -w net.ipv4.ip_forward=1   # і в /etc/sysctl.conf
    iptables -t nat -A PREROUTING -i eth0 -p udp --dport 10000 -j DNAT --to-destination 10.88.0.2:10000
    iptables -t nat -A POSTROUTING -o wg0 -p udp -d 10.88.0.2 --dport 10000 -j MASQUERADE
    iptables -A FORWARD -i eth0 -o wg0 -p udp -d 10.88.0.2 --dport 10000 -j ACCEPT
    iptables -A FORWARD -i wg0 -o eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT
    
    (MASQUERADE потрібен, щоб відповіді JVB поверталися тим самим тунелем, а не через Netia.)
  4. Storage: дозволити вхідний UDP 10000 з wg0.
  5. У Coolify env: JVB_ADVERTISE_IPS=46.101.119.200,192.168.50.73 → Redeploy.

Мінуси: весь медіатрафік іде через VPS (додаткова затримка і трафік DigitalOcean).

Варіант C — TURN на 443 (TURNS через Traefik, нових портів не треба)

Працює навіть там, де дозволено лише TCP 443 (корпоративні мережі). Якість гірша (медіа по TCP/TLS).

  1. DNS: turn.tes.gd уже веде на 46.101.119.200 (wildcard) — нічого не робити.
  2. Додати сервіс coturn (образ coturn/coturn) у compose, слухає TCP 3478 лише у внутрішній мережі. Конфіг: use-auth-secret, static-auth-secret=$TURN_CREDENTIALS, realm=crm-calls.tes.gd, no-tls, no-udp на слухачі (клієнт ↔ coturn — TCP), allowed-peer-ip=192.168.50.73, denied-peer-ip для інших приватних діапазонів.
  3. Traefik (Coolify): TCP-роутер HostSNI(turn.tes.gd) на entrypoint https з TLS (certresolver letsencrypt) → coturn:3478. Тобто Traefik знімає TLS і передає TURN-потік у coturn.
  4. У Coolify env (секрет лише там): TURN_CREDENTIALS=<випадковий рядок>, TURNS_HOST=turn.tes.gd, TURNS_PORT=443, TURN_TRANSPORT=tcp → Redeploy. Prosody (mod_external_services) роздає клієнтам тимчасові TURN-облікові дані; coturn ретранслює медіа на JVB 192.168.50.73:10000 всередині LAN.
  5. На роутері/VPS нічого відкривати не потрібно.

Пізніше, за наявності вхідного UDP (A або B), можна додати класичний TURN: 3478 UDP/TCP, 5349 TLS і діапазон relay-портів (напр. 49160–49200 UDP) з external-ip = вибрана публічна адреса.

Перевірка UDP після A або B

sudo tcpdump -ni any udp port 10000          # на storage
echo test | nc -u -w1 <публічна-IP> 10000     # ззовні

Під час дзвінка в chrome://webrtc-internals вибрана ICE-пара має вести на <публічна-IP>:10000.

Вбудовування (iframe) у вікі / CRM

  • Jitsi nginx не ставить X-Frame-Options; framing задається через Content-Security-Policy: frame-ancestors 'self' https://*.tes.gd https://test.units.tvorymo.com (змінна CSP_HEADER у compose, сервіс web). Щоб додати домен — дописати його туди.
  • Вбудовувати через https://crm-calls.tes.gd/external_api.js (JitsiMeetExternalAPI), iframe має мати allow="camera; microphone; display-capture; autoplay; clipboard-write; fullscreen".
  • Авторизація (postMessage → JWT) поки не налаштована: кімнати відкриті для всіх, хто знає URL. Для CRM планується ENABLE_AUTH=1, AUTH_TYPE=jwt, JWT_APP_ID, JWT_APP_SECRET (секрет — лише в Coolify).
Description
No description provided
Readme 344 KiB
Languages
C# 72.6%
TypeScript 22.9%
Shell 1.8%
Dockerfile 1.2%
JavaScript 0.8%
Other 0.7%