Fully verified40,129

Photos and video

PhotoPrism

PhotoPrism indexes photos and videos on your own server, groups them by date, place, and people, reads metadata, and provides browser-based search. This recipe uses MariaDB, keeps originals locally, and exposes the web interface on localhost only.

Overview

PhotoPrism turns a directory of photos and videos into a private web library. It indexes the existing folder structure, reads EXIF and XMP, generates previews, shows calendar and map views, recognizes faces, and searches with filters. It is suited to personal or family archives as an alternative to Google Photos, iCloud Photos, and cloud file viewers. Community Edition has no first-party native mobile app for automatic uploads.

The recipe runs official PhotoPrism image 260728, corresponding to release 260728-bbde8f452, with MariaDB 12.3.2. Originals and writable storage use host directories, while the database uses a separate Docker volume. Optional Ollama, PhotoPrism Vision, Watchtower, and hardware acceleration are deliberately absent.

Security and recipe boundaries

The full HTTP smoke test has passed on amd64 and arm64; backup, restore, and real media processing remain untested. The port binds to localhost, MariaDB is not published, and password authentication is required. The recipe does not encrypt originals, previews, the database, or .env. The indexer passes untrusted formats to external libraries and needs bursts of memory while it works. The recipe therefore sets no memory limit — a tight cap gets the indexer OOM-killed mid-run — so size the host for the peak instead.

Community Edition is available under AGPL-3.0, while additional upstream terms protect the trademark and brand assets. Some paid-edition capabilities are not part of Community Edition; consult upstream’s current comparison.

Update tracking

These are stored results of separate checks, not real-time data. An unknown status means the check has not been performed yet.

New releases

Recipe version compared with the latest known upstream release. A version number, not a reading of what changed.

Current version 260728Sep 1, 2026, 4:30 PM UTC

Critical vulnerabilities

Result of a dedicated Docker image scan, not a Compose configuration check.

Not checkedNot checked

Breaking updates

A new major version is found by comparing version numbers. A compatibility verdict is entered by hand after reading the release notes and the migration steps.

Not checkedNot checked

compose.yaml

Upstream Compose changes relative to the verified recipe.

Upstream Compose is not trackedNot checked

Outdated Docker images

Pinned image tags checked for newer versions.

Not checkedNot checked

From observation to action

Update plan

The recipe already pins the latest known release. The steps below show the evidence retained for that version.

260728260728
  1. Open the release evidence

    There is no exact release-notes URL for this manually tracked source. Start with the project sources below.

  2. Review the version boundary

    The version numbers do not cross a major compatibility boundary. No compatibility verdict has been recorded.

  3. Prepare image-tag changes

    No image-tag change is currently planned.

  4. Follow the documented migration shape

    Manual steps after the pull. Release-specific migration steps still come from the release notes and installation guide.

  5. Protect the rollback point

    No version change is currently planned. The recipe includes a backup procedure. Restore has not been tested.

  6. Verify the updated recipe

    An exact Fully verified check for this target was recorded on 2026-09-03.

Read the update procedure in the installation guide ↓

Specifications

Security and exposure

Installation levels

The status shows how fully the published recipe meets each level's requirements.

Partial

For home

A minimal setup for a local network or access through a VPN.

  • Single server
  • Local access
  • Minimum components

You still need to add: single server, local access, minimum components.

Partial

For a VPS

A public deployment with protected access and backups.

  • Domain
  • HTTPS via reverse proxy
  • Off-server backup

You still need to add: domain, https via reverse proxy, off-server backup.

Partial

Reliable

A setup designed for predictable operations and observability.

  • Separate database
  • Healthcheck
  • External monitoring
  • CPU and memory limits

You still need to add: external monitoring, cpu and memory limits.

Tailored to your server

Configuration generator

Answer five questions and download a ready-to-run PhotoPrism bundle.

Runs locally
01 Do you have a domain?
02 Which reverse proxy?
03 Server architecture
04 Where should data be stored?

Use an absolute path for a separate disk, such as /srv/photoprism.

PhotoPrism may modify photos and videos during imports and metadata editing; keep a separate off-server copy.

05 Is VPN access required?

Your bundle is ready

The archive is created in your browser. Your answers are never sent anywhere.

Screenshots

Screenshots have not been added yet.

Quick start

Read the full guide first: it explains external access, backups, and data locations.

