refactor(paths): single source of truth for a relocatable, split layout (phase 1)
Introduce scripts/source/paths.sh as the canonical path resolver for three independently-relocatable roots: LP_SYSTEM_DIR manager-owned control plane (configs/logs/install/db/ssl/ssh/migrate) LP_CONTAINERS_DIR container-user-owned live app data LP_BACKUPS_DIR container-user-owned backup repos (own mount-able) Roots come from the environment when set (install bakes them; CLI/app inherit from init.sh), else default to /libreportal-*. A transitional compat default keeps EXISTING installs (legacy single /docker tree, by config marker) on /docker until a deliberate reinstall, so deploying this never strands a running box. - init.sh derives the same vars inline (self-contained for the bare /root/init.sh reinstall case); paths.sh mirrors it for the standalone task/check processors, which now self-locate their scripts dir and source it. - Replace functional /docker literals with the derived vars across runtime, install, backup, crontab, crowdsec/restic, headscale, and reinstall paths; clean the inert '== /docker/containers/*' guard fallbacks to the variable form. - backend: CONTAINERS_DIR now from LP_CONTAINERS_DIR (compose env, filled at generation via a new CONTAINERS_DIR_TAG), legacy-safe default for un-recreated containers. - backup default path falls back to the backups root; exclude paths.sh from the sourced-file arrays (bootstrap file, sourced explicitly). The CLI-wrapper heredoc + root helpers still reference /docker; those get baked in phase 3. No layout/ownership change yet (phase 2). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> Signed-off-by: librelad <librelad@digitalangels.vip>
This commit is contained in:
parent
3190a4584a
commit
e4872ab511
@ -2,7 +2,7 @@
|
||||
# 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_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_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
|
||||
|
||||
@ -32,7 +32,11 @@ const router = express.Router();
|
||||
|
||||
const TASKS_DIR = path.join(__dirname, '..', '..', 'frontend', 'data', 'tasks');
|
||||
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');
|
||||
|
||||
// =====================================================================
|
||||
|
||||
@ -31,6 +31,7 @@ services:
|
||||
environment:
|
||||
FRONTEND_PATH: /data/frontend
|
||||
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
|
||||
labels:
|
||||
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_symlink="/usr/local/bin/libreportal"
|
||||
|
||||
# Directories
|
||||
docker_dir="/docker"
|
||||
containers_dir="$docker_dir/containers/"
|
||||
ssl_dir="$docker_dir/ssl/"
|
||||
ssh_dir="$docker_dir/ssh/"
|
||||
wireguard_dir="$docker_dir/wireguard/"
|
||||
logs_dir="$docker_dir/logs/"
|
||||
configs_dir="$docker_dir/configs/"
|
||||
backup_dir="$docker_dir/backups"
|
||||
restore_dir="$docker_dir/restore"
|
||||
migrate_dir="$docker_dir/migrate"
|
||||
# Install Scripts
|
||||
script_dir="$docker_dir/install"
|
||||
install_configs_dir="$script_dir/configs/"
|
||||
install_containers_dir="$script_dir/containers/"
|
||||
install_scripts_dir="$script_dir/scripts/"
|
||||
# Directories — three independently-relocatable roots (see scripts/source/paths.sh
|
||||
# for the canonical description). Defaults below; overridden by --system-dir /
|
||||
# --containers-dir / --backups-dir (parsed in the flag loop) via the LP_*_DIR
|
||||
# vars. init.sh derives inline (kept in sync with paths.sh) because the bare
|
||||
# /root/init.sh reinstall copy has no scripts/ alongside to source.
|
||||
# LP_SYSTEM_DIR — manager-owned control plane (configs/logs/install/db/…)
|
||||
# LP_CONTAINERS_DIR — container-user-owned live app data
|
||||
# LP_BACKUPS_DIR — container-user-owned backup repos (own mount-able)
|
||||
libreportalDerivePaths() {
|
||||
# Transitional compat: an existing install (legacy single /docker tree,
|
||||
# identified by its config marker) keeps using /docker until a deliberate
|
||||
# reinstall — so deploying new code never strands a running box.
|
||||
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}"
|
||||
|
||||
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
|
||||
init_shift_count=0
|
||||
|
||||
@ -52,7 +52,7 @@ backupLocationsMigrate()
|
||||
runFileOp chown "$owner":"$owner" "$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=""
|
||||
if [[ -f "$old_pass" ]]; then
|
||||
pass_value=$(runFileOp cat "$old_pass" | tr -d '\n\r')
|
||||
@ -75,7 +75,7 @@ backupLocationsMigrate()
|
||||
replacePlainPasswords "$cfg_file"
|
||||
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
|
||||
new_kopia=$(backupLocationKopiaConfig "$idx")
|
||||
if [[ -f "$old_kopia" ]]; then
|
||||
@ -85,7 +85,7 @@ backupLocationsMigrate()
|
||||
isNotice "Moved kopia state for location $idx → $new_kopia"
|
||||
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
|
||||
new_ssh=$(backupLocationSshKey "$idx")
|
||||
if [[ -f "$old_ssh" ]]; then
|
||||
|
||||
@ -69,7 +69,7 @@ backupLocationResolvedPath()
|
||||
if [[ "$mode" == "auto" ]]; then
|
||||
# Base dir is the configurable Default Backup Location (Backup Engine
|
||||
# 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}"
|
||||
else
|
||||
resticLocationField "$idx" PATH
|
||||
|
||||
@ -51,6 +51,6 @@ tagsManagerUpdateUniversalTag()
|
||||
# manager-owned configs/ + install templates use runInstallOp. The read
|
||||
# (awk above) needs no escalation — config/compose files are world-readable.
|
||||
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"
|
||||
}
|
||||
|
||||
@ -21,6 +21,9 @@ tagsProcessorStandardReplacements()
|
||||
tagsManagerUpdateUniversalTag "$full_file_path" "DOMAINSUBNAME_TAG" "$host_setup"
|
||||
tagsManagerUpdateUniversalTag "$full_file_path" "TIMEZONE_TAG" "$CFG_TIMEZONE"
|
||||
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"
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
crontabClean()
|
||||
{
|
||||
# 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
|
||||
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
|
||||
# crontab_task_processor.sh. These files are pure function/var defs, safe to
|
||||
# source.
|
||||
LP_SCRIPTS="${install_scripts_dir:-/docker/install/scripts/}"
|
||||
LP_DOCKER_CFG="/docker/configs/general/general_docker_install"
|
||||
# Self-locate the scripts dir, then load the relocatable path roots (sets
|
||||
# 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" ]] && \
|
||||
eval "$(grep -E '^CFG_DOCKER_INSTALL_(TYPE|USER)=' "$LP_DOCKER_CFG" | sed 's/[[:space:]]*#.*//')"
|
||||
: "${sudo_user_name:=libreportal}"
|
||||
: "${containers_dir:=/docker/containers/}"
|
||||
: "${docker_dir:=/docker}"
|
||||
: "${containers_dir:=/libreportal-containers/}"
|
||||
: "${docker_dir:=/libreportal-system}"
|
||||
for _lp_f in docker/command/run_privileged.sh \
|
||||
docker/command/docker_run_install.sh \
|
||||
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)
|
||||
TASK_DIR=""
|
||||
if [[ "$TASK_DIR" == "" ]]; then
|
||||
TASK_DIR="/docker/containers/libreportal/frontend/data/tasks"
|
||||
TASK_DIR="${containers_dir:-/libreportal-containers/}libreportal/frontend/data/tasks"
|
||||
fi
|
||||
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
|
||||
# forever. Load them here — these files are pure function/var defs, safe to
|
||||
# source, no side effects.
|
||||
LP_SCRIPTS="${install_scripts_dir:-/docker/install/scripts/}"
|
||||
LP_DOCKER_CFG="/docker/configs/general/general_docker_install"
|
||||
# Self-locate the scripts dir (where systemd launched us) so we can load the
|
||||
# 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" ]] && \
|
||||
eval "$(grep -E '^CFG_DOCKER_INSTALL_(TYPE|USER)=' "$LP_DOCKER_CFG" | sed 's/[[:space:]]*#.*//')"
|
||||
: "${sudo_user_name:=libreportal}"
|
||||
: "${containers_dir:=/docker/containers/}"
|
||||
: "${docker_dir:=/docker}"
|
||||
: "${containers_dir:=/libreportal-containers/}"
|
||||
: "${docker_dir:=/libreportal-system}"
|
||||
for _lp_f in docker/command/run_privileged.sh \
|
||||
docker/command/docker_run_install.sh \
|
||||
checks/requirements/check_install_type.sh; do
|
||||
@ -50,7 +56,7 @@ command -v resolveDockerInstallUser >/dev/null 2>&1 && resolveDockerInstallUser
|
||||
# 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"
|
||||
FIFO="$TASK_DIR/.queue.fifo"
|
||||
LOG_FILE="$TASK_DIR/task_processor.log"
|
||||
|
||||
@ -101,7 +101,7 @@ _runRootHelper() {
|
||||
if [[ -x "$helper" ]]; then
|
||||
sudo "$helper" "$@"
|
||||
elif [[ $EUID -eq 0 ]]; then
|
||||
bash "${script_dir:-/docker/install}/scripts/system/$name" "$@"
|
||||
bash "${script_dir:-/libreportal-system/install}/scripts/system/$name" "$@"
|
||||
else
|
||||
sudo "$helper" "$@"
|
||||
fi
|
||||
|
||||
@ -17,7 +17,7 @@ copyFile()
|
||||
# the manager-owned control plane (configs/logs/etc.) is runInstallOp.
|
||||
# Mirrors createTouch's path-based ownership; $user_name is now advisory.
|
||||
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
|
||||
local result=$($op cp $flags_full "$file" "$save_dir")
|
||||
|
||||
@ -9,7 +9,7 @@ copyFiles()
|
||||
|
||||
# Write as the destination's owner (see copyFile).
|
||||
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))
|
||||
if [ ${#files[@]} -eq 0 ]; then
|
||||
|
||||
@ -21,7 +21,7 @@ createTouch()
|
||||
local file_dir=$(dirname "$clean_file")
|
||||
|
||||
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"
|
||||
fi
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ moveFile()
|
||||
if [ -e "$file" ]; then
|
||||
# Move as the destination's owner — no root, no chown (see copyFile).
|
||||
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")
|
||||
checkSuccess "Moving $file_name to $save_dir"
|
||||
else
|
||||
|
||||
@ -8,8 +8,8 @@ copyFolder()
|
||||
local user_name="$3" # advisory — the destination path determines the owner
|
||||
|
||||
# Write as the destination's owner — no root, no chown (see copyFile).
|
||||
if [[ "$save_dir" == "$containers_dir"* || "$save_dir" == /docker/containers/* ]]; then
|
||||
if [[ "$folder" == "$containers_dir"* || "$folder" == /docker/containers/* ]]; then
|
||||
if [[ "$save_dir" == "$containers_dir"* || "$save_dir" == "${LP_CONTAINERS_DIR:-/libreportal-containers}"/* ]]; then
|
||||
if [[ "$folder" == "$containers_dir"* || "$folder" == "${LP_CONTAINERS_DIR:-/libreportal-containers}"/* ]]; then
|
||||
# container -> container: same owner (dockerinstall), a plain cp works.
|
||||
local result=$(runFileOp cp -rf "$folder" "$save_dir")
|
||||
else
|
||||
|
||||
@ -8,7 +8,7 @@ copyFolders()
|
||||
|
||||
# Write as the destination's owner — no root, no chown (see copyFile).
|
||||
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))
|
||||
if [ ${#subdirs[@]} -eq 0 ]; then
|
||||
|
||||
@ -14,7 +14,7 @@ createFolders()
|
||||
# AS that user via runFileOp — creating it as the right owner avoids a
|
||||
# chown-to-another-user the unprivileged runtime can't do. Mirrors
|
||||
# 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
|
||||
local result=$(runFileOp mkdir -p "$dir_path")
|
||||
[ "$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"
|
||||
|
||||
# Try HTTPS first
|
||||
if runAsManager git clone -q "$AUTH_HTTPS_REPO_URL" "/docker/install" 2>/dev/null; then
|
||||
runSystem cp -f /docker/install/init.sh /root/
|
||||
echo "SUCCESS: Git repository cloned via HTTPS into /docker/install."
|
||||
if runAsManager git clone -q "$AUTH_HTTPS_REPO_URL" "$script_dir" 2>/dev/null; then
|
||||
runSystem cp -f "$script_dir/init.sh" /root/
|
||||
echo "SUCCESS: Git repository cloned via HTTPS into $script_dir."
|
||||
echo ""
|
||||
echo "SUCCESS: Reinstallation complete, you can now run the "libreportal run" command."
|
||||
echo ""
|
||||
else
|
||||
# If HTTPS fails, try HTTP
|
||||
if runAsManager git clone -q "$AUTH_HTTP_REPO_URL" "/docker/install" 2>/dev/null; then
|
||||
runSystem cp -f /docker/install/init.sh /root/
|
||||
echo "SUCCESS: Git repository cloned via HTTP into /docker/install."
|
||||
if runAsManager git clone -q "$AUTH_HTTP_REPO_URL" "$script_dir" 2>/dev/null; then
|
||||
runSystem cp -f "$script_dir/init.sh" /root/
|
||||
echo "SUCCESS: Git repository cloned via HTTP into $script_dir."
|
||||
echo ""
|
||||
echo "SUCCESS: Reinstallation complete, you can now run the "libreportal run" command."
|
||||
echo ""
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
setupHeadscaleGenerateAuthKey()
|
||||
{
|
||||
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:]')
|
||||
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.
|
||||
crowdsecToggleLibrePortalLogMounts() {
|
||||
local mode="$1"
|
||||
local compose="/docker/containers/libreportal/docker-compose.yml"
|
||||
local compose="${containers_dir}libreportal/docker-compose.yml"
|
||||
[[ -f "$compose" ]] || return 0
|
||||
|
||||
case "$mode" in
|
||||
@ -24,7 +24,7 @@ crowdsecToggleLibrePortalLogMounts() {
|
||||
|
||||
if runFileOp docker ps --format '{{.Names}}' 2>/dev/null | grep -q '^libreportal-service$'; then
|
||||
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
|
||||
}
|
||||
|
||||
@ -215,7 +215,7 @@ installCrowdsecHost()
|
||||
# (use the rotate Tools action for that); this is a visibility
|
||||
# surface, not the auth source of truth.
|
||||
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
|
||||
local bouncer_key
|
||||
|
||||
@ -22,7 +22,7 @@ installResticHost()
|
||||
|
||||
installResticMigrateLegacyPasswords()
|
||||
{
|
||||
local pass_dir="/docker/configs/security/restic"
|
||||
local pass_dir="${configs_dir}security/restic"
|
||||
[[ ! -d "$pass_dir" ]] && return 0
|
||||
|
||||
declare -A legacy_map=(
|
||||
|
||||
@ -95,6 +95,7 @@ EOF
|
||||
"source/files/app_files.sh"|"source/files/cli_files.sh"| \
|
||||
"source/loading/check_files.sh"|"source/loading/initilize_files.sh"| \
|
||||
"source/loading/scan_files.sh"|"source/load_sources.sh"| \
|
||||
"source/paths.sh"| \
|
||||
"source/files/generate_arrays.sh")
|
||||
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
|
||||
# target's directory, so the mv stays atomic (same filesystem, same owner).
|
||||
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"
|
||||
fi
|
||||
|
||||
|
||||
9
start.sh
9
start.sh
@ -34,6 +34,11 @@ showRunHelp()
|
||||
|
||||
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
|
||||
if [[ "$initial_command1" == "run" ]]; then
|
||||
if [[ -z "$initial_command2" ]]; then
|
||||
@ -46,8 +51,8 @@ initLibrePortal()
|
||||
# Capture the install run to a log so credentials/URLs can be recovered
|
||||
# after we clear the screen at the end.
|
||||
if [[ "$initial_command2" == "install" ]]; then
|
||||
install_log_path="/docker/logs/install-$(date +%Y%m%d-%H%M%S).log"
|
||||
sudo mkdir -p /docker/logs 2>/dev/null
|
||||
install_log_path="${logs_dir:-/libreportal-system/logs/}install-$(date +%Y%m%d-%H%M%S).log"
|
||||
sudo mkdir -p "${logs_dir:-/libreportal-system/logs/}" 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
|
||||
# tee below — which runs as that user, not root — can append. A
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user