PhotoPrism is a self-hosted photo management app that indexes your existing photo and video folders, recognises faces and objects, reads EXIF and location data, and gives you a fast, searchable web interface, all on your own server. It’s especially good at organising existing archives (including RAW files) without moving or modifying them.

Comparing options? See Immich vs PhotoPrism.

Requirements

  • 2 vCPU and 3–4 GB RAM minimum, with 4 vCPU and 6–8 GB recommended for large libraries. Indexing is CPU-heavy, and TensorFlow (AI labels and faces) needs memory. Add swap on smaller servers. See swap.
  • Storage for your originals, plus roughly 10–20% for thumbnails and sidecar files. A storage VPS suits large libraries. See storage VPS.
  • Docker and Docker Compose. See install Docker.

1. Docker Compose

PhotoPrism provides an official compose.yaml. Download it from their docs, or use this outline:

# /opt/photoprism/compose.yaml (outline)
services:
  photoprism:
    image: photoprism/photoprism:latest
    restart: unless-stopped
    depends_on: [mariadb]
    security_opt:
      - seccomp:unconfined
      - apparmor:unconfined
    ports:
      - "127.0.0.1:2342:2342"
    environment:
      PHOTOPRISM_ADMIN_USER: "admin"
      PHOTOPRISM_ADMIN_PASSWORD: "change-me-long-password"
      PHOTOPRISM_SITE_URL: "https://photos.example.com/"
      PHOTOPRISM_DATABASE_DRIVER: "mysql"
      PHOTOPRISM_DATABASE_SERVER: "mariadb:3306"
      PHOTOPRISM_DATABASE_NAME: "photoprism"
      PHOTOPRISM_DATABASE_USER: "photoprism"
      PHOTOPRISM_DATABASE_PASSWORD: "change-me-db"
      PHOTOPRISM_ORIGINALS_LIMIT: 5000        # max file size in MB
      PHOTOPRISM_WORKERS: 2                   # indexing workers (≈ vCPUs/2)
    volumes:
      - "/srv/photos/originals:/photoprism/originals"
      - "/srv/photos/import:/photoprism/import"
      - "./storage:/photoprism/storage"

  mariadb:
    image: mariadb:11
    restart: unless-stopped
    command: --innodb-buffer-pool-size=512M --transaction-isolation=READ-COMMITTED --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=512
    environment:
      MARIADB_DATABASE: "photoprism"
      MARIADB_USER: "photoprism"
      MARIADB_PASSWORD: "change-me-db"
      MARIADB_ROOT_PASSWORD: "change-me-root"
    volumes:
      - "./database:/var/lib/mysql"

Folder roles:

  • originals: your photo library. PhotoPrism indexes it in place.
  • import: a drop folder. Files are moved into originals, sorted by date.
  • storage: cache, thumbnails, sidecar files and settings. Keep it on fast storage.
cd /opt/photoprism && docker compose up -d
docker compose logs -f photoprism

Use strong passwords from a password manager.

2. HTTPS

Put PhotoPrism behind Nginx with Let’s Encrypt (WebSocket headers required):

server {
    server_name photos.example.com;
    client_max_body_size 500M;
    location / {
        proxy_pass http://127.0.0.1:2342;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
    # listen 443 ssl; certbot --nginx
}

PHOTOPRISM_SITE_URL must match the public URL. See Nginx WebSocket proxy.

3. Get photos in and index them

  • Copy existing photos into originals (rsync from another server or NAS works well), then Library → Index in the web UI.
  • Or put them in import, and use Library → Import.
  • From phones: PhotoPrism has no native backup app. Use PhotoSync, a WebDAV client (PhotoPrism exposes WebDAV), or Syncthing to a folder that you index regularly. See Syncthing.

The first index of a large library can take hours. Later runs are incremental. Schedule indexing (settings or CLI) to pick up new files:

docker compose exec photoprism photoprism index

4. Faces, labels and places

  • Faces: People → review detected faces and assign names. PhotoPrism clusters similar faces.
  • Labels: automatic object and scene classification (search “beach”, “dog”).
  • Places: a map view from GPS EXIF data. Reverse geocoding uses PhotoPrism’s service unless disabled.

Tuning

  • Lower PHOTOPRISM_WORKERS on small VPSes, to keep the server responsive during indexing.
  • Disable features you don’t need (TensorFlow, faces, video transcoding) via environment options to save CPU and RAM.
  • Use nice and off-peak schedules for big imports. See process priority.

Backups

Back up three things: originals (irreplaceable), the database (albums, labels, faces, edits), and storage (sidecars and settings, regenerable but slow to rebuild).

docker compose exec -T mariadb mariadb-dump -uroot -p"change-me-root" photoprism > /backups/photoprism-db-$(date +%F).sql

Copy everything off-server. See backup strategy.

Security

  • HTTPS, a strong admin password, and multi-user accounts (editions differ in user features).
  • Consider VPN-only access for private libraries. See Tailscale.
  • Keep it updated. See updating self-hosted apps.

Quick reference

Task Command / setting
Start docker compose up -d
Index docker compose exec photoprism photoprism index
Public URL PHOTOPRISM_SITE_URL
Workers PHOTOPRISM_WORKERS
Port 2342 (behind Nginx)
Backup DB mariadb-dump … photoprism

Related: Immich photo backup and Jellyfin vs Plex.

  • Self-Hosting
  • Photos
  • Docker