Quiero empezar a ofrecer cursos (gratuitos y de pago) y me gustaría contar con una plataforma de videoconferencia online que no depende de código privativo ni servidores foráneos. Por eso, me puse manos a la obra para instalar y configurar una instancia de Jitsi en mi propio servidor (donde almaceno, entre otras cosas esta web y el repositorio oficial de Quirinux). Por un tema de seguridad (legalidad y responsabilidades) se me hacía peligroso pensar que cualquiera pudiera ingresar a mi instancia y crear reuniones. Se me ocurrió que tendría que existir alguna manera de crear un único usuario autenticado que pudiera crear y moderar las reuniones, habilitando a cualquier usuario anónimo a asistir a las charlas (pero sin poder crear nuevas ni moderar).
Arquitectura de Jitsi Meet
Jitsi necesita varios servicios para poder funcionar correctamente:
1. Prosody – Servidor XMPP (Jabber)
- Es el corazón de las comunicaciones en Jitsi
- Gestiona la autenticación de usuarios
- Coordina las sesiones y la señalización entre participantes
- Permite que los diferentes componentes de Jitsi se comuniquen entre sí
- En este manual configuramos dos dominios virtuales:
jitsi.quirinux.org: con autenticacióninternal_hashedpara moderadoresguest.jitsi.quirinux.org: con autenticaciónanonymouspara invitados
2. Jicofo (Jitsi Conference Focus)
- Actúa como el “director de orquesta” de las conferencias
- Gestiona la creación y destrucción de salas de reunión
- Asigna participantes a los bridges (JVB) según la carga
- Coordina la negociación de medios entre participantes
- Problema crítico encontrado: Jicofo rechazaba automáticamente la suscripción de presencia del componente
client_proxyde Prosody, impidiendo que las peticiones de conferencia llegaran correctamente. La solución fue añadir manualmentefocus.jitsi.quirinux.orgal roster de Jicofo con suscripción bidireccional (both).
3. JVB (Jitsi Videobridge)
- Es el “puente de video” que enruta los flujos multimedia
- Funciona como SFU (Selective Forwarding Unit)
- Recibe video/audio de cada participante y lo reenvía a los demás
- Optimiza el ancho de banda en conferencias grandes
- Puede escalarse horizontalmente añadiendo más bridges
4. Servidor Web (Apache en nuestro caso)
- Sirve la interfaz web de Jitsi Meet
- Maneja los certificados SSL/TLS
- Hace proxy de las conexiones WebSocket para XMPP
- Gestiona las peticiones HTTP/HTTPS
5. Componentes adicionales de Prosody
client_proxy: Permite que Jicofo no tenga que registrarse como componente completo, sino que actúa como proxy hacia el usuariofocus@auth.jitsi.quirinux.org- Varios componentes MUC (Multi-User Chat) para salas, lobbies y breakout rooms
- Componentes para funcionalidades como estadísticas, grabación, moderación AV, etc.
El desafío de la autenticación
La configuración predeterminada de Jitsi permite que cualquiera cree salas libremente (modo completamente anónimo). Esto es ideal para servicios públicos como meet.jit.si, pero representa un riesgo de seguridad y legal cuando administras tu propia instancia: usuarios maliciosos podrían usar tu servidor para actividades ilegales, consumir recursos sin control, o simplemente crear spam de salas.
La solución implementada en este manual establece un modelo de autenticación selectiva:
- Solo usuarios autenticados (como
charlie@jitsi.quirinux.org) pueden crear nuevas salas - Una vez creada la sala, cualquier persona puede unirse como invitado anónimo
- Los invitados no pueden crear salas nuevas ni moderar las existentes
Este modelo es perfecto para:
- Cursos y formaciones online
- Webinars y conferencias
- Reuniones corporativas con invitados externos
- Cualquier escenario donde quieras controlar quién inicia las sesiones pero permitir participación libre
El problema del roster y su solución
Durante la configuración encontramos un problema técnico crítico no documentado en los manuales oficiales de Jitsi: cuando se habilita la autenticación, el componente client_proxy de Prosody envía una suscripción de presencia a Jicofo para poder enrutar las peticiones de conferencia. Sin embargo, Jicofo (que usa la librería XMPP Smack de Java) rechaza automáticamente esta suscripción con un mensaje unsubscribed, porque por defecto no acepta suscripciones de entidades desconocidas.
El resultado es que aunque Jicofo esté conectado y funcionando, el client_proxy mantiene un array de sesiones vacío (#sessions == 0), y cuando un cliente intenta crear una conferencia, recibe inmediatamente un error service-unavailable porque el proxy cree que no hay ningún Jicofo disponible.
La solución consiste en añadir manualmente focus.jitsi.quirinux.org al roster de Jicofo en la base de datos de Prosody, estableciendo una suscripción bidireccional (subscription = "both"). Esto indica a Jicofo que confíe en el componente y acepte su presencia, permitiendo que el flujo de peticiones funcione correctamente.
Hecha esta introducción, vamos con el manual…
Manual completo: instalar y configurar Jitsi
Por: Charlie Martínez
Este manual documenta una instalación funcional de Jitsi Meet con autenticación en Debian 12, usando Apache con mod_md para SSL. La configuración del roster de Jicofo (paso 5.2) es crítica y no está documentada en los manuales oficiales, pero es necesaria para que el componente client_proxy funcione correctamente con autenticación habilitada.
Información del entorno
- Sistema operativo: Debian 12
- Dominio: jitsi.quirinux.org
- Servidor web: Apache con mod_md (Let’s Encrypt)
- Modo de autenticación: internal_hashed (solo usuarios autenticados pueden crear salas)
Versiones probadas:
- Debian 12
- Jitsi Meet 2.0.10741-1
- Jicofo 1.0-1169-1
- jitsi-videobridge2 (última estable)
- Apache 2.4.x con mod_md
1. Preparación del sistema
1.1 Actualizar el sistema
apt update && apt upgrade -y
1.2 Configurar el hostname
hostnamectl set-hostname jitsi.quirinux.org echo "127.0.0.1 jitsi.quirinux.org" >> /etc/hosts
1.3 Instalar dependencias básicas
apt install -y gnupg2 curl apt-transport-https
2. Instalación de Jitsi Meet
2.1 Añadir el repositorio de Jitsi
curl -sS https://download.jitsi.org/jitsi-key.gpg.key | gpg --dearmor > /usr/share/keyrings/jitsi-keyring.gpg echo "deb [signed-by=/usr/share/keyrings/jitsi-keyring.gpg] https://download.jitsi.org stable/" > /etc/apt/sources.list.d/jitsi-stable.list apt update
2.2 Instalar Jitsi Meet
apt install -y jitsi-meet
Durante la instalación:
- Hostname: Introduce tu dominio (jitsi.quirinux.org)
- SSL Certificate: Elige “Generate a new self-signed certificate” (lo cambiaremos después)
3. Configuración de SSL con Apache y mod_md
3.1 Detener Nginx (instalado por Jitsi)
Aunque es una dependencia de Jitsi, podemos prescindir de nginx, ya que no lo vamos a utilizar.
systemctl stop nginx systemctl disable nginx
3.2 Instalar y configurar Apache
apt install -y apache2 a2enmod ssl headers rewrite proxy proxy_http proxy_wstunnel
3.3 Configurar mod_md para Let’s Encrypt
a2enmod md cat > /etc/apache2/conf-available/md.conf << 'EOF' MDomain jitsi.quirinux.org MDCertificateAgreement accepted MDContactEmail admin@quirinux.org MDRenewWindow 33% MDStapling on EOF a2enconf md
3.4 Crear VirtualHost para Jitsi
cat > /etc/apache2/sites-available/jitsi.quirinux.org.conf << 'EOF'
<VirtualHost *:80>
ServerName jitsi.quirinux.org
# Redirigir todo a HTTPS
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</VirtualHost>
<VirtualHost *:443>
ServerName jitsi.quirinux.org
SSLEngine on
# Cabeceras de seguridad
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
DocumentRoot /usr/share/jitsi-meet
<Directory /usr/share/jitsi-meet>
Options -Indexes +FollowSymLinks
AllowOverride None
Require all granted
</Directory>
# Alias para HTTP Bind (BOSH)
Alias /http-bind /usr/share/jitsi-meet/http-bind
# Proxy WebSocket para XMPP
<Location /xmpp-websocket>
ProxyPass ws://localhost:5280/xmpp-websocket
ProxyPassReverse ws://localhost:5280/xmpp-websocket
</Location>
# Proxy para Colibri (JVB)
<Location /colibri-ws/>
ProxyPass ws://localhost:9090/colibri-ws/
ProxyPassReverse ws://localhost:9090/colibri-ws/
</Location>
# Logs
ErrorLog ${APACHE_LOG_DIR}/jitsi-error.log
CustomLog ${APACHE_LOG_DIR}/jitsi-access.log combined
</VirtualHost>
EOF
a2ensite jitsi.quirinux.org
systemctl restart apache2 3.5 Esperar a que mod_md obtenga el certificado
# Monitorear logs journalctl -u apache2 -f # Esperar hasta ver: "MDomain jitsi.quirinux.org has signed-up protocol version ACME/2.0" # Los certificados se guardarán automáticamente en /etc/apache2/md/domains/jitsi.quirinux.org/
4. Configuración de autenticación
4.1 Modificar configuración de Prosody
nano /etc/prosody/conf.avail/jitsi.quirinux.org.cfg.lua
Cambiar la línea:
VirtualHost "jitsi.quirinux.org"
authentication = "anonymous" -- CAMBIAR ESTA LÍNEA Por:
VirtualHost "jitsi.quirinux.org" authentication = "internal_hashed"
Añadir después del VirtualHost principal:
VirtualHost "guest.jitsi.quirinux.org"
authentication = "anonymous"
c2s_require_encryption = false
modules_enabled = {
"bosh";
"websocket";
"smacks";
} 4.2 Modificar configuración de Jitsi Meet
hosts: {
domain: 'jitsi.quirinux.org',
anonymousdomain: 'guest.jitsi.quirinux.org',
// ... resto de la configuración
} 4.3 Modificar configuración de Jicofo
nano /etc/jitsi/jicofo/jicofo.conf
Añadir dentro del bloque jicofo:
authentication: {
enabled: true
type: XMPP
login-url: "jitsi.quirinux.org"
} 4.4 Crear usuarios autenticados
# Usuario para Jicofo (focus) prosodyctl register focus auth.jitsi.quirinux.org PASSWORD_FOCUS # Usuario para JVB prosodyctl register jvb auth.jitsi.quirinux.org PASSWORD_JVB # Usuario moderador (puede crear salas) prosodyctl register charlie jitsi.quirinux.org PASSWORD_CHARLIE
5. Corrección crítica: Configurar roster de Jicofo
IMPORTANTE: Este paso es crítico y soluciona el error service-unavailable del componente focus.
5.1 Detener servicios
systemctl stop prosody systemctl stop jicofo
5.2 Añadir focus.jitsi.quirinux.org al roster de Jicofo
cat > /var/lib/prosody/auth%2ejitsi%2equirinux%2eorg/roster/focus.dat << 'EOF'
return {
["focus.jitsi.quirinux.org"] = {
["groups"] = {};
["name"] = "focus-proxy";
["subscription"] = "both";
};
[false] = {
["pending"] = {};
["version"] = 12;
};
};
EOF Explicación: El componente client_proxy de Prosody envía una suscripción de presencia a Jicofo, pero Jicofo la rechaza por defecto. Al añadir focus.jitsi.quirinux.org al roster con subscription = "both", Jicofo acepta la presencia y el proxy puede registrar la sesión correctamente.
5.3 Reiniciar servicios
systemctl start prosody sleep 5 systemctl start jicofo sleep 10 systemctl start jitsi-videobridge2
6. Verificación de la instalación
6.1 Verificar servicios
systemctl status prosody systemctl status jicofo systemctl status jitsi-videobridge2 systemctl status apache2
6.2 Verificar conexiones XMPP
prosodyctl shell << 'EOF' c2s:show() EOF
Deberías ver:
jvb@auth.jitsi.quirinux.org– onlinefocus@auth.jitsi.quirinux.org– online
6.3 Verificar logs de Jicofo
tail -50 /var/log/jitsi/jicofo.log | grep -i "connected\|error\|warn"
Deberías ver:
Connected.Registered- Sin errores de
unsubscribedoservice-unavailable
6.4 Probar en el navegador
- Accede a
https://jitsi.quirinux.org - Introduce un nombre de sala
- Debe pedir credenciales de autenticación
- Introduce usuario y contraseña (charlie / PASSWORD_CHARLIE)
- La sala debe crearse correctamente
7. Configuraciones adicionales recomendadas
7.1 Desactivar smacks hibernation para auth domain
nano /etc/prosody/conf.avail/jitsi.quirinux.org.cfg.lua
En el bloque VirtualHost "auth.jitsi.quirinux.org" añadir:
smacks_hibernation_time = 0;
7.2 Configurar logging de Jicofo
mkdir -p /usr/share/jicofo/lib cat > /usr/share/jicofo/lib/logging.properties << 'EOF' handlers=java.util.logging.ConsoleHandler, java.util.logging.FileHandler java.util.logging.FileHandler.pattern=/var/log/jitsi/jicofo.log .level=INFO org.jitsi.level=FINE EOF systemctl restart jicofo
7.3 Añadir ruta de plugins de Jitsi en Prosody
nano /etc/prosody/prosody.cfg.lua
Cambiar:
plugin_paths = { “/usr/local/lib/prosody/modules” }
Por:
plugin_paths = { "/usr/local/lib/prosody/modules", "/usr/share/jitsi-meet/prosody-plugins/" } 8. Resolución de problemas comunes
8.1 Error “service-unavailable” del componente focus
Síntoma: Los clientes no pueden conectarse, log muestra:
Strophe error: {"reason":"service-unavailable","targetJid":"focus.jitsi.quirinux.org"} Causa: El roster de Jicofo no incluye focus.jitsi.quirinux.org
Solución: Aplicar el paso 5.2 de este manual
8.2 Error “conflict – Replaced by new connection”
Síntoma: Jicofo se desconecta constantemente con error de conflicto
Causa: Múltiples instancias de Jicofo o sesiones antiguas en Prosody
Solución:
pkill -9 -f jicofo systemctl restart prosody sleep 5 systemctl start jicofo
8.3 Certificados SSL no funcionan
Síntoma: Error SSL en el navegador
Solución:
# Regenerar certificados de Prosody cd /var/lib/prosody prosodyctl cert generate jitsi.quirinux.org prosodyctl cert generate auth.jitsi.quirinux.org # Cambiar propietario chown -R prosody:prosody /var/lib/prosody/*.crt /var/lib/prosody/*.key systemctl restart prosody
8.4 Jicofo no arranca como servicio
Síntoma: systemctl status jicofo muestra “active (exited)” sin proceso java
Solución:
systemctl stop jicofo systemctl reset-failed jicofo pkill -9 -f jicofo rm -f /var/run/jicofo.pid systemctl daemon-reload systemctl start jicofo
9. Mantenimiento
9.1 Actualizar Jitsi
apt update apt upgrade jitsi-meet jicofo jitsi-videobridge2 systemctl restart prosody jicofo jitsi-videobridge2
9.2 Añadir nuevos usuarios moderadores
prosodyctl register USUARIO jitsi.quirinux.org PASSWORD
9.3 Cambiar contraseña de usuario
prosodyctl passwd USUARIO@jitsi.quirinux.org
9.4 Eliminar usuario
prosodyctl deluser USUARIO@jitsi.quirinux.org
9.5 Ver logs en tiempo real
# Jicofo tail -f /var/log/jitsi/jicofo.log # JVB tail -f /var/log/jitsi/jvb.log # Prosody journalctl -u prosody -f
10. Información de contacto y referencias
- Documentación oficial de Jitsi: https://jitsi.github.io/handbook/
- Foro de la comunidad: https://community.jitsi.org/
- Repositorio GitHub: https://github.com/jitsi