올인원 PhotoPrism 설치/관리 스크립트
1. 올인원 PhotoPrism 설치/관리 스크립트
1) 아래 스크립트를 그대로 복사하여 우분투 터미널에 붙여넣기 하신 후 엔터키만 누르면 스크립트 파일이 생성 됩니다.
cat > setup-photoprism.sh <<'__SCRIPT__'
#!/usr/bin/env bash
set -euo pipefail
# ==========================================================
# PhotoPrism 올인원 설치기 (재귀 감시 즉시 반영 + WebDAV 업로드 허용)
# - Docker/Compose 설치
# - MariaDB 연동
# - VAAPI 자동 감지
# - systemd 등록/자동 시작
# - WebDAV 기본 활성 (/import 업로드)
# - AUTH_MODE=password, UPLOAD_NSFW=true, READONLY=false
# - inotify 재귀감시로 업로드 즉시 import+index
# - --update-site 로 PHOTOPRISM_SITE_URL 갱신
# ==========================================================
# 루트 보장
if [[ $EUID -ne 0 ]]; then exec sudo -E bash "$0" "$@"; fi
PORT="${PORT:-2342}"
TZ="${TZ:-Asia/Seoul}"
rand() { openssl rand -base64 24 | tr -d '\n=' | cut -c1-32; }
trim() { echo -n "${1:-}" | tr -d '[:space:]'; }
normalize_url() {
local u="$(trim "${1:-}")"
[ -z "$u" ] && { echo ""; return 0; }
u="${u%/}"; [[ ! "$u" =~ ^https?:// ]] && u="https://$u"; echo "$u"
}
detect_vaapi() { [ -e /dev/dri ] && echo "true" || echo "false"; }
ADMIN_USER="${SUDO_USER:-$USER}"
ADMIN_HOME="$(getent passwd "$ADMIN_USER" | cut -d: -f6)"
BASE_DIR="${ADMIN_HOME}/photoprism"
DATA_DIR="${BASE_DIR}/data"
ORIGINALS_DIR="${BASE_DIR}/originals"
IMPORT_DIR="${BASE_DIR}/import"
STORAGE_DIR="${BASE_DIR}/storage"
ENV_FILE="${BASE_DIR}/.env"
COMPOSE_FILE="${BASE_DIR}/docker-compose.yml"
SERVICE_FILE="/etc/systemd/system/photoprism.service"
INFO_FILE="${BASE_DIR}/INSTALL_INFO.txt"
# ---- update-site 모드 ----
if [[ "${1:-}" == "--update-site" ]]; then
if [ ! -f "$ENV_FILE" ]; then echo "[!] ${ENV_FILE} 없음. 먼저 설치하세요."; exit 1; fi
SITE_URL_INPUT="${SITE_URL:-}"
if [ -z "$(trim "$SITE_URL_INPUT")" ]; then read -rp "새 도메인 (예: photos.example.com): " SITE_URL_INPUT; fi
NEW_URL="$(normalize_url "$SITE_URL_INPUT")"
[ -z "$NEW_URL" ] && { echo "[!] 빈 값은 허용 안 함"; exit 1; }
sed -i "s|^PHOTOPRISM_SITE_URL=.*|PHOTOPRISM_SITE_URL=${NEW_URL}|" "$ENV_FILE"
systemctl restart photoprism
NOW="$(date '+%Y-%m-%d %H:%M:%S')"
echo "== 도메인 갱신 완료 =="; echo "시각: ${NOW}"; echo "새 주소: ${NEW_URL}"
{ echo; echo "# [도메인 갱신] ${NOW}"; echo "# PHOTOPRISM_SITE_URL=${NEW_URL}"; } >> "$INFO_FILE"
exit 0
fi
echo "==[ PhotoPrism 설치 ]=="
echo "관리자: ${ADMIN_USER} 경로: ${BASE_DIR} 포트: ${PORT} TZ: ${TZ}"
echo
get_value() {
local ENV_NAME="$1" PROMPT="$2" DTYPE="$3" DFIXED="${4:-}"
local CUR="$(trim "${!ENV_NAME:-}")"
if [ -n "$CUR" ]; then echo "$CUR"; return; fi
read -rp "$PROMPT" CUR || true; CUR="$(trim "$CUR")"
if [ -n "$CUR" ]; then echo "$CUR"; return; fi
if [ "$DTYPE" = "random" ]; then rand; else echo "$DFIXED"; fi
}
ADMIN_ID="$(get_value ADMIN_ID "관리자 아이디(기본=admin): " fixed "admin")"
ADMIN_PASS="$(get_value ADMIN_PASS "관리자 비번(엔터=랜덤): " random)"
DB_ROOT_PASS="$(get_value DB_ROOT_PASS "DB root 비번(엔터=랜덤): " random)"
DB_PASS="$(get_value DB_PASS "DB 사용자 비번(엔터=랜덤): " random)"
SITE_URL_RAW="$(get_value SITE_URL "사이트 도메인(엔터=비움): " fixed "")"
SITE_URL="$(normalize_url "$SITE_URL_RAW")"
DB_NAME="photoprism"; DB_USER="photoprism"
echo; echo "[적용값] ADMIN_ID=${ADMIN_ID} SITE_URL=${SITE_URL:-<비움>} PORT/TZ=${PORT}/${TZ}"; echo
# ---- Docker 설치 ----
if ! command -v docker >/dev/null 2>&1; then
echo "[*] Docker 설치 중..."
apt update -y
apt install -y ca-certificates curl gnupg lsb-release
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --batch --yes --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" > /etc/apt/sources.list.d/docker.list
apt update -y
apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
usermod -aG docker "${ADMIN_USER}" || true
fi
apt install -y inotify-tools >/dev/null 2>&1 || true
mkdir -p "${DATA_DIR}" "${ORIGINALS_DIR}" "${IMPORT_DIR}" "${STORAGE_DIR}"
chown -R "${ADMIN_USER}:${ADMIN_USER}" "${BASE_DIR}"
# ---- .env 생성 (업로드 허용 옵션 포함) ----
cat > "${ENV_FILE}" <<EOF
PHOTOPRISM_ADMIN_USER=${ADMIN_ID}
PHOTOPRISM_ADMIN_PASSWORD=${ADMIN_PASS}
PHOTOPRISM_SITE_URL=${SITE_URL}
PHOTOPRISM_ORIGINALS_PATH=/photoprism/originals
PHOTOPRISM_IMPORT_PATH=/photoprism/import
PHOTOPRISM_STORAGE_PATH=/photoprism/storage
PHOTOPRISM_PUBLIC=false
PHOTOPRISM_DISABLE_WEBDAV=false
PHOTOPRISM_READONLY=false
PHOTOPRISM_AUTH_MODE=password
PHOTOPRISM_UPLOAD_NSFW=true
PHOTOPRISM_WORKERS=2
PHOTOPRISM_AUTO_INDEX=1
UMASK=0002
TZ=${TZ}
PHOTOPRISM_DATABASE_DRIVER=mysql
PHOTOPRISM_DATABASE_SERVER=mariadb:3306
PHOTOPRISM_DATABASE_NAME=${DB_NAME}
PHOTOPRISM_DATABASE_USER=${DB_USER}
PHOTOPRISM_DATABASE_PASSWORD=${DB_PASS}
PHOTOPRISM_FFMPEG_ENCODER=software
EOF
# ---- VAAPI 감지 ----
if [ "$(detect_vaapi)" = "true" ]; then
sed -i 's/^PHOTOPRISM_FFMPEG_ENCODER=.*/PHOTOPRISM_FFMPEG_ENCODER=vaapi/' "${ENV_FILE}"
HW_EXTRA="devices:
- /dev/dri:/dev/dri"
echo "[*] VAAPI 감지 → 하드웨어 가속 활성화"
else
HW_EXTRA=""
echo "[*] VAAPI 미감지 → 소프트웨어 인코딩"
fi
# ---- docker-compose.yml ----
cat > "${COMPOSE_FILE}" <<EOF
services:
mariadb:
image: docker.io/library/mariadb:11.4
container_name: photoprism-db
restart: unless-stopped
environment:
- MARIADB_DATABASE=${DB_NAME}
- MARIADB_USER=${DB_USER}
- MARIADB_PASSWORD=${DB_PASS}
- MARIADB_ROOT_PASSWORD=${DB_ROOT_PASS}
- MARIADB_AUTO_UPGRADE=1
- TZ=${TZ}
volumes:
- ${DATA_DIR}/mysql:/var/lib/mysql
photoprism:
image: docker.io/photoprism/photoprism:latest
container_name: photoprism-app
depends_on:
- mariadb
restart: unless-stopped
env_file:
- .env
ports:
- "${PORT}:2342"
volumes:
- ${ORIGINALS_DIR}:/photoprism/originals
- ${IMPORT_DIR}:/photoprism/import
- ${STORAGE_DIR}:/photoprism/storage
$( [ -n "${HW_EXTRA}" ] && echo " ${HW_EXTRA}" )
EOF
# ---- systemd: photoprism compose 서비스 ----
cat > "${SERVICE_FILE}" <<EOF
[Unit]
Description=PhotoPrism (Docker Compose)
After=network-online.target docker.service
Wants=network-online.target
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=${BASE_DIR}
ExecStart=/usr/bin/docker compose up -d
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=0
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable photoprism
# ---- 이미지 미리 당겨오기 (Docker Hub) ----
/usr/bin/docker pull docker.io/library/mariadb:11.4 || true
/usr/bin/docker pull docker.io/photoprism/photoprism:latest || true
# ---- 서비스 시작 ----
( cd "$BASE_DIR" && /usr/bin/docker compose pull || true )
systemctl start photoprism
# =========================
# 재귀 감시 → 즉시 import+index
# =========================
# 1) 워처 스크립트
cat > /usr/local/bin/photoprism-reindex-watch.sh << "EOSH"
#!/usr/bin/env bash
set -euo pipefail
CONTAINER="photoprism-app"
WATCH_DIR="__IMPORT_DIR__"
mkdir -p "$WATCH_DIR"
reindex() {
if ! /usr/bin/docker ps --format '{{.Names}}' | grep -qx "$CONTAINER"; then exit 0; fi
/usr/bin/docker exec "$CONTAINER" photoprism import --path /photoprism/import --move -a || true
/usr/bin/docker exec "$CONTAINER" photoprism index -a || true
}
# 중복 실행 방지 + 디바운스
exec 9>/tmp/photoprism-reindex.lock
flock -n 9 || exit 0
# 최초 1회
reindex
# 재귀 감시: 생성/이동/쓰기완료/삭제/속성변경
while inotifywait -r -e create,move,close_write,delete,attrib "$WATCH_DIR"; do
sleep 3
reindex
done
EOSH
sed -i "s|__IMPORT_DIR__|${IMPORT_DIR}|g" /usr/local/bin/photoprism-reindex-watch.sh
chmod +x /usr/local/bin/photoprism-reindex-watch.sh
# 2) 워처 서비스 (항상 실행)
cat > /etc/systemd/system/photoprism-reindex-watch.service << "EOU"
[Unit]
Description=PhotoPrism recursive reindex watcher
After=docker.service
StartLimitIntervalSec=0
[Service]
Type=simple
User=root
ExecStart=/usr/local/bin/photoprism-reindex-watch.sh
Restart=always
RestartSec=2
[Install]
WantedBy=multi-user.target
EOU
systemctl daemon-reload
systemctl enable --now photoprism-reindex-watch.service
NOW="$(date '+%Y-%m-%d %H:%M:%S')"
DEFAULT_ADDR="http://<서버IP>:${PORT}"
SHOW_ADDR="${SITE_URL:-$DEFAULT_ADDR}"
echo
echo "== 설치 완료! =="
echo "설치 시각 : ${NOW}"
echo "접속 주소 : ${SHOW_ADDR}"
echo "관리자 계정: ${ADMIN_ID}"
echo "관리자 비번: ${ADMIN_PASS}"
echo "DB root 비번: ${DB_ROOT_PASS}"
echo "DB 계정 : ${DB_USER} / ${DB_PASS}"
cat > "${INFO_FILE}" <<EOF
# ===== PhotoPrism 설치 정보 =====
설치 시각 : ${NOW}
접속주소 : ${SHOW_ADDR}
관리자 : ${ADMIN_ID}
관리자PW : ${ADMIN_PASS}
DB rootPW : ${DB_ROOT_PASS}
DB 계정 : ${DB_USER} / ${DB_PASS}
경로 안내 :
originals: ${ORIGINALS_DIR}
import : ${IMPORT_DIR}
storage : ${STORAGE_DIR}
EOF
cat >> "$0" <<EOF
# ===== [설치 당시 계정/환경 기록] =====
# 설치 시각 : ${NOW}
# 접속주소 : ${SHOW_ADDR}
# 관리자 : ${ADMIN_ID}
# 관리자PW : ${ADMIN_PASS}
# DB rootPW : ${DB_ROOT_PASS}
# DB 계정 : ${DB_USER} / ${DB_PASS}
EOF
echo
echo "[관리]"
echo " 상태 : systemctl status photoprism"
echo " 재시작 : systemctl restart photoprism"
echo " 중지 : systemctl stop photoprism"
echo
echo "[재귀 감시]"
echo " 상태 : systemctl status photoprism-reindex-watch.service"
echo " 로그 : journalctl -fu photoprism-reindex-watch.service"
echo
echo "[업데이트]"
echo " cd ${BASE_DIR} && docker compose pull && systemctl restart photoprism"
__SCRIPT__
2) 실행 파일 권한 부여
chmod +x setup-photoprism.sh
3) 실행 방법 2가지 ( 2개중에 하나로 실행하면됨. )
① 기본 실행 ( 중간 중간 암호 입력 하라는 메세지가 뜸.)
sudo bash setup-photoprism.sh
② 환경 변수 추가하여 완전 자동 실행 ( 암호는 모두 동일하게 실행하고, 사이트 URL없는 경우 환경변수 삭제해도 됨 )
sudo env ADMIN_ID="우분투관리자ID" ADMIN_PASS="암호" DB_ROOT_PASS="암호" DB_PASS="암호" SITE_URL="photos.example.com" bash setup-photoprism.sh
4) 최초 PhotoPrism 설치 후 SITE_URL 도메인 주소가 추가 되었을 경우 아래 명령어를 입력하면 자동 수정됨.
① 도메인 주소만 바꿀 때
sudo SITE_URL="새로운 도메인 주소" bash setup-photoprism.sh --update-site
5) 설치 후 검사
① sudo systemctl status photoprism
※ Active 항목에 active(exited)로 표시되면 정상
② docker ps
※NAME에 Photoprism 이 들어가는 것들의 STATUS가 UP으로 되어 있으면 정상
2. 올인원 PhotoPrism 한방 제거 스크립트
cat > uninstall-photoprism.sh <<'__SCRIPT__'
#!/usr/bin/env bash
set -euo pipefail
# ============================================
# PhotoPrism 완전 삭제 스크립트
# - systemd 서비스/패스 유닛 제거
# - Docker compose down(-v), 컨테이너/네트워크 정리
# - (옵션) 데이터 디렉터리 완전 삭제
# - (옵션) Docker 이미지 제거
# - (옵션) 설치 경로 변경 지원
# ============================================
# 기본값 (setup 스크립트와 동일)
ADMIN_USER="${SUDO_USER:-${USER}}"
ADMIN_HOME="$(getent passwd "$ADMIN_USER" | cut -d: -f6)"
BASE_DIR="${BASE_DIR:-${ADMIN_HOME}/photoprism}"
# 파일/유닛/이름들
SERVICE_FILE="/etc/systemd/system/photoprism.service"
REINDEX_SVC="/etc/systemd/system/photoprism-reindex.service"
REINDEX_PATH="/etc/systemd/system/photoprism-reindex.path"
REINDEX_BIN="/usr/local/bin/photoprism-reindex.sh"
COMPOSE_FILE="${BASE_DIR}/docker-compose.yml"
ENV_FILE="${BASE_DIR}/.env"
# 컨테이너 이름
APP_CTN="photoprism-app"
DB_CTN="photoprism-db"
PURGE_PHOTOS=false # originals/import/storage 포함 BASE_DIR 삭제
PURGE_IMAGES=false # docker images 삭제
NO_PROMPT=false # 파괴적 동작 확인 프롬프트 생략
usage() {
cat <<USAGE
PhotoPrism 완전 삭제 스크립트
사용법:
sudo bash uninstall-photoprism.sh [옵션]
옵션:
--purge 데이터 디렉터리까지 전부 삭제(BASE_DIR 내 originals/import/storage 포함) [영구 삭제]
--purge-images photoprism/photoprism, mariadb 이미지까지 삭제
--base-dir PATH 설치 경로가 다를 때 지정(기본: \$HOME/photoprism)
--yes 확인 프롬프트 생략(비대화식)
예시:
sudo bash uninstall-photoprism.sh
sudo bash uninstall-photoprism.sh --purge
sudo bash uninstall-photoprism.sh --purge --purge-images
sudo BASE_DIR=/DATA/photoprism bash uninstall-photoprism.sh --purge --yes
USAGE
}
# 인자 파싱
while [[ $# -gt 0 ]]; do
case "$1" in
--purge) PURGE_PHOTOS=true; shift;;
--purge-images) PURGE_IMAGES=true; shift;;
--base-dir) BASE_DIR="$2"; shift 2;;
--yes|-y) NO_PROMPT=true; shift;;
-h|--help) usage; exit 0;;
*) echo "[!] 알 수 없는 옵션: $1"; usage; exit 1;;
esac
done
echo "==[ PhotoPrism 완전 삭제 ]=="
echo "대상 경로 : ${BASE_DIR}"
echo "서비스 : ${SERVICE_FILE}"
echo "리인덱스 : ${REINDEX_SVC}, ${REINDEX_PATH}"
echo "옵션 : purge_photos=${PURGE_PHOTOS} purge_images=${PURGE_IMAGES} no_prompt=${NO_PROMPT}"
echo
# 루트 권한 보장
if [[ $EUID -ne 0 ]]; then
exec sudo BASE_DIR="${BASE_DIR}" PURGE_PHOTOS="${PURGE_PHOTOS}" PURGE_IMAGES="${PURGE_IMAGES}" NO_PROMPT="${NO_PROMPT}" bash "$0" "$@"
fi
confirm() {
$NO_PROMPT && return 0
read -r -p "$1 [y/N]: " ans
[[ "$ans" == "y" || "$ans" == "Y" ]]
}
# 1) systemd 유닛 중지/해제/삭제
echo "[1/6] systemd 유닛 정리..."
systemctl stop photoprism 2>/dev/null || true
systemctl disable photoprism 2>/dev/null || true
rm -f "${SERVICE_FILE}" 2>/dev/null || true
systemctl stop photoprism-reindex.path 2>/dev/null || true
systemctl disable photoprism-reindex.path 2>/dev/null || true
rm -f "${REINDEX_PATH}" 2>/dev/null || true
systemctl stop photoprism-reindex.service 2>/dev/null || true
systemctl disable photoprism-reindex.service 2>/dev/null || true
rm -f "${REINDEX_SVC}" 2>/dev/null || true
systemctl daemon-reload || true
# 2) reindex 스크립트 삭제
echo "[2/6] reindex 실행 스크립트 삭제..."
rm -f "${REINDEX_BIN}" 2>/dev/null || true
# 3) docker compose down(-v) 또는 개별 컨테이너 제거
echo "[3/6] Docker 컨테이너/네트워크 정리..."
if [[ -f "${COMPOSE_FILE}" ]]; then
(cd "${BASE_DIR}" && docker compose down -v || true)
else
docker rm -f "${APP_CTN}" 2>/dev/null || true
docker rm -f "${DB_CTN}" 2>/dev/null || true
fi
# 남은 네트워크 정리(있으면)
docker network prune -f >/dev/null 2>&1 || true
docker volume prune -f >/dev/null 2>&1 || true
# 4) 이미지 제거(옵션)
if [[ "${PURGE_IMAGES}" == "true" ]]; then
echo "[4/6] Docker 이미지 제거..."
docker images --format '{{.Repository}}:{{.Tag}} {{.ID}}' \
| awk '/^photoprism\/photoprism:/ {print $2}' \
| xargs -r docker rmi || true
docker images --format '{{.Repository}}:{{.Tag}} {{.ID}}' \
| awk '/^mariadb:/ {print $2}' \
| xargs -r docker rmi || true
fi
# 5) 설정/데이터 삭제
echo "[5/6] 파일/디렉터리 정리..."
if [[ -d "${BASE_DIR}" ]]; then
if [[ "${PURGE_PHOTOS}" == "true" ]]; then
if confirm "[!!] ${BASE_DIR} 전체(사진 포함)를 영구 삭제할까요?"; then
rm -rf "${BASE_DIR}"
echo "[OK] ${BASE_DIR} 전체 삭제 완료."
else
echo "[취소] 데이터 삭제를 건너뜁니다."
# 설정 파일만 제거
rm -f "${COMPOSE_FILE}" "${ENV_FILE}" "${BASE_DIR}/INSTALL_INFO.txt" 2>/dev/null || true
fi
else
echo "[i] 데이터는 보존하고 구성 파일만 삭제합니다."
rm -f "${COMPOSE_FILE}" "${ENV_FILE}" "${BASE_DIR}/INSTALL_INFO.txt" 2>/dev/null || true
# 비어있으면 디렉터리 제거 시도
rmdir "${BASE_DIR}/data" 2>/dev/null || true
rmdir "${BASE_DIR}" 2>/dev/null || true
fi
else
echo "[i] ${BASE_DIR} 가 존재하지 않습니다(건너뜀)."
fi
# 6) 최종 정리 메시지
echo
echo "== 정리 완료 =="
echo "- 남은 이미지 일괄 정리: docker image prune -a"
echo "- 남은 볼륨 정리: docker volume prune"
echo "- (재설치) setup-photoprism.sh 로 다시 설치하세요."
__SCRIPT__
2) 실행 파일 권한 부여
chmod +x uninstall-photoprism.sh
3) 실행 방법
① 기본 제거(사진 보존)
sudo bash uninstall-photoprism.sh
② 사진까지 전부 삭제(영구 삭제!)
sudo bash uninstall-photoprism.sh --purge
③ 이미지(photoprism, mariadb)까지 지우고 싶다면:
sudo bash uninstall-photoprism.sh --purge --purge-images
④ 설치 경로를 바꿔서 설치했었다면
sudo BASE_DIR=설치경로 bash uninstall-photoprism.sh --purge
공개 마지막 업데이트: 2025-09-25 11:38:52 AM