Prepare settingscp .env.example .env
Launchdocker compose up -d
Check statusdocker compose ps

Step-by-step guide

1. Check the Ubuntu or Debian server

Use Ubuntu 22.04+ or Debian 12+ with Docker Engine and Compose v2.24+. Allocate at least 2 CPUs, 4 GB RAM, and 4 GB swap; 8 GB RAM is recommended for large files and indexing. Disk must hold originals, previews, sidecars, and backups.

docker --version
docker compose version
free -h && df -h /srv

2. Prepare directories and secrets

mkdir -p ~/services/photoprism
sudo mkdir -p /srv/photoprism/{originals,storage,backups}
sudo chown -R "$(id -u):$(id -g)" /srv/photoprism
cd ~/services/photoprism
cp .env.example .env
chmod 600 .env
sed -i "s|^PHOTOPRISM_ADMIN_PASSWORD=.*|PHOTOPRISM_ADMIN_PASSWORD=$(openssl rand -base64 36 | tr -d '/+=')|" .env
sed -i "0,/^PHOTOPRISM_DATABASE_PASSWORD=.*/s||PHOTOPRISM_DATABASE_PASSWORD=$(openssl rand -hex 32)|" .env
sed -i "s|^PHOTOPRISM_DATABASE_ROOT_PASSWORD=.*|PHOTOPRISM_DATABASE_ROOT_PASSWORD=$(openssl rand -hex 32)|" .env
sed -i 's|^PHOTOPRISM_ORIGINALS_PATH=.*|PHOTOPRISM_ORIGINALS_PATH=/srv/photoprism/originals|' .env
sed -i 's|^PHOTOPRISM_STORAGE_PATH=.*|PHOTOPRISM_STORAGE_PATH=/srv/photoprism/storage|' .env
sed -i 's|^PHOTOPRISM_BACKUP_DIR=.*|PHOTOPRISM_BACKUP_DIR=/srv/photoprism/backups|' .env
sed -i "s|^PHOTOPRISM_UID=.*|PHOTOPRISM_UID=$(id -u)|" .env
sed -i "s|^PHOTOPRISM_GID=.*|PHOTOPRISM_GID=$(id -g)|" .env

Every .env variable:

  • PHOTOPRISM_VERSION is the exact official image tag;
  • PHOTOPRISM_PORT is the local web port;
  • PHOTOPRISM_SITE_URL is the public URL with a trailing /;
  • PHOTOPRISM_ADMIN_USER and PHOTOPRISM_ADMIN_PASSWORD form the initial administrator account;
  • PHOTOPRISM_DEFAULT_LOCALE selects the initial interface language;
  • PHOTOPRISM_ORIGINALS_PATH holds original photos and videos;
  • PHOTOPRISM_STORAGE_PATH holds previews, cache, sidecars, configuration, and dumps;
  • PHOTOPRISM_BACKUP_DIR is the local backup directory used by backup.sh;
  • PHOTOPRISM_UID and PHOTOPRISM_GID are the user the image runs the server as; they must match the owner of the directories above;
  • PHOTOPRISM_INIT is empty by default; setting tensorflow downloads a CPU-tuned TensorFlow build (~500 MB) on every container re-creation and holds the web server back until it lands;
  • PHOTOPRISM_DATABASE_NAME, PHOTOPRISM_DATABASE_USER, and PHOTOPRISM_DATABASE_PASSWORD configure the application database account;
  • PHOTOPRISM_DATABASE_ROOT_PASSWORD is used only for MariaDB administration and restore;
  • PHOTOPRISM_DATABASE_VOLUME names the MariaDB volume;
  • TZ is an IANA time zone.

3. Start PhotoPrism

docker compose config
docker compose pull
docker compose up -d --wait
docker compose ps
curl --fail http://127.0.0.1:2342/api/v1/status

Open http://localhost:2342 through an SSH tunnel and sign in with .env:

ssh -L 2342:127.0.0.1:2342 user@server.example

VPS deployment

Keep the 127.0.0.1 binding, do not publish MariaDB, and allow only SSH, HTTP, and HTTPS through the firewall. Set PHOTOPRISM_SITE_URL=https://photos.example.com/, recreate the container, and expose it only through an HTTPS reverse proxy.

Trusted LAN access

