Resumen rápido: Para desplegar Jitsi Meet en un VPS con Docker Compose y sostener videoconferencias estables de hasta 35 participantes concurrentes en 720p (modo SFU), la infraestructura mínima de producción requiere virtualización KVM con 4 vCPU dedicados (%st = 0.0%), 8 GB de RAM para dimensionar el heap de la JVM en Jitsi Videobridge (JVB) sin riesgo de OOM Killer, y 30 GB de almacenamiento en NVMe PCIe 4.0. El transporte multimedia en tiempo real exige un enlace simétrico de 1 Gbps optimizado con el algoritmo TCP BBR, una dirección IPv4 pública dedicada sin NAT estricto y la apertura directa del puerto 10000/UDP para tráfico RTP/WebRTC junto a 443/TCP para señalización XMPP y WebSockets bajo TLS.
Tabla de contenidos
- Requisitos de Hardware y Ancho de Banda para Jitsi Meet en KVM VPS
- Configuración de Red y Firewall: Apertura de Puertos UDP y TCP
- Despliegue de Jitsi Meet con Docker Compose y Variables de Entorno
- Optimización del Jitsi Videobridge (JVB) y Algoritmo TCP BBR
- Seguridad: Autenticación JWT y Protección contra Accesos No Autorizados
- Monitoreo de Calidad de Llamada y Plan de Recuperación ante Desastres
- Preguntas frecuentes (FAQ)
Requisitos de Hardware y Ancho de Banda para Jitsi Meet en KVM VPS
Al desplegar jitsi meet en vps docker, la arquitectura de recursos difiere radicalmente de la de una pila web convencional (como LAMP o LEMP). Jitsi no opera como un servidor monolítico; su componente central para la distribución de medios, Jitsi Videobridge (JVB), actúa como un Selective Forwarding Unit (SFU). A diferencia de una Multipoint Control Unit (MCU), el SFU no transcodifica los flujos de vídeo en el servidor —lo que consumiría cantidades masivas de GPU o ciclos de rasterización de CPU—, sino que enruta, conmuta y filtra paquetes RTP/RTCP entre los participantes según la visibilidad del cliente y las capas de resolución activas.
Esta arquitectura traslada la mayor presión del sistema hacia el subsistema de red (tasa de paquetes por segundo o PPS), la gestión de interrupciones de software del kernel (softirqs), el cifrado DTLS-SRTP y la latencia de recolección de basura en la máquina virtual Java (JVM).
1. Dinámica de Carga: CPU, RAM y el Impacto Crítico de %st
Para calcular la capacidad real de una instancia KVM frente a una carga WebRTC, es obligatorio desglosar cómo consume recursos cada contenedor del ecosistema:
- Jitsi Videobridge (JVB): Proceso Java multihilo. Gestiona la terminación de canales ICE/DTLS, la re-encapsulación de paquetes SRTP, el control de congestión basado en transporte (Transport-CC) y la selección de capas espaciales (Simulcast). Consume entre un 10% y un 25% de un vCPU moderno por cada 15 transmisiones activas conmutadas, exigiendo un heap de memoria estable para evitar paradas Stop-the-World.
- Prosody (XMPP): Demonio en Lua encargado de la señalización, gestión de salas MUC (Multi-User Chat) y presencia de red. Es predominantemente monohilo y altamente sensible a la latencia de entrada/salida de socket. Si el hilo de Prosody se bloquea, la negociación SDP de nuevas conexiones sufre timeouts.
- Jicofo (Jitsi Conference Focus): Servicio Java que orquesta las sesiones y asigna puentes JVB a las salas. Su huella en CPU es marginal (< 5% vCPU en reposo/concurrencia media), pero requiere retención en RAM para mantener el estado de cada conferencia.
- Jibri (Jitsi Broadcasting Infrastructure): Componente opcional para grabación local o emisión RTMP (YouTube/Twitch). Rompe el modelo SFU: lanza una instancia de Chromium headless y codifica vídeo en tiempo real mediante FFmpeg (libx264). Demanda de 2 a 3 vCPU dedicados y ~2 GB de RAM por cada grabación concurrente a 1080p.
+--------------------------------------------------------------+
| KVM HYPERVISOR |
| (Garantía de CPU Steal %st = 0.0% | AMD EPYC / Ryzen 9) |
+------------------------------+-------------------------------+
|
+----------------------------v-----------------------------+
| DOCKER HOST SUBSYSTEM |
| Kernel Linux 6.8+ | epoll | eBPF | sysctl UDP Buffers |
+----------------------------+-----------------------------+
|
+----------------------------+-----------------------------+
| |
+--------v---------+ +-------------------+ +----------------v----------------+
| nginx (Reverse) | | Prosody (Lua) | | Jitsi Videobridge (JVB) |
| TLS Term / WS | <-> | XMPP Signaling | <-> | DTLS-SRTP / SCTP DataChannels |
| HTTP/2 Static | | MUC Rooms State | | Simulcast / BWE / Packet Route |
+------------------+ +-------------------+ +---------------------------------+
|
[UDP 10000 -> WebRTC]
15k - 60k Packets/Sec
El factor crítico: CPU Steal Time (%st = 0.0%)
En arquitecturas WebRTC con tráfico UDP en tiempo real, un jitter superior a 30–50 ms degrada inmediatamente el buffer de fluctuación del navegador del cliente, provocando congelamiento de frames y cortes de audio (audio dropouts). En entornos con hipervisores sobreasignados (oversold), el CPU Steal Time (%st en top o vmstat) se dispara cuando el planificador del host pausa el hilo virtual de la máquina invitada para atender a otros inquilinos.
Para entornos de producción que ejecutan Jitsi Meet en Docker, es un requisito no negociable desplegar sobre infraestructura KVM con asignación física dedicada donde %st sea estrictamente 0.0%, tal como implementa tropic.host en sus nodos basados en AMD EPYC y Ryzen 9. Si el hilo de decodificación DTLS se detiene 40 ms debido a contención de CPU en el nodo raíz, el cliente asume pérdida de paquetes masiva y fuerza a la baja el bitrate mediante el algoritmo GCC (Google Congestion Control), destruyendo la calidad visual de la sala.
2. Modelado Matemático de Ancho de Banda y Tráfico de Red
El ancho de banda de una sala Jitsi con $N$ participantes conectados no escala de forma lineal ni cuadrática pura, sino de forma asimétrica debido a la tecnología Simulcast (VP8/VP9/AV1), que emite tres resoluciones concurrentes por cada cliente con cámara activa: 1. High (HD): 1280x720 @ 30 fps $\approx 1.5 - 2.5 \text{ Mbps}$ 2. Medium (SD): 640x360 @ 30 fps $\approx 500 - 700 \text{ kbps}$ 3. Low (LD): 320x180 @ 15 fps $\approx 150 - 200 \text{ kbps}$ 4. Audio (Opus): 48 kHz mono/estéreo con DTX $\approx 40 \text{ kbps}$
Ecuación de Ingress (Subida hacia el servidor)
Cada usuario con cámara activa envía su stream completo con las 3 capas espaciales simultáneas más el canal de audio hacia el JVB: $$\text{BW}{\text{in}} = \sum{i=1}^{P_{\text{video}}} \left( \text{Bitrate}{\text{High}} + \text{Bitrate}{\text{Med}} + \text{Bitrate}{\text{Low}} + \text{Bitrate}{\text{Audio}} \right)_i$$
Para un participante estándar, el ancho de banda entrante al VPS promedia: $$2.0 \text{ Mbps} + 0.6 \text{ Mbps} + 0.18 \text{ Mbps} + 0.04 \text{ Mbps} \approx \mathbf{2.82 \text{ Mbps por emisor}}$$
Ecuación de Egress (Bajada desde el servidor a los clientes)
El JVB sólo entrega la capa High del hablante activo (dominant speaker) y la capa Low (miniaturas de la cuadrícula o tile view) para el resto de los participantes visibles (hasta un límite habitual de $K = 15$ ventanas en pantalla): $$\text{BW}{\text{out, cliente}} = \text{Bitrate}{\text{High}} + (K - 1) \times \text{Bitrate}{\text{Low}} + (N - 1) \times \text{Bitrate}{\text{Audio}}$$
Para una sala de $N = 20$ participantes donde todos tienen cámara encendida ($K = 15$ visibles en pantalla): $$\text{BW}{\text{out, cliente}} = 2.0 \text{ Mbps} + (14 \times 0.18 \text{ Mbps}) + (19 \times 0.04 \text{ Mbps}) = 2.0 + 2.52 + 0.76 = \mathbf{5.28 \text{ Mbps}}$$ Multiplicado por los 20 participantes recibiendo datos: $$\text{BW}{\text{out, total}} = 20 \times 5.28 \text{ Mbps} \approx \mathbf{105.6 \text{ Mbps}}$$
La asimetría es evidente: el servidor recibe $\approx 56.4 \text{ Mbps}$ de subida y expulsa $\approx 105.6 \text{ Mbps}$ de salida sostenida, generando ráfagas de paquetes UDP de 1.200 bytes que alcanzan fácilmente entre 15.000 y 25.000 paquetes por segundo (PPS).
3. Matriz de Dimensionamiento y Benchmarks en KVM VPS
La siguiente tabla define las configuraciones de hardware requeridas en función del caso de uso, la concurrencia y el perfil de tráfico sobre instancias KVM con almacenamiento NVMe de alto rendimiento.
| Perfil de Carga | Concurrencia Simultánea | vCPU Recomendados (Ded. KVM, %st = 0) | Memoria RAM (Host / JVM Heap) | Ancho de Banda Red (Uplink / PPS Estimados) | Configuración de Almacenamiento (NVMe PCIe 4.0) | Perfil de Referencia tropic.host |
|---|---|---|---|---|---|---|
| Micro / 1-to-1 & Standby | Hasta 4 usuarios activos (1 sala) | 2 vCPU (AMD/Intel $\ge 3.0\text{ GHz}$) | 4 GB RAM (-Xmx1536m) |
1 Gbps port / $\approx 3.000\text{ PPS}$ | 40 GB NVMe (Random 4K > 30k IOPS) | Starter KVM |
| Equipo Estándar / Team Sync | 15–20 usuarios en cuadrícula (1 sala) | 4 vCPU (AMD EPYC/Xeon) | 8 GB RAM (-Xmx3072m) |
1 Gbps no medido / $\approx 25.000\text{ PPS}$ | 80 GB NVMe (Random 4K > 50k IOPS) | Business KVM |
| Auditorio / Webinar | 2–3 speakers, 80–120 oyentes pasivos | 6–8 vCPU dedicados | 16 GB RAM (-Xmx8192m) |
2.5 Gbps – 10 Gbps / $\approx 60.000\text{ PPS}$ | 160 GB NVMe (Baja latencia $p99 < 1\text{ ms}$) | Pro KVM |
| Producción con Grabación (Jibri) | 20 activos + 2 grabaciones locales 1080p | 10–12 vCPU dedicados | 24–32 GB RAM (-Xmx8192m + 8 GB Chromium/FFmpeg) |
2.5 Gbps / $\approx 45.000\text{ PPS}$ + Escritura I/O sostenida | 300+ GB NVMe enterprise (Cero thermal throttling) | Enterprise EPYC KVM |
4. Afinamiento del Kernel Linux para Tráfico UDP de Alta Densidad
El stack de red estándar de Linux está ajustado por defecto para servidores web con conexiones TCP transaccionales, lo que provoca descartes inmediatos de paquetes (packet drops) por saturación de buffers en WebRTC bajo cargas concurrentes.
Antes de desplegar los contenedores Docker, es obligatorio aplicar los siguientes parámetros en /etc/sysctl.d/99-jitsi-performance.conf:
# Aumento del búfer de recepción y transmisión de sockets UDP (evita buffer overflows en JVB)
net.core.rmem_max = 67108864
net.core.wmem_max = 67108864
net.core.rmem_default = 33554432
net.core.wmem_default = 33554432
# Tamaño de la cola de entrada del subsistema de red para procesar ráfagas de interrupciones
net.core.netdev_max_backlog = 100000
# Parámetros TCP para Prosody y terminación Nginx (BBRv1/v2 para baja latencia)
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
net.ipv4.tcp_notsent_lowat = 16384
net.ipv4.tcp_slow_start_after_idle = 0
# Aumento del rango de puertos efímeros y tablas de seguimiento de conexiones
net.ipv4.ip_local_port_range = 1024 65535
net.netfilter.nf_conntrack_max = 1048576
Para aplicar los cambios en tiempo de ejecución:
sudo sysctl -p /etc/sysctl.d/99-jitsi-performance.conf
A nivel de tarjeta de red, verifique y amplíe los descriptores del anillo de recepción (rx ring buffers) de la interfaz virtual virtio:
# Consultar tamaño actual y soporte máximo
sudo ethtool -g eth0
# Ajustar al límite de hardware (habitualmente 1024 o 4096)
sudo ethtool -G eth0 rx 4096 tx 4096
5. Configuración de Recursos y JVM en Docker Compose
En una arquitectura contenerizada, un error común consiste en omitir los límites de cgroups y permitir que el colector de basura de Java compita desordenadamente con Nginx y Prosody. El archivo docker-compose.yml debe contener límites estrictos y variables de optimización de JVM.
A continuación se detalla la configuración del servicio jvb optimizada para una instancia de 8 vCPU y 16 GB de RAM en un entorno KVM de tropic.host:
version: '3.8'
services:
jvb:
image: jitsi/jvb:stable-9457
restart: always
network_mode: host
environment:
- DOCKER_HOST_ADDRESS=203.0.113.10
- XMPP_SERVER=prosody
- XMPP_PORT=5222
- XMPP_DOMAIN=meet.jitsi
- XMPP_AUTH_DOMAIN=auth.meet.jitsi
- XMPP_INTERNAL_MUC_DOMAIN=internal-muc.meet.jitsi
- JVB_AUTH_USER=jvb
- JVB_AUTH_PASSWORD=SecretJvbAuthToken987
- JVB_PORT=10000
- JVB_STUN_SERVERS=meet-jit-si-turnrelay.jitsi.net:443
- JVB_ENABLE_APIS=rest,colibri
# Parámetros avanzados de Java Virtual Machine (G1GC afinado para latencia sub-20ms)
- JAVA_SYS_PROPS=-Dnet.java.sip.communicator.SC_HOME_DIR_LOCATION=/etc/jitsi -Dnet.java.sip.communicator.SC_HOME_DIR_NAME=videobridge -Xms4096m -Xmx6144m -XX:+UseG1GC -XX:MaxGCPauseMillis=20 -XX:InitiatingHeapOccupancyPercent=45 -XX:G1ReservePercent=15
volumes:
- /opt/jitsi/jvb/config:/config:Z
deploy:
resources:
limits:
cpus: '6.0'
memory: 8192M
reservations:
cpus: '4.0'
memory: 4096M
ulimits:
nofile:
soft: 65535
hard: 65535
Aislamiento de Red: El parámetronetwork_mode: hosten el contenedorjvbes indispensable en producción. Elimina la capa de encapsulamiento del puente Docker (docker0 bridge) y evita que cada paquete UDP atraviese el subsistema de traducción de direcciones de red (Docker NAT), ahorrando entre un 15% y un 25% de ciclos de CPU en el hipervisor a tasas superiores a 20.000 PPS.
6. Métricas de Auditoría y Verificación en Producción
Una vez inicializada la infraestructura, compruebe que no existen cuellos de botella en la asignación de hardware ejecutando las siguientes herramientas de telemetría directamente en el host:
- Auditoría de CPU Steal:
bash # Comprobar la columna %st cada 2 segundos. Debe permanecer estrictamente en 0.00 mpstat -P ALL 2 10 - Monitorización de descartes de paquetes UDP:
bash # Verificar si el contador 'packet receive errors' o 'buffer errors' se incrementa netstat -su | grep -E "errors|buffer" - Validación del rendimiento de almacenamiento NVMe (para instancias con Jibri):
bash # Validación de latencias de escritura aleatoria 4K con profundidad de cola 1 fio --name=direct-io-test --filename=/tmp/test.fio --rw=randwrite --bs=4k --ioengine=libaio --direct=1 --iodepth=1 --size=1G --runtime=15 --time_based
Una infraestructura de almacenamiento corporativa basada en NVMe PCIe 4.0 como la provista por tropic.host garantiza que los procesos concurrentes de escritura de métricas de logging, bases de datos XMPP en Prosody y flujos de grabación transcodificados por Jibri no generen bloqueos por I/O Wait (%iowait = 0.0%), asegurando la máxima estabilidad del stack WebRTC.
Configuración de Red y Firewall: Apertura de Puertos UDP y TCP
Al desplegar Jitsi Meet en un VPS con Docker, la capa de transporte de red se bifurca en dos planos arquitectónicos con requisitos de latencia, serialización y estado radicalmente opuestos: el plano de señalización/control (basado en TCP y WebSockets sobre TLS) y el plano de medios en tiempo real (RTP/SRTP transportado exclusivamente sobre UDP mediante el Jitsi Videobridge, o JVB).
Una configuración incorrecta de las tablas de netfilter o un dimensionamiento insuficiente de los buffers de socket del kernel degradará instantáneamente las llamadas con cortes de audio, pantallas negras y ráfagas de retransmisión por pérdidas de paquetes (packet drops).
1. Topología de Puertos del Stack Jitsi
El contenedor web expone los endpoints HTTP/HTTPS hacia el exterior, mientras que el contenedor JVB maneja directamente la conmutación de flujos de audio y vídeo como un Selective Forwarding Unit (SFU).
| Puerto / Protocolo | Servicio Interno | Destino en Docker | Función Técnica | Exposición |
|---|---|---|---|---|
80/TCP |
Nginx | web:80 |
Validación de certificados vía ACME HTTP-01 y redirección 301 Moved Permanently a HTTPS. |
Externa (0.0.0.0/0) |
443/TCP |
Nginx | web:443 |
Terminación TLS, descarga de activos estáticos web, señalización XMPP BOSH / WebSockets (/xmpp-websocket). |
Externa (0.0.0.0/0) |
10000/UDP |
Jitsi Videobridge | jvb:10000 |
Transporte RTP/SRTP de flujos de audio y vídeo bidireccionales entre clientes y el SFU. | Externa (0.0.0.0/0) |
22/TCP |
OpenSSH | Host OS (no contenedor) | Administración remota segura de la instancia. | Restringida / Externa |
4443/TCP (Opcional) |
Jitsi Videobridge | jvb:4443 |
Fallback de transporte de medios vía TCP para clientes corporativos con bloqueo de tráfico UDP saliente. | Externa (0.0.0.0/0) |
Nota de seguridad: Puertos internos como5222/TCP(comunicación C2S de Prosody),5347/TCP(componentes XMPP) y8080/TCP(APIs REST internas de Jicofo y JVB) operan exclusivamente dentro de la red puente de Docker (bridge network) y bajo ningún concepto deben publicarse hacia la interfaz de red pública del host.
2. La Trampa Arquitectónica: Docker Daemon e iptables Bypass frente a UFW
El error más crítico en la administración de un VPS para Jitsi Meet consiste en asumir que ufw filtra de forma predeterminada los puertos expuestos por Docker Compose mediante la directiva ports:.
Mecánica del bypass del kernel
- Cuando se ejecuta Docker con la configuración por defecto de Linux, el demonio manipula directamente las tablas
natyfilterdel subsistemanetfilterdel kernel. - Los paquetes entrantes destinados a un contenedor cruzan la cadena
PREROUTING, donde Docker aplica un DNAT hacia la IP interna del contenedor (172.x.x.x). - Posteriormente, el paquete viaja por la cadena
FORWARDdeiptables. - La interfaz de gestión
ufw, por el contrario, inyecta sus reglas de control de acceso en la cadenaINPUT. - Debido a que el paquete ya fue enrutado hacia la cadena
FORWARD, salta por completo todas las reglas de UFW. Si un contenedor expone un puerto en0.0.0.0:8080, dicho puerto queda accesible a todo Internet aunqueufw statusreporte una política globalStatus: activeyDefault: deny (incoming).
Para corregir esta vulnerabilidad sin desactivar la manipulación de iptables en Docker —lo cual rompería la resolución DNS embebida y el enrutamiento inter-contenedor—, se debe utilizar la cadena reservada DOCKER-USER. netfilter evalúa las reglas de DOCKER-USER al inicio de la cadena FORWARD, antes de que se procesen las reglas automáticas de Docker.
3. Implementación del Firewall con UFW y Blindaje de la Cadena DOCKER-USER
Para garantizar un filtrado determinista, configure primero las políticas base del sistema operativo y luego inyecte el control de acceso en el motor de Docker.
Paso 1: Configurar políticas base en UFW
Ejecute la secuencia de inicialización del firewall para el tráfico directo al host:
# Restablecer configuración previa para evitar reglas huérfanas
ufw --force reset
# Política por defecto: denegar todo el tráfico entrante, permitir tráfico saliente y de reenvío
ufw default deny incoming
ufw default allow outgoing
ufw default allow routed
# Permitir acceso SSH administrativo (utilizar puerto personalizado si aplica)
ufw allow 22/tcp comment 'SSH Administrative Access'
# Permitir puertos públicos del stack Jitsi
ufw allow 80/tcp comment 'Jitsi HTTP / Let-s Encrypt'
ufw allow 443/tcp comment 'Jitsi HTTPS / WebSockets'
ufw allow 10000/udp comment 'JVB RTP Media Stream'
# Opcional: Fallback TCP para medios en redes restringidas
ufw allow 4443/tcp comment 'JVB TCP Media Fallback'
Paso 2: Interceptar el tráfico de Docker en /etc/ufw/after.rules
Edite el archivo de reglas posteriores de UFW para forzar a la cadena DOCKER-USER a respetar el estado de las conexiones y bloquear el acceso externo no autorizado a los contenedores:
nano /etc/ufw/after.rules
Añada el siguiente bloque al final del archivo, respetando la sintaxis nativa de iptables-restore:
# =========================================================================
# CONTROL DETERMINISTA DE DOCKER-USER VIA UFW
# =========================================================================
*filter
:DOCKER-USER - [0:0]
-A DOCKER-USER -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A DOCKER-USER -i lo -j ACCEPT
-A DOCKER-USER -m conntrack --ctstate INVALID -j DROP
# Permitir tráfico explícito hacia los servicios públicos en contenedores
-A DOCKER-USER -p tcp -m multiport --dports 80,443 -j ACCEPT
-A DOCKER-USER -p udp --dport 10000 -j ACCEPT
-A DOCKER-USER -p tcp --dport 4443 -j ACCEPT
# Bloquear cualquier otro acceso directo desde interfaces públicas hacia redes Docker
-A DOCKER-USER -i eth0 -j DROP
-A DOCKER-USER -j RETURN
COMMIT
Verificación de interfaz: Sustituyaeth0por el identificador exacto de su interfaz de red pública física (verifíquelo conip -br link show). En instancias KVM optimizadas como las de tropic.host, la interfaz suele identificarse comoeth0oens3mediante drivers paravirtualizadosvirtio_net.
Active y recargue el subsistema de filtrado:
ufw enable
systemctl restart ufw
4. Ajustes del Kernel para Tráfico Masivo UDP y Prevención de Descarte de Paquetes
En videoconferencias de alta densidad con múltiples participantes por sala, el JVB procesa ráfagas masivas de datagramas UDP. Los valores de red por defecto en distribuciones como Ubuntu Server 24.04 LTS o Debian 12 asignan apenas 208 KB al búfer de recepción de socket (rmem_default), lo que genera saturación inmediata de colas del kernel y pérdida masiva de paquetes ante picos de tráfico (UDP buffer errors).
Cree un archivo de configuración sysctl dedicado para el subsistema de red:
cat << 'EOF' > /etc/sysctl.d/99-jitsi-network.conf
# =========================================================================
# TUNING DE BUFFER DE RED PARA JITSI MEET / SELECTIVE FORWARDING UNIT (JVB)
# =========================================================================
# Aumento de la longitud de la cola de backlog de la interfaz de red (número de paquetes)
# Evita descartes a nivel de driver en interfaces 1-10 Gbps con tráfico sostenido
net.core.netdev_max_backlog = 100000
# Búfers máximos y por defecto para sockets del sistema (32MB max, 8MB default)
net.core.rmem_max = 33554432
net.core.wmem_max = 33554432
net.core.rmem_default = 8388608
net.core.wmem_default = 8388608
# Búfers específicos para sockets UDP: min (16KB), default (8MB), max (32MB)
net.ipv4.udp_rmem_min = 16384
net.ipv4.udp_wmem_min = 16384
# Capacidad de la tabla de seguimiento de conexiones (evita NF_CONNTRACK FULL)
net.netfilter.nf_conntrack_max = 1048576
net.netfilter.nf_conntrack_tcp_timeout_established = 600
# Activación del algoritmo de control de congestión TCP BBR y colas FQ
# Optimiza la entrega de señalización WebSockets y streaming TCP fallback
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
# Mitigación de fragmentación IP y MTU Discovery
net.ipv4.ip_no_pmtu_disc = 0
EOF
Aplique los parámetros en caliente sin reiniciar el servidor:
sysctl --system
5. Interacción con la Infraestructura del Proveedor y Direccionamiento IP
Un despliegue de Jitsi Meet en contenedores requiere que el JVB conozca con absoluta precisión su dirección IP pública para anunciarla en los candidatos ICE (Interactive Connectivity Establishment) a través de SDP (Session Description Protocol).
[ Cliente WebRTC ]
│ (Candidatos ICE: IP_PUBLICA_VPS:10000/UDP)
▼
[ L3/L4 Anti-DDoS Scrubbing (tropic.host) ]
│ (Tráfico limpio sin filtrado de puertos ni DPI)
▼
[ Interfaz eth0 (KVM virtio_net: 1-10 Gbps) ]
│
├──> iptables (Cadena DOCKER-USER: 10000/UDP ACCEPT)
▼
[ Docker Bridge / jvb (Env: DOCKER_HOST_ADDRESS=IP_PUBLICA_VPS) ]
Cuando se opera sobre plataformas KVM sin sobreasignación como tropic.host, cada instancia dispone de una dirección IPv4 pública estática dedicada y limpia, enrutada directamente a la tarjeta de red sin capas de NAT carrier-grade intermedias (CGNAT) ni bloqueos de rangos de puertos UDP. Esto elimina la necesidad de configurar servidores STUN/TURN externos para la mayoría de los clientes, reduciendo el RTT (Round-Trip Time) a la latencia pura de la red física. Además, la conectividad directa a puntos de intercambio de tráfico clave (como DE-CIX Frankfurt o AMS-IX Ámsterdam) y el soporte nativo de BBR mitigan el jitter entre el SFU y los usuarios finales.
6. Auditoría y Validación de la Pila de Red en Producción
Una vez aplicadas las reglas y levantados los contenedores Docker mediante docker compose up -d, verifique que los sockets se encuentren enlazados en las interfaces correctas y que las reglas de iptables registren tráfico.
1. Inspección de puertos en escucha en el host
Valide que el JVB esté enlazado al puerto 10000/UDP y Nginx a los puertos 80/TCP y 443/TCP:
ss -tulpn | grep -E ":(80|443|10000)\b"
La salida esperada debe confirmar el enlace en 0.0.0.0 o :::*:
udp UNCONN 0 0 0.0.0.0:10000 0.0.0.0:* users:(("docker-proxy",pid=12345,fd=4))
tcp LISTEN 0 4096 0.0.0.0:80 0.0.0.0:* users:(("docker-proxy",pid=12340,fd=4))
tcp LISTEN 0 4096 0.0.0.0:443 0.0.0.0:* users:(("docker-proxy",pid=12342,fd=4))
2. Comprobación de contadores de paquetes en DOCKER-USER
Supervise que los paquetes entrantes no estén siendo descartados por error en la cadena de firewall:
iptables -L DOCKER-USER -n -v --line-numbers
Observe las columnas pkts y bytes. Las líneas que autorizan los puertos 80, 443 y 10000 deben incrementar sus contadores a medida que los clientes inicializan sesiones de videoconferencia.
3. Test de conectividad UDP externa directa
Para verificar que el proveedor de red no bloquea el tráfico entrante al puerto de medios, ejecute una prueba controlada desde una máquina externa:
# En el servidor Jitsi (detener temporalmente el stack Docker para escuchar directamente):
nc -u -l -p 10000
# En un equipo de prueba externo:
echo "PING_TEST_WEBRTC" | nc -u -v IP_PUBLICA_VPS 10000
Si el mensaje "PING_TEST_WEBRTC" aparece en el terminal del servidor, la cadena completa —enrutamiento del proveedor, hardware de mitigación DDoS, reglas del hipervisor KVM y tablas locales de netfilter— queda formalmente validada para soportar streaming de medios sin interrupciones.
Despliegue de Jitsi Meet con Docker Compose y Variables de Entorno
Una vez validada la apertura y el enrutamiento de sockets en el kernel, la orquestación del stack de videoconferencia se articula desacoplando la señalización XMPP, la lógica de control de conferencias, el servidor web perimetral y el enrutamiento de flujos WebRTC. La arquitectura oficial empaquetada para contenedores divide el ecosistema en cuatro microservicios independientes:
web: Servidor Nginx que aloja la interfaz gráfica en React, gestiona la terminación TLS (Let's Encrypt o certificados personalizados) y enruta el tráfico BOSH/WebSockets hacia Prosody.prosody: Servidor de mensajería y presencia XMPP optimizado en Lua. Coordina salas de chat de usuarios múltiples (MUC), autenticación de componentes internos y señalización SDP.jicofo(Jitsi Conference Focus): Demonio Java que actúa como intermediario entre las salas XMPP de Prosody y los nodos de medios JVB, asignando bridges dinámicamente a cada participante.jvb(Jitsi Videobridge): Unidad de retransmisión selectiva (SFU) basada en Java que conmuta flujos de vídeo/audio RTP/RTCP entre clientes sin transcodificar, requiriendo máxima prioridad de scheduling de CPU.
1. Preparación del entorno y versionado de artefactos
Para garantizar predictibilidad en producción y evitar roturas por etiquetas flotantes (:latest), clone el repositorio oficial de despliegue fijando una rama estable probada por la comunidad:
# Crear directorio base en la jerarquía estándar del sistema
mkdir -p /opt/jitsi-meet && cd /opt/jitsi-meet
# Clonar el árbol de despliegue apuntando al último tag estable release-9823
git clone --depth 1 --branch stable-9823 https://github.com/jitsi/docker-jitsi-meet.git .
# Generar archivo de configuración inicial desde la plantilla
cp env.example .env
Cree la estructura de persistencia local en el sistema de archivos del host. En la infraestructura KVM de tropic.host, el almacenamiento respaldado por NVMe empresarial PCIe 4.0 con rendimiento superior a 50 000 IOPS en lectura aleatoria 4K QD1 previene cuellos de botella de I/O cuando Prosody y Nginx escriben registros de acceso y estructuras temporales de sesión bajo tráfico intenso:
mkdir -p /opt/jitsi-meet-cfg/{web,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb}
chmod -R 750 /opt/jitsi-meet-cfg
2. Configuración determinista de variables de entorno (.env)
El archivo .env actúa como la única fuente de verdad para la inyección de secretos compartidos, nombres de dominio y topología de red de los contenedores. Ejecute el script auxiliar para generar contraseñas criptográficas seguras para la autenticación entre componentes internos (Jicofo a Prosody, JVB a Prosody):
./gen-passwords.sh
A continuación, configure los parámetros operativos críticos editando .env. Reemplace los valores por los correspondientes a su infraestructura:
# Configuración del dominio y acceso HTTP/HTTPS
HTTP_PORT=80
HTTPS_PORT=443
PUBLIC_URL=https://meet.ejemplo.com
# Persistencia de configuración en disco local
CONFIG=/opt/jitsi-meet-cfg
# Zona horaria del host
TZ=UTC
# Gestión automatizada de certificados TLS mediante ACME/Let's Encrypt
ENABLE_LETSENCRYPT=1
LETSENCRYPT_DOMAIN=meet.ejemplo.com
[email protected]
LETSENCRYPT_USE_STAGING=0
# Configuración de red para Jitsi Videobridge (JVB)
# CRÍTICO: Debe ser la IPv4 estática pública asignada a su VPS
DOCKER_HOST_ADDRESS=198.51.100.25
JVB_PORT=10000
JVB_TCP_PORT=4443
JVB_TCP_MAPPED_PORT=4443
# Parámetros del scheduler XMPP y subred interna
XMPP_DOMAIN=meet.jitsi
XMPP_SERVER=prosody
XMPP_BOSH_URL_BASE=http://prosody:5280
# Políticas de autenticación (0 = salas públicas; 1 = moderador requiere usuario)
ENABLE_AUTH=0
ENABLE_GUESTS=1
# Opciones avanzadas de la interfaz y WebRTC
ENABLE_SUBDOMAINS=0
ENABLE_COLIBRI_WEBSOCKET=1
ENABLE_XMPP_WEBSOCKET=1
Alineación de red en el ICE Gathering: La variableDOCKER_HOST_ADDRESSes el parámetro más crítico al desplegar Jitsi Meet en VPS Docker. Si se omite o se apunta a127.0.0.1, el JVB anunciará candidatos ICE privados a los navegadores remotos, provocando el fallo inmediato de conexión en la fase de negociación WebRTC (pantalla negra y desconexión tras 15 segundos).
3. Definición del orquestador (docker-compose.yml)
El archivo de composición gestiona el ciclo de vida de los cuatro contenedores, asegurando aislamiento en una red bridge dedicada y asignando cuotas de recursos mediante cgroups para blindar la estabilidad del demonio JVB.
Cree o ajuste su docker-compose.yml con la siguiente definición optimizada para entornos de alta concurrencia:
version: '3.8'
networks:
jitsi_net:
driver: bridge
ipam:
driver: default
config:
- subnet: 172.28.0.0/16
services:
# Front-end Web, Proxy Nginx y Terminación TLS
web:
image: jitsi/web:stable-9823
restart: unless-stopped
ports:
- "${HTTP_PORT}:80"
- "${HTTPS_PORT}:443"
volumes:
- ${CONFIG}/web:/config:Z
- ${CONFIG}/web/crontabs:/var/spool/cron/crontabs:Z
environment:
- HTTP_PORT
- HTTPS_PORT
- PUBLIC_URL
- TZ
- ENABLE_LETSENCRYPT
- LETSENCRYPT_DOMAIN
- LETSENCRYPT_EMAIL
- LETSENCRYPT_USE_STAGING
- ENABLE_COLIBRI_WEBSOCKET
- ENABLE_XMPP_WEBSOCKET
- XMPP_SERVER
networks:
jitsi_net:
depends_on:
- prosody
# Núcleo de Señalización XMPP
prosody:
image: jitsi/prosody:stable-9823
restart: unless-stopped
expose:
- '5222' # Comunicación C2S (Client to Server)
- '5347' # Componentes externos (Jicofo)
- '5280' # BOSH / WebSockets
volumes:
- ${CONFIG}/prosody/config:/config:Z
- ${CONFIG}/prosody/prosody-plugins-custom:/prosody-plugins-custom:Z
environment:
- TZ
- XMPP_DOMAIN
- XMPP_AUTH_DOMAIN=auth.${XMPP_DOMAIN}
- XMPP_MUC_DOMAIN=muc.${XMPP_DOMAIN}
- XMPP_INTERNAL_MUC_DOMAIN=internal-muc.${XMPP_DOMAIN}
- XMPP_MODULES
- XMPP_MUC_MODULES
- JICOFO_COMPONENT_SECRET
- JICOFO_AUTH_USER
- JICOFO_AUTH_PASSWORD
- JVB_AUTH_USER
- JVB_AUTH_PASSWORD
- PUBLIC_URL
- ENABLE_AUTH
- ENABLE_GUESTS
networks:
jitsi_net:
aliases:
- ${XMPP_SERVER}
deploy:
resources:
limits:
memory: 1024M
reservations:
memory: 512M
# Orquestador de Conferencias (Focus)
jicofo:
image: jitsi/jicofo:stable-9823
restart: unless-stopped
volumes:
- ${CONFIG}/jicofo:/config:Z
environment:
- TZ
- XMPP_DOMAIN
- XMPP_AUTH_DOMAIN=auth.${XMPP_DOMAIN}
- XMPP_INTERNAL_MUC_DOMAIN=internal-muc.${XMPP_DOMAIN}
- XMPP_SERVER
- JICOFO_COMPONENT_SECRET
- JICOFO_AUTH_USER
- JICOFO_AUTH_PASSWORD
- SENTRY_DSN
networks:
jitsi_net:
depends_on:
- prosody
deploy:
resources:
limits:
memory: 1024M
reservations:
memory: 512M
# Servidor SFU de Medios WebRTC (Jitsi Videobridge)
jvb:
image: jitsi/jvb:stable-9823
restart: unless-stopped
ports:
- "${JVB_PORT}:${JVB_PORT}/udp"
- "${JVB_TCP_PORT}:${JVB_TCP_MAPPED_PORT}/tcp"
volumes:
- ${CONFIG}/jvb:/config:Z
environment:
- TZ
- DOCKER_HOST_ADDRESS
- XMPP_DOMAIN
- XMPP_AUTH_DOMAIN=auth.${XMPP_DOMAIN}
- XMPP_INTERNAL_MUC_DOMAIN=internal-muc.${XMPP_DOMAIN}
- XMPP_SERVER
- JVB_AUTH_USER
- JVB_AUTH_PASSWORD
- JVB_PORT
- JVB_TCP_PORT
- JVB_TCP_MAPPED_PORT
- PUBLIC_URL
- ENABLE_COLIBRI_WEBSOCKET
networks:
jitsi_net:
depends_on:
- prosody
deploy:
resources:
limits:
cpus: '3.50'
memory: 3072M
reservations:
cpus: '1.00'
memory: 1536M
4. Consideraciones de virtualización y hardware subyacente
Al desplegar Jitsi Meet en VPS Docker bajo cargas de trabajo reales (múltiples streams de vídeo en 720p a 30 FPS con códecs VP8/VP9 o AV1), el motor SFU de JVB realiza una conmutación intensiva de paquetes UDP en el espacio de usuario. En entornos de virtualización tradicionales con sobreasignación (overselling) de procesador, el valor CPU Steal Time (%st) se eleva, introduciendo microcongelamientos (stuttering) y degradación severa en el cálculo de métricas de jitter p99 de audio.
Ejecutar este stack sobre instancias KVM dedicadas en tropic.host garantiza métricas %st = 0.0% continuas gracias a la asignación no compartida de núcleos AMD EPYC y Ryzen 9. Adicionalmente, el enlace troncal con velocidad simétrica de 1 a 10 Gbps conectado a los puntos neutros IXP de Frankfurt y Ámsterdam, combinado con la activación nativa de TCP BBR a nivel de kernel, asegura que las sesiones que deban degradar a TCP 4443 (por bloqueos corporativos de UDP) mantengan una latencia controlada sin colapsar la ventana de congestión.
5. Inicialización del stack y validación de señalización interna
Inicie los contenedores en segundo plano y verifique el orden secuencial de inicialización:
docker compose up -d
Compruebe de forma inmediata que todos los procesos alcancen el estado de ejecución sin reinicios anómalos:
docker compose ps
La salida debe mostrar los cuatro contenedores en estado Up:
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
jitsi-meet-jicofo-1 jitsi/jicofo:stable-9823 "/init" jicofo 15 seconds ago Up 14 seconds
jitsi-meet-jvb-1 jitsi/jvb:stable-9823 "/init" jvb 15 seconds ago Up 14 seconds 0.0.0.0:4443->4443/tcp, 0.0.0.0:10000->10000/udp
jitsi-meet-prosody-1 jitsi/prosody:stable-9823 "/init" prosody 15 seconds ago Up 14 seconds 5222/tcp, 5280/tcp, 5347/tcp
jitsi-meet-web-1 jitsi/web:stable-9823 "/init" web 15 seconds ago Up 14 seconds 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp
Verifique la secuencia de handshake y suscripción en los registros de Jicofo para confirmar que ha tomado control del dominio MUC y registrado exitosamente el bridge de medios:
docker compose logs -f jicofo | grep -E "Bridge|focus"
El registro debe confirmar la detección del nodo JVB disponible:
Jicofo 2026-10-04 16:50:12.431 INFO: [32] org.jitsi.jicofo.bridge.Bridge.log() Bridge: [email protected] is OPERATIONAL
Jicofo 2026-10-04 16:50:12.435 INFO: [32] org.jitsi.jicofo.bridge.BridgeSelector.log() Added new bridge: Bridge[[email protected], relayId=null, region=null]
Finalice inspeccionando el contenedor jvb para cerciorarse de que la dirección IP pública externa ha sido correctamente asimilada por el subsistema ICE de Harvester:
docker compose logs jvb | grep -i "mapping"
Una traza como org.jitsi.videobridge.ice.Harvester.log() Single-port mapping: 10000/udp -> 198.51.100.25:10000/udp certifica que el stack se encuentra listo para recibir conexiones WebRTC de clientes externos sin incidencias de NAT traversal.
Optimización del Jitsi Videobridge (JVB) y Algoritmo TCP BBR
Con los contenedores operacionales y el mapeo del harvester resuelto, la configuración estándar del kernel Linux y los valores por defecto de la máquina virtual de Java resultan insuficientes para soportar conferencias multiusuario concurrentes. Al desplegar jitsi meet en vps docker, el componente Jitsi Videobridge (JVB) asume el rol de Selective Forwarding Unit (SFU): no transcodifica vídeo, pero enruta, conmuta y replica ráfagas masivas de datagramas UDP (RTP/RTCP) entre todos los participantes.
Bajo perfiles de tráfico WebRTC con simulcast activo (resoluciones simultáneas de 180p, 360p y 720p/1080p por emisor), una sala con 15 participantes puede superar fácilmente los 25.000 paquetes UDP por segundo. Si los buffers del socket del kernel o las colas de red del sistema operativo se desbordan, el subsistema de red descarta datagramas de forma silenciosa antes de que alcancen el espacio de usuario. Esto degrada drásticamente la latencia p99, desincroniza el audio y fuerza congelamientos de vídeo.
1. Afinamiento de la pila de red del host (sysctl) para tráfico UDP masivo
El stack de red estándar de distribuciones como Ubuntu o Debian reserva buffers de recepción (rmem) y transmisión (wmem) orientados a servicios web convencionales (HTTP/Nginx), donde los flujos son transaccionales y de bajo volumen por conexión. Para garantizar que JVB procese ráfagas multimedia sin introducir pérdidas a nivel de socket, es indispensable redimensionar la memoria asignada a los buffers del sistema.
Cree un archivo de configuración dedicado en /etc/sysctl.d/99-jitsi-network.conf:
# /etc/sysctl.d/99-jitsi-network.conf
# Aumento de buffers globales de recepción y transmisión (64 MB para absorción de ráfagas)
net.core.rmem_max = 67108864
net.core.wmem_max = 67108864
net.core.rmem_default = 33554432
net.core.wmem_default = 33554432
# Rango mínimo, inicial y máximo de memoria para sockets UDP en páginas del sistema (4 KB por página)
# Formato: min default max (ejemplo: 256 MB de techo máximo para el subsistema UDP)
net.ipv4.udp_mem = 65536 131072 262144
net.ipv4.udp_rmem_min = 16384
net.ipv4.udp_wmem_min = 16384
# Capacidad de la cola de procesamiento entre la NIC física y el subsistema de red del kernel
net.core.netdev_max_backlog = 100000
# Límite superior de sockets en cola de escucha TCP (señalización Prosody / Web)
net.core.somaxconn = 65535
# Optimización del algoritmo de control de congestión y disciplina de colas
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
# Mitigación de latencia de buffers TCP y optimización de sockets
net.ipv4.tcp_notsent_lowat = 16384
net.ipv4.tcp_fastopen = 3
net.ipv4.tcp_fin_timeout = 15
net.ipv4.ip_local_port_range = 1024 65535
Aplique las directivas en caliente verificando que no existan errores de sintaxis en el archivo:
sysctl --system
Análisis técnico de las directivas aplicadas:
net.core.netdev_max_backlog = 100000: Eleva el número de tramas que la tarjeta de red puede encolar en el anillo de recepción antes de procesar las interrupciones por software (ksoftirqd). En servidores con alto volumen de paquetes pequeños (como los datagramas de audio OPUS de 20 ms), el valor estándar de1000satura la cola y provoca descartes inmediatos en la interfaz física.net.core.rmem_max = 67108864: Asigna un techo de 64 MB al socket de lectura. JVB requiere este margen para absorber variaciones en el tiempo de llegada de los paquetes sin forzar pérdidas de tramas clave (Keyframes/I-frames).net.ipv4.tcp_notsent_lowat = 16384: Limita el tamaño de los datos no enviados en el buffer de sockets TCP a 16 KB. Esto previene el fenómeno de bufferbloat en conexiones de señalización WebSockets, reduciendo el retraso de entrega de los paquetes de estado de la conferencia.
2. Implementación de TCP BBR y Fair Queueing (fq)
A pesar de que los flujos de medios en tiempo real viajan sobre UDP (SRTP), el rendimiento general de jitsi meet en vps docker depende críticamente de TCP para: 1. La señalización bidireccional XMPP vía WebSockets (puerto 443 a través de Nginx hacia Prosody). 2. La descarga inicial del bundle estático de la aplicación cliente (Jitsi Meet Web, bibliotecas WASM, empaquetado React). 3. El fallback de transporte de medios sobre TCP (puerto 4443 o TURN sobre 443) para clientes corporativos aislados tras firewalls simétricos que bloquean el tráfico UDP saliente.
El algoritmo estándar Cubic se basa en la pérdida de paquetes como señal de congestión. En redes inalámbricas (Wi-Fi, 4G, 5G), donde las fluctuaciones y pérdidas aleatorias no están relacionadas con la saturación del enlace, Cubic reduce drásticamente la ventana de congestión (cwnd), generando parones en la carga del cliente y desconexiones de señalización.
Por el contrario, BBR (Bottleneck Bandwidth and Round-trip propagation time) modela continuamente el ancho de banda máximo disponible y el RTT mínimo del trayecto. Al combinarse con la disciplina de encolamiento fq (Fair Queueing), BBR realiza un pacing estricto de los paquetes a nivel de kernel, previniendo micro-ráfagas destructivas y estabilizando el jitter.
Compruebe la carga de los módulos en el kernel:
lsmod | grep bbr
Si no devuelve salida, cargue el módulo manualmente y agréguelo a /etc/modules-load.d/bbr.conf:
modprobe tcp_bbr
echo "tcp_bbr" | tee -a /etc/modules-load.d/bbr.conf
Valide el estado activo del algoritmo y la disciplina de colas mediante sysctl:
sysctl net.ipv4.tcp_congestion_control net.core.default_qdisc
Salida esperada:
net.ipv4.tcp_congestion_control = bbr
net.core.default_qdisc = fq
Verifique el funcionamiento de BBR en un socket activo de señalización o HTTPS:
ss -tin '( dport = :443 or sport = :443 )'
La salida confirmará el cálculo dinámico del pacing rate y el RTT real de los clientes:
bbr wscale:7,7 rto:220 rtt:18.421/2.115 ato:40 mss:1440 rcvspace:64320 ssthresh:45 cwnd:28 pacing_rate 18.2Mbps delivery_rate 15.6Mbps
3. Ajuste de memoria y Garbage Collector de la JVM en el JVB
El Jitsi Videobridge se ejecuta sobre OpenJDK dentro del contenedor jitsi/jvb. Un error común en producción es dejar la gestión de memoria sujeta a los parámetros automáticos de la JVM, lo que provoca pausas prolongadas de parada de mundo (Stop-the-World, STW) durante la recolección de basura. Una pausa de GC superior a 25 ms interrumpe la retransmisión de paquetes UDP, degradando el jitter y disparando peticiones NACK/PLI innecesarias desde los navegadores.
Para garantizar pausas de recolección inferiores a 10 ms, configure el recolector G1GC con parámetros de latencia deterministas directamente en las variables de entorno del contenedor.
Abra su archivo .env o cree un archivo docker-compose.override.yml para desacoplar estos ajustes del repositorio base:
# docker-compose.override.yml
services:
jvb:
environment:
# Sizing de memoria para 50-100 streams simultáneos
- VIDEOBRIDGE_MAX_MEMORY=3072m
# Directivas de bajo jitter para la JVM
- JVM_SYS_PROPS=-XX:+UseG1GC -XX:MaxGCPauseMillis=10 -XX:InitiatingHeapOccupancyPercent=45 -XX:G1ReservePercent=15 -XX:G1HeapRegionSize=8m -XX:+ParallelRefProcEnabled -Djava.net.preferIPv4Stack=true
ulimits:
nofile:
soft: 65536
hard: 65536
deploy:
resources:
limits:
cpus: '4.0'
memory: 4096M
reservations:
cpus: '2.0'
memory: 3072M
Complemente esta configuración ajustando los límites de subprocesos y descartes en el archivo de propiedades internas de JVB. Edite ~/.jitsi-meet-cfg/jvb/custom-sip-communicator.properties:
# Sizing de hilos para procesamiento de paquetes de red
org.jitsi.videobridge.SUPPRESS_CALL_RECORDING_ALERT=true
org.jitsi.videobridge.octo.BIND_ADDRESS=0.0.0.0
org.jitsi.videobridge.rest.COLIBRI_ENABLE=true
# Ajuste de tamaño de cola de entrada para datagramas UDP por stream
org.jitsi.videobridge.PADDING_BUFFER_SIZE=1000
org.jitsi.videobridge.ENABLE_STATISTICS=true
org.jitsi.videobridge.STATISTICS_TRANSPORT=muc
Reinicie el contenedor JVB para asimilar las directivas de la JVM y del subsistema de medios:
docker compose up -d --force-recreate jvb
4. Estabilidad de hipervisor: impacto de CPU Steal Time en WebRTC
La gestión en tiempo real de flujos WebRTC es extraordinariamente sensible al jitter de cómputo. En entornos de virtualización compartida donde el proveedor aplica sobreventa (overselling) agresiva de procesador, el kernel del host desaloja la CPU virtual asignada a su servidor para atender a otros inquilinos. Este fenómeno se registra en la métrica %st (CPU Steal Time) mediante top o mpstat.
Si el %st supera el 0.5%, el hilo del kernel encargado de atender las interrupciones de red (ksoftirqd) se suspende. Durante esos milisegundos de suspensión, los paquetes UDP que llegan al puerto 10000 saturan el buffer y son descartados, manifestándose en los clientes como audio entrecortado («robótico») y congelamiento momentáneo del vídeo.
Para cargas de trabajo en tiempo real, el despliegue requiere infraestructura KVM con asignación física determinista y 0.0% de CPU Steal Time (%st = 0.0%). En los entornos KVM NVMe de tropic.host, los núcleos de alta frecuencia (arquitecturas AMD EPYC y Ryzen 9) operan sin sobreasignación de ciclos de cómputo. Esto, combinado con enlaces simétricos de 1 a 10 Gbps con BBR habilitado de origen y peering directo en los nodos neurálgicos de Frankfurt (DE-CIX), Ámsterdam (AMS-IX) y Londres (LINX), garantiza que el procesamiento de datagramas y la señalización WebSocket mantengan un p99 de latencia estable por debajo de los 15 ms a nivel de transporte.
5. Auditoría de descarte de paquetes y telemetría de red
Una vez aplicados los ajustes, valide que el sistema no presente descartes de datagramas a nivel de kernel ni de contenedor mientras se ejecutan pruebas de carga o conferencias activas.
Ejecute una auditoría en vivo del subsistema UDP mediante netstat:
watch -n 1 "netstat -su | grep -E 'buffer errors|packet receive errors|RcvbufErrors|SndbufErrors'"
Salida esperada bajo operación óptima:
0 packet receive errors
0 receive buffer errors
0 send buffer errors
Si el contador receive buffer errors se incrementa durante la prueba, indica que el valor de net.core.rmem_max o el parámetro VIDEOBRIDGE_MAX_MEMORY debe escalarse proporcionalmente al número de clientes conectados.
Para verificar que el socket UDP del contenedor JVB está escuchando con los tamaños de buffer asignados, inspeccione el descriptor del socket con ss:
ss -umpn -l -t -u '( sport = :10000 )'
La columna Recv-Q y Send-Q debe reflejar los límites de memoria definidos en el archivo de configuración del kernel:
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
UNCONN 0 0 0.0.0.0:10000 0.0.0.0:* users:(("java",pid=14205,fd=128))
skmem:(r0,rb67108864,t0,tb67108864,f0,w0,o0,bl0,d0)
El valor rb67108864 (64 MB de Receive Buffer) confirma que el contenedor hereda con precisión la configuración del host, blindando el servicio ante saturaciones repentinas y garantizando un transporte de medios estable para cada participante de la videoconferencia.
Seguridad: Autenticación JWT y Protección contra Accesos No Autorizados
Una vez optimizado el rendimiento del kernel y garantizado el transporte de medios UDP en el JVB, el vector de ataque más crítico se traslada a la capa de señalización y control de sesiones. Por defecto, una instalación estándar de jitsi meet en vps docker opera en modo de acceso anónimo abierto (anonymous). En esta configuración, cualquier cliente que alcance el puerto 443 puede instanciar salas de conferencia arbitrarias, reservando memoria en el contenedor Prosody y forzando la asignación de puertos y bridges de renderizado en el Jitsi Videobridge. En entornos de producción expuestos a Internet sin filtrado de IP, esto deriva rápidamente en secuestro de ancho de banda, ataques de saturación de señalización XMPP y consumo masivo de CPU.
Para mitigar este riesgo, la arquitectura debe migrar a un modelo de identidad criptográfica basado en JSON Web Tokens (JWT, RFC 7519) combinado con un esquema de doble dominio XMPP en Prosody: un dominio autenticado para los moderadores autorizados a crear salas y un dominio de invitados (guest domain) restringido exclusivamente a unirse a salas activas existentes.
Arquitectura de Doble Dominio en Prosody y Ciclo de Vida de la Sala
El mecanismo de control de acceso en Jitsi Meet desacopla la creación de la sala de la participación en ella. La lógica de control se implementa en el servidor XMPP Prosody mediante módulos Lua especializados (mod_auth_token, mod_muc_domain_mapper y mod_token_verification):
- Dominio Principal (
meet.dominio.com): Configurado con el móduloauth_token. Exige un JWT firmado por una clave privada o secreta autorizada. Solo los usuarios con un token válido pueden emitir el paquete XMPPiqque declara la creación de la sala en el componente MUC (Multi-User Chat). - Dominio de Invitados (
guest.meet.dominio.com): Configurado con autenticaciónanonymous. Permite la entrada de participantes sin credenciales ni tokens, pero el servidor rechaza cualquier solicitud de instanciación de un nuevo nodo MUC proveniente de este dominio. - Flujo de Interacción: Cuando un usuario no autenticado intenta acceder a
https://meet.dominio.com/SalaOperaciones, la interfaz web detecta que la sala no existe en el dominio principal y retiene al usuario en estado de espera (Waiting for the host). En cuanto el moderador envía su JWT válido en el handshake WebSocket inicial, Prosody valida la firma, genera la sala en el dominio autenticado y permite la entrada en cascada de los invitados que aguardaban en el dominioguest.
Configuración del Despliegue en Docker Compose
En el archivo de variables de entorno .env del despliegue oficial de Jitsi en Docker, se deben sustituir los valores predeterminados por las directivas de autenticación estricta:
# ------------------------------------------------------------------------------
# SEGURIDAD Y AUTENTICACIÓN JWT (docker-jitsi-meet)
# ------------------------------------------------------------------------------
# Habilita el subsistema de autenticación en Prosody
ENABLE_AUTH=1
# Tipo de mecanismo de verificación criptográfica
AUTH_TYPE=jwt
# Identificador de la aplicación cliente (claim 'iss')
JWT_APP_ID=tropic_infra_jitsi
# Clave secreta compartida (HS256) o clave pública PEM (RS256)
# Genere una cadena de alta entropía (mínimo 64 caracteres alfanuméricos)
JWT_APP_SECRET=a8f7c9e3b1d5420987f6e2c4a1b8905d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b
# Lista blanca de emisores (iss) y audiencias (aud) permitidas
JWT_ACCEPTED_ISSUERS=tropic_infra_jitsi,tropic_auth_gateway
JWT_ACCEPTED_AUDIENCES=jitsi_meet_conference
# Permite que usuarios sin token se unan a salas ya creadas por un moderador
ENABLE_GUESTS=1
# Dominio virtual interno para invitados anónimos
GUEST_DOMAIN=guest.meet.dominio.com
# Habilita el control de sala de espera (Lobby) gestionado por el moderador
ENABLE_LOBBY=1
# Forzar resolución criptográfica estricta en Prosody
JWT_SIGN_TYPE=HS256
Al regenerar los contenedores (docker compose up -d prosody jicofo web), Prosody reescribe automáticamente los archivos de configuración en /config/prosody/conf.d/. Internamente, el archivo de configuración del host virtual genera la siguiente estructura de componentes Lua:
VirtualHost "meet.dominio.com"
authentication = "token"
app_id = "tropic_infra_jitsi"
app_secret = "a8f7c9e3b1d5420987f6e2c4a1b8905d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b"
allow_empty_token = false
VirtualHost "guest.meet.dominio.com"
authentication = "anonymous"
c2s_require_encryption = false
Component "conference.meet.dominio.com" "muc"
storage = "memory"
modules_enabled = {
"muc_domain_mapper";
"token_verification";
"muc_lobby_rooms";
}
admins = { "[email protected]" }
muc_room_default_presence_broadcast = {
["root"] = "false";
["muc#item"] = "true";
["muc#user"] = "true";
}
Estructura de Reclamaciones (Claims) y Generación de Tokens
Jitsi Meet parsea campos obligatorios dentro del payload del JWT para determinar el rol del usuario, el nombre de la sala autorizada y los privilegios funcionales dentro del puente SFU. Una estructura de token válida según la especificación de Jitsi debe contener:
{
"aud": "jitsi_meet_conference",
"iss": "tropic_infra_jitsi",
"sub": "meet.dominio.com",
"room": "SalaOperaciones",
"exp": 1791234800,
"nbf": 1791231200,
"context": {
"user": {
"id": "usr-sysadmin-01",
"name": "DevOps Architect",
"email": "[email protected]",
"avatar": "https://avatar.dominio.com/ops.png",
"affiliation": "owner"
},
"features": {
"recording": true,
"livestreaming": false,
"screen-sharing": true,
"sip-outbound": false
}
}
}
room: Cadena con el nombre de la sala permitida. Para permitir que un token cree cualquier sala bajo ese dominio, se especifica el comodín"*".context.user.affiliation: Si el valor es"owner", Prosody otorga inmediatamente privilegios de administrador de MUC (affiliation='owner'), permitiendo silenciar participantes, expulsar conexiones maliciosas y habilitar la sala de espera.exp: Marca de tiempo Unix de expiración estricta. Configure valores de vida útil reducidos (TTL de 10 a 60 minutos) para evitar la reutilización de tokens en caso de filtración de URLs.
Para integrar la emisión de tokens en su backend de aprovisionamiento o en scripts de administración local dentro del host, utilice el siguiente script en Python 3 (generate_jitsi_jwt.py):
#!/usr/bin/env python3
import time
import jwt
APP_ID = "tropic_infra_jitsi"
APP_SECRET = "a8f7c9e3b1d5420987f6e2c4a1b8905d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b"
JITSI_DOMAIN = "meet.dominio.com"
def generate_moderator_token(room_name: str, user_name: str, duration_seconds: int = 3600) -> str:
now = int(time.time())
payload = {
"aud": "jitsi_meet_conference",
"iss": APP_ID,
"sub": JITSI_DOMAIN,
"room": room_name,
"nbf": now - 5,
"exp": now + duration_seconds,
"context": {
"user": {
"name": user_name,
"affiliation": "owner"
},
"features": {
"recording": True,
"screen-sharing": True
}
}
}
return jwt.encode(payload, APP_SECRET, algorithm="HS256")
if __name__ == "__main__":
token = generate_moderator_token(room_name="WarRoomInfra", user_name="DevOps Lead")
print(f"URL de Acceso Seguro:\nhttps://{JITSI_DOMAIN}/WarRoomInfra?jwt={token}")
Otorgue permisos de ejecución y pruebe la generación:
chmod +x generate_jitsi_jwt.py
./generate_jitsi_jwt.py
Salas de Espera (Lobby Mode) y Cifrado por Contraseña Local
Aun con JWT implementado, un moderador puede requerir un segundo factor de aislamiento para impedir que usuarios legítimos del dominio guest ingresen a una reunión antes de que el equipo directivo o técnico esté listo. Jitsi proporciona dos capas adicionales:
- Lobby Mode (
mod_muc_lobby): Al ingresar comoowner, el moderador activa la sala de espera mediante la API o interfaz gráfica. En el bus XMPP, Prosody crea una sala secundaria vinculada:[email protected]. Los invitados anónimos son retenidos en este componente intermedio sin acceso a los streams de audio/video del JVB hasta que el moderador emite un mensaje XMPP con la stanza<approve jid="invitado@guest..."/>. - Protección por Contraseña Efímera: Una vez creada la sala, el moderador puede definir una contraseña temporal. Prosody aplica el hash directamente en la memoria del componente MUC mediante el campo
muc#roomconfig_roomsecret. Esta contraseña no se almacena en disco y se destruye automáticamente en cuanto el último participante abandona la conferencia y Prosody desasigna el proceso de la sala.
Mitigación de Fuerza Bruta y Hardening de Endpoints en Nginx
El plano de autenticación y los sockets de señalización deben protegerse contra ataques de denegación de servicio que intenten saturar el hilo único de ejecución de Prosody. Dado que Prosody evalúa cada token JWT y cada handshake XMPP en un bucle de eventos asíncrono en Lua, ráfagas masivas de solicitudes HTTP POST hacia /http-bind (BOSH) o peticiones de actualización a /xmpp-websocket pueden elevar la latencia de procesamiento de todo el sistema.
Aplique un límite estricto de tasa (rate limiting) en la configuración del proxy inverso Nginx (/config/nginx/site-confs/default.conf):
# Zona de memoria compartida para rastreo de IPs (10MB almacenan ~160.000 direcciones)
limit_req_zone $binary_remote_addr zone=jitsi_auth_limit:10m rate=5r/s;
limit_req_zone $binary_remote_addr zone=jitsi_ws_limit:10m rate=15r/s;
# Protección sobre el endpoint BOSH
location = /http-bind {
limit_req zone=jitsi_auth_limit burst=10 nodelay;
limit_req_status 429;
proxy_pass http://prosody:5280/http-bind;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $http_host;
proxy_buffering off;
tcp_nodelay on;
}
# Protección sobre el endpoint WebSocket
location = /xmpp-websocket {
limit_req zone=jitsi_ws_limit burst=20 nodelay;
limit_req_status 429;
proxy_pass http://prosody:5280/xmpp-websocket;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $http_host;
proxy_read_timeout 900s;
tcp_nodelay on;
}
Recargue la configuración del proxy sin interrumpir las conferencias en curso:
docker exec -it docker-jitsi-meet-web-1 nginx -s reload
Coste Criptográfico y Aislamiento de CPU en Producción
La verificación continua de firmas JWT (especialmente si se migra a claves asimétricas RS256/ES256 con infraestructura PKI) y la terminación TLS concurrente representan una carga de cálculo de alta densidad matemática en la CPU del host. En escenarios donde decenas de usuarios acceden simultáneamente a múltiples salas, el proceso de validación no debe competir por ciclos de reloj con el hilo de señalización de Jicofo ni con el motor de conmutación de paquetes del JVB.
Para evitar picos de latencia (jitter) en la señalización durante ráfagas de autenticación, la plataforma sobre la que corre el hipervisor debe garantizar aislamiento computacional determinista. La infraestructura de tropic.host previene este cuello de botella al suministrar instancias KVM sobre procesadores AMD EPYC y Ryzen 9 sin sobreasignación (zero oversubscription), manteniendo una métrica de CPU Steal Time en cero absoluto (%st = 0.0%). Este nivel de aislamiento garantiza que las operaciones criptográficas en Prosody y los handshakes TLS en Nginx se ejecuten en sub-milisegundos en la cola del kernel, eliminando retardos en la admisión de participantes y asegurando la estabilidad integral de jitsi meet en vps docker.
Monitoreo de Calidad de Llamada y Plan de Recuperación ante Desastres
La operación continua de una plataforma de videoconferencia no admite fallos silenciosos: una degradación marginal en el transporte UDP se traduce de forma instantánea en audio entrecortado, congelamiento de fotogramas y desconexiones de señalización. Mantener la fiabilidad en una infraestructura basada en jitsi meet en vps docker exige desacoplar la observación pasiva del sistema operativo y desplegar telemetría activa a nivel de paquetes RTP/RTCP, mecanismos de autorrecuperación para contenedores desincronizados y un protocolo determinista de Disaster Recovery (DR).
Telemetría de WebRTC y Extracción de Métricas en Jitsi Videobridge (JVB)
El núcleo de conmutación de medios (JVB) procesa flujos SRTP en espacio de usuario y calcula de forma continua estadísticas críticas de transporte. Para exponer estos datos hacia Prometheus o sistemas de observabilidad externos, se debe habilitar el endpoint HTTP interno de estadísticas de Colibri en el archivo de configuración del puente (/config/jvb.conf o mediante variables de entorno en el contenedor).
Dentro del archivo .env del despliegue Docker, active la interfaz de métricas asignando el puerto y habilitando el transporte de estadísticas:
# Habilitación de la API de métricas Colibri en JVB
JVB_ENABLE_STATISTICS=true
JVB_STATISTICS_TRANSPORT=colibri
JVB_STATISTICS_INTERVAL=5000
Tras recrear el contenedor, JVB expone un payload JSON estructurado en el puerto 8080/tcp interno. Puede auditarse directamente mediante curl y jq desde la terminal del host:
docker exec -it docker-jitsi-meet-jvb-1 curl -s http://localhost:8080/colibri/stats | jq '{
conferences: .conferences,
participants: .participants,
threads: .threads,
packet_rate_upload: .packet_rate_upload,
packet_rate_download: .packet_rate_download,
loss_rate_upload: .loss_rate_upload,
loss_rate_download: .loss_rate_download,
jitter_aggregate: .jitter_aggregate,
rtt_aggregate: .rtt_aggregate,
bit_rate_upload: .bit_rate_upload,
bit_rate_download: .bit_rate_download
}'
Indicadores Clave de Rendimiento (KPIs) y Umbrales de Alerta
Para garantizar una experiencia corporativa sin degradación perceptual, los umbrales de alerta en Prometheus/Alertmanager deben configurarse bajo los siguientes límites operativos:
- Pérdida de Paquetes (
loss_rate_download/loss_rate_upload): Debe mantenerse estrictamente en $\le 0.015$ (1.5%). Un valor sostenido superior al 2.5% durante 60 segundos indica congestión de buffer UDP en el kernel o saturación en el tránsito de red del proveedor. - Jitter Agregado (
jitter_aggregate): Umbral crítico en $\ge 30\,\text{ms}$. Variaciones superiores introducen retraso en el buffer de desacople (jitter buffer) de WebRTC, incrementando la latencia interactiva extremo a extremo. - Round-Trip Time (
rtt_aggregate): El percentil 95 (p95) debe permanecer en $\le 100\,\text{ms}$ para participantes dentro de la misma región geográfica. - Pérdida de paquetes por desbordamiento de socket UDP: Monitoree caídas de paquetes a nivel de sistema operativo con el contador
RcvbufErrors:
netstat -su | grep -E "buffer errors|packet receive errors"
Si este contador incrementa mientras loss_rate_download es alto, el cuello de botella radica en el tamaño de los búferes del kernel Linux, resoluble incrementando net.core.rmem_max y net.core.wmem_max a 67108864 (64 MB).
En entornos de alta concurrencia, el rendimiento de red depende de la topología BGP subyacente. Los servidores KVM de tropic.host resuelven este vector al integrar enlaces simétricos de 1 a 10 Gbps con TCP BBR habilitado de fábrica y peering directo en los principales puntos neutros de intercambio (DE-CIX Frankfurt, AMS-IX, LINX). Esto minimiza el número de saltos de red (AS hops) y reduce drásticamente el jitter en llamadas con participantes distribuidos internacionalmente.
Watchdog de Salud y Políticas de Reinicio en Docker Compose
En escenarios de saturación de red o fugas de memoria en la JVM, un contenedor puede mantener su proceso principal activo pero dejar de procesar paquetes o perder la conexión XMPP con Prosody (estado de "puente zombi"). La directiva estándar restart: unless-stopped no rescata un contenedor en este estado.
Se debe implementar un healthcheck sintético en el servicio jvb dentro de docker-compose.yml que valide tanto la interfaz HTTP de salud como la vinculación real del socket UDP:
jvb:
image: jitsi/jvb:stable
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:8080/about/health && nc -z -u -w1 127.0.0.1 10000 || exit 1"]
interval: 15s
timeout: 5s
retries: 3
start_period: 30s
ulimits:
nofile:
soft: 65536
hard: 65536
Para forzar la recreación automática si un contenedor entra en estado unhealthy, se integra el servicio ligero de supervisión autoheal:
autoheal:
image: willfarrell/autoheal:latest
restart: unless-stopped
environment:
- AUTOHEAL_CONTAINER_LABEL=all
- AUTOHEAL_INTERVAL=10
- AUTOHEAL_START_PERIOD=60
volumes:
- /var/run/docker.sock:/var/run/docker.sock
Procedimiento Automatizado de Respaldos Cifrados
En un entorno de jitsi meet en vps docker, la arquitectura separa el plano de medios sin estado (stateless media plane en JVB) del plano de estado de configuración y autenticación (stateful control plane). El respaldo debe capturar exclusivamente la configuración determinista, certificados y el almacenamiento local de Prosody (cuentas internas y salas persistentes).
Script de Respaldo: /usr/local/bin/jitsi-backup.sh
Este script genera un archivo tar comprimido con Zstandard, lo cifra simétricamente con GPG y lo almacena localmente antes de sincronizarlo a un bucket S3 o almacenamiento secundario mediante rclone:
#!/usr/bin/env bash
set -euo pipefail
BACKUP_DIR="/var/backups/jitsi"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
CONFIG_SRC="/root/.jitsi-meet-cfg"
ENV_SRC="/opt/jitsi-meet-docker/.env"
PASSPHRASE_FILE="/etc/jitsi-backup.key"
ARCHIVE_NAME="jitsi_backup_${TIMESTAMP}.tar.zst.gpg"
mkdir -p "${BACKUP_DIR}"
chmod 700 "${BACKUP_DIR}"
# Congelar temporalmente escrituras en Prosody mediante checkpoint de configuración
tar -C / -cf - "${CONFIG_SRC#/}" "${ENV_SRC#/}" 2>/dev/null \
| zstd -T0 -3 \
| gpg --batch --yes --passphrase-file "${PASSPHRASE_FILE}" --symmetric --cipher-algo AES256 -o "${BACKUP_DIR}/${ARCHIVE_NAME}"
# Generar checksum SHA256 para validación de integridad
sha256sum "${BACKUP_DIR}/${ARCHIVE_NAME}" > "${BACKUP_DIR}/${ARCHIVE_NAME}.sha256"
# Sincronización a almacenamiento externo off-site (rclone / S3)
rclone copy "${BACKUP_DIR}/${ARCHIVE_NAME}" remote-backup:jitsi-dr/ --transfers=4
rclone copy "${BACKUP_DIR}/${ARCHIVE_NAME}.sha256" remote-backup:jitsi-dr/
# Rotación local: conservar últimos 7 días
find "${BACKUP_DIR}" -name "jitsi_backup_*.tar.zst.gpg*" -mtime +7 -delete
Automatice la ejecución diaria en cron del sistema (/etc/cron.d/jitsi-backup):
0 3 * * * root /usr/local/bin/jitsi-backup.sh > /var/log/jitsi-backup.log 2>&1
Runbook de Recuperación ante Desastres (Disaster Recovery)
Ante una pérdida total de la instancia de cómputo por fallo de hardware o compromiso de seguridad, el objetivo de tiempo de recuperación (RTO) debe ser inferior a 10 minutos con un objetivo de punto de recuperación (RPO) de 24 horas.
Paso 1: Provisión de la Nueva Instancia Base
Despliegue un nuevo nodo KVM limpio con Ubuntu 24.04 LTS en tropic.host, asegurando un procesador de alta frecuencia (AMD EPYC o Ryzen 9) y almacenamiento NVMe PCIe 4.0 para garantizar más de 50.000 IOPS en lectura aleatoria 4K QD1. Asigne una dirección IPv4 dedicada limpia.
Configure de inmediato las reglas de kernel en /etc/sysctl.d/99-jitsi.conf:
net.core.rmem_max = 67108864
net.core.wmem_max = 67108864
net.core.rmem_default = 33554432
net.core.wmem_default = 33554432
net.core.netdev_max_backlog = 100000
net.ipv4.udp_rmem_min = 16384
net.ipv4.udp_wmem_min = 16384
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
Aplique los cambios:
sysctl --system
Paso 2: Instalación del Motor de Contenedores y Estructura
apt-get update && apt-get install -y curl gnupg zstd jq rclone
curl -fsSL https://get.docker.com | bash
systemctl enable --now docker
mkdir -p /opt/jitsi-meet-docker
cd /opt/jitsi-meet-docker
git clone https://github.com/jitsi/docker-jitsi-meet.git .
git checkout tags/$(curl -s https://api.github.com/repos/jitsi/docker-jitsi-meet/releases/latest | jq -r .tag_name)
Paso 3: Descarga, Validación y Descifrado del Respaldo
Recupere el archivo de respaldo más reciente y su checksum desde el almacenamiento remoto:
# Descargar último archivo
rclone copy remote-backup:jitsi-dr/ /var/backups/jitsi/ --include "jitsi_backup_*.tar.zst.gpg*"
cd /var/backups/jitsi/
LATEST_BACKUP=$(ls -t jitsi_backup_*.tar.zst.gpg | head -n1)
# Validar integridad SHA256 antes de procesar
sha256sum -c "${LATEST_BACKUP}.sha256"
# Descifrar y restaurar en raíz
gpg --batch --yes --passphrase-file /etc/jitsi-backup.key --decrypt "${LATEST_BACKUP}" \
| zstd -d \
| tar -C / -xvf -
Paso 4: Reconciliación de Red y Levantamiento de Servicios
Si la nueva instancia posee una IP pública diferente a la original, actualice la variable DOCKER_HOST_ADDRESS en /opt/jitsi-meet-docker/.env con la nueva IP antes de iniciar los contenedores:
NEW_IPV4=$(curl -4 -s https://ifconfig.me)
sed -i "s/^DOCKER_HOST_ADDRESS=.*/DOCKER_HOST_ADDRESS=${NEW_IPV4}/" /opt/jitsi-meet-docker/.env
# Si los registros DNS no han propagado la nueva IP, actualice el registro A en su proveedor DNS.
Inicie el stack completo de Docker:
cd /opt/jitsi-meet-docker
docker compose up -d
Paso 5: Verificación de Integridad Funcional del DR
Ejecute la secuencia de validación técnica para certificar la operatividad del stack:
# 1. Comprobar que los puertos críticos están escuchando
ss -tulpn | grep -E "(:80|:443|:10000)"
# 2. Verificar que Prosody ha autenticado los componentes de Jicofo y JVB
docker logs docker-jitsi-meet-prosody-1 2>&1 | grep -E "authenticated as|connected"
# 3. Comprobar la respuesta de salud de JVB
curl -s http://localhost:8080/about/health
La respuesta del comando curl debe devolver un código de estado HTTP 200 con cuerpo vacío o status OK. En este punto, el plano de medios y señalización queda 100% restaurado y operativo, completando el ciclo de recuperación ante desastres sin inconsistencias de estado.
Preguntas frecuentes (FAQ)
¿Cuántos recursos necesita Jitsi Meet en un VPS?
Para reuniones de 10 a 20 personas simultáneas, se recomienda un VPS KVM con 4 vCPU, 8 GB de RAM y un puerto de red de 1 Gbps con tráfico simétrico.
¿Por qué es crucial la baja latencia para Jitsi Meet?
El tráfico WebRTC de audio y video es sensible al jitter y la pérdida de paquetes. Servidores en centros de datos con enlaces BBR garantizan una latencia p99 inferior a 25 ms.