Skip to Content
DeploymentEnvironment Variables

Environment Variables

Complete reference for all PicPeak environment variables. Set these in the .env file at the project root.

Avoid $ characters in passwords. Docker Compose interprets $ as variable substitution. Either omit $ entirely or escape it as $$.

Core

VariableRequiredDefaultDescription
NODE_ENVNoproductionEnvironment mode
JWT_SECRETYes---Authentication secret. Generate with openssl rand -base64 64
TZNoUTCTimezone
SHUTDOWN_TIMEOUT_MSNo8000Backend shutdown deadline in milliseconds after SIGTERM or SIGINT; forces an exit when exceeded. Set in the backend container’s environment and keep below Docker Compose’s stop_grace_period. See Stopping and restarting.
TRUST_PROXYNoloopback, linklocal, uniquelocalWhich upstream proxies PicPeak trusts for X-Forwarded-For / X-Forwarded-Proto. Accepts any Express trust proxy value: a number of hops, loopback, linklocal, uniquelocal, a CIDR, a comma list, or true. The default covers Docker networks and private-network proxies. A proxy with a public address needs an explicit entry, otherwise per-IP features such as the API rate limiter see the proxy’s address for every visitor.

Authentication cookies

Admin, gallery, and guest sessions are carried in HTTP cookies. These variables control how those cookies are set.

VariableRequiredDefaultDescription
COOKIE_SECURENofollows NODE_ENV (production → true)true, false, or auto — see below
COOKIE_SAMESITENoLaxLax, Strict, or None
COOKIE_DOMAINNo---Set to .example.com only if serving cookies across subdomains
ValueBehaviorWhen to use
(unset)Follows NODE_ENVtrue in production, false in developmentDefault. Fine for typical HTTPS-only deployments
trueAlways set the Secure flag (HTTPS-only cookies)Explicit HTTPS-only deployments
falseNever set the Secure flagLocal/LAN-only deployments with no HTTPS
autoDecide per request based on the actual protocolMixed HTTPS + LAN HTTP access (see below)

