Merge pull request #396 from outis1one/claude/frigate-authelia-openid-0l1htj
Claude/frigate authelia openid 0l1htj
This commit is contained in:
@@ -493,6 +493,7 @@ right (Portainer, ntfy), not general familiarity with the product:
|
|||||||
| Service | Native OIDC? | Notes |
|
| Service | Native OIDC? | Notes |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `mealie` | Yes — wired up | Pure env vars (`OIDC_AUTH_ENABLED`, `OIDC_CLIENT_ID/SECRET`, `OIDC_CONFIGURATION_URL`), see `_mealie_offer_authelia_oidc()`. Redirect URI is `<BASE_URL>/login`. Needs a `--forwarded-allow-ips` entrypoint override when Caddy-fronted, or the generated redirect URI comes out `http://` even when actually served over `https://` — see the function's own comment. |
|
| `mealie` | Yes — wired up | Pure env vars (`OIDC_AUTH_ENABLED`, `OIDC_CLIENT_ID/SECRET`, `OIDC_CONFIGURATION_URL`), see `_mealie_offer_authelia_oidc()`. Redirect URI is `<BASE_URL>/login`. Needs a `--forwarded-allow-ips` entrypoint override when Caddy-fronted, or the generated redirect URI comes out `http://` even when actually served over `https://` — see the function's own comment. |
|
||||||
|
| `homebox` | Yes — wired up | Pure env vars (`HBOX_OIDC_ENABLED`, `HBOX_OIDC_ISSUER_URL`, `HBOX_OIDC_CLIENT_ID/SECRET`, `HBOX_OIDC_SCOPE`), see `_homebox_offer_authelia_oidc()`. Confirmed against homebox.software's own OIDC docs and authelia.com's Homebox integration page — needs PKCE (unlike Mealie/ActualBudget). Redirect path is `/api/v1/users/login/oidc/callback`; issuer URL is reportedly sensitive to a trailing slash (a real upstream bug), so it's written from this repo's own portal-URL value as-is, never with one appended. The stock compose template didn't have `env_file: .env` (vars were listed individually in `environment:` instead) — added to the template, and patched onto any pre-existing install's compose file the first time this offer runs, or the written `.env` additions would silently never reach the container. `HBOX_OPTIONS_ALLOW_LOCAL_LOGIN=false`/`HBOX_OIDC_AUTO_REDIRECT=true` are real, documented env vars for fully replacing local login, offered as a separate step gated behind the same "have you tested the button first" confirmation as Mealie/Beszel. |
|
||||||
| `actualbudget` | Yes — wired up | Pure env vars (`ACTUAL_OPENID_DISCOVERY_URL`, `ACTUAL_OPENID_CLIENT_ID/SECRET`, `ACTUAL_OPENID_SERVER_HOSTNAME`), see `_actualbudget_offer_authelia_oidc()`. Redirect path `/openid/callback` (matches the existing preset in `_authelia_add_oidc_client()`'s menu). First OIDC login becomes the server owner if none is set yet — Actual's own behavior. |
|
| `actualbudget` | Yes — wired up | Pure env vars (`ACTUAL_OPENID_DISCOVERY_URL`, `ACTUAL_OPENID_CLIENT_ID/SECRET`, `ACTUAL_OPENID_SERVER_HOSTNAME`), see `_actualbudget_offer_authelia_oidc()`. Redirect path `/openid/callback` (matches the existing preset in `_authelia_add_oidc_client()`'s menu). First OIDC login becomes the server owner if none is set yet — Actual's own behavior. |
|
||||||
| `immich` | Yes — wired up | Real OAuth2/OIDC settings under Administration → Settings, backed by `GET`/`PUT /api/system-config` — confirmed the exact JSON field names against Immich's own `config-file.md` and source directly (the `oauth` sub-object: `enabled`/`issuerUrl`/`clientId`/`clientSecret`/`scope`/`buttonText`, etc.), not guessed. See `_immich_offer_authelia_oidc()`. GET/PUT exchange the *whole* config object (no partial-patch endpoint), so it round-trips everything else — storage template, library settings — completely unchanged; the same shape already proven by `import-photos.sh`'s own storage-template step in this file. Needs an admin API key, which doesn't exist until the user creates their account on first web visit — this offer runs from both the fresh-install path (usually a no-op that first time) and the "update" rerun path, which is the realistic way most people finish this. |
|
| `immich` | Yes — wired up | Real OAuth2/OIDC settings under Administration → Settings, backed by `GET`/`PUT /api/system-config` — confirmed the exact JSON field names against Immich's own `config-file.md` and source directly (the `oauth` sub-object: `enabled`/`issuerUrl`/`clientId`/`clientSecret`/`scope`/`buttonText`, etc.), not guessed. See `_immich_offer_authelia_oidc()`. GET/PUT exchange the *whole* config object (no partial-patch endpoint), so it round-trips everything else — storage template, library settings — completely unchanged; the same shape already proven by `import-photos.sh`'s own storage-template step in this file. Needs an admin API key, which doesn't exist until the user creates their account on first web visit — this offer runs from both the fresh-install path (usually a no-op that first time) and the "update" rerun path, which is the realistic way most people finish this. |
|
||||||
| `audiobookshelf` | Yes — wired up (Authelia side only) | Checked against audiobookshelf.org's own OIDC docs: config is UI-only (Settings → Authentication), no env var or config API — so `_audiobookshelf_offer_authelia_oidc()` registers the Authelia client (needs PKCE, confirmed via authelia.com's own integration page for it) and prints the exact individual-endpoint values to paste in, since Audiobookshelf wants those rather than a discovery URL. Three redirect URIs: web callback, mobile-redirect, and the `audiobookshelf://oauth` app-scheme callback. |
|
| `audiobookshelf` | Yes — wired up (Authelia side only) | Checked against audiobookshelf.org's own OIDC docs: config is UI-only (Settings → Authentication), no env var or config API — so `_audiobookshelf_offer_authelia_oidc()` registers the Authelia client (needs PKCE, confirmed via authelia.com's own integration page for it) and prints the exact individual-endpoint values to paste in, since Audiobookshelf wants those rather than a discovery URL. Three redirect URIs: web callback, mobile-redirect, and the `audiobookshelf://oauth` app-scheme callback. |
|
||||||
|
|||||||
@@ -802,6 +802,32 @@ write_readme() {
|
|||||||
chown "$ACTUAL_USER:$ACTUAL_USER" "$dir/README.md" 2>/dev/null || true
|
chown "$ACTUAL_USER:$ACTUAL_USER" "$dir/README.md" 2>/dev/null || true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Copies FILE to FILE.bak.<timestamp> if it already exists, right before a
|
||||||
|
# caller is about to overwrite it with a fresh `cat > FILE` heredoc. No-ops
|
||||||
|
# in DRY_RUN and silently no-ops if FILE doesn't exist yet (first install,
|
||||||
|
# nothing to save) — safe to call unconditionally right before every such
|
||||||
|
# write, fresh install or not.
|
||||||
|
#
|
||||||
|
# Confirmed live: install_frigate()'s fresh-install path overwrote a
|
||||||
|
# working, hand-crafted multi-container docker-compose.yml (Frigate +
|
||||||
|
# mosquitto + frigate-notify) with zero backup, because that file's shape
|
||||||
|
# didn't match what the service's own "existing install" detection knew
|
||||||
|
# how to recognize. Every service's own detection logic is a judgment call
|
||||||
|
# about what counts as "already installed" and can miss a real setup built
|
||||||
|
# outside this repo's own conventions — this exists as the safety net
|
||||||
|
# underneath that judgment call, not a replacement for it: call it right
|
||||||
|
# before any `cat > FILE` that could clobber something a user already has,
|
||||||
|
# so a wrong detection costs a `.bak` file to restore from instead of the
|
||||||
|
# original silently disappearing.
|
||||||
|
backup_if_exists() {
|
||||||
|
local file="$1"
|
||||||
|
[ "$DRY_RUN" = true ] && return 0
|
||||||
|
[ -f "$file" ] || return 0
|
||||||
|
local backup="${file}.bak.$(date +%Y%m%d-%H%M%S)"
|
||||||
|
cp -p "$file" "$backup" 2>/dev/null \
|
||||||
|
&& log_info "Backed up existing $(basename "$file") to $(basename "$backup")"
|
||||||
|
}
|
||||||
|
|
||||||
# ── Host port collision avoidance (shared by every service that publishes a
|
# ── Host port collision avoidance (shared by every service that publishes a
|
||||||
# fixed host port) ────────────────────────────────────────────────────────────
|
# fixed host port) ────────────────────────────────────────────────────────────
|
||||||
# With 70+ services in this repo, several ship the same default port (e.g.
|
# With 70+ services in this repo, several ship the same default port (e.g.
|
||||||
|
|||||||
@@ -180,6 +180,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
||||||
@@ -388,6 +393,7 @@ networks:
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << AB_COMPOSE
|
cat > docker-compose.yml << AB_COMPOSE
|
||||||
name: $CONTAINER
|
name: $CONTAINER
|
||||||
|
|
||||||
@@ -405,6 +411,7 @@ services:
|
|||||||
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
||||||
AB_COMPOSE
|
AB_COMPOSE
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << AB_ENV
|
cat > .env << AB_ENV
|
||||||
TZ=$TZ_VAL
|
TZ=$TZ_VAL
|
||||||
CADDY_NET=$SITE_CADDY_NET
|
CADDY_NET=$SITE_CADDY_NET
|
||||||
|
|||||||
@@ -170,6 +170,11 @@ CBLOCK
|
|||||||
[[ "${DRY_RUN:-false}" == "true" ]] && return 0
|
[[ "${DRY_RUN:-false}" == "true" ]] && return 0
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
generate_password() {
|
generate_password() {
|
||||||
local _len="${1:-32}"
|
local _len="${1:-32}"
|
||||||
@@ -368,6 +373,7 @@ install_ai-gpu() {
|
|||||||
sed -i "s|America/New_York|$TZ_VAL|g" {} \;
|
sed -i "s|America/New_York|$TZ_VAL|g" {} \;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists "$IMAGE_GEN_DIR/.env"
|
||||||
cat > "$IMAGE_GEN_DIR/.env" << IMGENV
|
cat > "$IMAGE_GEN_DIR/.env" << IMGENV
|
||||||
# InvokeAI — image generation
|
# InvokeAI — image generation
|
||||||
TZ=${TZ_VAL}
|
TZ=${TZ_VAL}
|
||||||
@@ -407,6 +413,7 @@ IMGENV
|
|||||||
local WEBUI_SECRET
|
local WEBUI_SECRET
|
||||||
WEBUI_SECRET="$(generate_password 32)"
|
WEBUI_SECRET="$(generate_password 32)"
|
||||||
|
|
||||||
|
backup_if_exists "$LLM_DIR/.env"
|
||||||
cat > "$LLM_DIR/.env" << LLMENV
|
cat > "$LLM_DIR/.env" << LLMENV
|
||||||
# Ollama + Open WebUI + SearXNG
|
# Ollama + Open WebUI + SearXNG
|
||||||
TZ=${TZ_VAL}
|
TZ=${TZ_VAL}
|
||||||
@@ -441,6 +448,7 @@ LLMENV
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists "$PORTAL_DIR/.env"
|
||||||
cat > "$PORTAL_DIR/.env" << PORTALENV
|
cat > "$PORTAL_DIR/.env" << PORTALENV
|
||||||
# AI Portal — GPU stack swap controller
|
# AI Portal — GPU stack swap controller
|
||||||
TZ=${TZ_VAL}
|
TZ=${TZ_VAL}
|
||||||
|
|||||||
@@ -174,6 +174,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
||||||
@@ -240,6 +245,7 @@ networks:
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << ABCOMPOSE
|
cat > docker-compose.yml << ABCOMPOSE
|
||||||
name: archivebox
|
name: archivebox
|
||||||
|
|
||||||
@@ -262,6 +268,7 @@ services:
|
|||||||
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
||||||
ABCOMPOSE
|
ABCOMPOSE
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << ABENV
|
cat > .env << ABENV
|
||||||
CADDY_NET=$SITE_CADDY_NET
|
CADDY_NET=$SITE_CADDY_NET
|
||||||
ABENV
|
ABENV
|
||||||
|
|||||||
@@ -188,6 +188,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
||||||
@@ -278,6 +283,7 @@ networks:
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << ARM_COMPOSE
|
cat > docker-compose.yml << ARM_COMPOSE
|
||||||
name: arm
|
name: arm
|
||||||
|
|
||||||
@@ -306,6 +312,7 @@ services:
|
|||||||
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
||||||
ARM_COMPOSE
|
ARM_COMPOSE
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << ARM_ENV
|
cat > .env << ARM_ENV
|
||||||
ARM_OUTPUT=$ARM_OUTPUT
|
ARM_OUTPUT=$ARM_OUTPUT
|
||||||
CADDY_NET=$SITE_CADDY_NET
|
CADDY_NET=$SITE_CADDY_NET
|
||||||
|
|||||||
@@ -255,6 +255,11 @@ CBLOCK
|
|||||||
[[ "${DRY_RUN:-false}" == "true" ]] && return 0
|
[[ "${DRY_RUN:-false}" == "true" ]] && return 0
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
generate_password() {
|
generate_password() {
|
||||||
local _len="${1:-32}"
|
local _len="${1:-32}"
|
||||||
@@ -1588,6 +1593,7 @@ _asterisk_write_compose() {
|
|||||||
"
|
"
|
||||||
[[ "$USE_EMBEDDED_COTURN" != true ]] && _COTURN_DEPENDS="" && _COTURN_SERVICE=""
|
[[ "$USE_EMBEDDED_COTURN" != true ]] && _COTURN_DEPENDS="" && _COTURN_SERVICE=""
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << EOF
|
cat > docker-compose.yml << EOF
|
||||||
name: PROJECT_NAME_PLACEHOLDER
|
name: PROJECT_NAME_PLACEHOLDER
|
||||||
|
|
||||||
@@ -2727,6 +2733,7 @@ install_asterisk() {
|
|||||||
# WireGuard/Tailscale) on a subnet this box isn't directly attached to."
|
# WireGuard/Tailscale) on a subnet this box isn't directly attached to."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << ENV
|
cat > .env << ENV
|
||||||
# ── Domain ────────────────────────────────────────────────────
|
# ── Domain ────────────────────────────────────────────────────
|
||||||
# ${_domain_comment}
|
# ${_domain_comment}
|
||||||
|
|||||||
@@ -180,6 +180,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
||||||
@@ -379,6 +384,7 @@ networks:
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << ABS_COMPOSE
|
cat > docker-compose.yml << ABS_COMPOSE
|
||||||
name: $CONTAINER
|
name: $CONTAINER
|
||||||
|
|
||||||
@@ -400,6 +406,7 @@ services:
|
|||||||
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
||||||
ABS_COMPOSE
|
ABS_COMPOSE
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << ABS_ENV
|
cat > .env << ABS_ENV
|
||||||
AUDIOBOOKS_PATH=$AUDIOBOOKS_PATH
|
AUDIOBOOKS_PATH=$AUDIOBOOKS_PATH
|
||||||
PODCASTS_PATH=./podcasts
|
PODCASTS_PATH=./podcasts
|
||||||
|
|||||||
@@ -186,6 +186,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
||||||
@@ -408,6 +413,7 @@ install_authelia() {
|
|||||||
cd "$AUTHELIA_DIR" || return 1
|
cd "$AUTHELIA_DIR" || return 1
|
||||||
|
|
||||||
# ── .env ─────────────────────────────────────────────────────────────────
|
# ── .env ─────────────────────────────────────────────────────────────────
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << AUTHELIA_ENV
|
cat > .env << AUTHELIA_ENV
|
||||||
MY_DOMAIN=${AUTHELIA_DOMAIN}
|
MY_DOMAIN=${AUTHELIA_DOMAIN}
|
||||||
SMTP_USER=${AUTHELIA_SMTP_USER}
|
SMTP_USER=${AUTHELIA_SMTP_USER}
|
||||||
@@ -416,6 +422,7 @@ TZ=${AUTHELIA_TZ}
|
|||||||
AUTHELIA_ENV
|
AUTHELIA_ENV
|
||||||
|
|
||||||
# ── docker-compose.yml (quoted heredoc: ${SMTP_USER} resolved by compose/.env) ──
|
# ── docker-compose.yml (quoted heredoc: ${SMTP_USER} resolved by compose/.env) ──
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << 'AUTHELIA_COMPOSE'
|
cat > docker-compose.yml << 'AUTHELIA_COMPOSE'
|
||||||
name: authelia
|
name: authelia
|
||||||
|
|
||||||
|
|||||||
@@ -120,6 +120,11 @@ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|||||||
local _companion; _companion="$(dirname "${BASH_SOURCE[0]}")/beszel.md"
|
local _companion; _companion="$(dirname "${BASH_SOURCE[0]}")/beszel.md"
|
||||||
[ -f "$_companion" ] && cat "$_companion" >> "$_dir/README.md"
|
[ -f "$_companion" ] && cat "$_companion" >> "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
||||||
@@ -458,6 +463,7 @@ networks:
|
|||||||
# profile recognizes. security_opt: apparmor:unconfined below is
|
# profile recognizes. security_opt: apparmor:unconfined below is
|
||||||
# Beszel's own documented fix (beszel.dev/guide/systemd#apparmor-error)
|
# Beszel's own documented fix (beszel.dev/guide/systemd#apparmor-error)
|
||||||
# — confirmed live, this exact error on a real box.
|
# — confirmed live, this exact error on a real box.
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << BESZEL_COMPOSE
|
cat > docker-compose.yml << BESZEL_COMPOSE
|
||||||
name: beszel
|
name: beszel
|
||||||
|
|
||||||
@@ -504,6 +510,7 @@ BESZEL_COMPOSE
|
|||||||
# README). Not threaded through automatically here because Caddy setup
|
# README). Not threaded through automatically here because Caddy setup
|
||||||
# (below) happens after this file is written, same ordering every
|
# (below) happens after this file is written, same ordering every
|
||||||
# other service in this repo uses for its own Caddy prompt.
|
# other service in this repo uses for its own Caddy prompt.
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << BESZEL_ENV
|
cat > .env << BESZEL_ENV
|
||||||
TZ=${SITE_TZ:-$(cat /etc/timezone 2>/dev/null || echo UTC)}
|
TZ=${SITE_TZ:-$(cat /etc/timezone 2>/dev/null || echo UTC)}
|
||||||
CADDY_NET=$SITE_CADDY_NET
|
CADDY_NET=$SITE_CADDY_NET
|
||||||
@@ -678,6 +685,7 @@ install_beszel-agent() {
|
|||||||
# and there's no caddy_net to conditionally join since this box never
|
# and there's no caddy_net to conditionally join since this box never
|
||||||
# runs a web UI of its own. See that function's own comment for why the
|
# runs a web UI of its own. See that function's own comment for why the
|
||||||
# systemd/dbus/sensor mounts below matter (Services/Temp columns).
|
# systemd/dbus/sensor mounts below matter (Services/Temp columns).
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << AGENT_COMPOSE
|
cat > docker-compose.yml << AGENT_COMPOSE
|
||||||
name: beszel-agent
|
name: beszel-agent
|
||||||
|
|
||||||
@@ -703,6 +711,7 @@ services:
|
|||||||
- /sys/class/thermal:/sys/class/thermal:ro
|
- /sys/class/thermal:/sys/class/thermal:ro
|
||||||
AGENT_COMPOSE
|
AGENT_COMPOSE
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << AGENT_ENV
|
cat > .env << AGENT_ENV
|
||||||
TZ=${SITE_TZ:-$(cat /etc/timezone 2>/dev/null || echo UTC)}
|
TZ=${SITE_TZ:-$(cat /etc/timezone 2>/dev/null || echo UTC)}
|
||||||
HUB_URL=$HUB_URL
|
HUB_URL=$HUB_URL
|
||||||
|
|||||||
@@ -192,6 +192,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
||||||
@@ -279,6 +284,7 @@ install_caddy() {
|
|||||||
|
|
||||||
cd "$CADDY_DIR" || return 1
|
cd "$CADDY_DIR" || return 1
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << 'CADDY_COMPOSE'
|
cat > docker-compose.yml << 'CADDY_COMPOSE'
|
||||||
name: caddy
|
name: caddy
|
||||||
|
|
||||||
|
|||||||
@@ -177,6 +177,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
||||||
@@ -242,6 +247,7 @@ networks:
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << CW_COMPOSE
|
cat > docker-compose.yml << CW_COMPOSE
|
||||||
name: calibre-web
|
name: calibre-web
|
||||||
|
|
||||||
@@ -264,6 +270,7 @@ services:
|
|||||||
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
||||||
CW_COMPOSE
|
CW_COMPOSE
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << CW_ENV
|
cat > .env << CW_ENV
|
||||||
CADDY_NET=$SITE_CADDY_NET
|
CADDY_NET=$SITE_CADDY_NET
|
||||||
CW_ENV
|
CW_ENV
|
||||||
|
|||||||
@@ -177,6 +177,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
||||||
@@ -243,6 +248,7 @@ networks:
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << CD_COMPOSE
|
cat > docker-compose.yml << CD_COMPOSE
|
||||||
name: changedetection
|
name: changedetection
|
||||||
|
|
||||||
@@ -272,6 +278,7 @@ ${_CADDY_NET_BLOCK} depends_on:
|
|||||||
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
||||||
CD_COMPOSE
|
CD_COMPOSE
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << CD_ENV
|
cat > .env << CD_ENV
|
||||||
# Changedetection.io environment — edit before starting if needed
|
# Changedetection.io environment — edit before starting if needed
|
||||||
BASE_URL=https://changes.${SITE_DOMAIN}
|
BASE_URL=https://changes.${SITE_DOMAIN}
|
||||||
|
|||||||
@@ -174,6 +174,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
||||||
@@ -212,6 +217,7 @@ install_ddclient() {
|
|||||||
|
|
||||||
local TZ_VAL; TZ_VAL="${SITE_TZ:-$(cat /etc/timezone 2>/dev/null || echo UTC)}"
|
local TZ_VAL; TZ_VAL="${SITE_TZ:-$(cat /etc/timezone 2>/dev/null || echo UTC)}"
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << 'DDCLIENT_COMPOSE'
|
cat > docker-compose.yml << 'DDCLIENT_COMPOSE'
|
||||||
name: ddclient
|
name: ddclient
|
||||||
|
|
||||||
@@ -229,6 +235,7 @@ services:
|
|||||||
- ./config:/config
|
- ./config:/config
|
||||||
DDCLIENT_COMPOSE
|
DDCLIENT_COMPOSE
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << DDCLIENT_ENV
|
cat > .env << DDCLIENT_ENV
|
||||||
TZ=$TZ_VAL
|
TZ=$TZ_VAL
|
||||||
DDCLIENT_ENV
|
DDCLIENT_ENV
|
||||||
|
|||||||
@@ -178,6 +178,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
||||||
@@ -477,6 +482,7 @@ networks:
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << DRUM_COMPOSE
|
cat > docker-compose.yml << DRUM_COMPOSE
|
||||||
name: drum-rhythm-game
|
name: drum-rhythm-game
|
||||||
|
|
||||||
@@ -492,6 +498,7 @@ services:
|
|||||||
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
||||||
DRUM_COMPOSE
|
DRUM_COMPOSE
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << DRUM_ENV
|
cat > .env << DRUM_ENV
|
||||||
CADDY_NET=${SITE_CADDY_NET}
|
CADDY_NET=${SITE_CADDY_NET}
|
||||||
DRUM_ENV
|
DRUM_ENV
|
||||||
|
|||||||
@@ -189,6 +189,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
||||||
@@ -352,6 +357,7 @@ networks:
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << EMBY_COMPOSE
|
cat > docker-compose.yml << EMBY_COMPOSE
|
||||||
name: $CONTAINER
|
name: $CONTAINER
|
||||||
|
|
||||||
@@ -377,6 +383,7 @@ services:
|
|||||||
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
||||||
EMBY_COMPOSE
|
EMBY_COMPOSE
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << EMBY_ENV
|
cat > .env << EMBY_ENV
|
||||||
MEDIA_PATH=$MEDIA_PATH
|
MEDIA_PATH=$MEDIA_PATH
|
||||||
CADDY_NET=$SITE_CADDY_NET
|
CADDY_NET=$SITE_CADDY_NET
|
||||||
|
|||||||
@@ -177,6 +177,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
||||||
@@ -315,6 +320,7 @@ networks:
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << FB_COMPOSE
|
cat > docker-compose.yml << FB_COMPOSE
|
||||||
name: $CONTAINER
|
name: $CONTAINER
|
||||||
|
|
||||||
@@ -334,6 +340,7 @@ services:
|
|||||||
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
||||||
FB_COMPOSE
|
FB_COMPOSE
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << FB_ENV
|
cat > .env << FB_ENV
|
||||||
CADDY_NET=$SITE_CADDY_NET
|
CADDY_NET=$SITE_CADDY_NET
|
||||||
FB_ENV
|
FB_ENV
|
||||||
|
|||||||
@@ -199,6 +199,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
||||||
@@ -339,6 +344,7 @@ networks:
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << FMD_COMPOSE
|
cat > docker-compose.yml << FMD_COMPOSE
|
||||||
name: $CONTAINER
|
name: $CONTAINER
|
||||||
|
|
||||||
@@ -357,6 +363,7 @@ services:
|
|||||||
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
||||||
FMD_COMPOSE
|
FMD_COMPOSE
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << FMD_ENV
|
cat > .env << FMD_ENV
|
||||||
FMD_REGISTRATIONTOKEN=$FMD_TOKEN
|
FMD_REGISTRATIONTOKEN=$FMD_TOKEN
|
||||||
CADDY_NET=$SITE_CADDY_NET
|
CADDY_NET=$SITE_CADDY_NET
|
||||||
|
|||||||
@@ -207,6 +207,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
||||||
@@ -365,6 +370,7 @@ install_frigate-audio() {
|
|||||||
|
|
||||||
# ── .env ──────────────────────────────────────────────────────────────────
|
# ── .env ──────────────────────────────────────────────────────────────────
|
||||||
log_info "Writing .env..."
|
log_info "Writing .env..."
|
||||||
|
backup_if_exists "$DIR/.env"
|
||||||
cat > "$DIR/.env" << ENVEOF
|
cat > "$DIR/.env" << ENVEOF
|
||||||
# Frigate audio stack — generated by setup.sh
|
# Frigate audio stack — generated by setup.sh
|
||||||
# DO NOT commit this file — it contains credentials.
|
# DO NOT commit this file — it contains credentials.
|
||||||
@@ -432,6 +438,7 @@ networks:
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists "$DIR/docker-compose.yml"
|
||||||
cat > "$DIR/docker-compose.yml" << 'COMPOSEEOF'
|
cat > "$DIR/docker-compose.yml" << 'COMPOSEEOF'
|
||||||
# Frigate NVR + Mosquitto MQTT + frigate-notify
|
# Frigate NVR + Mosquitto MQTT + frigate-notify
|
||||||
# Generated by ubuntu-post-install setup.sh
|
# Generated by ubuntu-post-install setup.sh
|
||||||
|
|||||||
@@ -174,6 +174,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
||||||
@@ -234,6 +239,7 @@ networks:
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << FN_COMPOSE
|
cat > docker-compose.yml << FN_COMPOSE
|
||||||
name: frigate-notify
|
name: frigate-notify
|
||||||
|
|
||||||
|
|||||||
+67
-5
@@ -202,6 +202,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
||||||
@@ -626,6 +631,7 @@ networks:
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << FRIGATE_COMPOSE
|
cat > docker-compose.yml << FRIGATE_COMPOSE
|
||||||
name: frigate
|
name: frigate
|
||||||
|
|
||||||
@@ -673,16 +679,71 @@ FRIGATE_COMPOSE
|
|||||||
# reverse_proxy block) stops that trust from being spoofed by a
|
# reverse_proxy block) stops that trust from being spoofed by a
|
||||||
# request that reaches Frigate's published host port directly,
|
# request that reaches Frigate's published host port directly,
|
||||||
# bypassing Caddy/Authelia entirely.
|
# bypassing Caddy/Authelia entirely.
|
||||||
|
# Whether to even OFFER this can't just check "$DOCKER_DIR/authelia"
|
||||||
|
# locally — Frigate's own box very often has no local Caddy at all
|
||||||
|
# (configure_caddy_for_service falls back to writing a snippet for
|
||||||
|
# a remote Caddy machine to pick up, confirmed live: this is the
|
||||||
|
# normal shape for a dedicated NVR box), in which case Authelia, if
|
||||||
|
# it exists anywhere, lives on THAT remote Caddy machine instead —
|
||||||
|
# a box this script has no filesystem access to inspect. Default to
|
||||||
|
# "y" only when local Authelia is actually confirmed; otherwise still
|
||||||
|
# offer it (default "n") and sort out local-vs-remote below once the
|
||||||
|
# admin says yes, rather than silently refusing to ask at all.
|
||||||
local FRIGATE_USE_AUTHELIA="n" FRIGATE_PROXY_SECRET="" AUTH_CONFIG_BLOCK=""
|
local FRIGATE_USE_AUTHELIA="n" FRIGATE_PROXY_SECRET="" AUTH_CONFIG_BLOCK=""
|
||||||
if [ -d "$DOCKER_DIR/authelia" ]; then
|
local _frigate_local_authelia="n"
|
||||||
echo ""
|
[ -d "$DOCKER_DIR/authelia" ] && _frigate_local_authelia="y"
|
||||||
prompt_yn "Protect Frigate with Authelia SSO (disables Frigate's own login)? (y/n):" "y" FRIGATE_USE_AUTHELIA
|
echo ""
|
||||||
fi
|
prompt_yn "Protect Frigate with Authelia SSO (disables Frigate's own login)? (y/n):" "$_frigate_local_authelia" FRIGATE_USE_AUTHELIA
|
||||||
|
|
||||||
if [[ "$FRIGATE_USE_AUTHELIA" =~ ^[Yy]$ ]]; then
|
if [[ "$FRIGATE_USE_AUTHELIA" =~ ^[Yy]$ ]]; then
|
||||||
FRIGATE_PROXY_SECRET="${ENV_MAP[FRIGATE_PROXY_AUTH_SECRET]:-$(generate_password 32)}"
|
FRIGATE_PROXY_SECRET="${ENV_MAP[FRIGATE_PROXY_AUTH_SECRET]:-$(generate_password 32)}"
|
||||||
|
|
||||||
|
# Local Authelia snippet (import authelia) only actually exists
|
||||||
|
# in the Caddyfile it's imported into if Authelia is on THAT
|
||||||
|
# same machine. When it's on this box, that's this box's own
|
||||||
|
# Caddy — safe to assume. When Caddy itself turns out to be
|
||||||
|
# remote (below), "local" instead means "local to wherever
|
||||||
|
# Caddy is", which this script can't see — so ask, rather than
|
||||||
|
# silently emit an import that would fail Caddy's own reload
|
||||||
|
# with "file to import not found" on that other machine.
|
||||||
|
local _frigate_auth_block=" import authelia"
|
||||||
|
if [ "$_frigate_local_authelia" != "y" ]; then
|
||||||
|
echo ""
|
||||||
|
log_info "No local Authelia on this box — Caddy for Frigate may end up on a"
|
||||||
|
log_info "different machine (decided next)."
|
||||||
|
local _authelia_with_caddy=""
|
||||||
|
prompt_yn " Does Authelia run on that SAME machine as Caddy? (y/n):" "y" _authelia_with_caddy
|
||||||
|
if [[ ! "$_authelia_with_caddy" =~ ^[Yy]$ ]]; then
|
||||||
|
# Genuinely cross-machine: Authelia is a third box,
|
||||||
|
# different from both this one and wherever Caddy ends
|
||||||
|
# up. Needs the explicit header-pinned forward_auth form
|
||||||
|
# — see CLAUDE.md's "forward_auth to a remote Authelia"
|
||||||
|
# note for why the bare "authelia:9091" shortcut can't
|
||||||
|
# be used here and X-Forwarded-Host must be pinned
|
||||||
|
# explicitly (a second Caddy hop otherwise silently
|
||||||
|
# evaluates every domain as if it were auth's own
|
||||||
|
# portal domain — confirmed live, a real incident this
|
||||||
|
# exact snippet shape was written to prevent).
|
||||||
|
local _remote_authelia_domain=""
|
||||||
|
prompt_text " Authelia's own portal domain (e.g. authelia.example.com):" "" _remote_authelia_domain
|
||||||
|
if [ -n "$_remote_authelia_domain" ]; then
|
||||||
|
_frigate_auth_block=" forward_auth https://${_remote_authelia_domain} {
|
||||||
|
uri /api/authz/forward-auth
|
||||||
|
copy_headers Remote-User Remote-Groups Remote-Name Remote-Email
|
||||||
|
header_up X-Forwarded-Method {method}
|
||||||
|
header_up X-Forwarded-Proto {scheme}
|
||||||
|
header_up X-Forwarded-Host {host}
|
||||||
|
header_up X-Forwarded-Uri {uri}
|
||||||
|
}"
|
||||||
|
else
|
||||||
|
log_warning "No domain entered — falling back to 'import authelia', which will fail"
|
||||||
|
log_warning "Caddy's reload unless Authelia is actually local to that Caddy machine."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
configure_caddy_for_service "Frigate" "frigate:5000" "frigate" \
|
configure_caddy_for_service "Frigate" "frigate:5000" "frigate" \
|
||||||
" import authelia" \
|
"$_frigate_auth_block" \
|
||||||
" header_up X-Proxy-Secret ${FRIGATE_PROXY_SECRET}"
|
" header_up X-Proxy-Secret ${FRIGATE_PROXY_SECRET}"
|
||||||
if [ "${CADDY_SERVICE_CONFIGURED:-false}" = true ]; then
|
if [ "${CADDY_SERVICE_CONFIGURED:-false}" = true ]; then
|
||||||
AUTH_CONFIG_BLOCK="auth:
|
AUTH_CONFIG_BLOCK="auth:
|
||||||
@@ -780,6 +841,7 @@ snapshots:
|
|||||||
FRIGATE_CONFIG
|
FRIGATE_CONFIG
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << FRIGATE_ENV
|
cat > .env << FRIGATE_ENV
|
||||||
FRIGATE_MEDIA=$FRIGATE_MEDIA
|
FRIGATE_MEDIA=$FRIGATE_MEDIA
|
||||||
CADDY_NET=$SITE_CADDY_NET
|
CADDY_NET=$SITE_CADDY_NET
|
||||||
|
|||||||
@@ -92,6 +92,11 @@ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
||||||
@@ -199,6 +204,7 @@ install_garage-webui() {
|
|||||||
ensure_docker_dir_ownership "$DIR"
|
ensure_docker_dir_ownership "$DIR"
|
||||||
cd "$DIR" || return 1
|
cd "$DIR" || return 1
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << COMPOSE
|
cat > docker-compose.yml << COMPOSE
|
||||||
name: garage-webui
|
name: garage-webui
|
||||||
|
|
||||||
@@ -219,6 +225,7 @@ services:
|
|||||||
- "${WEB_PORT}:3909"
|
- "${WEB_PORT}:3909"
|
||||||
COMPOSE
|
COMPOSE
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << ENV
|
cat > .env << ENV
|
||||||
TZ=${SITE_TZ:-$(cat /etc/timezone 2>/dev/null || echo UTC)}
|
TZ=${SITE_TZ:-$(cat /etc/timezone 2>/dev/null || echo UTC)}
|
||||||
|
|
||||||
|
|||||||
@@ -108,6 +108,11 @@ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
||||||
@@ -277,6 +282,7 @@ api_bind_addr = "[::]:${ADMIN_PORT}"
|
|||||||
admin_token = "${ADMIN_TOKEN}"
|
admin_token = "${ADMIN_TOKEN}"
|
||||||
TOML
|
TOML
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << COMPOSE
|
cat > docker-compose.yml << COMPOSE
|
||||||
name: garage
|
name: garage
|
||||||
|
|
||||||
@@ -297,6 +303,7 @@ services:
|
|||||||
- "${ADMIN_PORT}:${ADMIN_PORT}"
|
- "${ADMIN_PORT}:${ADMIN_PORT}"
|
||||||
COMPOSE
|
COMPOSE
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << ENV
|
cat > .env << ENV
|
||||||
TZ=${SITE_TZ:-$(cat /etc/timezone 2>/dev/null || echo UTC)}
|
TZ=${SITE_TZ:-$(cat /etc/timezone 2>/dev/null || echo UTC)}
|
||||||
|
|
||||||
|
|||||||
@@ -187,6 +187,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
||||||
@@ -405,6 +410,7 @@ networks:
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << GATUS_COMPOSE
|
cat > docker-compose.yml << GATUS_COMPOSE
|
||||||
name: gatus
|
name: gatus
|
||||||
|
|
||||||
@@ -423,6 +429,7 @@ services:
|
|||||||
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
||||||
GATUS_COMPOSE
|
GATUS_COMPOSE
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << GATUS_ENV
|
cat > .env << GATUS_ENV
|
||||||
TZ=$TZ_VAL
|
TZ=$TZ_VAL
|
||||||
CADDY_NET=$SITE_CADDY_NET
|
CADDY_NET=$SITE_CADDY_NET
|
||||||
|
|||||||
@@ -104,6 +104,11 @@ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
||||||
@@ -585,6 +590,7 @@ install_gitea() {
|
|||||||
[[ "$WEB_PORT" != 3001 ]] && log_info "Port 3001 was taken — Gitea's web UI will use ${WEB_PORT}."
|
[[ "$WEB_PORT" != 3001 ]] && log_info "Port 3001 was taken — Gitea's web UI will use ${WEB_PORT}."
|
||||||
[[ "$SSH_PORT" != 2222 ]] && log_info "Port 2222 was taken — Gitea's SSH clone port will use ${SSH_PORT}."
|
[[ "$SSH_PORT" != 2222 ]] && log_info "Port 2222 was taken — Gitea's SSH clone port will use ${SSH_PORT}."
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << EOF
|
cat > docker-compose.yml << EOF
|
||||||
name: gitea
|
name: gitea
|
||||||
services:
|
services:
|
||||||
@@ -699,6 +705,7 @@ EOF
|
|||||||
cp -f "$SYNC_SRC" "$DIR/gitea-github-sync.sh"
|
cp -f "$SYNC_SRC" "$DIR/gitea-github-sync.sh"
|
||||||
chmod +x "$DIR/gitea-github-sync.sh"
|
chmod +x "$DIR/gitea-github-sync.sh"
|
||||||
|
|
||||||
|
backup_if_exists "$DIR/.env"
|
||||||
cat > "$DIR/.env" << ENV
|
cat > "$DIR/.env" << ENV
|
||||||
# Written by services/gitea.sh — re-run that (update mode) to change any of this.
|
# Written by services/gitea.sh — re-run that (update mode) to change any of this.
|
||||||
GITEA_URL='http://localhost:${WEB_PORT}'
|
GITEA_URL='http://localhost:${WEB_PORT}'
|
||||||
|
|||||||
@@ -274,6 +274,7 @@ networks:
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << HOMEASSISTANT_COMPOSE
|
cat > docker-compose.yml << HOMEASSISTANT_COMPOSE
|
||||||
name: homeassistant
|
name: homeassistant
|
||||||
|
|
||||||
|
|||||||
@@ -177,6 +177,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
||||||
@@ -196,6 +201,124 @@ fi
|
|||||||
|
|
||||||
register_service homebox utilities "Home inventory and asset management (Homebox)" 7745
|
register_service homebox utilities "Home inventory and asset management (Homebox)" 7745
|
||||||
|
|
||||||
|
# Offers to wire Homebox's own native OIDC support to Authelia — real
|
||||||
|
# server-side automation via env vars, not paste-in instructions, same
|
||||||
|
# shape as Mealie/ActualBudget. Confirmed against homebox.software's own
|
||||||
|
# OIDC docs and authelia.com's Homebox integration page directly: PKCE is
|
||||||
|
# required, redirect path is /api/v1/users/login/oidc/callback, and the
|
||||||
|
# issuer URL is sensitive to a trailing slash (a real reported bug) — the
|
||||||
|
# portal URL this repo already stores never has one, so left as-is here.
|
||||||
|
#
|
||||||
|
# Args: DIR CONTAINER
|
||||||
|
_homebox_offer_authelia_oidc() {
|
||||||
|
local DIR="$1" CONTAINER="$2"
|
||||||
|
|
||||||
|
declare -F _authelia_provision_oidc_client >/dev/null 2>&1 || return 0
|
||||||
|
[ -d "$DOCKER_DIR/authelia" ] || return 0
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
local USE_SSO=""
|
||||||
|
prompt_yn " Add \"Sign in with Authelia\" (OpenID Connect) to Homebox? (y/n):" "n" USE_SSO
|
||||||
|
[[ "$USE_SSO" =~ ^[Yy]$ ]] || return 0
|
||||||
|
|
||||||
|
if grep -q '^HBOX_OIDC_ENABLED=' "$DIR/.env" 2>/dev/null; then
|
||||||
|
echo ""
|
||||||
|
log_info "Authelia SSO is already configured for Homebox (HBOX_OIDC_* already set in $DIR/.env)."
|
||||||
|
local RECONFIGURE=""
|
||||||
|
prompt_yn " Reconfigure it (registers a fresh Authelia client + secret)? (y/n):" "n" RECONFIGURE
|
||||||
|
[[ "$RECONFIGURE" =~ ^[Yy]$ ]] || return 0
|
||||||
|
sed -i '/^HBOX_OIDC_/d; /^HBOX_OPTIONS_TRUST_PROXY=/d' "$DIR/.env"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Existing installs from before this offer existed won't have env_file
|
||||||
|
# picked up their .env's OIDC additions otherwise — this repo's own
|
||||||
|
# compose template gained it above; a pre-existing compose file needs
|
||||||
|
# the same one-line patch to actually load what's about to be written.
|
||||||
|
if ! grep -q '^\s*env_file: \.env\s*$' "$DIR/docker-compose.yml" 2>/dev/null; then
|
||||||
|
sed -i "/^ hostname: /a\\ env_file: .env" "$DIR/docker-compose.yml"
|
||||||
|
fi
|
||||||
|
|
||||||
|
local APP_DOMAIN
|
||||||
|
APP_DOMAIN="$(_authelia_pick_domain "Domain Homebox is reachable at (number or domain)")"
|
||||||
|
if [ -z "$APP_DOMAIN" ]; then
|
||||||
|
log_warning "No domain entered — skipping SSO setup."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local _2fa="" AUTH_POLICY="two_factor"
|
||||||
|
prompt_yn " Require two-factor for Homebox logins via Authelia too? (y/n):" "y" _2fa
|
||||||
|
[[ "$_2fa" =~ ^[Yy]$ ]] || AUTH_POLICY="one_factor"
|
||||||
|
|
||||||
|
if ! _authelia_provision_oidc_client "Homebox" "homebox" "$AUTH_POLICY" "y" "y" \
|
||||||
|
"https://${APP_DOMAIN}/api/v1/users/login/oidc/callback"; then
|
||||||
|
log_warning "Couldn't register Homebox as an OIDC client in Authelia — skipping SSO setup."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat >> "$DIR/.env" << ENV
|
||||||
|
|
||||||
|
# Written by services/homebox.sh's Authelia SSO step — adds "Sign in with
|
||||||
|
# Authelia" alongside local login; local accounts keep working unchanged.
|
||||||
|
HBOX_OIDC_ENABLED=true
|
||||||
|
HBOX_OIDC_ISSUER_URL=${OIDC_AUTHELIA_PORTAL_URL}
|
||||||
|
HBOX_OIDC_CLIENT_ID=homebox
|
||||||
|
HBOX_OIDC_CLIENT_SECRET=${OIDC_CLIENT_SECRET_PLAIN}
|
||||||
|
HBOX_OIDC_SCOPE=openid profile email groups
|
||||||
|
HBOX_OPTIONS_TRUST_PROXY=true
|
||||||
|
ENV
|
||||||
|
chown "$ACTUAL_USER:$ACTUAL_USER" "$DIR/.env" 2>/dev/null || true
|
||||||
|
|
||||||
|
(cd "$DIR" && docker compose up -d) \
|
||||||
|
&& log_success "\"Sign in with Authelia\" added to Homebox — local login still works too." \
|
||||||
|
|| log_warning "Restart failed — check: docker compose -f $DIR/docker-compose.yml logs"
|
||||||
|
|
||||||
|
declare -F _authelia_scope_access >/dev/null 2>&1 && _authelia_scope_access "homebox" "$APP_DOMAIN"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
log_info "Test the \"Login with Authelia\" button on Homebox's own login page before"
|
||||||
|
log_info "disabling local login — re-run 'sudo ./setup.sh homebox' (choose update) once"
|
||||||
|
log_info "you've confirmed it works, and you'll be offered that as a separate step."
|
||||||
|
}
|
||||||
|
|
||||||
|
# Split out from _homebox_offer_authelia_oidc so disabling local login is
|
||||||
|
# never offered in the same breath as first setting SSO up — same
|
||||||
|
# reasoning as Mealie/Beszel's equivalent split (confirmed live on Beszel:
|
||||||
|
# saying yes before actually testing the button leaves both login paths
|
||||||
|
# broken at once). Only reached from a later "update" rerun once OIDC is
|
||||||
|
# already configured and the admin declines to reconfigure.
|
||||||
|
_homebox_offer_disable_local_login() {
|
||||||
|
local DIR="$1"
|
||||||
|
grep -q '^HBOX_OPTIONS_ALLOW_LOCAL_LOGIN=false' "$DIR/.env" 2>/dev/null && return 0
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
local _tested=""
|
||||||
|
prompt_yn " Have you ALREADY logged into Homebox successfully using the Authelia button (not just enabled it)? (y/n):" "n" _tested
|
||||||
|
if [[ ! "$_tested" =~ ^[Yy]$ ]]; then
|
||||||
|
log_info "Skipped. Test the Authelia login button first, then re-run 'sudo ./setup.sh homebox' (choose update) to come back to this."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local _disable_local=""
|
||||||
|
prompt_yn " Also disable Homebox's own local login, so Authelia is the only way in? (y/n):" "n" _disable_local
|
||||||
|
[[ "$_disable_local" =~ ^[Yy]$ ]] || return 0
|
||||||
|
|
||||||
|
log_warning "Anyone without an Authelia account (only a local Homebox one) will no longer be able to log in."
|
||||||
|
log_info "Reversible any time: set HBOX_OPTIONS_ALLOW_LOCAL_LOGIN back to true in $DIR/.env and 'docker compose up -d'."
|
||||||
|
local _auto_redirect=""
|
||||||
|
prompt_yn " Skip Homebox's login page entirely and jump straight to Authelia? (y/n):" "y" _auto_redirect
|
||||||
|
|
||||||
|
sed -i '/^HBOX_OPTIONS_ALLOW_LOCAL_LOGIN=/d; /^HBOX_OIDC_AUTO_REDIRECT=/d' "$DIR/.env"
|
||||||
|
{
|
||||||
|
echo "HBOX_OPTIONS_ALLOW_LOCAL_LOGIN=false"
|
||||||
|
[[ "$_auto_redirect" =~ ^[Yy]$ ]] && echo "HBOX_OIDC_AUTO_REDIRECT=true"
|
||||||
|
} >> "$DIR/.env"
|
||||||
|
chown "$ACTUAL_USER:$ACTUAL_USER" "$DIR/.env" 2>/dev/null || true
|
||||||
|
|
||||||
|
(cd "$DIR" && docker compose up -d) \
|
||||||
|
&& log_success "Local login is now disabled — Authelia is the only way into Homebox." \
|
||||||
|
|| log_warning "Restart failed — check: docker compose -f $DIR/docker-compose.yml logs"
|
||||||
|
}
|
||||||
|
|
||||||
install_homebox() {
|
install_homebox() {
|
||||||
require_docker || return 1
|
require_docker || return 1
|
||||||
log_info "Installing Homebox..."
|
log_info "Installing Homebox..."
|
||||||
@@ -256,6 +379,8 @@ install_homebox() {
|
|||||||
( cd "$HB_DIR" && docker compose pull && docker compose up -d ) \
|
( cd "$HB_DIR" && docker compose pull && docker compose up -d ) \
|
||||||
&& log_success "Homebox image refreshed" \
|
&& log_success "Homebox image refreshed" \
|
||||||
|| log_warning "Refresh failed — check: docker compose -f $HB_DIR/docker-compose.yml logs"
|
|| log_warning "Refresh failed — check: docker compose -f $HB_DIR/docker-compose.yml logs"
|
||||||
|
_homebox_offer_authelia_oidc "$HB_DIR" "$CONTAINER"
|
||||||
|
_homebox_offer_disable_local_login "$HB_DIR"
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
cancel)
|
cancel)
|
||||||
@@ -311,6 +436,7 @@ networks:
|
|||||||
local HB_PEPPER
|
local HB_PEPPER
|
||||||
HB_PEPPER="$(generate_password 48)"
|
HB_PEPPER="$(generate_password 48)"
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << HB_COMPOSE
|
cat > docker-compose.yml << HB_COMPOSE
|
||||||
name: $CONTAINER
|
name: $CONTAINER
|
||||||
|
|
||||||
@@ -320,6 +446,7 @@ services:
|
|||||||
container_name: $CONTAINER
|
container_name: $CONTAINER
|
||||||
hostname: $CONTAINER
|
hostname: $CONTAINER
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
env_file: .env
|
||||||
environment:
|
environment:
|
||||||
- HBOX_LOG_LEVEL=info
|
- HBOX_LOG_LEVEL=info
|
||||||
- HBOX_WEB_MAX_UPLOAD_SIZE=10
|
- HBOX_WEB_MAX_UPLOAD_SIZE=10
|
||||||
@@ -331,6 +458,7 @@ services:
|
|||||||
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
||||||
HB_COMPOSE
|
HB_COMPOSE
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << HB_ENV
|
cat > .env << HB_ENV
|
||||||
CADDY_NET=$SITE_CADDY_NET
|
CADDY_NET=$SITE_CADDY_NET
|
||||||
|
|
||||||
@@ -346,6 +474,8 @@ HB_ENV
|
|||||||
|
|
||||||
configure_caddy_for_service "Homebox${INSTANCE_SUFFIX:+ ($INSTANCE_SUFFIX)}" "${CONTAINER}:7745" "homebox${INSTANCE_SUFFIX:+-$INSTANCE_SUFFIX}"
|
configure_caddy_for_service "Homebox${INSTANCE_SUFFIX:+ ($INSTANCE_SUFFIX)}" "${CONTAINER}:7745" "homebox${INSTANCE_SUFFIX:+-$INSTANCE_SUFFIX}"
|
||||||
|
|
||||||
|
_homebox_offer_authelia_oidc "$HB_DIR" "$CONTAINER"
|
||||||
|
|
||||||
write_readme "$HB_DIR" << MD
|
write_readme "$HB_DIR" << MD
|
||||||
# Homebox${INSTANCE_SUFFIX:+ — $INSTANCE_SUFFIX}
|
# Homebox${INSTANCE_SUFFIX:+ — $INSTANCE_SUFFIX}
|
||||||
|
|
||||||
|
|||||||
@@ -183,6 +183,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
||||||
@@ -606,6 +611,7 @@ networks:
|
|||||||
[ -n "$EXTERNAL_LIBRARY" ] && _EXTERNAL_VOLUME_LINE=" - \${EXTERNAL_LIBRARY}:/usr/src/app/external:ro
|
[ -n "$EXTERNAL_LIBRARY" ] && _EXTERNAL_VOLUME_LINE=" - \${EXTERNAL_LIBRARY}:/usr/src/app/external:ro
|
||||||
"
|
"
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << IMMICH_COMPOSE
|
cat > docker-compose.yml << IMMICH_COMPOSE
|
||||||
name: $PROJECT
|
name: $PROJECT
|
||||||
|
|
||||||
@@ -686,6 +692,7 @@ S3_SECRET_ACCESS_KEY=$S3_SECRET_ACCESS_KEY
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$IMMICH_STRATEGY" = "2" ]; then
|
if [ "$IMMICH_STRATEGY" = "2" ]; then
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << IMMICH_ENV
|
cat > .env << IMMICH_ENV
|
||||||
# IMMICH CONFIGURATION — External Library Mode
|
# IMMICH CONFIGURATION — External Library Mode
|
||||||
#
|
#
|
||||||
@@ -713,6 +720,7 @@ TZ=$TZ_VAL
|
|||||||
CADDY_NET=$SITE_CADDY_NET
|
CADDY_NET=$SITE_CADDY_NET
|
||||||
IMMICH_ENV
|
IMMICH_ENV
|
||||||
else
|
else
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << IMMICH_ENV
|
cat > .env << IMMICH_ENV
|
||||||
# IMMICH CONFIGURATION — Unified Library
|
# IMMICH CONFIGURATION — Unified Library
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -185,6 +185,11 @@ CBLOCK
|
|||||||
[[ "${DRY_RUN:-false}" == "true" ]] && return 0
|
[[ "${DRY_RUN:-false}" == "true" ]] && return 0
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
||||||
@@ -314,6 +319,7 @@ networks:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$USE_GPU" =~ ^[Yy]$ ]]; then
|
if [[ "$USE_GPU" =~ ^[Yy]$ ]]; then
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << IOPAINT_GPU
|
cat > docker-compose.yml << IOPAINT_GPU
|
||||||
name: iopaint
|
name: iopaint
|
||||||
|
|
||||||
@@ -346,6 +352,7 @@ services:
|
|||||||
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
||||||
IOPAINT_GPU
|
IOPAINT_GPU
|
||||||
else
|
else
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << IOPAINT_CPU
|
cat > docker-compose.yml << IOPAINT_CPU
|
||||||
name: iopaint
|
name: iopaint
|
||||||
|
|
||||||
@@ -373,6 +380,7 @@ IOPAINT_CPU
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# ── .env ─────────────────────────────────────────────────────────────────
|
# ── .env ─────────────────────────────────────────────────────────────────
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << IOPAINT_ENV
|
cat > .env << IOPAINT_ENV
|
||||||
# IOPaint — change MODEL and restart to switch (no need to edit docker-compose.yml)
|
# IOPaint — change MODEL and restart to switch (no need to edit docker-compose.yml)
|
||||||
|
|
||||||
|
|||||||
@@ -182,6 +182,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
||||||
@@ -347,6 +352,7 @@ networks:
|
|||||||
'
|
'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << JELLYFIN_COMPOSE
|
cat > docker-compose.yml << JELLYFIN_COMPOSE
|
||||||
name: $CONTAINER
|
name: $CONTAINER
|
||||||
|
|
||||||
@@ -368,6 +374,7 @@ $HWACCEL_BLOCK
|
|||||||
${_DISCOVERY_PORTS}${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
${_DISCOVERY_PORTS}${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
||||||
JELLYFIN_COMPOSE
|
JELLYFIN_COMPOSE
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << JELLYFIN_ENV
|
cat > .env << JELLYFIN_ENV
|
||||||
MEDIA_PATH=$MEDIA_PATH
|
MEDIA_PATH=$MEDIA_PATH
|
||||||
CADDY_NET=$SITE_CADDY_NET
|
CADDY_NET=$SITE_CADDY_NET
|
||||||
|
|||||||
@@ -177,6 +177,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
||||||
@@ -314,6 +319,7 @@ networks:
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << JOPLIN_COMPOSE
|
cat > docker-compose.yml << JOPLIN_COMPOSE
|
||||||
name: $CONTAINER
|
name: $CONTAINER
|
||||||
|
|
||||||
@@ -340,6 +346,7 @@ ${_CADDY_NET_BLOCK}
|
|||||||
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
||||||
JOPLIN_COMPOSE
|
JOPLIN_COMPOSE
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << JOPLIN_ENV
|
cat > .env << JOPLIN_ENV
|
||||||
# Joplin Server configuration
|
# Joplin Server configuration
|
||||||
APP_PORT=22300
|
APP_PORT=22300
|
||||||
|
|||||||
@@ -174,6 +174,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
||||||
@@ -459,6 +464,7 @@ networks:
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists "$JS99ER_DIR/docker-compose.yml"
|
||||||
cat > "$JS99ER_DIR/docker-compose.yml" << COMPOSE
|
cat > "$JS99ER_DIR/docker-compose.yml" << COMPOSE
|
||||||
name: js99er
|
name: js99er
|
||||||
|
|
||||||
|
|||||||
@@ -188,6 +188,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
||||||
@@ -410,6 +415,7 @@ install_koha() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# ── docker-compose.yml ────────────────────────────────────────────────────
|
# ── docker-compose.yml ────────────────────────────────────────────────────
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << KOHA_COMPOSE
|
cat > docker-compose.yml << KOHA_COMPOSE
|
||||||
name: koha
|
name: koha
|
||||||
|
|
||||||
@@ -481,6 +487,7 @@ ${_CADDY_NET_SECTION}
|
|||||||
KOHA_COMPOSE
|
KOHA_COMPOSE
|
||||||
|
|
||||||
# ── config-main.env ───────────────────────────────────────────────────────
|
# ── config-main.env ───────────────────────────────────────────────────────
|
||||||
|
backup_if_exists config-main.env
|
||||||
cat > config-main.env << KOHA_ENV
|
cat > config-main.env << KOHA_ENV
|
||||||
# Koha ILS configuration — generated at install time
|
# Koha ILS configuration — generated at install time
|
||||||
MYSQL_SERVER=koha-db
|
MYSQL_SERVER=koha-db
|
||||||
|
|||||||
@@ -388,6 +388,7 @@ for a in data.get('assets', []):
|
|||||||
mkdir -p "$DIR"
|
mkdir -p "$DIR"
|
||||||
ensure_docker_dir_ownership "$DIR"
|
ensure_docker_dir_ownership "$DIR"
|
||||||
|
|
||||||
|
backup_if_exists "$DIR/docker-compose.yml"
|
||||||
cat > "$DIR/docker-compose.yml" << EOF
|
cat > "$DIR/docker-compose.yml" << EOF
|
||||||
name: kyber-server
|
name: kyber-server
|
||||||
services:
|
services:
|
||||||
@@ -411,6 +412,7 @@ EOF
|
|||||||
# Write .env with restricted permissions
|
# Write .env with restricted permissions
|
||||||
# Values are single-quoted so special characters ($, !, &, etc.) are safe.
|
# Values are single-quoted so special characters ($, !, &, etc.) are safe.
|
||||||
# Exception: single quotes inside a value would still break — avoid them.
|
# Exception: single quotes inside a value would still break — avoid them.
|
||||||
|
backup_if_exists "$DIR/.env"
|
||||||
cat > "$DIR/.env" << EOF
|
cat > "$DIR/.env" << EOF
|
||||||
MAXIMA_CREDENTIALS='${EA_EMAIL}:${EA_PASSWORD}'
|
MAXIMA_CREDENTIALS='${EA_EMAIL}:${EA_PASSWORD}'
|
||||||
KYBER_TOKEN='${KYBER_TOKEN}'
|
KYBER_TOKEN='${KYBER_TOKEN}'
|
||||||
@@ -558,6 +560,11 @@ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
ACTUAL_USER="${SUDO_USER:-$USER}"
|
ACTUAL_USER="${SUDO_USER:-$USER}"
|
||||||
ACTUAL_HOME=$(eval echo "~$ACTUAL_USER")
|
ACTUAL_HOME=$(eval echo "~$ACTUAL_USER")
|
||||||
|
|||||||
@@ -188,6 +188,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
||||||
@@ -353,6 +358,7 @@ install_lyrion() {
|
|||||||
_HTTP_PORT_INTERNAL="9000"
|
_HTTP_PORT_INTERNAL="9000"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << LYRION_COMPOSE
|
cat > docker-compose.yml << LYRION_COMPOSE
|
||||||
name: $CONTAINER
|
name: $CONTAINER
|
||||||
|
|
||||||
@@ -375,6 +381,7 @@ ${_NETWORK_BLOCK}${_PORTS_BLOCK} environment:
|
|||||||
|
|
||||||
LYRION_COMPOSE
|
LYRION_COMPOSE
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << LYRION_ENV
|
cat > .env << LYRION_ENV
|
||||||
MUSIC_PATH=$MUSIC_PATH
|
MUSIC_PATH=$MUSIC_PATH
|
||||||
CADDY_NET=$SITE_CADDY_NET
|
CADDY_NET=$SITE_CADDY_NET
|
||||||
|
|||||||
@@ -174,6 +174,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
||||||
@@ -254,6 +259,7 @@ networks:
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << MM_COMPOSE
|
cat > docker-compose.yml << MM_COMPOSE
|
||||||
name: mm-$MM_PORT
|
name: mm-$MM_PORT
|
||||||
|
|
||||||
|
|||||||
@@ -170,6 +170,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
||||||
@@ -244,6 +249,7 @@ networks:
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << MA_COMPOSE
|
cat > docker-compose.yml << MA_COMPOSE
|
||||||
name: mail-archiver
|
name: mail-archiver
|
||||||
|
|
||||||
@@ -279,6 +285,7 @@ ${_CADDY_NET_BLOCK}
|
|||||||
${_CADDY_NET_SECTION}
|
${_CADDY_NET_SECTION}
|
||||||
MA_COMPOSE
|
MA_COMPOSE
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << MA_ENV
|
cat > .env << MA_ENV
|
||||||
# ── General ───────────────────────────────────────────────────────────────────
|
# ── General ───────────────────────────────────────────────────────────────────
|
||||||
TZ=$TZ_VAL
|
TZ=$TZ_VAL
|
||||||
|
|||||||
@@ -213,6 +213,11 @@ CBLOCK
|
|||||||
[[ "${DRY_RUN:-false}" == "true" ]] && return 0
|
[[ "${DRY_RUN:-false}" == "true" ]] && return 0
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
generate_password() {
|
generate_password() {
|
||||||
local _len="${1:-32}"
|
local _len="${1:-32}"
|
||||||
@@ -518,6 +523,7 @@ networks:
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << EOF
|
cat > docker-compose.yml << EOF
|
||||||
name: ${PROJECT}
|
name: ${PROJECT}
|
||||||
|
|
||||||
@@ -580,6 +586,7 @@ ${_CADDY_NET_BLOCK} healthcheck:
|
|||||||
${_CADDY_NET_BLOCK}${_COTURN_SERVICE}${_CADDY_NET_SECTION}
|
${_CADDY_NET_BLOCK}${_COTURN_SERVICE}${_CADDY_NET_SECTION}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << EOF
|
cat > .env << EOF
|
||||||
TZ=$TZ_VAL
|
TZ=$TZ_VAL
|
||||||
CADDY_NET=$SITE_CADDY_NET
|
CADDY_NET=$SITE_CADDY_NET
|
||||||
|
|||||||
@@ -180,6 +180,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
||||||
@@ -459,6 +464,7 @@ networks:
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << MEALIE_COMPOSE
|
cat > docker-compose.yml << MEALIE_COMPOSE
|
||||||
name: $CONTAINER
|
name: $CONTAINER
|
||||||
|
|
||||||
@@ -483,6 +489,7 @@ services:
|
|||||||
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
||||||
MEALIE_COMPOSE
|
MEALIE_COMPOSE
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << MEALIE_ENV
|
cat > .env << MEALIE_ENV
|
||||||
# Public URL Mealie is served on — used for email links and OAuth redirects.
|
# Public URL Mealie is served on — used for email links and OAuth redirects.
|
||||||
# Update if you change your domain or switch from HTTP to HTTPS.
|
# Update if you change your domain or switch from HTTP to HTTPS.
|
||||||
|
|||||||
@@ -188,6 +188,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
||||||
@@ -323,6 +328,7 @@ networks:
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << MC_COMPOSE
|
cat > docker-compose.yml << MC_COMPOSE
|
||||||
name: $CONTAINER
|
name: $CONTAINER
|
||||||
|
|
||||||
@@ -350,6 +356,7 @@ services:
|
|||||||
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
||||||
MC_COMPOSE
|
MC_COMPOSE
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << MC_ENV
|
cat > .env << MC_ENV
|
||||||
MC_HOSTNAME=$MC_HOSTNAME
|
MC_HOSTNAME=$MC_HOSTNAME
|
||||||
MC_REVERSE_PROXY=false
|
MC_REVERSE_PROXY=false
|
||||||
|
|||||||
@@ -1519,6 +1519,7 @@ PREGENINFOEOF
|
|||||||
- ./config:/data/config"
|
- ./config:/data/config"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists "$MC_DIR/docker-compose.yml"
|
||||||
cat > "$MC_DIR/docker-compose.yml" << COMPOSEEOF
|
cat > "$MC_DIR/docker-compose.yml" << COMPOSEEOF
|
||||||
name: ${MC_NAME}
|
name: ${MC_NAME}
|
||||||
|
|
||||||
@@ -1902,6 +1903,7 @@ EXPOSE 80
|
|||||||
CLIENTDOCKEREOF
|
CLIENTDOCKEREOF
|
||||||
|
|
||||||
# Standalone compose for the client-mods page (its own folder).
|
# Standalone compose for the client-mods page (its own folder).
|
||||||
|
backup_if_exists "$CLIENT_MODS_DIR/docker-compose.yml"
|
||||||
cat > "$CLIENT_MODS_DIR/docker-compose.yml" << CMCOMPOSEEOF
|
cat > "$CLIENT_MODS_DIR/docker-compose.yml" << CMCOMPOSEEOF
|
||||||
name: ${CM_NAME}
|
name: ${CM_NAME}
|
||||||
|
|
||||||
|
|||||||
@@ -177,6 +177,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
||||||
@@ -242,6 +247,7 @@ networks:
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << N8N_COMPOSE
|
cat > docker-compose.yml << N8N_COMPOSE
|
||||||
name: n8n
|
name: n8n
|
||||||
|
|
||||||
@@ -266,6 +272,7 @@ services:
|
|||||||
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
||||||
N8N_COMPOSE
|
N8N_COMPOSE
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << N8N_ENV
|
cat > .env << N8N_ENV
|
||||||
# n8n environment — edit before starting if needed
|
# n8n environment — edit before starting if needed
|
||||||
N8N_HOST=n8n
|
N8N_HOST=n8n
|
||||||
|
|||||||
@@ -70,6 +70,11 @@ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
# Match common.sh's eval-based pattern so local vars in install_* are set correctly
|
# Match common.sh's eval-based pattern so local vars in install_* are set correctly
|
||||||
prompt_text() {
|
prompt_text() {
|
||||||
@@ -260,6 +265,7 @@ networks:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# ── docker-compose.yml ──────────────────────────────────────────────────
|
# ── docker-compose.yml ──────────────────────────────────────────────────
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << NCCOMPOSE
|
cat > docker-compose.yml << NCCOMPOSE
|
||||||
name: nextcloud
|
name: nextcloud
|
||||||
services:
|
services:
|
||||||
@@ -290,6 +296,7 @@ ${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
|||||||
NCCOMPOSE
|
NCCOMPOSE
|
||||||
|
|
||||||
# ── .env ────────────────────────────────────────────────────────────────
|
# ── .env ────────────────────────────────────────────────────────────────
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << NCENV
|
cat > .env << NCENV
|
||||||
TZ=$TZ_VAL
|
TZ=$TZ_VAL
|
||||||
CADDY_NET=$SITE_CADDY_NET
|
CADDY_NET=$SITE_CADDY_NET
|
||||||
|
|||||||
@@ -184,6 +184,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
||||||
@@ -309,6 +314,7 @@ networks:
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << NTFY_COMPOSE
|
cat > docker-compose.yml << NTFY_COMPOSE
|
||||||
name: $CONTAINER
|
name: $CONTAINER
|
||||||
|
|
||||||
@@ -329,6 +335,7 @@ services:
|
|||||||
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
||||||
NTFY_COMPOSE
|
NTFY_COMPOSE
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << NTFY_ENV
|
cat > .env << NTFY_ENV
|
||||||
TZ=${SITE_TZ:-$(cat /etc/timezone 2>/dev/null || echo UTC)}
|
TZ=${SITE_TZ:-$(cat /etc/timezone 2>/dev/null || echo UTC)}
|
||||||
CADDY_NET=$SITE_CADDY_NET
|
CADDY_NET=$SITE_CADDY_NET
|
||||||
|
|||||||
@@ -70,6 +70,11 @@ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
# Match common.sh's eval-based pattern so local vars in install_* are set correctly
|
# Match common.sh's eval-based pattern so local vars in install_* are set correctly
|
||||||
prompt_text() {
|
prompt_text() {
|
||||||
@@ -280,6 +285,7 @@ networks:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# ── docker-compose.yml ──────────────────────────────────────────────────
|
# ── docker-compose.yml ──────────────────────────────────────────────────
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << OOCOMPOSE
|
cat > docker-compose.yml << OOCOMPOSE
|
||||||
name: onlyoffice
|
name: onlyoffice
|
||||||
services:
|
services:
|
||||||
@@ -299,6 +305,7 @@ ${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
|||||||
OOCOMPOSE
|
OOCOMPOSE
|
||||||
|
|
||||||
# ── .env ────────────────────────────────────────────────────────────────
|
# ── .env ────────────────────────────────────────────────────────────────
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << OOENV
|
cat > .env << OOENV
|
||||||
CADDY_NET=$SITE_CADDY_NET
|
CADDY_NET=$SITE_CADDY_NET
|
||||||
# JWT authentication — keep JWT_SECRET private
|
# JWT authentication — keep JWT_SECRET private
|
||||||
|
|||||||
@@ -210,6 +210,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
||||||
@@ -325,6 +330,7 @@ networks:
|
|||||||
# example — NET_ADMIN specifically is only needed if this instance is
|
# example — NET_ADMIN specifically is only needed if this instance is
|
||||||
# ever used as a DHCP server too, which it isn't here, but the other two
|
# ever used as a DHCP server too, which it isn't here, but the other two
|
||||||
# (SYS_TIME, SYS_NICE) are part of that same documented baseline.
|
# (SYS_TIME, SYS_NICE) are part of that same documented baseline.
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << PIHOLE_COMPOSE
|
cat > docker-compose.yml << PIHOLE_COMPOSE
|
||||||
name: pihole
|
name: pihole
|
||||||
|
|
||||||
@@ -351,6 +357,7 @@ services:
|
|||||||
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
||||||
PIHOLE_COMPOSE
|
PIHOLE_COMPOSE
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << PIHOLE_ENV
|
cat > .env << PIHOLE_ENV
|
||||||
TZ=${SITE_TZ:-$(cat /etc/timezone 2>/dev/null || echo UTC)}
|
TZ=${SITE_TZ:-$(cat /etc/timezone 2>/dev/null || echo UTC)}
|
||||||
# Admin web UI password (System Console / login screen).
|
# Admin web UI password (System Console / login screen).
|
||||||
|
|||||||
@@ -177,6 +177,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
||||||
@@ -242,6 +247,7 @@ networks:
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << PORTAINER_COMPOSE
|
cat > docker-compose.yml << PORTAINER_COMPOSE
|
||||||
name: portainer
|
name: portainer
|
||||||
|
|
||||||
|
|||||||
@@ -1746,6 +1746,7 @@ _pstn_apply_settings() {
|
|||||||
# Direct") — unquoted, bash's `source` would treat the second word of
|
# Direct") — unquoted, bash's `source` would treat the second word of
|
||||||
# any such value as a command to run ("Direct: command not found"),
|
# any such value as a command to run ("Direct: command not found"),
|
||||||
# confirmed live while testing the multi-IP change.
|
# confirmed live while testing the multi-IP change.
|
||||||
|
backup_if_exists "$EA_DIR/.pstn-trunk.env"
|
||||||
cat > "$EA_DIR/.pstn-trunk.env" << ENV
|
cat > "$EA_DIR/.pstn-trunk.env" << ENV
|
||||||
PROVIDER_NAME="${PROVIDER_NAME}"
|
PROVIDER_NAME="${PROVIDER_NAME}"
|
||||||
TRUNK_SERVER="${SERVER}"
|
TRUNK_SERVER="${SERVER}"
|
||||||
|
|||||||
@@ -91,6 +91,11 @@ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
||||||
@@ -230,6 +235,7 @@ install_rustdesk() {
|
|||||||
prompt_yn "Require encrypted connections only? (recommended) (y/n):" "y" _enc
|
prompt_yn "Require encrypted connections only? (recommended) (y/n):" "y" _enc
|
||||||
[ "$_enc" = "n" ] || [ "$_enc" = "N" ] && ENCRYPTED_ONLY="0"
|
[ "$_enc" = "n" ] || [ "$_enc" = "N" ] && ENCRYPTED_ONLY="0"
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << RD_COMPOSE
|
cat > docker-compose.yml << RD_COMPOSE
|
||||||
name: $CONTAINER
|
name: $CONTAINER
|
||||||
|
|
||||||
@@ -251,6 +257,7 @@ services:
|
|||||||
- ./rustdesk_data:/data
|
- ./rustdesk_data:/data
|
||||||
RD_COMPOSE
|
RD_COMPOSE
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << RD_ENV
|
cat > .env << RD_ENV
|
||||||
# ── General ───────────────────────────────────────────────────────────────────
|
# ── General ───────────────────────────────────────────────────────────────────
|
||||||
TZ=$TZ_VAL
|
TZ=$TZ_VAL
|
||||||
|
|||||||
@@ -60,6 +60,11 @@ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
||||||
@@ -176,6 +181,7 @@ EOF
|
|||||||
prompt_text " WEB_EXT_API_KEY (e.g. user:12345678:901), blank to skip:" "" FF_KEY
|
prompt_text " WEB_EXT_API_KEY (e.g. user:12345678:901), blank to skip:" "" FF_KEY
|
||||||
prompt_text " WEB_EXT_API_SECRET, blank to skip:" "" FF_SECRET
|
prompt_text " WEB_EXT_API_SECRET, blank to skip:" "" FF_SECRET
|
||||||
if [ -n "$FF_KEY" ] && [ -n "$FF_SECRET" ]; then
|
if [ -n "$FF_KEY" ] && [ -n "$FF_SECRET" ]; then
|
||||||
|
backup_if_exists "$SS_DIR/.env"
|
||||||
cat > "$SS_DIR/.env" << ENVEOF
|
cat > "$SS_DIR/.env" << ENVEOF
|
||||||
WEB_EXT_API_KEY="$FF_KEY"
|
WEB_EXT_API_KEY="$FF_KEY"
|
||||||
WEB_EXT_API_SECRET="$FF_SECRET"
|
WEB_EXT_API_SECRET="$FF_SECRET"
|
||||||
|
|||||||
@@ -177,6 +177,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
||||||
@@ -242,6 +247,7 @@ networks:
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << PDF_COMPOSE
|
cat > docker-compose.yml << PDF_COMPOSE
|
||||||
name: stirling-pdf
|
name: stirling-pdf
|
||||||
|
|
||||||
@@ -261,6 +267,7 @@ services:
|
|||||||
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
||||||
PDF_COMPOSE
|
PDF_COMPOSE
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << PDF_ENV
|
cat > .env << PDF_ENV
|
||||||
# Stirling PDF configuration
|
# Stirling PDF configuration
|
||||||
|
|
||||||
|
|||||||
@@ -147,6 +147,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
||||||
@@ -225,6 +230,7 @@ networks:
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << EOF
|
cat > docker-compose.yml << EOF
|
||||||
name: syncthing
|
name: syncthing
|
||||||
|
|
||||||
@@ -249,6 +255,7 @@ services:
|
|||||||
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << ENV
|
cat > .env << ENV
|
||||||
CADDY_NET=$SITE_CADDY_NET
|
CADDY_NET=$SITE_CADDY_NET
|
||||||
PUID=$PUID
|
PUID=$PUID
|
||||||
|
|||||||
@@ -180,6 +180,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
||||||
@@ -474,6 +479,7 @@ networks:
|
|||||||
- \"${PROTO_MIN}-${PROTO_MAX}:${PROTO_MIN}-${PROTO_MAX}/udp\""
|
- \"${PROTO_MIN}-${PROTO_MAX}:${PROTO_MIN}-${PROTO_MAX}/udp\""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << TRACCAR_COMPOSE
|
cat > docker-compose.yml << TRACCAR_COMPOSE
|
||||||
name: $CONTAINER
|
name: $CONTAINER
|
||||||
|
|
||||||
@@ -560,6 +566,7 @@ SMS_HTTP_PASSWORD=$SMS_HTTP_PASSWORD
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << TRACCAR_ENV
|
cat > .env << TRACCAR_ENV
|
||||||
TZ=$TZ_VAL
|
TZ=$TZ_VAL
|
||||||
CADDY_NET=$SITE_CADDY_NET
|
CADDY_NET=$SITE_CADDY_NET
|
||||||
|
|||||||
@@ -89,6 +89,11 @@ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
||||||
@@ -238,6 +243,7 @@ networks:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Unquoted heredoc; ${...} used for caddy_net vars; all Docker Compose vars escaped with \$
|
# Unquoted heredoc; ${...} used for caddy_net vars; all Docker Compose vars escaped with \$
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << UNIFI_COMPOSE
|
cat > docker-compose.yml << UNIFI_COMPOSE
|
||||||
name: $PROJECT
|
name: $PROJECT
|
||||||
|
|
||||||
@@ -286,6 +292,7 @@ configs:
|
|||||||
db.getSiblingDB("\${MONGO_DBNAME}_stat").createUser({user: "\${MONGO_USER}", pwd: "\${MONGO_PASS}", roles: [{role: "\${MONGO_ROLE}", db: "\${MONGO_DBNAME}_stat"}]});
|
db.getSiblingDB("\${MONGO_DBNAME}_stat").createUser({user: "\${MONGO_USER}", pwd: "\${MONGO_PASS}", roles: [{role: "\${MONGO_ROLE}", db: "\${MONGO_DBNAME}_stat"}]});
|
||||||
UNIFI_COMPOSE
|
UNIFI_COMPOSE
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << UNIFI_ENV
|
cat > .env << UNIFI_ENV
|
||||||
# ── General ───────────────────────────────────────────────────────────────────
|
# ── General ───────────────────────────────────────────────────────────────────
|
||||||
TZ=$TZ_VAL
|
TZ=$TZ_VAL
|
||||||
|
|||||||
@@ -177,6 +177,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
||||||
@@ -277,6 +282,7 @@ ${UPTIME_ENV_BLOCK}
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << UPTIME_COMPOSE
|
cat > docker-compose.yml << UPTIME_COMPOSE
|
||||||
name: uptime-kuma
|
name: uptime-kuma
|
||||||
|
|
||||||
|
|||||||
@@ -194,6 +194,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
||||||
@@ -420,6 +425,7 @@ networks:
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << VW_COMPOSE
|
cat > docker-compose.yml << VW_COMPOSE
|
||||||
name: $CONTAINER
|
name: $CONTAINER
|
||||||
|
|
||||||
@@ -437,6 +443,7 @@ services:
|
|||||||
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
||||||
VW_COMPOSE
|
VW_COMPOSE
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << VW_ENV
|
cat > .env << VW_ENV
|
||||||
# ── General ───────────────────────────────────────────────────────────────────
|
# ── General ───────────────────────────────────────────────────────────────────
|
||||||
TZ=$TZ_VAL
|
TZ=$TZ_VAL
|
||||||
|
|||||||
@@ -64,6 +64,11 @@ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
||||||
@@ -151,6 +156,7 @@ networks:
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << WT_COMPOSE
|
cat > docker-compose.yml << WT_COMPOSE
|
||||||
name: watchtower
|
name: watchtower
|
||||||
|
|
||||||
@@ -179,6 +185,7 @@ ${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
|||||||
WT_COMPOSE
|
WT_COMPOSE
|
||||||
|
|
||||||
# Create .env
|
# Create .env
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << WT_ENV
|
cat > .env << WT_ENV
|
||||||
# Watchtower Configuration
|
# Watchtower Configuration
|
||||||
# =========================
|
# =========================
|
||||||
|
|||||||
@@ -68,6 +68,11 @@ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
||||||
@@ -126,6 +131,7 @@ install_watchyourlan() {
|
|||||||
prompt_text "GUI port [8840]:" "8840" GUI_PORT
|
prompt_text "GUI port [8840]:" "8840" GUI_PORT
|
||||||
[ -z "$GUI_PORT" ] && GUI_PORT="8840"
|
[ -z "$GUI_PORT" ] && GUI_PORT="8840"
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << 'WYL_COMPOSE'
|
cat > docker-compose.yml << 'WYL_COMPOSE'
|
||||||
name: watchyourlan
|
name: watchyourlan
|
||||||
|
|
||||||
@@ -141,6 +147,7 @@ services:
|
|||||||
- ./watchyourlan_data:/data
|
- ./watchyourlan_data:/data
|
||||||
WYL_COMPOSE
|
WYL_COMPOSE
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << WYL_ENV
|
cat > .env << WYL_ENV
|
||||||
# ── General ───────────────────────────────────────────────────────────────────
|
# ── General ───────────────────────────────────────────────────────────────────
|
||||||
TZ=$TZ_VAL
|
TZ=$TZ_VAL
|
||||||
|
|||||||
@@ -199,6 +199,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
||||||
@@ -302,6 +307,7 @@ networks:
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << WGEASY_COMPOSE
|
cat > docker-compose.yml << WGEASY_COMPOSE
|
||||||
name: wg-easy
|
name: wg-easy
|
||||||
|
|
||||||
@@ -332,6 +338,7 @@ services:
|
|||||||
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
${_CADDY_NET_BLOCK}${_CADDY_NET_SECTION}
|
||||||
WGEASY_COMPOSE
|
WGEASY_COMPOSE
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << WGEASY_ENV
|
cat > .env << WGEASY_ENV
|
||||||
WG_HOST=$WG_HOST
|
WG_HOST=$WG_HOST
|
||||||
# Plain-text password — used only if PASSWORD_HASH could not be generated above
|
# Plain-text password — used only if PASSWORD_HASH could not be generated above
|
||||||
|
|||||||
@@ -169,6 +169,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
||||||
@@ -404,6 +409,7 @@ DOCKERFILE
|
|||||||
# network_mode: host — server.py reaches Wolf at localhost:47989 directly.
|
# network_mode: host — server.py reaches Wolf at localhost:47989 directly.
|
||||||
# Docker socket (ro) — server.py calls `docker logs wolf` to read secrets.
|
# Docker socket (ro) — server.py calls `docker logs wolf` to read secrets.
|
||||||
log_info "Writing docker-compose.yml..."
|
log_info "Writing docker-compose.yml..."
|
||||||
|
backup_if_exists "$WOLFPAIR_DIR/docker-compose.yml"
|
||||||
cat > "$WOLFPAIR_DIR/docker-compose.yml" << 'COMPOSE'
|
cat > "$WOLFPAIR_DIR/docker-compose.yml" << 'COMPOSE'
|
||||||
name: wolf-pair
|
name: wolf-pair
|
||||||
|
|
||||||
|
|||||||
@@ -179,6 +179,11 @@ CBLOCK
|
|||||||
mkdir -p "$_dir"
|
mkdir -p "$_dir"
|
||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
# Globals — ACTUAL_USER/ACTUAL_HOME must come before DOCKER_DIR
|
||||||
@@ -875,6 +880,7 @@ UDEV
|
|||||||
# if the drive is remounted at a different path. IP/MAC/render-node are
|
# if the drive is remounted at a different path. IP/MAC/render-node are
|
||||||
# baked in at install time because they're hardware-specific and not stored
|
# baked in at install time because they're hardware-specific and not stored
|
||||||
# in .env — use 'manage.sh update-network' to regenerate if they change.
|
# in .env — use 'manage.sh update-network' to regenerate if they change.
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << EOF
|
cat > docker-compose.yml << EOF
|
||||||
name: wolf
|
name: wolf
|
||||||
|
|
||||||
@@ -922,6 +928,7 @@ EOF
|
|||||||
log_success "docker-compose.yml created"
|
log_success "docker-compose.yml created"
|
||||||
|
|
||||||
# Save the game storage path so it's visible and editable later
|
# Save the game storage path so it's visible and editable later
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << EOF
|
cat > .env << EOF
|
||||||
# Wolf game/ROM storage root — edit this and run ./manage.sh update-storage to apply
|
# Wolf game/ROM storage root — edit this and run ./manage.sh update-storage to apply
|
||||||
GAME_STORAGE_DIR=${GAME_STORAGE_DIR}
|
GAME_STORAGE_DIR=${GAME_STORAGE_DIR}
|
||||||
|
|||||||
@@ -207,6 +207,11 @@ CBLOCK
|
|||||||
cat > "$_dir/README.md"
|
cat > "$_dir/README.md"
|
||||||
chown "$ACTUAL_USER:$ACTUAL_USER" "$_dir/README.md" 2>/dev/null || true
|
chown "$ACTUAL_USER:$ACTUAL_USER" "$_dir/README.md" 2>/dev/null || true
|
||||||
}
|
}
|
||||||
|
backup_if_exists() {
|
||||||
|
local _file="$1"
|
||||||
|
[ -f "$_file" ] || return 0
|
||||||
|
cp -p "$_file" "${_file}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
ACTUAL_USER="${ACTUAL_USER:-${SUDO_USER:-$USER}}"
|
||||||
@@ -361,6 +366,7 @@ PHPINI
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
backup_if_exists docker-compose.yml
|
||||||
cat > docker-compose.yml << WPCOMPOSE
|
cat > docker-compose.yml << WPCOMPOSE
|
||||||
name: $CONTAINER
|
name: $CONTAINER
|
||||||
|
|
||||||
@@ -398,6 +404,7 @@ networks:
|
|||||||
${_CADDY_NET_SECTION}
|
${_CADDY_NET_SECTION}
|
||||||
WPCOMPOSE
|
WPCOMPOSE
|
||||||
|
|
||||||
|
backup_if_exists .env
|
||||||
cat > .env << WPENV
|
cat > .env << WPENV
|
||||||
TZ=$TZ_VAL
|
TZ=$TZ_VAL
|
||||||
CADDY_NET=$SITE_CADDY_NET
|
CADDY_NET=$SITE_CADDY_NET
|
||||||
|
|||||||
Reference in New Issue
Block a user