# ============================================================================== # Changemaker Lite v2 — Environment Variables # Copy this file to .env and fill in the values # Generate secrets with: openssl rand -hex 32 # ============================================================================== # # SECURITY WARNING: # - All passwords marked REQUIRED_STRONG_PASSWORD_CHANGE_THIS MUST be changed # - Use strong, unique passwords (20+ characters recommended) # - Generate secrets with: openssl rand -hex 32 # - NEVER commit .env to version control # ============================================================================== # ============================================================================== # MINIMUM VIABLE SETUP (required — change these before deploying) # ============================================================================== # 1. V2_POSTGRES_PASSWORD — database password (8+ chars) # 2. REDIS_PASSWORD — cache password (8+ chars) # 3. JWT_ACCESS_SECRET — openssl rand -hex 32 # 4. JWT_REFRESH_SECRET — openssl rand -hex 32 (different from above) # 5. JWT_INVITE_SECRET — openssl rand -hex 32 (different from above) # 6. ENCRYPTION_KEY — openssl rand -hex 32 (different from JWT secrets) # 7. INITIAL_ADMIN_PASSWORD — 12+ chars, uppercase + lowercase + digit # 8. DOMAIN — your deployment domain (default: cmlite.org) # # Everything below these 8 values works with defaults for development. # ============================================================================== # --- General --- NODE_ENV=development # Root domain serves MkDocs documentation site only # All application routes (admin + public) accessible at app.${DOMAIN} DOMAIN=cmlite.org USER_ID=1000 GROUP_ID=1000 DOCKER_GROUP_ID=984 # --- V2 PostgreSQL --- V2_POSTGRES_USER=changemaker V2_POSTGRES_PASSWORD=REQUIRED_STRONG_PASSWORD_CHANGE_THIS V2_POSTGRES_DB=changemaker_v2 V2_POSTGRES_PORT=5433 # --- JWT Auth --- JWT_ACCESS_SECRET=GENERATE_WITH_openssl_rand_hex_32 JWT_REFRESH_SECRET=GENERATE_WITH_openssl_rand_hex_32 JWT_INVITE_SECRET=GENERATE_WITH_openssl_rand_hex_32 JWT_ACCESS_EXPIRY=15m JWT_REFRESH_EXPIRY=7d # Encryption key for DB-stored secrets (SMTP password, etc.) # REQUIRED in production — must NOT reuse JWT_ACCESS_SECRET # Generate with: openssl rand -hex 32 ENCRYPTION_KEY=GENERATE_WITH_openssl_rand_hex_32 # Gitea SSO cookie signing secret (separate from JWT — falls back to JWT_ACCESS_SECRET if empty) # Generate with: openssl rand -hex 32 GITEA_SSO_SECRET= # Salt for deriving deterministic service passwords (Gitea, Rocket.Chat) # Falls back to JWT_ACCESS_SECRET if empty — set a dedicated value to isolate secret rotation # Generate with: openssl rand -hex 32 SERVICE_PASSWORD_SALT= # --- Initial Super Admin User (auto-created during database seeding) --- # These credentials are used to create the initial super admin account # Change these before running the seed script in production INITIAL_ADMIN_EMAIL=admin@cmlite.org INITIAL_ADMIN_PASSWORD=REQUIRED_STRONG_PASSWORD_CHANGE_THIS # --- API --- API_PORT=4000 API_URL=http://localhost:4000 # Include docs/root domain for inline payment widgets on MkDocs pages CORS_ORIGINS=http://localhost:3000,http://localhost,http://localhost:4003 # --- Admin GUI --- ADMIN_PORT=3000 ADMIN_URL=http://localhost:3000 # --- Nginx --- NGINX_HTTP_PORT=80 NGINX_HTTPS_PORT=443 # --- Embed Proxy Ports --- # Dedicated nginx ports for iframe embedding without DNS/subdomain. # Change these to avoid port conflicts when running multiple instances on one host. NOCODB_EMBED_PORT=8881 N8N_EMBED_PORT=8882 GITEA_EMBED_PORT=8883 MAILHOG_EMBED_PORT=8884 MINI_QR_EMBED_PORT=8885 EXCALIDRAW_EMBED_PORT=8886 HOMEPAGE_EMBED_PORT=8887 VAULTWARDEN_EMBED_PORT=8890 ROCKETCHAT_EMBED_PORT=8891 GANCIO_EMBED_PORT=8892 JITSI_EMBED_PORT=8893 GRAFANA_EMBED_PORT=8894 ALERTMANAGER_EMBED_PORT=8895 # --- Docker / Container Management --- # Docker network name (used by dashboard to auto-discover containers) DOCKER_NETWORK_NAME=changemaker-lite # Docker socket proxy URL (read-only container inspection) DOCKER_PROXY_URL=http://docker-socket-proxy:2375 # Newt tunnel container (for Pangolin restart/status checks) NEWT_CONTAINER_NAME=newt-changemaker NEWT_COMPOSE_SERVICE=newt # --- SMTP / Email --- SMTP_HOST=mailhog-changemaker SMTP_PORT=1025 SMTP_USER= SMTP_PASS= SMTP_FROM=noreply@cmlite.org SMTP_FROM_NAME=Changemaker Lite EMAIL_TEST_MODE=true TEST_EMAIL_RECIPIENT=admin@cmlite.org # --- Listmonk --- LISTMONK_PORT=9001 # Use 5434 to avoid conflict with main PostgreSQL (5432 internal / 5433 host) LISTMONK_DB_PORT=5434 LISTMONK_DB_USER=listmonk LISTMONK_DB_PASSWORD=REQUIRED_STRONG_PASSWORD_CHANGE_THIS LISTMONK_DB_NAME=listmonk # Web admin login (for the Listmonk dashboard at :9001) LISTMONK_WEB_ADMIN_USER=admin LISTMONK_WEB_ADMIN_PASSWORD=REQUIRED_STRONG_PASSWORD_CHANGE_THIS # API user (auto-created by listmonk-init container, used by V2 API for sync) # Generate token: openssl rand -hex 16 # NOTE: LISTMONK_ADMIN_USER/PASSWORD are what the V2 API uses to connect. # They MUST match LISTMONK_API_USER/TOKEN (same credentials, different var names). LISTMONK_API_USER=v2-api LISTMONK_API_TOKEN=GENERATE_WITH_openssl_rand_hex_16 LISTMONK_ADMIN_USER=v2-api LISTMONK_ADMIN_PASSWORD=SAME_AS_LISTMONK_API_TOKEN LISTMONK_SYNC_ENABLED=false LISTMONK_WEBHOOK_SECRET= LISTMONK_PROXY_PORT=9002 # Listmonk SMTP — MailHog for development (production SMTP added as second provider if credentials set) LISTMONK_SMTP_HOST=mailhog-changemaker LISTMONK_SMTP_PORT=1025 LISTMONK_SMTP_USER= LISTMONK_SMTP_PASSWORD= LISTMONK_SMTP_TLS_TYPE=none LISTMONK_SMTP_FROM=Changemaker Lite # Production SMTP (uncomment and set for real email delivery): # LISTMONK_SMTP_HOST=smtp.protonmail.ch # LISTMONK_SMTP_PORT=587 # LISTMONK_SMTP_USER=your@email.com # LISTMONK_SMTP_PASSWORD=your-password # LISTMONK_SMTP_TLS_TYPE=STARTTLS # --- Represent API (Canadian electoral data) --- REPRESENT_API_URL=https://represent.opennorth.ca # --- NocoDB v2 (read-only data browser) --- # NocoDB uses its own database (nocodb_meta) to avoid conflicts with Prisma # The database is auto-created by init-nocodb-db.sh on first PostgreSQL startup # nocodb-init container auto-registers changemaker_v2 as a browsable data source NOCODB_V2_PORT=8091 NOCODB_URL=http://changemaker-v2-nocodb:8080 NOCODB_PORT=8091 NC_ADMIN_EMAIL=admin@cmlite.org NC_ADMIN_PASSWORD=REQUIRED_STRONG_PASSWORD_CHANGE_THIS # --- Redis --- # Shared Redis (v2 uses authenticated connection) REDIS_PASSWORD=REQUIRED_STRONG_PASSWORD_CHANGE_THIS REDIS_URL=redis://:${REDIS_PASSWORD}@redis-changemaker:6379 # --- Payments (Stripe) --- # Enable payments feature (memberships, products, donations) # Stripe API keys are stored encrypted in DB via admin settings page ENABLE_PAYMENTS=false # --- Media Management --- ENABLE_MEDIA_FEATURES=false MEDIA_API_PORT=4100 MEDIA_API_PUBLIC_URL=http://media-api:4100 # Used during admin Docker build to set the media API endpoint for Vite VITE_MEDIA_API_URL=http://changemaker-media-api:4100 MEDIA_ROOT=/media/library MEDIA_UPLOADS=/media/uploads MAX_UPLOAD_SIZE_GB=10 PUBLIC_MEDIA_PORT=3100 VIDEO_PLAYER_DEBUG=false # Video Analytics (Feb 2026) VIDEO_ANALYTICS_RETENTION_DAYS=90 VIDEO_ANALYTICS_IP_HASHING_ENABLED=true # Video Scheduling (Feb 2026) VIDEO_SCHEDULE_DEFAULT_TIMEZONE=UTC VIDEO_SCHEDULE_NOTIFICATION_ENABLED=true # Preview Links (Feb 2026) VIDEO_PREVIEW_LINK_EXPIRY_HOURS=24 # --- Container Registry --- # Gitea registry for pre-built production images. # Set IMAGE_TAG to a commit SHA (or 'latest') to pull pre-built images instead of building from source. # Leave IMAGE_TAG blank/unset (defaults to 'local') to build locally from source. GITEA_REGISTRY=gitea.bnkops.com/admin IMAGE_TAG= # Docker Compose profiles — set to 'monitoring' to include Prometheus/Grafana/Alertmanager # in every 'docker compose up -d'. Leave blank to start monitoring separately. COMPOSE_PROFILES= # Credentials used by the registry status API endpoint (GET /api/registry/status) # For docker push/pull, run: docker login gitea.bnkops.com GITEA_REGISTRY_USER=admin GITEA_REGISTRY_PASS= # API token for the REMOTE registry (gitea.bnkops.com) — used by build-release.sh --upload # Create at: https://gitea.bnkops.com/user/settings/applications # This is NOT the same as GITEA_API_TOKEN (which is for the local platform Gitea below) GITEA_REGISTRY_API_TOKEN= # --- Gitea (Local Platform Instance) --- GITEA_URL=http://gitea-changemaker:3000 GITEA_PORT=3030 GITEA_WEB_PORT=3030 GITEA_SSH_PORT=2222 # Admin user (auto-created on first boot by gitea-init.sh) GITEA_ADMIN_USER=admin GITEA_DB_TYPE=mysql GITEA_DB_HOST=gitea-db:3306 GITEA_DB_NAME=gitea GITEA_DB_USER=gitea GITEA_DB_PASSWD=REQUIRED_STRONG_PASSWORD_CHANGE_THIS GITEA_DB_ROOT_PASSWORD=REQUIRED_STRONG_PASSWORD_CHANGE_THIS GITEA_ROOT_URL=https://git.cmlite.org GITEA_DOMAIN=git.cmlite.org # --- Gitea Docs Comments --- # Enable comments on MkDocs pages (backed by Gitea Issues) GITEA_COMMENTS_ENABLED=false # Personal access token for the LOCAL Gitea instance (docs comments, user provisioning, SSO) # Create at: http://localhost:3030/user/settings/applications (or https://git.DOMAIN/...) # This is NOT the same as GITEA_REGISTRY_API_TOKEN (which is for the remote registry above) GITEA_API_TOKEN= # Repository owner (Gitea username that will own the docs-comments repo) GITEA_COMMENTS_REPO_OWNER= # Repository name (auto-created via admin setup button) GITEA_COMMENTS_REPO_NAME=docs-comments # OAuth2 Application credentials (create in Gitea → Settings → Applications → OAuth2) # Redirect URIs: https://{DOMAIN}/comments/callback/ and http://localhost:4003/comments/callback/ GITEA_OAUTH_CLIENT_ID= GITEA_OAUTH_CLIENT_SECRET= # --- n8n --- N8N_URL=http://n8n-changemaker:5678 N8N_PORT=5678 N8N_HOST=n8n.cmlite.org N8N_ENCRYPTION_KEY=REQUIRED_STRONG_PASSWORD_CHANGE_THIS N8N_USER_EMAIL=admin@example.com N8N_USER_PASSWORD=REQUIRED_STRONG_PASSWORD_CHANGE_THIS GENERIC_TIMEZONE=UTC # --- MkDocs --- # Port mapping for MkDocs container (host:container) # This also controls the Vite dev proxy in local development # Change this port to use a different local port, and the admin dev server will automatically use it MKDOCS_PORT=4003 MKDOCS_SITE_SERVER_PORT=4004 BASE_DOMAIN=https://cmlite.org MKDOCS_PREVIEW_URL=http://mkdocs:8000 MKDOCS_DOCS_PATH=/mkdocs/docs # --- Code Server --- CODE_SERVER_PORT=8888 CODE_SERVER_URL=http://code-server-changemaker:8443 USER_NAME=coder # --- Homepage --- HOMEPAGE_PORT=3010 HOMEPAGE_VAR_BASE_URL=http://localhost # --- Mini QR --- MINI_QR_PORT=8089 MINI_QR_URL=http://mini-qr:8080 # --- Excalidraw (Collaborative Whiteboard) --- EXCALIDRAW_PORT=8090 EXCALIDRAW_URL=http://excalidraw-changemaker:80 EXCALIDRAW_WS_URL=wss://draw.cmlite.org # --- Vaultwarden (Password Manager) --- VAULTWARDEN_PORT=8445 VAULTWARDEN_URL=http://vaultwarden-changemaker:80 # Admin panel token (access at /admin) — generate with: openssl rand -hex 32 VAULTWARDEN_ADMIN_TOKEN= # MUST use HTTPS — Bitwarden web vault enforces HTTPS for account creation # Set to your Pangolin tunnel URL (e.g., https://vault.yourdomain.org) # Local access (browsing existing vault) works on HTTP, but signup/invite requires HTTPS VAULTWARDEN_DOMAIN=https://vault.cmlite.org VAULTWARDEN_SIGNUPS_ALLOWED=false VAULTWARDEN_WEBSOCKET_ENABLED=true # SMTP security: "off" for MailHog, "starttls" or "force_tls" for production VAULTWARDEN_SMTP_SECURITY=off # --- MailHog --- MAILHOG_SMTP_PORT=1025 MAILHOG_WEB_PORT=8025 # --- NAR (National Address Register) --- # Path to extracted NAR data (contains YYYYMM/Addresses/ and YYYYMM/Locations/) # Download from: https://www150.statcan.gc.ca/n1/pub/46-26-0002/462600022022001-eng.htm NAR_DATA_DIR=/data # --- Overpass / Area Import --- # OpenStreetMap Overpass API endpoint (use a private instance for heavy usage) OVERPASS_API_URL=https://overpass-api.de/api/interpreter # Minimum delay between Overpass requests (ms) — public API requires 30s OVERPASS_MIN_DELAY_MS=30000 # Maximum reverse geocode grid points for area import fill-in AREA_IMPORT_MAX_GRID_POINTS=500 # --- Geocoding --- # Optional Mapbox API key for improved geocoding accuracy # Free tier: 100,000 requests/month # Sign up: https://www.mapbox.com/pricing MAPBOX_API_KEY= # Rate limit delay between provider requests (milliseconds) GEOCODING_RATE_LIMIT_MS=1100 # Redis-backed persistent cache settings GEOCODING_CACHE_ENABLED=true GEOCODING_CACHE_TTL_HOURS=24 # Phase 2: Performance & Accuracy # Google Maps API (optional, most accurate but costs $0.005/request after 100k/month) GOOGLE_MAPS_API_KEY= GOOGLE_MAPS_ENABLED=false # Parallel geocoding for bulk imports (10x speedup) GEOCODING_PARALLEL_ENABLED=true GEOCODING_BATCH_SIZE=10 # Bulk Re-Geocoding (Phase 3) BULK_GEOCODE_ENABLED=true BULK_GEOCODE_MAX_BATCH=5000 # --- Pangolin Tunnel --- # Server: self-hosted Pangolin instance PANGOLIN_API_URL=https://api.bnkserve.org/v1 PANGOLIN_API_KEY= PANGOLIN_ORG_ID= # Populated after setup (via admin GUI or API) PANGOLIN_SITE_ID= PANGOLIN_ENDPOINT=https://pangolin.bnkserve.org PANGOLIN_NEWT_ID= PANGOLIN_NEWT_SECRET= # --- Prisma CLI (host-side only, NOT used by Docker containers) --- # Containers resolve the DB hostname internally via docker-compose environment # This is used when running `npx prisma migrate dev` from the host machine DATABASE_URL=postgresql://changemaker:YOUR_POSTGRES_PASSWORD@localhost:5433/changemaker_v2 # --- Rocket.Chat (Team Chat) --- # ENABLE_CHAT is the initial default; once saved in admin Settings, the DB value is authoritative ENABLE_CHAT=false ROCKETCHAT_ADMIN_USER=rcadmin ROCKETCHAT_ADMIN_PASSWORD=REQUIRED_STRONG_PASSWORD_CHANGE_THIS ROCKETCHAT_URL=http://rocketchat-changemaker:3000 # MongoDB credentials for Rocket.Chat (required — MongoDB runs with --auth) MONGO_ROOT_USER=rocketchat MONGO_ROOT_PASSWORD=REQUIRED_STRONG_PASSWORD_CHANGE_THIS # --- Gancio (Event Management) --- # Uses shared PostgreSQL (database: gancio, auto-created by init-gancio-db.sh) GANCIO_PORT=8092 GANCIO_URL=http://gancio-changemaker:13120 GANCIO_BASE_URL=https://events.cmlite.org # Gancio admin credentials for shift-to-event sync (OAuth login) GANCIO_ADMIN_USER=admin GANCIO_ADMIN_PASSWORD=REQUIRED_STRONG_PASSWORD_CHANGE_THIS # Enable automatic shift → Gancio event sync GANCIO_SYNC_ENABLED=false # --- Jitsi Meet (Video Conferencing) --- # Self-hosted Jitsi with JWT auth — integrates with Rocket.Chat for channel video calls # ENABLE_MEET is the initial default; once saved in admin Settings, the DB value is authoritative ENABLE_MEET=false # JWT authentication (shared between Jitsi Prosody, Rocket.Chat, and the API) # Generate with: openssl rand -hex 32 JITSI_APP_ID=changemaker JITSI_APP_SECRET=GENERATE_WITH_openssl_rand_hex_32 # Internal XMPP passwords (used between Jitsi containers, not exposed externally) # Generate each with: openssl rand -hex 16 JITSI_JICOFO_AUTH_PASSWORD=GENERATE_WITH_openssl_rand_hex_16 JITSI_JVB_AUTH_PASSWORD=GENERATE_WITH_openssl_rand_hex_16 JITSI_URL=http://jitsi-web-changemaker:80 # JVB public IP (required for NAT traversal — set to server's public IP in production) JVB_ADVERTISE_IP= # JVB UDP port for media traffic (must be open in firewall) JVB_PORT=10000 # --- SMS Campaigns (Termux Android Bridge) --- # ENABLE_SMS is the initial default; once saved in admin Settings, the DB value is authoritative # URL + API key are typically managed via admin Settings page (DB overrides env) # Use Tailscale IP (100.x.x.x) for stable addressing across networks ENABLE_SMS=false TERMUX_API_URL=http://100.x.x.x:5001 TERMUX_API_KEY= SMS_DELAY_BETWEEN_MS=3000 SMS_MAX_RETRIES=3 SMS_RESPONSE_SYNC_INTERVAL_MS=120000 SMS_DEVICE_MONITOR_INTERVAL_MS=300000 # --- Social, People & Analytics --- # ENABLE_SOCIAL is the initial default; once saved in admin Settings, the DB value is authoritative ENABLE_SOCIAL=false # ENABLE_PEOPLE is the initial default; once saved in admin Settings, the DB value is authoritative ENABLE_PEOPLE=false # ENABLE_ANALYTICS is the initial default; once saved in admin Settings, the DB value is authoritative ENABLE_ANALYTICS=false # --- Control Panel Agent --- # Set to true to enable the CCP remote management agent ENABLE_CCP_AGENT=false # URL of the Changemaker Control Panel CCP_URL= # One-time invite code for registration CCP_INVITE_CODE= # How the CCP can reach this agent (must be externally accessible) CCP_AGENT_URL= # Agent port (default 7443) CCP_AGENT_PORT=7443 # --- Monitoring (only used with --profile monitoring) --- PROMETHEUS_PORT=9090 GRAFANA_PORT=3005 GRAFANA_ADMIN_PASSWORD=REQUIRED_STRONG_PASSWORD_CHANGE_THIS GRAFANA_ROOT_URL=http://localhost:3005 CADVISOR_PORT=8086 NODE_EXPORTER_PORT=9100 REDIS_EXPORTER_PORT=9121 ALERTMANAGER_PORT=9093 GOTIFY_PORT=8889 GOTIFY_ADMIN_USER=admin GOTIFY_ADMIN_PASSWORD=REQUIRED_STRONG_PASSWORD_CHANGE_THIS # --- Bunker Ops (Fleet Management) --- INSTANCE_LABEL= # Unique label for this instance (defaults to DOMAIN) BUNKER_OPS_ENABLED=false # Enable remote metrics push to central server BUNKER_OPS_REMOTE_WRITE_URL= # VictoriaMetrics remote_write endpoint (e.g., https://ops.example.com/api/v1/write) # --- GeoIP (MaxMind GeoLite2) --- # Free account: https://www.maxmind.com/en/geolite2/signup MAXMIND_ACCOUNT_ID= # MaxMind account ID MAXMIND_LICENSE_KEY= # MaxMind license key (auto-downloads GeoLite2-City DB at startup)