Hello is there anyone already succesfully installed jitsi-docker with multi-tenant configuration?
I already have a manual-installed jitsi running on my own server with multi-tenant, and everything works well, but still failed on installing it with jitsi-docker, it says 404 not found (mydomain.com/multi/tenant ).
What things to be configured to activate this multi-tenant feature?
Any advice would be great. Thanks!
saghul
October 6, 2021, 3:04pm
#2
The Docker setup does not support multi-tenancy at this time, though it would be nice to have if some is up for contributing it
thanks for the response and confirmation @saghul
Hello @sagul what exactly is multi-tenancy? Is it like trying to access the same setup with two different organizations with their own background image and logo?
for example
for org1, the URL should be mydomain.com/org1/room_name
for org2 it is mydomain.com/org2/room_name
saghul
October 7, 2021, 9:53am
#5
Sort of. On our end it’s just the support for sub-directories so you can “namespace” meetings.
That’s right, basically with multi-tenancy you can manage the first param as an app-id or as an identifier.
@Raihan_Rafid If you need only this functionality then I can help you. you have to make some changes to the prosody config and web/meet.conf then build your own docker image. This is the only way to make this work as of now.
I’ve tried adding muc_mapper_domain_base = "{{ .Env.XMPP_DOMAIN }}"
on prosody/rootfs/defaults/conf.d/jitsi-meet.cfg.lua
but it still didn’t work, any other workaround?
replace jitsi-meet.cfg.lua
with below content
admins = {
"{{ .Env.JICOFO_AUTH_USER }}@{{ .Env.XMPP_AUTH_DOMAIN }}",
"{{ .Env.JVB_AUTH_USER }}@{{ .Env.XMPP_AUTH_DOMAIN }}"
}
plugin_paths = { "/prosody-plugins/", "/prosody-plugins-custom" }
http_default_host = "{{ .Env.XMPP_DOMAIN }}"
muc_mapper_domain_prefix = "muc"
muc_mapper_domain_base = "{{ .Env.XMPP_DOMAIN }}"
{{ $DISABLE_POLLS := .Env.DISABLE_POLLS | default "false" | toBool -}}
{{ $ENABLE_AUTH := .Env.ENABLE_AUTH | default "0" | toBool -}}
{{ $ENABLE_BREAKOUT_ROOMS := .Env.ENABLE_BREAKOUT_ROOMS | default "1" | toBool }}
{{ $ENABLE_GUEST_DOMAIN := and $ENABLE_AUTH (.Env.ENABLE_GUESTS | default "0" | toBool) -}}
{{ $AUTH_TYPE := .Env.AUTH_TYPE | default "internal" -}}
{{ $JWT_ASAP_KEYSERVER := .Env.JWT_ASAP_KEYSERVER | default "" -}}
{{ $JWT_ALLOW_EMPTY := .Env.JWT_ALLOW_EMPTY | default "0" | toBool -}}
{{ $JWT_AUTH_TYPE := .Env.JWT_AUTH_TYPE | default "token" }}
{{ $JWT_TOKEN_AUTH_MODULE := .Env.JWT_TOKEN_AUTH_MODULE | default "token_verification" -}}
{{ $ENABLE_LOBBY := .Env.ENABLE_LOBBY | default "0" | toBool -}}
{{ $ENABLE_XMPP_WEBSOCKET := .Env.ENABLE_XMPP_WEBSOCKET | default "1" | toBool -}}
{{ $ENABLE_SUBDOMAINS := .Env.ENABLE_SUBDOMAINS | default "false" -}}
{{ $PUBLIC_URL := .Env.PUBLIC_URL | default "https://localhost:8443" -}}
{{ $TURN_PORT := .Env.TURN_PORT | default "443" }}
{{ $TURNS_PORT := .Env.TURNS_PORT | default "443" }}
{{ if .Env.TURN_CREDENTIALS }}
external_service_secret = "{{.Env.TURN_CREDENTIALS}}";
{{ end }}
{{ if or .Env.TURN_HOST .Env.TURNS_HOST }}
external_services = {
{{ if .Env.TURN_HOST }}
{ type = "turn", host = "{{ .Env.TURN_HOST }}", port = {{ $TURN_PORT }}, transport = "tcp", secret = true, ttl = 86400, algorithm = "turn" }
{{ end }}
{{ if and .Env.TURN_HOST .Env.TURNS_HOST }}
,
{{ end }}
{{ if .Env.TURNS_HOST }}
{ type = "turns", host = "{{ .Env.TURNS_HOST }}", port = {{ $TURNS_PORT }}, transport = "tcp", secret = true, ttl = 86400, algorithm = "turn" }
{{ end }}
};
{{ end }}
{{ if and $ENABLE_AUTH (eq $AUTH_TYPE "jwt") .Env.JWT_ACCEPTED_ISSUERS -}}
asap_accepted_issuers = { "{{ join "\",\"" (splitList "," .Env.JWT_ACCEPTED_ISSUERS) }}" }
{{ end -}}
{{ if and $ENABLE_AUTH (eq $AUTH_TYPE "jwt") .Env.JWT_ACCEPTED_AUDIENCES -}}
asap_accepted_audiences = { "{{ join "\",\"" (splitList "," .Env.JWT_ACCEPTED_AUDIENCES) }}" }
{{ end -}}
consider_bosh_secure = true;
-- Deprecated in 0.12
-- https://github.com/bjc/prosody/commit/26542811eafd9c708a130272d7b7de77b92712de
{{ $XMPP_CROSS_DOMAINS := $PUBLIC_URL }}
{{ $XMPP_CROSS_DOMAIN := .Env.XMPP_CROSS_DOMAIN | default "" }}
{{ if eq $XMPP_CROSS_DOMAIN "true"}}
cross_domain_websocket = true
cross_domain_bosh = true
{{ else }}
{{ if not (eq $XMPP_CROSS_DOMAIN "false") }}
{{ $XMPP_CROSS_DOMAINS = list $PUBLIC_URL .Env.XMPP_CROSS_DOMAIN | join "," }}
{{ end }}
cross_domain_websocket = { "{{ join "\",\"" (splitList "," $XMPP_CROSS_DOMAINS) }}" }
cross_domain_bosh = { "{{ join "\",\"" (splitList "," $XMPP_CROSS_DOMAINS) }}" }
{{ end }}
unlimited_jids = {
"{{ .Env.JICOFO_AUTH_USER }}@{{ .Env.XMPP_AUTH_DOMAIN }}",
"{{ .Env.JVB_AUTH_USER }}@{{ .Env.XMPP_AUTH_DOMAIN }}"
}
VirtualHost "{{ .Env.XMPP_DOMAIN }}"
{{ if $ENABLE_AUTH }}
{{ if eq $AUTH_TYPE "jwt" }}
authentication = "{{ $JWT_AUTH_TYPE }}"
app_id = "{{ .Env.JWT_APP_ID }}"
app_secret = "{{ .Env.JWT_APP_SECRET }}"
allow_empty_token = {{ if $JWT_ALLOW_EMPTY }}true{{ else }}false{{ end }}
{{ if $JWT_ASAP_KEYSERVER }}
asap_key_server = "{{ .Env.JWT_ASAP_KEYSERVER }}"
{{ end }}
{{ else if eq $AUTH_TYPE "ldap" }}
authentication = "cyrus"
cyrus_application_name = "xmpp"
allow_unencrypted_plain_auth = true
{{ else if eq $AUTH_TYPE "internal" }}
authentication = "internal_hashed"
{{ end }}
{{ else }}
-- https://github.com/jitsi/docker-jitsi-meet/pull/502#issuecomment-619146339
{{ if $ENABLE_XMPP_WEBSOCKET }}
authentication = "token"
{{ else }}
authentication = "anonymous"
{{ end }}
app_id = ""
app_secret = ""
allow_empty_token = true
{{ end }}
ssl = {
key = "/config/certs/{{ .Env.XMPP_DOMAIN }}.key";
certificate = "/config/certs/{{ .Env.XMPP_DOMAIN }}.crt";
}
modules_enabled = {
{{ if $ENABLE_XMPP_WEBSOCKET }}
"websocket";
"smacks"; -- XEP-0198: Stream Management
{{ end }}
"bosh";
"pubsub";
"ping";
"speakerstats";
"conference_duration";
{{ if or .Env.TURN_HOST .Env.TURNS_HOST }}
"external_services";
{{ end }}
"av_moderation";
{{ if $ENABLE_LOBBY }}
"muc_lobby_rooms";
{{ end }}
{{ if $ENABLE_BREAKOUT_ROOMS }}
"breakout_rooms";
{{ end }}
{{ if .Env.XMPP_MODULES }}
"{{ join "\";\n\"" (splitList "," .Env.XMPP_MODULES) }}";
{{ end }}
{{ if and $ENABLE_AUTH (eq $AUTH_TYPE "ldap") }}
"auth_cyrus";
{{end}}
{{ if .Env.ENABLE_RECORDING }}
"allow_jibri_tobypass";
{{ end }}
}
{{ if or $ENABLE_LOBBY $ENABLE_BREAKOUT_ROOMS }}
main_muc = "{{ .Env.XMPP_MUC_DOMAIN }}"
{{ end }}
{{ if $ENABLE_LOBBY }}
lobby_muc = "lobby.{{ .Env.XMPP_DOMAIN }}"
{{ if .Env.XMPP_RECORDER_DOMAIN }}
muc_lobby_whitelist = { "{{ .Env.XMPP_RECORDER_DOMAIN }}" }
{{ end }}
{{ end }}
av_moderation_component = "avmoderation.{{ .Env.XMPP_DOMAIN }}"
speakerstats_component = "speakerstats.{{ .Env.XMPP_DOMAIN }}"
conference_duration_component = "conferenceduration.{{ .Env.XMPP_DOMAIN }}"
c2s_require_encryption = false
{{ if $ENABLE_GUEST_DOMAIN }}
VirtualHost "{{ .Env.XMPP_GUEST_DOMAIN }}"
-- https://github.com/jitsi/docker-jitsi-meet/pull/502#issuecomment-619146339
{{ if $ENABLE_XMPP_WEBSOCKET }}
authentication = "token"
{{ else }}
authentication = "anonymous"
{{ end }}
app_id = ""
app_secret = ""
allow_empty_token = true
c2s_require_encryption = false
{{ end }}
VirtualHost "{{ .Env.XMPP_AUTH_DOMAIN }}"
ssl = {
key = "/config/certs/{{ .Env.XMPP_AUTH_DOMAIN }}.key";
certificate = "/config/certs/{{ .Env.XMPP_AUTH_DOMAIN }}.crt";
}
modules_enabled = {
"limits_exception";
}
authentication = "internal_hashed"
{{ if .Env.XMPP_RECORDER_DOMAIN }}
VirtualHost "{{ .Env.XMPP_RECORDER_DOMAIN }}"
modules_enabled = {
"ping";
}
authentication = "internal_hashed"
{{ end }}
Component "{{ .Env.XMPP_INTERNAL_MUC_DOMAIN }}" "muc"
storage = "memory"
modules_enabled = {
"ping";
{{ if .Env.XMPP_INTERNAL_MUC_MODULES }}
"{{ join "\";\n\"" (splitList "," .Env.XMPP_INTERNAL_MUC_MODULES) }}";
{{ end }}
}
restrict_room_creation = true
muc_room_locking = false
muc_room_default_public_jids = true
Component "{{ .Env.XMPP_MUC_DOMAIN }}" "muc"
storage = "memory"
modules_enabled = {
"muc_meeting_id";
{{ if .Env.XMPP_MUC_MODULES -}}
"{{ join "\";\n\"" (splitList "," .Env.XMPP_MUC_MODULES) }}";
{{ end -}}
{{ if and $ENABLE_AUTH (eq $AUTH_TYPE "jwt") -}}
"{{ join "\";\n\"" (splitList "," .Env.JWT_TOKEN_AUTH_MODULE) }}";
{{ end -}}
{{ if .Env.ENABLE_RECORDING -}}
"allow_jibri_tobypass";
{{ end -}}
{{ if eq $ENABLE_SUBDOMAINS "true" -}}
"muc_domain_mapper";
{{ end -}}
{{ if not $DISABLE_POLLS -}}
"polls";
{{ end -}}
}
muc_room_cache_size = 1000
muc_room_locking = false
muc_room_default_public_jids = true
-- Proxy to jicofo's user JID, so that it doesn't have to register as a component.
Component "{{ .Env.JICOFO_AUTH_USER }}.{{ .Env.XMPP_DOMAIN }}" "client_proxy"
target_address = "{{ .Env.JICOFO_AUTH_USER }}@{{ .Env.XMPP_AUTH_DOMAIN }}"
Component "speakerstats.{{ .Env.XMPP_DOMAIN }}" "speakerstats_component"
muc_component = "{{ .Env.XMPP_MUC_DOMAIN }}"
Component "conferenceduration.{{ .Env.XMPP_DOMAIN }}" "conference_duration_component"
muc_component = "{{ .Env.XMPP_MUC_DOMAIN }}"
Component "avmoderation.{{ .Env.XMPP_DOMAIN }}" "av_moderation_component"
muc_component = "{{ .Env.XMPP_MUC_DOMAIN }}"
{{ if $ENABLE_LOBBY -}}
Component "lobby.{{ .Env.XMPP_DOMAIN }}" "muc"
storage = "memory"
restrict_room_creation = true
muc_room_locking = false
muc_room_default_public_jids = true
{{ end -}}
also match meet.conf with below content
{{ $ENABLE_XMPP_WEBSOCKET := .Env.ENABLE_XMPP_WEBSOCKET | default "1" | toBool }}
{{ $ENABLE_COLIBRI_WEBSOCKET := .Env.ENABLE_COLIBRI_WEBSOCKET | default "1" | toBool }}
{{ $ENABLE_SUBDOMAINS := .Env.ENABLE_SUBDOMAINS | default "true" | toBool -}}
server_name _;
client_max_body_size 0;
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;
# Security headers
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
{{ if .Env.DEPLOYMENTINFO_SHARD }}
# jitsi shard header for keepalive
add_header X-Jitsi-Shard {{ .Env.DEPLOYMENTINFO_SHARD }};
{{ end }}
location = /config.js {
alias /config/config.js;
}
location = /interface_config.js {
alias /config/interface_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;
}
{{ if $ENABLE_COLIBRI_WEBSOCKET }}
# colibri (JVB) websockets
location ~ ^/colibri-ws/([a-zA-Z0-9-\.]+)/(.*) {
proxy_pass http://$1:9090/colibri-ws/$1/$2$is_args$args;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
tcp_nodelay on;
}
{{ end }}
# BOSH
location = /http-bind {
proxy_pass {{ .Env.XMPP_BOSH_URL_BASE }}/http-bind;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host {{ .Env.XMPP_DOMAIN }};
}
{{ if $ENABLE_XMPP_WEBSOCKET }}
# xmpp websockets
location = /xmpp-websocket {
proxy_pass {{ .Env.XMPP_BOSH_URL_BASE }}/xmpp-websocket;
proxy_http_version 1.1;
proxy_set_header Connection "upgrade";
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host {{ .Env.XMPP_DOMAIN }};
proxy_set_header X-Forwarded-For $remote_addr;
tcp_nodelay on;
}
{{ end }}
location ~ ^/([^/?&:'"]+)$ {
try_files $uri @root_path;
}
location @root_path {
rewrite ^/(.*)$ / break;
}
location ~ ^/([^/?&:'"]+)/config.js$
{
set $subdomain "$1.";
set $subdir "$1/";
alias /config/config.js;
}
#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;
}
{{ if $ENABLE_SUBDOMAINS }}
{{ if $ENABLE_XMPP_WEBSOCKET }}
# websockets for subdomains
location ~ ^/([^/?&:'"]+)/xmpp-websocket {
set $subdomain "$1.";
set $subdir "$1/";
set $prefix "$1";
rewrite ^/(.*)$ /xmpp-websocket;
}
{{ end }}
# BOSH for subdomains
location ~ ^/([^/?&:'"]+)/http-bind {
set $subdomain "$1.";
set $subdir "$1/";
set $prefix "$1";
rewrite ^/(.*)$ /http-bind;
}
{{ end }}
{{ if .Env.ETHERPAD_URL_BASE }}
# Etherpad-lite
location /etherpad/ {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
#proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_pass {{ .Env.ETHERPAD_URL_BASE }}/;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_buffering off;
#proxy_set_header Host {{ .Env.XMPP_DOMAIN }};
}
{{ end }}
build prosody docker image
build web docker image
1 Like
Will try that asap, thanks for advance
working like a charm darl, thank you so much
1 Like