Will's avatar
⬅️ Back to notes

Photoprism setup

Updated 20 September 2022

🏷️ technology 🏷️ selfhost

I’ve switched from managed photo providers (such as Apple or Google photos) to a self-hosted Photoprism instance. This note documents my setup.

I use Linode for this, and you can get a free $100 credit using this referral link.

Server setup

Provision a new instance (at least 4GB memory and 2 CPU cores), and create and attach a big (I use 200GB) volume.

Encrypt the attached volume using LUKS (I’ll write about this separately soon), create a filesystem, mount points (fstab, etc.) and mount it (e.g. to /data).

Install Docker and Docker Compose.

Running Photoprism

Create a docker-compose.yml:

version: '3.5'

services:
  photoprism:
    image: photoprism/photoprism:latest
    depends_on:
      - mariadb
    restart: unless-stopped
    security_opt:
      - seccomp:unconfined
      - apparmor:unconfined
    ports:
      - "80:2342"
    environment:
      PHOTOPRISM_ADMIN_PASSWORD: "CHANGEME"
      PHOTOPRISM_AUTH_MODE: "password"
      PHOTOPRISM_SITE_URL: "http://CHANGEME"
      PHOTOPRISM_ORIGINALS_LIMIT: 5000
      PHOTOPRISM_HTTP_COMPRESSION: "gzip"
      PHOTOPRISM_LOG_LEVEL: "info"
      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: 85
      PHOTOPRISM_DETECT_NSFW: "false"
      PHOTOPRISM_UPLOAD_NSFW: "true"
      PHOTOPRISM_DATABASE_DRIVER: "mysql"
      PHOTOPRISM_DATABASE_SERVER: "mariadb:3306"
      PHOTOPRISM_DATABASE_NAME: "photoprism"
      PHOTOPRISM_DATABASE_USER: "photoprism"
      PHOTOPRISM_DATABASE_PASSWORD: "CHANGEME"
      PHOTOPRISM_SITE_CAPTION: "AI-Powered Photos App"
      PHOTOPRISM_SITE_DESCRIPTION: ""
      PHOTOPRISM_SITE_AUTHOR: ""
    working_dir: "/photoprism"
    volumes:
      - "/data/originals:/photoprism/originals"
      - "./import:/photoprism/import"
      - "/data/storage:/photoprism/storage"

  mariadb:
    restart: unless-stopped
    image: mariadb:10.8
    security_opt:
      - seccomp:unconfined
      - apparmor:unconfined
    command: mysqld --innodb-buffer-pool-size=512M --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:
      - "/data/database:/var/lib/mysql"
    environment:
      MARIADB_AUTO_UPGRADE: "1"
      MARIADB_INITDB_SKIP_TZINFO: "1"
      MARIADB_DATABASE: "photoprism"
      MARIADB_USER: "photoprism"
      MARIADB_PASSWORD: "CHANGEME"
      MARIADB_ROOT_PASSWORD: "CHANGEME"

Bring up the instance using docker-compose up -d. I personally host this in a private Tailscale network so I don’t bother with TLS certificates, but you may want to stick Photoprism behind a reverse proxy if you intend to expose it publicly.

Backups

Photoprism provides its own backup facility. However, since I run nearly everything in Docker, I am hesitant when adding too much configuration to the host itself.

Instead I added a Restic-based backup container specifically made for Photoprism. To use this, simply add the following to the bottom of the docker-compose.yml and bring the services back up:

...

  photosbackup:
    image: wilw/photoprism-backup
    restart: always
    volumes:
      - "/path/to/originals:/photoprism/originals"
    environment:
      PHOTOPRISM_DATABASE_SERVER: "mariadb"
      PHOTOPRISM_DATABASE_NAME: "photoprism"
      PHOTOPRISM_DATABASE_USER: "photoprism"
      PHOTOPRISM_DATABASE_PASSWORD: "CHANGEME"
      AWS_ACCESS_KEY_ID: "CHANGEME"
      AWS_SECRET_ACCESS_KEY: "CHANGEME"
      RESTIC_REPOSITORY: "s3:endpoint/bucket"
      RESTIC_PASSWORD: "CHANGEME"
      RESTIC_HOSTNAME: "hostname"

Documentation for the container is available here (specifically around configuring the Restic repos).