PhotoPrism
★ 40.3kA self-hosted alternative to Lightroom, Google Photos
GNU Affero General Public License v3.0Open Core — Some Features Paid13 Containers — 13 containers — heavy hosting footprintDocker · Compose · Binary +1Needs MariaDB5+ active committers (12mo)
About
PhotoPrism is a self-hosted photo and video management application designed for people who want a private way to browse, organize, search, and share their media. The README presents it as an...
Community Ratings
No ratings yetNew this week
Read recap →Weekly Recap — Oct 2, 2026 – Oct 9, 2026Oct 9, 2026
Features
- browse photos and videos
- RAW and video format support
- PWA home-screen install
- advanced search filters
- automatic labeling
- face recognition
- live photos
- world maps and geocoding
- metadata extraction and merging
- WebDAV access
Details
- Last Updated
- Oct 11, 2026
- Created
- Jan 27, 2018
- Install Methods
- dockerdocker-composebinarysource
- Requirements
- Web browserDocker
- Backup & Export
- native-exportwebdav-syncfile-backup
- Runtime / Stack
- GoDocker
- Privacy & Independence
- Cloud: Optional
- Deployment
Deployment: Docker Compose ✓13 Containers — heavy hosting footprintRuns as 13 containers
Run PhotoPrism with Docker Compose
Compose file from the PhotoPrism project repository.
13 services · database: mariadb · infra: traefik, mariadb, postgres · 6 unclassified (qdrant, ollama, open-webui, glauth-plugins, keycloak, prometheus)
no resource limits declared
needs persistent storage (14 volumes)
compose.yaml · @ b7e758c · scanned Jul 7, 2026
## FOR TEST AND DEVELOPMENT ONLY, DO NOT USE IN PRODUCTION ##
## Setup: https://docs.photoprism.app/developer-guide/setup/ ##
services:
## PhotoPrism Build & Test Environment
photoprism:
build:
context: .
args:
WORKING_DIR: "${WORKING_DIR:-/go/src/github.com/photoprism/photoprism}"
image: photoprism/photoprism:develop
depends_on:
- mariadb
- dummy-webdav
- dummy-oidc
stop_grace_period: 15s
security_opt:
- seccomp:unconfined
- apparmor:unconfined
## Publish the dev environment's HTTP, TLS, and debugger ports on the host
## (bound to 127.0.0.1 by default; override SERVICES_BIND_HOST to change):
ports:
- "${SERVICES_BIND_HOST:-127.0.0.1}:2342:2342" # HTTP (default)
- "${SERVICES_BIND_HOST:-127.0.0.1}:2443:2443" # TLS (default)
- "${SERVICES_BIND_HOST:-127.0.0.1}:2343:2343" # HTTP (acceptance tests)
- "${SERVICES_BIND_HOST:-127.0.0.1}:40000:40000" # Go debugger
shm_size: "2gb"
## Set links and labels for use with Traefik reverse proxy
links:
- "traefik:localssl.dev"
- "traefik:app.localssl.dev"
- "traefik:vision.localssl.dev"
- "traefik:qdrant.localssl.dev"
- "traefik:keycloak.localssl.dev"
- "traefik:dummy-oidc.localssl.dev"
- "traefik:dummy-webdav.localssl.dev"
labels:
- "traefik.enable=true"
- "traefik.docker.network=${COMPOSE_NETWORK_NAME:-photoprism}"
- "traefik.http.services.photoprism.loadbalancer.server.port=2342"
- "traefik.http.services.photoprism.loadbalancer.server.scheme=http"
- "traefik.http.routers.photoprism.entrypoints=websecure"
- "traefik.http.routers.photoprism.rule=Host(`localssl.dev`) || HostRegexp(`^.+\\.localssl\\.dev`)"
- "traefik.http.routers.photoprism.priority=2"
- "traefik.http.routers.photoprism.tls.domains[0].main=localssl.dev"
- "traefik.http.routers.photoprism.tls.domains[0].sans=*.localssl.dev"
- "traefik.http.routers.photoprism.tls=true"
## Override variables with optional env file, see https://docs.docker.com/reference/compose-file/services/#required
env_file:
- path: ".telemetry"
required: false
- path: ".env"
required: false
## Configure development environment
environment:
## Run as a non-root user after initialization (supported: 0, 33, 50-99, 500-600, and 900-1200):
PHOTOPRISM_UID: ${UID:-1000} # user id, should match your host user id
PHOTOPRISM_GID: ${GID:-1000} # group id
## Access Management:
PHOTOPRISM_ADMIN_USER: "admin" # admin login username
PHOTOPRISM_ADMIN_PASSWORD: "photoprism" # initial admin password (8-72 characters)
PHOTOPRISM_AUTH_MODE: "password" # authentication mode (public, password)
PHOTOPRISM_REGISTER_URI: "https://keycloak.localssl.dev/admin/"
PHOTOPRISM_PASSWORD_RESET_URI: "https://keycloak.localssl.dev/realms/master/login-actions/reset-credentials"
PHOTOPRISM_USAGE_INFO: "true"
PHOTOPRISM_FILES_QUOTA: "100"
## Customization:
PHOTOPRISM_DEFAULT_LOCALE: "en" # default user interface language, e.g. "en" or "de"
PHOTOPRISM_PLACES_LOCALE: "local" # location details language, e.g. "local", "en", or "de"
## OpenID Connect (pre-configured for local tests):
## see https://keycloak.localssl.dev/realms/master/.well-known/openid-configuration
## the seeded "photoprism-develop" client in scripts/sql/mariadb-init.sql
## allows callbacks for /api/v1/oidc/redirect and /i/* paths
PHOTOPRISM_OIDC_URI: "https://keycloak.localssl.dev/realms/master"
PHOTOPRISM_OIDC_CLIENT: "photoprism-develop"
PHOTOPRISM_OIDC_SECRET: "9d8351a0-ca01-4556-9c37-85eb634869b9"
PHOTOPRISM_OIDC_PROMPT: "" # authorization prompt: login, select_account, or consent (empty = seamless SSO)
PHOTOPRISM_OIDC_PROVIDER: "Keycloak"
PHOTOPRISM_OIDC_REGISTER: "true"
PHOTOPRISM_OIDC_WEBDAV: "true"
PHOTOPRISM_DISABLE_OIDC: "false"
## LDAP Authentication (pre-configured for local tests):
PHOTOPRISM_LDAP_URI: "ldap://dummy-ldap:389"
PHOTOPRISM_LDAP_INSECURE: "true"
PHOTOPRISM_LDAP_SYNC: "true"
PHOTOPRISM_LDAP_BIND: "simple"
PHOTOPRISM_LDAP_BIND_DN: "cn"
PHOTOPRISM_LDAP_BASE_DN: "dc=localssl,dc=dev"
PHOTOPRISM_LDAP_ROLE: ""
PHOTOPRISM_LDAP_ROLE_DN: "ou=photoprism-*,ou=groups,dc=localssl,dc=dev"
PHOTOPRISM_LDAP_WEBDAV_DN: "ou=photoprism-webdav,ou=groups,dc=localssl,dc=dev"
## HTTPS/TLS Options:
## see https://docs.photoprism.app/getting-started/using-https/
PHOTOPRISM_DISABLE_TLS: "true"
PHOTOPRISM_DEFAULT_TLS: "true"
## Site Information:
PHOTOPRISM_SITE_URL: "${PHOTOPRISM_SITE_URL:-https://app.localssl.dev/}" # "http(s)://domain.name(:port)/(path)"
PHOTOPRISM_SITE_NAME: "" # short name for identifying this instance within a cluster
PHOTOPRISM_SITE_CAPTION: "AI-Powered Photos App" # short caption or tagline shown alongside the title
PHOTOPRISM_SITE_DESCRIPTION: "Tags and finds pictures without getting in your way!" # longer description shown in SEO and social meta tags
PHOTOPRISM_SITE_AUTHOR: "@photoprism_app" # site owner shown in the author meta tag
PHOTOPRISM_DEBUG: "true"
PHOTOPRISM_READONLY: "false"
PHOTOPRISM_EXPERIMENTAL: "true"
PHOTOPRISM_HTTP_MODE: "debug"
PHOTOPRISM_HTTP_HOST: "0.0.0.0"
PHOTOPRISM_HTTP_PORT: 2342
PHOTOPRISM_HTTP_COMPRESSION: "zstd,gzip" # improves transfer speed and bandwidth utilization (none, gzip, zstd, or comma-separated list e.g. "zstd,gzip")
MYSQL_TCP_PORT: "${MARIADB_PORT:-4001}" # default MariaDB database port used by the "mariadb" client (see .my.cnf)
PGPORT: "${POSTGRES_PORT:-4002}" # default PostgreSQL database port used by "psql"
PHOTOPRISM_DATABASE_DRIVER: "mysql"
PHOTOPRISM_DATABASE_SERVER: "mariadb:${MARIADB_PORT:-4001}"
PHOTOPRISM_DATABASE_NAME: "photoprism"
PHOTOPRISM_DATABASE_USER: "root"
PHOTOPRISM_DATABASE_PASSWORD: "photoprism"
PHOTOPRISM_TEST_DRIVER: "sqlite"
# PHOTOPRISM_TEST_DSN_MYSQL8: "root:photoprism@tcp(mysql:${MARIADB_PORT:-4001})/photoprism?charset=utf8mb4,utf8&collation=utf8mb4_unicode_ci&parseTime=true&timeout=15s"
WORKING_DIR: "${WORKING_DIR:-/go/src/github.com/photoprism/photoprism}"
PHOTOPRISM_ASSETS_PATH: "${WORKING_DIR:-/go/src/github.com/photoprism/photoprism}/assets"
PHOTOPRISM_STORAGE_PATH: "${WORKING_DIR:-/go/src/github.com/photoprism/photoprism}/storage"
PHOTOPRISM_ORIGINALS_PATH: "${WORKING_DIR:-/go/src/github.com/photoprism/photoprism}/storage/originals"
PHOTOPRISM_ORIGINALS_LIMIT: 128000 # sets originals file size limit to 128 GB
PHOTOPRISM_IMPORT_PATH: "${WORKING_DIR:-/go/src/github.com/photoprism/photoprism}/storage/import"
PHOTOPRISM_DISABLE_CHOWN: "false" # disables updating storage permissions via chmod and chown on startup
PHOTOPRISM_DISABLE_BACKUPS: "false" # disables backing up albums and photo metadata to YAML files
PHOTOPRISM_DISABLE_WEBDAV: "false" # disables built-in WebDAV server
PHOTOPRISM_DISABLE_MCP: "false" # disables Model Context Protocol (MCP) API endpoint for AI agent integrations
PHOTOPRISM_DISABLE_SETTINGS: "false" # disables settings UI and API
PHOTOPRISM_DISABLE_PLACES: "false" # disables reverse geocoding and maps
PHOTOPRISM_DISABLE_EXIFTOOL: "false" # disables creating JSON metadata sidecar files with ExifTool
PHOTOPRISM_DISABLE_TENSORFLOW: "false" # disables all features depending on TensorFlow
PHOTOPRISM_DISABLE_RAW: "false" # disables indexing and conversion of RAW images
PHOTOPRISM_RAW_PRESETS: "false" # enables applying user presets when converting RAW images (reduces performance)
PHOTOPRISM_DETECT_NSFW: "false" # automatically flags photos as private that MAY be offensive (requires TensorFlow)
PHOTOPRISM_UPLOAD_NSFW: "false" # allows uploads that MAY be offensive (no effect without TensorFlow)
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_THUMB_LIBRARY: "auto" # image processing library to be used for generating thumbnails (auto, vips)
PHOTOPRISM_THUMB_UNCACHED: "true" # enables on-demand thumbnail rendering (high memory and cpu usage)
## Video Transcoding (https://docs.photoprism.app/getting-started/advanced/transcoding/):
# PHOTOPRISM_FFMPEG_ENCODER: "software" # H.264/AVC encoder (software, intel, nvidia, apple, raspberry, vaapi, or vulkan)
# LIBVA_DRIVER_NAME: "i965" # For Intel architectures Haswell and older which do not support QSV yet but use VAAPI instead
PHOTOPRISM_FFMPEG_SIZE: "1920" # video size limit in pixels (720-7680) (default: 3840)
# PHOTOPRISM_FFMPEG_BITRATE: "64" # video bitrate limit in Mbps (default: 60)
## Run/install on first startup (options: update tensorflow https intel gpu davfs yt-dlp):
PHOTOPRISM_INIT: "https"
## Computer Vision (https://docs.photoprism.app/getting-started/config-options/#computer-vision):
PHOTOPRISM_VISION_API: "true" # server: enables service API endpoints under /api/v1/vision (requires access token)
PHOTOPRISM_VISION_URI: "" # client: service URI, e.g. http://hostname/api/v1/vision (leave blank to disable)
PHOTOPRISM_VISION_KEY: "" # client: service access token (for authentication)
OLLAMA_BASE_URL: "http://ollama:11434" # use "https://ollama.com" for Ollama Cloud
OLLAMA_API_KEY: "" # API key required to access Ollama (optional)
## Additional dependencies and tools:
TF_CPP_MIN_LOG_LEVEL: 1
GOCACHE: "${WORKING_DIR:-/go/src/github.com/photoprism/photoprism}/.local/gocache"
CODEX_HOME: "${WORKING_DIR:-/go/src/github.com/photoprism/photoprism}/.local/codex"
CLAUDE_CONFIG_DIR: "${WORKING_DIR:-/go/src/github.com/photoprism/photoprism}/.local/claude"
GH_REPO: "photoprism/photoprism"
GH_CONFIG_DIR: "${WORKING_DIR:-/go/src/github.com/photoprism/photoprism}/.local/gh"
## Shared devices for video hardware transcoding (optional):
# devices:
# - "/dev/dri:/dev/dri" # Required Intel QSV or VAAPI hardware transcoding
# - "/dev/video11:/dev/video11" # Video4Linux Video Encode Device (h264_v4l2m2m)
working_dir: "${WORKING_DIR:-/go/src/github.com/photoprism/photoprism}"
volumes:
- ".:${WORKING_DIR:-/go/src/github.com/photoprism/photoprism}"
- "./storage:/photoprism"
- "go-mod:/go/pkg/mod"
## Traefik v3 (Reverse Proxy)
## includes "*.localssl.dev" SSL certificate for test environments
## Docs: https://doc.traefik.io/traefik/
traefik:
image: photoprism/traefik:latest
stop_grace_period: 15s
security_opt:
- no-new-privileges:true
command:
- --api.dashboard=false
- --global.checknewversion=false
- --global.sendanonymoususage=false
- --providers.docker=true
- --providers.docker.exposedbydefault=false
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
## Publish Traefik's HTTP and HTTPS entrypoints on the host (bound to every interface
## by default; override TRAEFIK_BIND_HOST, TRAEFIK_HTTP_PORT, or TRAEFIK_HTTPS_PORT):
ports:
- "${TRAEFIK_BIND_HOST:-0.0.0.0}:${TRAEFIK_HTTP_PORT:-80}:80" # HTTP (redirects to HTTPS)
- "${TRAEFIK_BIND_HOST:-0.0.0.0}:${TRAEFIK_HTTPS_PORT:-443}:443" # HTTPS (required)
labels:
- "traefik.enable=true"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock" # enables Traefik to watch services
## MariaDB (Database Server)
## Docs: https://mariadb.com/docs/reference/
## Release Notes: https://mariadb.com/kb/en/changes-improvements-in-mariadb-1011/
mariadb:
image: mariadb:12.3
stop_grace_period: 15s
security_opt: # see https://github.com/MariaDB/mariadb-docker/issues/434#issuecomment-1136151239
- seccomp:unconfined
- apparmor:unconfined
command:
- "--port=${MARIADB_PORT:-4001}"
- --innodb-strict-mode=1
- --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
expose:
- "${MARIADB_PORT:-4001}" # does not default to 3306 in order to avoid conflicts and confuse port scanners
## Publish the MariaDB port on the host for direct access from the host:
ports:
- "${SERVICES_BIND_HOST:-127.0.0.1}:${MARIADB_PORT:-4001}:${MARIADB_PORT:-4001}" # MariaDB
volumes:
- "mariadb:/var/lib/mysql"
- "./scripts/sql/mariadb-init.sql:/docker-entrypoint-initdb.d/init.sql"
environment:
MARIADB_AUTO_UPGRADE: "1"
MARIADB_INITDB_SKIP_TZINFO: "1"
MARIADB_DATABASE: "photoprism"
MARIADB_USER: "photoprism"
MARIADB_PASSWORD: "photoprism"
MARIADB_ROOT_PASSWORD: "photoprism"
## PostgreSQL (Database Server)
## Docs: https://www.postgresql.org/docs/current/index.html
## Release Notes: https://www.postgresql.org/docs/release/
postgres:
image: postgres:18-alpine
## Only starts if the "all" or "postgres" profile is specified:
## docker compose --profile postgres up -d
profiles: [ "all", "postgres" ]
stop_grace_period: 15s
expose:
- "${POSTGRES_PORT:-4002}"
## Publish the PostgreSQL port on the host for direct access from the host:
ports:
- "${SERVICES_BIND_HOST:-127.0.0.1}:${POSTGRES_PORT:-4002}:${POSTGRES_PORT:-4002}" # PostgreSQL
volumes:
- "postgres:/var/lib/postgresql"
- "./scripts/sql/postgresql-init.sql:/docker-entrypoint-initdb.d/init.sql"
environment:
POSTGRES_DB: photoprism
POSTGRES_USER: photoprism
POSTGRES_PASSWORD: photoprism
PGPORT: "${POSTGRES_PORT:-4002}"
PGDATA: /var/lib/postgresql/18/docker
## Qdrant (Vector Database)
## Docs: https://qdrant.tech/documentation/guides/installation/#docker-compose
## Release Notes: https://github.com/qdrant/qdrant/releases
## Web UI: https://qdrant.localssl.dev/dashboard
qdrant:
image: qdrant/qdrant:latest
## Only starts if the "all" or "qdrant" profile is specified:
## docker compose --profile qdrant up -d
profiles: [ "all", "qdrant" ]
stop_grace_period: 10s
links:
- "traefik:localssl.dev"
- "traefik:app.localssl.dev"
- "traefik:vision.localssl.dev"
labels:
- "traefik.enable=true"
- "traefik.docker.network=${COMPOSE_NETWORK_NAME:-photoprism}"
- "traefik.http.services.qdrant.loadbalancer.server.port=6333"
- "traefik.http.services.qdrant.loadbalancer.server.scheme=http"
- "traefik.http.routers.qdrant.entrypoints=websecure"
- "traefik.http.routers.qdrant.rule=Host(`qdrant.localssl.dev`)"
- "traefik.http.routers.qdrant.priority=3"
- "traefik.http.routers.qdrant.tls.domains[0].main=localssl.dev"
- "traefik.http.routers.qdrant.tls.domains[0].sans=*.localssl.dev"
- "traefik.http.routers.qdrant.tls=true"
expose:
- 6333
- 6334
- 6335
volumes:
- "./.qdrant.yaml:/qdrant/config/production.yaml"
- "./storage/services/qdrant:/qdrant/storage"
## Ollama Large-Language Model Runner
## run "ollama pull [name]:[version]" to download a vision model
## listed at <https://ollama.com/search?c=vision>, for example:
## docker compose exec ollama ollama pull gemma3:latest
ollama:
image: ollama/ollama:latest
## Only starts if the "all", "ollama", or "vision" profile is specified:
## docker compose --profile ollama up -d
profiles: [ "all", "ollama", "vision" ]
stop_grace_period: 10s
## Optionally publish the Ollama API on the host (no built-in auth — private/internal networks only):
# ports:
# - "${SERVICES_BIND_HOST:-127.0.0.1}:11434:11434" # Ollama API
labels:
- "traefik.enable=true"
- "traefik.docker.network=${COMPOSE_NETWORK_NAME:-photoprism}"
- "traefik.http.services.ollama.loadbalancer.server.port=11434"
- "traefik.http.routers.ollama.rule=Host(`ollama.localssl.dev`)"
- "traefik.http.routers.ollama.entrypoints=websecure"
- "traefik.http.routers.ollama.tls=true"
environment:
## Ollama Configuration Options:
OLLAMA_HOST: "0.0.0.0:11434"
OLLAMA_MODELS: "/root/.ollama" # model storage path (see volumes section below)
OLLAMA_MAX_QUEUE: "100" # maximum number of queued requests
OLLAMA_NUM_PARALLEL: "1" # maximum number of parallel requests
OLLAMA_MAX_LOADED_MODELS: "1" # maximum number of loaded models per GPU
OLLAMA_LOAD_TIMEOUT: "5m" # maximum time for loading models (default "5m")
OLLAMA_KEEP_ALIVE: "5m" # duration that models stay loaded in memory (default "5m")
OLLAMA_CONTEXT_LENGTH: "4096" # maximum input context length
OLLAMA_MULTIUSER_CACHE: "false" # optimize prompt caching for multi-user scenarios
OLLAMA_NOPRUNE: "false" # disables pruning of model blobs at startup
OLLAMA_NOHISTORY: "true" # disables readline history
OLLAMA_FLASH_ATTENTION: "true" # required for OLLAMA_KV_CACHE_TYPE quantization
OLLAMA_KV_CACHE_TYPE: "f16" # cache precision: f16 (default), q8_0, q4_0
OLLAMA_SCHED_SPREAD: "false" # allows scheduling models across all GPUs.
# OLLAMA_DEBUG: "true" # shows additional debug information
# OLLAMA_INTEL_GPU: "true" # enables experimental Intel GPU detection
## Telemetry / privacy opt-outs (containers do not inherit /etc/environment):
DO_NOT_TRACK: "true"
HF_HUB_DISABLE_TELEMETRY: "1"
# OLLAMA_NO_CLOUD: "1" # uncomment to disable Ollama Cloud models/features
## NVIDIA GPU Hardware Acceleration (optional):
# NVIDIA_VISIBLE_DEVICES: "all"
# NVIDIA_DRIVER_CAPABILITIES: "compute,utility"
volumes:
- "./storage/services/ollama:/root/.ollama"
## NVIDIA GPU Hardware Acceleration (optional):
# deploy:
# resources:
# reservations:
# devices:
# - driver: "nvidia"
# capabilities: [ gpu ]
# count: "all"
## Open WebUI, a Web Interface for Ollama
## see https://github.com/open-webui/open-webui
open-webui:
image: ghcr.io/open-webui/open-webui:main
## Only starts if the "all", "ollama", "open-webui", or "vision" profile is specified:
## docker compose --profile open-webui up -d
profiles: [ "all", "ollama", "open-webui", "vision" ]
stop_grace_period: 10s
## Publish Open WebUI on the host (default access is via https://chat.localssl.dev/ through Traefik):
ports:
- "${SERVICES_BIND_HOST:-127.0.0.1}:8080:8080" # Open WebUI
labels:
- "traefik.enable=true"
- "traefik.docker.network=${COMPOSE_NETWORK_NAME:-photoprism}"
- "traefik.http.services.open-webui.loadbalancer.server.port=8080"
- "traefik.http.routers.open-webui.rule=Host(`chat.localssl.dev`) || Host(`open-webui.localssl.dev`) || Host(`ollama-ui.localssl.dev`)"
- "traefik.http.routers.open-webui.entrypoints=websecure"
- "traefik.http.routers.open-webui.tls=true"
environment:
WEBUI_URL: "https://chat.localssl.dev"
# WEBUI_SECRET_KEY: ""
OLLAMA_BASE_URL: "http://ollama:11434"
ANONYMIZED_TELEMETRY: "false" # disable Chroma telemetry
HF_HUB_DISABLE_TELEMETRY: "1" # disable Hugging Face telemetry
# HUGGING_FACE_HUB_TOKEN: "" # see https://huggingface.co/docs/hub/en/security-tokens
volumes:
- "./storage/services/open-webui:/app/backend/data"
## PhotoPrism® Computer Vision API
## see https://github.com/photoprism/photoprism-vision
photoprism-vision:
image: photoprism/vision:latest
## Only starts if the "all" or "vision" profile is specified:
## docker compose --profile vision up -d
profiles: [ "all", "vision" ]
stop_grace_period: 15s
working_dir: "/app"
links:
- "traefik:localssl.dev"
- "traefik:app.localssl.dev"
- "traefik:qdrant.localssl.dev"
labels:
- "traefik.enable=true"
- "traefik.docker.network=${COMPOSE_NETWORK_NAME:-photoprism}"
- "traefik.http.services.vision.loadbalancer.server.port=5000"
- "traefik.http.services.vision.loadbalancer.server.scheme=http"
- "traefik.http.routers.vision.entrypoints=websecure"
- "traefik.http.routers.vision.rule=Host(`vision.localssl.dev`)"
- "traefik.http.routers.vision.priority=3"
- "traefik.http.routers.vision.tls.domains[0].main=localssl.dev"
- "traefik.http.routers.vision.tls.domains[0].sans=*.localssl.dev"
- "traefik.http.routers.vision.tls=true"
expose:
- 5000
environment:
TF_CPP_MIN_LOG_LEVEL: 2
## Ollama client configuration (for the service, see below):
OLLAMA_ENABLED: "true"
OLLAMA_HOST: "http://ollama:11434"
## Dummy WebDAV Server
dummy-webdav:
image: photoprism/dummy-webdav:251210
stop_grace_period: 10s
environment:
WEBDAV_USERNAME: admin
WEBDAV_PASSWORD: photoprism
labels:
- "traefik.enable=true"
- "traefik.docker.network=${COMPOSE_NETWORK_NAME:-photoprism}"
- "traefik.http.services.dummy-webdav.loadbalancer.server.port=80"
- "traefik.http.routers.dummy-webdav.entrypoints=websecure"
- "traefik.http.routers.dummy-webdav.rule=Host(`dummy-webdav.localssl.dev`)"
- "traefik.http.routers.dummy-webdav.priority=3"
- "traefik.http.routers.dummy-webdav.tls.domains[0].main=localssl.dev"
- "traefik.http.routers.dummy-webdav.tls.domains[0].sans=*.localssl.dev"
- "traefik.http.routers.dummy-webdav.tls=true"
## Dummy OIDC Identity Provider
dummy-oidc:
image: photoprism/dummy-oidc:260427
stop_grace_period: 5s
labels:
- "traefik.enable=true"
- "traefik.docker.network=${COMPOSE_NETWORK_NAME:-photoprism}"
- "traefik.http.services.dummy-oidc.loadbalancer.server.port=9998"
- "traefik.http.routers.dummy-oidc.entrypoints=websecure"
- "traefik.http.routers.dummy-oidc.rule=Host(`dummy-oidc.localssl.dev`)"
- "traefik.http.routers.dummy-oidc.priority=3"
- "traefik.http.routers.dummy-oidc.tls.domains[0].main=localssl.dev"
- "traefik.http.routers.dummy-oidc.tls.domains[0].sans=*.localssl.dev"
- "traefik.http.routers.dummy-oidc.tls=true"
## Dummy LDAP Directory Server
## Docs: https://glauth.github.io/docs/
dummy-ldap:
image: glauth/glauth-plugins:latest
stop_grace_period: 5s
## Publish the dummy-ldap port on the host (default access is via "dummy-ldap:389" within the compose network):
ports:
- "${SERVICES_BIND_HOST:-127.0.0.1}:389:389" # LDAP
labels:
- "traefik.enable=true"
- "traefik.docker.network=${COMPOSE_NETWORK_NAME:-photoprism}"
- "traefik.http.services.dummy-ldap.loadbalancer.server.port=5555"
- "traefik.http.routers.dummy-ldap.entrypoints=websecure"
- "traefik.http.routers.dummy-ldap.rule=Host(`dummy-ldap.localssl.dev`)"
- "traefik.http.routers.dummy-ldap.priority=3"
- "traefik.http.routers.dummy-ldap.tls.domains[0].main=localssl.dev"
- "traefik.http.routers.dummy-ldap.tls.domains[0].sans=*.localssl.dev"
- "traefik.http.routers.dummy-ldap.tls=true"
volumes:
- "./.ldap.cfg:/app/config/config.cfg"
## Keycloak (OIDC Identity Provider)
## Docs: https://www.keycloak.org/docs/latest/server_admin/
## Login with "user / photoprism" and "admin / photoprism".
keycloak:
image: quay.io/keycloak/keycloak:25.0
## Only starts if the "all", "auth", or "keycloak" profile is specified:
## docker compose --profile keycloak up -d
profiles: [ "all", "auth", "keycloak" ]
stop_grace_period: 10s
command: "start-dev" # development mode, do not use this in production!
links:
- "traefik:localssl.dev"
- "traefik:app.localssl.dev"
labels:
- "traefik.enable=true"
- "traefik.docker.network=${COMPOSE_NETWORK_NAME:-photoprism}"
- "traefik.http.services.keycloak.loadbalancer.server.port=8080"
- "traefik.http.routers.keycloak.entrypoints=websecure"
- "traefik.http.routers.keycloak.rule=Host(`keycloak.localssl.dev`)"
- "traefik.http.routers.keycloak.priority=3"
- "traefik.http.routers.keycloak.tls.domains[0].main=localssl.dev"
- "traefik.http.routers.keycloak.tls.domains[0].sans=*.localssl.dev"
- "traefik.http.routers.keycloak.tls=true"
environment: # see https://www.keycloak.org/server/all-config
KEYCLOAK_ADMIN: "admin"
KEYCLOAK_ADMIN_PASSWORD: "photoprism"
KC_METRICS_ENABLED: "false"
KC_HOSTNAME: "keycloak.localssl.dev"
KC_HOSTNAME_STRICT: "false"
KC_PROXY: "edge"
KC_DB: "mariadb"
KC_DB_URL: "jdbc:mariadb://mariadb:${MARIADB_PORT:-4001}/keycloak"
KC_DB_USERNAME: "keycloak"
KC_DB_PASSWORD: "keycloak"
## Run "docker compose --profile prometheus up" to start your development environment with Prometheus.
## Docs: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#oauth2
## The following grants API access to Prometheus with the preconfigured client credentials (adjust flags as needed):
## ./photoprism client add --id=cs5cpu17n6gj2qo5 --secret=xcCbOrw6I0vcoXzhnOmXhjpVSyFq0l0e -s metrics -n Prometheus -e 60 -t 1
prometheus:
image: prom/prometheus:latest
## Only starts if the "all", "auth", or "prometheus" profile is specified:
## docker compose --profile prometheus up -d
profiles: [ "all", "auth", "prometheus" ]
stop_grace_period: 10s
labels:
- "traefik.enable=true"
- "traefik.docker.network=${COMPOSE_NETWORK_NAME:-photoprism}"
- "traefik.http.services.prometheus.loadbalancer.server.port=9090"
- "traefik.http.routers.prometheus.entrypoints=websecure"
- "traefik.http.routers.prometheus.rule=Host(`prometheus.localssl.dev`)"
- "traefik.http.routers.prometheus.priority=3"
- "traefik.http.routers.prometheus.tls.domains[0].main=localssl.dev"
- "traefik.http.routers.prometheus.tls.domains[0].sans=*.localssl.dev"
- "traefik.http.routers.prometheus.tls=true"
volumes:
- "./prometheus.yml:/etc/prometheus/prometheus.yml"
## Create named volume for Go module cache
volumes:
go-mod:
driver: local
mariadb:
driver: local
postgres:
driver: local
## Create a shared bridge network for connecting with services in other compose.yaml files.
## Override COMPOSE_NETWORK_NAME to run multiple parallel environments without colliding on the default name.
networks:
default:
name: ${COMPOSE_NETWORK_NAME:-photoprism}
driver: bridge
This file may be out of date. Check the PhotoPrism documentation for current setup steps.
Open-source health
Tags
Track your self-hosted stack
Bookmark software to try, rate tools you've used, and keep your collection in one place.
Metadata extracted from README on Jul 26, 2026
Related Software
Damselfly
1.8k
Damselfly is a server-based digital photo management system for managing large folder-based photo collections with fast search, tagging, and AI-assisted recognition.
Photo GalleriesMedia ManagementArtificial Intelligence+4
Nextcloud Memories
3.9k
Memories is a photo management app for Nextcloud with timeline browsing, sharing, metadata editing, and AI-based tagging.
Photo GalleriesCopyleft LicenseMedia Management+3
5 ContainersCloud Required
ChronoFrame
1.9k
A self-hosted web application for photo display and management with map-based browsing, EXIF parsing, and multi-format image support.
Photo GalleriesPermissive LicenseMedia Management+3
Mejiro
184
Pellicola is a PHP web app for instant photo publishing and browsing.
Photo GalleriesMedia ManagementWeb Servers+3
LibrePhotos
8.1k
LibrePhotos is a self-hosted photo management service with face recognition, object detection, and semantic search.
Photo GalleriesMedia ManagementArtificial Intelligence+2
HomeGallery
1.2k
HomeGallery is a self-hosted open-source web gallery for browsing personal photos and videos with tagging, mobile-friendly viewing, and AI-powered image and face discovery.
Photo GalleriesPermissive LicenseMedia Management+2
pixlstash
89
PixlStash is a local picture library server for organizing, filtering, and reviewing large image collections.
Media ManagementPhoto GalleriesArtificial Intelligence+2
Single Container
Thumbor
10.5k
thumbor is a smart imaging service for on-demand cropping, resizing, transforming, and optimizing images.
Photo GalleriesMedia ManagementWeb Servers+2
Immich
116.0k
High performance self-hosted photo and video management solution.
Photo GalleriesCopyleft LicenseMedia Management+1
6 Containers
PiGallery 2
2.3k
A fast directory-first photo gallery website for low-resource servers, especially Raspberry Pi.
Photo GalleriesMedia ManagementSelf Hosting Solutions+1
2 Containers
Piwigo
3.9k
Piwigo is an open source web-based photo gallery for managing and sharing photo libraries.
Photo GalleriesMedia ManagementCMS Platforms+3
Fully FOSS
Photoview
6.5k
Photoview is a self-hosted photo gallery that scans local directories, generates thumbnails, and organizes photos and videos for fast browsing.
Photo GalleriesMedia ManagementSelf Hosting Solutions+2
4 ContainersFully FOSS
