mirror of
https://github.com/yusufipk/OpenFrame.git
synced 2026-09-11 17:46:06 +00:00
Self-hosted instances on the R2/S3 backend could only upload a video as a single PUT, which fails behind a Cloudflare proxy/tunnel (100MB request-body cap) and is capped at 5GiB with no resilience. Bunny already avoids this via tus; this brings the R2/S3 path to parity. Files larger than a threshold (default 90MiB) are now split into parts (default 32MiB, min 5MiB) and uploaded directly browser->R2 via presigned UploadPart URLs, then reassembled server-side with CompleteMultipartUpload. Each request stays under the 100MB cap, lifts the size ceiling well past 5GiB, and adds per-chunk retry. Files at/under the threshold keep the existing single-PUT path unchanged. Bunny path is untouched. Thresholds are env-overridable via OPENFRAME_R2_MULTIPART_THRESHOLD_BYTES and OPENFRAME_R2_MULTIPART_PART_SIZE_BYTES. Verified end-to-end against real Cloudflare R2 and a local MinIO behind an nginx 90MB cap (single 141MB PUT 413s on master; 32MB parts pass here). Closes #22
148 lines
6.9 KiB
Bash
148 lines
6.9 KiB
Bash
# Copy this file to .env and fill in your values
|
|
|
|
# ============================================================================
|
|
# DATABASE
|
|
# ============================================================================
|
|
# PostgreSQL connection string
|
|
DATABASE_URL="postgresql://user:password@localhost:5432/openframe?schema=public"
|
|
# Enable PostgreSQL pool connect/acquire debug logs (set to "true" only when debugging)
|
|
DB_POOL_DEBUG="false"
|
|
|
|
# ============================================================================
|
|
# AUTHENTICATION - NextAuth.js
|
|
# ============================================================================
|
|
NEXTAUTH_URL="http://localhost:3000"
|
|
NEXTAUTH_SECRET="your-secret-key-here-generate-with-openssl-rand-base64-32"
|
|
|
|
# ============================================================================
|
|
# OPTIONAL SELF-HOSTING FEATURE FLAGS
|
|
# ============================================================================
|
|
OPENFRAME_ENABLE_STRIPE="true"
|
|
OPENFRAME_ENABLE_BUNNY_UPLOADS="true"
|
|
# Self-hosted direct video uploads to your S3-compatible storage (R2_* vars below).
|
|
# Mutually exclusive with Bunny: set OPENFRAME_ENABLE_BUNNY_UPLOADS=false when enabling this.
|
|
OPENFRAME_ENABLE_S3_VIDEO_UPLOADS="false"
|
|
# Max size per uploaded video file in bytes (default 5GB if unset)
|
|
OPENFRAME_MAX_VIDEO_UPLOAD_BYTES="5368709120"
|
|
# Files larger than this use chunked (S3 multipart) uploads instead of a single PUT.
|
|
# Default 90MiB keeps each request under the common 100MB Cloudflare proxy/tunnel cap.
|
|
# Lower it if your proxy enforces a stricter request-body limit.
|
|
OPENFRAME_R2_MULTIPART_THRESHOLD_BYTES="94371840"
|
|
# Size of each multipart chunk in bytes (default 32MiB, minimum 5MiB).
|
|
OPENFRAME_R2_MULTIPART_PART_SIZE_BYTES="33554432"
|
|
# Direct browser uploads require bucket CORS allowing PUT from your app origin(s).
|
|
# Run once after creating the bucket: bun run r2:configure-cors
|
|
# Or set CORS manually in Cloudflare R2 -> bucket -> Settings -> CORS policy.
|
|
OPENFRAME_REQUIRE_INVITE_CODE="true"
|
|
SELF_HOSTED_AUTO_CREATE_BUCKET="false"
|
|
|
|
# ============================================================================
|
|
# OAUTH PROVIDERS
|
|
# ============================================================================
|
|
# Google OAuth
|
|
# Create credentials at: https://console.cloud.google.com/apis/credentials
|
|
GOOGLE_CLIENT_ID="your-google-client-id.apps.googleusercontent.com"
|
|
GOOGLE_CLIENT_SECRET="your-google-client-secret"
|
|
|
|
# GitHub OAuth
|
|
# Create credentials at: https://github.com/settings/developers
|
|
GITHUB_CLIENT_ID="your-github-client-id"
|
|
GITHUB_CLIENT_SECRET="your-github-client-secret"
|
|
|
|
# ============================================================================
|
|
# FILE STORAGE
|
|
# ============================================================================
|
|
# Cloudflare R2 (S3-compatible)
|
|
# For self-hosted S3-compatible storage such as MinIO, set:
|
|
# - R2_ENDPOINT (server/container endpoint)
|
|
# - R2_PRESIGN_ENDPOINT (browser-reachable endpoint for presigned upload URLs)
|
|
# - R2_PUBLIC_BASE_URL (public base URL for served files)
|
|
R2_ACCOUNT_ID="your-account-id"
|
|
R2_ENDPOINT=""
|
|
R2_PRESIGN_ENDPOINT=""
|
|
R2_PUBLIC_BASE_URL=""
|
|
R2_ACCESS_KEY_ID="your-access-key"
|
|
R2_SECRET_ACCESS_KEY="your-secret-key"
|
|
R2_BUCKET_NAME="openframe"
|
|
# R2 orphan cleanup configuration (script + external cron; app runtime does not schedule this)
|
|
# R2_ORPHAN_CLEANUP_CRON="*/15 * * * *"
|
|
# Scheduled delete mode:
|
|
# */15 * * * * cd /home/yusuf/Programming/OpenFrame && bun run r2:cleanup-orphans
|
|
|
|
# ============================================================================
|
|
# EMAIL & NOTIFICATIONS
|
|
# ============================================================================
|
|
|
|
# Telegram bot token from @BotFather — shared across all users
|
|
# Users only need to provide their own Chat ID in Settings
|
|
TELEGRAM_BOT_TOKEN="your-telegram-bot-token"
|
|
|
|
SMTP_HOST="smtp.gmail.com"
|
|
SMTP_PORT="587"
|
|
SMTP_USER="[email protected]"
|
|
SMTP_PASSWORD="your-app-specific-password"
|
|
SMTP_FROM="[email protected]"
|
|
|
|
# ============================================================================
|
|
# APPLICATION
|
|
# ============================================================================
|
|
NEXT_PUBLIC_APP_URL="http://localhost:3000"
|
|
# development | production | test
|
|
NODE_ENV="development"
|
|
# Disable all app-level rate limiting for local testing. Leave unset to keep rate limiting enabled.
|
|
# Accepted truthy values: "true", "1", "yes", "on"
|
|
# DISABLE_RATE_LIMIT="true"
|
|
|
|
# Trusted reverse proxy mode — controls which headers getClientIp() trusts for rate limiting.
|
|
# Set this only when you have confirmed that your proxy strips/overwrites client-supplied headers.
|
|
# cloudflare — trust cf-connecting-ip (Cloudflare edge in front of the origin)
|
|
# nginx — trust x-real-ip / last x-forwarded-for (Nginx real_ip_header with set_real_ip_from)
|
|
# Leave unset for local dev or when no trusted proxy is in place.
|
|
TRUSTED_PROXY_MODE="cloudflare"
|
|
|
|
# Admin emails for accessing the /admin panel (comma separated list)
|
|
# e.g., "[email protected],[email protected]"
|
|
ADMIN_EMAILS=""
|
|
# Invite code for internal registration (required to sign up)
|
|
# Generate a secure code for your team
|
|
INVITE_CODE="your-secret-invite-code"
|
|
# Enable debug logging
|
|
# DEBUG="openframe:*"
|
|
|
|
# ============================================================================
|
|
# DOWNLOADS
|
|
# ============================================================================
|
|
# Project bulk-download manifest limits (GET /api/projects/[projectId]/download).
|
|
# Caps how many files and total known bytes a single manifest may enumerate.
|
|
OPENFRAME_PROJECT_DOWNLOAD_MAX_FILES="250"
|
|
# 20 GiB in bytes (20 * 1024 * 1024 * 1024)
|
|
OPENFRAME_PROJECT_DOWNLOAD_MAX_BYTES="21474836480"
|
|
# Comma-separated hostnames allowed for direct (non-proxied) version download URLs
|
|
# in manifests and the video page. Bunny CDN host is always allowed when configured.
|
|
# Example: "cdn.example.com,files.example.com"
|
|
NEXT_PUBLIC_DIRECT_DOWNLOAD_ALLOWED_HOSTS=""
|
|
|
|
# ============================================================================
|
|
# VIDEO PROCESSING
|
|
# ============================================================================
|
|
|
|
# Bunny Stream for direct video uploads
|
|
BUNNY_STREAM_API_KEY="your-stream-library-api-key"
|
|
BUNNY_STREAM_LIBRARY_ID="your-library-id"
|
|
# Bunny Core API key (account-level) used to enforce KeepOriginalFiles/ExposeOriginals on the library
|
|
BUNNY_API_KEY="your-account-api-key"
|
|
# Bunny Stream CDN base URL (for HLS streaming)
|
|
BUNNY_CDN_URL="your-url-to-bunny-cdn"
|
|
NEXT_PUBLIC_BUNNY_CDN_URL="your-url-to-bunny-cdn"
|
|
# Bunny orphan cleanup configuration (script + external cron; app runtime does not schedule this)
|
|
# Grace period is fixed at 24 hours in the script.
|
|
# */15 * * * * cd /home/yusuf/Programming/OpenFrame && bun run bunny:cleanup-orphans
|
|
|
|
# ============================================================================
|
|
# BILLING
|
|
# ============================================================================
|
|
# Stripe recurring price used for paid accounts
|
|
STRIPE_SECRET_KEY="sk_test_..."
|
|
STRIPE_PRICE_ID="prod_UBWFFKZC3d80z4"
|
|
STRIPE_WEBHOOK_SECRET="whsec_..."
|