#cloud-config # Nodo stream Hetzner: MediaMTX + ffmpeg + relay-agent (YouTube sul nodo). # HCLOUD_USER_DATA_FILE=.../infra/stream-node/cloud-init.yaml package_update: true packages: - docker.io - ffmpeg - curl - apparmor - python3 - fonts-dejavu-core write_files: - path: /opt/stream-node/mediamtx.yml permissions: "0644" content: | logLevel: info authInternalUsers: - user: any pass: ips: [] permissions: - action: api - action: metrics - action: publish - action: read - action: playback api: yes apiAddress: :9997 rtmp: yes rtmpAddress: :1935 hls: yes hlsAddress: :8888 paths: all_others: - path: /opt/stream-node/relay-agent.service permissions: "0644" content: | [Unit] Description=Match Live TV YouTube relay agent After=network-online.target docker.service Wants=network-online.target [Service] Type=simple EnvironmentFile=-/opt/stream-node/agent.env ExecStart=/usr/bin/python3 /opt/stream-node/relay-agent.py Restart=always RestartSec=2 [Install] WantedBy=multi-user.target - path: /opt/stream-node/agent.env permissions: "0600" content: | STREAM_NODE_AGENT_SECRET=mediamtx_webhook_dev_secret STREAM_NODE_AGENT_LISTEN=0.0.0.0:9100 STREAM_NODE_LOCAL_HLS_URL=http://127.0.0.1:8888 STREAM_NODE_RELAY_LOG_DIR=/var/log - path: /opt/stream-node/bootstrap.sh permissions: "0755" content: | #!/bin/bash set -euo pipefail mkdir -p /recordings /slates /var/log systemctl enable --now docker for i in $(seq 1 60); do if docker info >/dev/null 2>&1; then break; fi sleep 2 done docker pull bluenviron/mediamtx:latest docker rm -f mediamtx 2>/dev/null || true FONT=/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf # Copertina alwaysAvailable (NON nera): resta in HLS/YouTube se l'app cade. ffmpeg -y -f lavfi -i color=c=0x0a0a0e:s=1280x720:r=30:d=30 \ -f lavfi -i anullsrc=r=48000:cl=mono \ -vf "drawtext=fontfile=${FONT}:text='Match Live TV':fontsize=64:fontcolor=white:x=(w-text_w)/2:y=(h-text_h)/2-48,drawtext=fontfile=${FONT}:text='Trasmissione in pausa':fontsize=36:fontcolor=white:x=(w-text_w)/2:y=(h-text_h)/2+36" \ -c:v libx264 -pix_fmt yuv420p -profile:v baseline -level 3.1 \ -x264-params "keyint=30:min-keyint=30:scenecut=0:bframes=0" \ -g 30 -keyint_min 30 -preset fast \ -c:a aac -b:a 128k -ac 1 -ar 48000 -shortest /slates/offline.mp4 docker run -d --name mediamtx --restart unless-stopped --network host \ --security-opt apparmor=unconfined \ -v /opt/stream-node/mediamtx.yml:/mediamtx.yml:ro \ -v /recordings:/recordings \ -v /slates:/slates:ro \ bluenviron/mediamtx:latest /mediamtx.yml if [[ -f /opt/stream-node/relay-agent.py ]]; then cp /opt/stream-node/relay-agent.service /etc/systemd/system/mltv-relay-agent.service systemctl daemon-reload systemctl enable --now mltv-relay-agent.service fi for i in $(seq 1 30); do if curl -fsS http://127.0.0.1:9997/v3/paths/list >/dev/null; then echo "mediamtx ready" | tee /opt/stream-node/ready exit 0 fi sleep 2 done echo "mediamtx NOT ready" | tee /opt/stream-node/ready docker logs mediamtx || true exit 1 runcmd: - [bash, /opt/stream-node/bootstrap.sh]