Without TLS, use an SSH tunnel or VPN. For permanent LAN access, replace 127.0.0.1 in compose.yaml with a specific private address, set the matching origin in PHOTOPRISM_SITE_URL, and restrict the port with a firewall. Do not use 0.0.0.0 without network controls.

Domain and HTTPS

Replace photos.example.com in one file under proxy/. Caddy obtains a certificate, Nginx expects Certbot files, and Traefik uses the letsencrypt resolver. For a containerized proxy, localhost means the proxy itself; use a reachable host gateway. After changing the URL, run:

docker compose up -d --force-recreate photoprism
curl --fail https://photos.example.com/api/v1/status

Backup

chmod +x backup.sh restore.sh
./backup.sh

The script stops PhotoPrism, dumps MariaDB, and archives the originals and storage directories into a single .tar in PHOTOPRISM_BACKUP_DIR. Stopping is required: an index running during the copy would leave the database describing files the originals archive does not contain. The root password reaches the container through MYSQL_PWD rather than argv, so it stays out of the process list. The archive holds photos and passwords: encrypt it, keep an off-server copy, and test restores. Built-in database dumps in storage do not replace an originals backup.

Restore

Restore irreversibly replaces the originals, storage, and database. The script takes an emergency copy of the current state before replacing it. Use the same image versions, check .env, then:

./restore.sh ./backups/photoprism-YYYYMMDDTHHMMSSZ.tar
docker compose ps
curl --fail http://127.0.0.1:2342/api/v1/status

The procedure has not passed a practical restore test; test it on a separate server first.

Update

Back up, read the release notes, and change PHOTOPRISM_VERSION only to a reviewed exact tag, never latest. Update MariaDB separately.

docker compose pull photoprism
docker compose up -d --wait photoprism
docker compose logs --tail=200 photoprism

Rollback

Do not run old PhotoPrism code over a migrated database. Restore the previous tag and complete pre-update archive, including its dump and storage. Photos added after that backup are absent; copy them aside before replacing data.

Stop and remove

docker compose down preserves data. After verifying an external backup, remove everything irreversibly:

docker compose down
docker volume rm photoprism-database
sudo rm -rf /srv/photoprism
rm -rf ~/services/photoprism

Sources: Docker Compose, configuration, backup, updates, and release 260728.

Troubleshooting

PhotoPrism does not become healthy

docker compose ps
docker compose logs --tail=200 photoprism mariadb
docker inspect --format '{{json .State.Health}}' "$(docker compose ps -q photoprism)"

First startup and TensorFlow installation take time. Check free RAM, swap, and disk, originals/storage permissions, and replacement of all three passwords.

MariaDB connection fails

docker compose exec mariadb healthcheck.sh --connect --innodb_initialized
docker compose exec photoprism photoprism show config | grep -i database

The .env password takes effect when the volume is initialized. Changing it does not alter an existing MariaDB user. Restore the old value or explicitly change the database password. Never remove the volume without a verified dump.

Indexing fails or the container restarts

Upstream warns that less than 4 GB swap and hard memory limits may cause restarts while large files are processed. Check free -h, docker stats, logs, and storage space. Do not start another complete index before a backup.

The library is empty after startup

Verify that PHOTOPRISM_ORIGINALS_PATH points to media and is readable:

docker compose exec photoprism find /photoprism/originals -maxdepth 2 -type f | head
docker compose exec photoprism photoprism index

On the host, check curl http://127.0.0.1:2342/api/v1/status. PHOTOPRISM_SITE_URL must exactly match the public HTTPS URL and end in /. A containerized proxy cannot reach host localhost without a host gateway.

PhotoPrism fails after an update

Do not roll back only the image tag over a migrated database. Inspect migration logs, restore the previous Compose and .env, then restore one consistent pre-update archive containing the MariaDB dump, storage, and originals.

Official sources

Latest release: 2026-07-28 · GitHub Stars: 40,129 · metadata checked Sep 1, 2026, 4:30 PM UTC

Disclaimer

Fossary is an independent informational catalog and is not affiliated with the developers of the listed applications. We collect information from public sources and verify published recipes, but we do not develop, distribute, or control these applications.

A listing or validation status is not a requirement, endorsement, or personal recommendation to use an application. You decide whether it is suitable and use it at your own risk. We do not warrant an application's security, availability, or fitness for purpose and, to the extent permitted by law, are not liable for resulting loss or damage. Review its license, security settings, data processing, and backup procedures before installation.