mirror of
https://github.com/photoprism/photoprism.git
synced 2025-10-05 16:57:17 +08:00
421 lines
16 KiB
Plaintext
421 lines
16 KiB
Plaintext
#cloud-config
|
|
|
|
# Set hostname
|
|
hostname: photoprism-pi
|
|
fqdn: photoprism-pi.local
|
|
|
|
# Update and upgrade packages
|
|
package_update: true
|
|
package_upgrade: true
|
|
|
|
# Install required packages
|
|
packages:
|
|
- apt-transport-https
|
|
- ca-certificates
|
|
- curl
|
|
- gnupg
|
|
- lsb-release
|
|
- git
|
|
- openssl
|
|
- avahi-daemon
|
|
|
|
# Install Docker Engine (latest version)
|
|
runcmd:
|
|
# Print welcome message
|
|
- printf "\e[0s;35m[SETUP] Starting PhotoPrism installation on Raspberry Pi...\e[0m\n"
|
|
|
|
# Uninstall old versions if they exist
|
|
- printf "\e[0;35m[SETUP] Removing old Docker versions if present...\e[0m\n"
|
|
- for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do apt-get remove -y $pkg || true; done
|
|
- printf "\e[0;35m[SETUP] ✓ Old Docker versions removed or not present\e[0m\n"
|
|
|
|
# Add Docker's official GPG key
|
|
- printf "\e[0;35m[SETUP] Adding Docker repository GPG key...\e[0m\n"
|
|
- apt-get update
|
|
- apt-get install -y ca-certificates curl
|
|
- install -m 0755 -d /etc/apt/keyrings
|
|
- curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
|
|
- chmod a+r /etc/apt/keyrings/docker.asc
|
|
- printf "\e[0;35m[SETUP] ✓ Docker GPG key added\e[0m\n"
|
|
|
|
# Add Docker repository
|
|
- printf "\e[0;35m[SETUP] Adding Docker repository...\e[0m\n"
|
|
- echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
|
|
- apt-get update
|
|
- printf "\e[0;35m[SETUP] ✓ Docker repository added\e[0m\n"
|
|
|
|
# Install Docker Engine
|
|
- printf "\e[0;35m[SETUP] Installing Docker Engine...\e[0m\n"
|
|
- apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
|
- printf "\e[0;35m[SETUP] ✓ Docker Engine installed\e[0m\n"
|
|
|
|
# Create directories for PhotoPrism and Traefik
|
|
- printf "\e[0;35m[SETUP] Creating directory structure for PhotoPrism...\e[0m\n"
|
|
- mkdir -p /opt/photoprism/photos
|
|
- mkdir -p /opt/photoprism/storage
|
|
- mkdir -p /opt/photoprism/database
|
|
- mkdir -p /opt/photoprism/import
|
|
- mkdir -p /opt/photoprism/originals
|
|
- mkdir -p /opt/photoprism/traefik/certs
|
|
- mkdir -p /opt/photoprism/traefik/conf.d
|
|
- mkdir -p /etc/traefik
|
|
- chown -R 1000:1000 /opt/photoprism
|
|
- chmod -R 755 /opt/photoprism
|
|
- chmod -R ug+rwX,o-rwx /opt/photoprism/storage
|
|
- chmod -R ug+rwX,o-rwx /opt/photoprism/database
|
|
- chmod -R ug+rwX,o-rwx /opt/photoprism/import
|
|
- chmod -R ug+rwX,o-rwx /opt/photoprism/originals
|
|
- chmod -R ug+rwX,o-rwx /opt/photoprism/photos
|
|
- printf "\e[0;35m[SETUP] ✓ PhotoPrism directory structure created\e[0m\n"
|
|
|
|
|
|
# Create mount points for external drives
|
|
- printf "\e[0;35m[SETUP] Creating mount points for external drives...\e[0m\n"
|
|
- mkdir -p /mnt/a
|
|
- mkdir -p /mnt/b
|
|
- mkdir -p /mnt/c
|
|
- mkdir -p /mnt/d
|
|
- chown -R 1000:1000 /mnt
|
|
- printf "\e[0;35m[SETUP] ✓ External drive mount points created\e[0m\n"
|
|
|
|
# Configure external drives in fstab
|
|
- printf "\e[0;35m[SETUP] Configuring external drives in fstab...\e[0m\n"
|
|
- |
|
|
cat >> /etc/fstab << 'EOF'
|
|
/dev/sda1 /mnt/a auto nofail,noatime,noauto,x-systemd.automount,x-systemd.device-timeout=10s,uid=1000,gid=1000 0 0
|
|
/dev/sdb1 /mnt/b auto nofail,noatime,noauto,x-systemd.automount,x-systemd.device-timeout=10s,uid=1000,gid=1000 0 0
|
|
/dev/sdc1 /mnt/c auto nofail,noatime,noauto,x-systemd.automount,x-systemd.device-timeout=10s,uid=1000,gid=1000 0 0
|
|
/dev/sdd1 /mnt/d auto nofail,noatime,noauto,x-systemd.automount,x-systemd.device-timeout=10s,uid=1000,gid=1000 0 0
|
|
EOF
|
|
- printf "\e[0;35m[SETUP] ✓ External drives configured in fstab\e[0m\n"
|
|
|
|
# Set up swap
|
|
- printf "\e[0;35m[SETUP] Setting up swap space...\e[0m\n"
|
|
- |
|
|
cat > /usr/local/bin/swapon.sh << 'EOF'
|
|
#!/usr/bin/env bash
|
|
|
|
# add 8 GB of swap if no swap was configured yet
|
|
if [[ -z $(swapon --show) ]]; then
|
|
fallocate -l 8G /swapfile
|
|
chmod 600 /swapfile
|
|
mkswap /swapfile
|
|
swapon /swapfile
|
|
swapon --show
|
|
free -h
|
|
echo '/swapfile none swap sw 0 0' | tee -a /etc/fstab
|
|
fi
|
|
EOF
|
|
- chmod +x /usr/local/bin/swapon.sh
|
|
- /usr/local/bin/swapon.sh
|
|
- printf "\e[0;35m[SETUP] ✓ Swap space configured\e[0m\n"
|
|
|
|
# Verify the installation is successful
|
|
- printf "\e[0;35m[SETUP] Verifying Docker installation...\e[0m\n"
|
|
- docker run --rm hello-world
|
|
- printf "\e[0;35m[SETUP] ✓ Docker installation verified\e[0m\n"
|
|
|
|
# Ensure docker group exists and pi user is added to it
|
|
- printf "\e[0;35m[SETUP] Ensuring pi user is in docker group...\e[0m\n"
|
|
- getent group docker || groupadd docker
|
|
- usermod -aG docker pi
|
|
- printf "\e[0;35m[SETUP] ✓ Pi user added to docker group\e[0m\n"
|
|
|
|
# Enable services
|
|
- printf "\e[0;35m[SETUP] Enabling required services...\e[0m\n"
|
|
- systemctl enable docker
|
|
- systemctl enable avahi-daemon
|
|
- printf "\e[0;35m[SETUP] ✓ Services enabled\e[0m\n"
|
|
|
|
# Add a service to start PhotoPrism on boot
|
|
- printf "\e[0;35m[SETUP] Creating PhotoPrism service...\e[0m\n"
|
|
- |
|
|
cat > /etc/systemd/system/photoprism.service << 'EOF'
|
|
[Unit]
|
|
Description=PhotoPrism Service
|
|
After=docker.service network-online.target
|
|
Requires=docker.service network-online.target
|
|
|
|
[Service]
|
|
Type=oneshot
|
|
RemainAfterExit=yes
|
|
WorkingDirectory=/opt/photoprism
|
|
ExecStart=/usr/bin/docker compose up -d
|
|
ExecStop=/usr/bin/docker compose down
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF
|
|
- printf "\e[0;35m[SETUP] ✓ PhotoPrism service created\e[0m\n"
|
|
|
|
# Enable PhotoPrism service
|
|
- printf "\e[0;35m[SETUP] Enabling and starting PhotoPrism service...\e[0m\n"
|
|
- systemctl enable photoprism.service
|
|
- systemctl start photoprism.service
|
|
- printf "\e[0;35m[SETUP] ✓ PhotoPrism service started\e[0m\n"
|
|
|
|
# Configure Avahi for .local domain
|
|
- printf "\e[0;35m[SETUP] Restarting and configuring Avahi for .local domain...\e[0m\n"
|
|
- systemctl restart avahi-daemon
|
|
- printf "\e[0;35m[SETUP] ✓ Avahi configured for .local domain\e[0m\n"
|
|
|
|
# Update MOTD and issue file with actual IP address
|
|
- printf "\e[0;35m[SETUP] Updating MOTD and console login message with actual IP address...\e[0m\n"
|
|
- chmod +x /usr/local/bin/update-motd-ip.sh
|
|
- /usr/local/bin/update-motd-ip.sh
|
|
- PRIMARY_IFACE=$(ip route | grep default | awk '{print $5}')
|
|
- IP=$(ip addr show $PRIMARY_IFACE 2>/dev/null | grep -oP 'inet \K[\d.]+' || hostname -I | awk '{print $1}')
|
|
- |
|
|
cat > /etc/issue << EOF
|
|
|
|
|
|
Welcome to PhotoPrism Pi!
|
|
|
|
You should soon be able to access the web interface
|
|
by navigating to one of the following URLs:
|
|
|
|
http://$IP:2342/
|
|
https://photoprism-pi.local/
|
|
|
|
For further information and help with troubleshooting:
|
|
https://docs.photoprism.app/photoprism-pi/
|
|
https://docs.photoprism.app/getting-started/troubleshooting/
|
|
|
|
EOF
|
|
- printf "\e[0;35m[SETUP] ✓ MOTD and console login message updated with actual IP\e[0m\n"
|
|
|
|
|
|
|
|
# Write configuration files
|
|
write_files:
|
|
- path: /usr/local/bin/update-motd-ip.sh
|
|
permissions: '0755'
|
|
content: |
|
|
#!/bin/bash
|
|
IP=$(hostname -I | awk '{print $1}')
|
|
sed -i "s|http://<your IP address>:2342/|http://$IP:2342/|g" /etc/motd
|
|
|
|
- path: /etc/motd
|
|
permissions: '0644'
|
|
content: |
|
|
|
|
Welcome to PhotoPrism Pi!
|
|
|
|
You should soon be able to access the web interface
|
|
by navigating to one of the following URLs:
|
|
|
|
http://<IP address>:2342/
|
|
https://photoprism-pi.local/
|
|
|
|
Your initial password for the "admin" account is
|
|
"photoprismpi". Please change it after logging in for the
|
|
first time, especially if your device is connected to the
|
|
Internet or a shared network.
|
|
|
|
For further information and help with troubleshooting:
|
|
https://docs.photoprism.app/photoprism-pi/
|
|
https://docs.photoprism.app/getting-started/troubleshooting/
|
|
|
|
- path: /opt/photoprism/compose.yaml
|
|
permissions: '0644'
|
|
content: |
|
|
name: photoprism
|
|
|
|
services:
|
|
photoprism:
|
|
image: photoprism/photoprism:latest
|
|
depends_on:
|
|
- mariadb
|
|
restart: always
|
|
security_opt:
|
|
- seccomp=unconfined
|
|
- apparmor=unconfined
|
|
user: "1000:1000"
|
|
ports:
|
|
- "2342:2342"
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.photoprism.rule=Host(`photoprism-pi.local`)"
|
|
- "traefik.http.routers.photoprism.entrypoints=websecure"
|
|
- "traefik.http.routers.photoprism.tls=true"
|
|
- "traefik.http.services.photoprism.loadbalancer.server.port=2342"
|
|
- "traefik.docker.network=photoprism"
|
|
environment:
|
|
PHOTOPRISM_ADMIN_PASSWORD: "photoprismpi"
|
|
PHOTOPRISM_AUTH_MODE: "passwd"
|
|
PHOTOPRISM_SITE_URL: "https://photoprism-pi.local/"
|
|
PHOTOPRISM_SITE_CAPTION: "AI-Powered Photos App"
|
|
PHOTOPRISM_HTTP_COMPRESSION: "gzip"
|
|
PHOTOPRISM_WORKERS: 3
|
|
PHOTOPRISM_LOG_LEVEL: "info"
|
|
PHOTOPRISM_TRACE: "false"
|
|
PHOTOPRISM_READONLY: "false"
|
|
PHOTOPRISM_EXPERIMENTAL: "false"
|
|
PHOTOPRISM_DISABLE_CHOWN: "false"
|
|
PHOTOPRISM_DISABLE_WEBDAV: "false"
|
|
PHOTOPRISM_DISABLE_SETTINGS: "false"
|
|
PHOTOPRISM_DISABLE_TENSORFLOW: "false"
|
|
PHOTOPRISM_DISABLE_FACES: "false"
|
|
PHOTOPRISM_DISABLE_CLASSIFICATION: "false"
|
|
PHOTOPRISM_DISABLE_RAW: "false"
|
|
PHOTOPRISM_RAW_PRESETS: "false"
|
|
PHOTOPRISM_JPEG_QUALITY: 82
|
|
PHOTOPRISM_FFMPEG_SIZE: 1920
|
|
PHOTOPRISM_AUTO_INDEX: 300 # delay before automatically indexing files in SECONDS when uploading via WebDAV (-1 to disable)
|
|
PHOTOPRISM_AUTO_IMPORT: -1 # delay before automatically importing files in SECONDS when uploading via WebDAV (-1 to disable)
|
|
PHOTOPRISM_DETECT_NSFW: "false" # automatically flags photos as private that MAY be offensive (requires TensorFlow)
|
|
PHOTOPRISM_UPLOAD_NSFW: "true" # allow uploads that MAY be offensive
|
|
PHOTOPRISM_UPLOAD_ALLOW: "" # restricts uploads to these file types (comma-separated list of EXTENSIONS; leave blank to allow all)
|
|
PHOTOPRISM_UPLOAD_ARCHIVES: "true" # allows upload of zip archives (will be extracted before import)
|
|
PHOTOPRISM_UPLOAD_LIMIT: 5000 # maximum size of uploaded files and uncompressed archive contents in MB
|
|
PHOTOPRISM_ORIGINALS_LIMIT: 5000 # maximum size of original media files in MB (larger files are skipped)
|
|
PHOTOPRISM_RESOLUTION_LIMIT: 300 # maximum resolution of original media files in Pixels (larger files are skipped)
|
|
PHOTOPRISM_SIDECAR_YAML: "false" # creates YAML sidecar files to back up picture metadata
|
|
PHOTOPRISM_INDEX_SCHEDULE: "" # indexing SCHEDULE in cron format (e.g. "@every 3h" for every 3 hours; "" to disable)
|
|
PHOTOPRISM_BACKUP_ALBUMS: "true" # creates YAML files to back up album metadata
|
|
PHOTOPRISM_BACKUP_DATABASE: "true" # creates regular backups based on the configured schedule
|
|
PHOTOPRISM_BACKUP_SCHEDULE: "daily" # backup SCHEDULE in cron format (e.g. "0 12 * * *" for daily at noon) or at a random time (daily, weekly)
|
|
PHOTOPRISM_DATABASE_DRIVER: "mysql"
|
|
PHOTOPRISM_DATABASE_SERVER: "mariadb:3306"
|
|
PHOTOPRISM_DATABASE_NAME: "photoprism"
|
|
PHOTOPRISM_DATABASE_USER: "photoprism"
|
|
PHOTOPRISM_DATABASE_PASSWORD: "insecure"
|
|
PHOTOPRISM_INIT: "yt-dlp"
|
|
working_dir: "/photoprism"
|
|
volumes:
|
|
- "/opt/photoprism/storage:/photoprism/storage"
|
|
- "/opt/photoprism/originals:/photoprism/originals"
|
|
- "/mnt:/photoprism/originals/mnt:slave"
|
|
- "/opt/photoprism/import:/photoprism/import"
|
|
|
|
mariadb:
|
|
restart: always
|
|
image: mariadb:11
|
|
security_opt:
|
|
- seccomp=unconfined
|
|
- apparmor=unconfined
|
|
command: --innodb-buffer-pool-size=256M --transaction-isolation=READ-COMMITTED --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=512 --innodb-rollback-on-timeout=OFF --innodb-lock-wait-timeout=120
|
|
volumes:
|
|
- "/opt/photoprism/database:/var/lib/mysql"
|
|
environment:
|
|
MARIADB_AUTO_UPGRADE: "1"
|
|
MARIADB_INITDB_SKIP_TZINFO: "1"
|
|
MARIADB_DATABASE: "photoprism"
|
|
MARIADB_USER: "photoprism"
|
|
MARIADB_PASSWORD: "insecure"
|
|
MARIADB_ROOT_PASSWORD: "insecure"
|
|
|
|
traefik:
|
|
restart: always
|
|
image: traefik:v3.5
|
|
ports:
|
|
- "80:80"
|
|
- "443:443"
|
|
volumes:
|
|
- "/var/run/docker.sock:/var/run/docker.sock:ro"
|
|
- "/opt/photoprism/traefik:/etc/traefik:rw"
|
|
labels:
|
|
- "traefik.enable=true"
|
|
command:
|
|
- "--api.insecure=false"
|
|
- "--providers.docker=true"
|
|
- "--providers.docker.exposedbydefault=false"
|
|
- "--entrypoints.web.address=:80"
|
|
- "--entrypoints.websecure.address=:443"
|
|
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
|
|
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
|
|
- "--providers.docker.network=photoprism"
|
|
- "--providers.docker.defaultRule=Host(`{{ normalize .Name }}.local`)"
|
|
- "--log.level=DEBUG"
|
|
|
|
watchtower:
|
|
restart: always
|
|
image: containrrr/watchtower
|
|
environment:
|
|
WATCHTOWER_CLEANUP: "true"
|
|
WATCHTOWER_POLL_INTERVAL: 7200
|
|
volumes:
|
|
- "/var/run/docker.sock:/var/run/docker.sock"
|
|
|
|
networks:
|
|
default:
|
|
name: photoprism
|
|
driver: bridge
|
|
|
|
- path: /etc/avahi/avahi-daemon.conf
|
|
permissions: '0644'
|
|
content: |
|
|
[server]
|
|
#host-name=foo
|
|
#domain-name=local
|
|
#browse-domains=0pointer.de, zeroconf.org
|
|
use-ipv4=yes
|
|
use-ipv6=no
|
|
allow-interfaces=eth0
|
|
#deny-interfaces=eth1
|
|
#check-response-ttl=no
|
|
#use-iff-running=no
|
|
#enable-dbus=yes
|
|
#disallow-other-stacks=no
|
|
#allow-point-to-point=no
|
|
#cache-entries-max=4096
|
|
#clients-max=4096
|
|
#objects-per-client-max=1024
|
|
#entries-per-entry-group-max=32
|
|
ratelimit-interval-usec=1000000
|
|
ratelimit-burst=1000
|
|
|
|
[wide-area]
|
|
enable-wide-area=yes
|
|
|
|
[publish]
|
|
#disable-publishing=no
|
|
#disable-user-service-publishing=no
|
|
#add-service-cookie=no
|
|
#publish-addresses=yes
|
|
publish-hinfo=no
|
|
publish-workstation=no
|
|
#publish-domain=yes
|
|
#publish-dns-servers=192.168.50.1, 192.168.50.2
|
|
#publish-resolv-conf-dns-servers=yes
|
|
#publish-aaaa-on-ipv4=yes
|
|
#publish-a-on-ipv6=no
|
|
|
|
[reflector]
|
|
#enable-reflector=no
|
|
#reflect-ipv=no
|
|
#reflect-filters=_airplay._tcp.local,_raop._tcp.local
|
|
|
|
[rlimits]
|
|
#rlimit-as=
|
|
#rlimit-core=0
|
|
#rlimit-data=8388608
|
|
#rlimit-fsize=0
|
|
#rlimit-nofile=768
|
|
#rlimit-stack=8388608
|
|
#rlimit-nproc=3
|
|
|
|
# Configure users
|
|
users:
|
|
- name: pi
|
|
gecos: PhotoPrism User
|
|
sudo: ALL=(ALL) NOPASSWD:ALL
|
|
groups: adm,dialout,cdrom,floppy,sudo,audio,dip,video,plugdev,netdev,docker
|
|
shell: /bin/bash
|
|
lock_passwd: false
|
|
|
|
# Set passwords
|
|
chpasswd:
|
|
expire: false
|
|
list: |
|
|
pi:raspberry
|
|
|
|
# Automatically reboot after cloud-init completes
|
|
power_state:
|
|
delay: "+1"
|
|
mode: reboot
|
|
message: "Rebooting system after cloud-init completes setup"
|
|
timeout: 30
|
|
condition: True
|
|
|