|

instalar servidor de Jitsi con autenticación sobre Apache en Debian (sin nginx ni Docker)

Cómo instalar y configurar el servidor libre de videoconferencia Jitsi con un usuario autenticado que sea el único habilitado para crear reuniones. Manual completo que recopila toda la configuración necesaria paso por paso, sin nginx ni docker.

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ón internal_hashed para moderadores
    • guest.jitsi.quirinux.org: con autenticación anonymous para 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_proxy de Prosody, impidiendo que las peticiones de conferencia llegaran correctamente. La solución fue añadir manualmente focus.jitsi.quirinux.org al 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 usuario focus@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.

Instalación y configuración:

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.

  • Sistema operativo: Debian 12
  • Dominio: jitsi.quirinux.org <- Modificar por tu dominio
  • 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

apt update && apt upgrade -y
hostnamectl set-hostname jitsi.quirinux.org
echo "127.0.0.1 jitsi.quirinux.org" >> /etc/hosts

apt install -y gnupg2 curl apt-transport-https
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
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)

Aunque es una dependencia de Jitsi, podemos prescindir de nginx, ya que no lo vamos a utilizar.

systemctl stop nginx
systemctl disable nginx

Nota para Debian 12: Los plugins de Jitsi Meet pueden presentar incompatibilidades con la versión de Prosody incluida en Debian 12 (Lua 5.4). Si al iniciar Prosody aparecen errores del tipo no field package.preload en módulos como speakerstats_component, consultá el apartado 8.5 de este manual para resolverlos. Los módulos afectados suelen ser opcionales y no impiden el funcionamiento de las videoconferencias.

apt install -y apache2
a2enmod ssl headers rewrite proxy proxy_http proxy_wstunnel
sudo a2enmod md

Creamos un archivo /etc/apache2/sites-available/jitsi-quirinux.org.conf con el siguiente contenido:

MDomain jitsi.quirinux.org
MDCertificateAgreement accepted
MDContactEmail admin@quirinux.org
MDRenewWindow 33%
MDStapling on

<VirtualHost *:80>
ServerName jitsi.quirinux.org
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</VirtualHost>

<VirtualHost *:443>
ServerName jitsi.quirinux.org
SSLEngine on

<IfModule pagespeed_module>
ModPagespeed off
ModPagespeedDisallow "*"
</IfModule>

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>

SSLProxyEngine on
SSLProxyVerify none
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off
SSLProxyCheckPeerExpire off

ProxyPreserveHost On

<Location /xmpp-websocket>
ProxyPass wss://localhost:5281/xmpp-websocket
ProxyPassReverse wss://localhost:5281/xmpp-websocket
</Location>

<Location /colibri-ws>
ProxyPass ws://localhost:9090/colibri-ws
ProxyPassReverse ws://localhost:9090/colibri-ws
</Location>

RewriteEngine On
RewriteCond %{REQUEST_URI} !^/xmpp-websocket
RewriteCond %{REQUEST_URI} !^/colibri-ws
RewriteCond %{REQUEST_URI} !^/config\.js
RewriteCond %{REQUEST_URI} !^/interface_config\.js
RewriteCond %{REQUEST_URI} !^/libs/
RewriteCond %{REQUEST_URI} !^/css/
RewriteCond %{REQUEST_URI} !^/images/
RewriteCond %{REQUEST_URI} !^/fonts/
RewriteCond %{REQUEST_URI} !^/lang/
RewriteCond %{REQUEST_URI} !^/sounds/
RewriteCond %{REQUEST_URI} !^/static/
RewriteCond %{REQUEST_URI} !^/http-bind
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ /index.html [L]

ErrorLog ${APACHE_LOG_DIR}/jitsi-error.log
CustomLog ${APACHE_LOG_DIR}/jitsi-access.log combined
</VirtualHost>

Habilitamos módulos necesarios, habilitamos el sitio y reiniciamos Apache:

