Merge claude/1
This commit is contained in:
commit
fc2c6a6197
@ -2,7 +2,7 @@
|
|||||||
# Backup Engine - **ADVANCED** Engine-level knobs most users won't need to touch
|
# Backup Engine - **ADVANCED** Engine-level knobs most users won't need to touch
|
||||||
# ================================================================================
|
# ================================================================================
|
||||||
CFG_BACKUP_ENGINE=restic # Default Backup Engine - Fallback engine for new locations (each location can override) [restic:Restic|borg:BorgBackup|kopia:Kopia]
|
CFG_BACKUP_ENGINE=restic # Default Backup Engine - Fallback engine for new locations (each location can override) [restic:Restic|borg:BorgBackup|kopia:Kopia]
|
||||||
CFG_BACKUP_DEFAULT_PATH=/docker/backups # Default Backup Location - Base directory for locations set to Automatic path mode; each location lives in its own numbered subfolder (<path>/<id>)
|
CFG_BACKUP_DEFAULT_PATH= # Default Backup Location - Base directory for locations set to Automatic path mode; each location lives in its own numbered subfolder (<path>/<id>). Empty = the LibrePortal backups root (own mount-able).
|
||||||
CFG_BACKUP_STRATEGY=auto # Backup Strategy - How containers are quiesced before snapshotting [auto:Automatic — live where safe, stop otherwise (recommended)|stop-snapshot-start:Stop → snapshot → start (always safe)|pause-snapshot-unpause:Pause → snapshot → unpause (less downtime)|live:Live — snapshot while running (force)]
|
CFG_BACKUP_STRATEGY=auto # Backup Strategy - How containers are quiesced before snapshotting [auto:Automatic — live where safe, stop otherwise (recommended)|stop-snapshot-start:Stop → snapshot → start (always safe)|pause-snapshot-unpause:Pause → snapshot → unpause (less downtime)|live:Live — snapshot while running (force)]
|
||||||
CFG_BACKUP_VERIFY_AFTER=true # Verify After Backup - Run integrity check after each backup
|
CFG_BACKUP_VERIFY_AFTER=true # Verify After Backup - Run integrity check after each backup
|
||||||
CFG_BACKUP_VERIFY_DATA_PERCENT=5 # Verify Data Sample % - Percentage of repo data to checksum-verify weekly
|
CFG_BACKUP_VERIFY_DATA_PERCENT=5 # Verify Data Sample % - Percentage of repo data to checksum-verify weekly
|
||||||
|
|||||||
@ -32,7 +32,11 @@ const router = express.Router();
|
|||||||
|
|
||||||
const TASKS_DIR = path.join(__dirname, '..', '..', 'frontend', 'data', 'tasks');
|
const TASKS_DIR = path.join(__dirname, '..', '..', 'frontend', 'data', 'tasks');
|
||||||
const FIFO_PATH = path.join(TASKS_DIR, '.queue.fifo');
|
const FIFO_PATH = path.join(TASKS_DIR, '.queue.fifo');
|
||||||
const CONTAINERS_DIR = '/docker/containers';
|
// Host live-app-data root. Provided by the compose env (LP_CONTAINERS_DIR, filled
|
||||||
|
// from the host's containers root at generation — see scripts/source/paths.sh).
|
||||||
|
// Falls back to the legacy /docker path so a container that hasn't been recreated
|
||||||
|
// since the split-layout change keeps working until it is.
|
||||||
|
const CONTAINERS_DIR = process.env.LP_CONTAINERS_DIR || '/docker/containers';
|
||||||
const APPS_SERVICES_JSON = path.join(__dirname, '..', '..', 'frontend', 'data', 'apps', 'generated', 'apps-services.json');
|
const APPS_SERVICES_JSON = path.join(__dirname, '..', '..', 'frontend', 'data', 'apps', 'generated', 'apps-services.json');
|
||||||
|
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
|
|||||||
@ -31,6 +31,7 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
FRONTEND_PATH: /data/frontend
|
FRONTEND_PATH: /data/frontend
|
||||||
LIBREPORTAL_CONFIG_PATH: /app/libreportal.config
|
LIBREPORTAL_CONFIG_PATH: /app/libreportal.config
|
||||||
|
LP_CONTAINERS_DIR: CONTAINERS_DIR_DATA #LIBREPORTAL|CONTAINERS_DIR_TAG|CONTAINERS_DIR_DATA
|
||||||
TZ: TIMEZONE_DATA #LIBREPORTAL|TIMEZONE_TAG|TIMEZONE_DATA
|
TZ: TIMEZONE_DATA #LIBREPORTAL|TIMEZONE_TAG|TIMEZONE_DATA
|
||||||
labels:
|
labels:
|
||||||
libreportal.category: "CATEGORY_DATA" #LIBREPORTAL|CATEGORY_TAG|CATEGORY_DATA
|
libreportal.category: "CATEGORY_DATA" #LIBREPORTAL|CATEGORY_TAG|CATEGORY_DATA
|
||||||
|
|||||||
57
init.sh
57
init.sh
@ -110,22 +110,47 @@ lp_lib_dir="/usr/local/lib/libreportal"
|
|||||||
command_script="$lp_lib_dir/libreportal"
|
command_script="$lp_lib_dir/libreportal"
|
||||||
command_symlink="/usr/local/bin/libreportal"
|
command_symlink="/usr/local/bin/libreportal"
|
||||||
|
|
||||||
# Directories
|
# Directories — three independently-relocatable roots (see scripts/source/paths.sh
|
||||||
docker_dir="/docker"
|
# for the canonical description). Defaults below; overridden by --system-dir /
|
||||||
containers_dir="$docker_dir/containers/"
|
# --containers-dir / --backups-dir (parsed in the flag loop) via the LP_*_DIR
|
||||||
ssl_dir="$docker_dir/ssl/"
|
# vars. init.sh derives inline (kept in sync with paths.sh) because the bare
|
||||||
ssh_dir="$docker_dir/ssh/"
|
# /root/init.sh reinstall copy has no scripts/ alongside to source.
|
||||||
wireguard_dir="$docker_dir/wireguard/"
|
# LP_SYSTEM_DIR — manager-owned control plane (configs/logs/install/db/…)
|
||||||
logs_dir="$docker_dir/logs/"
|
# LP_CONTAINERS_DIR — container-user-owned live app data
|
||||||
configs_dir="$docker_dir/configs/"
|
# LP_BACKUPS_DIR — container-user-owned backup repos (own mount-able)
|
||||||
backup_dir="$docker_dir/backups"
|
libreportalDerivePaths() {
|
||||||
restore_dir="$docker_dir/restore"
|
# Transitional compat: an existing install (legacy single /docker tree,
|
||||||
migrate_dir="$docker_dir/migrate"
|
# identified by its config marker) keeps using /docker until a deliberate
|
||||||
# Install Scripts
|
# reinstall — so deploying new code never strands a running box.
|
||||||
script_dir="$docker_dir/install"
|
if [[ -z "${LP_SYSTEM_DIR:-}" ]]; then
|
||||||
install_configs_dir="$script_dir/configs/"
|
if [[ ! -e /libreportal-system && -f /docker/configs/general/general_docker_install ]]; then
|
||||||
install_containers_dir="$script_dir/containers/"
|
LP_SYSTEM_DIR=/docker
|
||||||
install_scripts_dir="$script_dir/scripts/"
|
: "${LP_CONTAINERS_DIR:=/docker/containers}"
|
||||||
|
: "${LP_BACKUPS_DIR:=/docker/backups}"
|
||||||
|
else
|
||||||
|
LP_SYSTEM_DIR=/libreportal-system
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
: "${LP_CONTAINERS_DIR:=/libreportal-containers}"
|
||||||
|
: "${LP_BACKUPS_DIR:=/libreportal-backups}"
|
||||||
|
|
||||||
|
docker_dir="$LP_SYSTEM_DIR"
|
||||||
|
system_dir="$LP_SYSTEM_DIR"
|
||||||
|
configs_dir="$LP_SYSTEM_DIR/configs/"
|
||||||
|
logs_dir="$LP_SYSTEM_DIR/logs/"
|
||||||
|
ssl_dir="$LP_SYSTEM_DIR/ssl/"
|
||||||
|
ssh_dir="$LP_SYSTEM_DIR/ssh/"
|
||||||
|
wireguard_dir="$LP_SYSTEM_DIR/wireguard/"
|
||||||
|
migrate_dir="$LP_SYSTEM_DIR/migrate"
|
||||||
|
restore_dir="$LP_SYSTEM_DIR/restore"
|
||||||
|
script_dir="$LP_SYSTEM_DIR/install"
|
||||||
|
install_configs_dir="$script_dir/configs/"
|
||||||
|
install_containers_dir="$script_dir/containers/"
|
||||||
|
install_scripts_dir="$script_dir/scripts/"
|
||||||
|
containers_dir="$LP_CONTAINERS_DIR/"
|
||||||
|
backup_dir="$LP_BACKUPS_DIR"
|
||||||
|
}
|
||||||
|
libreportalDerivePaths
|
||||||
|
|
||||||
# Parse flags
|
# Parse flags
|
||||||
init_shift_count=0
|
init_shift_count=0
|
||||||
|
|||||||
@ -52,7 +52,7 @@ backupLocationsMigrate()
|
|||||||
runFileOp chown "$owner":"$owner" "$loc_dir"
|
runFileOp chown "$owner":"$owner" "$loc_dir"
|
||||||
runFileOp chmod 0700 "$loc_dir"
|
runFileOp chmod 0700 "$loc_dir"
|
||||||
|
|
||||||
local old_pass="/docker/configs/security/restic/loc_${idx}.pass"
|
local old_pass="${configs_dir}security/restic/loc_${idx}.pass"
|
||||||
local pass_value=""
|
local pass_value=""
|
||||||
if [[ -f "$old_pass" ]]; then
|
if [[ -f "$old_pass" ]]; then
|
||||||
pass_value=$(runFileOp cat "$old_pass" | tr -d '\n\r')
|
pass_value=$(runFileOp cat "$old_pass" | tr -d '\n\r')
|
||||||
@ -75,7 +75,7 @@ backupLocationsMigrate()
|
|||||||
replacePlainPasswords "$cfg_file"
|
replacePlainPasswords "$cfg_file"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local old_kopia="/docker/configs/security/restic/kopia/loc_${idx}.config"
|
local old_kopia="${configs_dir}security/restic/kopia/loc_${idx}.config"
|
||||||
local new_kopia
|
local new_kopia
|
||||||
new_kopia=$(backupLocationKopiaConfig "$idx")
|
new_kopia=$(backupLocationKopiaConfig "$idx")
|
||||||
if [[ -f "$old_kopia" ]]; then
|
if [[ -f "$old_kopia" ]]; then
|
||||||
@ -85,7 +85,7 @@ backupLocationsMigrate()
|
|||||||
isNotice "Moved kopia state for location $idx → $new_kopia"
|
isNotice "Moved kopia state for location $idx → $new_kopia"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local old_ssh="/docker/configs/security/restic/ssh/loc_${idx}.key"
|
local old_ssh="${configs_dir}security/restic/ssh/loc_${idx}.key"
|
||||||
local new_ssh
|
local new_ssh
|
||||||
new_ssh=$(backupLocationSshKey "$idx")
|
new_ssh=$(backupLocationSshKey "$idx")
|
||||||
if [[ -f "$old_ssh" ]]; then
|
if [[ -f "$old_ssh" ]]; then
|
||||||
|
|||||||
@ -69,7 +69,7 @@ backupLocationResolvedPath()
|
|||||||
if [[ "$mode" == "auto" ]]; then
|
if [[ "$mode" == "auto" ]]; then
|
||||||
# Base dir is the configurable Default Backup Location (Backup Engine
|
# Base dir is the configurable Default Backup Location (Backup Engine
|
||||||
# config); each location gets its own numbered subfolder.
|
# config); each location gets its own numbered subfolder.
|
||||||
local base="${CFG_BACKUP_DEFAULT_PATH:-$docker_dir/backups}"
|
local base="${CFG_BACKUP_DEFAULT_PATH:-${backup_dir:-$docker_dir/backups}}"
|
||||||
echo "${base%/}/${idx}"
|
echo "${base%/}/${idx}"
|
||||||
else
|
else
|
||||||
resticLocationField "$idx" PATH
|
resticLocationField "$idx" PATH
|
||||||
|
|||||||
@ -51,6 +51,6 @@ tagsManagerUpdateUniversalTag()
|
|||||||
# manager-owned configs/ + install templates use runInstallOp. The read
|
# manager-owned configs/ + install templates use runInstallOp. The read
|
||||||
# (awk above) needs no escalation — config/compose files are world-readable.
|
# (awk above) needs no escalation — config/compose files are world-readable.
|
||||||
local op="runInstallOp"
|
local op="runInstallOp"
|
||||||
[[ "$file_path" == "$containers_dir"* || "$file_path" == /docker/containers/* ]] && op="runFileOp"
|
[[ "$file_path" == "$containers_dir"* || "$file_path" == "${LP_CONTAINERS_DIR:-/libreportal-containers}"/* ]] && op="runFileOp"
|
||||||
$op sed -i "/#LIBREPORTAL|${tag_name}|/s|${esc_placeholder}|${esc_new}|g" "$file_path"
|
$op sed -i "/#LIBREPORTAL|${tag_name}|/s|${esc_placeholder}|${esc_new}|g" "$file_path"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,6 +21,9 @@ tagsProcessorStandardReplacements()
|
|||||||
tagsManagerUpdateUniversalTag "$full_file_path" "DOMAINSUBNAME_TAG" "$host_setup"
|
tagsManagerUpdateUniversalTag "$full_file_path" "DOMAINSUBNAME_TAG" "$host_setup"
|
||||||
tagsManagerUpdateUniversalTag "$full_file_path" "TIMEZONE_TAG" "$CFG_TIMEZONE"
|
tagsManagerUpdateUniversalTag "$full_file_path" "TIMEZONE_TAG" "$CFG_TIMEZONE"
|
||||||
tagsManagerUpdateUniversalTag "$full_file_path" "DOCKER_NETWORK_TAG" "$CFG_NETWORK_NAME"
|
tagsManagerUpdateUniversalTag "$full_file_path" "DOCKER_NETWORK_TAG" "$CFG_NETWORK_NAME"
|
||||||
|
# Host live-app-data root, passed into the WebUI container (only the
|
||||||
|
# libreportal compose carries this tag; "only update tags that exist").
|
||||||
|
tagsManagerUpdateUniversalTag "$full_file_path" "CONTAINERS_DIR_TAG" "${containers_dir%/}"
|
||||||
|
|
||||||
isSuccessful "Standard LibrePortal tag replacements applied using universal tag manager"
|
isSuccessful "Standard LibrePortal tag replacements applied using universal tag manager"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
crontabClean()
|
crontabClean()
|
||||||
{
|
{
|
||||||
# Remove old backup log entries
|
# Remove old backup log entries
|
||||||
data_to_remove=" >> /docker/logs/backup.log 2>&1"
|
data_to_remove=" >> ${logs_dir}${backup_log_file} 2>&1"
|
||||||
|
|
||||||
if crontab -l 2>/dev/null | grep -q "$data_to_remove"; then
|
if crontab -l 2>/dev/null | grep -q "$data_to_remove"; then
|
||||||
crontab -l 2>/dev/null | sed "s|$data_to_remove||g" | crontab -
|
crontab -l 2>/dev/null | sed "s|$data_to_remove||g" | crontab -
|
||||||
|
|||||||
@ -16,13 +16,18 @@ if [[ "$script_check_processor_flag" == "start_script" ]]; then
|
|||||||
# them every privileged op is "command not found". Same bootstrap as
|
# them every privileged op is "command not found". Same bootstrap as
|
||||||
# crontab_task_processor.sh. These files are pure function/var defs, safe to
|
# crontab_task_processor.sh. These files are pure function/var defs, safe to
|
||||||
# source.
|
# source.
|
||||||
LP_SCRIPTS="${install_scripts_dir:-/docker/install/scripts/}"
|
# Self-locate the scripts dir, then load the relocatable path roots (sets
|
||||||
LP_DOCKER_CFG="/docker/configs/general/general_docker_install"
|
# docker_dir/containers_dir/configs_dir/…). Same bootstrap as the task processor.
|
||||||
|
LP_SELF_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
|
||||||
|
LP_SCRIPTS="${install_scripts_dir:-$(cd "$LP_SELF_DIR/../.." 2>/dev/null && pwd)/}"
|
||||||
|
[[ -f "${LP_SCRIPTS}source/paths.sh" ]] && source "${LP_SCRIPTS}source/paths.sh"
|
||||||
|
LP_SCRIPTS="${install_scripts_dir:-$LP_SCRIPTS}"
|
||||||
|
LP_DOCKER_CFG="${configs_dir:-/libreportal-system/configs/}general/general_docker_install"
|
||||||
[[ -f "$LP_DOCKER_CFG" ]] && \
|
[[ -f "$LP_DOCKER_CFG" ]] && \
|
||||||
eval "$(grep -E '^CFG_DOCKER_INSTALL_(TYPE|USER)=' "$LP_DOCKER_CFG" | sed 's/[[:space:]]*#.*//')"
|
eval "$(grep -E '^CFG_DOCKER_INSTALL_(TYPE|USER)=' "$LP_DOCKER_CFG" | sed 's/[[:space:]]*#.*//')"
|
||||||
: "${sudo_user_name:=libreportal}"
|
: "${sudo_user_name:=libreportal}"
|
||||||
: "${containers_dir:=/docker/containers/}"
|
: "${containers_dir:=/libreportal-containers/}"
|
||||||
: "${docker_dir:=/docker}"
|
: "${docker_dir:=/libreportal-system}"
|
||||||
for _lp_f in docker/command/run_privileged.sh \
|
for _lp_f in docker/command/run_privileged.sh \
|
||||||
docker/command/docker_run_install.sh \
|
docker/command/docker_run_install.sh \
|
||||||
checks/requirements/check_install_type.sh; do
|
checks/requirements/check_install_type.sh; do
|
||||||
@ -37,7 +42,7 @@ command -v resolveDockerInstallUser >/dev/null 2>&1 && resolveDockerInstallUser
|
|||||||
# Essential configuration (keeping your original structure)
|
# Essential configuration (keeping your original structure)
|
||||||
TASK_DIR=""
|
TASK_DIR=""
|
||||||
if [[ "$TASK_DIR" == "" ]]; then
|
if [[ "$TASK_DIR" == "" ]]; then
|
||||||
TASK_DIR="/docker/containers/libreportal/frontend/data/tasks"
|
TASK_DIR="${containers_dir:-/libreportal-containers/}libreportal/frontend/data/tasks"
|
||||||
fi
|
fi
|
||||||
LOCK_FILE="$TASK_DIR/task_processor.lock"
|
LOCK_FILE="$TASK_DIR/task_processor.lock"
|
||||||
|
|
||||||
|
|||||||
@ -32,13 +32,19 @@ script_task_processor_flag="$1"
|
|||||||
# docker-install-owned task dir fails ("command not found") and tasks loop
|
# docker-install-owned task dir fails ("command not found") and tasks loop
|
||||||
# forever. Load them here — these files are pure function/var defs, safe to
|
# forever. Load them here — these files are pure function/var defs, safe to
|
||||||
# source, no side effects.
|
# source, no side effects.
|
||||||
LP_SCRIPTS="${install_scripts_dir:-/docker/install/scripts/}"
|
# Self-locate the scripts dir (where systemd launched us) so we can load the
|
||||||
LP_DOCKER_CFG="/docker/configs/general/general_docker_install"
|
# relocatable path roots — paths.sh sets docker_dir/containers_dir/configs_dir/…
|
||||||
|
# (the data + backup roots can't be derived from our own location).
|
||||||
|
LP_SELF_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
|
||||||
|
LP_SCRIPTS="${install_scripts_dir:-$(cd "$LP_SELF_DIR/../.." 2>/dev/null && pwd)/}"
|
||||||
|
[[ -f "${LP_SCRIPTS}source/paths.sh" ]] && source "${LP_SCRIPTS}source/paths.sh"
|
||||||
|
LP_SCRIPTS="${install_scripts_dir:-$LP_SCRIPTS}"
|
||||||
|
LP_DOCKER_CFG="${configs_dir:-/libreportal-system/configs/}general/general_docker_install"
|
||||||
[[ -f "$LP_DOCKER_CFG" ]] && \
|
[[ -f "$LP_DOCKER_CFG" ]] && \
|
||||||
eval "$(grep -E '^CFG_DOCKER_INSTALL_(TYPE|USER)=' "$LP_DOCKER_CFG" | sed 's/[[:space:]]*#.*//')"
|
eval "$(grep -E '^CFG_DOCKER_INSTALL_(TYPE|USER)=' "$LP_DOCKER_CFG" | sed 's/[[:space:]]*#.*//')"
|
||||||
: "${sudo_user_name:=libreportal}"
|
: "${sudo_user_name:=libreportal}"
|
||||||
: "${containers_dir:=/docker/containers/}"
|
: "${containers_dir:=/libreportal-containers/}"
|
||||||
: "${docker_dir:=/docker}"
|
: "${docker_dir:=/libreportal-system}"
|
||||||
for _lp_f in docker/command/run_privileged.sh \
|
for _lp_f in docker/command/run_privileged.sh \
|
||||||
docker/command/docker_run_install.sh \
|
docker/command/docker_run_install.sh \
|
||||||
checks/requirements/check_install_type.sh; do
|
checks/requirements/check_install_type.sh; do
|
||||||
@ -50,7 +56,7 @@ command -v resolveDockerInstallUser >/dev/null 2>&1 && resolveDockerInstallUser
|
|||||||
# PATHS & CONSTANTS
|
# PATHS & CONSTANTS
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
||||||
TASK_DIR="${TASK_DIR:-/docker/containers/libreportal/frontend/data/tasks}"
|
TASK_DIR="${TASK_DIR:-${containers_dir:-/libreportal-containers/}libreportal/frontend/data/tasks}"
|
||||||
LOCK_FILE="$TASK_DIR/.processor.lock"
|
LOCK_FILE="$TASK_DIR/.processor.lock"
|
||||||
FIFO="$TASK_DIR/.queue.fifo"
|
FIFO="$TASK_DIR/.queue.fifo"
|
||||||
LOG_FILE="$TASK_DIR/task_processor.log"
|
LOG_FILE="$TASK_DIR/task_processor.log"
|
||||||
|
|||||||
@ -101,7 +101,7 @@ _runRootHelper() {
|
|||||||
if [[ -x "$helper" ]]; then
|
if [[ -x "$helper" ]]; then
|
||||||
sudo "$helper" "$@"
|
sudo "$helper" "$@"
|
||||||
elif [[ $EUID -eq 0 ]]; then
|
elif [[ $EUID -eq 0 ]]; then
|
||||||
bash "${script_dir:-/docker/install}/scripts/system/$name" "$@"
|
bash "${script_dir:-/libreportal-system/install}/scripts/system/$name" "$@"
|
||||||
else
|
else
|
||||||
sudo "$helper" "$@"
|
sudo "$helper" "$@"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@ -17,7 +17,7 @@ copyFile()
|
|||||||
# the manager-owned control plane (configs/logs/etc.) is runInstallOp.
|
# the manager-owned control plane (configs/logs/etc.) is runInstallOp.
|
||||||
# Mirrors createTouch's path-based ownership; $user_name is now advisory.
|
# Mirrors createTouch's path-based ownership; $user_name is now advisory.
|
||||||
local op="runInstallOp"
|
local op="runInstallOp"
|
||||||
[[ "$save_dir" == "$containers_dir"* || "$save_dir" == /docker/containers/* ]] && op="runFileOp"
|
[[ "$save_dir" == "$containers_dir"* || "$save_dir" == "${LP_CONTAINERS_DIR:-/libreportal-containers}"/* ]] && op="runFileOp"
|
||||||
|
|
||||||
if [ "$silent_flag" == "loud" ]; then
|
if [ "$silent_flag" == "loud" ]; then
|
||||||
local result=$($op cp $flags_full "$file" "$save_dir")
|
local result=$($op cp $flags_full "$file" "$save_dir")
|
||||||
|
|||||||
@ -9,7 +9,7 @@ copyFiles()
|
|||||||
|
|
||||||
# Write as the destination's owner (see copyFile).
|
# Write as the destination's owner (see copyFile).
|
||||||
local op="runInstallOp"
|
local op="runInstallOp"
|
||||||
[[ "$save_dir" == "$containers_dir"* || "$save_dir" == /docker/containers/* ]] && op="runFileOp"
|
[[ "$save_dir" == "$containers_dir"* || "$save_dir" == "${LP_CONTAINERS_DIR:-/libreportal-containers}"/* ]] && op="runFileOp"
|
||||||
|
|
||||||
local files=($($op find "$source" -type f))
|
local files=($($op find "$source" -type f))
|
||||||
if [ ${#files[@]} -eq 0 ]; then
|
if [ ${#files[@]} -eq 0 ]; then
|
||||||
|
|||||||
@ -21,7 +21,7 @@ createTouch()
|
|||||||
local file_dir=$(dirname "$clean_file")
|
local file_dir=$(dirname "$clean_file")
|
||||||
|
|
||||||
local op="runInstallOp"
|
local op="runInstallOp"
|
||||||
if [[ "$clean_file" == "$containers_dir"* || "$clean_file" == /docker/containers/* ]]; then
|
if [[ "$clean_file" == "$containers_dir"* || "$clean_file" == "${LP_CONTAINERS_DIR:-/libreportal-containers}"/* ]]; then
|
||||||
op="runFileOp"
|
op="runFileOp"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ moveFile()
|
|||||||
if [ -e "$file" ]; then
|
if [ -e "$file" ]; then
|
||||||
# Move as the destination's owner — no root, no chown (see copyFile).
|
# Move as the destination's owner — no root, no chown (see copyFile).
|
||||||
local op="runInstallOp"
|
local op="runInstallOp"
|
||||||
[[ "$save_dir" == "$containers_dir"* || "$save_dir" == /docker/containers/* ]] && op="runFileOp"
|
[[ "$save_dir" == "$containers_dir"* || "$save_dir" == "${LP_CONTAINERS_DIR:-/libreportal-containers}"/* ]] && op="runFileOp"
|
||||||
local result=$($op mv "$file" "$save_dir")
|
local result=$($op mv "$file" "$save_dir")
|
||||||
checkSuccess "Moving $file_name to $save_dir"
|
checkSuccess "Moving $file_name to $save_dir"
|
||||||
else
|
else
|
||||||
|
|||||||
@ -8,8 +8,8 @@ copyFolder()
|
|||||||
local user_name="$3" # advisory — the destination path determines the owner
|
local user_name="$3" # advisory — the destination path determines the owner
|
||||||
|
|
||||||
# Write as the destination's owner — no root, no chown (see copyFile).
|
# Write as the destination's owner — no root, no chown (see copyFile).
|
||||||
if [[ "$save_dir" == "$containers_dir"* || "$save_dir" == /docker/containers/* ]]; then
|
if [[ "$save_dir" == "$containers_dir"* || "$save_dir" == "${LP_CONTAINERS_DIR:-/libreportal-containers}"/* ]]; then
|
||||||
if [[ "$folder" == "$containers_dir"* || "$folder" == /docker/containers/* ]]; then
|
if [[ "$folder" == "$containers_dir"* || "$folder" == "${LP_CONTAINERS_DIR:-/libreportal-containers}"/* ]]; then
|
||||||
# container -> container: same owner (dockerinstall), a plain cp works.
|
# container -> container: same owner (dockerinstall), a plain cp works.
|
||||||
local result=$(runFileOp cp -rf "$folder" "$save_dir")
|
local result=$(runFileOp cp -rf "$folder" "$save_dir")
|
||||||
else
|
else
|
||||||
|
|||||||
@ -8,7 +8,7 @@ copyFolders()
|
|||||||
|
|
||||||
# Write as the destination's owner — no root, no chown (see copyFile).
|
# Write as the destination's owner — no root, no chown (see copyFile).
|
||||||
local op="runInstallOp"
|
local op="runInstallOp"
|
||||||
[[ "$save_dir" == "$containers_dir"* || "$save_dir" == /docker/containers/* ]] && op="runFileOp"
|
[[ "$save_dir" == "$containers_dir"* || "$save_dir" == "${LP_CONTAINERS_DIR:-/libreportal-containers}"/* ]] && op="runFileOp"
|
||||||
|
|
||||||
local subdirs=($(find "$source" -mindepth 1 -maxdepth 1 -type d))
|
local subdirs=($(find "$source" -mindepth 1 -maxdepth 1 -type d))
|
||||||
if [ ${#subdirs[@]} -eq 0 ]; then
|
if [ ${#subdirs[@]} -eq 0 ]; then
|
||||||
|
|||||||
@ -14,7 +14,7 @@ createFolders()
|
|||||||
# AS that user via runFileOp — creating it as the right owner avoids a
|
# AS that user via runFileOp — creating it as the right owner avoids a
|
||||||
# chown-to-another-user the unprivileged runtime can't do. Mirrors
|
# chown-to-another-user the unprivileged runtime can't do. Mirrors
|
||||||
# createTouch; the $user_name hint is advisory for these paths.
|
# createTouch; the $user_name hint is advisory for these paths.
|
||||||
if [[ "$clean_dir" == "$containers_dir"* || "$clean_dir" == /docker/containers/* ]]; then
|
if [[ "$clean_dir" == "$containers_dir"* || "$clean_dir" == "${LP_CONTAINERS_DIR:-/libreportal-containers}"/* ]]; then
|
||||||
if [ ! -d "$dir_path" ]; then
|
if [ ! -d "$dir_path" ]; then
|
||||||
local result=$(runFileOp mkdir -p "$dir_path")
|
local result=$(runFileOp mkdir -p "$dir_path")
|
||||||
[ "$silent_flag" == "loud" ] && checkSuccess "Creating $folder_name directory"
|
[ "$silent_flag" == "loud" ] && checkSuccess "Creating $folder_name directory"
|
||||||
|
|||||||
@ -63,17 +63,17 @@ runReinstall()
|
|||||||
AUTH_HTTP_REPO_URL="http://${CFG_GIT_USER}:${CFG_GIT_KEY}@${CLEAN_GIT_URL}.git"
|
AUTH_HTTP_REPO_URL="http://${CFG_GIT_USER}:${CFG_GIT_KEY}@${CLEAN_GIT_URL}.git"
|
||||||
|
|
||||||
# Try HTTPS first
|
# Try HTTPS first
|
||||||
if runAsManager git clone -q "$AUTH_HTTPS_REPO_URL" "/docker/install" 2>/dev/null; then
|
if runAsManager git clone -q "$AUTH_HTTPS_REPO_URL" "$script_dir" 2>/dev/null; then
|
||||||
runSystem cp -f /docker/install/init.sh /root/
|
runSystem cp -f "$script_dir/init.sh" /root/
|
||||||
echo "SUCCESS: Git repository cloned via HTTPS into /docker/install."
|
echo "SUCCESS: Git repository cloned via HTTPS into $script_dir."
|
||||||
echo ""
|
echo ""
|
||||||
echo "SUCCESS: Reinstallation complete, you can now run the "libreportal run" command."
|
echo "SUCCESS: Reinstallation complete, you can now run the "libreportal run" command."
|
||||||
echo ""
|
echo ""
|
||||||
else
|
else
|
||||||
# If HTTPS fails, try HTTP
|
# If HTTPS fails, try HTTP
|
||||||
if runAsManager git clone -q "$AUTH_HTTP_REPO_URL" "/docker/install" 2>/dev/null; then
|
if runAsManager git clone -q "$AUTH_HTTP_REPO_URL" "$script_dir" 2>/dev/null; then
|
||||||
runSystem cp -f /docker/install/init.sh /root/
|
runSystem cp -f "$script_dir/init.sh" /root/
|
||||||
echo "SUCCESS: Git repository cloned via HTTP into /docker/install."
|
echo "SUCCESS: Git repository cloned via HTTP into $script_dir."
|
||||||
echo ""
|
echo ""
|
||||||
echo "SUCCESS: Reinstallation complete, you can now run the "libreportal run" command."
|
echo "SUCCESS: Reinstallation complete, you can now run the "libreportal run" command."
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
setupHeadscaleGenerateAuthKey()
|
setupHeadscaleGenerateAuthKey()
|
||||||
{
|
{
|
||||||
headscale_preauthkey=""
|
headscale_preauthkey=""
|
||||||
local temp_key_file="/docker/key.txt"
|
local temp_key_file="${docker_dir:-/libreportal-system}/key.txt"
|
||||||
|
|
||||||
local CFG_INSTALL_NAME=$(echo "$CFG_INSTALL_NAME" | tr '[:upper:]' '[:lower:]')
|
local CFG_INSTALL_NAME=$(echo "$CFG_INSTALL_NAME" | tr '[:upper:]' '[:lower:]')
|
||||||
dockerCommandRun "docker exec headscale headscale preauthkeys create -e 1h -u $CFG_INSTALL_NAME" > "$temp_key_file" 2>&1
|
dockerCommandRun "docker exec headscale headscale preauthkeys create -e 1h -u $CFG_INSTALL_NAME" > "$temp_key_file" 2>&1
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
# mount set takes effect.
|
# mount set takes effect.
|
||||||
crowdsecToggleLibrePortalLogMounts() {
|
crowdsecToggleLibrePortalLogMounts() {
|
||||||
local mode="$1"
|
local mode="$1"
|
||||||
local compose="/docker/containers/libreportal/docker-compose.yml"
|
local compose="${containers_dir}libreportal/docker-compose.yml"
|
||||||
[[ -f "$compose" ]] || return 0
|
[[ -f "$compose" ]] || return 0
|
||||||
|
|
||||||
case "$mode" in
|
case "$mode" in
|
||||||
@ -24,7 +24,7 @@ crowdsecToggleLibrePortalLogMounts() {
|
|||||||
|
|
||||||
if runFileOp docker ps --format '{{.Names}}' 2>/dev/null | grep -q '^libreportal-service$'; then
|
if runFileOp docker ps --format '{{.Names}}' 2>/dev/null | grep -q '^libreportal-service$'; then
|
||||||
isNotice "Recreating libreportal so log mount toggle takes effect..."
|
isNotice "Recreating libreportal so log mount toggle takes effect..."
|
||||||
( cd /docker/containers/libreportal && runAsManager docker compose up -d >/dev/null 2>&1 ) || true
|
( cd "${containers_dir}libreportal" && runAsManager docker compose up -d >/dev/null 2>&1 ) || true
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,7 +215,7 @@ installCrowdsecHost()
|
|||||||
# (use the rotate Tools action for that); this is a visibility
|
# (use the rotate Tools action for that); this is a visibility
|
||||||
# surface, not the auth source of truth.
|
# surface, not the auth source of truth.
|
||||||
local key_file="/etc/crowdsec/traefik_bouncer.key"
|
local key_file="/etc/crowdsec/traefik_bouncer.key"
|
||||||
local cfg_file="/docker/configs/security/security_crowdsec"
|
local cfg_file="${configs_dir}security/security_crowdsec"
|
||||||
|
|
||||||
if ! runSystem cscli bouncers list -o raw 2>/dev/null | grep -q '^traefik-bouncer'; then
|
if ! runSystem cscli bouncers list -o raw 2>/dev/null | grep -q '^traefik-bouncer'; then
|
||||||
local bouncer_key
|
local bouncer_key
|
||||||
|
|||||||
@ -22,7 +22,7 @@ installResticHost()
|
|||||||
|
|
||||||
installResticMigrateLegacyPasswords()
|
installResticMigrateLegacyPasswords()
|
||||||
{
|
{
|
||||||
local pass_dir="/docker/configs/security/restic"
|
local pass_dir="${configs_dir}security/restic"
|
||||||
[[ ! -d "$pass_dir" ]] && return 0
|
[[ ! -d "$pass_dir" ]] && return 0
|
||||||
|
|
||||||
declare -A legacy_map=(
|
declare -A legacy_map=(
|
||||||
|
|||||||
@ -95,6 +95,7 @@ EOF
|
|||||||
"source/files/app_files.sh"|"source/files/cli_files.sh"| \
|
"source/files/app_files.sh"|"source/files/cli_files.sh"| \
|
||||||
"source/loading/check_files.sh"|"source/loading/initilize_files.sh"| \
|
"source/loading/check_files.sh"|"source/loading/initilize_files.sh"| \
|
||||||
"source/loading/scan_files.sh"|"source/load_sources.sh"| \
|
"source/loading/scan_files.sh"|"source/load_sources.sh"| \
|
||||||
|
"source/paths.sh"| \
|
||||||
"source/files/generate_arrays.sh")
|
"source/files/generate_arrays.sh")
|
||||||
continue
|
continue
|
||||||
;;
|
;;
|
||||||
|
|||||||
62
scripts/source/paths.sh
Normal file
62
scripts/source/paths.sh
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# LibrePortal path roots — single source of truth for the (relocatable) layout.
|
||||||
|
#
|
||||||
|
# Three independently-placeable roots, each owned by exactly one principal:
|
||||||
|
# LP_SYSTEM_DIR control plane — manager (libreportal) owned, 750
|
||||||
|
# configs/ logs/ install/ database.db ssl/ ssh/ migrate/ restore/
|
||||||
|
# LP_CONTAINERS_DIR live app data — container user (dockerinstall) owned (rootless)
|
||||||
|
# LP_BACKUPS_DIR restic/kopia repos — container user owned (separable / own mount)
|
||||||
|
#
|
||||||
|
# The roots come from the environment when set (the install bakes them into the
|
||||||
|
# task-processor systemd unit, and the CLI/app inherit them from init.sh), else
|
||||||
|
# they default to /libreportal-*. A custom location is chosen at INSTALL time and
|
||||||
|
# baked by root — never read at runtime from a manager-writable config.
|
||||||
|
#
|
||||||
|
# SECURITY: the root-owned helpers under /usr/local/lib/libreportal/ do NOT source
|
||||||
|
# this file. They get the paths baked in at install (sed placeholders), so the
|
||||||
|
# manager cannot redirect a root `chown`/`chmod` by editing config. This file is
|
||||||
|
# only for the manager-run code (app, CLI, task processor), which runs without
|
||||||
|
# extra privilege.
|
||||||
|
#
|
||||||
|
# Mirror copy: init.sh derives the same vars inline (it is self-contained for the
|
||||||
|
# bare /root/init.sh reinstall case, where scripts/ isn't alongside). Keep the two
|
||||||
|
# derivations in sync.
|
||||||
|
|
||||||
|
# --- Resolve the three roots ------------------------------------------------
|
||||||
|
# Transitional compat: an EXISTING install (the legacy single /docker tree,
|
||||||
|
# identified by its config marker) keeps using /docker until a deliberate
|
||||||
|
# reinstall to the split layout — so deploying new code never strands a running
|
||||||
|
# box. Fresh installs (no marker) get the /libreportal-* split.
|
||||||
|
if [[ -z "${LP_SYSTEM_DIR:-}" ]]; then
|
||||||
|
if [[ ! -e /libreportal-system && -f /docker/configs/general/general_docker_install ]]; then
|
||||||
|
LP_SYSTEM_DIR=/docker
|
||||||
|
: "${LP_CONTAINERS_DIR:=/docker/containers}"
|
||||||
|
: "${LP_BACKUPS_DIR:=/docker/backups}"
|
||||||
|
else
|
||||||
|
LP_SYSTEM_DIR=/libreportal-system
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
: "${LP_CONTAINERS_DIR:=/libreportal-containers}"
|
||||||
|
: "${LP_BACKUPS_DIR:=/libreportal-backups}"
|
||||||
|
|
||||||
|
# --- Derived: system tree (manager-owned). docker_dir is the legacy name. ---
|
||||||
|
docker_dir="$LP_SYSTEM_DIR"
|
||||||
|
system_dir="$LP_SYSTEM_DIR"
|
||||||
|
configs_dir="$LP_SYSTEM_DIR/configs/"
|
||||||
|
logs_dir="$LP_SYSTEM_DIR/logs/"
|
||||||
|
ssl_dir="$LP_SYSTEM_DIR/ssl/"
|
||||||
|
ssh_dir="$LP_SYSTEM_DIR/ssh/"
|
||||||
|
wireguard_dir="$LP_SYSTEM_DIR/wireguard/"
|
||||||
|
migrate_dir="$LP_SYSTEM_DIR/migrate"
|
||||||
|
restore_dir="$LP_SYSTEM_DIR/restore"
|
||||||
|
script_dir="$LP_SYSTEM_DIR/install"
|
||||||
|
install_configs_dir="$script_dir/configs/"
|
||||||
|
install_containers_dir="$script_dir/containers/"
|
||||||
|
install_scripts_dir="$script_dir/scripts/"
|
||||||
|
|
||||||
|
# --- Derived: data tree (container-user-owned) — the root IS the dir ---------
|
||||||
|
containers_dir="$LP_CONTAINERS_DIR/"
|
||||||
|
|
||||||
|
# --- Derived: backups tree (container-user-owned; own mount-able) -----------
|
||||||
|
backup_dir="$LP_BACKUPS_DIR"
|
||||||
@ -13,7 +13,7 @@ atomicWriteWebUI() {
|
|||||||
# can write the dockerinstall-owned WebUI/app files. Temp + rename share the
|
# can write the dockerinstall-owned WebUI/app files. Temp + rename share the
|
||||||
# target's directory, so the mv stays atomic (same filesystem, same owner).
|
# target's directory, so the mv stays atomic (same filesystem, same owner).
|
||||||
local op="runInstallOp" wop="runInstallWrite"
|
local op="runInstallOp" wop="runInstallWrite"
|
||||||
if [[ "$target_file" == "$containers_dir"* || "$target_file" == /docker/containers/* ]]; then
|
if [[ "$target_file" == "$containers_dir"* || "$target_file" == "${LP_CONTAINERS_DIR:-/libreportal-containers}"/* ]]; then
|
||||||
op="runFileOp"; wop="runFileWrite"
|
op="runFileOp"; wop="runFileWrite"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
9
start.sh
9
start.sh
@ -34,6 +34,11 @@ showRunHelp()
|
|||||||
|
|
||||||
initLibrePortal()
|
initLibrePortal()
|
||||||
{
|
{
|
||||||
|
# Load the relocatable path roots up front (sets logs_dir/docker_dir/…) — the
|
||||||
|
# install-log below needs logs_dir before load_sources runs. cwd is the install
|
||||||
|
# dir, so the relative path resolves.
|
||||||
|
[[ -f "scripts/source/paths.sh" ]] && source "scripts/source/paths.sh"
|
||||||
|
|
||||||
# For the full application loading
|
# For the full application loading
|
||||||
if [[ "$initial_command1" == "run" ]]; then
|
if [[ "$initial_command1" == "run" ]]; then
|
||||||
if [[ -z "$initial_command2" ]]; then
|
if [[ -z "$initial_command2" ]]; then
|
||||||
@ -46,8 +51,8 @@ initLibrePortal()
|
|||||||
# Capture the install run to a log so credentials/URLs can be recovered
|
# Capture the install run to a log so credentials/URLs can be recovered
|
||||||
# after we clear the screen at the end.
|
# after we clear the screen at the end.
|
||||||
if [[ "$initial_command2" == "install" ]]; then
|
if [[ "$initial_command2" == "install" ]]; then
|
||||||
install_log_path="/docker/logs/install-$(date +%Y%m%d-%H%M%S).log"
|
install_log_path="${logs_dir:-/libreportal-system/logs/}install-$(date +%Y%m%d-%H%M%S).log"
|
||||||
sudo mkdir -p /docker/logs 2>/dev/null
|
sudo mkdir -p "${logs_dir:-/libreportal-system/logs/}" 2>/dev/null
|
||||||
sudo touch "$install_log_path" 2>/dev/null
|
sudo touch "$install_log_path" 2>/dev/null
|
||||||
# Own it by whoever runs the install (the manager under Model A) so the
|
# Own it by whoever runs the install (the manager under Model A) so the
|
||||||
# tee below — which runs as that user, not root — can append. A
|
# tee below — which runs as that user, not root — can append. A
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user