fix(photoprism): Switch to SQLite database for simpler LXC setup
- Replace MariaDB with SQLite (no external database needed) - Update LXC config with proper device permissions and capabilities - Install libvips42 instead of mariadb-server - Fix binary path to ./bin/photoprism - Use environment variables instead of options.yml - Simplify backup to just archive storage directory - Update WIP.md with SQLite note Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
26519e7619
commit
7bcd09b81d
@ -16,7 +16,8 @@ _Last updated: 2026-03-06 (PhotoPrism Gallery)_
|
||||
- LuCI: `luci-app-photoprism` KISS dashboard with stats and actions
|
||||
- Features: AI face recognition, object detection, places/maps
|
||||
- HAProxy integration via mitmproxy (WAF-safe, no bypass)
|
||||
- MariaDB database, FFmpeg transcoding, HEIC support
|
||||
- SQLite database (simpler, no external DB), FFmpeg transcoding, HEIC support
|
||||
- Dependencies: libvips42 for image processing
|
||||
|
||||
- **AI Gateway `/login` Command**
|
||||
- CLI: `aigatewayctl login [provider]` - Interactive or scripted provider authentication
|
||||
|
||||
@ -10,7 +10,7 @@ LXC_PATH="/srv/lxc"
|
||||
LXC_ROOTFS="${LXC_PATH}/${LXC_NAME}/rootfs"
|
||||
LXC_CONFIG="${LXC_PATH}/${LXC_NAME}/config"
|
||||
DATA_PATH="/srv/photoprism"
|
||||
PHOTOPRISM_VERSION="240915-ce"
|
||||
PHOTOPRISM_VERSION="260305-fad9d5395"
|
||||
HOST_IP="192.168.255.1"
|
||||
|
||||
# Detect architecture
|
||||
@ -110,6 +110,11 @@ create_lxc_config() {
|
||||
# PhotoPrism LXC Configuration
|
||||
lxc.uts.name = ${LXC_NAME}
|
||||
lxc.rootfs.path = dir:${LXC_ROOTFS}
|
||||
lxc.arch = aarch64
|
||||
|
||||
# Auto-start on boot
|
||||
lxc.start.auto = 1
|
||||
lxc.start.delay = 5
|
||||
|
||||
# Network - use host network
|
||||
lxc.net.0.type = none
|
||||
@ -122,89 +127,88 @@ lxc.mount.entry = ${DATA_PATH}/originals opt/photoprism/originals none bind,crea
|
||||
lxc.mount.entry = ${DATA_PATH}/storage opt/photoprism/storage none bind,create=dir 0 0
|
||||
lxc.mount.entry = ${DATA_PATH}/import opt/photoprism/import none bind,create=dir 0 0
|
||||
|
||||
# Resource limits
|
||||
lxc.cgroup2.memory.max = ${mem_bytes}
|
||||
|
||||
# Startup command
|
||||
lxc.init.cmd = /opt/start-photoprism.sh
|
||||
|
||||
# TTY
|
||||
lxc.tty.max = 4
|
||||
lxc.pty.max = 128
|
||||
|
||||
# Capabilities
|
||||
lxc.cap.drop = sys_admin
|
||||
# Character devices
|
||||
lxc.cgroup2.devices.allow = c 1:* rwm
|
||||
lxc.cgroup2.devices.allow = c 5:* rwm
|
||||
lxc.cgroup2.devices.allow = c 136:* rwm
|
||||
|
||||
# Resource limits
|
||||
lxc.cgroup2.memory.max = ${mem_bytes}
|
||||
|
||||
# Security
|
||||
lxc.cap.drop = sys_module mac_admin mac_override sys_time sys_rawio
|
||||
|
||||
# Startup command (uses SQLite, no external DB)
|
||||
lxc.init.cmd = /opt/init.sh
|
||||
EOF
|
||||
|
||||
log "LXC config created"
|
||||
}
|
||||
|
||||
# Create startup script inside container
|
||||
# Create startup script inside container (uses SQLite - no external DB needed)
|
||||
create_startup_script() {
|
||||
cat > "${LXC_ROOTFS}/opt/start-photoprism.sh" << 'SCRIPT'
|
||||
cat > "${LXC_ROOTFS}/opt/init.sh" << 'SCRIPT'
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Start MariaDB
|
||||
service mariadb start
|
||||
sleep 2
|
||||
# Setup environment
|
||||
export HOME=/opt/photoprism
|
||||
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
export TERM=linux
|
||||
|
||||
# Wait for MariaDB to be ready
|
||||
for i in $(seq 1 30); do
|
||||
if mysqladmin ping >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
# Create directories
|
||||
mkdir -p /opt/photoprism/storage/cache
|
||||
mkdir -p /opt/photoprism/storage/sidecar
|
||||
mkdir -p /opt/photoprism/originals
|
||||
mkdir -p /opt/photoprism/import
|
||||
mkdir -p /run /var/run
|
||||
|
||||
# PhotoPrism environment - SQLite config (no external DB)
|
||||
export PHOTOPRISM_CONFIG_PATH=/opt/photoprism
|
||||
export PHOTOPRISM_DATABASE_DRIVER=sqlite
|
||||
export PHOTOPRISM_DATABASE_DSN=/opt/photoprism/storage/photoprism.db
|
||||
export PHOTOPRISM_ORIGINALS_PATH=/opt/photoprism/originals
|
||||
export PHOTOPRISM_STORAGE_PATH=/opt/photoprism/storage
|
||||
export PHOTOPRISM_IMPORT_PATH=/opt/photoprism/import
|
||||
export PHOTOPRISM_HTTP_HOST=0.0.0.0
|
||||
export PHOTOPRISM_HTTP_PORT=2342
|
||||
export PHOTOPRISM_ADMIN_USER=admin
|
||||
export PHOTOPRISM_ADMIN_PASSWORD="${PHOTOPRISM_ADMIN_PASSWORD:-secubox123}"
|
||||
export PHOTOPRISM_DISABLE_FACES=false
|
||||
export PHOTOPRISM_DISABLE_CLASSIFICATION=false
|
||||
export PHOTOPRISM_DISABLE_PLACES=false
|
||||
|
||||
# Run PhotoPrism
|
||||
cd /opt/photoprism
|
||||
exec ./photoprism start
|
||||
|
||||
# Start PhotoPrism (foreground to keep container running)
|
||||
exec ./bin/photoprism start
|
||||
SCRIPT
|
||||
chmod +x "${LXC_ROOTFS}/opt/start-photoprism.sh"
|
||||
chmod +x "${LXC_ROOTFS}/opt/init.sh"
|
||||
}
|
||||
|
||||
# Create PhotoPrism configuration
|
||||
create_photoprism_config() {
|
||||
local db_pass="$1"
|
||||
|
||||
# Create PhotoPrism directories (config is done via env vars in init script)
|
||||
create_photoprism_dirs() {
|
||||
mkdir -p "${LXC_ROOTFS}/opt/photoprism"
|
||||
|
||||
cat > "${LXC_ROOTFS}/opt/photoprism/options.yml" << EOF
|
||||
# PhotoPrism Configuration
|
||||
AdminUser: "${ADMIN_USER}"
|
||||
AdminPassword: "${ADMIN_PASS}"
|
||||
|
||||
# Storage
|
||||
OriginalsPath: "/opt/photoprism/originals"
|
||||
StoragePath: "/opt/photoprism/storage"
|
||||
ImportPath: "/opt/photoprism/import"
|
||||
|
||||
# Server
|
||||
HttpHost: "0.0.0.0"
|
||||
HttpPort: ${HTTP_PORT}
|
||||
|
||||
# Database
|
||||
DatabaseDriver: "mysql"
|
||||
DatabaseDsn: "${DB_USER}:${db_pass}@tcp(127.0.0.1:3306)/${DB_NAME}?charset=utf8mb4,utf8&parseTime=true"
|
||||
|
||||
# Features
|
||||
DisableFaces: $([ "$FACE_RECOGNITION" = "1" ] && echo "false" || echo "true")
|
||||
DisableClassification: $([ "$OBJECT_DETECTION" = "1" ] && echo "false" || echo "true")
|
||||
DisablePlaces: $([ "$PLACES" = "1" ] && echo "false" || echo "true")
|
||||
DisableRaw: $([ "$RAW_THUMBS" = "1" ] && echo "false" || echo "true")
|
||||
|
||||
# Quality
|
||||
JpegQuality: 85
|
||||
ThumbSize: 2048
|
||||
ThumbSizeUncached: 7680
|
||||
EOF
|
||||
mkdir -p "${LXC_ROOTFS}/opt/photoprism/storage"
|
||||
mkdir -p "${LXC_ROOTFS}/opt/photoprism/originals"
|
||||
mkdir -p "${LXC_ROOTFS}/opt/photoprism/import"
|
||||
}
|
||||
|
||||
# Install packages inside container
|
||||
install_packages() {
|
||||
log "Installing packages in container..."
|
||||
|
||||
# Fix /dev nodes for chroot
|
||||
[ -e "${LXC_ROOTFS}/dev/null" ] || mknod -m 666 "${LXC_ROOTFS}/dev/null" c 1 3
|
||||
[ -e "${LXC_ROOTFS}/dev/zero" ] || mknod -m 666 "${LXC_ROOTFS}/dev/zero" c 1 5
|
||||
[ -e "${LXC_ROOTFS}/dev/random" ] || mknod -m 666 "${LXC_ROOTFS}/dev/random" c 1 8
|
||||
[ -e "${LXC_ROOTFS}/dev/urandom" ] || mknod -m 666 "${LXC_ROOTFS}/dev/urandom" c 1 9
|
||||
chmod 666 "${LXC_ROOTFS}/dev/null" 2>/dev/null || true
|
||||
|
||||
# Configure apt
|
||||
cat > "${LXC_ROOTFS}/etc/apt/sources.list" << EOF
|
||||
deb http://deb.debian.org/debian bookworm main contrib non-free non-free-firmware
|
||||
@ -212,22 +216,27 @@ deb http://deb.debian.org/debian bookworm-updates main contrib non-free non-free
|
||||
deb http://security.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware
|
||||
EOF
|
||||
|
||||
# Create install script
|
||||
# Create install script - install gpgv first for apt verification
|
||||
cat > "${LXC_ROOTFS}/tmp/install.sh" << 'INSTALL'
|
||||
#!/bin/bash
|
||||
set -e
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# Install gpgv first (required for apt signature verification)
|
||||
# Use --allow-unauthenticated only for this bootstrap step
|
||||
apt-get update --allow-insecure-repositories || true
|
||||
apt-get install -y --allow-unauthenticated gpgv gnupg
|
||||
|
||||
# Now apt can verify signatures
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends \
|
||||
mariadb-server \
|
||||
libvips42 \
|
||||
ffmpeg \
|
||||
exiftool \
|
||||
libheif-examples \
|
||||
ca-certificates \
|
||||
curl \
|
||||
wget \
|
||||
gnupg
|
||||
wget
|
||||
|
||||
# Clean up
|
||||
apt-get clean
|
||||
@ -235,8 +244,14 @@ rm -rf /var/lib/apt/lists/*
|
||||
INSTALL
|
||||
chmod +x "${LXC_ROOTFS}/tmp/install.sh"
|
||||
|
||||
# Mount /proc for chroot
|
||||
mount -t proc proc "${LXC_ROOTFS}/proc" 2>/dev/null || true
|
||||
|
||||
# Run install via chroot
|
||||
chroot "$LXC_ROOTFS" /tmp/install.sh
|
||||
|
||||
# Unmount /proc
|
||||
umount "${LXC_ROOTFS}/proc" 2>/dev/null || true
|
||||
rm -f "${LXC_ROOTFS}/tmp/install.sh"
|
||||
}
|
||||
|
||||
@ -244,7 +259,7 @@ INSTALL
|
||||
install_photoprism_binary() {
|
||||
log "Downloading PhotoPrism ${PHOTOPRISM_VERSION} for ${ARCH}..."
|
||||
|
||||
local url="https://github.com/photoprism/photoprism/releases/download/${PHOTOPRISM_VERSION}/photoprism_${PHOTOPRISM_VERSION}_linux_${ARCH}.tar.gz"
|
||||
local url="https://github.com/photoprism/photoprism/releases/download/${PHOTOPRISM_VERSION}/photoprism_${PHOTOPRISM_VERSION}-linux-${ARCH}.tar.gz"
|
||||
|
||||
mkdir -p "${LXC_ROOTFS}/opt/photoprism"
|
||||
|
||||
@ -256,33 +271,12 @@ install_photoprism_binary() {
|
||||
tar -xzf /tmp/photoprism.tar.gz -C "${LXC_ROOTFS}/opt/photoprism"
|
||||
rm -f /tmp/photoprism.tar.gz
|
||||
|
||||
chmod +x "${LXC_ROOTFS}/opt/photoprism/photoprism"
|
||||
# Binary is in bin/ subdirectory
|
||||
chmod +x "${LXC_ROOTFS}/opt/photoprism/bin/photoprism"
|
||||
log "PhotoPrism binary installed"
|
||||
}
|
||||
|
||||
# Setup MariaDB
|
||||
setup_database() {
|
||||
local db_pass="$1"
|
||||
|
||||
cat > "${LXC_ROOTFS}/tmp/setup-db.sh" << DBSCRIPT
|
||||
#!/bin/bash
|
||||
service mariadb start
|
||||
sleep 2
|
||||
|
||||
mysql -e "CREATE DATABASE IF NOT EXISTS ${DB_NAME};"
|
||||
mysql -e "CREATE USER IF NOT EXISTS '${DB_USER}'@'localhost' IDENTIFIED BY '${db_pass}';"
|
||||
mysql -e "GRANT ALL PRIVILEGES ON ${DB_NAME}.* TO '${DB_USER}'@'localhost';"
|
||||
mysql -e "FLUSH PRIVILEGES;"
|
||||
|
||||
service mariadb stop
|
||||
DBSCRIPT
|
||||
chmod +x "${LXC_ROOTFS}/tmp/setup-db.sh"
|
||||
|
||||
chroot "$LXC_ROOTFS" /tmp/setup-db.sh
|
||||
rm -f "${LXC_ROOTFS}/tmp/setup-db.sh"
|
||||
}
|
||||
|
||||
# Full installation
|
||||
# Full installation (uses SQLite - no external database needed)
|
||||
cmd_install() {
|
||||
defaults
|
||||
|
||||
@ -299,34 +293,25 @@ cmd_install() {
|
||||
mkdir -p "${DATA_PATH}/import"
|
||||
chmod -R 755 "$DATA_PATH"
|
||||
|
||||
# Generate passwords if not set
|
||||
# Generate admin password if not set
|
||||
if [ -z "$ADMIN_PASS" ]; then
|
||||
ADMIN_PASS=$(generate_password)
|
||||
uci_set admin.password "$ADMIN_PASS"
|
||||
log "Generated admin password: $ADMIN_PASS"
|
||||
fi
|
||||
|
||||
local db_pass="$DB_PASS"
|
||||
if [ -z "$db_pass" ]; then
|
||||
db_pass=$(generate_password)
|
||||
uci_set database.password "$db_pass"
|
||||
fi
|
||||
|
||||
# Download rootfs
|
||||
download_rootfs "$ARCH"
|
||||
|
||||
# Install packages
|
||||
# Install packages (libvips, ffmpeg, etc.)
|
||||
install_packages
|
||||
|
||||
# Download PhotoPrism
|
||||
# Download PhotoPrism binary
|
||||
install_photoprism_binary
|
||||
|
||||
# Setup database
|
||||
setup_database "$db_pass"
|
||||
|
||||
# Create configs
|
||||
# Create configs and startup script
|
||||
create_lxc_config
|
||||
create_photoprism_config "$db_pass"
|
||||
create_photoprism_dirs
|
||||
create_startup_script
|
||||
|
||||
# Enable service
|
||||
@ -497,7 +482,7 @@ cmd_index() {
|
||||
fi
|
||||
|
||||
log "Starting photo indexing..."
|
||||
lxc-attach -n "$LXC_NAME" -- /opt/photoprism/photoprism index
|
||||
lxc-attach -n "$LXC_NAME" -- /opt/photoprism/bin/photoprism index
|
||||
log "Indexing complete"
|
||||
}
|
||||
|
||||
@ -514,7 +499,7 @@ cmd_import() {
|
||||
[ "$(uci_get import.delete_after_import 0)" = "1" ] && delete_opt="--move"
|
||||
|
||||
log "Importing photos from ${DATA_PATH}/import..."
|
||||
lxc-attach -n "$LXC_NAME" -- /opt/photoprism/photoprism import $delete_opt
|
||||
lxc-attach -n "$LXC_NAME" -- /opt/photoprism/bin/photoprism import $delete_opt
|
||||
log "Import complete"
|
||||
}
|
||||
|
||||
@ -528,14 +513,14 @@ cmd_passwd() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
lxc-attach -n "$LXC_NAME" -- /opt/photoprism/photoprism passwd "$ADMIN_USER" "$new_pass"
|
||||
lxc-attach -n "$LXC_NAME" -- /opt/photoprism/bin/photoprism passwd "$ADMIN_USER" "$new_pass"
|
||||
uci_set admin.password "$new_pass"
|
||||
|
||||
log "Password reset for $ADMIN_USER"
|
||||
log "New password: $new_pass"
|
||||
}
|
||||
|
||||
# Backup
|
||||
# Backup (SQLite database is in storage directory)
|
||||
cmd_backup() {
|
||||
defaults
|
||||
local backup_dir="${DATA_PATH}/backups"
|
||||
@ -544,17 +529,8 @@ cmd_backup() {
|
||||
|
||||
mkdir -p "$backup_dir"
|
||||
|
||||
if lxc_running; then
|
||||
log "Dumping database..."
|
||||
lxc-attach -n "$LXC_NAME" -- mysqldump -u root "$DB_NAME" > "${backup_dir}/database-${timestamp}.sql"
|
||||
fi
|
||||
|
||||
log "Creating backup archive..."
|
||||
tar -czf "$backup_file" \
|
||||
-C "$DATA_PATH" storage \
|
||||
-C "$backup_dir" "database-${timestamp}.sql" 2>/dev/null || true
|
||||
|
||||
rm -f "${backup_dir}/database-${timestamp}.sql"
|
||||
log "Creating backup archive (includes SQLite database)..."
|
||||
tar -czf "$backup_file" -C "$DATA_PATH" storage
|
||||
|
||||
log "Backup created: $backup_file"
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user