25fbefc703
Every other feature routes readers to docs.picpeak.app. Face recognition was the one that either pointed somewhere else or pointed at nothing — poor placement for the feature with the highest read-before-you-enable burden anything here ships. .env.example referenced docs/feature-face-recognition.md, which does not exist — and creating it is not the fix, because .gitignore:89 ignores docs/feature-*.md outright, so the file would be invisible to anyone who cloned. That was the only pointer to legal guidance an operator got while editing the variables that turn Art. 9 processing on. Also: the README linked the sidecar's developer README for the feature name and had no row in the documentation table, docs/single-container.md left readers who wanted the feature nowhere to go, ml/README.md had no backlink, and the admin consent callout had no link at all. It does now, inline at the end of the obligation. Reported by @Luca-Timo.
293 lines
13 KiB
Bash
293 lines
13 KiB
Bash
# PicPeak Environment Configuration
|
|
# Copy this file to .env and update with your values
|
|
|
|
# Environment
|
|
NODE_ENV=production
|
|
|
|
# JWT Secret — OPTIONAL. Leave unset and it is auto-generated on first run
|
|
# (Docker: the secrets-init service writes it to a private volume and reuses it
|
|
# across restarts). Set it explicitly only to pin your own value.
|
|
# Generate one with: openssl rand -base64 64
|
|
#JWT_SECRET=your_very_long_random_jwt_secret_here
|
|
|
|
# OIDC SSO for admins (#798) — configured in the admin UI; only these two
|
|
# values live in the environment:
|
|
# Key encrypting the OIDC client secret at rest (defaults to JWT_SECRET).
|
|
#OIDC_ENCRYPTION_KEY=
|
|
# Break-glass: 'true' re-enables local password login even while the SSO
|
|
# settings disable it (recovery when the IdP is down or misconfigured).
|
|
#OIDC_BREAK_GLASS=false
|
|
|
|
# Auth cookie Secure flag
|
|
# unset - default: follows NODE_ENV (production=true, dev=false)
|
|
# true - always set Secure (HTTPS-only cookies; breaks plain-HTTP access)
|
|
# false - never set Secure (allows HTTP; cookies not protected on HTTPS)
|
|
# auto - decide per request: Secure on HTTPS, not on HTTP
|
|
#
|
|
# Use COOKIE_SECURE=auto if your deployment is reachable over both HTTPS
|
|
# (via reverse proxy like Nginx Proxy Manager, Traefik, Caddy) AND plain
|
|
# HTTP (e.g. LAN access at http://192.168.x.x:3010). The backend reads
|
|
# req.secure from Express, which respects the X-Forwarded-Proto header
|
|
# when the proxy is in the trust list.
|
|
#
|
|
# Requirements for auto mode:
|
|
# 1. Your reverse proxy MUST send X-Forwarded-Proto: https on HTTPS
|
|
# requests. Standard configs for NPM/Traefik/Caddy do this by default.
|
|
# 2. The proxy must be on a trusted IP range. By default PicPeak trusts
|
|
# loopback and private networks (127.0.0.1, 10.x, 172.16-31.x,
|
|
# 192.168.x, link-local). Proxies outside those ranges need custom
|
|
# trust proxy configuration.
|
|
# COOKIE_SECURE=auto
|
|
|
|
# Cookie SameSite attribute (Lax | Strict | None). Default: Lax
|
|
# COOKIE_SAMESITE=Lax
|
|
|
|
# Cookie Domain — set this if serving auth cookies across subdomains.
|
|
# Leave unset for same-origin setups.
|
|
# COOKIE_DOMAIN=.example.com
|
|
|
|
# Database Configuration (PostgreSQL)
|
|
DATABASE_CLIENT=pg
|
|
DB_USER=picpeak
|
|
# DB_PASSWORD — OPTIONAL. Leave unset and it is auto-generated on first run
|
|
# (Docker). Set it explicitly to pin your own, e.g. for an external database.
|
|
# IMPORTANT: Avoid $ character in passwords - Docker Compose interprets it as variable substitution
|
|
# If you must use $, escape it as $$ (e.g., Pass$$word instead of Pass$word)
|
|
#DB_PASSWORD=your_secure_postgres_password_here
|
|
DB_NAME=picpeak_prod
|
|
|
|
# Redis Configuration
|
|
# REDIS_PASSWORD — OPTIONAL. Leave unset and it is auto-generated on first run (Docker).
|
|
# IMPORTANT: Same warning applies - avoid $ or escape as $$
|
|
#REDIS_PASSWORD=your_secure_redis_password_here
|
|
|
|
# Admin Account (initial setup) — OPTIONAL
|
|
# Leave these unset (default) to create your admin IN THE BROWSER on first run:
|
|
# open /admin and PicPeak shows a setup screen. The one-time setup token is
|
|
# written to data/SETUP_TOKEN with mode 0600 — read it with
|
|
# `docker compose exec backend cat /app/data/SETUP_TOKEN`. It is NOT logged
|
|
# unless that write fails, so it never sits in `docker logs`.
|
|
# Set ADMIN_PASSWORD to auto-create the admin on first boot instead (legacy;
|
|
# credentials written to data/ADMIN_CREDENTIALS.txt).
|
|
#ADMIN_USERNAME=admin
|
|
#ADMIN_EMAIL=admin@yourdomain.com
|
|
#ADMIN_PASSWORD=your_secure_admin_password_here
|
|
|
|
# Email Configuration — OPTIONAL, and normally left alone.
|
|
# SMTP is configured in the setup wizard / Settings -> Email and stored in the
|
|
# database (email_configs); that is what the mail queue actually sends with.
|
|
# These variables are a legacy path kept for config-as-code deployments: when
|
|
# SMTP_HOST is set, the initial migration seeds the database row from it.
|
|
# Developers running the `dev` compose profile want SMTP_HOST=mailhog here so
|
|
# that seed points at the mailhog container.
|
|
# For Gmail: use app-specific password
|
|
# For SendGrid: SMTP_USER=apikey, SMTP_PASS=your-api-key
|
|
#SMTP_HOST=smtp.gmail.com
|
|
#SMTP_PORT=587
|
|
#SMTP_SECURE=false
|
|
#SMTP_USER=your-email@gmail.com
|
|
#SMTP_PASS=your-app-specific-password
|
|
#EMAIL_FROM=noreply@yourdomain.com
|
|
|
|
# Application URLs — OPTIONAL. Leave unset for the normal install.
|
|
# The public origin is captured by the setup wizard (it proposes the address
|
|
# you opened the browser at) and stored as the `general_site_url` setting, so
|
|
# you can change it later in Settings -> General without touching this file.
|
|
# Setting FRONTEND_URL here OVERRIDES that setting and makes the field
|
|
# read-only in the admin UI - use it only for config-as-code deployments.
|
|
# Use full origin with scheme, no trailing slash.
|
|
# Admin UI is served by the frontend at /admin.
|
|
#FRONTEND_URL=https://yourdomain.com
|
|
#ADMIN_URL=https://yourdomain.com
|
|
|
|
# Static HTML title + description used for social link previews when the
|
|
# fetcher doesn't trigger the per-event OG endpoint — most notably the
|
|
# WhatsApp Business API and various 3rd-party preview-service caches
|
|
# (#521). Set these to your brand so link previews aren't generic.
|
|
# Substituted into index.html at frontend-container start, so changes
|
|
# take effect on the next `docker compose up -d frontend` — no rebuild
|
|
# required.
|
|
BRAND_TITLE=PicPeak
|
|
BRAND_DESCRIPTION=Photo gallery shared with PicPeak.
|
|
|
|
# API URL for email assets (logos, images in notification emails)
|
|
# OPTIONAL: when unset this is derived from the resolved public origin + /api,
|
|
# so the wizard's answer covers it. Set it only for split-origin deployments
|
|
# where the API lives on a different host than the gallery.
|
|
#API_URL=https://yourdomain.com/api
|
|
|
|
# Frontend API base
|
|
# For pre-built images and production behind a reverse proxy, keep '/api'.
|
|
# If you rebuild the frontend yourself, you may set a full URL at build time.
|
|
VITE_API_URL=/api
|
|
|
|
# Port Configuration (optional)
|
|
# BACKEND_PORT=3001
|
|
# FRONTEND_PORT=3000
|
|
# DB_PORT=5432
|
|
# REDIS_PORT=6379
|
|
|
|
# File watcher (watch-folder auto-import, local storage only)
|
|
# Max photos processed in parallel — raise on hosts with memory headroom,
|
|
# lower to 1 on very small hosts. Default: 2
|
|
# FILE_WATCHER_CONCURRENCY=2
|
|
|
|
# Release Channel
|
|
# Options: 'stable' (default), 'beta', or specific version like 'v2.3.0'
|
|
# 'stable' uses the :stable tag (same as :latest on main)
|
|
# 'beta' uses the :beta tag for pre-release versions
|
|
PICPEAK_CHANNEL=stable
|
|
|
|
# Update Check Configuration
|
|
# Set to 'false' to disable update notifications in admin UI
|
|
UPDATE_CHECK_ENABLED=true
|
|
|
|
# Timezone
|
|
TZ=UTC
|
|
|
|
# Analytics (Optional - Umami)
|
|
VITE_UMAMI_URL=
|
|
VITE_UMAMI_WEBSITE_ID=
|
|
VITE_UMAMI_SHARE_URL=
|
|
|
|
# Storage variables (host paths)
|
|
# These control where data is stored on the host. Defaults are local folders.
|
|
APP_STORAGE=./storage
|
|
APP_DATA=./data
|
|
LOGS=./logs
|
|
|
|
# ─── Storage Backend ────────────────────────────────────────────────────────
|
|
# PicPeak can store photos, thumbnails and archive zips on the local filesystem
|
|
# (default) or on any S3-compatible object store (AWS S3, MinIO, Cloudflare R2,
|
|
# Backblaze B2, Wasabi, DigitalOcean Spaces, …).
|
|
#
|
|
# STORAGE_BACKEND=local (default)
|
|
# Uses STORAGE_PATH on the local filesystem. Backwards compatible — every
|
|
# existing deployment keeps working unchanged.
|
|
#
|
|
# STORAGE_BACKEND=s3
|
|
# Reads STORAGE_S3_* below. Auto-import via the filesystem watcher is
|
|
# disabled in this mode (S3 has no inotify) — every photo must enter via the
|
|
# admin upload UI/API. Run `node backend/scripts/migrate-storage.js` to copy
|
|
# existing local content to S3 before flipping the env.
|
|
#
|
|
# STORAGE_BACKEND=local
|
|
#
|
|
# STORAGE_S3_BUCKET=picpeak
|
|
# STORAGE_S3_REGION=us-east-1
|
|
# STORAGE_S3_ACCESS_KEY=AKIAxxxxxxxxxxxxxxxx
|
|
# STORAGE_S3_SECRET_KEY=xxxxxxxxxxxxxxxxxxxxxxxx
|
|
# Custom endpoint — set this for MinIO / R2 / B2 / Spaces. Leave unset for AWS.
|
|
# STORAGE_S3_ENDPOINT=https://s3.us-west-002.backblazeb2.com
|
|
# Optional namespace prefix inside the bucket — useful for multi-deployment buckets.
|
|
# STORAGE_S3_PREFIX=picpeak
|
|
# STORAGE_S3_FORCE_PATH_STYLE=false # MinIO needs true; auto-on when endpoint is set
|
|
# STORAGE_S3_SSL=true
|
|
#
|
|
# Minimum IAM policy (AWS S3) for the bucket above:
|
|
# {
|
|
# "Version": "2012-10-17",
|
|
# "Statement": [{
|
|
# "Effect": "Allow",
|
|
# "Action": [
|
|
# "s3:GetObject", "s3:PutObject", "s3:DeleteObject",
|
|
# "s3:ListBucket", "s3:GetBucketLocation"
|
|
# ],
|
|
# "Resource": [
|
|
# "arn:aws:s3:::picpeak",
|
|
# "arn:aws:s3:::picpeak/*"
|
|
# ]
|
|
# }]
|
|
# }
|
|
#
|
|
# EXTERNAL_MEDIA_ROOT (above) always lives on the local filesystem regardless
|
|
# of STORAGE_BACKEND — reference-mode galleries are not migrated to S3 in v1.
|
|
|
|
# ─── Outbound Webhooks (#327) ────────────────────────────────────────────────
|
|
# PicPeak POSTs event/photo lifecycle notifications to URLs you configure
|
|
# under Settings → Webhooks. Each delivery is signed HMAC-SHA256 with a
|
|
# per-webhook secret in the X-PicPeak-Signature header.
|
|
#
|
|
# WEBHOOK_ALLOW_PRIVATE_URLS (default: false)
|
|
# Block URLs resolving to private IPs / loopback / .local etc. as an
|
|
# SSRF mitigation. Set to "true" ONLY in dev when your receiver is on
|
|
# the same docker network or localhost. Production deployments must
|
|
# leave this OFF.
|
|
# WEBHOOK_ALLOW_PRIVATE_URLS=false
|
|
#
|
|
# WEBHOOK_DELIVERY_INTERVAL_MS (default: 5000)
|
|
# How often the worker polls webhook_deliveries for pending rows.
|
|
# WEBHOOK_DELIVERY_INTERVAL_MS=5000
|
|
#
|
|
# WEBHOOK_DELIVERY_CONCURRENCY (default: 5)
|
|
# Maximum in-flight deliveries per worker tick. One slow consumer can
|
|
# monopolize all 5 slots — bump this if your receivers are slow OR ship
|
|
# a separate webhook-only deployment.
|
|
# WEBHOOK_DELIVERY_CONCURRENCY=5
|
|
#
|
|
# WEBHOOK_HTTP_TIMEOUT_MS (default: 10000)
|
|
# Per-request timeout. Beyond this, the delivery is recorded as a
|
|
# network error and retried.
|
|
# WEBHOOK_HTTP_TIMEOUT_MS=10000
|
|
#
|
|
# WEBHOOK_MAX_ATTEMPTS (default: 5)
|
|
# Total attempts before a delivery is marked failed. Backoff between
|
|
# attempts is exponential: 1m, 5m, 30m, 2h, 12h.
|
|
# WEBHOOK_MAX_ATTEMPTS=5
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Face recognition — "People in this gallery" (#1074, optional)
|
|
# -----------------------------------------------------------------------------
|
|
# Requires the optional picpeak-ml sidecar container:
|
|
# docker compose --profile faces up -d
|
|
#
|
|
# NONE of these variables do anything until the `faces` feature flag is
|
|
# enabled in Admin → Settings, AND the per-event "Detect people in this
|
|
# gallery" toggle is switched on. Both default to OFF. With the flag off the
|
|
# backend never contacts the sidecar, so leaving these at their defaults on an
|
|
# install without the container is completely inert.
|
|
#
|
|
# Face embeddings are biometric data (GDPR Art. 9 special category in the EU).
|
|
# The photographer is the controller and needs a lawful basis for the people
|
|
# in their photos — read https://docs.picpeak.app/features/face-recognition
|
|
# before enabling.
|
|
#
|
|
# NOT AVAILABLE ON THE ALL-IN-ONE IMAGE. The single-container build sets
|
|
# PICPEAK_SINGLE_CONTAINER=true and the backend refuses to enable face
|
|
# recognition there regardless of these variables or the feature flag: that
|
|
# image runs the backend, frontend, database and every worker in one
|
|
# container, with no ML sidecar to talk to, and face detection would compete
|
|
# with image processing for the same CPU and memory. Use the standard
|
|
# multi-container deployment if you want this feature.
|
|
#
|
|
# FACE_ML_TOKEN (no default — REQUIRED to run the sidecar)
|
|
# Shared secret between the backend and the sidecar. The sidecar refuses to
|
|
# start without it rather than serving anonymously, so an accidentally
|
|
# published port is never a free face-detection API. Generate with:
|
|
# openssl rand -hex 32
|
|
# FACE_ML_TOKEN=
|
|
#
|
|
# FACE_ML_URL (default: http://picpeak-ml:8000)
|
|
# Defaults to the sidecar's compose service name, so the standard
|
|
# deployment needs no configuration here. Only change it if you run the
|
|
# sidecar outside the default compose network.
|
|
# FACE_ML_URL=http://picpeak-ml:8000
|
|
#
|
|
# FACE_PROCESSOR_CONCURRENCY (default: 1)
|
|
# Face-detection workers in the backend. Defaults to 1 deliberately: face
|
|
# scanning shares a host with Sharp image processing, which is the real
|
|
# memory pressure (see UPLOAD_PROCESSOR_CONCURRENCY). Raise only on hosts
|
|
# with headroom to spare.
|
|
# FACE_PROCESSOR_CONCURRENCY=1
|
|
#
|
|
# FACE_ORT_THREADS (default: 1)
|
|
# ONNX Runtime threads inside the sidecar. More threads mean faster
|
|
# per-photo inference and higher RSS.
|
|
# FACE_ORT_THREADS=1
|
|
|
|
# Note on FRONTEND_API_URL (documentation only):
|
|
# When using pre-built frontend images, runtime env vars cannot override the built JS.
|
|
# Do NOT rely on FRONTEND_API_URL in Compose. Instead, keep VITE_API_URL=/api and
|
|
# let the frontend Nginx proxy /api to the backend. Only if you rebuild the frontend
|
|
# should you change VITE_API_URL at build time.
|