Sudden struggles with CORS errors (cross_domain_bosh deprecated?)

hi everyone,

i have a question regarding the lib-jitsi-meet api and cross domain bosh.

i am self hosting a jitsi server on debian 11 with nginx and i am building a custom browser-UI using lib-jitsi-meet. the server is located on a different domain than the UI (the server is on jitsi.mydomain.com and the UI at mydomain.com). I have a server block configured for each domain.

my problem is that all of a sudden (after not touching either the server or the UI code for a week) i cannot connect to the server anymore via the api due to some CORS errors.
At first, I had simply set cross_domain_bosh = true in /etc/prosody/conf.avail/jitsi.mydomain.com.cfg.lua but this seems to have stopped working, so I followed the instructions here and here, but I am still getting these errors:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://jitsi.mydomain.com/http-bind. (Reason: CORS header ‘Access-Control-Allow-Origin’ does not match ‘https://mydomain.com’).

(it is worth noting that the domain displayed here does match the one I specified in the config file)

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://jitsi.mydomain.com/http-bind. (Reason: CORS request did not succeed). Status code: (null).

2022-10-19T07:39:50.941Z [modules/xmpp/strophe.util.js] <6628/ca/mt.Strophe.log>: Strophe: request id 3.3 error 0 happened

I also tried updating prosody to version 0.12, but same story there. (i since downgraded again to 0.11.9). The only change I became aware of was that in version 0.12, the prosody log file suddenly stated that cross_domain_bosh was being deprecated. So as I said, I went back to my previous prosody version.

This is what I have set in /etc/nginx/sites-available/jitsi.mydomain.com.conf (I only included what I believe to be relevant for my problem)

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 imag>
gzip_vary on;
gzip_proxied no-cache no-store private expired auth;
gzip_min_length 512;

location = /config.js {
    alias /etc/jitsi/meet/jitsi.mydomain.com-config.js;
}

location = /external_api.js {
    alias /usr/share/jitsi-meet/libs/external_api.min.js;
}

location = /_api/room-info {
proxy_pass http://prosody/room-info?prefix=$prefix&$args;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $http_host;
}

