Refactor README, architecture, and backup documentation to emphasize the use of Vaultwarden for credential management across various services. Update scripts for Nextcloud, Gitea, Paperless, and others to reference Vaultwarden for sensitive information. Remove outdated references to previous backup strategies and ensure clarity on credential retrieval processes. This improves security practices and streamlines backup operations.
177 lines
5.7 KiB
Bash
177 lines
5.7 KiB
Bash
#!/bin/bash
|
|
# deploy-immich-credentials.sh — деплой кредов Immich и immich-deduper на VM 200
|
|
# Секреты из Vaultwarden (объекты IMMICH, IMMICH_DEDUPER).
|
|
#
|
|
# Использование:
|
|
# /root/scripts/deploy-immich-credentials.sh
|
|
# /root/scripts/deploy-immich-credentials.sh --dry-run
|
|
#
|
|
# Требования: bw, jq, /root/.bw-master, SSH без пароля root@host → admin@192.168.1.200
|
|
#
|
|
# Vaultwarden: IMMICH — поля DB_PASSWORD, IMMICH_API_KEY, GEMINI_API_KEY и др. (см. .env).
|
|
# IMMICH_DEDUPER — поля PSQL_PASS, DEDUP_*, IMMICH_PATH, PSQL_*.
|
|
|
|
set -e
|
|
|
|
VM_SSH="admin@192.168.1.200"
|
|
IMMICH_PATH="/opt/immich"
|
|
DEDUPER_PATH="/opt/immich-deduper"
|
|
BW_MASTER_FILE="${BW_MASTER_PASSWORD_FILE:-/root/.bw-master}"
|
|
DRY_RUN=false
|
|
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--dry-run) DRY_RUN=true ;;
|
|
esac
|
|
done
|
|
|
|
export PATH="/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:${PATH}"
|
|
|
|
log() { echo "[$(date -Iseconds)] $*"; }
|
|
err() { echo "[$(date -Iseconds)] ERROR: $*" >&2; }
|
|
|
|
ensure_bw_unlocked() {
|
|
local status
|
|
status=$(bw status 2>/dev/null | jq -r '.status' 2>/dev/null || echo "unknown")
|
|
if [ "$status" = "unlocked" ]; then
|
|
log "bw already unlocked, reusing session"
|
|
return 0
|
|
fi
|
|
if [ ! -f "$BW_MASTER_FILE" ]; then
|
|
err "Missing $BW_MASTER_FILE"
|
|
exit 1
|
|
fi
|
|
export BW_SESSION=$(bw unlock --passwordfile "$BW_MASTER_FILE" --raw 2>/dev/null) || {
|
|
err "bw unlock failed"
|
|
exit 1
|
|
}
|
|
log "bw unlocked"
|
|
}
|
|
|
|
get_field() {
|
|
local item="$1" name="$2"
|
|
echo "$item" | jq -r ".fields[] | select(.name==\"$name\") | .value // empty"
|
|
}
|
|
|
|
get_immich_secrets() {
|
|
local id
|
|
id=$(bw list items --search IMMICH 2>/dev/null | jq -r '.[] | select(.name=="IMMICH") | .id' | head -1) || true
|
|
[ -z "$id" ] && id=$(bw list items 2>/dev/null | jq -r '.[] | select(.name=="IMMICH") | .id' | head -1) || true
|
|
[ -z "$id" ] && { err "IMMICH not found in Vaultwarden"; exit 1; }
|
|
IMMICH_ITEM=$(bw get item "$id" 2>/dev/null) || { err "IMMICH get item failed for id=$id"; exit 1; }
|
|
DB_PASSWORD=$(get_field "$IMMICH_ITEM" "DB_PASSWORD")
|
|
IMMICH_API_KEY=$(get_field "$IMMICH_ITEM" "IMMICH_API_KEY")
|
|
GEMINI_API_KEY=$(get_field "$IMMICH_ITEM" "GEMINI_API_KEY")
|
|
if [ -z "$DB_PASSWORD" ]; then err "IMMICH: missing DB_PASSWORD field"; exit 1; fi
|
|
if [ -z "$IMMICH_API_KEY" ]; then err "IMMICH: missing IMMICH_API_KEY field"; exit 1; fi
|
|
}
|
|
|
|
get_deduper_secrets() {
|
|
local id
|
|
id=$(bw list items 2>/dev/null | jq -r '.[] | select(.name=="IMMICH_DEDUPER") | .id' | head -1)
|
|
[ -z "$id" ] && { err "IMMICH_DEDUPER not found in Vaultwarden"; exit 1; }
|
|
DEDUP_ITEM=$(bw get item "$id" 2>/dev/null) || {
|
|
err "IMMICH_DEDUPER not found in Vaultwarden"
|
|
exit 1
|
|
}
|
|
PSQL_PASS=$(get_field "$DEDUP_ITEM" "PSQL_PASS")
|
|
[ -z "$PSQL_PASS" ] && PSQL_PASS=$(echo "$DEDUP_ITEM" | jq -r '.login.password // empty')
|
|
DEDUP_PORT=$(get_field "$DEDUP_ITEM" "DEDUP_PORT")
|
|
DEDUP_DATA=$(get_field "$DEDUP_ITEM" "DEDUP_DATA")
|
|
DEDUP_IMAGE=$(get_field "$DEDUP_ITEM" "DEDUP_IMAGE")
|
|
IMMICH_PATH_FIELD=$(get_field "$DEDUP_ITEM" "IMMICH_PATH")
|
|
PSQL_HOST=$(get_field "$DEDUP_ITEM" "PSQL_HOST")
|
|
PSQL_PORT=$(get_field "$DEDUP_ITEM" "PSQL_PORT")
|
|
PSQL_DB=$(get_field "$DEDUP_ITEM" "PSQL_DB")
|
|
[ -z "$PSQL_PASS" ] && PSQL_PASS="${DB_PASSWORD:-}"
|
|
DEDUP_PORT="${DEDUP_PORT:-8086}"
|
|
DEDUP_DATA="${DEDUP_DATA:-/opt/immich-deduper/data}"
|
|
DEDUP_IMAGE="${DEDUP_IMAGE:-razgrizhsu/immich-deduper:latest-cpu}"
|
|
IMMICH_PATH_FIELD="${IMMICH_PATH_FIELD:-/mnt/data/library}"
|
|
PSQL_HOST="${PSQL_HOST:-database}"
|
|
PSQL_PORT="${PSQL_PORT:-5432}"
|
|
PSQL_DB="${PSQL_DB:-immich}"
|
|
}
|
|
|
|
gen_immich_env() {
|
|
local tmp
|
|
tmp=$(mktemp)
|
|
cat > "$tmp" << EOF
|
|
# Immich .env (generated from Vaultwarden)
|
|
UPLOAD_LOCATION=/mnt/data/library
|
|
DB_DATA_LOCATION=/mnt/data/postgres
|
|
IMMICH_VERSION=v2
|
|
DB_PASSWORD=${DB_PASSWORD}
|
|
DB_USERNAME=postgres
|
|
DB_DATABASE_NAME=immich
|
|
IMMICH_URL=http://immich-server:2283
|
|
IMMICH_API_KEY=${IMMICH_API_KEY}
|
|
DB_HOST=immich_postgres
|
|
DB_PORT=5432
|
|
EXTERNAL_IMMICH_URL=https://immich.katykhin.ru
|
|
GEMINI_API_KEY=${GEMINI_API_KEY}
|
|
EOF
|
|
echo "$tmp"
|
|
}
|
|
|
|
gen_deduper_env() {
|
|
local tmp
|
|
tmp=$(mktemp)
|
|
cat > "$tmp" << EOF
|
|
# Deduper .env (generated from Vaultwarden)
|
|
DEDUP_PORT=${DEDUP_PORT}
|
|
DEDUP_DATA=${DEDUP_DATA}
|
|
DEDUP_IMAGE=${DEDUP_IMAGE}
|
|
IMMICH_PATH=${IMMICH_PATH_FIELD}
|
|
PSQL_HOST=${PSQL_HOST}
|
|
PSQL_PORT=${PSQL_PORT}
|
|
PSQL_DB=${PSQL_DB}
|
|
PSQL_USER=postgres
|
|
PSQL_PASS=${PSQL_PASS}
|
|
EOF
|
|
echo "$tmp"
|
|
}
|
|
|
|
push_to_vm() {
|
|
local local_file="$1" remote_path="$2"
|
|
scp -o BatchMode=yes -o ConnectTimeout=10 -o StrictHostKeyChecking=accept-new -q "$local_file" "${VM_SSH}:/tmp/deploy-env.tmp" || {
|
|
err "scp to ${VM_SSH} failed. Ensure SSH key from Proxmox: ssh-copy-id ${VM_SSH}"
|
|
exit 1
|
|
}
|
|
ssh -o BatchMode=yes -o ConnectTimeout=10 "$VM_SSH" "sudo mv /tmp/deploy-env.tmp ${remote_path} && sudo chmod 600 ${remote_path}" || {
|
|
err "ssh to ${VM_SSH} failed"
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
run_compose() {
|
|
ssh -o BatchMode=yes "$VM_SSH" "cd ${IMMICH_PATH} && sudo docker compose up -d --force-recreate"
|
|
ssh -o BatchMode=yes "$VM_SSH" "cd ${DEDUPER_PATH} && sudo docker compose up -d --force-recreate"
|
|
log "Immich and deduper started"
|
|
}
|
|
|
|
main() {
|
|
log "deploy-immich-credentials start (dry_run=$DRY_RUN)"
|
|
ensure_bw_unlocked
|
|
get_immich_secrets
|
|
get_deduper_secrets
|
|
|
|
if [ "$DRY_RUN" = true ]; then
|
|
log "DRY-RUN: would push .env files and run compose"
|
|
log " DB_PASSWORD=*** IMMICH_API_KEY=***"
|
|
exit 0
|
|
fi
|
|
|
|
tmp_immich=$(gen_immich_env)
|
|
tmp_deduper=$(gen_deduper_env)
|
|
trap "rm -f $tmp_immich $tmp_deduper" EXIT
|
|
push_to_vm "$tmp_immich" "${IMMICH_PATH}/.env"
|
|
log "Immich .env written"
|
|
push_to_vm "$tmp_deduper" "${DEDUPER_PATH}/.env"
|
|
log "Deduper .env written"
|
|
run_compose
|
|
log "done"
|
|
}
|
|
|
|
main
|