Files
picpeak/.env.example
T
Luca 415bffa04c feat: zero-config first run — in-browser admin bootstrap + auto-generated secrets
Fresh installs need nothing in .env. See PR description for the full feature.
2026-07-01 14:49:18 +02:00

217 lines
8.8 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
# 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
# printed to the backend logs (`docker compose logs backend | grep -i "setup token"`)
# and saved to data/SETUP_TOKEN.
# 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
# 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
# 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)
# This must be the publicly accessible URL where email recipients can load images.
# If not set, defaults to http://localhost:3001 which will show broken images in emails.
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
# 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
# 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.