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:
CyberMind-FR 2026-01-31 13:29:06 +01:00
parent 760408c36f
commit 00082fe066
15 changed files with 1846 additions and 0 deletions

View 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))

View File

@ -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();
}
});

View 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

View File

@ -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}
}
}
}

View File

@ -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"]
}
}
}

View 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))

View 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.

View 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 ''

View 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
}

View File

@ -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

View 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

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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
}