PhotoPrism is a privacy-focused photo and video manager for people who want a searchable library without handing their originals to a hosted platform. It combines a responsive web interface, local indexing, metadata extraction, labels, face recognition, maps, WebDAV, sharing, and an installable PWA.
This is not just a thumbnail viewer. PhotoPrism maintains a media index, generates derived files, processes video and RAW formats, and stores application state in a database. That makes it capable, but it also means the storage and backup design deserves more attention than a single-folder gallery.
What Is PhotoPrism?
Repository: https://github.com/photoprism/photoprism
Checked commit: 70e20b5 (2026-10-24)
License: AGPL-3.0
Primary language: Go
Frontend: Vue and JavaScript
Recommended database: MariaDB/MySQL
Media tooling: ExifTool, libvips, FFmpeg, RAW tooling, TensorFlow/ONNX components
Tested image: photoprism/photoprism:latest, digest-pinned
The main container indexes local originals and serves the UI. MariaDB stores the searchable index and application data. The originals directory remains the source media, while PhotoPrism’s storage directory contains thumbnails, cache data, sidecars, configuration, album backups, and database backups.
Features
- search across filenames, dates, places, labels, people, colors, quality, resolution, and media properties;
- local metadata extraction from EXIF, XMP, and related sources;
- automatic labels, face detection, and face recognition;
- RAW photos, common image types, videos, Live Photos, and generated previews;
- maps and reverse-geocoding support for location-aware libraries;
- WebDAV access for compatible desktop clients;
- mobile upload workflows with compatible apps such as PhotoSync;
- browser UI and installable PWA shell for phones and desktops;
- sharing, albums, favorites, archive/review workflows, and user accounts;
- optional Ollama vision workflows.
The local computer-vision features do not require sending your library to a cloud AI provider. Optional Ollama integration is a separate service and should be enabled only when you want its model workflow and have planned for model storage and RAM.
Self-Hosting with Docker
The reusable Home-Lab profile is available here:
Home-Lab PhotoPrism Composeservices:
photoprism:
image: ${PHOTOPRISM_IMAGE:-photoprism/photoprism@sha256:0f85369636ad99ca9a1c33f2d04df6c590802d16b7c33b4a1ea026b595be06d1}
container_name: homelab-photoprism
depends_on:
mariadb:
condition: service_healthy
ports:
- "${PHOTOPRISM_PORT:-3840}:2342"
security_opt:
- seccomp:unconfined
- apparmor:unconfined
environment:
PHOTOPRISM_ADMIN_USER: "${PHOTOPRISM_ADMIN_USER:-admin}"
PHOTOPRISM_ADMIN_PASSWORD: "${PHOTOPRISM_ADMIN_PASSWORD:?Set PHOTOPRISM_ADMIN_PASSWORD in .env}"
PHOTOPRISM_AUTH_MODE: "password"
PHOTOPRISM_SITE_URL: "${PHOTOPRISM_SITE_URL:-http://192.168.1.2:3840/}"
PHOTOPRISM_SITE_TITLE: "PhotoPrism"
PHOTOPRISM_SITE_CAPTION: "AI-Powered Photos App"
PHOTOPRISM_DEFAULT_LOCALE: "en"
PHOTOPRISM_PLACES_LOCALE: "local"
PHOTOPRISM_LOG_LEVEL: "info"
PHOTOPRISM_READONLY: "false"
PHOTOPRISM_DISABLE_TLS: "true"
PHOTOPRISM_DEFAULT_TLS: "false"
PHOTOPRISM_DISABLE_CHOWN: "false"
PHOTOPRISM_DISABLE_WEBDAV: "false"
PHOTOPRISM_DISABLE_MCP: "false"
PHOTOPRISM_DISABLE_SETTINGS: "false"
PHOTOPRISM_DISABLE_PLACES: "false"
PHOTOPRISM_DISABLE_EXIFTOOL: "false"
PHOTOPRISM_DISABLE_TENSORFLOW: "false"
PHOTOPRISM_DISABLE_FACES: "false"
PHOTOPRISM_DISABLE_RAW: "false"
PHOTOPRISM_SIDECAR_YAML: "true"
PHOTOPRISM_BACKUP_ALBUMS: "true"
PHOTOPRISM_BACKUP_DATABASE: "true"
PHOTOPRISM_BACKUP_SCHEDULE: "daily"
PHOTOPRISM_INDEX_SCHEDULE: ""
PHOTOPRISM_AUTO_INDEX: "300"
PHOTOPRISM_AUTO_IMPORT: "-1"
PHOTOPRISM_UPLOAD_NSFW: "true"
PHOTOPRISM_XMP_FACES: "true"
PHOTOPRISM_UPLOAD_ARCHIVES: "true"
PHOTOPRISM_UPLOAD_LIMIT: "5000"
PHOTOPRISM_ORIGINALS_LIMIT: "5000"
PHOTOPRISM_HTTP_COMPRESSION: "zstd,gzip"
PHOTOPRISM_DATABASE_DRIVER: "mysql"
PHOTOPRISM_DATABASE_SERVER: "mariadb:3306"
PHOTOPRISM_DATABASE_NAME: "photoprism"
PHOTOPRISM_DATABASE_USER: "photoprism"
PHOTOPRISM_DATABASE_PASSWORD: "${MARIADB_PASSWORD:?Set MARIADB_PASSWORD in .env}"
PHOTOPRISM_INIT: "update"
PHOTOPRISM_UID: "1000"
PHOTOPRISM_GID: "1000"
volumes:
- "${PHOTOPRISM_ORIGINALS_PATH:-./originals}:/photoprism/originals"
- "${PHOTOPRISM_IMPORT_PATH:-./import}:/photoprism/import"
- "${PHOTOPRISM_STORAGE_PATH:-./storage}:/photoprism/storage"
restart: unless-stopped
mariadb:
image: ${MARIADB_IMAGE:-mariadb@sha256:99c125f103f5d081ebbc9ffe064e63daf7f688ac33a5f7f29af2d7260a96debf}
container_name: homelab-photoprism-mariadb
command: --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
environment:
MARIADB_AUTO_UPGRADE: "1"
MARIADB_INITDB_SKIP_TZINFO: "1"
MARIADB_DATABASE: "photoprism"
MARIADB_USER: "photoprism"
MARIADB_PASSWORD: "${MARIADB_PASSWORD:?Set MARIADB_PASSWORD in .env}"
MARIADB_ROOT_PASSWORD: "${MARIADB_ROOT_PASSWORD:?Set MARIADB_ROOT_PASSWORD in .env}"
volumes:
- photoprism_database:/var/lib/mysql
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 10s
timeout: 5s
retries: 12
restart: unless-stopped
volumes:
photoprism_database:
name: homelab_photoprism_database
Start it:
cd /home/jalcocert/Desktop/Home-Lab/photoprism
cp .env.sample .env
# Replace the three password values in .env.
mkdir -p originals import storage
docker compose pull
docker compose up -d
docker compose ps
The tested LAN UI is:
http://192.168.1.2:3840
The admin username is admin by default and the password is the value you set in PHOTOPRISM_ADMIN_PASSWORD. There is no universal default password. The profile uses MariaDB internally and does not publish the database port to the host.
Put photos and videos in originals/, or set PHOTOPRISM_ORIGINALS_PATH to an existing library. Use import/ for files PhotoPrism should process into the managed originals library. The storage/ directory and MariaDB volume must be persisted.
Field Note: The Empty Library Started Successfully
I tested the digest-pinned PhotoPrism and MariaDB images with empty originals and import directories. MariaDB became healthy first. PhotoPrism then completed its startup migrations, initialized its runtime packages, and listened on port 2342 inside the container.
The host-level checks were:
curl -fsS http://127.0.0.1:3840/api/v1/status
# {"status":"operational"}
curl -fsS -D - http://127.0.0.1:3840/ -o /dev/null
# HTTP/1.1 307 Temporary Redirect
# Location: /library/login
The first startup took longer than a typical web-only container because the image ran its configured package initialization and database migrations. This trial validates the empty-library deployment path; it does not benchmark indexing, face recognition, GPU acceleration, or a large media import.
Originals, Storage and Backups
The most important PhotoPrism distinction is between originals and generated state:
| Location | What it contains | Backup importance |
|---|---|---|
originals/ |
Source photos and videos | The irreplaceable media |
import/ |
Optional staging files | Back up if it contains files not yet imported |
storage/ |
Thumbnails, cache, sidecars, config, album/database backups | Needed for a complete, convenient restore |
| MariaDB volume | Search index, users, albums, metadata and application state | Required to preserve the library database |
Do not rely on the database alone. Do not assume the originals directory alone recreates your labels, faces, albums, users, and settings. Back up all components, and test a restore on a separate instance before changing the production library.
PhotoPrism can write YAML sidecars and album backups, which helps make metadata more portable, but these are complementary to a complete backup rather than a substitute for one.
PWA, WebDAV and Remote Access
PhotoPrism’s browser client can be installed as a PWA, which gives a phone or desktop an app-like launcher and responsive UI. It is not a full offline-first photo application. Search, permissions, indexes, thumbnails, and most library operations still depend on the PhotoPrism server.
WebDAV is useful for desktop file workflows and compatible mobile backup tools, but it should be protected with HTTPS and carefully scoped credentials. It is an access path into the library, not a backup system.
The Home-Lab profile uses HTTP only for trusted-LAN testing. For remote use, put PhotoPrism behind a reverse proxy with HTTPS, set PHOTOPRISM_SITE_URL to that public URL, and review upload, WebDAV, sharing, and account settings before opening it to the internet.
Database, AI and Hardware
MariaDB is the recommended database for larger or multi-user libraries. SQLite is simpler and can suit smaller installations, but MariaDB gives the index more room for concurrent activity. Redis is not required for the standard stack, and the database is not exposed publicly in the Home-Lab Compose.
CPU processing is the portable default. Larger libraries benefit from fast storage, adequate RAM and swap, and possibly Intel, NVIDIA, Apple, or Raspberry Pi acceleration. GPU setup is platform-specific and should be added only after the CPU deployment works.
PhotoPrism includes local vision components for labels and faces. Optional Ollama integration is a separate model runner, not a mandatory dependency. It can add semantic or generative workflows, but it also brings model downloads, hardware requirements, and another container to secure.
Compared with Other Photo Projects
| Project | Best fit | Difference from PhotoPrism |
|---|---|---|
| Immich | Phone-first backup, sharing, and modern photo UX | PhotoPrism emphasizes mature indexing, metadata, WebDAV, and broad file handling |
| Ente | End-to-end encrypted photo workflows | PhotoPrism keeps processing and the primary library on your server; it is not an E2EE-by-default archive |
| Photoview | Lightweight self-hosted gallery | PhotoPrism adds deeper search, labels, faces, maps, WebDAV, and media processing |
| PhotoStream or simple galleries | Browse a directory | PhotoPrism builds a searchable media index with accounts and metadata |
FAQ
What username and password do I use?
admin as the initial username unless you change PHOTOPRISM_ADMIN_USER. You choose the password in .env through PHOTOPRISM_ADMIN_PASSWORD. Never use the placeholder password from .env.sample for a real deployment.
Can I access the local UI?
http://192.168.1.2:3840. The root redirects unauthenticated users to /library/login, and /api/v1/status returned {"status":"operational"}. Use HTTPS before remote access.
Is PhotoPrism a PWA and does it work offline?
Does it need MariaDB, or can I use SQLite?
Does PhotoPrism upload my photos to an AI provider?
Do I need a GPU?
Is WebDAV a backup?
Can I use an existing photo folder?
PHOTOPRISM_ORIGINALS_PATH to the host path you want to index and ensure the container user can read it. Use read-only mounting only when you intentionally want to prevent write-oriented workflows. Keep the storage directory separate and writable.
Conclusion
PhotoPrism is a strong choice when you want a private, searchable photo archive with local processing and a broad file-oriented workflow. It is more involved than a simple gallery because it maintains a database-backed index, generated thumbnails, sidecars, faces, labels, maps, WebDAV, and backups.
Start with the tested two-container LAN profile, create your own admin password, add a small disposable library, and verify backup/restore before importing everything. Once the fundamentals are reliable, add HTTPS, GPU acceleration, WebDAV, PWA access, or Ollama deliberately.
Comments