-
Notifications
You must be signed in to change notification settings - Fork 47
Expand file tree
/
Copy path.env.example
More file actions
145 lines (130 loc) · 7.46 KB
/
Copy path.env.example
File metadata and controls
145 lines (130 loc) · 7.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# ============================================================
# FreeFrame — Environment Configuration
# ============================================================
#
# Development:
# cp .env.example .env
# docker compose -f docker-compose.dev.yml up --build
# (Dev compose overrides most values below with local defaults)
#
# Production:
# cp .env.example .env.prod
# Edit .env.prod with your real credentials
# docker compose --env-file .env.prod -f docker-compose.prod.yml up -d --build
#
# ============================================================
# ─── Database ───────────────────────────────────────────────
# Dev: auto-overridden by docker-compose.dev.yml (local Postgres)
# Prod: set a strong password or use an external database
POSTGRES_USER=freeframe
POSTGRES_PASSWORD=freeframe
POSTGRES_DB=freeframe
DATABASE_URL=postgresql://freeframe:freeframe@localhost:5432/freeframe
# External database (RDS, Supabase, Neon, etc.):
# Remove the postgres service from compose, then set:
# DATABASE_URL=postgresql://user:password@your-db-host:5432/freeframe
# ─── Redis / Valkey ─────────────────────────────────────────
# Dev: no password needed (auto-overridden by dev compose)
# Prod: set a password or use an external Redis/Valkey instance
REDIS_PASSWORD=
REDIS_URL=redis://localhost:6379/0
# External Redis/Valkey (Upstash, ElastiCache, etc.):
# Remove the redis service from compose, then set:
# REDIS_URL=redis://:password@your-redis-host:6379/0
# ─── S3 Storage ─────────────────────────────────────────────
# FreeFrame stores ALL media via the S3 API — there is no local-filesystem
# backend. To keep media on your own host, run an S3-compatible server (MinIO)
# and point FreeFrame at it (see the optional block in docker-compose.prod.yml).
#
# S3_STORAGE=s3 → native AWS S3. S3_ENDPOINT is IGNORED (pointing it at a
# non-AWS URL fails fast at startup — use "minio" instead).
# S3_STORAGE=minio → any other S3-compatible endpoint (self-hosted MinIO,
# Cloudflare R2, Backblaze B2, DO Spaces, Ceph, …).
# S3_ENDPOINT is used and required.
S3_STORAGE=minio
S3_BUCKET=freeframe
S3_ACCESS_KEY=minioadmin
S3_SECRET_KEY=minioadmin
S3_REGION=us-east-1
S3_ENDPOINT=http://localhost:9000
# S3_PUBLIC_ENDPOINT= # Browser-reachable base URL for presigned URLs, if it
# # differs from S3_ENDPOINT (e.g. internal http://minio:9000
# # vs public https://storage.example.com). Set this whenever
# # the browser can't reach S3_ENDPOINT directly.
#
# MinIO server CORS: browser origins allowed to PUT/GET presigned objects directly (dev
# compose). Dev default: http://localhost:3000. For LAN uploads from other devices set "*"
# or your LAN origin (e.g. http://192.168.1.50:3000).
# MINIO_CORS_ALLOW_ORIGIN=http://localhost:3000
# Production — native AWS S3 (uncomment and fill in):
# S3_STORAGE=s3
# S3_BUCKET=your-freeframe-bucket
# S3_ACCESS_KEY=YOUR_S3_ACCESS_KEY
# S3_SECRET_KEY=YOUR_S3_SECRET_KEY
# S3_REGION=us-east-1
# Production — non-AWS S3-compatible (Cloudflare R2, Backblaze B2, DO Spaces, or
# self-hosted MinIO). Keep S3_STORAGE as a non-"s3" value so S3_ENDPOINT is used:
# S3_STORAGE=minio
# S3_BUCKET=your-freeframe-bucket
# S3_ACCESS_KEY=YOUR_ACCESS_KEY
# S3_SECRET_KEY=YOUR_SECRET_KEY
# S3_ENDPOINT=https://<account-id>.r2.cloudflarestorage.com
# S3_PUBLIC_ENDPOINT=https://media.your-domain.com # if the browser needs a different host
# ─── Auth ───────────────────────────────────────────────────
# Prod: generate a strong secret → openssl rand -hex 64
JWT_SECRET=change-me-to-a-secure-random-string
JWT_ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=15
REFRESH_TOKEN_EXPIRE_DAYS=7
# ─── Frontend ───────────────────────────────────────────────
# Dev: http://localhost:3000
# Prod: your actual domain with https://
FRONTEND_URL=http://localhost:3000
# Web app → API base URL, baked into the browser bundle at build time (dev compose).
# Dev default: http://localhost:8000. For LAN access from other devices, set this and
# FRONTEND_URL to your machine's IP (e.g. http://192.168.1.50:8000).
NEXT_PUBLIC_API_URL=http://localhost:8000
# Extra browser origins the API's CORS allows, comma-separated (beyond the frontend +
# localhost defaults). Set to "*" to allow any origin — handy for LAN testing; never in prod.
CORS_ALLOW_ORIGINS=
# ─── Email ──────────────────────────────────────────────────
# REQUIRED for login: FreeFrame signs users in with emailed magic codes (and
# sends invites/notifications). Without a working mailer, users cannot log in —
# the app logs a warning at startup if email isn't configured.
# Option 1: SMTP (Mailgun, Postmark, SendGrid, self-hosted, etc.)
MAIL_PROVIDER=smtp
MAIL_FROM_ADDRESS=noreply@example.com
# Leave blank to use the instance branding name from Settings > Admin > Branding.
# Set it to pin a fixed From display name regardless of branding.
MAIL_FROM_NAME=
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=
SMTP_PASSWORD=
SMTP_USE_TLS=true
# Option 2: AWS SES
# MAIL_PROVIDER=ses
# MAIL_FROM_ADDRESS=noreply@your-domain.com
# MAIL_FROM_NAME=
# AWS_MAIL_ACCESS_KEY_ID=YOUR_SES_ACCESS_KEY
# AWS_MAIL_SECRET_ACCESS_KEY=YOUR_SES_SECRET_KEY
# AWS_MAIL_REGION=us-east-1
# ─── SSL (Production only) ──────────────────────────────────
# Set DOMAIN and ACME_EMAIL to enable automatic Let's Encrypt SSL.
# Without these, FreeFrame runs on HTTP only (port 80).
DOMAIN=your-domain.com
ACME_EMAIL=admin@your-domain.com
# ─── Workers & Performance ──────────────────────────────────
API_WORKERS=4 # Gunicorn worker processes (prod only)
TRANSCODING_CONCURRENCY=2 # Parallel video transcoding jobs (CPU intensive)
EMAIL_CONCURRENCY=2 # Parallel email sending jobs
MAINTENANCE_CONCURRENCY=1 # Parallel housekeeping jobs (retention GC, upload reaper, orphan sweep)
NEXT_PUBLIC_UPLOAD_CONCURRENCY=5 # Upload parts sent at once, per file (browser). Lower it if your
# object store throttles concurrent part PUTs. Build-time: rebuild web to apply.
TRANSCODER_ENGINE=ffmpeg
MAX_UPLOAD_BYTES=0 # Max size (bytes) for one uploaded file; 0 = unlimited
STALE_UPLOAD_TIMEOUT_HOURS=24 # Reclaim uploads stuck at uploading/failed for longer than N hours; 0 = disabled
STUCK_PROCESSING_TIMEOUT_HOURS=6 # Re-dispatch a transcode for versions stuck at processing longer than N hours; 0 = disabled
SOFT_DELETE_RETENTION_DAYS=30 # Hard-delete rows soft-deleted longer than N days (cascade + S3 reclaim); 0 = disabled
ORPHAN_SWEEP_GRACE_HOURS=0 # S3 orphan sweeper: reclaim raw/+processed/ keys with no DB row; 0 = disabled; >0 = only keys older than N hours
ORPHAN_SWEEP_DELETE=false # false = report-only (log only); true = actually delete orphans