feat(jitsi): Add Jitsi Meet video conferencing integration
- secubox-app-jitsi: Docker-based Jitsi stack with jitsctl control CLI - luci-app-jitsi: LuCI web configuration interface - Catalog entry for SecuBox AppStore Features: - End-to-end encrypted video conferencing - HAProxy integration with WebSocket/SSL support - Mesh federation for SecuBox P2P network - User authentication management - Backup/restore functionality Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
760408c36f
commit
00082fe066
29
package/secubox/luci-app-jitsi/Makefile
Normal file
29
package/secubox/luci-app-jitsi/Makefile
Normal file
@ -0,0 +1,29 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
LUCI_TITLE:=LuCI Jitsi Meet Configuration
|
||||
LUCI_DEPENDS:=+secubox-app-jitsi
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
PKG_NAME:=luci-app-jitsi
|
||||
PKG_VERSION:=1.0.0
|
||||
PKG_RELEASE:=1
|
||||
PKG_MAINTAINER:=CyberMind Studio <contact@cybermind.fr>
|
||||
PKG_LICENSE:=Apache-2.0
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
define Package/luci-app-jitsi/install
|
||||
$(INSTALL_DIR) $(1)/usr/share/luci/menu.d
|
||||
$(INSTALL_DATA) ./root/usr/share/luci/menu.d/luci-app-jitsi.json $(1)/usr/share/luci/menu.d/
|
||||
|
||||
$(INSTALL_DIR) $(1)/usr/share/rpcd/acl.d
|
||||
$(INSTALL_DATA) ./root/usr/share/rpcd/acl.d/luci-app-jitsi.json $(1)/usr/share/rpcd/acl.d/
|
||||
|
||||
$(INSTALL_DIR) $(1)/www/luci-static/resources/view/jitsi
|
||||
$(INSTALL_DATA) ./htdocs/luci-static/resources/view/jitsi/*.js $(1)/www/luci-static/resources/view/jitsi/
|
||||
|
||||
$(INSTALL_DIR) $(1)/usr/libexec/rpcd
|
||||
$(INSTALL_BIN) ./root/usr/libexec/rpcd/luci.jitsi $(1)/usr/libexec/rpcd/
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,luci-app-jitsi))
|
||||
@ -0,0 +1,298 @@
|
||||
'use strict';
|
||||
'require view';
|
||||
'require form';
|
||||
'require uci';
|
||||
'require rpc';
|
||||
'require poll';
|
||||
|
||||
var callJitsiStatus = rpc.declare({
|
||||
object: 'luci.jitsi',
|
||||
method: 'status',
|
||||
expect: { '': {} }
|
||||
});
|
||||
|
||||
var callJitsiStart = rpc.declare({
|
||||
object: 'luci.jitsi',
|
||||
method: 'start'
|
||||
});
|
||||
|
||||
var callJitsiStop = rpc.declare({
|
||||
object: 'luci.jitsi',
|
||||
method: 'stop'
|
||||
});
|
||||
|
||||
var callJitsiRestart = rpc.declare({
|
||||
object: 'luci.jitsi',
|
||||
method: 'restart'
|
||||
});
|
||||
|
||||
var callJitsiInstall = rpc.declare({
|
||||
object: 'luci.jitsi',
|
||||
method: 'install'
|
||||
});
|
||||
|
||||
var callJitsiGenerateConfig = rpc.declare({
|
||||
object: 'luci.jitsi',
|
||||
method: 'generate_config'
|
||||
});
|
||||
|
||||
return view.extend({
|
||||
load: function() {
|
||||
return Promise.all([
|
||||
uci.load('jitsi'),
|
||||
callJitsiStatus()
|
||||
]);
|
||||
},
|
||||
|
||||
render: function(data) {
|
||||
var status = data[1];
|
||||
var m, s, o;
|
||||
|
||||
m = new form.Map('jitsi', _('Jitsi Meet Video Conferencing'),
|
||||
_('Self-hosted video conferencing with end-to-end encryption.'));
|
||||
|
||||
// Status section
|
||||
s = m.section(form.NamedSection, 'main', 'jitsi', _('Service Status'));
|
||||
s.anonymous = true;
|
||||
|
||||
o = s.option(form.DummyValue, '_status', _('Status'));
|
||||
o.rawhtml = true;
|
||||
o.cfgvalue = function() {
|
||||
var html = '<div style="display:flex;gap:20px;flex-wrap:wrap;">';
|
||||
|
||||
if (!status.docker_available) {
|
||||
html += '<span style="color:red;font-weight:bold;">Docker not available - Install docker package</span>';
|
||||
} else {
|
||||
// Container status
|
||||
var containers = status.containers || {};
|
||||
for (var name in containers) {
|
||||
var state = containers[name];
|
||||
var color = state === 'running' ? 'green' : (state === 'not_found' ? 'gray' : 'orange');
|
||||
html += '<span><b>' + name.replace('jitsi-', '') + ':</b> ';
|
||||
html += '<span style="color:' + color + '">' + state + '</span></span>';
|
||||
}
|
||||
|
||||
// Stats
|
||||
if (status.stats) {
|
||||
html += '<span style="margin-left:20px;">';
|
||||
html += '<b>Active:</b> ' + (status.stats.conferences || 0) + ' conferences, ';
|
||||
html += (status.stats.participants || 0) + ' participants';
|
||||
html += '</span>';
|
||||
}
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
return html;
|
||||
};
|
||||
|
||||
// Control buttons
|
||||
o = s.option(form.Button, '_start', _('Start'));
|
||||
o.inputtitle = _('Start');
|
||||
o.inputstyle = 'apply';
|
||||
o.onclick = function() {
|
||||
return callJitsiStart().then(function() {
|
||||
window.location.reload();
|
||||
});
|
||||
};
|
||||
|
||||
o = s.option(form.Button, '_stop', _('Stop'));
|
||||
o.inputtitle = _('Stop');
|
||||
o.inputstyle = 'remove';
|
||||
o.onclick = function() {
|
||||
return callJitsiStop().then(function() {
|
||||
window.location.reload();
|
||||
});
|
||||
};
|
||||
|
||||
o = s.option(form.Button, '_restart', _('Restart'));
|
||||
o.inputtitle = _('Restart');
|
||||
o.inputstyle = 'reload';
|
||||
o.onclick = function() {
|
||||
return callJitsiRestart().then(function() {
|
||||
window.location.reload();
|
||||
});
|
||||
};
|
||||
|
||||
// Configuration section
|
||||
s = m.section(form.NamedSection, 'main', 'jitsi', _('General Configuration'));
|
||||
s.anonymous = true;
|
||||
|
||||
o = s.option(form.Flag, 'enabled', _('Enabled'),
|
||||
_('Enable Jitsi Meet service'));
|
||||
o.rmempty = false;
|
||||
|
||||
o = s.option(form.Value, 'domain', _('Domain'),
|
||||
_('Public domain for Jitsi Meet (e.g., meet.example.com)'));
|
||||
o.placeholder = 'meet.example.com';
|
||||
o.rmempty = false;
|
||||
|
||||
o = s.option(form.Value, 'public_url', _('Public URL'),
|
||||
_('Full public URL (leave empty to auto-generate from domain)'));
|
||||
o.placeholder = 'https://meet.example.com';
|
||||
o.optional = true;
|
||||
|
||||
o = s.option(form.ListValue, 'timezone', _('Timezone'));
|
||||
o.value('UTC', 'UTC');
|
||||
o.value('Europe/Paris', 'Europe/Paris');
|
||||
o.value('Europe/London', 'Europe/London');
|
||||
o.value('America/New_York', 'America/New York');
|
||||
o.value('America/Los_Angeles', 'America/Los Angeles');
|
||||
o.value('Asia/Tokyo', 'Asia/Tokyo');
|
||||
o.default = 'UTC';
|
||||
|
||||
// Web settings
|
||||
s = m.section(form.NamedSection, 'web', 'jitsi', _('Web Interface'));
|
||||
s.anonymous = true;
|
||||
|
||||
o = s.option(form.Value, 'port', _('HTTPS Port'),
|
||||
_('Port for web interface'));
|
||||
o.datatype = 'port';
|
||||
o.default = '8443';
|
||||
|
||||
o = s.option(form.Flag, 'enable_guests', _('Allow Guests'),
|
||||
_('Allow users to join without authentication'));
|
||||
o.default = '1';
|
||||
|
||||
o = s.option(form.Flag, 'enable_auth', _('Require Authentication'),
|
||||
_('Require login to create meetings'));
|
||||
o.default = '0';
|
||||
|
||||
o = s.option(form.ListValue, 'default_language', _('Default Language'));
|
||||
o.value('en', 'English');
|
||||
o.value('fr', 'French');
|
||||
o.value('de', 'German');
|
||||
o.value('es', 'Spanish');
|
||||
o.value('it', 'Italian');
|
||||
o.value('pt', 'Portuguese');
|
||||
o.value('zh', 'Chinese');
|
||||
o.value('ja', 'Japanese');
|
||||
o.default = 'en';
|
||||
|
||||
// JVB settings
|
||||
s = m.section(form.NamedSection, 'jvb', 'jitsi', _('Video Bridge (JVB)'));
|
||||
s.anonymous = true;
|
||||
|
||||
o = s.option(form.Value, 'port', _('Media Port (UDP)'),
|
||||
_('UDP port for video/audio streams'));
|
||||
o.datatype = 'port';
|
||||
o.default = '10000';
|
||||
|
||||
o = s.option(form.Flag, 'enable_tcp_fallback', _('Enable TCP Fallback'),
|
||||
_('Allow TCP fallback for restrictive networks'));
|
||||
o.default = '0';
|
||||
|
||||
o = s.option(form.Value, 'tcp_port', _('TCP Fallback Port'),
|
||||
_('TCP port for fallback'));
|
||||
o.datatype = 'port';
|
||||
o.default = '4443';
|
||||
o.depends('enable_tcp_fallback', '1');
|
||||
|
||||
o = s.option(form.Value, 'stun_servers', _('STUN Servers'),
|
||||
_('STUN servers for NAT traversal'));
|
||||
o.placeholder = 'meet-jit-si-turnrelay.jitsi.net:443';
|
||||
|
||||
// Security settings
|
||||
s = m.section(form.NamedSection, 'security', 'jitsi', _('Security'));
|
||||
s.anonymous = true;
|
||||
|
||||
o = s.option(form.Flag, 'lobby_enabled', _('Enable Lobby'),
|
||||
_('Require moderator approval to join'));
|
||||
o.default = '1';
|
||||
|
||||
o = s.option(form.Flag, 'password_required', _('Require Room Password'),
|
||||
_('Prompt for password when creating rooms'));
|
||||
o.default = '0';
|
||||
|
||||
o = s.option(form.Flag, 'jwt_enabled', _('Enable JWT Authentication'),
|
||||
_('Use JWT tokens for authentication'));
|
||||
o.default = '0';
|
||||
|
||||
o = s.option(form.Value, 'jwt_app_id', _('JWT App ID'));
|
||||
o.depends('jwt_enabled', '1');
|
||||
|
||||
o = s.option(form.Value, 'jwt_app_secret', _('JWT App Secret'));
|
||||
o.password = true;
|
||||
o.depends('jwt_enabled', '1');
|
||||
|
||||
// TURN settings
|
||||
s = m.section(form.NamedSection, 'turn', 'jitsi', _('TURN Server'));
|
||||
s.anonymous = true;
|
||||
|
||||
o = s.option(form.Flag, 'enabled', _('Use External TURN'),
|
||||
_('Use external TURN server for better NAT traversal'));
|
||||
o.default = '0';
|
||||
|
||||
o = s.option(form.Value, 'server', _('TURN Server'));
|
||||
o.placeholder = 'turn.example.com:443';
|
||||
o.depends('enabled', '1');
|
||||
|
||||
o = s.option(form.Value, 'username', _('Username'));
|
||||
o.depends('enabled', '1');
|
||||
|
||||
o = s.option(form.Value, 'password', _('Password'));
|
||||
o.password = true;
|
||||
o.depends('enabled', '1');
|
||||
|
||||
// Mesh integration
|
||||
s = m.section(form.NamedSection, 'mesh', 'jitsi', _('Mesh Integration'));
|
||||
s.anonymous = true;
|
||||
|
||||
o = s.option(form.Flag, 'enabled', _('Enable Mesh Integration'),
|
||||
_('Announce Jitsi on SecuBox mesh network'));
|
||||
o.default = '0';
|
||||
|
||||
o = s.option(form.Flag, 'announce_service', _('Announce Service'),
|
||||
_('Register with mesh DNS'));
|
||||
o.default = '1';
|
||||
o.depends('enabled', '1');
|
||||
|
||||
// Actions
|
||||
s = m.section(form.NamedSection, 'main', 'jitsi', _('Actions'));
|
||||
s.anonymous = true;
|
||||
|
||||
o = s.option(form.Button, '_install', _('Install Containers'));
|
||||
o.inputtitle = _('Install');
|
||||
o.inputstyle = 'apply';
|
||||
o.onclick = function() {
|
||||
if (confirm(_('This will download Docker images. Continue?'))) {
|
||||
return callJitsiInstall().then(function(res) {
|
||||
alert(res.output || 'Installation started');
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
o = s.option(form.Button, '_regenerate', _('Regenerate Configuration'));
|
||||
o.inputtitle = _('Regenerate');
|
||||
o.inputstyle = 'reload';
|
||||
o.onclick = function() {
|
||||
return callJitsiGenerateConfig().then(function(res) {
|
||||
alert(res.output || 'Configuration regenerated');
|
||||
});
|
||||
};
|
||||
|
||||
// Help section
|
||||
s = m.section(form.NamedSection, 'main', 'jitsi', _('Quick Start'));
|
||||
s.anonymous = true;
|
||||
|
||||
o = s.option(form.DummyValue, '_help');
|
||||
o.rawhtml = true;
|
||||
o.cfgvalue = function() {
|
||||
var domain = uci.get('jitsi', 'main', 'domain') || 'meet.example.com';
|
||||
return '<div style="background:#f5f5f5;padding:15px;border-radius:5px;">' +
|
||||
'<h4>Setup Steps:</h4>' +
|
||||
'<ol>' +
|
||||
'<li>Set your domain above</li>' +
|
||||
'<li>Click "Install Containers" to download images</li>' +
|
||||
'<li>Enable the service and save</li>' +
|
||||
'<li>Configure HAProxy/DNS to point to this device</li>' +
|
||||
'</ol>' +
|
||||
'<h4>Access:</h4>' +
|
||||
'<p>Web: <a href="https://' + domain + '" target="_blank">https://' + domain + '</a></p>' +
|
||||
'<p>CLI: <code>jitsctl status</code></p>' +
|
||||
'</div>';
|
||||
};
|
||||
|
||||
return m.render();
|
||||
}
|
||||
});
|
||||
120
package/secubox/luci-app-jitsi/root/usr/libexec/rpcd/luci.jitsi
Normal file
120
package/secubox/luci-app-jitsi/root/usr/libexec/rpcd/luci.jitsi
Normal file
@ -0,0 +1,120 @@
|
||||
#!/bin/sh
|
||||
|
||||
. /lib/functions.sh
|
||||
. /usr/share/libubox/jshn.sh
|
||||
|
||||
JITSI_DIR="/srv/jitsi"
|
||||
|
||||
case "$1" in
|
||||
list)
|
||||
echo '{"status":{},"start":{},"stop":{},"restart":{},"install":{},"generate_config":{},"add_user":{"username":"str","password":"str"},"remove_user":{"username":"str"},"list_users":{},"logs":{"service":"str","lines":"int"}}'
|
||||
;;
|
||||
call)
|
||||
case "$2" in
|
||||
status)
|
||||
# Get service status
|
||||
json_init
|
||||
|
||||
# Check enabled
|
||||
enabled=$(uci -q get jitsi.main.enabled)
|
||||
domain=$(uci -q get jitsi.main.domain)
|
||||
|
||||
json_add_boolean "enabled" ${enabled:-0}
|
||||
json_add_string "domain" "$domain"
|
||||
|
||||
# Check containers
|
||||
if command -v docker >/dev/null 2>&1; then
|
||||
json_add_boolean "docker_available" 1
|
||||
|
||||
json_add_object "containers"
|
||||
for container in jitsi-web jitsi-prosody jitsi-jicofo jitsi-jvb; do
|
||||
state=$(docker inspect -f '{{.State.Status}}' "$container" 2>/dev/null)
|
||||
json_add_string "$container" "${state:-not_found}"
|
||||
done
|
||||
json_close_object
|
||||
|
||||
# Get stats from JVB if running
|
||||
stats=$(docker exec jitsi-jvb curl -s http://localhost:8080/colibri/stats 2>/dev/null)
|
||||
if [ -n "$stats" ]; then
|
||||
conferences=$(echo "$stats" | jsonfilter -e '@.conferences' 2>/dev/null)
|
||||
participants=$(echo "$stats" | jsonfilter -e '@.participants' 2>/dev/null)
|
||||
json_add_object "stats"
|
||||
json_add_int "conferences" ${conferences:-0}
|
||||
json_add_int "participants" ${participants:-0}
|
||||
json_close_object
|
||||
fi
|
||||
else
|
||||
json_add_boolean "docker_available" 0
|
||||
fi
|
||||
|
||||
json_dump
|
||||
;;
|
||||
start)
|
||||
/etc/init.d/jitsi start >/dev/null 2>&1
|
||||
echo '{"success":true}'
|
||||
;;
|
||||
stop)
|
||||
/etc/init.d/jitsi stop >/dev/null 2>&1
|
||||
echo '{"success":true}'
|
||||
;;
|
||||
restart)
|
||||
/etc/init.d/jitsi restart >/dev/null 2>&1
|
||||
echo '{"success":true}'
|
||||
;;
|
||||
install)
|
||||
output=$(/usr/sbin/jitsctl install 2>&1)
|
||||
json_init
|
||||
json_add_boolean "success" 1
|
||||
json_add_string "output" "$output"
|
||||
json_dump
|
||||
;;
|
||||
generate_config)
|
||||
output=$(/usr/sbin/jitsctl generate-config 2>&1)
|
||||
json_init
|
||||
json_add_boolean "success" 1
|
||||
json_add_string "output" "$output"
|
||||
json_dump
|
||||
;;
|
||||
add_user)
|
||||
read -r input
|
||||
username=$(echo "$input" | jsonfilter -e '@.username')
|
||||
password=$(echo "$input" | jsonfilter -e '@.password')
|
||||
output=$(/usr/sbin/jitsctl add-user "$username" "$password" 2>&1)
|
||||
code=$?
|
||||
json_init
|
||||
json_add_boolean "success" $((code == 0))
|
||||
json_add_string "output" "$output"
|
||||
json_dump
|
||||
;;
|
||||
remove_user)
|
||||
read -r input
|
||||
username=$(echo "$input" | jsonfilter -e '@.username')
|
||||
output=$(/usr/sbin/jitsctl remove-user "$username" 2>&1)
|
||||
code=$?
|
||||
json_init
|
||||
json_add_boolean "success" $((code == 0))
|
||||
json_add_string "output" "$output"
|
||||
json_dump
|
||||
;;
|
||||
list_users)
|
||||
domain=$(uci -q get jitsi.main.domain)
|
||||
users=$(docker exec jitsi-prosody ls -1 /config/data/"$domain"/accounts/ 2>/dev/null | sed 's/\.dat$//' | tr '\n' ',')
|
||||
json_init
|
||||
json_add_string "users" "$users"
|
||||
json_dump
|
||||
;;
|
||||
logs)
|
||||
read -r input
|
||||
service=$(echo "$input" | jsonfilter -e '@.service')
|
||||
lines=$(echo "$input" | jsonfilter -e '@.lines')
|
||||
[ -z "$lines" ] && lines=50
|
||||
logs=$(cd "$JITSI_DIR" && docker-compose logs --tail="$lines" ${service:-} 2>&1 | tail -100)
|
||||
json_init
|
||||
json_add_string "logs" "$logs"
|
||||
json_dump
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
@ -0,0 +1,14 @@
|
||||
{
|
||||
"admin/services/jitsi": {
|
||||
"title": "Jitsi Meet",
|
||||
"order": 60,
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "jitsi/config"
|
||||
},
|
||||
"depends": {
|
||||
"acl": ["luci-app-jitsi"],
|
||||
"uci": {"jitsi": true}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
{
|
||||
"luci-app-jitsi": {
|
||||
"description": "Grant access to Jitsi Meet configuration",
|
||||
"read": {
|
||||
"file": {
|
||||
"/etc/config/jitsi": ["read"],
|
||||
"/srv/jitsi/.env": ["read"]
|
||||
},
|
||||
"ubus": {
|
||||
"file": ["read", "stat"],
|
||||
"luci.jitsi": ["*"]
|
||||
},
|
||||
"uci": ["jitsi"]
|
||||
},
|
||||
"write": {
|
||||
"file": {
|
||||
"/etc/config/jitsi": ["write"]
|
||||
},
|
||||
"ubus": {
|
||||
"luci.jitsi": ["*"]
|
||||
},
|
||||
"uci": ["jitsi"]
|
||||
}
|
||||
}
|
||||
}
|
||||
90
package/secubox/secubox-app-jitsi/Makefile
Normal file
90
package/secubox/secubox-app-jitsi/Makefile
Normal file
@ -0,0 +1,90 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=secubox-app-jitsi
|
||||
PKG_VERSION:=1.0.0
|
||||
PKG_RELEASE:=1
|
||||
PKG_ARCH:=all
|
||||
PKG_MAINTAINER:=CyberMind Studio <contact@cybermind.fr>
|
||||
PKG_LICENSE:=Apache-2.0
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/secubox-app-jitsi
|
||||
SECTION:=utils
|
||||
CATEGORY:=Utilities
|
||||
PKGARCH:=all
|
||||
SUBMENU:=SecuBox Apps
|
||||
TITLE:=SecuBox Jitsi Meet Video Conferencing
|
||||
DEPENDS:=+docker +docker-compose +wget +openssl-util
|
||||
endef
|
||||
|
||||
define Package/secubox-app-jitsi/description
|
||||
Jitsi Meet - Secure, fully featured video conferencing for SecuBox.
|
||||
|
||||
Features:
|
||||
- End-to-end encrypted video conferences
|
||||
- No account required for guests
|
||||
- Screen sharing and recording
|
||||
- Chat, reactions, and virtual backgrounds
|
||||
- Mobile app support (iOS/Android)
|
||||
- WebRTC-based, works in any browser
|
||||
- Self-hosted for complete privacy
|
||||
|
||||
Runs via Docker containers for easy deployment.
|
||||
Integrates with HAProxy for SSL termination.
|
||||
Configure in /etc/config/jitsi.
|
||||
endef
|
||||
|
||||
define Package/secubox-app-jitsi/conffiles
|
||||
/etc/config/jitsi
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
endef
|
||||
|
||||
define Package/secubox-app-jitsi/install
|
||||
$(INSTALL_DIR) $(1)/etc/config
|
||||
$(INSTALL_CONF) ./files/etc/config/jitsi $(1)/etc/config/jitsi
|
||||
|
||||
$(INSTALL_DIR) $(1)/etc/init.d
|
||||
$(INSTALL_BIN) ./files/etc/init.d/jitsi $(1)/etc/init.d/jitsi
|
||||
|
||||
$(INSTALL_DIR) $(1)/usr/sbin
|
||||
$(INSTALL_BIN) ./files/usr/sbin/jitsctl $(1)/usr/sbin/jitsctl
|
||||
|
||||
$(INSTALL_DIR) $(1)/usr/share/jitsi
|
||||
$(INSTALL_DATA) ./files/usr/share/jitsi/docker-compose.yml $(1)/usr/share/jitsi/
|
||||
$(INSTALL_DATA) ./files/usr/share/jitsi/env.template $(1)/usr/share/jitsi/
|
||||
|
||||
$(INSTALL_DIR) $(1)/usr/share/jitsi/prosody
|
||||
$(INSTALL_DATA) ./files/usr/share/jitsi/prosody/prosody.cfg.lua.template $(1)/usr/share/jitsi/prosody/
|
||||
|
||||
$(INSTALL_DIR) $(1)/usr/lib/secubox/haproxy.d
|
||||
$(INSTALL_DATA) ./files/usr/lib/secubox/haproxy.d/jitsi.cfg $(1)/usr/lib/secubox/haproxy.d/
|
||||
endef
|
||||
|
||||
define Package/secubox-app-jitsi/postinst
|
||||
#!/bin/sh
|
||||
[ -n "$${IPKG_INSTROOT}" ] || {
|
||||
echo ""
|
||||
echo "============================================"
|
||||
echo " Jitsi Meet Video Conferencing Installed"
|
||||
echo "============================================"
|
||||
echo ""
|
||||
echo "Quick Start:"
|
||||
echo " 1. Configure: uci set jitsi.main.domain='meet.example.com'"
|
||||
echo " 2. Install: jitsctl install"
|
||||
echo " 3. Start: /etc/init.d/jitsi start"
|
||||
echo ""
|
||||
echo "Control commands:"
|
||||
echo " jitsctl status - Show service status"
|
||||
echo " jitsctl logs - View container logs"
|
||||
echo " jitsctl shell - Access container shell"
|
||||
echo ""
|
||||
echo "Web interface: https://<your-domain>"
|
||||
echo ""
|
||||
}
|
||||
exit 0
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,secubox-app-jitsi))
|
||||
188
package/secubox/secubox-app-jitsi/README.md
Normal file
188
package/secubox/secubox-app-jitsi/README.md
Normal file
@ -0,0 +1,188 @@
|
||||
# SecuBox Jitsi Meet
|
||||
|
||||
Self-hosted video conferencing with end-to-end encryption for SecuBox.
|
||||
|
||||
## Features
|
||||
|
||||
- **Secure Video Calls**: End-to-end encrypted video conferences
|
||||
- **No Account Required**: Guests can join without registration
|
||||
- **Screen Sharing**: Share your screen with participants
|
||||
- **Chat & Reactions**: In-meeting chat and emoji reactions
|
||||
- **Breakout Rooms**: Split meetings into smaller groups
|
||||
- **Recording**: Optional recording to Dropbox (requires setup)
|
||||
- **Mobile Support**: iOS and Android apps available
|
||||
- **HAProxy Integration**: Automatic SSL and reverse proxy setup
|
||||
- **Mesh Federation**: Announce service on SecuBox mesh network
|
||||
|
||||
## Requirements
|
||||
|
||||
- Docker and docker-compose
|
||||
- 2GB+ RAM (4GB recommended)
|
||||
- Public domain with DNS pointing to your SecuBox
|
||||
- SSL certificate (via Let's Encrypt or HAProxy)
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# Install
|
||||
opkg install secubox-app-jitsi luci-app-jitsi
|
||||
|
||||
# Configure domain
|
||||
uci set jitsi.main.domain='meet.example.com'
|
||||
uci set jitsi.main.enabled='1'
|
||||
uci commit jitsi
|
||||
|
||||
# Install Docker containers
|
||||
jitsctl install
|
||||
|
||||
# Start service
|
||||
/etc/init.d/jitsi start
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Via LuCI
|
||||
Navigate to **Services > Jitsi Meet** in the LuCI web interface.
|
||||
|
||||
### Via CLI
|
||||
```bash
|
||||
# Show status
|
||||
jitsctl status
|
||||
|
||||
# View logs
|
||||
jitsctl logs
|
||||
|
||||
# Add authenticated user
|
||||
jitsctl add-user admin secretpassword
|
||||
|
||||
# Regenerate configuration
|
||||
jitsctl generate-config
|
||||
|
||||
# Restart containers
|
||||
jitsctl restart
|
||||
```
|
||||
|
||||
### UCI Options
|
||||
|
||||
```
|
||||
config jitsi 'main'
|
||||
option enabled '1'
|
||||
option domain 'meet.example.com'
|
||||
option timezone 'Europe/Paris'
|
||||
|
||||
config jitsi 'web'
|
||||
option port '8443'
|
||||
option enable_guests '1'
|
||||
option enable_auth '0'
|
||||
option default_language 'en'
|
||||
|
||||
config jitsi 'jvb'
|
||||
option port '10000'
|
||||
option enable_tcp_fallback '0'
|
||||
option stun_servers 'meet-jit-si-turnrelay.jitsi.net:443'
|
||||
|
||||
config jitsi 'security'
|
||||
option lobby_enabled '1'
|
||||
option password_required '0'
|
||||
option jwt_enabled '0'
|
||||
```
|
||||
|
||||
## HAProxy Integration
|
||||
|
||||
If secubox-app-haproxy is installed, Jitsi will automatically configure a vhost:
|
||||
|
||||
```bash
|
||||
jitsctl configure-haproxy
|
||||
```
|
||||
|
||||
This creates:
|
||||
- HTTPS frontend on port 443
|
||||
- WebSocket support for real-time communication
|
||||
- SSL termination (using your certificate)
|
||||
|
||||
## Firewall
|
||||
|
||||
The following ports are required:
|
||||
|
||||
| Port | Protocol | Description |
|
||||
|------|----------|-------------|
|
||||
| 443 | TCP | HTTPS (via HAProxy) |
|
||||
| 8443 | TCP | Direct web access |
|
||||
| 10000 | UDP | Video/audio streams |
|
||||
| 4443 | TCP | TCP fallback (optional) |
|
||||
|
||||
Firewall rules are automatically added during installation.
|
||||
|
||||
## Mesh Integration
|
||||
|
||||
Enable mesh federation to:
|
||||
- Announce Jitsi on the SecuBox mesh network
|
||||
- Auto-register DNS entry (e.g., meet.c3box.mesh.local)
|
||||
- Enable multi-node video bridge deployment
|
||||
|
||||
```bash
|
||||
uci set jitsi.mesh.enabled='1'
|
||||
uci commit jitsi
|
||||
/etc/init.d/jitsi restart
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Containers not starting
|
||||
```bash
|
||||
# Check Docker status
|
||||
docker ps -a
|
||||
|
||||
# View container logs
|
||||
jitsctl logs web
|
||||
jitsctl logs prosody
|
||||
jitsctl logs jicofo
|
||||
jitsctl logs jvb
|
||||
```
|
||||
|
||||
### Video/audio not working
|
||||
1. Check UDP port 10000 is open on firewall
|
||||
2. Verify STUN servers are reachable
|
||||
3. Enable TCP fallback if behind strict NAT
|
||||
|
||||
### Authentication issues
|
||||
```bash
|
||||
# List users
|
||||
jitsctl list-users
|
||||
|
||||
# Reset user password
|
||||
jitsctl remove-user admin
|
||||
jitsctl add-user admin newpassword
|
||||
```
|
||||
|
||||
## Backup & Restore
|
||||
|
||||
```bash
|
||||
# Create backup
|
||||
jitsctl backup /tmp/jitsi-backup.tar.gz
|
||||
|
||||
# Restore
|
||||
jitsctl restore /tmp/jitsi-backup.tar.gz
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ HAProxy (443) │
|
||||
│ SSL Termination │
|
||||
└──────────────────────┬──────────────────────────────────┘
|
||||
│
|
||||
┌──────────────────────┴──────────────────────────────────┐
|
||||
│ Docker Network: meet.jitsi │
|
||||
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────────┐ │
|
||||
│ │ Web │ │ Prosody │ │ Jicofo │ │ JVB │ │
|
||||
│ │ :8443 │ │ :5222 │ │ :8888 │ │ :10000/UDP │ │
|
||||
│ │ React │ │ XMPP │ │ Focus │ │ Media │ │
|
||||
│ └─────────┘ └─────────┘ └─────────┘ └─────────────┘ │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Apache 2.0 - See LICENSE file for details.
|
||||
53
package/secubox/secubox-app-jitsi/files/etc/config/jitsi
Normal file
53
package/secubox/secubox-app-jitsi/files/etc/config/jitsi
Normal file
@ -0,0 +1,53 @@
|
||||
# Jitsi Meet Video Conferencing Configuration
|
||||
|
||||
config jitsi 'main'
|
||||
option enabled '0'
|
||||
option domain 'meet.secubox.local'
|
||||
option public_url ''
|
||||
option container_type 'docker'
|
||||
option timezone 'Europe/Paris'
|
||||
option letsencrypt '0'
|
||||
option letsencrypt_email ''
|
||||
|
||||
config jitsi 'web'
|
||||
option port '8443'
|
||||
option enable_guests '1'
|
||||
option enable_auth '0'
|
||||
option default_language 'en'
|
||||
option enable_transcription '0'
|
||||
option enable_recording '0'
|
||||
option watermark_link ''
|
||||
|
||||
config jitsi 'jvb'
|
||||
option port '10000'
|
||||
option enable_tcp_fallback '0'
|
||||
option tcp_port '4443'
|
||||
option stun_servers 'meet-jit-si-turnrelay.jitsi.net:443'
|
||||
option max_bandwidth '10000000'
|
||||
|
||||
config jitsi 'prosody'
|
||||
option c2s_port '5222'
|
||||
option http_port '5280'
|
||||
option guest_domain_enabled '1'
|
||||
|
||||
config jitsi 'jicofo'
|
||||
option port '8888'
|
||||
option enable_ocontrol '0'
|
||||
|
||||
config jitsi 'security'
|
||||
option jwt_enabled '0'
|
||||
option jwt_app_id ''
|
||||
option jwt_app_secret ''
|
||||
option lobby_enabled '1'
|
||||
option password_required '0'
|
||||
|
||||
config jitsi 'mesh'
|
||||
option enabled '0'
|
||||
option announce_service '1'
|
||||
option cascade_jvb '0'
|
||||
|
||||
config jitsi 'turn'
|
||||
option enabled '0'
|
||||
option server ''
|
||||
option username ''
|
||||
option password ''
|
||||
49
package/secubox/secubox-app-jitsi/files/etc/init.d/jitsi
Normal file
49
package/secubox/secubox-app-jitsi/files/etc/init.d/jitsi
Normal file
@ -0,0 +1,49 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
# Jitsi Meet Video Conferencing Service
|
||||
|
||||
START=95
|
||||
STOP=15
|
||||
USE_PROCD=1
|
||||
|
||||
JITSI_DIR="/srv/jitsi"
|
||||
COMPOSE_FILE="$JITSI_DIR/docker-compose.yml"
|
||||
|
||||
start_service() {
|
||||
local enabled=$(uci -q get jitsi.main.enabled)
|
||||
[ "$enabled" != "1" ] && return 0
|
||||
|
||||
# Check Docker
|
||||
if ! command -v docker >/dev/null 2>&1; then
|
||||
logger -t jitsi "Docker not available"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Generate config if needed
|
||||
if [ ! -f "$JITSI_DIR/.env" ]; then
|
||||
/usr/sbin/jitsctl generate-config
|
||||
fi
|
||||
|
||||
# Start containers
|
||||
cd "$JITSI_DIR"
|
||||
docker-compose up -d
|
||||
|
||||
logger -t jitsi "Jitsi Meet started"
|
||||
}
|
||||
|
||||
stop_service() {
|
||||
if [ -f "$COMPOSE_FILE" ]; then
|
||||
cd "$JITSI_DIR"
|
||||
docker-compose down
|
||||
fi
|
||||
logger -t jitsi "Jitsi Meet stopped"
|
||||
}
|
||||
|
||||
reload_service() {
|
||||
/usr/sbin/jitsctl generate-config
|
||||
cd "$JITSI_DIR"
|
||||
docker-compose restart
|
||||
}
|
||||
|
||||
status() {
|
||||
/usr/sbin/jitsctl status
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
# HAProxy configuration snippet for Jitsi Meet
|
||||
# Include in main haproxy.cfg or via haproxy.d directory
|
||||
|
||||
# Frontend rule for Jitsi (add to your HTTPS frontend)
|
||||
# acl is_jitsi hdr(host) -i meet.example.com
|
||||
# use_backend jitsi_web if is_jitsi
|
||||
|
||||
backend jitsi_web
|
||||
mode http
|
||||
option httpchk GET /
|
||||
http-check expect status 200
|
||||
# WebSocket support
|
||||
option http-server-close
|
||||
timeout tunnel 1h
|
||||
server jitsi 127.0.0.1:8443 check ssl verify none
|
||||
|
||||
# XMPP BOSH/WebSocket backend (if needed separately)
|
||||
backend jitsi_xmpp
|
||||
mode http
|
||||
option httpchk GET /http-bind
|
||||
server prosody 127.0.0.1:5280 check
|
||||
667
package/secubox/secubox-app-jitsi/files/usr/sbin/jitsctl
Normal file
667
package/secubox/secubox-app-jitsi/files/usr/sbin/jitsctl
Normal file
@ -0,0 +1,667 @@
|
||||
#!/bin/sh
|
||||
# Jitsi Meet Control Script for SecuBox
|
||||
# Manages Jitsi Meet Docker deployment
|
||||
|
||||
VERSION="1.0.0"
|
||||
JITSI_DIR="/srv/jitsi"
|
||||
CONFIG_DIR="$JITSI_DIR/.jitsi-meet-cfg"
|
||||
TEMPLATE_DIR="/usr/share/jitsi"
|
||||
ENV_FILE="$JITSI_DIR/.env"
|
||||
COMPOSE_FILE="$JITSI_DIR/docker-compose.yml"
|
||||
|
||||
# Jitsi Docker image versions
|
||||
JITSI_IMAGE_VERSION="stable-9location1"
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
CYAN='\033[0;36m'
|
||||
NC='\033[0m'
|
||||
|
||||
log() { echo -e "${GREEN}[JITSI]${NC} $1"; }
|
||||
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
||||
error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
||||
|
||||
# ============================================================================
|
||||
# Configuration Generation
|
||||
# ============================================================================
|
||||
|
||||
generate_secret() {
|
||||
openssl rand -hex 16 2>/dev/null || head -c 32 /dev/urandom | md5sum | cut -d' ' -f1
|
||||
}
|
||||
|
||||
generate_config() {
|
||||
log "Generating Jitsi configuration..."
|
||||
|
||||
mkdir -p "$JITSI_DIR"
|
||||
mkdir -p "$CONFIG_DIR"/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri}
|
||||
|
||||
# Read UCI configuration
|
||||
local domain=$(uci -q get jitsi.main.domain || echo "meet.secubox.local")
|
||||
local public_url=$(uci -q get jitsi.main.public_url)
|
||||
[ -z "$public_url" ] && public_url="https://$domain"
|
||||
local timezone=$(uci -q get jitsi.main.timezone || echo "UTC")
|
||||
local letsencrypt=$(uci -q get jitsi.main.letsencrypt || echo "0")
|
||||
local le_email=$(uci -q get jitsi.main.letsencrypt_email)
|
||||
|
||||
# Web config
|
||||
local web_port=$(uci -q get jitsi.web.port || echo "8443")
|
||||
local enable_guests=$(uci -q get jitsi.web.enable_guests || echo "1")
|
||||
local enable_auth=$(uci -q get jitsi.web.enable_auth || echo "0")
|
||||
local default_lang=$(uci -q get jitsi.web.default_language || echo "en")
|
||||
|
||||
# JVB config
|
||||
local jvb_port=$(uci -q get jitsi.jvb.port || echo "10000")
|
||||
local jvb_tcp=$(uci -q get jitsi.jvb.enable_tcp_fallback || echo "0")
|
||||
local jvb_tcp_port=$(uci -q get jitsi.jvb.tcp_port || echo "4443")
|
||||
local stun_servers=$(uci -q get jitsi.jvb.stun_servers || echo "meet-jit-si-turnrelay.jitsi.net:443")
|
||||
|
||||
# Security
|
||||
local jwt_enabled=$(uci -q get jitsi.security.jwt_enabled || echo "0")
|
||||
local jwt_app_id=$(uci -q get jitsi.security.jwt_app_id)
|
||||
local jwt_secret=$(uci -q get jitsi.security.jwt_app_secret)
|
||||
local lobby=$(uci -q get jitsi.security.lobby_enabled || echo "1")
|
||||
|
||||
# TURN
|
||||
local turn_enabled=$(uci -q get jitsi.turn.enabled || echo "0")
|
||||
local turn_server=$(uci -q get jitsi.turn.server)
|
||||
local turn_user=$(uci -q get jitsi.turn.username)
|
||||
local turn_pass=$(uci -q get jitsi.turn.password)
|
||||
|
||||
# Generate secrets if not already stored
|
||||
local jicofo_secret=$(uci -q get jitsi.secrets.jicofo_component_secret)
|
||||
local jicofo_auth_pass=$(uci -q get jitsi.secrets.jicofo_auth_password)
|
||||
local jvb_auth_pass=$(uci -q get jitsi.secrets.jvb_auth_password)
|
||||
|
||||
if [ -z "$jicofo_secret" ]; then
|
||||
jicofo_secret=$(generate_secret)
|
||||
uci -q set jitsi.secrets=jitsi
|
||||
uci -q set jitsi.secrets.jicofo_component_secret="$jicofo_secret"
|
||||
fi
|
||||
if [ -z "$jicofo_auth_pass" ]; then
|
||||
jicofo_auth_pass=$(generate_secret)
|
||||
uci -q set jitsi.secrets.jicofo_auth_password="$jicofo_auth_pass"
|
||||
fi
|
||||
if [ -z "$jvb_auth_pass" ]; then
|
||||
jvb_auth_pass=$(generate_secret)
|
||||
uci -q set jitsi.secrets.jvb_auth_password="$jvb_auth_pass"
|
||||
uci commit jitsi
|
||||
fi
|
||||
|
||||
# Determine auth type
|
||||
local auth_type="internal"
|
||||
[ "$enable_auth" = "1" ] && auth_type="internal_hashed"
|
||||
[ "$jwt_enabled" = "1" ] && auth_type="jwt"
|
||||
|
||||
# Write .env file
|
||||
cat > "$ENV_FILE" << EOF
|
||||
# Jitsi Meet Configuration
|
||||
# Generated by SecuBox jitsctl v$VERSION
|
||||
# $(date)
|
||||
|
||||
# Core settings
|
||||
CONFIG=$CONFIG_DIR
|
||||
HTTP_PORT=8000
|
||||
HTTPS_PORT=$web_port
|
||||
TZ=$timezone
|
||||
|
||||
# Domain settings
|
||||
PUBLIC_URL=$public_url
|
||||
XMPP_DOMAIN=$domain
|
||||
XMPP_SERVER=xmpp.$domain
|
||||
JVB_BREWERY_MUC=jvbbrewery
|
||||
XMPP_AUTH_DOMAIN=auth.$domain
|
||||
XMPP_GUEST_DOMAIN=guest.$domain
|
||||
XMPP_MUC_DOMAIN=muc.$domain
|
||||
XMPP_INTERNAL_MUC_DOMAIN=internal-muc.$domain
|
||||
XMPP_MODULES=
|
||||
XMPP_MUC_MODULES=
|
||||
XMPP_INTERNAL_MUC_MODULES=
|
||||
|
||||
# Authentication
|
||||
ENABLE_AUTH=$enable_auth
|
||||
ENABLE_GUESTS=$enable_guests
|
||||
AUTH_TYPE=$auth_type
|
||||
|
||||
# JWT (if enabled)
|
||||
EOF
|
||||
|
||||
if [ "$jwt_enabled" = "1" ]; then
|
||||
cat >> "$ENV_FILE" << EOF
|
||||
JWT_APP_ID=$jwt_app_id
|
||||
JWT_APP_SECRET=$jwt_secret
|
||||
JWT_ACCEPTED_ISSUERS=$jwt_app_id
|
||||
JWT_ACCEPTED_AUDIENCES=$jwt_app_id
|
||||
EOF
|
||||
fi
|
||||
|
||||
cat >> "$ENV_FILE" << EOF
|
||||
|
||||
# XMPP secrets
|
||||
JICOFO_COMPONENT_SECRET=$jicofo_secret
|
||||
JICOFO_AUTH_USER=focus
|
||||
JICOFO_AUTH_PASSWORD=$jicofo_auth_pass
|
||||
JVB_AUTH_USER=jvb
|
||||
JVB_AUTH_PASSWORD=$jvb_auth_pass
|
||||
|
||||
# JVB settings
|
||||
JVB_PORT=$jvb_port
|
||||
JVB_STUN_SERVERS=$stun_servers
|
||||
JVB_TCP_HARVESTER_DISABLED=$([ "$jvb_tcp" = "1" ] && echo "false" || echo "true")
|
||||
JVB_TCP_PORT=$jvb_tcp_port
|
||||
|
||||
# Features
|
||||
ENABLE_LOBBY=$lobby
|
||||
ENABLE_BREAKOUT_ROOMS=1
|
||||
ENABLE_PREJOIN_PAGE=1
|
||||
ENABLE_WELCOME_PAGE=1
|
||||
ENABLE_CLOSE_PAGE=0
|
||||
ENABLE_NOISY_MIC_DETECTION=1
|
||||
ENABLE_TALK_WHILE_MUTED=1
|
||||
ENABLE_REACTIONS=1
|
||||
|
||||
# UI settings
|
||||
DEFAULT_LANGUAGE=$default_lang
|
||||
DISABLE_AUDIO_LEVELS=0
|
||||
DISABLE_POLLS=0
|
||||
ENABLE_CALENDAR=0
|
||||
EOF
|
||||
|
||||
# Add TURN config if enabled
|
||||
if [ "$turn_enabled" = "1" ] && [ -n "$turn_server" ]; then
|
||||
cat >> "$ENV_FILE" << EOF
|
||||
|
||||
# TURN server
|
||||
TURN_CREDENTIALS=$turn_user
|
||||
TURN_SECRET=$turn_pass
|
||||
TURN_HOST=$turn_server
|
||||
TURN_PORT=443
|
||||
TURNS_HOST=$turn_server
|
||||
TURNS_PORT=443
|
||||
EOF
|
||||
fi
|
||||
|
||||
# Add Let's Encrypt config
|
||||
if [ "$letsencrypt" = "1" ] && [ -n "$le_email" ]; then
|
||||
cat >> "$ENV_FILE" << EOF
|
||||
|
||||
# Let's Encrypt
|
||||
ENABLE_LETSENCRYPT=1
|
||||
LETSENCRYPT_DOMAIN=$domain
|
||||
LETSENCRYPT_EMAIL=$le_email
|
||||
LETSENCRYPT_USE_STAGING=0
|
||||
EOF
|
||||
fi
|
||||
|
||||
# Copy docker-compose.yml
|
||||
cp "$TEMPLATE_DIR/docker-compose.yml" "$COMPOSE_FILE"
|
||||
|
||||
log "Configuration generated at $ENV_FILE"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Installation
|
||||
# ============================================================================
|
||||
|
||||
install_jitsi() {
|
||||
log "Installing Jitsi Meet..."
|
||||
|
||||
# Check Docker
|
||||
if ! command -v docker >/dev/null 2>&1; then
|
||||
error "Docker is required. Install with: opkg install docker docker-compose"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Create directories
|
||||
mkdir -p "$JITSI_DIR"
|
||||
mkdir -p "$CONFIG_DIR"
|
||||
|
||||
# Generate configuration
|
||||
generate_config
|
||||
|
||||
# Pull images
|
||||
log "Pulling Jitsi Docker images (this may take a while)..."
|
||||
cd "$JITSI_DIR"
|
||||
docker-compose pull
|
||||
|
||||
# Configure HAProxy if available
|
||||
if [ -x /usr/sbin/haproxyctl ]; then
|
||||
configure_haproxy
|
||||
fi
|
||||
|
||||
# Configure firewall
|
||||
configure_firewall
|
||||
|
||||
# Register with mesh
|
||||
register_mesh_service
|
||||
|
||||
log "Jitsi Meet installed successfully!"
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo " 1. Set your domain: uci set jitsi.main.domain='meet.example.com'"
|
||||
echo " 2. Commit changes: uci commit jitsi"
|
||||
echo " 3. Regenerate: jitsctl generate-config"
|
||||
echo " 4. Enable service: uci set jitsi.main.enabled=1 && uci commit jitsi"
|
||||
echo " 5. Start: /etc/init.d/jitsi start"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# HAProxy Integration
|
||||
# ============================================================================
|
||||
|
||||
configure_haproxy() {
|
||||
log "Configuring HAProxy for Jitsi..."
|
||||
|
||||
local domain=$(uci -q get jitsi.main.domain || echo "meet.secubox.local")
|
||||
local web_port=$(uci -q get jitsi.web.port || echo "8443")
|
||||
|
||||
# Check if vhost already exists
|
||||
local existing=$(uci show haproxy 2>/dev/null | grep "\.domain='$domain'" | head -1)
|
||||
if [ -n "$existing" ]; then
|
||||
warn "HAProxy vhost for $domain already exists"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Add backend
|
||||
uci -q add haproxy backend
|
||||
uci -q set haproxy.@backend[-1].name='jitsi_web'
|
||||
uci -q set haproxy.@backend[-1].mode='http'
|
||||
uci -q add_list haproxy.@backend[-1].server="jitsi 127.0.0.1:$web_port check"
|
||||
|
||||
# Add vhost
|
||||
uci -q add haproxy vhost
|
||||
uci -q set haproxy.@vhost[-1].enabled='1'
|
||||
uci -q set haproxy.@vhost[-1].domain="$domain"
|
||||
uci -q set haproxy.@vhost[-1].backend='jitsi_web'
|
||||
uci -q set haproxy.@vhost[-1].ssl='1'
|
||||
uci -q set haproxy.@vhost[-1].ssl_redirect='1'
|
||||
uci -q set haproxy.@vhost[-1].websocket='1'
|
||||
|
||||
uci commit haproxy
|
||||
|
||||
# Reload HAProxy
|
||||
/etc/init.d/haproxy reload 2>/dev/null
|
||||
|
||||
log "HAProxy configured for $domain"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Firewall
|
||||
# ============================================================================
|
||||
|
||||
configure_firewall() {
|
||||
log "Configuring firewall..."
|
||||
|
||||
local jvb_port=$(uci -q get jitsi.jvb.port || echo "10000")
|
||||
local jvb_tcp_port=$(uci -q get jitsi.jvb.tcp_port || echo "4443")
|
||||
|
||||
# JVB UDP port (required for video)
|
||||
if ! uci show firewall 2>/dev/null | grep -q "Jitsi-JVB"; then
|
||||
uci add firewall rule
|
||||
uci set firewall.@rule[-1].name='Jitsi-JVB'
|
||||
uci set firewall.@rule[-1].src='wan'
|
||||
uci set firewall.@rule[-1].dest_port="$jvb_port"
|
||||
uci set firewall.@rule[-1].proto='udp'
|
||||
uci set firewall.@rule[-1].target='ACCEPT'
|
||||
uci set firewall.@rule[-1].enabled='1'
|
||||
fi
|
||||
|
||||
# JVB TCP fallback port
|
||||
local jvb_tcp=$(uci -q get jitsi.jvb.enable_tcp_fallback || echo "0")
|
||||
if [ "$jvb_tcp" = "1" ]; then
|
||||
if ! uci show firewall 2>/dev/null | grep -q "Jitsi-JVB-TCP"; then
|
||||
uci add firewall rule
|
||||
uci set firewall.@rule[-1].name='Jitsi-JVB-TCP'
|
||||
uci set firewall.@rule[-1].src='wan'
|
||||
uci set firewall.@rule[-1].dest_port="$jvb_tcp_port"
|
||||
uci set firewall.@rule[-1].proto='tcp'
|
||||
uci set firewall.@rule[-1].target='ACCEPT'
|
||||
uci set firewall.@rule[-1].enabled='1'
|
||||
fi
|
||||
fi
|
||||
|
||||
uci commit firewall
|
||||
/etc/init.d/firewall reload 2>/dev/null
|
||||
|
||||
log "Firewall configured"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Mesh Integration
|
||||
# ============================================================================
|
||||
|
||||
register_mesh_service() {
|
||||
local mesh_enabled=$(uci -q get jitsi.mesh.enabled || echo "0")
|
||||
[ "$mesh_enabled" != "1" ] && return 0
|
||||
|
||||
local domain=$(uci -q get jitsi.main.domain)
|
||||
local web_port=$(uci -q get jitsi.web.port || echo "8443")
|
||||
|
||||
# Register with P2P daemon
|
||||
if [ -x /usr/sbin/secubox-p2p ]; then
|
||||
/usr/sbin/secubox-p2p register-service jitsi-meet "$web_port" 2>/dev/null
|
||||
log "Registered Jitsi with mesh network"
|
||||
fi
|
||||
|
||||
# Add DNS entry if DNS federation enabled
|
||||
local dns_enabled=$(uci -q get secubox-p2p.dns.enabled || echo "0")
|
||||
if [ "$dns_enabled" = "1" ]; then
|
||||
local dns_domain=$(uci -q get secubox-p2p.dns.base_domain || echo "mesh.local")
|
||||
local hostname=$(echo "$domain" | cut -d'.' -f1)
|
||||
log "Mesh DNS: $hostname.$dns_domain"
|
||||
fi
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# User Management
|
||||
# ============================================================================
|
||||
|
||||
add_user() {
|
||||
local username="$1"
|
||||
local password="$2"
|
||||
|
||||
if [ -z "$username" ] || [ -z "$password" ]; then
|
||||
echo "Usage: jitsctl add-user <username> <password>"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local domain=$(uci -q get jitsi.main.domain)
|
||||
|
||||
log "Adding user: $username"
|
||||
|
||||
docker exec jitsi-prosody prosodyctl register "$username" "$domain" "$password"
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
log "User $username added successfully"
|
||||
else
|
||||
error "Failed to add user $username"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
remove_user() {
|
||||
local username="$1"
|
||||
|
||||
if [ -z "$username" ]; then
|
||||
echo "Usage: jitsctl remove-user <username>"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local domain=$(uci -q get jitsi.main.domain)
|
||||
|
||||
log "Removing user: $username"
|
||||
|
||||
docker exec jitsi-prosody prosodyctl unregister "$username" "$domain"
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
log "User $username removed"
|
||||
else
|
||||
error "Failed to remove user $username"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
list_users() {
|
||||
local domain=$(uci -q get jitsi.main.domain)
|
||||
|
||||
echo "Registered users for $domain:"
|
||||
docker exec jitsi-prosody ls -1 /config/data/"$domain"/accounts/ 2>/dev/null | sed 's/\.dat$//'
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Status & Logs
|
||||
# ============================================================================
|
||||
|
||||
show_status() {
|
||||
echo ""
|
||||
echo "========================================"
|
||||
echo " Jitsi Meet Status v$VERSION"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
|
||||
local enabled=$(uci -q get jitsi.main.enabled)
|
||||
local domain=$(uci -q get jitsi.main.domain)
|
||||
local public_url=$(uci -q get jitsi.main.public_url)
|
||||
[ -z "$public_url" ] && public_url="https://$domain"
|
||||
|
||||
echo "Configuration:"
|
||||
echo " Enabled: $([ "$enabled" = "1" ] && echo -e "${GREEN}Yes${NC}" || echo -e "${RED}No${NC}")"
|
||||
echo " Domain: $domain"
|
||||
echo " Public URL: $public_url"
|
||||
echo ""
|
||||
|
||||
if ! command -v docker >/dev/null 2>&1; then
|
||||
echo -e "Docker: ${RED}Not installed${NC}"
|
||||
return
|
||||
fi
|
||||
|
||||
echo "Containers:"
|
||||
for container in jitsi-web jitsi-prosody jitsi-jicofo jitsi-jvb; do
|
||||
local state=$(docker inspect -f '{{.State.Status}}' "$container" 2>/dev/null)
|
||||
if [ "$state" = "running" ]; then
|
||||
echo -e " $container: ${GREEN}Running${NC}"
|
||||
elif [ -n "$state" ]; then
|
||||
echo -e " $container: ${YELLOW}$state${NC}"
|
||||
else
|
||||
echo -e " $container: ${RED}Not found${NC}"
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
|
||||
# Show ports
|
||||
local jvb_port=$(uci -q get jitsi.jvb.port || echo "10000")
|
||||
local web_port=$(uci -q get jitsi.web.port || echo "8443")
|
||||
echo "Ports:"
|
||||
echo " Web: $web_port/tcp"
|
||||
echo " JVB Media: $jvb_port/udp"
|
||||
echo ""
|
||||
|
||||
# Show active conferences (if available)
|
||||
local stats=$(docker exec jitsi-jvb curl -s http://localhost:8080/colibri/stats 2>/dev/null)
|
||||
if [ -n "$stats" ]; then
|
||||
local conferences=$(echo "$stats" | jsonfilter -e '@.conferences' 2>/dev/null || echo "0")
|
||||
local participants=$(echo "$stats" | jsonfilter -e '@.participants' 2>/dev/null || echo "0")
|
||||
echo "Active:"
|
||||
echo " Conferences: $conferences"
|
||||
echo " Participants: $participants"
|
||||
echo ""
|
||||
fi
|
||||
}
|
||||
|
||||
show_logs() {
|
||||
local service="$1"
|
||||
local lines="${2:-50}"
|
||||
|
||||
cd "$JITSI_DIR"
|
||||
|
||||
case "$service" in
|
||||
web|prosody|jicofo|jvb)
|
||||
docker-compose logs --tail="$lines" "$service"
|
||||
;;
|
||||
all|"")
|
||||
docker-compose logs --tail="$lines"
|
||||
;;
|
||||
*)
|
||||
echo "Usage: jitsctl logs [web|prosody|jicofo|jvb|all] [lines]"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
shell() {
|
||||
local container="${1:-jitsi-prosody}"
|
||||
|
||||
log "Connecting to $container..."
|
||||
docker exec -it "$container" /bin/bash 2>/dev/null || docker exec -it "$container" /bin/sh
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Upgrade
|
||||
# ============================================================================
|
||||
|
||||
upgrade() {
|
||||
log "Upgrading Jitsi Meet..."
|
||||
|
||||
cd "$JITSI_DIR"
|
||||
|
||||
# Pull latest images
|
||||
docker-compose pull
|
||||
|
||||
# Restart with new images
|
||||
docker-compose down
|
||||
docker-compose up -d
|
||||
|
||||
# Cleanup old images
|
||||
docker image prune -f
|
||||
|
||||
log "Jitsi Meet upgraded"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Backup / Restore
|
||||
# ============================================================================
|
||||
|
||||
backup() {
|
||||
local backup_file="${1:-/tmp/jitsi-backup-$(date +%Y%m%d-%H%M%S).tar.gz}"
|
||||
|
||||
log "Creating backup..."
|
||||
|
||||
tar -czf "$backup_file" \
|
||||
-C / \
|
||||
etc/config/jitsi \
|
||||
"$CONFIG_DIR" \
|
||||
"$ENV_FILE" \
|
||||
2>/dev/null
|
||||
|
||||
if [ -f "$backup_file" ]; then
|
||||
local size=$(ls -lh "$backup_file" | awk '{print $5}')
|
||||
log "Backup created: $backup_file ($size)"
|
||||
else
|
||||
error "Backup failed"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
restore() {
|
||||
local backup_file="$1"
|
||||
|
||||
if [ -z "$backup_file" ] || [ ! -f "$backup_file" ]; then
|
||||
echo "Usage: jitsctl restore <backup_file>"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log "Restoring from $backup_file..."
|
||||
|
||||
# Stop service
|
||||
/etc/init.d/jitsi stop 2>/dev/null
|
||||
|
||||
# Extract backup
|
||||
tar -xzf "$backup_file" -C /
|
||||
|
||||
# Restart
|
||||
/etc/init.d/jitsi start
|
||||
|
||||
log "Restore complete"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Main
|
||||
# ============================================================================
|
||||
|
||||
show_help() {
|
||||
cat << EOF
|
||||
Jitsi Meet Control v$VERSION
|
||||
|
||||
Usage: jitsctl <command> [options]
|
||||
|
||||
Commands:
|
||||
install Install Jitsi Meet Docker stack
|
||||
generate-config Generate/update configuration from UCI
|
||||
status Show service status
|
||||
logs [svc] [n] Show container logs
|
||||
shell [container] Access container shell
|
||||
|
||||
start Start all containers
|
||||
stop Stop all containers
|
||||
restart Restart all containers
|
||||
upgrade Upgrade to latest images
|
||||
|
||||
add-user <u> <p> Add authenticated user
|
||||
remove-user <u> Remove user
|
||||
list-users List registered users
|
||||
|
||||
backup [file] Create configuration backup
|
||||
restore <file> Restore from backup
|
||||
|
||||
configure-haproxy Add HAProxy vhost
|
||||
configure-fw Configure firewall rules
|
||||
|
||||
Examples:
|
||||
jitsctl install
|
||||
jitsctl status
|
||||
jitsctl logs jvb 100
|
||||
jitsctl add-user admin secretpassword
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
install)
|
||||
install_jitsi
|
||||
;;
|
||||
generate-config)
|
||||
generate_config
|
||||
;;
|
||||
status)
|
||||
show_status
|
||||
;;
|
||||
logs)
|
||||
show_logs "$2" "$3"
|
||||
;;
|
||||
shell)
|
||||
shell "$2"
|
||||
;;
|
||||
start)
|
||||
cd "$JITSI_DIR" && docker-compose up -d
|
||||
;;
|
||||
stop)
|
||||
cd "$JITSI_DIR" && docker-compose down
|
||||
;;
|
||||
restart)
|
||||
cd "$JITSI_DIR" && docker-compose restart
|
||||
;;
|
||||
upgrade)
|
||||
upgrade
|
||||
;;
|
||||
add-user)
|
||||
add_user "$2" "$3"
|
||||
;;
|
||||
remove-user)
|
||||
remove_user "$2"
|
||||
;;
|
||||
list-users)
|
||||
list_users
|
||||
;;
|
||||
backup)
|
||||
backup "$2"
|
||||
;;
|
||||
restore)
|
||||
restore "$2"
|
||||
;;
|
||||
configure-haproxy)
|
||||
configure_haproxy
|
||||
;;
|
||||
configure-fw)
|
||||
configure_firewall
|
||||
;;
|
||||
-h|--help|help)
|
||||
show_help
|
||||
;;
|
||||
*)
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
@ -0,0 +1,138 @@
|
||||
# Jitsi Meet Docker Compose for SecuBox
|
||||
# Based on https://github.com/jitsi/docker-jitsi-meet
|
||||
|
||||
version: '3.5'
|
||||
|
||||
services:
|
||||
# Frontend web server
|
||||
web:
|
||||
image: jitsi/web:${JITSI_IMAGE_VERSION:-stable}
|
||||
container_name: jitsi-web
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- '${HTTP_PORT:-8000}:80'
|
||||
- '${HTTPS_PORT:-8443}:443'
|
||||
volumes:
|
||||
- ${CONFIG}/web:/config:Z
|
||||
- ${CONFIG}/transcripts:/usr/share/jitsi-meet/transcripts:Z
|
||||
environment:
|
||||
- ENABLE_AUTH
|
||||
- ENABLE_GUESTS
|
||||
- ENABLE_LOBBY
|
||||
- ENABLE_PREJOIN_PAGE
|
||||
- ENABLE_WELCOME_PAGE
|
||||
- ENABLE_BREAKOUT_ROOMS
|
||||
- ENABLE_REACTIONS
|
||||
- ENABLE_NOISY_MIC_DETECTION
|
||||
- ENABLE_TALK_WHILE_MUTED
|
||||
- DEFAULT_LANGUAGE
|
||||
- PUBLIC_URL
|
||||
- TZ
|
||||
- XMPP_AUTH_DOMAIN
|
||||
- XMPP_BOSH_URL_BASE
|
||||
- XMPP_DOMAIN
|
||||
- XMPP_GUEST_DOMAIN
|
||||
- XMPP_MUC_DOMAIN
|
||||
networks:
|
||||
meet.jitsi:
|
||||
aliases:
|
||||
- ${XMPP_DOMAIN}
|
||||
|
||||
# XMPP server
|
||||
prosody:
|
||||
image: jitsi/prosody:${JITSI_IMAGE_VERSION:-stable}
|
||||
container_name: jitsi-prosody
|
||||
restart: unless-stopped
|
||||
expose:
|
||||
- '5222'
|
||||
- '5347'
|
||||
- '5280'
|
||||
volumes:
|
||||
- ${CONFIG}/prosody/config:/config:Z
|
||||
- ${CONFIG}/prosody/prosody-plugins-custom:/prosody-plugins-custom:Z
|
||||
environment:
|
||||
- AUTH_TYPE
|
||||
- ENABLE_AUTH
|
||||
- ENABLE_GUESTS
|
||||
- ENABLE_LOBBY
|
||||
- ENABLE_XMPP_WEBSOCKET
|
||||
- JICOFO_AUTH_USER
|
||||
- JICOFO_AUTH_PASSWORD
|
||||
- JICOFO_COMPONENT_SECRET
|
||||
- JVB_AUTH_USER
|
||||
- JVB_AUTH_PASSWORD
|
||||
- JWT_APP_ID
|
||||
- JWT_APP_SECRET
|
||||
- JWT_ACCEPTED_ISSUERS
|
||||
- JWT_ACCEPTED_AUDIENCES
|
||||
- PUBLIC_URL
|
||||
- TZ
|
||||
- XMPP_DOMAIN
|
||||
- XMPP_AUTH_DOMAIN
|
||||
- XMPP_GUEST_DOMAIN
|
||||
- XMPP_MUC_DOMAIN
|
||||
- XMPP_INTERNAL_MUC_DOMAIN
|
||||
networks:
|
||||
meet.jitsi:
|
||||
aliases:
|
||||
- ${XMPP_SERVER:-xmpp.meet.jitsi}
|
||||
|
||||
# Conference focus
|
||||
jicofo:
|
||||
image: jitsi/jicofo:${JITSI_IMAGE_VERSION:-stable}
|
||||
container_name: jitsi-jicofo
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ${CONFIG}/jicofo:/config:Z
|
||||
environment:
|
||||
- AUTH_TYPE
|
||||
- ENABLE_AUTH
|
||||
- ENABLE_AUTO_OWNER
|
||||
- JICOFO_AUTH_USER
|
||||
- JICOFO_AUTH_PASSWORD
|
||||
- JICOFO_ENABLE_BRIDGE_HEALTH_CHECKS
|
||||
- JICOFO_ENABLE_HEALTH_CHECKS
|
||||
- JVB_BREWERY_MUC
|
||||
- TZ
|
||||
- XMPP_DOMAIN
|
||||
- XMPP_AUTH_DOMAIN
|
||||
- XMPP_INTERNAL_MUC_DOMAIN
|
||||
- XMPP_MUC_DOMAIN
|
||||
- XMPP_SERVER
|
||||
depends_on:
|
||||
- prosody
|
||||
networks:
|
||||
meet.jitsi:
|
||||
|
||||
# Video bridge (SFU)
|
||||
jvb:
|
||||
image: jitsi/jvb:${JITSI_IMAGE_VERSION:-stable}
|
||||
container_name: jitsi-jvb
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- '${JVB_PORT:-10000}:${JVB_PORT:-10000}/udp'
|
||||
- '127.0.0.1:8080:8080'
|
||||
volumes:
|
||||
- ${CONFIG}/jvb:/config:Z
|
||||
environment:
|
||||
- DOCKER_HOST_ADDRESS
|
||||
- ENABLE_COLIBRI_WEBSOCKET
|
||||
- JVB_AUTH_USER
|
||||
- JVB_AUTH_PASSWORD
|
||||
- JVB_BREWERY_MUC
|
||||
- JVB_PORT
|
||||
- JVB_STUN_SERVERS
|
||||
- JVB_ENABLE_APIS
|
||||
- PUBLIC_URL
|
||||
- TZ
|
||||
- XMPP_AUTH_DOMAIN
|
||||
- XMPP_INTERNAL_MUC_DOMAIN
|
||||
- XMPP_SERVER
|
||||
depends_on:
|
||||
- prosody
|
||||
networks:
|
||||
meet.jitsi:
|
||||
|
||||
networks:
|
||||
meet.jitsi:
|
||||
driver: bridge
|
||||
@ -0,0 +1,37 @@
|
||||
# Jitsi Meet Environment Template
|
||||
# This file is processed by jitsctl to generate .env
|
||||
|
||||
CONFIG=/srv/jitsi/.jitsi-meet-cfg
|
||||
HTTP_PORT=8000
|
||||
HTTPS_PORT=8443
|
||||
TZ=UTC
|
||||
|
||||
PUBLIC_URL=https://meet.example.com
|
||||
XMPP_DOMAIN=meet.example.com
|
||||
XMPP_SERVER=xmpp.meet.example.com
|
||||
XMPP_AUTH_DOMAIN=auth.meet.example.com
|
||||
XMPP_GUEST_DOMAIN=guest.meet.example.com
|
||||
XMPP_MUC_DOMAIN=muc.meet.example.com
|
||||
XMPP_INTERNAL_MUC_DOMAIN=internal-muc.meet.example.com
|
||||
|
||||
ENABLE_AUTH=0
|
||||
ENABLE_GUESTS=1
|
||||
AUTH_TYPE=internal
|
||||
|
||||
JICOFO_COMPONENT_SECRET=changeme
|
||||
JICOFO_AUTH_USER=focus
|
||||
JICOFO_AUTH_PASSWORD=changeme
|
||||
JVB_AUTH_USER=jvb
|
||||
JVB_AUTH_PASSWORD=changeme
|
||||
JVB_BREWERY_MUC=jvbbrewery
|
||||
|
||||
JVB_PORT=10000
|
||||
JVB_STUN_SERVERS=meet-jit-si-turnrelay.jitsi.net:443
|
||||
|
||||
ENABLE_LOBBY=1
|
||||
ENABLE_BREAKOUT_ROOMS=1
|
||||
ENABLE_PREJOIN_PAGE=1
|
||||
ENABLE_WELCOME_PAGE=1
|
||||
ENABLE_REACTIONS=1
|
||||
|
||||
DEFAULT_LANGUAGE=en
|
||||
@ -0,0 +1,58 @@
|
||||
-- Prosody configuration template for SecuBox Jitsi
|
||||
-- This is a reference template; actual config is generated by Docker
|
||||
|
||||
plugin_paths = { "/prosody-plugins/", "/prosody-plugins-custom" }
|
||||
|
||||
muc_mapper_domain_base = "XMPP_DOMAIN";
|
||||
muc_mapper_domain_prefix = "muc";
|
||||
|
||||
http_default_host = "XMPP_DOMAIN"
|
||||
|
||||
consider_bosh_secure = true;
|
||||
consider_websocket_secure = true;
|
||||
|
||||
cross_domain_bosh = true;
|
||||
cross_domain_websocket = true;
|
||||
|
||||
VirtualHost "XMPP_DOMAIN"
|
||||
authentication = "AUTH_TYPE"
|
||||
ssl = {
|
||||
key = "/config/certs/XMPP_DOMAIN.key";
|
||||
certificate = "/config/certs/XMPP_DOMAIN.crt";
|
||||
}
|
||||
modules_enabled = {
|
||||
"bosh";
|
||||
"websocket";
|
||||
"smacks";
|
||||
"pubsub";
|
||||
"ping";
|
||||
"speakerstats";
|
||||
"conference_duration";
|
||||
"room_metadata";
|
||||
"muc_lobby_rooms";
|
||||
"muc_breakout_rooms";
|
||||
"av_moderation";
|
||||
"polls";
|
||||
}
|
||||
main_muc = "MUC_DOMAIN"
|
||||
lobby_muc = "lobby.XMPP_DOMAIN"
|
||||
breakout_rooms_muc = "breakout.XMPP_DOMAIN"
|
||||
|
||||
VirtualHost "GUEST_DOMAIN"
|
||||
authentication = "anonymous"
|
||||
|
||||
Component "MUC_DOMAIN" "muc"
|
||||
storage = "memory"
|
||||
modules_enabled = {
|
||||
"muc_meeting_id";
|
||||
"muc_domain_mapper";
|
||||
"polls";
|
||||
}
|
||||
muc_room_locking = false
|
||||
muc_room_default_public_jids = true
|
||||
|
||||
Component "AUTH_DOMAIN" "speakerstats_component"
|
||||
muc_component = "MUC_DOMAIN"
|
||||
|
||||
Component "focus.XMPP_DOMAIN" "client_proxy"
|
||||
target_address = "focus@AUTH_DOMAIN"
|
||||
@ -0,0 +1,59 @@
|
||||
{
|
||||
"id": "secubox-app-jitsi",
|
||||
"name": "Jitsi Meet",
|
||||
"version": "1.0.0",
|
||||
"category": "communication",
|
||||
"description": "Self-hosted video conferencing with end-to-end encryption",
|
||||
"long_description": "Jitsi Meet is a secure, fully featured, and completely free video conferencing solution. Host your own video meetings with end-to-end encryption, no account required for guests, screen sharing, chat, reactions, and more. Runs via Docker containers for easy deployment.",
|
||||
"icon": "video",
|
||||
"author": "CyberMind Studio",
|
||||
"license": "Apache-2.0",
|
||||
"homepage": "https://jitsi.org",
|
||||
"repository": "https://github.com/jitsi/jitsi-meet",
|
||||
"packages": [
|
||||
"secubox-app-jitsi",
|
||||
"luci-app-jitsi"
|
||||
],
|
||||
"dependencies": [
|
||||
"docker",
|
||||
"docker-compose"
|
||||
],
|
||||
"optional": [
|
||||
"secubox-app-haproxy"
|
||||
],
|
||||
"ports": [
|
||||
{"port": 8443, "protocol": "tcp", "description": "Web interface (HTTPS)"},
|
||||
{"port": 10000, "protocol": "udp", "description": "Video/audio streams"},
|
||||
{"port": 4443, "protocol": "tcp", "description": "TCP fallback"}
|
||||
],
|
||||
"resources": {
|
||||
"ram_min": "2048",
|
||||
"ram_recommended": "4096",
|
||||
"disk": "500",
|
||||
"cpu": "medium"
|
||||
},
|
||||
"features": [
|
||||
"End-to-end encrypted video",
|
||||
"No account required for guests",
|
||||
"Screen sharing",
|
||||
"Chat and reactions",
|
||||
"Virtual backgrounds",
|
||||
"Breakout rooms",
|
||||
"Recording (optional)",
|
||||
"Mobile app support",
|
||||
"HAProxy integration",
|
||||
"Mesh federation"
|
||||
],
|
||||
"tags": ["video", "conferencing", "webrtc", "communication", "meetings", "collaboration"],
|
||||
"screenshots": [],
|
||||
"documentation": "https://jitsi.github.io/handbook/docs/intro",
|
||||
"config_file": "/etc/config/jitsi",
|
||||
"service_name": "jitsi",
|
||||
"web_interface": {
|
||||
"port": 8443,
|
||||
"path": "/",
|
||||
"ssl": true
|
||||
},
|
||||
"haproxy_integration": true,
|
||||
"mesh_service": true
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user