Skip to main content

FFmpeg + NGINX HTTPS HLS Streaming Server Ubuntu 24.04

๐Ÿงฉ Step 1 โ€” Update and install dependencies

sudo apt update
sudo apt install -y ffmpeg nginx python3-yaml openssl

๐Ÿ—‚๏ธ Step 2 โ€” Directory setup

sudo mkdir -p /usr/local/ffmpeg-hls
sudo mkdir -p /var/www/html/cctv
sudo chown -R www-data:www-data /var/www/html

๐Ÿงพ Step 3 โ€” Camera configuration file
Create file /usr/local/ffmpeg-hls/cams.yml

- name: cam1
  url: rtsp-url-here
- name: cam2
  url: rtsp-url-here
- name: cam3
  url: rtsp-url-here
# Add up to cam16 if needed...

โš™๏ธ Step 4 โ€” Auto FFmpeg launcher script
Create file /usr/local/ffmpeg-hls/start-all-cams.sh

#!/bin/bash
CONFIG_FILE="/usr/local/ffmpeg-hls/cams.yml"
OUTPUT_ROOT="/var/www/html/cctv"
HLS_DURATION=10            # seconds per segment
TOTAL_HISTORY_MIN=10       # total minutes to keep
SEGMENTS_TO_KEEP=$(( (TOTAL_HISTORY_MIN*60) / HLS_DURATION ))

mkdir -p "$OUTPUT_ROOT"

# 1๏ธโƒฃ Generate#Generate list of active cams
python3 - <<'PYCODE' > /tmp/camlist.txt
import yaml, sys
data = yaml.safe_load(open("/usr/local/ffmpeg-hls/cams.yml"))
for cam in data:
    print(f"{cam['name']}|{cam['url']}")
PYCODE

# 2๏ธโƒฃ Build#Build array of active cam names
ACTIVE_CAMS=($(awk -F'|' '{print $1}' /tmp/camlist.txt))

# 3๏ธโƒฃ Clean#Clean up old folders not in YAML
for dir in "$OUTPUT_ROOT"/*/; do
  [ -d "$dir" ] || continue
  CAM_NAME=$(basename "$dir")
  if [[ ! " ${ACTIVE_CAMS[@]} " =~ " ${CAM_NAME} " ]]; then
    echo "๐Ÿงน Removing old folder: $dir"
    rm -rf "$dir"
  fi
done

# 4๏ธโƒฃ Start#Start each active camera
while IFS="|" read -r NAME URL; do
    [ -z "$NAME" ] && continue
    mkdir -p "$OUTPUT_ROOT/$NAME"

    echo "๐ŸŽฅ Starting $NAME ..."
    (
      while true; do
        ffmpeg -hide_banner -loglevel warning \
          -rtsp_transport tcp \
          -i "$URL" \
          -fflags +genpts -use_wallclock_as_timestamps 1 \
          -an -c:v copy \
          -f hls \
          -hls_time $HLS_DURATION \
          -hls_list_size $SEGMENTS_TO_KEEP \
          -hls_flags delete_segments+append_list+program_date_time \
          -hls_segment_filename "$OUTPUT_ROOT/$NAME/segment_%05d.ts" \
          "$OUTPUT_ROOT/$NAME/index.m3u8"

        echo "โš ๏ธ  $NAME disconnected, retrying in 5s..."
        sleep 5
      done
    ) &
done < /tmp/camlist.txt

echo "โœ… All active camera streams started!"
wait

Make it executable:

sudo chmod +x /usr/local/ffmpeg-hls/start-all-cams.sh

๐Ÿ” Step 5 โ€” Systemd service
Create file /etc/systemd/system/cctv-hls.service

[Unit]
Description=FFmpeg HLS Auto Streams (All Cameras)
After=network-online.target
Wants=network-online.target

[Service]
ExecStart=/usr/local/ffmpeg-hls/start-all-cams.sh
Restart=always
RestartSec=10
LimitNOFILE=65535

[Install]
WantedBy=multi-user.target

โš™๏ธ Apply changes

sudo nano /usr/local/ffmpeg-hls/start-all-cams.sh
# (paste script above)
sudo chmod +x /usr/local/ffmpeg-hls/start-all-cams.sh
sudo systemctl restart cctv-hls

๐Ÿ”’ Step 6 โ€” HTTPS setup with NGINX (self-signed)
Generate SSL certificate:

sudo mkdir -p /etc/ssl/cctv
sudo openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
  -keyout /etc/ssl/cctv/cctv.key \
  -out /etc/ssl/cctv/cctv.crt \
  -subj "/CN=cctv.local"

Configure NGINX site:
Create file /etc/nginx/sites-available/cctv

server {
    listen 443 ssl;
    server_name _;

    ssl_certificate     /etc/ssl/cctv/cctv.crt;
    ssl_certificate_key /etc/ssl/cctv/cctv.key;

    root /var/www/html;
    index index.html;

    location /cctv/ {
        add_header Cache-Control no-cache;
        types {
            application/vnd.apple.mpegurl m3u8;
            video/mp2t ts;
        }
        autoindex on;
        add_header Access-Control-Allow-Origin *;
    }
}

server {
    listen 80;
    server_name _;
    return 301 https://$host$request_uri;
}

Enable and reload:

sudo ln -s /etc/nginx/sites-available/cctv /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default
sudo systemctl restart nginx

โœ… Step 7 โ€” Verify everything

sudo systemctl status cctv-hls

Then visit:

https://<server-ip>/cctv/cam1/index.m3u8
https://<server-ip>/cctv/cam2/index.m3u8
https://<server-ip>/cctv/cam3/index.m3u8