JVB port/advertise IPs from env; network options A/B/C in README

This commit is contained in:
crm-calls agent
2026-10-14 16:15:00 +00:00
parent dda1ec27cc
commit 22444286bd
2 changed files with 76 additions and 47 deletions

109
README.md
View File

@@ -24,56 +24,85 @@ Colibri-websocket у цій версії Jitsi не використовуєть
- `JICOFO_AUTH_PASSWORD` — пароль jicofo у prosody
- `JVB_AUTH_PASSWORD` — пароль jvb у prosody
Необов'язкові (є значення за замовчуванням у compose):
Мережеві (задані в Coolify env, змінюються без правок у репозиторії):
- `PUBLIC_URL` (`https://crm-calls.tes.gd`)
- `JVB_ADVERTISE_IPS` (`46.101.119.200,192.168.50.73`)
- `TZ` (`Europe/Kyiv`), `DEFAULT_LANGUAGE` (`uk`), `JITSI_IMAGE_VERSION` (`stable-11248`)
- `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`).
Публічна адреса `46.101.119.200`, сервер `storage` — `192.168.50.73` у внутрішній мережі.
Після зміни env — Redeploy застосунку в Coolify.
| Звідки (зовні) | Куди | Протокол | Навіщо |
|------------------------------|----------------------------|----------|--------|
| `46.101.119.200:10000` | `192.168.50.73:10000` | **UDP** | медіа JVB (обов'язково) |
| `46.101.119.200:80, 443` | `192.168.50.73:80, 443` | TCP | вже працює (Traefik) |
## Мережа
Також на самому `storage` має бути відкритий вхідний UDP 10000 (якщо там є ufw/iptables;
порт, опублікований Docker, зазвичай проходить повз ufw).
- `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:
```sh
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
```sh
# на storage:
sudo tcpdump -ni any udp port 10000
# ззовні:
echo test | nc -u -w1 46.101.119.200 10000
sudo tcpdump -ni any udp port 10000 # на storage
echo test | nc -u -w1 <публічна-IP> 10000 # ззовні
```
У tcpdump має з'явитися пакет. Під час дзвінка в `chrome://webrtc-internals` вибрана
ICE-пара має бути з віддаленою адресою `46.101.119.200:10000`.
Без UDP 10000 сторінка й кімната відкриваються, але дзвінок з 3+ учасниками (через JVB) не матиме
звуку/відео. Дзвінок удвох може працювати в режимі P2P (напряму між браузерами через STUN),
але не за суворим NAT/корпоративним файрволом — для цього потрібен TURN.
## TURN (на майбутнє)
Потрібен для клієнтів, у яких UDP заблоковано (корпоративні мережі, частина мобільних операторів).
1. Додати сервіс `coturn` (наприклад `coturn/coturn`) у compose або окремим застосунком у Coolify,
`network_mode: host` або опублікувати порти.
2. Пробросити на роутері до `192.168.50.73`:
- `3478` UDP і TCP (TURN/STUN),
- `5349` TCP (TURNS/TLS) — або краще TURNS на 443 окремої IP/піддомену, бо 443 вже зайнятий Traefik,
- діапазон relay-портів, напр. `49160-49200` UDP (задається в `min-port`/`max-port` coturn).
3. coturn: `external-ip=46.101.119.200/192.168.50.73`, `realm=crm-calls.tes.gd`,
`use-auth-secret`, `static-auth-secret=<секрет у Coolify env>`, TLS-сертифікат для домену
TURN (напр. `turn.tes.gd`) для 5349.
4. Jitsi: задати в env prosody `TURN_HOST=turn.tes.gd`, `TURN_PORT=3478`, `TURNS_HOST=turn.tes.gd`,
`TURNS_PORT=5349`, `TURN_CREDENTIALS=<той самий секрет>`, `TURN_TRANSPORT=udp,tcp`
(prosody через `mod_external_services` роздає клієнтам тимчасові TURN-облікові дані).
Під час дзвінка в `chrome://webrtc-internals` вибрана ICE-пара має вести на `<публічна-IP>:10000`.
## Вбудовування (iframe) у вікі / CRM

View File

@@ -5,7 +5,7 @@
# https://crm-calls.tes.gd (443, Coolify Traefik) -> web:8000 (nginx)
# / -> Jitsi web app
# /xmpp-websocket -> prosody:5280 (proxied by web's nginx)
# UDP 10000 -> jvb (media + SCTP bridge channel), published on the host, bypasses Traefik.
# UDP JVB_PORT (10000) -> jvb (media + SCTP bridge channel), published on the host, bypasses Traefik.
#
# Secrets (JICOFO_AUTH_PASSWORD, JVB_AUTH_PASSWORD) live only in Coolify env vars.
@@ -99,9 +99,9 @@ services:
- /run:size=32M,mode=1750,exec
- /tmp:size=16M,mode=1777,noexec
ports:
# Media must reach JVB directly (not via Traefik). Router must forward
# public 46.101.119.200:10000/udp -> 192.168.50.73:10000/udp.
- '10000:10000/udp'
# Media must reach JVB directly (not via Traefik). How the public UDP port
# reaches storage is not decided yet (see README); port and advertised IPs come from Coolify env.
- '${JVB_PORT:-10000}:${JVB_PORT:-10000}/udp'
volumes:
- jitsi-jvb-config:/config
environment:
@@ -112,9 +112,9 @@ services:
XMPP_AUTH_DOMAIN: auth.meet.jitsi
XMPP_INTERNAL_MUC_DOMAIN: internal-muc.meet.jitsi
JVB_AUTH_PASSWORD: '${JVB_AUTH_PASSWORD}'
JVB_PORT: '10000'
# Public IP first; LAN IP lets clients inside 192.168.50.0/24 connect without hairpin NAT.
JVB_ADVERTISE_IPS: '${JVB_ADVERTISE_IPS:-46.101.119.200,192.168.50.73}'
JVB_PORT: '${JVB_PORT:-10000}'
# Comma-separated, set in Coolify env: public IP of the chosen UDP path + LAN IP 192.168.50.73.
JVB_ADVERTISE_IPS: '${JVB_ADVERTISE_IPS:-192.168.50.73}'
depends_on:
- prosody