NextNVR/deploy_nvr.sh

210 lines
6.6 KiB
Bash
Executable file

#!/bin/bash
# NextNVR — Deploy & Update Script
# Usage: curl -sSLO https://git.lohmar.co.uk/cclohmar/NextNVR/raw/branch/main/deploy_nvr.sh
# chmod +x deploy_nvr.sh && ./deploy_nvr.sh
#
# Greenfield: clones repo, prompts for storage, builds config, installs service.
# Update: kills old instance, pulls latest, rebuilds, restarts (config preserved).
set -e
GIT_URL="https://git.lohmar.co.uk/cclohmar/NextNVR.git"
DEPLOY_DIR="/opt/nextnvr"
SERVICE_NAME="nextnvr"
GO_VERSION="1.24.5"
GO_ARCH="amd64"
GO2RTC_VER="1.9.14"
[ "$(uname -m)" = "aarch64" ] && GO_ARCH="arm64"
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'
log() { echo -e "${GREEN}[NextNVR]${NC} $1"; }
warn() { echo -e "${YELLOW}[NextNVR]${NC} $1"; }
err() { echo -e "${RED}[NextNVR]${NC} $1"; }
info() { echo -e "${CYAN}[NextNVR]${NC} $1"; }
echo ""
echo "============================================"
echo " NextNVR — Deploy / Update"
echo " $(uname -m) / $(uname -s)"
echo "============================================"
echo ""
# ── 0. Check sudo ──
if ! command -v sudo &>/dev/null; then
if [ "$(id -u)" -eq 0 ]; then
sudo() { "$@"; }
else
err "sudo is required. Install it first or run as root."
exit 1
fi
fi
# ── 1. Stop all existing instances ──
log "Stopping any running NextNVR instances..."
# Graceful stop via systemd first.
if systemctl is-active --quiet "${SERVICE_NAME}" 2>/dev/null; then
sudo systemctl stop "${SERVICE_NAME}" 2>/dev/null || true
sleep 2
fi
# Kill any remaining processes by PID (targeted, no wildcard pkill).
for proc in "/opt/nextnvr/nextnvr" "go2rtc"; do
for pid in $(pgrep -f "${proc}" 2>/dev/null || true); do
sudo kill "${pid}" 2>/dev/null || true
done
done
sleep 2
# Final check — force kill stragglers.
for pid in $(pgrep -f "/opt/nextnvr/nextnvr" 2>/dev/null || true); do
sudo kill -9 "${pid}" 2>/dev/null || true
done
sleep 1
log "All instances stopped."
# ── 2. Detect greenfield vs update ──
GREENFIELD=false
if [ ! -d "${DEPLOY_DIR}" ]; then
GREENFIELD=true
log "Greenfield deployment detected."
else
log "Existing installation detected — update mode (config preserved)."
fi
# ── 3. System dependencies ──
detect_pkg_manager() {
if command -v apt-get &>/dev/null; then PKG="sudo apt-get install -y -qq"; DISTRO="debian"
elif command -v dnf &>/dev/null; then PKG="sudo dnf install -y -q"; DISTRO="fedora"
elif command -v yum &>/dev/null; then PKG="sudo yum install -y -q"; DISTRO="rhel"
elif command -v pacman &>/dev/null; then PKG="sudo pacman -S --noconfirm --needed"; DISTRO="arch"
elif command -v apk &>/dev/null; then PKG="sudo apk add --no-cache"; DISTRO="alpine"
else err "Unsupported distro."; exit 1; fi
log "Detected: ${DISTRO}"
}
detect_pkg_manager
if ! command -v ffmpeg &>/dev/null; then
info "Installing ffmpeg..."; eval "${PKG} ffmpeg"; log "ffmpeg installed."
fi
if ! command -v git &>/dev/null; then
info "Installing git..."; eval "${PKG} git"
fi
if ! command -v curl &>/dev/null; then
info "Installing curl..."; eval "${PKG} curl"
fi
if ! command -v jq &>/dev/null; then
info "Installing jq..."; eval "${PKG} jq"
fi
# ── 4. Time sync ──
if command -v timedatectl &>/dev/null; then
sudo timedatectl set-ntp true 2>/dev/null || true
fi
log "Time sync: OK | $(date)"
# ── 5. Go ──
GO_TAR="go${GO_VERSION}.linux-${GO_ARCH}.tar.gz"
GO_HOME="$HOME/.local/go"
if [ ! -f "${GO_HOME}/bin/go" ]; then
info "Installing Go ${GO_VERSION}..."
curl -sSL "https://go.dev/dl/${GO_TAR}" -o /tmp/${GO_TAR}
mkdir -p "${GO_HOME}"
tar -C "$HOME/.local" -xzf /tmp/${GO_TAR}
rm /tmp/${GO_TAR}
fi
export PATH="${GO_HOME}/bin:$PATH"
export GOPATH="$HOME/go"
log "Go: $(${GO_HOME}/bin/go version)"
# ── 6. Clone / pull ──
if $GREENFIELD; then
sudo mkdir -p "${DEPLOY_DIR}"
sudo chown "$(whoami):$(id -gn)" "${DEPLOY_DIR}"
git clone "${GIT_URL}" "${DEPLOY_DIR}"
log "Repository cloned."
else
git -C "${DEPLOY_DIR}" pull origin main
log "Repository updated."
fi
cd "${DEPLOY_DIR}"
# ── 7. go2rtc ──
GO2RTC_BIN="${DEPLOY_DIR}/go2rtc"
if [ ! -f "${GO2RTC_BIN}" ]; then
info "Downloading go2rtc ${GO2RTC_VER}..."
curl -sSL "https://github.com/AlexxIT/go2rtc/releases/download/v${GO2RTC_VER}/go2rtc_linux_${GO_ARCH}" -o "${GO2RTC_BIN}"
chmod +x "${GO2RTC_BIN}"
log "go2rtc installed."
fi
# ── 8. Configuration (greenfield only) ──
CONFIG_FILE="${DEPLOY_DIR}/config.json"
if $GREENFIELD; then
# Build config.json from sample with sensible defaults.
cp config.json.sample "${CONFIG_FILE}"
STORAGE_PATH=$(jq -r .storage.recordings_path "${CONFIG_FILE}")
sudo mkdir -p "${STORAGE_PATH}" 2>/dev/null || true
sudo chown "$(whoami):$(id -gn)" "${STORAGE_PATH}" 2>/dev/null || true
log "Config created: ${CONFIG_FILE}"
log "Storage: ${STORAGE_PATH} (change via web UI Settings)"
else
log "Config preserved: ${CONFIG_FILE}"
fi
# ── 9. Build ──
log "Building NextNVR..."
go mod tidy 2>/dev/null || true
VERSION=$(cat VERSION 2>/dev/null || echo "0.0.0")
BUILD_TIME=$(date -u +%Y-%m-%dT%H:%M:%SZ)
CGO_ENABLED=0 go build -ldflags="-s -w -X main.Version=${VERSION} -X main.BuildTime=${BUILD_TIME}" -o nextnvr .
chmod +x nextnvr
log "Binary: nextnvr v${VERSION} ($(du -h nextnvr | cut -f1))"
# ── 10. Systemd service ──
SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}.service"
sudo tee "${SERVICE_FILE}" > /dev/null <<EOF
[Unit]
Description=NextNVR — IP Camera Recorder
After=network.target
Wants=network.target
[Service]
Type=simple
User=$(whoami)
WorkingDirectory=${DEPLOY_DIR}
ExecStart=${DEPLOY_DIR}/nextnvr --config ${CONFIG_FILE}
Restart=always
RestartSec=10
LimitNOFILE=65536
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable "${SERVICE_NAME}"
sudo systemctl restart "${SERVICE_NAME}"
sleep 2
# ── Done ──
echo ""
echo "============================================"
echo -e " ${GREEN}NextNVR deployment complete!${NC}"
echo "============================================"
echo ""
info " Web UI: http://$(hostname -I 2>/dev/null | awk '{print $1}' || echo 'localhost'):8080"
info " Config: ${CONFIG_FILE}"
info " Storage: $(jq -r .storage.recordings_path ${CONFIG_FILE} 2>/dev/null || echo 'unknown')"
echo ""
echo " Service:"
echo " sudo systemctl status ${SERVICE_NAME}"
echo " sudo systemctl restart ${SERVICE_NAME}"
echo " sudo journalctl -u ${SERVICE_NAME} -f"
echo ""
sudo systemctl status "${SERVICE_NAME}" --no-pager --lines=5 2>/dev/null || true
echo ""