A common self-hosted setup:

  • Public: HTTPS via a reverse proxy like Nginx Proxy Manager, Traefik, or Caddy (e.g. https://photos.example.com)
  • LAN: Plain HTTP on a private address (e.g. http://192.168.1.50:3001) for admin access without going through the proxy

With a static COOKIE_SECURE=true, LAN login breaks because browsers refuse to send Secure cookies over HTTP. With COOKIE_SECURE=false, HTTPS login loses the security of the Secure flag. The auto value fixes this by deciding the Secure flag per request — the backend reads req.secure from Express, which reflects the X-Forwarded-Proto header forwarded by your reverse proxy.

Requirements for auto mode:

  1. Your reverse proxy must forward X-Forwarded-Proto: https on HTTPS requests. Nginx Proxy Manager, Traefik, and Caddy do this by default. Custom Nginx configs need proxy_set_header X-Forwarded-Proto $scheme;.
  2. Your proxy must be on a trusted IP range. PicPeak trusts loopback, linklocal, uniquelocal (127.0.0.1, 10.x, 172.16–31.x, 192.168.x, link-local, ULA). This covers Docker networks and most self-hosted setups. Proxies outside those ranges won’t have their X-Forwarded-Proto honored.

Example .env entry:

COOKIE_SECURE=auto

auto is opt-in. The default behavior (following NODE_ENV) is unchanged — existing deployments see no difference unless they explicitly set COOKIE_SECURE=auto.

Database

VariableRequiredDefaultDescription
DATABASE_CLIENTNopgDatabase client (pg or sqlite3)
DB_HOSTNopostgresPostgreSQL host (defaults to bundled container)
DB_PORTNo5432PostgreSQL port
DB_USERNopicpeakDatabase username
DB_PASSWORDYes---Database password
DB_NAMENopicpeak_prodDatabase name

Redis

VariableRequiredDefaultDescription
REDIS_PASSWORDYes---Redis password

Admin account

VariableRequiredDefaultDescription
ADMIN_USERNAMENoadminInitial admin username
ADMIN_EMAILNo[email protected]Initial admin email (used for login)
ADMIN_PASSWORDNoauto-generatedInitial admin password

Email (SMTP)

VariableRequiredDefaultDescription
SMTP_HOSTNo---SMTP server hostname
SMTP_PORTNo587SMTP server port
SMTP_SECURENofalseUse TLS (true for port 465)
SMTP_USERNo---SMTP username
SMTP_PASSNo---SMTP password or API key
EMAIL_FROMNo[email protected]Sender email address

Application URLs

VariableRequiredDefaultDescription
FRONTEND_URLNohttp://localhost:3000Frontend origin (scheme + host + port, no trailing slash)
ADMIN_URLNohttp://localhost:3000Admin origin (usually same as FRONTEND_URL)
API_URLNohttp://localhost:3001Public API URL for email assets
VITE_API_URLNo/apiFrontend API base path (keep /api for Docker)

Ports

VariableRequiredDefaultDescription
BACKEND_PORTNo3001Host port for the backend
FRONTEND_PORTNo3000Host port for the frontend
DB_PORTNo5432Host port for PostgreSQL
REDIS_PORTNo6379Host port for Redis

Storage

VariableRequiredDefaultDescription
APP_STORAGENo./storageHost path for storage
APP_DATANo./dataHost path for application data
LOGSNo./logsHost path for logs
EXTERNAL_MEDIA_ROOTNoAuto-detected or set by ComposeLibrary path visible to the backend process. In Docker, set this to the container-side path of the read-only mount; see External Media configuration.

External-folder watching

Available in builds containing PicPeak PR #1345 . These settings control automatic imports for reference-mode events. Each event must also opt in using Watch folder for new files; the global default does not enable watching for every event. See External Media for setup, permissions and deletion behaviour.

VariableRequiredDefaultDescription
EXTERNAL_MEDIA_WATCHNotrueGlobal service switch. Set false to stop automatic external imports for all events; saved per-event watch settings remain unchanged.
EXTERNAL_MEDIA_WATCH_POLLINGNofalseUse repeated filesystem metadata checks instead of notifications. Useful for NFS/SMB shares that do not report writes from other machines.
EXTERNAL_MEDIA_WATCH_POLL_INTERVAL_MSNo5000File polling interval when polling is enabled (5 seconds).
EXTERNAL_MEDIA_WATCH_SWEEP_INTERVAL_MSNo900000Full scan of watched folders every 15 minutes as a fallback. 0 disables this scan.
EXTERNAL_MEDIA_WATCH_DEBOUNCE_MSNo10000Quiet period after the last detected new file before starting an import (10 seconds).
EXTERNAL_MEDIA_WATCH_STABILITY_MSNo5000Settling interval for new files (5 seconds). Automatic passes defer recently modified or changing files and retry later.
EXTERNAL_MEDIA_WATCH_RECONCILE_INTERVAL_MSNo60000Advanced: how often the backend re-reads event watch settings (1 minute). Add this explicitly to Compose’s backend environment block if overriding it.

All interval values are in milliseconds. The updated bundled Compose files forward the first six options from .env; they do not forward EXTERNAL_MEDIA_WATCH_RECONCILE_INTERVAL_MS. Custom Compose definitions must pass the desired variables through environment or env_file. On AIO, set them on the PicPeak container. Recreate the container after changes; for a native process, restart the backend with the new environment.

The watcher uses the local EXTERNAL_MEDIA_ROOT with both local and S3 storage backends. These settings do not configure the managed-storage file watcher or the S3 prefix walker.

Docker user mapping

VariableRequiredDefaultDescription
PUIDNo1001Container user UID
PGIDNo1001Container user GID

Used for the static HTML title and meta description on the SPA shell — the fallback that catches link-preview fetchers (WhatsApp Business API, Twilio, LinkPreview, etc.) that don’t trigger the per-event Open Graph endpoint. Substituted into index.html at frontend-container start, so changes take effect on the next docker compose up -d frontend — no frontend rebuild needed.

VariableRequiredDefaultDescription
BRAND_TITLENoPicPeakTitle shown when a non-crawler fetcher reads index.html
BRAND_DESCRIPTIONNoPhoto gallery shared with PicPeak.Meta description / og:description for the same fallback

Release channel

VariableRequiredDefaultDescription
PICPEAK_CHANNELNostableImage tag: stable, beta, or a specific version
UPDATE_CHECK_ENABLEDNotrueShow update notifications in admin dashboard

Analytics

VariableRequiredDefaultDescription
VITE_UMAMI_URLNo---Umami analytics server URL
VITE_UMAMI_WEBSITE_IDNo---Umami website ID
VITE_UMAMI_SHARE_URLNo---Umami public share URL

Public landing page

VariableRequiredDefaultDescription
PUBLIC_SITE_CACHE_TTL_MSNo60000Cache TTL for the landing page in milliseconds

Storage backend

See Storage Backends for the migration playbook and provider-specific examples.

VariableRequiredDefaultDescription
STORAGE_BACKENDNolocallocal or s3
STORAGE_S3_BUCKETWhen s3---Bucket name
STORAGE_S3_REGIONNous-east-1AWS region; use auto for R2
STORAGE_S3_ACCESS_KEYWhen s3---Access key ID
STORAGE_S3_SECRET_KEYWhen s3---Secret access key
STORAGE_S3_ENDPOINTNo---Custom endpoint (MinIO, R2, B2, Spaces…)
STORAGE_S3_PREFIXNo---Namespace inside the bucket
STORAGE_S3_FORCE_PATH_STYLENoauto when endpoint settrue for MinIO and IP-based endpoints
STORAGE_S3_SSLNotruefalse for plain-HTTP endpoints (dev MinIO)
STORAGE_AUTO_IMPORTNofalseEnable the S3 prefix walker (replaces chokidar in S3 mode)
STORAGE_AUTO_IMPORT_INTERVAL_MSNo300000Walker poll interval (5 minutes)

Webhooks

See Webhooks for event catalog, payload shapes, and verification examples.

VariableRequiredDefaultDescription
WEBHOOK_ALLOW_PRIVATE_URLSNofalseWhen true, allows webhooks to POST to private/loopback addresses. Production must leave this off. Dev only.
WEBHOOK_DELIVERY_INTERVAL_MSNo5000How often the worker polls for pending deliveries
WEBHOOK_DELIVERY_CONCURRENCYNo5Max in-flight deliveries per tick. Bump if your receivers are slow.
WEBHOOK_HTTP_TIMEOUT_MSNo10000Per-request timeout
WEBHOOK_MAX_ATTEMPTSNo5Total attempts before a delivery is marked failed
Last updated on