--- title: "Servidor de streaming con Nginx RTMP y HLS en Ubuntu 24.04" description: "Monta un servidor de streaming en Ubuntu 24.04 con Nginx y el módulo RTMP: recibe emisiones de OBS con clave, sírvelas en HLS al navegador y retransmítelas." category: "Casos de Uso" language: es source: https://cubepath.com/es/docs/casos-de-uso/servidor-de-streaming-con-nginx-rtmp updated: 2026-09-25 --- # Servidor de streaming con Nginx RTMP y HLS en Ubuntu 24.04 El módulo RTMP de Nginx convierte un servidor web en un servidor de streaming: recibe la emisión de un programa como OBS Studio por el protocolo RTMP y la reparte a los espectadores, ya sea por RTMP o en formato HLS, que se reproduce en cualquier navegador. En este tutorial instalarás Nginx con el módulo RTMP en Ubuntu 24.04, protegerás la emisión con una clave, publicarás el directo en HLS con un reproductor web, y opcionalmente lo grabarás y lo retransmitirás a YouTube o Twitch. ## Requisitos previos - Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath. Para reenviar el vídeo sin transcodificar bastan 2 vCPUs y 2 GB de RAM; lo que más importa es el ancho de banda de salida. - Un usuario no root con privilegios `sudo`. - OBS Studio (u otro software compatible con RTMP) en tu ordenador para emitir. - Opcional: un dominio con un registro A apuntando a la IP del servidor, si quieres servir el directo por HTTPS. Calcula el ancho de banda: cada espectador consume aproximadamente el bitrate de la emisión. Con 3 Mbit/s y 100 espectadores simultáneos necesitas unos 300 Mbit/s de salida. ## Paso 1: Instalar Nginx y el módulo RTMP Ubuntu empaqueta el módulo RTMP como módulo dinámico de Nginx, así que no hace falta compilar nada. Instala ambos, junto con FFmpeg, que usarás para enviar una emisión de prueba: ```bash sudo apt update sudo apt install nginx libnginx-mod-rtmp ffmpeg ``` El paquete activa el módulo automáticamente. Compruébalo: ```bash ls /etc/nginx/modules-enabled/ | grep rtmp ``` ```output 50-mod-rtmp.conf ``` ## Paso 2: Crear los directorios de trabajo El módulo escribe los fragmentos HLS en disco y Nginx los sirve por HTTP. Los procesos de Nginx en Ubuntu se ejecutan como `www-data`, así que ese usuario necesita permiso de escritura: ```bash sudo mkdir -p /var/www/stream/hls sudo chown -R www-data:www-data /var/www/stream ``` ## Paso 3: Configurar el servidor RTMP La configuración RTMP no va dentro del bloque `http`, sino en un bloque `rtmp` propio en el nivel superior de la configuración. Créala en un archivo aparte: ```bash sudo nano /etc/nginx/rtmp.conf ``` ```nginx rtmp { server { listen 1935; chunk_size 4096; notify_method get; application live { live on; record off; # Comprobar la clave de emisión antes de aceptar la publicación on_publish http://127.0.0.1:8080/auth; # Los espectadores ven el directo por HLS, no por RTMP allow play 127.0.0.1; deny play all; hls on; hls_path /var/www/stream/hls; hls_fragment 3s; hls_playlist_length 60s; } } } ``` Qué hace cada directiva: - `listen 1935`: puerto estándar de RTMP. - `application live`: define la aplicación a la que se emite. La URL de emisión será `rtmp://your_server_ip/live`. - `on_publish`: antes de aceptar una emisión, Nginx hace una petición HTTP a esa URL. Si responde con un código 2xx, la emisión se acepta; si no, se rechaza. `notify_method get` hace que la petición sea GET, para poder leer sus parámetros desde Nginx. - `hls_fragment` y `hls_playlist_length`: duración de cada fragmento y del historial de la lista de reproducción. Fragmentos más cortos reducen el retraso, pero exigen más peticiones a los espectadores. Añade el archivo al final de `/etc/nginx/nginx.conf`, fuera del bloque `http`: ```bash echo 'include /etc/nginx/rtmp.conf;' | sudo tee -a /etc/nginx/nginx.conf ``` ## Paso 4: Configurar la entrega HLS y la clave de emisión Ahora configura la parte HTTP. Necesitas dos bloques `server`: uno público en el puerto 80 que sirve los fragmentos HLS y el reproductor, y otro que solo escucha en `127.0.0.1:8080` con la comprobación de la clave y la página de estadísticas, inaccesible desde fuera. Elige una clave de emisión larga y aleatoria: ```bash openssl rand -hex 16 ``` ```output 3f9c1e7a52b84d06a1c9e2f7b3d58a40 ``` Crea el sitio: ```bash sudo nano /etc/nginx/sites-available/stream ``` ```nginx server { listen 80 default_server; listen [::]:80 default_server; server_name your_domain; root /var/www/stream; index index.html; location /hls/ { types { application/vnd.apple.mpegurl m3u8; video/mp2t ts; } add_header Cache-Control no-cache; add_header Access-Control-Allow-Origin *; } } server { listen 127.0.0.1:8080; location = /auth { if ($arg_key = "your_stream_key") { return 200; } return 403; } location = /stat { rtmp_stat all; } } ``` Sustituye `your_stream_key` por la clave que generaste y `your_domain` por tu dominio (o por la IP del servidor si no tienes dominio). Con `notify_method get`, los parámetros que añada el emisor a la URL (`?key=...`) llegan a `/auth` y Nginx los lee en `$arg_key`. Desactiva el sitio por defecto, activa el nuevo y comprueba la sintaxis: ```bash sudo rm /etc/nginx/sites-enabled/default sudo ln -s /etc/nginx/sites-available/stream /etc/nginx/sites-enabled/stream sudo nginx -t ``` ```output nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful ``` Recarga Nginx y comprueba que escucha en los puertos 1935, 80 y 8080: ```bash sudo systemctl reload nginx sudo ss -tlnp | grep nginx ``` ```output LISTEN 0 511 127.0.0.1:8080 0.0.0.0:* users:(("nginx",pid=4122,fd=8),...) LISTEN 0 511 0.0.0.0:1935 0.0.0.0:* users:(("nginx",pid=4122,fd=6),...) LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=4122,fd=7),...) LISTEN 0 511 [::]:80 [::]:* users:(("nginx",pid=4122,fd=9),...) ``` ## Paso 5: Abrir los puertos en el firewall Abre el puerto RTMP para recibir emisiones y el HTTP para los espectadores. Permite SSH antes de activar UFW para no perder el acceso: ```bash sudo ufw allow OpenSSH sudo ufw allow 1935/tcp sudo ufw allow 'Nginx HTTP' sudo ufw enable ``` Si siempre emites desde la misma IP fija, puedes limitar el puerto RTMP a ella con `sudo ufw allow from your_home_ip to any port 1935 proto tcp` en lugar de abrirlo a todo el mundo. ## Paso 6: Probar con una emisión generada por FFmpeg Antes de configurar OBS, comprueba que todo funciona con una emisión de prueba generada en el propio servidor: una carta de ajuste en movimiento con un tono de audio. Sustituye `your_stream_key` por tu clave: ```bash ffmpeg -re \ -f lavfi -i testsrc2=size=1280x720:rate=30 \ -f lavfi -i sine=frequency=1000:sample_rate=48000 \ -c:v libx264 -preset veryfast -b:v 2500k -g 60 -pix_fmt yuv420p \ -c:a aac -b:a 128k \ -f flv "rtmp://127.0.0.1/live/stream?key=your_stream_key" ``` `-g 60` fuerza un fotograma clave cada 2 segundos (a 30 fps), necesario para que los fragmentos HLS se corten con regularidad. Deja el comando en marcha y, en otra terminal, comprueba que se generan los fragmentos: ```bash ls /var/www/stream/hls/ ``` ```output stream-0.ts stream-1.ts stream-2.ts stream.m3u8 ``` El nombre de los archivos es el nombre del stream (`stream`); la clave no forma parte de él y nunca aparece en la URL de los espectadores. Consulta la lista de reproducción por HTTP: ```bash curl http://127.0.0.1/hls/stream.m3u8 ``` ```output #EXTM3U #EXT-X-VERSION:3 #EXT-X-MEDIA-SEQUENCE:0 #EXT-X-TARGETDURATION:4 #EXTINF:4.000, stream-0.ts #EXTINF:4.000, stream-1.ts ``` Comprueba también que la clave funciona: repite el comando `ffmpeg` con una clave incorrecta. La conexión se rechazará y en `/var/log/nginx/error.log` verás que la notificación `on_publish` ha devuelto un error. Detén FFmpeg con `Ctrl+C`. ## Paso 7: Añadir un reproductor web Los navegadores basados en Chromium y Firefox no reproducen HLS de forma nativa, así que el reproductor usa la librería hls.js (Safari lo reproduce directamente). Crea la página: ```bash sudo nano /var/www/stream/index.html ``` ```html Directo ``` Ajusta los permisos: ```bash sudo chown www-data:www-data /var/www/stream/index.html ``` Vuelve a lanzar la emisión de prueba del paso 6 y abre `http://your_server_ip/` en el navegador. Deberías ver la carta de ajuste con un retraso de 10 a 20 segundos, lo normal en HLS. ## Paso 8: Emitir desde OBS Studio En OBS, ve a **Ajustes > Emisión** y configura: | Campo | Valor | |-------|-------| | Servicio | Personalizado | | Servidor | `rtmp://your_server_ip/live` | | Clave de retransmisión | `stream?key=your_stream_key` | En **Ajustes > Salida**, con el modo de salida en **Avanzado**, fija el **Intervalo de fotogramas clave** en 2 segundos y un bitrate de vídeo acorde a tu conexión de subida (por ejemplo, 2500-4500 kbps para 720p o 1080p a 30 fps). Pulsa **Iniciar transmisión** y abre `http://your_server_ip/` para ver el directo. Para ver qué emisiones están activas y cuántos clientes tienen, consulta las estadísticas desde el servidor: ```bash curl -s http://127.0.0.1:8080/stat | grep -E '|' ``` ```output live stream 1 ``` ## Paso 9 (opcional): Retransmitir a YouTube o Twitch Nginx puede reenviar la emisión que recibe a otras plataformas, de modo que desde OBS emites una sola vez y el servidor la reparte. Añade una directiva `push` por destino dentro de `application live`, en `/etc/nginx/rtmp.conf`: ```nginx application live { # ... configuración anterior ... push rtmp://a.rtmp.youtube.com/live2/your_youtube_key; push rtmp://live.twitch.tv/app/your_twitch_key; } ``` Las claves son las que te da cada plataforma en su panel de emisión. Comprueba la configuración y recarga: ```bash sudo nginx -t && sudo systemctl reload nginx ``` La retransmisión solo reenvía el vídeo, sin transcodificar, así que la emisión de OBS debe cumplir los requisitos de cada plataforma (H.264, AAC, fotograma clave cada 2 segundos). ## Paso 10 (opcional): Grabar las emisiones Para guardar cada emisión en disco, crea un directorio de grabaciones: ```bash sudo mkdir -p /var/www/recordings sudo chown www-data:www-data /var/www/recordings ``` Y en `application live`, sustituye `record off;` por: ```nginx record all; record_path /var/www/recordings; record_unique on; ``` `record_unique on` añade la fecha al nombre del archivo para no sobrescribir grabaciones anteriores. Tras recargar Nginx, cada emisión se guarda en formato FLV. Para convertirla a MP4 sin recodificar: ```bash ffmpeg -i /var/www/recordings/stream-1758795600.flv -c copy stream.mp4 ``` Las grabaciones ocupan aproximadamente el bitrate por la duración (unos 1,3 GB por hora a 3 Mbit/s), así que vigila el espacio en disco con `df -h`. ## Solución de problemas **OBS muestra "No se pudo conectar al servidor"**: comprueba que el puerto 1935 está abierto (`sudo ufw status`) y que Nginx escucha en él (`sudo ss -tlnp | grep 1935`). Si ambos están bien, revisa la clave: una clave incorrecta también cierra la conexión. **`nginx: [emerg] unknown directive "rtmp"`**: el módulo no está cargado. Comprueba que existe `/etc/nginx/modules-enabled/50-mod-rtmp.conf` y que la línea `include /etc/nginx/rtmp.conf;` está al final de `nginx.conf` y no dentro del bloque `http`. **No aparecen archivos en `/var/www/stream/hls`**: busca errores de permisos con `sudo tail -n 50 /var/log/nginx/error.log` y comprueba que el directorio pertenece a `www-data`. **El vídeo se corta o se congela en el navegador**: suele deberse a un intervalo de fotogramas clave distinto de 2 segundos o a un bitrate superior a la subida de tu conexión. Revisa las estadísticas de OBS (fotogramas perdidos por red). ## Conclusión Tienes un servidor de streaming con Nginx que recibe emisiones RTMP protegidas con clave, las publica en HLS con un reproductor web y puede retransmitirlas a otras plataformas y grabarlas. Como siguientes pasos, protege el reproductor con HTTPS usando Certbot (`sudo apt install certbot python3-certbot-nginx`), transcodifica la emisión a varias calidades con FFmpeg para adaptarte a espectadores con conexiones lentas, o coloca una CDN delante de `/hls/` si esperas muchos espectadores simultáneos.