From d3ed1acc20bd4ef15889c16c69bf51730cd3d316 Mon Sep 17 00:00:00 2001 From: AZLyyds <2773638053@qq.com> Date: Mon, 10 Aug 2026 10:38:05 +0800 Subject: [PATCH 1/3] Add missing systemd unit template for the installer install.sh looks for packaging/fossilsafe.service and aborts if it is missing. Also create /mnt/fossilsafe paths up front so ProtectSystem=strict does not fail with NAMESPACE errors. Signed-off-by: AZLyyds <2773638053@qq.com> --- packaging/fossilsafe.service | 41 ++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 packaging/fossilsafe.service diff --git a/packaging/fossilsafe.service b/packaging/fossilsafe.service new file mode 100644 index 0000000..93eef70 --- /dev/null +++ b/packaging/fossilsafe.service @@ -0,0 +1,41 @@ +[Unit] +Description=FossilSafe LTO Backup Appliance +Documentation=https://fossilsafe.io +After=network-online.target +Wants=network-online.target + +[Service] +Type=simple +User={{SERVICE_USER}} +Group={{SERVICE_USER}} +SupplementaryGroups={{TAPE_GROUP}} +WorkingDirectory={{INSTALL_DIR}} +Environment=FOSSILSAFE_CONFIG_PATH={{CONFIG_PATH}} +Environment=FOSSILSAFE_DATA_DIR={{DATA_DIR}} +Environment=FOSSILSAFE_BACKEND_BIND={{BACKEND_BIND}} +Environment=FOSSILSAFE_BACKEND_PORT={{BACKEND_PORT}} +Environment=PYTHONUNBUFFERED=1 +# Create mount/data dirs before ProtectSystem=strict kicks in (+ = root) +ExecStartPre=+/bin/mkdir -p {{DATA_DIR}} /var/log/fossilsafe /mnt/fossilsafe/nfs /mnt/fossilsafe/smb /mnt/fossilsafe/external /mnt/ltfs +ExecStart={{VENV_DIR}}/bin/gunicorn -c {{INSTALL_DIR}}/gunicorn.conf.py backend.lto_backend_main:app +Restart=on-failure +RestartSec=5 +TimeoutStopSec=60 + +NoNewPrivileges=true +ProtectSystem=strict +ProtectHome=true +PrivateTmp=true +ProtectKernelTunables=true +ProtectKernelModules=true +ProtectControlGroups=true +RestrictSUIDSGID=true +LockPersonality=true +RestrictRealtime=true +ReadWritePaths={{DATA_DIR}} {{INSTALL_DIR}} /var/log/fossilsafe /mnt/fossilsafe /mnt/ltfs /etc/fossilsafe +DeviceAllow=/dev/fuse rw +DeviceAllow=char-scsi_generic rw +DeviceAllow=char-scsi_tape rw + +[Install] +WantedBy=multi-user.target From 6a697c3ec29407fde036d4f9115c32ec28f09d30 Mon Sep 17 00:00:00 2001 From: AZLyyds <2773638053@qq.com> Date: Mon, 10 Aug 2026 10:38:05 +0800 Subject: [PATCH 2/3] Fix installer package deps and file copy on Debian 13 Pull in npm, pick libfuse3-3 or libfuse3-4 from apt, and copy packaging/ plus fsafe-cli.py when using rsync. Point install-service.sh at the repo-root packaging template. Signed-off-by: AZLyyds <2773638053@qq.com> --- scripts/install.sh | 17 ++++++++++++++--- scripts/setup/install-service.sh | 13 +++++++++++-- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/scripts/install.sh b/scripts/install.sh index b6d646e..dde212a 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -2110,7 +2110,6 @@ SYSTEM_PACKAGES=( coreutils curl fuse3 - libfuse3-3 gzip lsscsi mt-st @@ -2124,6 +2123,7 @@ SYSTEM_PACKAGES=( tar util-linux nodejs + npm certbot python3-certbot-nginx ) @@ -2134,7 +2134,6 @@ if [[ "${HEADLESS}" -eq 1 ]]; then coreutils curl fuse3 - libfuse3-3 gzip lsscsi mt-st @@ -2149,6 +2148,15 @@ if [[ "${HEADLESS}" -eq 1 ]]; then ) fi +# Debian 12 ships libfuse3-3; Debian 13+ ships libfuse3-4. +if apt_package_available "libfuse3-4"; then + SYSTEM_PACKAGES+=(libfuse3-4) +elif apt_package_available "libfuse3-3"; then + SYSTEM_PACKAGES+=(libfuse3-3) +else + warn "No libfuse3 runtime package found in apt; FUSE/LTFS may not work." +fi + if [[ "${CHANGER_REQUIRED}" -eq 1 ]]; then SYSTEM_PACKAGES+=(mtx) fi @@ -2372,12 +2380,15 @@ step_header "[8/${STEP_TOTAL}] Installing FossilSafe files" \ if command -v rsync >/dev/null; then rsync -a --delete "${SOURCE_ROOT}/backend" "${INSTALL_DIR}/" rsync -a --delete "${SOURCE_ROOT}/frontend" "${INSTALL_DIR}/" + rsync -a --delete "${SOURCE_ROOT}/packaging" "${INSTALL_DIR}/" rsync -a "${SOURCE_ROOT}/gunicorn.conf.py" "${INSTALL_DIR}/gunicorn.conf.py" + rsync -a "${SOURCE_ROOT}/scripts/fossilsafe_cli.py" "${INSTALL_DIR}/fsafe-cli.py" rsync -a "${SOURCE_REQUIREMENTS}" "${INSTALL_DIR}/requirements.txt" else - rm -rf "${INSTALL_DIR}/backend" "${INSTALL_DIR}/frontend" + rm -rf "${INSTALL_DIR}/backend" "${INSTALL_DIR}/frontend" "${INSTALL_DIR}/packaging" cp -a "${SOURCE_ROOT}/backend" "${INSTALL_DIR}/backend" cp -a "${SOURCE_ROOT}/frontend" "${INSTALL_DIR}/frontend" + cp -a "${SOURCE_ROOT}/packaging" "${INSTALL_DIR}/packaging" cp -a "${SOURCE_ROOT}/gunicorn.conf.py" "${INSTALL_DIR}/gunicorn.conf.py" cp -a "${SOURCE_ROOT}/scripts/fossilsafe_cli.py" "${INSTALL_DIR}/fsafe-cli.py" cp -a "${SOURCE_REQUIREMENTS}" "${INSTALL_DIR}/requirements.txt" diff --git a/scripts/setup/install-service.sh b/scripts/setup/install-service.sh index 2bebb0e..5787bb6 100755 --- a/scripts/setup/install-service.sh +++ b/scripts/setup/install-service.sh @@ -15,7 +15,8 @@ BIND_ADDRESS="${FOSSILSAFE_BACKEND_BIND:-0.0.0.0}" BIND_PORT="${FOSSILSAFE_BACKEND_PORT:-5000}" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -TEMPLATE="${SCRIPT_DIR}/../packaging/fossilsafe.service" +REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)" +TEMPLATE="${REPO_ROOT}/packaging/fossilsafe.service" OUTPUT="/etc/systemd/system/fossilsafe.service" usage() { @@ -84,15 +85,23 @@ chmod 750 "$DATA_DIR" # Generate unit file echo "Generating systemd unit file..." +VENV_DIR="${INSTALL_DIR}/venv" +# CONFIG_PATH may be a dir (/etc/fossilsafe) or the config.json file itself +if [[ -d "${CONFIG_PATH}" ]]; then + CONFIG_FILE="${CONFIG_PATH%/}/config.json" +else + CONFIG_FILE="${CONFIG_PATH}" +fi sed \ -e "s|{{INSTALL_DIR}}|$INSTALL_DIR|g" \ -e "s|{{SERVICE_USER}}|$SERVICE_USER|g" \ -e "s|{{SERVICE_GROUP}}|$SERVICE_GROUP|g" \ -e "s|{{TAPE_GROUP}}|$TAPE_GROUP|g" \ - -e "s|{{CONFIG_PATH}}|$CONFIG_PATH|g" \ + -e "s|{{CONFIG_PATH}}|$CONFIG_FILE|g" \ -e "s|{{DATA_DIR}}|$DATA_DIR|g" \ -e "s|{{BACKEND_BIND}}|$BIND_ADDRESS|g" \ -e "s|{{BACKEND_PORT}}|$BIND_PORT|g" \ + -e "s|{{VENV_DIR}}|$VENV_DIR|g" \ "$TEMPLATE" > "$OUTPUT" chmod 644 "$OUTPUT" From 65dcbff1f05cb453d52d7d1446d0ca69feef0685 Mon Sep 17 00:00:00 2001 From: AZLyyds <2773638053@qq.com> Date: Mon, 10 Aug 2026 10:38:05 +0800 Subject: [PATCH 3/3] Remove unused imports that break the UI TypeScript build tsc -b fails on unused Link/React imports during npm run build. Signed-off-by: AZLyyds <2773638053@qq.com> --- frontend/src/pages/DashboardPage.tsx | 2 +- frontend/src/pages/JobsPage.tsx | 1 - frontend/src/pages/SettingsPage.tsx | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/frontend/src/pages/DashboardPage.tsx b/frontend/src/pages/DashboardPage.tsx index 1cc04bd..7c576d3 100644 --- a/frontend/src/pages/DashboardPage.tsx +++ b/frontend/src/pages/DashboardPage.tsx @@ -1,4 +1,4 @@ -import { Link, useNavigate } from "react-router-dom" +import { useNavigate } from "react-router-dom" import { useState, useEffect } from "react" import { api, Job, Tape } from "../lib/api" import RestoreWizard from "@/components/RestoreWizard" diff --git a/frontend/src/pages/JobsPage.tsx b/frontend/src/pages/JobsPage.tsx index 366775d..4858b02 100644 --- a/frontend/src/pages/JobsPage.tsx +++ b/frontend/src/pages/JobsPage.tsx @@ -1,5 +1,4 @@ import React, { useState, useEffect } from "react" -import { Link } from "react-router-dom" import { cn } from "@/lib/utils" import { useDemoMode } from "@/lib/demoMode" import { api, Job, Tape } from "@/lib/api" diff --git a/frontend/src/pages/SettingsPage.tsx b/frontend/src/pages/SettingsPage.tsx index 76965c4..1fdb8ef 100644 --- a/frontend/src/pages/SettingsPage.tsx +++ b/frontend/src/pages/SettingsPage.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from "react" +import { useState, useEffect } from "react" import { useSearchParams } from "react-router-dom" import { cn } from "@/lib/utils" import { useDemoMode } from "@/lib/demoMode"