#!/usr/bin/env bash set -euo pipefail # Run from a committed, published release checkout on an x86_64 Ubuntu host. # VISION_BIND is a comma-separated list of explicit private/Tailscale IPv4s. # MEDIA_ARCHIVE optionally points to an already downloaded pinned release archive. [[ $(id -u) == 0 ]] || { echo 'Run as root'; exit 1; } [[ $(uname -m) == x86_64 ]] || { echo 'This installer targets x86_64'; exit 1; } command -v python3 >/dev/null if ! command -v ffmpeg >/dev/null; then apt-get update DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends ffmpeg fi if [[ -f /sys/class/drm/renderD128/device/vendor ]] && [[ $(cat /sys/class/drm/renderD128/device/vendor) == 0x8086 ]]; then if ! dpkg-query -W -f='${Status}' intel-media-va-driver-non-free 2>/dev/null | grep -q 'install ok installed'; then apt-get update DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends intel-media-va-driver-non-free fi fi release_dir=$(cd -- "$(dirname -- "$0")/.." && pwd) bind_address=${VISION_BIND:-127.0.0.1} python3 - "$bind_address" <<'PY' import ipaddress,sys for value in sys.argv[1].split(','): ip=ipaddress.ip_address(value.strip()) assert ip.version==4 and not ip.is_unspecified and not ip.is_multicast and (ip.is_private or ip in ipaddress.ip_network('100.64.0.0/10')), 'Use explicit private or Tailscale addresses' PY getent passwd zhaovision >/dev/null || useradd --system --home-dir /var/lib/zhaovision --shell /usr/sbin/nologin zhaovision if getent group render >/dev/null; then usermod -a -G render zhaovision fi install -d -o zhaovision -g zhaovision -m 700 /var/lib/zhaovision /var/lib/zhaovision/recordings install -d -m 755 /opt/zhaovision /usr/local/lib/zhaovision archive=${MEDIA_ARCHIVE:-/tmp/mediamtx_v1.21.1_linux_amd64.tar.gz} if [[ ! -f "$archive" ]]; then curl -fL --retry 3 'https://github.com/bluenviron/mediamtx/releases/download/v1.21.1/mediamtx_v1.21.1_linux_amd64.tar.gz' -o "$archive" fi python3 - "$archive" <<'PY' import hashlib,sys expected='653abc672a3e693f8d3b2717752492fdcfb8072291ec108d03d3dd857411b0ee' assert hashlib.file_digest(open(sys.argv[1],'rb'),'sha256').hexdigest()==expected, 'MediaMTX checksum mismatch' PY tar -xzf "$archive" -C /usr/local/lib/zhaovision mediamtx LICENSE chmod 755 /usr/local/lib/zhaovision/mediamtx if [[ -e /opt/zhaovision/current && ! -L /opt/zhaovision/current ]]; then echo '/opt/zhaovision/current is not a symlink; refusing to replace it'; exit 1 fi ln -sfn "$release_dir" /opt/zhaovision/current if [[ ! -f /etc/zhaovision.env ]]; then umask 077 printf 'VISION_BIND=%s\nVISION_PORT=8790\nVISION_DATA=/var/lib/zhaovision\nVISION_RECORDINGS=/var/lib/zhaovision/recordings\n' "$bind_address" > /etc/zhaovision.env fi install -m 644 "$release_dir/deploy/zhaovision.service" /etc/systemd/system/zhaovision.service install -m 644 "$release_dir/deploy/zhaovision-media.service" /etc/systemd/system/zhaovision-media.service systemctl daemon-reload systemctl enable zhaovision.service zhaovision-media.service systemctl restart zhaovision.service for attempt in {1..20}; do [[ -s /var/lib/zhaovision/mediamtx.yml ]] && break sleep 1 done systemctl restart zhaovision-media.service echo 'Services started. Initial setup code: /var/lib/zhaovision/setup-code.txt' echo "Tailscale entry: http://${bind_address}:8790/"