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

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_ROOTNo/app/storage/external-mediaPath to external photo library

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