sudo a2enmod ssl headers rewrite proxy proxy_http proxy_wstunnel
sudo a2ensite jitsi.quirinux.org
systemctl restart apache2

3.4.1 Corrección de bug del paquet jitsi-meet de Debian:

El paquete jitsi-meet para Debian omite la declaración en el archivo index.html, lo que hace que Apache lo sirva en modo Quirks y la interfaz aparezca como pantalla negra. Este comando lo corrige manualmente. Si en el futuro actualizás el paquete, es posible que haya que reaplicar este paso:

sed -i '1s/^/\n/' /usr/share/jitsi-meet/index.html

Verificar que quedó correctamente

head -3 /usr/share/jitsi-meet/index.html
# 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/
nano /etc/prosody/conf.avail/jitsi.quirinux.org.cfg.lua

Cambiar:

VirtualHost "jitsi.quirinux.org"
authentication = "jitsi-anonymous"

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";
    }

Editamos el fichero /etc/jitsi/meet/jitsi.quirinux.org-config.js y buscamos la línea hosts: { para que quede de esta manera:

hosts: {
    domain: 'jitsi.quirinux.org',
    anonymousdomain: 'guest.jitsi.quirinux.org',
    // ... resto de la configuración
}
nano /etc/jitsi/jicofo/jicofo.conf

Añadir dentro del bloque jicofo:

authentication: {
    enabled: true
    type: XMPP
    login-url: "jitsi.quirinux.org"
}

Verifica las contraseñas de jicofo y videobridge:

grep -i "password" /etc/jitsi/jicofo/jicofo.conf
grep -i "password" /etc/jitsi/videobridge/jvb.conf

Luego crea los usuarios con dichas contraseñas, y crea un usuario para tí (con el que te autenticaras como moderador para poder crear salas).

# Usuario para Jicofo (focus) — usar la contraseña de jicofo.conf
prosodyctl register focus auth.jitsi.quirinux.org password-jicofo

# Usuario para JVB — usar la contraseña de jvb.conf
prosodyctl register jvb auth.jitsi.quirinux.org password-jvb

# Usuario moderador (puede crear salas)
prosodyctl register charlie jitsi.quirinux.org password

IMPORTANTE: Este paso es crítico y soluciona el error service-unavailable del componente focus.

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.

systemctl start prosody
systemctl start jicofo
systemctl start jitsi-videobridge2

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 – online
  • focus@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 unsubscribed o service-unavailable

6.4 Probar en el navegador

  1. Accede a https://jitsi.quirinux.org
  2. Introduce un nombre de sala
  3. Debe pedir credenciales de autenticación
  4. Introduce usuario y contraseña (charlie / PASSWORD_CHARLIE)
  5. La sala debe crearse correctamente

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

8.5 Error «no field package.preload» en módulos de Prosody

Síntoma: Al iniciar Prosody, el log muestra errores como:

Causa: Incompatibilidad entre los plugins de Jitsi Meet y la versión de Prosody incluida en Debian 12, que usa Lua 5.4 con una estructura de rutas diferente a la esperada por algunos módulos opcionales de Jitsi.

Solución: Deshabilitar el módulo afectado en la configuración de Prosody. El módulo speakerstats es opcional (solo registra estadísticas de quién habla) y no afecta al funcionamiento de las videoconferencias.

Editar el archivo /etc/prosody/conf.avail/jitsi.quirinux.org.cfg.lua y comentar la siguiente línea:

Component "speakerstats.jitsi.quirinux.org" "speakerstats_component"

Tiene que quedar así:

--Component "speakerstats.jitsi.quirinux.org" "speakerstats_component"

Luego reiniciar Prosody

systemctl restart prosody

Nota: Si el mismo error aparece con otros módulos (por ejemplo av_moderation, breakout_rooms, etc.), aplicá el mismo criterio: comentá el componente si no es esencial para tu caso de uso. Los módulos críticos son conference, auth y focus; el resto son funcionalidades adicionales.

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

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *