Files
homelab-docs/scripts/deploy-immich-credentials.sh
Andrey 16c254510a Update documentation to centralize Vaultwarden integration details and enhance backup scripts
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.
2026-02-28 00:52:56 +03:00

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