Hello,
I am trying to deploy a Jitsi-meet environment like meet.jit.si.
At first it works, but when a participant is behind a firewall that only allows ports 80 and 443, the video and the screenshare connection doesn’t work.
I followed the following procedure:
I tried to implement the solution with nginx multiplexing with coturn but I couldn’t do it.
The server works fine except in this context
My configuration
/etc/nginx/sites-enabled/jitsi.domain.com.conf
server_names_hash_bucket_size 64;
types {
# nginx's default mime.types doesn't include a mapping for wasm
application/wasm wasm;
}
server {
listen 80;
listen [::]:80;
server_name jitsi.domain.com;
location ^~ /.well-known/acme-challenge/ {
default_type "text/plain";
root /usr/share/jitsi-meet;
}
location = /.well-known/acme-challenge/ {
return 404;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 4444 ssl;
listen [::]:4444 ssl;
server_name jitsi.domain.com;
# Mozilla Guideline v5.4, nginx 1.17.7, OpenSSL 1.1.1d, intermediate configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m; # about 40000 sessions
ssl_session_tickets off;
add_header Strict-Transport-Security "max-age=63072000" always;
set $prefix "";
ssl_certificate /etc/letsencrypt/live/jitsi.domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/jitsi.domain.com/privkey.pem;
root /usr/share/jitsi-meet;
# ssi on with javascript for multidomain variables in config.js
ssi on;
ssi_types application/x-javascript application/javascript;
index index.html index.htm;
error_page 404 /static/404.html;
gzip on;
gzip_types text/plain text/css application/javascript application/json image/x-icon application/octet-stream application/wasm;
gzip_vary on;
gzip_proxied no-cache no-store private expired auth;
gzip_min_length 512;
location = /config.js {
alias /etc/jitsi/meet/jitsi.domain.com-config.js;
}
location = /external_api.js {
alias /usr/share/jitsi-meet/libs/external_api.min.js;
}
# ensure all static content can always be found first
location ~ ^/(libs|css|static|images|fonts|lang|sounds|connection_optimization|.well-known)/(.*)$
{
add_header 'Access-Control-Allow-Origin' '*';
alias /usr/share/jitsi-meet/$1/$2;
# cache all versioned files
if ($arg_v) {
expires 1y;
}
}
# BOSH
location = /http-bind {
proxy_pass http://127.0.0.1:5280/http-bind?prefix=$prefix&$args;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $http_host;
}
# xmpp websockets
location = /xmpp-websocket {
proxy_pass http://127.0.0.1:5280/xmpp-websocket?prefix=$prefix&$args;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $http_host;
tcp_nodelay on;
}
# colibri (JVB) websockets for jvb1
location ~ ^/colibri-ws/default-id/(.*) {
proxy_pass http://127.0.0.1:9090/colibri-ws/default-id/$1$is_args$args;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
tcp_nodelay on;
}
# load test minimal client, uncomment when used
#location ~ ^/_load-test/([^/?&:'"]+)$ {
# rewrite ^/_load-test/(.*)$ /load-test/index.html break;
#}
#location ~ ^/_load-test/libs/(.*)$ {
# add_header 'Access-Control-Allow-Origin' '*';
# alias /usr/share/jitsi-meet/load-test/libs/$1;
#}
location ~ ^/([^/?&:'"]+)$ {
try_files $uri @root_path;
}
location @root_path {
rewrite ^/(.*)$ / break;
}
location ~ ^/([^/?&:'"]+)/config.js$
{
set $subdomain "$1.";
set $subdir "$1/";
alias /etc/jitsi/meet/jitsi.domain.com-config.js;
}
# BOSH for subdomains
location ~ ^/([^/?&:'"]+)/http-bind {
set $subdomain "$1.";
set $subdir "$1/";
set $prefix "$1";
rewrite ^/(.*)$ /http-bind;
}
# websockets for subdomains
location ~ ^/([^/?&:'"]+)/xmpp-websocket {
set $subdomain "$1.";
set $subdir "$1/";
set $prefix "$1";
rewrite ^/(.*)$ /xmpp-websocket;
}
# Anything that didn't match above, and isn't a real file, assume it's a room name and redirect to /
location ~ ^/([^/?&:'"]+)/(.*)$ {
set $subdomain "$1.";
set $subdir "$1/";
rewrite ^/([^/?&:'"]+)/(.*)$ /$2;
}
}
/etc/nginx/modules-enabled/turnjitsi.conf
stream {
map $ssl_preread_server_name $name {
jitsi.domain.com web_backend;
turn-jitsi-meet.domain.com turn_backend;
}
upstream web_backend {
server 127.0.0.1:4444;
}
upstream turn_backend {
server 127.0.0.1:5349;
}
server {
listen 443;
listen [::]:443;
# since 1.11.5
ssl_preread on;
proxy_pass $name;
# Increase buffer to serve video
proxy_buffer_size 10m;
}
}
/etc/turnserver.conf
# jitsi-meet coturn config. Do not modify this line
keep-address-family
use-auth-secret
lt-cred-mech
fingerprint
static-auth-secret="dMWQB5EqHYuWXHcx"
no-cli
server-name=turn-jitsi-meet.domain.com
realm=turn-jitsi-meet.domain.com
listening-port=3478
cert=/etc/coturn/certs/jitsi.domain.com.fullchain.pem
pkey=/etc/coturn/certs/jitsi.domain.com.privkey.pem
tls-listening-port=5349
fingerprint
#listening-ip=0.0.0.0
no-udp
no-tlsv1
no-tlsv1_1
log-file=/var/log/turnserver/turnserver.log
verbose
# https://ssl-config.mozilla.org/#server=haproxy&version=2.1&config=intermediate&openssl=1.1.0g&guideline=5.4
cipher-list=ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
# jitsi-meet coturn relay disable config. Do not modify this line
denied-peer-ip=0.0.0.0-0.255.255.255
denied-peer-ip=10.0.0.0-10.255.255.255
denied-peer-ip=100.64.0.0-100.127.255.255
denied-peer-ip=127.0.0.0-127.255.255.255
denied-peer-ip=169.254.0.0-169.254.255.255
denied-peer-ip=127.0.0.0-127.255.255.255
denied-peer-ip=172.16.0.0-172.31.255.255
denied-peer-ip=192.0.0.0-192.0.0.255
denied-peer-ip=192.0.2.0-192.0.2.255
denied-peer-ip=192.88.99.0-192.88.99.255
denied-peer-ip=192.168.0.0-192.168.255.255
denied-peer-ip=198.18.0.0-198.19.255.255
denied-peer-ip=198.51.100.0-198.51.100.255
denied-peer-ip=203.0.113.0-203.0.113.255
denied-peer-ip=240.0.0.0-255.255.255.255
denied-peer-ip=::1
denied-peer-ip=64:ff9b::-64:ff9b::ffff:ffff
denied-peer-ip=::ffff:0.0.0.0-::ffff:255.255.255.255
denied-peer-ip=100::-100::ffff:ffff:ffff:ffff
denied-peer-ip=2001::-2001:1ff:ffff:ffff:ffff:ffff:ffff:ffff
denied-peer-ip=2002::-2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff
denied-peer-ip=fc00::-fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
denied-peer-ip=fe80::-febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff
/etc/prosody/conf.d/jitsi.domain.com.cfg.lua
plugin_paths = { "/usr/share/jitsi-meet/prosody-plugins/" }
-- domain mapper options, must at least have domain base set to use the mapper
muc_mapper_domain_base = "jitsi.domain.com";
external_service_secret = "dMWQB5EqHYuWXHcx";
external_services = {
{ type = "stun", host = "turn-jitsi-meet.domain.com", port = 443 },
{ type = "turn", host = "turn-jitsi-meet.domain.com", port = 443, transport = "udp", secret = true, ttl = 86400, algorithm = "turn" },
{ type = "turns", host = "turn-jitsi-meet.domain.com", port = 443, transport = "tcp", secret = true, ttl = 86400, algorithm = "turn" }
};
turncredentials_secret = "dMWQB5EqHYuWXHcx";
turncredentials_port = 443;
turncredentials_ttl = 86400;
turncredentials = {
{ type = "stun", host = "turn-jitsi-meet.domain.com" },
{ type = "turn", host = "turn-jitsi-meet.domain.com", port = 443},
{ type = "turns", host = "turn-jitsi-meet.domain.com", port = 443, transport = "tcp" }
};
cross_domain_bosh = false;
consider_bosh_secure = true;
-- https_ports = { }; -- Remove this line to prevent listening on port 5284
-- https://ssl-config.mozilla.org/#server=haproxy&version=2.1&config=intermediate&openssl=1.1.0g&guideline=5.4
ssl = {
protocol = "tlsv1_2+";
ciphers = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"
}
unlimited_jids = {
"focus@auth.jitsi.domain.com",
"jvb@auth.jitsi.domain.com"
}
VirtualHost "jitsi.domain.com"
-- enabled = false -- Remove this line to enable this host
authentication = "internal_plain"
-- Properties below are modified by jitsi-meet-tokens package config
-- and authentication above is switched to "token"
--app_id="example_app_id"
--app_secret="example_app_secret"
-- Assign this host a certificate for TLS, otherwise it would use the one
-- set in the global section (if any).
-- Note that old-style SSL on port 5223 only supports one certificate, and will always
-- use the global one.
ssl = {
key = "/etc/prosody/certs/jitsi.domain.com.key";
certificate = "/etc/prosody/certs/jitsi.domain.com.crt";
}
av_moderation_component = "avmoderation.jitsi.domain.com"
speakerstats_component = "speakerstats.jitsi.domain.com"
conference_duration_component = "conferenceduration.jitsi.domain.com"
-- we need bosh
modules_enabled = {
"bosh";
"pubsub";
"ping"; -- Enable mod_ping
"speakerstats";
-- "external_services";
"conference_duration";
"muc_lobby_rooms";
"muc_breakout_rooms";
"av_moderation";
"turncredentials";
}
c2s_require_encryption = false
lobby_muc = "lobby.jitsi.domain.com"
breakout_rooms_muc = "breakout.jitsi.domain.com"
main_muc = "conference.jitsi.domain.com"
-- muc_lobby_whitelist = { "recorder.jitsi.domain.com" } -- Here we can whitelist jibri to enter lobby enabled rooms
Component "conference.jitsi.domain.com" "muc"
restrict_room_creation = true
storage = "memory"
modules_enabled = {
"muc_meeting_id";
"muc_domain_mapper";
"polls";
--"token_verification";
"muc_rate_limit";
}
admins = { "focus@auth.jitsi.domain.com" }
muc_room_locking = false
muc_room_default_public_jids = true
Component "breakout.jitsi.domain.com" "muc"
restrict_room_creation = true
storage = "memory"
modules_enabled = {
"muc_meeting_id";
"muc_domain_mapper";
--"token_verification";
"muc_rate_limit";
}
admins = { "focus@auth.jitsi.domain.com" }
muc_room_locking = false
muc_room_default_public_jids = true
-- internal muc component
Component "internal.auth.jitsi.domain.com" "muc"
storage = "memory"
modules_enabled = {
"ping";
}
admins = { "focus@auth.jitsi.domain.com", "jvb@auth.jitsi.domain.com" }
muc_room_locking = false
muc_room_default_public_jids = true
VirtualHost "auth.jitsi.domain.com"
ssl = {
key = "/etc/prosody/certs/auth.jitsi.domain.com.key";
certificate = "/etc/prosody/certs/auth.jitsi.domain.com.crt";
}
modules_enabled = {
"limits_exception";
}
authentication = "internal_hashed"
-- Proxy to jicofo's user JID, so that it doesn't have to register as a component.
Component "focus.jitsi.domain.com" "client_proxy"
target_address = "focus@auth.jitsi.domain.com"
Component "speakerstats.jitsi.domain.com" "speakerstats_component"
muc_component = "conference.jitsi.domain.com"
Component "conferenceduration.jitsi.domain.com" "conference_duration_component"
muc_component = "conference.jitsi.domain.com"
Component "avmoderation.jitsi.domain.com" "av_moderation_component"
muc_component = "conference.jitsi.domain.com"
Component "lobby.jitsi.domain.com" "muc"
storage = "memory"
restrict_room_creation = true
muc_room_locking = false
muc_room_default_public_jids = true
modules_enabled = {
"muc_rate_limit";
"polls";
}
VirtualHost "guest.jitsi.domain.com"
authentication = "anonymous"
modules_enabled = {
"bosh";
"pubsub";
"ping"; -- Enable mod_ping
"speakerstats";
-- "external_services";
"conference_duration";
"muc_lobby_rooms";
"muc_breakout_rooms";
"av_moderation";
"turncredentials";
}
c2s_require_encryption = false
/etc/jitsi/videobridge/sip-communicator.properties
org.ice4j.ice.harvest.DISABLE_AWS_HARVESTER=true
org.ice4j.ice.harvest.STUN_MAPPING_HARVESTER_ADDRESSES=turn-jitsi-meet.domain.com:5349
org.jitsi.videobridge.ENABLE_STATISTICS=true
org.jitsi.videobridge.STATISTICS_TRANSPORT=muc
org.jitsi.videobridge.xmpp.user.shard.HOSTNAME=localhost
org.jitsi.videobridge.xmpp.user.shard.DOMAIN=auth.jitsi.domain.com
org.jitsi.videobridge.xmpp.user.shard.USERNAME=jvb
org.jitsi.videobridge.xmpp.user.shard.PASSWORD=oHB6mEw0
org.jitsi.videobridge.xmpp.user.shard.MUC_JIDS=JvbBrewery@internal.auth.jitsi.domain.com
org.jitsi.videobridge.xmpp.user.shard.MUC_NICKNAME=1978931c-8a3b-45f6-80ca-928370754877
org.jitsi.videobridge.DISABLE_TCP_HARVESTER=true
org.ice4j.ipv6.DISABLED=true
My error in jvb logfile
JVB 2022-02-18 15:45:40.502 WARNING: [65] [confId=bfd670a7d719421f gid=53658 stats_id=Ken-i8S conf_name=static2@conference.jitsi.domain.com ufrag=66mou1fs6o592v epId=5057ea3d local_ufrag=66mou1fs6o592v] ConnectivityCheckClient.startCheckForPair#374: Failed to send BINDING-REQUEST(0x1)[attrib.count=6 len=92 tranID=0x95A6820D7F01A9EE031153B6]
java.lang.IllegalArgumentException: No socket found for __IP_PUBLIC__:10000/udp->172.20.131.6:55307/udp
at org.ice4j.stack.NetAccessManager.sendMessage(NetAccessManager.java:631)
at org.ice4j.stack.NetAccessManager.sendMessage(NetAccessManager.java:581)
at org.ice4j.stack.StunClientTransaction.sendRequest0(StunClientTransaction.java:267)
at org.ice4j.stack.StunClientTransaction.sendRequest(StunClientTransaction.java:245)
at org.ice4j.stack.StunStack.sendRequest(StunStack.java:680)
at org.ice4j.ice.ConnectivityCheckClient.startCheckForPair(ConnectivityCheckClient.java:335)
at org.ice4j.ice.ConnectivityCheckClient.startCheckForPair(ConnectivityCheckClient.java:231)
at org.ice4j.ice.ConnectivityCheckClient$PaceMaker.run(ConnectivityCheckClient.java:938)
at org.ice4j.util.PeriodicRunnable.executeRun(PeriodicRunnable.java:206)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
JVB 2022-02-18 15:45:40.502 INFO: [65] [confId=bfd670a7d719421f gid=53658 stats_id=Ken-i8S conf_name=static2@conference.jitsi.domain.com ufrag=66mou1fs6o592v epId=5057ea3d local_ufrag=66mou1fs6o592v] ConnectivityCheckClient$PaceMaker.run#942: Pair failed: __IP_PUBLIC__:10000/udp/host -> 172.20.131.6:55307/udp/host (stream-5057ea3d.RTP)
JVB 2022-02-18 15:45:45.952 INFO: [26] HealthChecker.run#171: Performed a successful health check in PT0.000009713S. Sticky failure: false
If i try a connection with 3 participants, 2 in a normal network everything works but for the lastest behind firewall more restricted with a proxy there isn’t video and share.
If i try the same test with the meet.jit.si environnement everything works.
Could you help me for debug my configuration please?
Thank you