# ensure all static content can always be found first
location ~ ^/(libs|css|static|images|fonts|lang|sounds|connection_optimizat>
{
    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://localhost:5280;
# http://prosody/http-bind?prefix=$prefix&$args;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host “jitsi.mydomain.com”;
# Host $http_host;
proxy_set_header Connection “”;
add_header ‘Access-Control-Allow-Origin’ “https://mydomain.com”;
add_header ‘Vary’ “Origin”;
}

and this is my config in /etc/prosody/conf.avail/jitsi.mydomain.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.mydomain.com”;

external_service_secret = “mysecret”;
external_services = {
{ type = “stun”, host = “jitsi.mydomain.com”, port = 3478 },
{ type = “turn”, host = “jitsi.mydomain.com”, port = 3478, transport = “udp”, secret = true, ttl = 86400, algorithm = “turn” },>
{ type = “turns”, host = “jitsi.mydomain.com”, port = 5349, transpot = “tcp”, secret = true, ttl = 86400, algorithm = “turn” }

};

– cross_domain_bosh = true;
consider_bosh_secure = true;

asap_accepted_issuers = { “" };
asap_accepted_audiences = { "
” };

I commented cross_domain_bosh = true; out because otherwhise I would get an error stating that multiple ‘Access-Control-Allow-Origin’ headers are not allowed.

Finally, this is my config in /etc/jitsi/meet/jitsi.mydomain.com-config.js

var subdir = ‘’;
var subdomain = ‘’;

if (subdomain) {
subdomain = subdomain.substr(0, subdomain.length - 1).split(‘.’)
.join(‘_’)
.toLowerCase() + ‘.’;
}

// In case of no ssi provided by the webserver, use empty strings
if (subdir.startsWith(‘<!–’)) {
subdir = ‘’;
}
if (subdomain.startsWith(‘<!–’)) {
subdomain = ‘’;
}

var config = {
// Connection
//

hosts: {
    // XMPP domain.
   domain: 'jitsi.mydomain.com',

    // XMPP MUC domain. FIXME: use XEP-0030 to discover it.
    muc: 'conference.' + subdomain + 'jitsi.mydomain.com',
},

// BOSH URL. FIXME: use XEP-0156 to discover it.
bosh: '//<!--# echo var="http_host" -->/<!--# echo var="subdir" default="" -->http-bind',

I would be so grateful for any hints on what could be going wrong!

have a good day everone!

Just a stab in the dark on my part, but how about if you restore cross_domain_bosh = true and in nginx where you explicitly set ‘Access-Control-Allow-Origin’ header you also drop the one being set by prosody?

e.g.

add_header ‘Access-Control-Allow-Origin’ “https://mydomain.com”;
proxy_hide_header Access-Control-Allow-Origin;

hi shawn, thanks a lot for your suggestion!

I tried it but still I am unable to connect to the server :frowning: the errors in the browser’s inspector are gone though.

however, when I call

connection = new JitsiMeetJS.JitsiConnection(null,token,serverOptions);
connection.addEventListener(JitsiMeetJS.events.connection.CONNECTION_ESTABLISHED, onConnectionSuccess);
connection.addEventListener(JitsiMeetJS.events.connection.CONNECTION_FAILED, onConnectionFailed);
connection.addEventListener(JitsiMeetJS.events.connection.CONNECTION_DISCONNECTED, disconnect);
connection.connect();

it still always fails.

and when I try to instantiate a room I get a Focus error:

2022-10-19T10:13:04.725Z [modules/xmpp/moderator.js] <6628/_r.prototype._allocateConferenceFocusError>: Focus error, retry after 4000 Not connected

I’m thinking it might have to do with JWT, but then again, it worked before (I’m just generating a token manually on jwt.io or https://jitok.emrah.com/ and then I have a field in the UI where I can paste the token, so its pretty simple)

But I guess even if the JWT is a issue, it’s still weird that connection.connect() fails before I attempt to do anything in the UI, right?

I’m no expert, but I’d have though you’d see an auth related issue instead of a connection error if the problem was due to an invalid JWT.

Is this rendering to a valid URL? Check it directly on https://jitsi.mydomain.com/config.js

yes thought so too!

yes, so if I go to https://jitsi.mydomain.com/config.js I am shown the config file in the browser.
however, if i go to https://mydomain.com/config.js (mydomain.com is where the website with my custom UI is at) i see 404 not found. could this maybe be the problem? like, do I need to also configure the server block where the UI is at in some specific way?

Yes, that might be the problem. In the default setup, the assumption is that the domain used to host the web app is the same as the xmpp domain. It is possible to resolve this with tweaks in a few places.

Alas, I’m afraid I’m AFK today so easily pull up reference.

But off the top of my head, here are some of the things you need to resolve:

  • Make sure your app is correctly loading config.js file
  • The bosh/websocket address specified in config.js should correctly reference a path that can reach prosody
  • The domain/muc addresses should match the xmpp domain not the web domain
  • The domain specified in jvb.conf should be a valid web address that can reach the JVB.

HTH

thank you so much shawn, this is already a huge help! I’m gonna try to figure this out.

just to be sure, the xmpp domain is the domain that points to my jitsi install, right? (so jitsi.mydomain.com)

maybe i’ll be back with more questions later :smiley: but for now huge thanks!!

hi there, sorry to bother you again!

so I realized that I might as well just store the files of my custom UI in /var/www/jitsi.mydomain.com, since I don’t really need two domains anyways (I was just really confused how the whole thing with lib-jitsi-meet works, which is why I got into the thing with having two domains in the first place).

I also changed my /etc/nginx/sites-available/jitsi.mydomain.com.conf like this:

types {

application/wasm     wasm;
audio/wav            wav;

}
upstream prosody {
zone upstreams 64K;
server 127.0.0.1:5280;
keepalive 2;
}
upstream jvb1 {
zone upstreams 64K;
server 127.0.0.1:9090;
keepalive 2;
}

server {
listen 80;
listen [::]:80;

root /var/www/jitsi.mydomain.com/html;
index index.html index.htm index.nginx-debian.html;

server_name jitsi.mydomain.com;

location = /.well-known/acme-challenge/ {
return 404;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name jitsi.mydomain.com;

*# here is some some mozilla stuff i'm not including because i guess is not interesting for you #*

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.mydomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/jitsi.mydomain.com/privkey.pem;

root /var/www/jitsi.mydomain.com/html;
index index.html index.htm index.nginx-debian.html;


# 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 ap>
gzip_vary on;
gzip_proxied no-cache no-store private expired auth;
gzip_min_length 512;

location = /config.js {
    alias /etc/jitsi/meet/jitsi.mydomain.com-config.js;
}

location = /external_api.js {
    alias /usr/share/jitsi-meet/libs/external_api.min.js;
}

location = /_api/room-info {

proxy_pass http://prosody/room-info?prefix=$prefix&$args;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $http_host;
}

# ensure all static content can always be found first
location ~ ^/(libs|css|static|images|fonts|lang|sounds|connection_optimization|.well-k>
{
    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://localhost:5280;
    # http://prosody/http-bind?prefix=$prefix&$args;
    proxy_http_version 1.1;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header Host "jitsi.mydomain.com";
    # Host $http_host;
    proxy_set_header Connection "";

}

(there is more code under this but i think its not relevant for my question)

and now, jitsi.mydomain.com points to my custom UI (which is what I wanted!).
However, connection.connect() still fails.

I checked prosody.log and it gives the following strange info:

portmanager info Activated service ‘legacy_ssl’ on no ports
portmanager info Activated service ‘https’ on no ports

So I was just wondering if I am doing something strange here that is not supposed to work? Or did I just maybe misspell something somewhere/need to reconfigure another file? In the latter case I will just try to figure it out, but I want to make sure I am not doing something that is not supposed to work in the first place :wink:

cheers!

edit: nevermind, just looked at the code again and the thing with the tokens makes sense! sorry for that!! I still couldn’t get cross domain bosh to work, so I’m not marking this topic as solved, but I think I’m good for now!
edit 2: okay I just replaced
serviceUrl: ‘//jitsi.mydomain.com/http-bind’, with
serviceUrl: ‘https://jitsi.mydomain.com/http-bind’,
in the javascript file of my custom UI and cross domain bosh seems to work again. I uncommented cross_domain_bosh = true in /etc/prosody/conf.avail/jitsi.mydomain.com.cfg.lua and left my /etc/nginx/sites-available/jitsi.mydomain.com.conf untouched. It seems the root for my troubles was simply me not understanding the JWT stuff… apologies for this!!
— edits end —

Okay so I just made a somewhat strange discovery: if I set allow_empy_tokens = true in /etc/prosody/conf.avail/jitsi.mydomain.com.cfg.lua suddenly connection.connect() succeeds!

I should say also that now I changed my nginx config for jitsi.mydomain.com back to the initial default, with one change, which is that it’s pointing now to my custom UI.

but anyhow –

Is this how it should be?? I thought tokens were only needed to create a conference, not to establish connection to the server.

Both.

okay thank you for clearing this up! :slight_smile: